2121from litellm .types .utils import ModelResponse
2222
2323from effectful .handlers .llm import Template , Tool
24- from effectful .handlers .llm .encoding import (
25- Encodable ,
26- type_to_encodable_type ,
27- )
28- from effectful .internals .unification import TypeExpression , nested_type
24+ from effectful .handlers .llm .encoding import type_to_encodable_type
2925from effectful .ops .semantics import fwd , handler
3026from effectful .ops .syntax import ObjectInterpretation , defop , implements
3127from effectful .ops .types import Operation
@@ -217,18 +213,16 @@ def call_with_json_args(
217213
218214
219215@defop
220- def compute_response [** P , T ](
221- template : Template [P , T ], model_input_pair : tuple [list [Any ], Encodable [T ]]
222- ) -> ModelResponse :
216+ def compute_response (template : Template , model_input : list [Any ]) -> ModelResponse :
223217 """Produce a complete model response for an input message sequence. This may
224218 involve multiple API requests if tools are invoked by the model.
225219
226220 """
227- model_input , ret_type_encoder = model_input_pair
221+ ret_type = template . __signature__ . return_annotation
228222 tools = template .tools
229223
230224 tool_schemas = [function_definition (t ) for t in tools .values ()]
231- response_encoding_type : type | None = ret_type_encoder .t
225+ response_encoding_type : type | None = type_to_encodable_type ( ret_type ) .t
232226 if response_encoding_type == str :
233227 response_encoding_type = None
234228
@@ -268,12 +262,7 @@ def compute_response[**P, T](
268262 )
269263
270264
271- type ModelInput [T ] = tuple [list [Any ], Encodable [T ]]
272-
273-
274- def decode_response [** P , T ](
275- template : Callable [P , T ], model_input_pair : ModelInput [T ], response : ModelResponse
276- ) -> T :
265+ def decode_response [** P , T ](template : Callable [P , T ], response : ModelResponse ) -> T :
277266 """Decode an LLM response into an instance of the template return type. This
278267 operation should raise if the output cannot be decoded.
279268 """
@@ -284,7 +273,8 @@ def decode_response[**P, T](
284273 result_str = last_resp .content or last_resp .reasoning_content
285274 assert result_str
286275
287- encodable_ty = model_input_pair [1 ]
276+ ret_type = template .__signature__ .return_annotation
277+ encodable_ty = type_to_encodable_type (ret_type )
288278
289279 if encodable_ty .t == str :
290280 # if encoding as a type, value is just directly what the llm returned
@@ -301,29 +291,28 @@ def decode_response[**P, T](
301291@defop
302292def format_model_input [** P , T ](
303293 template : Template [P , T ], * args : P .args , ** kwargs : P .kwargs
304- ) -> ModelInput [ T ]:
294+ ) -> list [ Any ]:
305295 """Format a template applied to arguments into a sequence of input
306296 messages.
307297
308298 """
309- signature = template .__signature__
310-
311- bound_args = signature .bind (* args , ** kwargs )
299+ bound_args = template .__signature__ .bind (* args , ** kwargs )
312300 bound_args .apply_defaults ()
313301 # encode arguments
314302 arguments = {}
315- for param , value in bound_args .arguments .items ():
316- ty : TypeExpression = nested_type (value ).value
317- encoder = type_to_encodable_type (ty ) # type: ignore
318- encoded = encoder .encode (value , template .__context__ )
303+ for param in bound_args .arguments :
304+ encoder = type_to_encodable_type (
305+ template .__signature__ .parameters [param ].annotation
306+ )
307+ encoded = encoder .encode (bound_args .arguments [param ], template .__context__ )
319308 arguments [param ] = encoder .serialize (encoded )
320309
321310 prompt = _OpenAIPromptFormatter ().format_as_messages (
322311 template .__prompt_template__ , ** arguments
323312 )
324313
325314 # install prefix if the return type has a return annotation
326- ret_type = template .__type_rule__ ( * args , ** kwargs )
315+ ret_type = template .__signature__ . return_annotation
327316 origin = typing .get_origin (ret_type )
328317 ret_type = ret_type if origin is None else origin
329318 ret_type_encoder = type_to_encodable_type (ret_type )
@@ -338,7 +327,7 @@ def format_model_input[**P, T](
338327 # Note: The OpenAI api only seems to accept images in the 'user' role. The
339328 # effect of different roles on the model's response is currently unclear.
340329 messages = [{"type" : "message" , "content" : prompt , "role" : "user" }]
341- return ( messages , ret_type_encoder )
330+ return messages
342331
343332
344333class InstructionHandler (ObjectInterpretation ):
@@ -358,16 +347,12 @@ def __init__(self, instruction: str):
358347 self .instruction = instruction
359348
360349 @implements (format_model_input )
361- def _inject_instruction (
362- self , template : Template , * args , ** kwargs
363- ) -> tuple [list [Any ], Any ]:
350+ def _inject_instruction (self , template : Template , * args , ** kwargs ) -> list [Any ]:
364351 """Append instruction message to the formatted model input."""
365- (messages , decode_ty ) = fwd ()
366- return (
367- messages
368- + [{"type" : "message" , "content" : self .instruction , "role" : "user" }],
369- decode_ty ,
370- )
352+ messages = fwd ()
353+ return messages + [
354+ {"type" : "message" , "content" : self .instruction , "role" : "user" }
355+ ]
371356
372357
373358class RetryLLMHandler (ObjectInterpretation ):
@@ -436,4 +421,4 @@ def _call[**P, T](
436421 ) -> T :
437422 model_input = format_model_input (template , * args , ** kwargs )
438423 resp = compute_response (template , model_input )
439- return decode_response (template , model_input , resp )
424+ return decode_response (template , resp )
0 commit comments