Ë
    tPêjÖ5  ã                   ó   — U d Z ddlmZ ddlmZmZ ddlmZ ddlm	Z	 ddl
mZmZ ddlmZmZmZmZmZmZ ddlmZ  e«       Zeed	<    ed
d¬«      Zed   ed<   deddfd„Zd,d„Z edd¬«      Zed   ed<   	 	 	 	 d-d„Zd.d„Z edd¬«      Zed   ed<   deddfd„Z d/d„Z!d,d„Z"d0d„Z#d1dee$e$f   d edz  defd!„Z%d1d edz  de&e$e$f   fd"„Z'd1ded edz  defd#„Z(d1d$edz  defd%„Z)defd&„Z*	 d1	 	 	 d2d'„Z+d(ede,fd)„Z-d*ee$e$f   dedz  fd+„Z.y)3z Trace-context + Baggage helpers.é    )ÚMapping)Ú
ContextVarÚToken)ÚFinal)Úbaggage)ÚContextÚget_current)ÚLinkÚNonRecordingSpanÚSpanÚSpanContextÚget_current_spanÚset_span_in_context)ÚTraceContextTextMapPropagatorÚ_PROPAGATORÚlitellm_otel_request_root_spanN)ÚdefaultzContextVar[Span | None]Ú_request_root_spanÚspanÚreturnc                 óF   — t        | «      rt        j                  | «       yy)u  Anchor the request's root (server) span for explicit child parenting.

    No-ops for a non-recordable span so a bad capture can never replace a good one
    with a phantom parent. Idempotent â€” the proxy captures the same server span at
    more than one entry point.
    N)Úis_recordable_spanr   Úset©r   s    úo/home/oem/CyberBrain26-unified/.venv/lib/python3.12/site-packages/litellm/integrations/otel/plumbing/context.pyÚset_request_root_spanr   )   s   € ô ˜$ÔÜ×Ñ˜tÕ$ð  ó    c                  óH   — t         j                  «       } t        | «      r| S dS )zDThe anchored request root span, or ``None`` outside a proxy request.N)r   Úgetr   r   s    r   Úrequest_root_spanr    4   s"   € ä$×(Ñ(Ó*€DÜ% dÔ+ˆ4Ð5°Ð5r   Ú&litellm_otel_mcp_message_trace_carrierz$ContextVar[Mapping[str, str] | None]Ú_mcp_message_trace_carrierc                 ó,   — t         j                  | «      S )zæStash the current MCP message's propagated trace-context carrier.

    Returns the reset token; the caller must reset it once the message is handled
    so the carrier never leaks to the next message on the same session task.
    )r"   r   )Úcarriers    r   Úset_mcp_message_trace_carrierr%   D   s   € ô &×)Ñ)¨'Ó2Ð2r   c                 ó.   — t         j                  | «       y ©N)r"   Úreset©Útokens    r   Úreset_mcp_message_trace_carrierr+   O   s   € Ü×$Ñ$ UÕ+r   Ú'litellm_otel_mcp_message_transport_spanÚ_mcp_message_transport_spanúToken[Span | None]c                 ó¤   — t        | t        «      rt        | «      r| nd}|�|j                  «       rt	        |«       t
        j                  |«      S )u  Publish the transport span of the request carrying the current MCP message.

    Also re-anchors the request root, so everything else the message emits or stamps
    â€” the identity attributes seeded onto the server span, a guardrail span, a
    proxy-level failure â€” lands on this request instead of on the one that opened
    the session. The MCP SDK dispatches each message on its own task, so the anchor
    is scoped to this message; the handler re-publishes it for the next one either
    way. Only a transport still open for writes is anchored: replacing the anchor
    with a request that already answered would just move the dropped writes from one
    finished span to another.

    Takes ``object`` because the gateway reads it back out of the ASGI scope, whose
    values are untyped; anything that is not a usable span is stored as ``None``
    rather than trusted.

    Returns the reset token; the caller must reset it once the message is handled
    so the transport never leaks to the next message on the same session task.
    N)Ú
