§
    ~ŠtjH   ã                  ó¦   — 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d0d„Zd0d„Z	 d1d2d"„Zddd#œd3d'„Zd4d*„ZdS )5u'  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ÚgroqÚrawr   ÚreturnúOptional[str]c                ó  — | sdS t          | ¦  «                             ¦   «                              ¦   «         }|r|dk    rdS t          D ]
}||v r|c S Œ|                     dd¦  «        d                              dd¦  «        d         p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)r   ÚvalueÚaliass      úe/var/www/html/CA-Chatbot/venv/lib/python3.11/site-packages/langsmith/integrations/livekit/_helpers.pyÚnormalize_providerr!   (   s¢   € ð ð ØˆtÝ�‰HŒH�NŠNÑÔ×"Ò"Ñ$Ô$€EØð �E˜YÒ&Ð&ØˆtÝ"ð ð ˆØ�Eˆ>ˆ>ØˆLˆLˆLð à�;Š;�u˜aÑ Ô  Ô$×*Ò*¨3°Ñ2Ô2°1Ô5Ð=¸Ð=ó    ÚspanÚboolc                óX   — 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)r#   Úscopes     r    Úis_livekit_spanr+   <   s.   € õ �DÐ1°4Ñ8Ô8€EÝ�5˜& $Ñ'Ô'Õ+IÒIÐIr"   Úraw_tool_callsú
list[dict]c                óì   — g }| pdD ]l}t          |t          ¦  «        r+	 t          j        |¦  «        }n# t          j        $ r Y Œ>w xY wt          |t
          ¦  «        r|                     |¦  «         Œm|S )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)r,   Ú
tool_callsr   s      r    Úparse_tool_callsr7   G   s“   € ð
  €JØÐ# ð #ð #ˆÝ�c�3ÑÔð 	ðÝ”j ‘o”o��øÝÔ'ð ð ð Ø�ðøøøå�c�4Ñ Ô ð 	#Ø×Ò˜cÑ"Ô"Ð"øØÐs   Ÿ4´AÁAÚmetricsc                ó¢   — t          | ¦  «        }t          |t          ¦  «        r*|                     d¦  «        pi                      d¦  «        S dS )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   r0   r4   Úget©r8   Úparseds     r    Ú extract_provider_from_lk_metricsr@   X   sO   € õ # 7Ñ+Ô+€FÝ�&�$ÑÔð DØ—
’
˜:Ñ&Ô&Ð,¨"×1Ò1Ð2BÑCÔCÐCØˆ4r"   c                óÌ   — t          | ¦  «        }t          |t          ¦  «        r?|                     d¦  «        pi                      d¦  «        p|                     d¦  «        S dS )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.
    r:   Ú
