2727logger = logging .getLogger (__name__ )
2828
2929
30+ class JSONEncoder (json .JSONEncoder ):
31+ """Custom JSON encoder that handles non-serializable types."""
32+
33+ def default (self , obj : Any ) -> Any :
34+ """Handle non-serializable types.
35+
36+ Args:
37+ obj: The object to serialize
38+
39+ Returns:
40+ A JSON serializable version of the object
41+ """
42+ value = ""
43+ try :
44+ value = super ().default (obj )
45+ except TypeError :
46+ value = "<replaced>"
47+ return value
48+
49+
3050class Tracer :
3151 """Handles OpenTelemetry tracing.
3252
@@ -267,7 +287,7 @@ def start_model_invoke_span(
267287 "gen_ai.system" : "strands-agents" ,
268288 "agent.name" : agent_name ,
269289 "gen_ai.agent.name" : agent_name ,
270- "gen_ai.prompt" : json .dumps (messages ),
290+ "gen_ai.prompt" : json .dumps (messages , cls = JSONEncoder ),
271291 }
272292
273293 if model_id :
@@ -290,7 +310,7 @@ def end_model_invoke_span(
290310 error: Optional exception if the model call failed.
291311 """
292312 attributes : Dict [str , AttributeValue ] = {
293- "gen_ai.completion" : json .dumps (message ["content" ]),
313+ "gen_ai.completion" : json .dumps (message ["content" ], cls = JSONEncoder ),
294314 "gen_ai.usage.prompt_tokens" : usage ["inputTokens" ],
295315 "gen_ai.usage.completion_tokens" : usage ["outputTokens" ],
296316 "gen_ai.usage.total_tokens" : usage ["totalTokens" ],
@@ -314,7 +334,7 @@ def start_tool_call_span(
314334 attributes : Dict [str , AttributeValue ] = {
315335 "tool.name" : tool ["name" ],
316336 "tool.id" : tool ["toolUseId" ],
317- "tool.parameters" : json .dumps (tool ["input" ]),
337+ "tool.parameters" : json .dumps (tool ["input" ], cls = JSONEncoder ),
318338 }
319339
320340 # Add additional kwargs as attributes
@@ -340,8 +360,8 @@ def end_tool_call_span(
340360
341361 attributes .update (
342362 {
343- "tool.result" : json .dumps (tool_result .get ("content" )),
344- "gen_ai.completion" : json .dumps (tool_result .get ("content" )),
363+ "tool.result" : json .dumps (tool_result .get ("content" ), cls = JSONEncoder ),
364+ "gen_ai.completion" : json .dumps (tool_result .get ("content" ), cls = JSONEncoder ),
345365 "tool.status" : status_str ,
346366 }
347367 )
@@ -370,7 +390,7 @@ def start_event_loop_cycle_span(
370390 parent_span = parent_span if parent_span else event_loop_kwargs .get ("event_loop_parent_span" )
371391
372392 attributes : Dict [str , AttributeValue ] = {
373- "gen_ai.prompt" : json .dumps (messages ),
393+ "gen_ai.prompt" : json .dumps (messages , cls = JSONEncoder ),
374394 "event_loop.cycle_id" : event_loop_cycle_id ,
375395 }
376396
@@ -399,11 +419,11 @@ def end_event_loop_cycle_span(
399419 error: Optional exception if the cycle failed.
400420 """
401421 attributes : Dict [str , AttributeValue ] = {
402- "gen_ai.completion" : json .dumps (message ["content" ]),
422+ "gen_ai.completion" : json .dumps (message ["content" ], cls = JSONEncoder ),
403423 }
404424
405425 if tool_result_message :
406- attributes ["tool.result" ] = json .dumps (tool_result_message ["content" ])
426+ attributes ["tool.result" ] = json .dumps (tool_result_message ["content" ], cls = JSONEncoder )
407427
408428 self ._end_span (span , attributes , error )
409429
@@ -440,7 +460,7 @@ def start_agent_span(
440460 attributes ["gen_ai.request.model" ] = model_id
441461
442462 if tools :
443- tools_json = tools
463+ tools_json = json . dumps ( tools , cls = JSONEncoder )
444464 attributes ["agent.tools" ] = tools_json
445465 attributes ["gen_ai.agent.tools" ] = tools_json
446466
@@ -472,7 +492,7 @@ def end_agent_span(
472492 if response :
473493 attributes .update (
474494 {
475- "gen_ai.completion" : str (response ),
495+ "gen_ai.completion" : json . dumps (response , cls = JSONEncoder ),
476496 }
477497 )
478498
0 commit comments