isinstancer   r   Úis_recordingr   r-   r   )r   Ú	transports     r   Úset_mcp_message_transport_spanr3   d   sG   € ô&  *¨$´Ô5Ô:LÈTÔ:R‘tÐX\€IØÐ ×!7Ñ!7Ô!9Ü˜iÔ(Ü&×*Ñ*¨9Ó5Ð5r   c                 ó.   — t         j                  | «       y r'   )r-   r(   r)   s    r   Ú reset_mcp_message_transport_spanr5   }   s   € Ü×%Ñ% eÕ,r   c                  óT   — t         j                  «       } | �| j                  «       sy| S )uŽ  The published transport span, only while it is still open for writes.

    Recording â€” not merely valid â€” is the bar here because this span is the target
    of ``error.*`` stamping from another task, and the publisher's validity check
    cannot speak for a span that has since ended. A finished span keeps a valid
    context forever, so it would otherwise be handed back for a write the SDK then
    refuses. The POST carrying a ``tools/call`` stays open until the result is
    written, so it is recording for the life of the call; a notification POST can
    answer first, and this returns ``None`` for it rather than writing into the void.
    N)r-   r   r1   r   s    r   Úmcp_message_transport_spanr7   �   s*   € ô .×1Ñ1Ó3€DØ€|˜4×,Ñ,Ô.ØØ€Kr   c                  óŠ   — t         j                  «       } | �| j                  «       S t        «       }|�|j                  «       S dS )aê  The transport span an MCP message span should attach to.

    Prefers the transport the gateway published for this specific message; falls
    back to the ambient request anchor for paths that emit an MCP span on the
    request task itself (the REST MCP endpoints). Parenting needs only the
    immutable context, and unlike ``mcp_message_transport_span`` it stays correct
    against a transport that has already finished, so this does not require the
    span to still be recording.
    N)r-   r   Úget_span_contextr    )Ú	publishedr   s     r   Ú_mcp_transport_span_contextr;   ’   sH   € ô 3×6Ñ6Ó8€IØÐØ×)Ñ)Ó+Ð+Ü#Ó%€DØ&*Ð&6ˆ4× Ñ Ó"Ð@¸DÐ@r   ÚvaluesÚcontextc                 óŠ   — |}| j                  «       D ]  \  }}t        j                  |||¬«      }Œ |�|S |xs
 t        «       S )z6Return a context with ``values`` written into Baggage.©r=   )Úitemsr   Úset_baggager	   )r<   r=   ÚctxÚkeyÚvalues        r   Úset_request_baggagerE   £   sJ   € à
€CØ—l‘l“nò ;‰
ˆˆUÜ×!Ñ! # u°cÔ:‰ð;à�/ˆ3ÐA¨Ò(@´;³=ÐAr   c                 óŽ   — t        j                  | «      j                  «       D ��ci c]  \  }}|t        |«      “Œ c}}S c c}}w )z.All Baggage entries on ``context`` as strings.)r   Úget_allr@   Ústr)r=   rC   rD   s      r   Úget_baggage_attributesrI   «   s4   € ä.5¯o©o¸gÓ.F×.LÑ.LÓ.N×O¡
  UˆC”�U“‰OÓOÐOùÓOs   §Ac                 ó   — t        | |¬«      S )zDA context with ``span`` as the active span (for explicit parenting).r?   )r   )r   r=   s     r   Úcontext_from_spanrK   °   s   € ä˜t¨WÔ5Ð5r   Úthreadedc                 ór   — t        «       }t        | «      r!t        t        |«      «      st        | |¬«      }|S )uÙ  The context a child span should parent under.

    Ambient-first: parent to the active OTel context (the server span, restored
    by the logging worker or active in the request task), falling back to a span
    passed explicitly (``threaded``) only when the ambient context has no
    recordable span â€” e.g. a background service call with no request on the
    stack. When neither is recordable the ambient context is returned unchanged,
    so the span starts a new root trace.

    Only service/DB spans pass ``threaded`` (the ``parent_otel_span`` handed to
    the service hook). Request-level spans â€” the LLM call and guardrails â€” are
    created where the server span is genuinely ambient, so they never need it.
    r?   )r	   r   r   rK   )rL   rB   s     r   Úresolve_parent_contextrN   µ   s3   € ô ‹-€CÜ˜(Ô#Ô,>Ô?OÐPSÓ?TÔ,UÜ °#Ô6ˆØ€Jr   c                  óD   — t        «       } | �t        | «      S t        «       S )u­  The parent context for a request-level span (the LLM call, a guardrail).

    These are direct children of the request's root server span â€” siblings of the
    ``auth`` phase span and of each other, never nested under whatever span is
    momentarily active. So prefer the explicitly anchored root span; fall back to
    ambient context only when there is no anchor (the SDK / no-proxy path), where
    the span legitimately starts its own root trace.

    Unlike :func:`resolve_parent_context` (used by DB/service spans, which DO want
    to nest under the active phase span, e.g. an auth DB lookup under ``auth``),
    this never returns the active span when an anchor exists.
    )r    rK   r	   )Úroots    r   Úresolve_request_span_contextrQ   É   s%   € ô $Ó%€DØÐÜ  Ó&Ð&Ü‹=Ðr   c                 óZ  — | �| nt         j                  «       }t        t        j	                  t        |xs i «      t        «       ¬«      «      }t        |«      rt        |j                  «       «      fnd}t        «       }|€t        «       |fS t        t        |«      t        «       ¬«      |fS )uâ  Parent context + links for an MCP message span.

    The span always nests under the transport span of the request carrying this
    message, so a tool call and the ``POST`` that carried it stay in one trace.
    The transport comes from :func:`_mcp_transport_span_context`, which is the
    *current message's* POST rather than whatever request happened to open the
    session, so a long-lived session does not glue every message under its first
    request.

    When the client propagates W3C trace context in the request's ``params._meta``
    (SEP-414), that remote context is recorded as a span *link*, never the parent.
    The OTel GenAI MCP semconv prefers the inverse (remote parent, transport link),
    but the gateway's tracing backend only ever receives the gateway's half of such
    a trace: parenting into the client's trace id roots the span in a trace whose
    root span never reaches the backend, so the span is unreachable from the trace
    view and the transport transaction shows a dangling link (observed with
    clients that propagate synthetic trace ids). Anchoring to the gateway's own
    request and linking the client's context keeps every trace renderable while
    preserving the client-side correlation.

    With no transport at all the span starts its own root trace, still carrying
    the link â€” the client context is only ever a link, so this event keeps one
    shape everywhere. Both returned contexts are built on an explicitly empty
    base, so ambient (stale session) state can never leak in, and the span
    inherits the transport's sampling decision exactly like every other
    request-level span â€” a client's sampled flag neither forces nor suppresses
    recording.

    Only trace context (``traceparent``/``tracestate``) is extracted, never the
    client's W3C Baggage: ``params._meta`` is caller-controlled, and the otel
    baggage processor stamps allowlisted baggage keys (``litellm.team.id``,
    ``litellm.metadata.*``, ...) onto the span as attributes, so honoring remote
    baggage would let a client spoof a span's identity attribution. The base context
    for extraction is explicitly empty so an absent or malformed ``traceparent`` can
    never fall through to the ambient (stale session) span.
    r?   © )r"   r   r   r   ÚextractÚdictr   r   r
   r9   r;   rK   r   )r$   ÚsourceÚ
