1010from dspy .adapters .utils import get_field_description_string
1111from dspy .clients .typesafe import TypeSafe
1212from dspy .dsp .utils .settings import settings
13- from dspy .predict .predict import Predict , _sanitize_lm_state , serialize_object
13+ from dspy .predict .parameter import Parameter
14+ from dspy .predict .predict import _sanitize_lm_state , serialize_object
15+ from dspy .primitives .module import Module
16+ from dspy .primitives .prediction import Prediction
1417from dspy .signatures .signature import Signature , ensure_signature
1518from dspy .utils .annotation import experimental
1619from dspy .utils .callback import BaseCallback
1720
1821
1922@experimental
20- class Decide (Predict ):
23+ class Decide (Module , Parameter ):
2124 """Answer a signature's closed-set outputs in one System One request.
2225
2326 Declare outputs using Noul, Score[(number, description), ...], and
@@ -47,7 +50,8 @@ def __init__(
4750 client : TypeSafe | None = None ,
4851 callbacks : list [BaseCallback ] | None = None ,
4952 ):
50- super ().__init__ (signature , callbacks = callbacks )
53+ super ().__init__ (callbacks = callbacks )
54+ self .signature = ensure_signature (signature )
5155 self .client = client
5256 types = self ._output_types (self .signature )
5357 self .thresholds = {name : 0.5 for name , kind in types .items () if kind is Noul }
@@ -56,6 +60,9 @@ def __init__(
5660 {name : {str (v ): 1.0 for v , _ in kind .options } for name , kind in types .items () if issubclass (kind , Choice )}
5761 )
5862
63+ def reset (self ):
64+ """Keep configuration intact: Decide has no demonstration or training state to reset."""
65+
5966 @staticmethod
6067 def _output_types (signature ):
6168 if not signature .output_fields :
@@ -128,7 +135,7 @@ def _questions(self, signature, types):
128135 def _prepare (self , kwargs ):
129136 trace = kwargs .pop ("_trace" , True )
130137 signature = ensure_signature (kwargs .pop ("signature" , self .signature ))
131- if "demos" in kwargs or self . demos :
138+ if "demos" in kwargs or getattr ( self , " demos" , None ) :
132139 raise ValueError ("Decide does not support demonstrations." )
133140 client = self .client if self .client is not None else settings .system_one
134141 if client is None :
@@ -204,7 +211,12 @@ def _decode(self, answers, signature, types, inputs, trace):
204211 probabilities = answer ["probabilities" ],
205212 )
206213 outputs [name ] = result if field .annotation is kind else result .value
207- return self ._forward_postprocess ([outputs ], signature , _trace = trace , ** inputs )
214+ prediction = Prediction .from_completions ([outputs ], signature = signature )
215+ if trace and settings .trace is not None and settings .max_trace_size > 0 :
216+ if len (settings .trace ) >= settings .max_trace_size :
217+ settings .trace .pop (0 )
218+ settings .trace .append ((self , inputs , prediction ))
219+ return prediction
208220
209221 def forward (self , ** kwargs ):
210222 client , signature , types , inputs , questions , trace = self ._prepare (kwargs )
@@ -217,26 +229,28 @@ async def aforward(self, **kwargs):
217229 return self ._decode (answers , signature , types , inputs , trace )
218230
219231 def dump_state (self , json_mode = True ):
220- if self . demos :
232+ if getattr ( self , " demos" , None ) :
221233 raise ValueError ("Decide does not support demonstrations." )
222- state = super ().dump_state (json_mode = json_mode )
223- state .pop ("demos" )
224- state ["thresholds" ] = copy .deepcopy (self .thresholds )
225- state ["weights" ] = copy .deepcopy (self .weights )
226234 if self .client is not None and not isinstance (self .client , TypeSafe ):
227235 raise TypeError (
228236 "Saving an explicit Decide client requires dspy.experimental.TypeSafe; configure custom clients in settings."
229237 )
230- state ["client" ] = self .client .dump_state () if self .client is not None else None
231- return state
238+ return {
239+ "signature" : self .signature .dump_state (),
240+ "thresholds" : copy .deepcopy (self .thresholds ),
241+ "weights" : copy .deepcopy (self .weights ),
242+ "client" : self .client .dump_state () if self .client is not None else None ,
243+ }
232244
233245 def load_state (self , state , * , allow_unsafe_lm_state = False ):
234246 state = copy .deepcopy (state )
235247 if state .pop ("demos" , None ):
236248 raise ValueError ("Decide does not support demonstrations." )
237249 client_state = state .pop ("client" , None )
238- super ().load_state (state , allow_unsafe_lm_state = allow_unsafe_lm_state )
239- self .demos = []
250+ self .signature = self .signature .load_state (state ["signature" ])
251+ self .thresholds = state ["thresholds" ]
252+ self .weights = state ["weights" ]
253+ self .__dict__ .pop ("demos" , None )
240254 self .client = TypeSafe (** _sanitize_lm_state (client_state , allow_unsafe_lm_state )) if client_state else None
241255 self ._validate_parameters (self ._output_types (self .signature ))
242256 return self
0 commit comments