27
27
logger = logging .getLogger (__name__ )
28
28
29
29
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
+
30
50
class Tracer :
31
51
"""Handles OpenTelemetry tracing.
32
52
@@ -267,7 +287,7 @@ def start_model_invoke_span(
267
287
"gen_ai.system" : "strands-agents" ,
268
288
"agent.name" : agent_name ,
269
289
"gen_ai.agent.name" : agent_name ,
270
- "gen_ai.prompt" : json .dumps (messages ),
290
+ "gen_ai.prompt" : json .dumps (messages , cls = JSONEncoder ),
271
291
}
272
292
273
293
if model_id :
@@ -290,7 +310,7 @@ def end_model_invoke_span(
290
310
error: Optional exception if the model call failed.
291
311
"""
292
312
attributes : Dict [str , AttributeValue ] = {
293
- "gen_ai.completion" : json .dumps (message ["content" ]),
313
+ "gen_ai.completion" : json .dumps (message ["content" ], cls = JSONEncoder ),
294
314
"gen_ai.usage.prompt_tokens" : usage ["inputTokens" ],
295
315
"gen_ai.usage.completion_tokens" : usage ["outputTokens" ],
296
316
"gen_ai.usage.total_tokens" : usage ["totalTokens" ],
@@ -314,7 +334,7 @@ def start_tool_call_span(
314
334
attributes : Dict [str , AttributeValue ] = {
315
335
"tool.name" : tool ["name" ],
316
336
"tool.id" : tool ["toolUseId" ],
317
- "tool.parameters" : json .dumps (tool ["input" ]),
337
+ "tool.parameters" : json .dumps (tool ["input" ], cls = JSONEncoder ),
318
338
}
319
339
320
340
# Add additional kwargs as attributes
@@ -340,8 +360,8 @@ def end_tool_call_span(
340
360
341
361
attributes .update (
342
362
{
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 ),
345
365
"tool.status" : status_str ,
346
366
}
347
367
)
@@ -370,7 +390,7 @@ def start_event_loop_cycle_span(
370
390
parent_span = parent_span if parent_span else event_loop_kwargs .get ("event_loop_parent_span" )
371
391
372
392
attributes : Dict [str , AttributeValue ] = {
373
- "gen_ai.prompt" : json .dumps (messages ),
393
+ "gen_ai.prompt" : json .dumps (messages , cls = JSONEncoder ),
374
394
"event_loop.cycle_id" : event_loop_cycle_id ,
375
395
}
376
396
@@ -399,11 +419,11 @@ def end_event_loop_cycle_span(
399
419
error: Optional exception if the cycle failed.
400
420
"""
401
421
attributes : Dict [str , AttributeValue ] = {
402
- "gen_ai.completion" : json .dumps (message ["content" ]),
422
+ "gen_ai.completion" : json .dumps (message ["content" ], cls = JSONEncoder ),
403
423
}
404
424
405
425
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 )
407
427
408
428
self ._end_span (span , attributes , error )
409
429
@@ -440,7 +460,7 @@ def start_agent_span(
440
460
attributes ["gen_ai.request.model" ] = model_id
441
461
442
462
if tools :
443
- tools_json = tools
463
+ tools_json = json . dumps ( tools , cls = JSONEncoder )
444
464
attributes ["agent.tools" ] = tools_json
445
465
attributes ["gen_ai.agent.tools" ] = tools_json
446
466
@@ -472,7 +492,7 @@ def end_agent_span(
472
492
if response :
473
493
attributes .update (
474
494
{
475
- "gen_ai.completion" : str (response ),
495
+ "gen_ai.completion" : json . dumps (response , cls = JSONEncoder ),
476
496
}
477
497
)
478
498
0 commit comments