@@ -72,6 +72,9 @@ def _bind_arguments(method: Callable[..., Any], *args: Any, **kwargs: Any) -> Di
7272def _llm_input_messages (arguments : Mapping [str , Any ]) -> Iterator [Tuple [str , Any ]]:
7373 def process_message (idx : int , message : Any ) -> Iterator [Tuple [str , Any ]]:
7474 yield f"{ LLM_INPUT_MESSAGES } .{ idx } .{ MESSAGE_ROLE } " , message .role
75+ # tool_call_id links a role=tool result message back to the original tool call request
76+ if message .tool_call_id :
77+ yield f"{ LLM_INPUT_MESSAGES } .{ idx } .{ MESSAGE_TOOL_CALL_ID } " , message .tool_call_id
7578 if message .content :
7679 yield f"{ LLM_INPUT_MESSAGES } .{ idx } .{ MESSAGE_CONTENT } " , message .get_content_string ()
7780 if message .tool_calls :
@@ -85,9 +88,10 @@ def process_message(idx: int, message: Any) -> Iterator[Tuple[str, Any]]:
8588 f"{ LLM_INPUT_MESSAGES } .{ idx } .{ MESSAGE_TOOL_CALLS } .{ tool_call_index } .{ TOOL_CALL_FUNCTION_NAME } " ,
8689 _get_attr (function_obj , "name" ),
8790 )
91+ arguments = _get_attr (function_obj , "arguments" )
8892 yield (
8993 f"{ LLM_INPUT_MESSAGES } .{ idx } .{ MESSAGE_TOOL_CALLS } .{ tool_call_index } .{ TOOL_CALL_FUNCTION_ARGUMENTS_JSON } " ,
90- safe_json_dumps ( _get_attr ( function_obj , " arguments" , {}) ),
94+ json . dumps ( arguments ) if isinstance ( arguments , dict ) else ( arguments or "{}" ),
9195 )
9296
9397 messages = arguments .get ("messages" , [])
@@ -199,9 +203,12 @@ def _output_value_and_mime_type(output: str) -> Iterator[Tuple[str, Any]]:
199203 f"{ LLM_OUTPUT_MESSAGES } .{ i } .{ MESSAGE_TOOL_CALLS } .{ tool_call_index } .{ TOOL_CALL_FUNCTION_NAME } " ,
200204 _get_attr (function_obj , "name" ),
201205 )
206+ arguments = _get_attr (function_obj , "arguments" )
202207 yield (
203208 f"{ LLM_OUTPUT_MESSAGES } .{ i } .{ MESSAGE_TOOL_CALLS } .{ tool_call_index } .{ TOOL_CALL_FUNCTION_ARGUMENTS_JSON } " ,
204- safe_json_dumps (_get_attr (function_obj , "arguments" , {})),
209+ json .dumps (arguments )
210+ if isinstance (arguments , dict )
211+ else (arguments or "{}" ),
205212 )
206213
207214 yield OUTPUT_VALUE , safe_json_dumps (messages )
@@ -246,8 +253,8 @@ def _parse_model_output_stream(output: Any) -> Dict[str, Any]:
246253 non_indexed_tool_calls : list [Dict [str , Any ]] = []
247254
248255 for chunk in output :
249- if chunk .content :
250- accumulated_content += chunk .content
256+ if chunk .content is not None and chunk . content != "" :
257+ accumulated_content += str ( chunk .content )
251258
252259 if chunk .tool_calls :
253260 for tool_call in chunk .tool_calls :
@@ -306,6 +313,33 @@ def _parse_model_output_stream(output: Any) -> Dict[str, Any]:
306313 return {"messages" : messages }
307314
308315
316+ def _stream_output_messages (output : Dict [str , Any ]) -> Iterator [Tuple [str , Any ]]:
317+ for i , message in enumerate (output .get ("messages" , [])):
318+ if role := _get_attr (message , "role" ):
319+ yield f"{ LLM_OUTPUT_MESSAGES } .{ i } .{ MESSAGE_ROLE } " , role
320+ if content := _get_attr (message , "content" ):
321+ yield f"{ LLM_OUTPUT_MESSAGES } .{ i } .{ MESSAGE_CONTENT } " , content
322+ if tool_calls := _get_attr (message , "tool_calls" ):
323+ for j , tool_call in enumerate (tool_calls ):
324+ if tc_id := _get_attr (tool_call , "id" ):
325+ yield (
326+ f"{ LLM_OUTPUT_MESSAGES } .{ i } .{ MESSAGE_TOOL_CALLS } .{ j } .{ TOOL_CALL_ID } " ,
327+ tc_id ,
328+ )
329+ function_obj = _get_attr (tool_call , "function" , {})
330+ if fn_name := _get_attr (function_obj , "name" ):
331+ yield (
332+ f"{ LLM_OUTPUT_MESSAGES } .{ i } .{ MESSAGE_TOOL_CALLS } .{ j } .{ TOOL_CALL_FUNCTION_NAME } " ,
333+ fn_name ,
334+ )
335+ fn_args = _get_attr (function_obj , "arguments" )
336+ if fn_args is not None :
337+ yield (
338+ f"{ LLM_OUTPUT_MESSAGES } .{ i } .{ MESSAGE_TOOL_CALLS } .{ j } .{ TOOL_CALL_FUNCTION_ARGUMENTS_JSON } " ,
339+ fn_args ,
340+ )
341+
342+
309343class _ModelWrapper :
310344 def __init__ (self , tracer : trace_api .Tracer ) -> None :
311345 self ._tracer = tracer
@@ -407,6 +441,7 @@ def run_stream(
407441 output_message = json .dumps (output_message_dict )
408442 span .set_attribute (OUTPUT_MIME_TYPE , JSON )
409443 span .set_attribute (OUTPUT_VALUE , output_message )
444+ span .set_attributes (dict (_stream_output_messages (output_message_dict )))
410445
411446 # Find the final response with complete metrics (last one with response_usage)
412447 final_response_with_metrics = None
@@ -540,6 +575,7 @@ async def arun_stream(
540575 output_message = json .dumps (output_message_dict )
541576 span .set_attribute (OUTPUT_MIME_TYPE , JSON )
542577 span .set_attribute (OUTPUT_VALUE , output_message )
578+ span .set_attributes (dict (_stream_output_messages (output_message_dict )))
543579
544580 # Find the final response with complete metrics (last one with response_usage)
545581 final_response_with_metrics = None
@@ -597,6 +633,7 @@ async def arun_stream(
597633MESSAGE_FUNCTION_CALL_NAME = MessageAttributes .MESSAGE_FUNCTION_CALL_NAME
598634MESSAGE_NAME = MessageAttributes .MESSAGE_NAME
599635MESSAGE_ROLE = MessageAttributes .MESSAGE_ROLE
636+ MESSAGE_TOOL_CALL_ID = MessageAttributes .MESSAGE_TOOL_CALL_ID
600637MESSAGE_TOOL_CALLS = MessageAttributes .MESSAGE_TOOL_CALLS
601638
602639# mime types
0 commit comments