Ë
    ³ŒjH   ã                  óÀ   — d Z ddlmZ ddlZddlmZmZ ddlmZ dZ	dZ
dd„Zdd	„Zdd
„Zdd„Zdd„Zdd„Zdd„Zdd„Z	 d	 	 	 	 	 	 	 dd„Zdddœ	 	 	 	 	 	 	 dd„Zdd„Zy)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                óä   — | syt        | «      j                  «       j                  «       }|r|dk(  ryt        D ]
  }||v sŒ|c S  |j	                  dd«      d   j	                  dd«      d   x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      úq/var/www/html/Fitness-lenito-AI-main/venv/lib/python3.12/site-packages/langsmith/integrations/livekit/_helpers.pyÚnormalize_providerr   (   su   € ñ ØÜ�‹H�N‰NÓ×"Ñ"Ó$€EÙ�E˜YÒ&Øß"ˆØ�EŠ>ØŠLð #ð �;‰;�u˜aÓ  Ñ$×*Ñ*¨3°Ó2°1Ñ5Ò=¸Ð=ó    c                óD   — t        | dd«      }t        |dd«      t        k(  S )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(   <   s(   € ô �DÐ1°4Ó8€EÜ�5˜& $Ó'Ô+IÑIÐIr    c                óâ   — g }| xs dD ]J  }t        |t        «      r	 t        j                  |«      }t        |t
        «      sŒ:|j                  |«       ŒL |S # t        j                  $ r Y Œdw xY w)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   G   ss   € ð
  €JØÒ# Ò#ˆÜ�cœ3ÔðÜ—j‘j “o�ô �cœ4Õ Ø×Ñ˜cÕ"ð $ð Ðøô	 ×'Ñ'ò Ùðús   �AÁA.Á-A.c                ó‚   — t        | «      }t        |t        «      r$|j                  d«      xs i j                  d«      S y)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<   X   s;   € ô # 7Ó+€FÜ�&œ$ÔØ—
‘
˜:Ó&Ò,¨"×1Ñ1Ð2BÓCÐCØr    c                ó¨   — t        | «      }t        |t        «      r7|j                  d«      xs i j                  d«      xs |j                  d«      S y)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?   d   sR   € ô # 7Ó+€FÜ�&œ$ÔØ—
‘
˜:Ó&Ò,¨"×1Ñ1°,Ó?ò 
À6Ç:Á:ØóD
ð 	
ð r    c                óH   — t        | t        t        f«      rt        | «      S dS )zFCoerce a numeric metrics value to ``int``, or ``None`` if not numeric.N)r+   ÚintÚfloat)r   s    r   Ú_as_intrC   r   s   € ä# E¬C´¨<Ô8Œ3ˆu‹:ÐB¸dÐBr    c                óP  — t        | «      }t        |t        «      si S i }t        |j	                  d«      «      x}�||d<   t        |j	                  d«      «      x}�||d<   t        |j	                  d«      «      x}�||d<   t        |j	                  d«      «      x}�d|i|d<   |S )	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   w   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                óö  — t        | «      }t        |t        «      si S i }dD ]$  }t        |j	                  |«      «      x}€Œ |||<   Œ& |j	                  d«      }i }t        |t        «      rBt        |j	                  d«      «      x}�||d<   t        |j	                  d«      «      x}�||d<   |r||d<   |j	                  d«      }	t        |	t        «      r#t        |	j	                  d«      «      x}�d|i|d<   |S )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Ñ:ØˆE�#ŠJð Að —‘Ð1Ó2€JØ#%€LÜ�*œdÔ#Ü˜ZŸ^™^¨NÓ;Ó<Ð<ˆEÐIØ$)ˆL˜Ñ!Ü˜jŸn™n¨_Ó=Ó>Ð>ˆFÐKØ)/ˆL˜Ñ&ÙØ'3ˆÐ#Ñ$à—*‘*Ð3Ó4€KÜ�+œtÔ$Ü˜[Ÿ_™_¨^Ó<Ó=Ð=ˆEÐJØ-4°eÐ,<ˆEÐ(Ñ)Ø€Lr    c           	     óx  — i }|dkD  r|S | j                  «       D ]�  \  }}|› d|› �}t        |t        «      r |j                  t	        |||dz   «      «       Œ=t        |t
        t        t        t        f«      r|||<   Œct        |t        t        f«      sŒz|sŒ}t        d„ |D «       «      sŒ�t        |«      ||<   ŒŸ |S )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  ó\   K  — | ]$  }t        |t        t        t        t        f«      –— Œ& y ­w)N)r+   r   rA   rB   Úbool)Ú.0Úitems     r   Ú	<genexpr>z7flatten_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   ra   ÚlistÚtupleÚall)ÚobjÚprefixÚ_depthÚflatÚkrO   r#   s          r   rg   rg   £   s«   € ð €DØ�‚zØˆØ—	‘	–‰ˆˆ1Ø�˜˜1˜#ˆˆÜ�aœÔØ�K‰KÔ<¸QÀÀfÈqÁjÓQÕRÜ˜œC¤¤e¬TÐ2Ô3ØˆD�ŠJä�qœ4¤˜-Õ(ÚÜÑLÉ!ÓLÕLä˜a›ˆD�ŠJð ð €Kr    ©Útool_call_idr#   c               óP   — d| dœ}|rt        |«      |d<   |rt        |«      |d<   |S )zFBuild a ``tool`` result message, with its call id / name when present.Útool©ÚroleÚcontentrq   r#   )r   )rv   rq   r#   Úmsgs       r   Úbuild_tool_messagerx   ¾   s5   € ð  ¨GÑ4€CÙÜ! ,Ó/ˆˆNÑÙÜ˜$“iˆˆF‰Ø€Jr    c                ó  — |j                   xs i }t        |j                  d«      xs d«      }| dk(  r,t        ||j                  d«      |j                  d«      ¬«      S | |dœ}t	        |j                  d«      «      }|r||d<   |S )	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.
    rv   Ú rs   Úidr#   rp   rt   r2   )Ú
attributesr   r8   rx   r3   )ru   ÚeventÚattrsrv   rw   r2   s         r   Úbuild_message_from_eventr   Í   s‰   € ð ×ÑÒ" €EÜ�%—)‘)˜IÓ&Ò,¨"Ó-€GØˆv‚~Ü!Ø %§)¡)¨D£/¸¿	¹	À&Ó8Iô
ð 	
ð ¨'Ñ2€CÜ! %§)¡)¨LÓ"9Ó:€JÙØ&ˆˆLÑØ€Jr    )r   r   ÚreturnúOptional[str])r&   r   r€   ra   )r1   r   r€   z
list[dict])r:   r   r€   r�   )r   r   r€   zOptional[int])r:   r   r€   zdict[str, Any])r   )rk   r/   rl   r   rm   rA   r€   r/   )rv   r   rq   r�   r#   r�   r€   r/   )ru   r   r}   r   r€   r/   )Ú__doc__Ú
__future__r   r,   Útypingr   r   Ú"langsmith._internal.voice._helpersr   r%   r   r   r(   r3   r<   r?   rC   rP   r\   rg   rx   r   r*   r    r   Ú<module>r†      s´   ðñõ #ã ß  å Dð "2Ð ðÐ ó>ó(Jóó"	óóCó
ó"ð8 +,ðØ	ðØðØ$'ðà	óð< #'Øñ	Øðð  ðð ð	ð
 
óôr    