model_nameNr<   r>   s     r    Úextract_model_from_lk_metricsrC   d   sk   € õ # 7Ñ+Ô+€FÝ�&�$ÑÔð 
Ø—
’
˜:Ñ&Ô&Ð,¨"×1Ò1°,Ñ?Ô?ð 
À6Ç:Â:ØñD
ô D
ð 	
ð ˆ4r"   r   úOptional[int]c                ó\   — t          | t          t          f¦  «        rt          | ¦  «        ndS )zFCoerce a numeric metrics value to ``int``, or ``None`` if not numeric.N)r0   ÚintÚfloat)r   s    r    Ú_as_intrH   r   s%   € å# E­Cµ¨<Ñ8Ô8ÐB�3ˆu‰:Œ:ˆ:¸dÐBr"   údict[str, Any]c                ó¢  — t          | ¦  «        }t          |t          ¦  «        si S i }t          |                     d¦  «        ¦  «        x}�||d<   t          |                     d¦  «        ¦  «        x}�||d<   t          |                     d¦  «        ¦  «        x}�||d<   t          |                     d¦  «        ¦  «        x}�d|i|d	<   |S )
z:Parse a ``lk.llm_metrics`` blob into ``set_usage`` kwargs.Úprompt_tokensNÚinput_tokensÚcompletion_tokensÚoutput_tokensÚtotal_tokensÚprompt_cached_tokensÚ
cache_readÚinput_token_details©r   r0   r4   rH   r=   )r8   r?   ÚusageÚvs       r    Úextract_llm_usagerV   w   sÜ   € å" 7Ñ+Ô+€FÝ�f�dÑ#Ô#ð Øˆ	Ø€EÝ�V—Z’Z Ñ0Ô0Ñ1Ô1Ð1ˆÐ>Ø !ˆˆnÑÝ�V—Z’ZÐ 3Ñ4Ô4Ñ5Ô5Ð5ˆÐBØ!"ˆˆoÑÝ�V—Z’Z Ñ/Ô/Ñ0Ô0Ð0ˆÐ=Ø !ˆˆnÑÝ�V—Z’ZÐ 6Ñ7Ô7Ñ8Ô8Ð8ˆÐEØ(4°aÐ'8ˆÐ#Ñ$Ø€Lr"   c                óf  — t          | ¦  «        }t          |t          ¦  «        si S i }dD ]+}t          |                     |¦  «        ¦  «        x}�|||<   Œ,|                     d¦  «        }i }t          |t          ¦  «        rRt          |                     d¦  «        ¦  «        x}�||d<   t          |                     d¦  «        ¦  «        x}�||d<   |r||d<   |                     d¦  «        }	t          |	t          ¦  «        r+t          |	                     d¦  «        ¦  «        x}�d|i|d<   |S )	zEParse a ``lk.realtime_model_metrics`` blob into ``set_usage`` kwargs.)rL   rN   rO   NrR   Úaudio_tokensÚaudioÚcached_tokensrQ   Úoutput_token_detailsrS   )
r8   r?   rT   ÚkeyÚcountÚ
in_detailsÚinput_detailrY   ÚcachedÚout_detailss
             r    Úextract_realtime_usagerb   ˆ   sG  € å" 7Ñ+Ô+€FÝ�f�dÑ#Ô#ð Øˆ	Ø€EØ@ð ð ˆÝ˜VŸZšZ¨™_œ_Ñ-Ô-Ð-ˆEÐ:ØˆE�#‰Jøà—’Ð1Ñ2Ô2€JØ#%€LÝ�*�dÑ#Ô#ð 0Ý˜ZŸ^š^¨NÑ;Ô;Ñ<Ô<Ð<ˆEÐIØ$)ˆL˜Ñ!Ý˜jŸnšn¨_Ñ=Ô=Ñ>Ô>Ð>ˆFÐKØ)/ˆL˜Ñ&Øð 4Ø'3ˆÐ#Ñ$à—*’*Ð3Ñ4Ô4€KÝ�+�tÑ$Ô$ð =Ý˜[Ÿ_š_¨^Ñ<Ô<Ñ=Ô=Ð=ˆEÐJØ-4°eÐ,<ˆEÐ(Ñ)Ø€Lr"   Úobjr4   Úprefixr   Ú_depthrF   c           	     óÄ  — i }|dk    r|S |                       ¦   «         D ]À\  }}|› d|› �}t          |t          ¦  «        r(|                     t	          |||dz   ¦  «        ¦  «         ŒIt          |t
          t          t          t          f¦  «        r|||<   Œwt          |t          t          f¦  «        r-|r+t          d„ |D ¦   «         ¦  «        r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  óf   K  — | ],}t          |t          t          t          t          f¦  «        V — Œ-d S )N)r0   r   rF   rG   r$   )Ú.0Úitems     r    ú	<genexpr>z7flatten_lk_attributes_to_ls_metadata.<locals>.<genexpr>¸   s5   è è € ÐLÐLÀ$•J˜t¥c­3µµtÐ%<Ñ=Ô=ÐLÐLÐLÐLÐLÐLr"   )Úitemsr0   r4   ÚupdateÚ$flatten_lk_attributes_to_ls_metadatar   rF   rG   r$   ÚlistÚtupleÚall)rc   rd   re   ÚflatÚkrU   r'   s          r    ro   ro   £   sõ   € ð €DØ�‚z€zØˆØ—	’	‘”ð !ð !‰ˆˆ1Øˆˆ˜1ˆˆˆÝ�a�ÑÔð 		!Ø�KŠKÕ<¸QÀÀfÈqÁjÑQÔQÑRÔRÐRÐRÝ˜�C¥¥e­TÐ2Ñ3Ô3ð 	!ØˆD�‰JˆJå�q�4¥˜-Ñ(Ô(ð	!àð	!õ ÐLÐLÈ!ÐLÑLÔLÑLÔLð	!õ
 ˜a™œˆD�‰JøØ€Kr"   ©Útool_call_idr'   Úcontentrv   r'   c               ó`   — d| dœ}|rt          |¦  «        |d<   |rt          |¦  «        |d<   |S )zFBuild a ``tool`` result message, with its call id / name when present.Útool©Úrolerw   rv   r'   )r   )rw   rv   r'   Úmsgs       r    Úbuild_tool_messager}   ¾   sG   € ð  ¨GÐ4Ð4€CØð 0Ý! ,Ñ/Ô/ˆˆNÑØð  Ý˜$‘i”iˆˆF‰Ø€Jr"   r{   Úeventc                ó8  — |j         pi }t          |                     d¦  «        pd¦  «        }| dk    r8t          ||                     d¦  «        |                     d¦  «        ¬¦  «        S | |dœ}t	          |                     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.
    rw   Ú ry   Úidr'   ru   rz   r6   )Ú
attributesr   r=   r}   r7   )r{   r~   Úattrsrw   r|   r6   s         r    Úbuild_message_from_eventr„   Í   s«   € ð ÔÐ" €EÝ�%—)’)˜IÑ&Ô&Ð,¨"Ñ-Ô-€GØˆv‚~€~Ý!Ø %§)¢)¨D¡/¤/¸¿	º	À&Ñ8IÔ8Ið
ñ 
ô 
ð 	
ð ¨'Ð2Ð2€CÝ! %§)¢)¨LÑ"9Ô"9Ñ:Ô:€JØð 'Ø&ˆˆLÑØ€Jr"   )r   r   r   r   )r#   r   r   r$   )r,   r   r   r-   )r8   r   r   r   )r   r   r   rD   )r8   r   r   rI   )r   )rc   r4   rd   r   re   rF   r   r4   )rw   r   rv   r   r'   r   r   r4   )r{   r   r~   r   r   r4   )Ú__doc__Ú
__future__r   r1   Útypingr   r   Ú"langsmith._internal.voice._helpersr   r)   r   r!   r+   r7   r@   rC   rH   rV   rb   ro   r}   r„   r/   r"   r    ú<module>r‰      sp  ððð ð #Ð "Ð "Ð "Ð "Ð "à €€€Ø  Ð  Ð  Ð  Ð  Ð  Ð  Ð  à DÐ DÐ DÐ DÐ DÐ Dð "2Ð ðÐ ð>ð >ð >ð >ð(Jð Jð Jð Jðð ð ð ð"	ð 	ð 	ð 	ðð ð ð ðCð Cð Cð Cð
ð ð ð ð"ð ð ð ð8 +,ðð ð ð ð ð< #'Øð	ð ð ð ð ð ðð ð ð ð ð r"   