11from  __future__ import  annotations 
22
3+ import  base64 
34import  json 
45from  typing  import  Any 
56
67from  opentelemetry ._events  import  Event , EventLogger , EventLoggerProvider 
78from  opentelemetry .instrumentation .google_genai  import  GoogleGenAiSdkInstrumentor 
89from  opentelemetry .trace  import  get_current_span 
10+ from  typing_extensions  import  TypeAlias 
911
1012import  logfire 
1113from  logfire ._internal .utils  import  handle_internal_errors 
1214
15+ Part : TypeAlias  =  'dict[str, Any] | str' 
16+ 
17+ 
18+ def  default_json (x : Any ) ->  str :
19+     return  base64 .b64encode (x ).decode ('utf-8' ) if  isinstance (x , bytes ) else  x 
20+ 
1321
1422class  SpanEventLogger (EventLogger ):
1523    @handle_internal_errors  
@@ -18,18 +26,25 @@ def emit(self, event: Event) -> None:
1826        assert  isinstance (event .body , dict )
1927        body : dict [str , Any ] =  {** event .body }
2028        if  event .name  ==  'gen_ai.choice' :
21-             parts  =  body .pop ('content' )['parts' ]
22-             new_parts : list [dict [str , Any ] |  str ] =  []
23-             for  part  in  parts :
24-                 new_part : str  |  dict [str , Any ] =  {k : v  for  k , v  in  part .items () if  v  is  not   None }
25-                 if  list (new_part .keys ()) ==  ['text' ]:  # pragma: no branch 
26-                     new_part  =  new_part ['text' ]
27-                 new_parts .append (new_part )
28-             body ['message' ] =  {'role' : 'assistant' , 'content' : new_parts }
29+             if  'content'  in  body :  # pragma: no branch 
30+                 parts  =  body .pop ('content' )['parts' ]
31+                 new_parts  =  [transform_part (part ) for  part  in  parts ]
32+                 body ['message' ] =  {'role' : 'assistant' , 'content' : new_parts }
2933        else :
34+             if  'content'  in  body :  # pragma: no branch 
35+                 body ['content' ] =  transform_part (body ['content' ])
3036            body ['role' ] =  body .get ('role' , event .name .split ('.' )[1 ])
3137
32-         span .add_event (event .name , attributes = {'event_body' : json .dumps (body )})
38+         span .add_event (event .name , attributes = {'event_body' : json .dumps (body , default = default_json )})
39+ 
40+ 
41+ def  transform_part (part : Part ) ->  Part :
42+     if  isinstance (part , str ):
43+         return  part 
44+     new_part  =  {k : v  for  k , v  in  part .items () if  v  is  not   None }
45+     if  list (new_part .keys ()) ==  ['text' ]:
46+         return  new_part ['text' ]
47+     return  new_part 
3348
3449
3550class  SpanEventLoggerProvider (EventLoggerProvider ):
0 commit comments