ó
    üÞ j|&  ã                  ó$  • S r SSKJr  SSKrSSKrSSKJrJr  SSKJ	r	  \R                  " \5      rSrSrSS jrSS	 jrSS
 jrSS jrSS jrSS jrSS jrSS jr S       SS jjrSSS.       SS jjrS S jrS!S jrS"S jrS#S jrg)$u'  Small pure helpers for the LiveKit â†’ LangSmith span processor.

Split out of :mod:`langsmith.integrations.livekit.processor` to keep that module
focused on span dispatch and lifecycle: provider-slug normalization, LiveKit
span detection, and the tiny chat-message builders the handlers reuse.
é    )ÚannotationsN)ÚAnyÚOptional)Útry_parse_json_objectzlivekit-agents)
ÚopenaiÚ	anthropicÚgeminiÚgoogleÚdeepgramÚcartesiaÚ
elevenlabsÚcohereÚmistralÚgroqc                ó
  • U (       d  g[        U 5      R                  5       R                  5       nU(       a  US:X  a  g[         H  nX!;   d  M
  Us  $    UR	                  SS5      S   R	                  SS5      S   =(       d    S$ )a‚  Map a LiveKit provider (often an API host) to a LangSmith provider slug.

Matches a known provider slug as a substring (so ``api.openai.com`` and
``beta.anthropic.com`` resolve to ``openai`` / ``anthropic``); otherwise
returns the value's host, stripped of scheme/path. Returns ``None`` for
empty input or LiveKit's ``"unknown"`` placeholder, so we never stamp a
non-matching provider.
NÚunknownz://é   éÿÿÿÿÚ/r   )ÚstrÚstripÚlowerÚ_PROVIDER_ALIASESÚsplit)ÚrawÚvalueÚaliass      Úa/var/www/html/gaurav/venv/lib/python3.13/site-packages/langsmith/integrations/livekit/_helpers.pyÚnormalize_providerr   "   ss   € ö ØÜ�‹H�N‰NÓ×"Ñ"Ó$€EÞ�E˜YÓ&Øß"ˆØ�>ØŠLñ #ð �;‰;�u˜aÓ  Ñ$×*Ñ*¨3°Ó2°1Ñ5×=¸Ð=ó    c                óD   • [        U SS5      n[        USS5      [        :H  $ )a  Whether a span came from LiveKit's tracer (its instrumentation scope).

Used to gate root detection: only a parentless span emitted by LiveKit is
the conversation root. Named LiveKit spans are matched by name above and
don't need this; it guards the broad ``parent is None`` case alone.
Úinstrumentation_scopeNÚname)ÚgetattrÚ_LIVEKIT_INSTRUMENTATION_SCOPE)ÚspanÚscopes     r   Úis_livekit_spanr(   6   s(   € ô �DÐ1°4Ó8€EÜ�5˜& $Ó'Ô+IÑIÐIr    c                ó  • / nU =(       d    S HW  n[        U[        5      (       a   [        R                  " U5      n[        U[
        5      (       d  MF  UR                  U5        MY     U$ ! [        R                   a     Mt  f = f)z“Parse an event's ``tool_calls`` to OpenAI-shape dicts (JSON strings decoded).

Entries that are neither dicts nor JSON-object strings are dropped.
© )Ú
isinstancer   ÚjsonÚloadsÚJSONDecodeErrorÚdictÚappend)Úraw_tool_callsÚ
tool_callsr   s      r   Úparse_tool_callsr3   A   sy   € ð
  €JØ×# Ò#ˆÜ�cœ3×ÑðÜ—j’j “o�ô �cœ4× Ó Ø×Ñ˜cÖ"ñ $ð Ðøô	 ×'Ñ'ó Úðús   §A+Á+BÂBc                ó–   • [        U 5      n[        U[        5      (       a)  UR                  S5      =(       d    0 R                  S5      $ g)uÜ   Read the provider (``metadata.model_provider``) from a LiveKit metrics blob.

LiveKit reports it as the API-base-URL host (its OpenAI plugin â†’
``api.openai.com``); the caller normalizes it to a slug before setting it.
ÚmetadataÚmodel_providerN©r   r+   r/   Úget©ÚmetricsÚparseds     r   Ú extract_provider_from_lk_metricsr<   R   s>   € ô # 7Ó+€FÜ�&œ$×ÑØ—
‘
˜:Ó&×,¨"×1Ñ1Ð2BÓCÐCØr    c                óÆ   • [        U 5      n[        U[        5      (       aA  UR                  S5      =(       d    0 R                  S5      =(       d    UR                  S5      $ g)zßRead the model name (``metadata.model_name`` or ``model_name``) from a blob.

LiveKit doesn't always set ``gen_ai.request.model`` (notably on ``tts_request``),
so the model is recovered from the metrics blob as a fallback.
r5   Ú
model_nameNr7   r9   s     r   Úextract_model_from_lk_metricsr?   ^   sU   € ô # 7Ó+€FÜ�&œ$×ÑØ—
‘
˜:Ó&×,¨"×1Ñ1°,Ó?÷ 
À6Ç:Á:ØóD
ð 	
ð r    c                óR   • [        U [        [        45      (       a  [        U 5      $ S$ )zFCoerce a numeric metrics value to ``int``, or ``None`` if not numeric.N)r+   ÚintÚfloat)r   s    r   Ú_as_intrC   l   s!   € ä# E¬C´¨<×8Ñ8Œ3ˆu‹:ÐB¸dÐBr    c                ó\  • [        U 5      n[        U[        5      (       d  0 $ 0 n[        UR	                  S5      5      =nb  X2S'   [        UR	                  S5      5      =nb  X2S'   [        UR	                  S5      5      =nb  X2S'   [        UR	                  S5      5      =nb  SU0US'   U$ )	z:Parse a ``lk.llm_metrics`` blob into ``set_usage`` kwargs.Úprompt_tokensÚinput_tokensÚcompletion_tokensÚoutput_tokensÚtotal_tokensÚprompt_cached_tokensÚ
cache_readÚinput_token_details©r   r+   r/   rC   r8   )r:   r;   ÚusageÚvs       r   Úextract_llm_usagerP   q   s¶   € ä" 7Ó+€FÜ�fœd×#Ñ#Øˆ	Ø€EÜ�V—Z‘Z Ó0Ó1Ð1ˆÑ>Ø !ˆnÑÜ�V—Z‘ZÐ 3Ó4Ó5Ð5ˆÑBØ!"ˆoÑÜ�V—Z‘Z Ó/Ó0Ð0ˆÑ=Ø !ˆnÑÜ�V—Z‘ZÐ 6Ó7Ó8Ð8ˆÑEØ(4°aÐ'8ˆÐ#Ñ$Ø€Lr    c                ó$  • [        U 5      n[        U[        5      (       d  0 $ 0 nS H&  n[        UR	                  U5      5      =nc  M"  XBU'   M(     UR	                  S5      n0 n[        U[        5      (       aB  [        UR	                  S5      5      =nb  XvS'   [        UR	                  S5      5      =nb  X†S'   U(       a  XbS'   UR	                  S5      n	[        U	[        5      (       a$  [        U	R	                  S5      5      =nb  SU0US'   U$ )zEParse a ``lk.realtime_model_metrics`` blob into ``set_usage`` kwargs.)rF   rH   rI   rL   Úaudio_tokensÚaudioÚcached_tokensrK   Úoutput_token_detailsrM   )
r:   r;   rN   ÚkeyÚcountÚ
in_detailsÚinput_detailrS   ÚcachedÚout_detailss
             r   Úextract_realtime_usager\   ‚   s  € ä" 7Ó+€FÜ�fœd×#Ñ#Øˆ	Ø€EÛ@ˆÜ˜VŸZ™Z¨›_Ó-Ð-ˆEÓ:Ø�#‹Jñ Að —‘Ð1Ó2€JØ#%€LÜ�*œd×#Ñ#Ü˜ZŸ^™^¨NÓ;Ó<Ð<ˆEÑIØ$)˜Ñ!Ü˜jŸn™n¨_Ó=Ó>Ð>ˆFÑKØ)/˜Ñ&ÞØ'3Ð#Ñ$à—*‘*Ð3Ó4€KÜ�+œt×$Ñ$Ü˜[Ÿ_™_¨^Ó<Ó=Ð=ˆEÑJØ-4°eÐ,<ˆEÐ(Ñ)Ø€Lr    c           	     ó²  • 0 nUS:”  a  U$ U R                  5        H¸  u  pEU SU 3n[        U[        5      (       a   UR                  [	        XVUS-   5      5        MA  [        U[
        [        [        [        45      (       a  XSU'   Ml  [        U[        [        45      (       d  M‰  U(       d  M’  [        S U 5       5      (       d  M«  [        U5      X6'   Mº     U$ )u  Flatten a JSON-object blob's scalar leaves to ``{prefix_key: value}``.

Recurses into nested dicts (capped at depth 4); keeps scalars and lists of
scalars, dropping anything else. Returns a flat dict the caller stamps onto
the span â€” so this stays agnostic to the span itself.
é   Ú_r   c              3  ó`   #   • U H%  n[        U[        [        [        [        45      v •  M'     g 7f©N)r+   r   rA   rB   Úbool)Ú.0Úitems     r   Ú	<genexpr>Ú7flatten_lk_attributes_to_ls_metadata.<locals>.<genexpr>²   s#   é € ÐLÉ!À$”J˜t¤c¬3´´tÐ%<×=Ð=Ê!ùs   ‚,.)Úitemsr+   r/   ÚupdateÚ$flatten_lk_attributes_to_ls_metadatar   rA   rB   rb   ÚlistÚtupleÚall)ÚobjÚprefixÚ_depthÚflatÚkrO   r#   s          r   ri   ri   �   s±   € ð €DØ�ƒzØˆØ—	‘	–‰ˆØ�˜˜1˜#ˆˆÜ�aœ×ÑØ�K‰KÔ<¸QÀfÈqÁjÓQÖRÜ˜œC¤¤e¬TÐ2×3Ñ3Ø�‹Jä�qœ4¤˜-×(Ó(ß�ÜÑLÉ!ÓL×LÓLä˜a›ˆD‹Jñ ð €Kr    ©Útool_call_idr#   c               ód   • SU S.nU(       a  [        U5      US'   U(       a  [        U5      US'   U$ )zFBuild a ``tool`` result message, with its call id / name when present.Útool©ÚroleÚcontentrs   r#   )r   )rx   rs   r#   Úmsgs       r   Úbuild_tool_messagerz   ¸   s5   € ð  ¨GÑ4€CÞÜ! ,Ó/ˆˆNÑÞÜ˜$“iˆˆF‰Ø€Jr    c                ó   • SSU SXS.S./S.$ )z4Build an assistant message containing one tool call.Ú	assistantÚ Úfunction)r#   Ú	arguments)ÚidÚtyper~   )rw   rx   r2   r*   )Úcall_idr#   r   s      r   Ú!build_assistant_tool_call_messagerƒ   Ç   s,   € ð Øð Ø"Ø%)ÑBñð
ñ
ð 
r    c                ó$  • UR                   =(       d    0 n[        UR                  S5      =(       d    S5      nU S:X  a(  [        X2R                  S5      UR                  S5      S9$ XS.n[	        UR                  S5      5      nU(       a  XTS'   U$ )	u  Build a chat message dict from a LiveKit ``gen_ai.*`` span event.

``role`` is authoritative (the caller derives it from the event name). Tool
calls are forwarded in their OpenAI shape (JSON-string entries decoded) â€”
LangSmith's ingester renders them directly.
rx   r}   ru   r€   r#   rr   rv   r2   )Ú
attributesr   r8   rz   r3   )rw   ÚeventÚattrsrx   ry   r2   s         r   Úbuild_message_from_eventrˆ   Ö   sƒ   € ð ×Ñ×" €EÜ�%—)‘)˜IÓ&×,¨"Ó-€GØˆvƒ~Ü!Ø§)¡)¨D£/¸¿	¹	À&Ó8Iñ
ð 	
ð Ñ2€CÜ! %§)¡)¨LÓ"9Ó:€JÞØ&ˆLÑØ€Jr    c                ó2   • SR                  S U  5       5      $ )zHFlatten a ``ChatMessage.content`` list to text, dropping non-text parts.Ú
c              3  óR   #   • U H  n[        U[        5      (       d  M  Uv •  M      g 7fra   )r+   r   )rc   Úparts     r   re   Ú#_content_to_text.<locals>.<genexpr>ì   s   é € ÐG¡g˜d´¸DÄ#×1F—T‘T¢gùs   ‚'ž	')Újoin)rx   s    r   Ú_content_to_textr�   ê   s   € à�9‰9ÑG¡gÓGÓGÐGr    c           	     ó¼  •  U R                  SSSSS9S   n/ nU H—  nUS   nUS:X  a1  US	   n[	        US
   5      nU(       a  UR                  XVS.5        M=  M?  US:X  a'  UR                  [        US   US   US   5      5        Ml  US:X  d  Mt  UR                  [        US   US   US   S95        M™     U$ ! [         a    [        R                  SSS9  / s $ f = f)a  Convert a LiveKit ``ChatContext`` into LangSmith chat messages.

Keeps LiveKit's conversation order, including instructions, tool calls, and
tool outputs. Returns ``[]`` if LiveKit cannot serialize the history, so
export falls back to the span-derived transcript.
FT)Úexclude_timestampÚexclude_function_callÚexclude_metricsÚexclude_config_updaterg   zslangsmith voice: could not read the session report's chat history; falling back to the transcript built from spans.)Úexc_infor�   Úmessagerw   rx   rv   Úfunction_callr‚   r#   r   Úfunction_call_outputÚoutputrr   )Úto_dictÚ	ExceptionÚloggerÚwarningr�   r0   rƒ   rz   )Úchat_historyrg   Úmessagesrd   Úkindrw   Útexts          r   Ú build_messages_from_chat_historyr¢   ï   s  € ðØ×$Ñ$Ø#Ø"'Ø Ø"&ð	 %ð 
ð
 ñˆð €HÛˆØ�F‰|ˆØ�9ÓØ˜‘<ˆDÜ# D¨¡OÓ4ˆDÞØ—‘¨Ñ ?Ö@ñ à�_Ó$Ø�O‰OÜ1Ø˜‘O T¨&¡\°4¸Ñ3Dóöð
 Ð+Õ+Ø�O‰OÜ"Ø˜‘NØ!% i¡Ø˜f™ñöñ ð* €Oøô= ó Ü�‰ð?àð 	ñ 	
ð
 Š	ðús   ‚B8 Â8 CÃC)r   r   ÚreturnúOptional[str])r&   r   r£   rb   )r1   r   r£   ú
list[dict])r:   r   r£   r¤   )r   r   r£   zOptional[int])r:   r   r£   zdict[str, Any])r   )rm   r/   rn   r   ro   rA   r£   r/   )rx   r   rs   r¤   r#   r¤   r£   r/   )r‚   r   r#   r   r   r   r£   r/   )rw   r   r†   r   r£   r/   )rx   z	list[Any]r£   r   )rž   r   r£   r¥   )Ú__doc__Ú
__future__r   r,   ÚloggingÚtypingr   r   Ú"langsmith._internal.voice._helpersr   Ú	getLoggerÚ__name__rœ   r%   r   r   r(   r3   r<   r?   rC   rP   r\   ri   rz   rƒ   rˆ   r�   r¢   r*   r    r   Ú<module>r­      sÕ   ðñõ #ã Û ß  å Dà	×	Ò	˜8Ó	$€à!1Ð ðÐ ô>ô(Jôô"	ôôCô
ô"ð8 +,ðØ	ðØðØ$'ðà	õð< #'Øñ	Øðð  ðð ð	ð
 
õôôô(Hõ
,r    