propagatedÚlinksr2   s        r   Úresolve_mcp_span_contextrY   Ü   s˜   € ðN  'Ð2‘GÔ8R×8VÑ8VÓ8X€FÜ(¬×)<Ñ)<¼TÀ&Â,ÈBÓ=OÔY`ÓYbÐ)<Ó)cÓd€JÜ=OÐPZÔ=[”D˜×4Ñ4Ó6Ó7Ñ9Ðac€EÜ2Ó4€IØÐÜ‹y˜%ÐÐÜÔ-¨iÓ8Ä'Ã)ÔLÈeÐSÐSr   Úobjc                 óˆ   — t        | t        «      sy	 | j                  «       }|duxr |j                  S # t        $ r Y yw xY w)zKTrue if ``obj`` is a live span with a valid context (safe to parent under).FN)r0   r   r9   Ú	ExceptionÚis_valid)rZ   rB   s     r   r   r     sK   € ä�cœ4Ô ØðØ×)Ñ)Ó+ˆð �dˆ?Ò+˜sŸ|™|Ð+øô ò Ùðús   “5 µ	AÁ AÚheadersc                 óÒ   — t        d„ | D «       «      sy| j                  «       D ��ci c]  \  }}t        |«      j                  «       |“Œ! }}}t        j                  |«      S c c}}w )zGExtract a remote parent context from incoming HTTP headers, if present.c              3   óB   K  — | ]  }|j                  «       d k(  –— Œ y­w)ÚtraceparentN)Úlower)Ú.0rC   s     r   ú	<genexpr>z&extract_traceparent.<locals>.<genexpr>  s   è ø€ Ò?°ˆs�y‰y‹{˜mÕ+Ñ?ùs   ‚N)Úanyr@   rH   rb   r   rT   )r^   rC   rD   r$   s       r   Úextract_traceparentrf     sW   € äÑ?°wÔ?Ô?ØØ@GÇÁÃ×P±*°#°u”c˜#“h—n‘nÓ&¨Ñ-ÐP€GÑPÜ×Ñ˜wÓ'Ð'ùó Qs   §$A#)r   zSpan | None)r$   úMapping[str, str] | Noner   úToken[Mapping[str, str] | None])r*   rh   r   N)r*   r.   r   N)r   zSpanContext | Noner'   )r$   rg   r   z tuple[Context, tuple[Link, ...]])/Ú__doc__Úcollections.abcr   Úcontextvarsr   r   Útypingr   Úopentelemetryr   Úopentelemetry.contextr   r	   Úopentelemetry.tracer
   r   r   r   r   r   Ú,opentelemetry.trace.propagation.tracecontextr   r   Ú__annotations__r   r   r    r"   r%   r+   r-   Úobjectr3   r5   r7   r;   rH   rE   rU   rI   rK   rN   rQ   rY   Úboolr   rf   rS   r   r   ú<module>rt      sÌ  ðÚ &å #ß )Ý å !ß 6÷÷ õñ 3Ó4€ˆUÓ 4ñ" 8BÐBbÐlpÔ7qÐ �EÐ3Ñ4Ó qð% ð %¨ó %ó6ñ MWØ,°dôMÐ ˜EÐ"HÑIó ð
3Ø'ð3à&ó3ó,ñ  AKØ-°tôAÐ ˜UÐ#<Ñ=ó ð
6¨ð 6Ð4Hó 6ó2-óó"Añ"B ¨¨S¨Ñ 1ð B¸GÀd¹Nð BÐV]ó BñP G¨d¡Nð P¸dÀ3ÈÀ8¹nó Pñ
6˜Dð 6¨7°T©>ð 6ÀWó 6ñ
 T¨D¡[ð ¸Gó ð( gó ð( +/ð-TØ'ð-Tà'ó-Tð`,˜Fð , tó ,ð( ¨¨c¨Ñ!2ð (°wÀ±~ô (r   