Ë
    tPêjl(  ã                   óÊ  — U d Z ddlmZ ddlmZ ddlmZmZ erddlm	Z	m
Z
mZmZmZmZ  G d„ dee«      Z G d„ d	ee«      Z ed
¬«       G d„ d«      «       Zej&                   eej&                  ej(                  d¬«      ej*                   eej*                  ej,                  ej&                  ¬«      ej.                   eej.                  ej,                  ej&                  ¬«      ej0                   eej0                  ej,                  ej&                  ¬«      ej2                   eej2                  ej4                  ej&                  ¬«      ej6                   eej6                  ej,                  ej&                  ¬«      ej8                   eej8                  ej4                  ej&                  ¬«      iZeeeef      ed<   dZ eed<   de e dœZ!eeeef      ed<   dededz  fd„Z" e#h d£«      Z$ee#e      ed<   dededz  fd„Z%dZ&eed<   dddefd „Z'dd!defd"„Z(dd#defd$„Z)dd%defd&„Z*dd'defd(„Z+dd)defd*„Z,de-e   fd+„Z.d,ede-e   fd-„Z/	 d0d.eeef   dz  ddfd/„Z0y)1u*  
This module declares every span the instrumentation can emit and the hierarchy.

Span-name patterns live here as typed builder functions.

Canonical hierarchy::

    PROXY_REQUEST  (SERVER, root)     # owned by the FastAPI instrumentor
    â”œâ”€â”€ SERVICE    (INTERNAL)         # auth phase span (live; see logger.phase_span)
    â”‚   â””â”€â”€ DB_CALL (CLIENT)          #   its key/user/team lookups nest here
    â”œâ”€â”€ GUARDRAIL  (INTERNAL)         # request-lifecycle hook, sibling of LLM_CALL
    â”œâ”€â”€ LLM_CALL   (CLIENT)
    â”œâ”€â”€ MCP_TOOL_CALL  (CLIENT)       # nests under the POST carrying the message
    â”œâ”€â”€ MCP_LIST_TOOLS (CLIENT)       #   (client-propagated context is a span link)
    â””â”€â”€ DB_CALL    (CLIENT)           # e.g. the spend-log write

Guardrails parent to PROXY_REQUEST, not LLM_CALL: pre/during/post-call guardrail
hooks are orchestrated by the request lifecycle (a pre-call guardrail runs
before the LLM call even starts), so a guardrail is a sibling of the LLM call,
not a child of it. The emitter parents every span to the ambient OTel context
(the active server span), which matches this.

MCP spans (``MCP_TOOL_CALL``, ``MCP_LIST_TOOLS``) are parented at emit time by
:func:`resolve_mcp_span_context`: they nest under the ``PROXY_REQUEST`` transport
span of the request carrying that message, so the tool call stays in one trace.
Trace context the client propagated in ``params._meta`` (SEP-414) is recorded as
a span *link*, never the parent â€” a remote parent would root the span in a trace
whose root never reaches the gateway's tracing backend. Links always target that
remote client context, never a registry role, so ``SpanSpec`` declares no link
field; the concrete transport parent is resolved per message at emit time.

Not every service call becomes a span â€” :func:`span_role_for_service` decides:

- ``DB_CALL`` (CLIENT) â€” outbound datastores (redis, postgres,
  ``batch_write_to_db``), carrying ``db.*`` semconv.
- ``SERVICE`` (INTERNAL) â€” genuine internal work worth a span (background
  budget/reset jobs, pod-lock manager).
- ``None`` (metrics-only) â€” framework instrumentation that duplicates a gen-AI
  span (``self`` = the ``track_llm_api_timing`` wrapper, ``router``,
  ``proxy_pre_call``) or ``auth`` (which gets a live phase span instead). These
  still feed Prometheus/Datadog; they just never enter the trace.

``DB_CALL`` and ``SERVICE`` are built from the same ``ServiceSpanData``; only the
role (hence span kind and attribute vocabulary) differs. A service call can fire
outside any request (a background job), in which case it parents to no server
span and starts its own root trace rather than being dropped.

Management/admin endpoints are ordinary FastAPI routes â€” their SERVER spans are
owned by the instrumentor too, so they don't appear as a role here.
é    )Ú	dataclass)ÚEnum)ÚTYPE_CHECKINGÚFinal)ÚGuardrailSpanDataÚLLMCallSpanDataÚMCPListToolsSpanDataÚMCPToolCallSpanDataÚProxyRequestSpanDataÚServiceSpanDatac                   ó(   — e Zd ZdZdZdZdZdZdZdZ	y)	ÚSpanRoleÚproxy_requestÚllm_callÚmcp_tool_callÚmcp_list_toolsÚ	guardrailÚdb_callÚserviceN)
Ú__name__Ú
__module__Ú__qualname__ÚPROXY_REQUESTÚLLM_CALLÚMCP_TOOL_CALLÚMCP_LIST_TOOLSÚ	GUARDRAILÚDB_CALLÚSERVICE© ó    új/home/oem/CyberBrain26-unified/.venv/lib/python3.12/site-packages/litellm/integrations/otel/model/spans.pyr   r   C   s%   „ Ø#€MØ€HØ#€MØ%€NØ€IØ€GØ�Gr!   r   c                   ó    — e Zd ZdZdZdZdZdZy)ÚLiteLLMSpanKindÚserverÚclientÚinternalÚproducerÚconsumerN)r   r   r   ÚSERVERÚCLIENTÚINTERNALÚPRODUCERÚCONSUMERr    r!   r"   r$   r$   M   s   „ Ø€FØ€FØ€HØ€HØ�Hr!   r$   T)Úfrozenc                   ó2   — e Zd ZU eed<   eed<   edz  ed<   y)ÚSpanSpecÚroleÚkindNÚparent)r   r   r   r   Ú__annotations__r$   r    r!   r"   r1   r1   U   s   … à
ƒNØ
ÓØ�t‰OÔr!   r1   N)r4   ÚSPAN_REGISTRYÚ
postgresqlÚ
POSTGRESQLÚredis)r9   ÚpostgresÚbatch_write_to_dbÚ_DB_SYSTEM_BY_SERVICEÚservice_nameÚreturnc                 óJ   — | t         v r	t         |    S | j                  d«      ryy)zÄThe ``db.system.name`` for a datastore service, else ``None``.

    ``None`` means the service is not an outbound datastore call. Redis-backed
    spend queues (``redis_*``) map to ``redis``.
    Úredis_r9   N)r<   Ú
startswith©r=   s    r"   Ú	db_systemrC   {   s,   € ð Ô,Ñ,Ü$ \Ñ2Ð2Ø×Ñ˜xÔ(ØØr!   >   ÚauthÚselfÚrouterÚproxy_pre_callÚ_METRICS_ONLY_SERVICESc                 ój   — | t         v ryt        | «      �t        j                  S t        j                  S )aP  The span role for a service call, or ``None`` when it must not be a span.

    ``DB_CALL`` for outbound datastores, ``SERVICE`` for genuine internal work
    worth a span (background jobs), and ``None`` for framework instrumentation
    that duplicates a gen-AI span or belongs in metrics only
    (see ``_METRICS_ONLY_SERVICES``).
    N)rH   rC   r   r   r   rB   s    r"   Úspan_role_for_servicerJ   ˜   s1   € ð Ô-Ñ-ØÜ(¨Ó6ÐBŒ8×ÑÐXÌ×HXÑHXÐXr!   zReceived Proxy Server RequestÚLITELLM_PROXY_REQUEST_SPAN_NAMEÚdatar   c                 ót   — | j                   xs d}| j                  j                  › d|› �j                  «       S )zA``"{operation} {model}"`` e.g. ``"chat gpt-4o"`` (GenAI semconv).Ú ú )Úrequest_modelÚ	operationÚvalueÚstrip)rL   Úmodels     r"   Úllm_call_span_namerU   ¯   s7   € à×%Ñ%Ò+¨€EØ�n‰n×"Ñ"Ð# 1 U GÐ,×2Ñ2Ó4Ð4r!   r
   c                 óT   — | j                   › d| j                  › �j                  «       S )zO``"{mcp.method.name} {tool}"`` e.g. ``"tools/call get-weather"`` (MCP semconv).rO   )ÚmethodÚ	tool_namerS   ©rL   s    r"   Úmcp_tool_call_span_namerZ   µ   s%   € à�k‰kˆ]˜!˜DŸN™NÐ+Ð,×2Ñ2Ó4Ð4r!   r	   c                 ó   — | j                   S )u‡   ``"{mcp.method.name}"`` i.e. ``"tools/list"`` â€” no low-cardinality target, so
    the method name alone names the span (MCP semconv).)rW   rY   s    r"   Úmcp_list_tools_span_namer\   º   s   € ð �;‰;Ðr!   r   c                 óT   — | j                   › d| j                  › �j                  «       S )z&``"{method} {route}"`` (HTTP semconv).rO   )Úhttp_methodÚrouterS   rY   s    r"   Úproxy_request_span_namer`   À   s'   € à×ÑÐ˜q §¡ Ð-×3Ñ3Ó5Ð5r!   r   c                 ó<   — d| j                   › �j                  «       S )Nzexecute_guardrail )Úguardrail_namerS   rY   s    r"   Úguardrail_span_namerc   Å   s   € Ø × 3Ñ 3Ð4Ð5×;Ñ;Ó=Ð=r!   r   c                 ó\   — | j                   › d| j                  xs d› �j                  «       S )u˜   ``"{service} {call_type}"`` e.g. ``"redis set"`` â€” service name alone when
    no call type is known, so identically-named calls stay distinguishable.rO   rN   )r=   Ú	call_typerS   rY   s    r"   Úservice_span_namerf   É   s/   € ð ×ÑÐ   $§.¡.Ò"6°BÐ!7Ð8×>Ñ>Ó@Ð@r!   c                  óv   — t         j                  «       D � �cg c]  \  } }|j                  �Œ| ‘Œ c}} S c c}} w )zƒRoles with no in-process parent, i.e. they start a new trace (only the
    instrumentor-owned ``PROXY_REQUEST`` server span today).©r6   Úitemsr4   )r2   Úspecs     r"   Ú
root_rolesrk   Ï   s.   € ô $1×#6Ñ#6Ó#8×P‘Z�T˜4¸D¿K¹KÑ<OŠDÓPÐPùÓPs   ˜5­5r4   c                 ó|   — t         j                  «       D ��cg c]  \  }}|j                  | k(  sŒ|‘Œ c}}S c c}}w ©Nrh   )r4   r2   rj   s      r"   Úchild_rolesrn   Õ   s.   € Ü#0×#6Ñ#6Ó#8×R‘Z�T˜4¸D¿K¹KÈ6Ó<QŠDÓRÐRùÓRs   ˜8°8Úregistryc                 ó`  — | �| nt         }|j                  «       D ]d  \  }}|j                  |urt        d|› d|j                  › �«      ‚|j                  €Œ<|j                  |vsŒKt        d|› d|j                  › �«      ‚ t
        D �cg c]	  }||vsŒ|‘Œ }}|rt        d|› �«      ‚y c c}w )NzSPAN_REGISTRY[z] has mismatched role z
span role z declares unknown parent z SPAN_REGISTRY is missing roles: )r6   ri   r2   Ú
ValueErrorr4   r   )ro   Úregr2   rj   Úmissings        r"   Úvalidate_registryrt   Ù   sÂ   € ð &Ð1‘´}€CØ—i‘i“kò X‰
ˆˆdØ�9‰9˜DÑ Ü˜~¨d¨VÐ3IÈ$Ï)É)ÈÐUÓVÐVØ�;‰;Ñ" t§{¡{¸#Ò'=Ü˜z¨$¨Ð/HÈÏÉÈÐVÓWÐWð	Xô
 (0ÖC˜t°4¸s²?’dÐC€GÐCÙÜÐ;¸G¸9ÐEÓFÐFð ùò Ds   Â
	B+ÂB+rm   )1Ú__doc__Údataclassesr   Úenumr   Útypingr   r   Ú(litellm.integrations.otel.model.payloadsr   r   r	   r
   r   r   Ústrr   r$   r1   r   r*   r   r+   r   r   r   r,   r   r   r6   Údictr5   r8   r<   rC   Ú	frozensetrH   rJ   rK   rU   rZ   r\   r`   rc   rf   Úlistrk   rn   rt   r    r!   r"   ú<module>r~      sê  ðò1õf "Ý ß 'á÷÷ ôˆs�Dô ô�c˜4ô ñ �$Ô÷ð ó ðð ×Ñ™H X×%;Ñ%;¸_×=SÑ=SÐ\`ÔaØ×Ñ‘x × 1Ñ 1°?×3IÑ3IÐRZ×RhÑRhÔið ×Ñ™H X×%;Ñ%;¸_×=SÑ=SÐ\d×\rÑ\rÔsØ×Ñ™X h×&=Ñ&=¸×?UÑ?UÐ^f×^tÑ^tÔuØ×Ñ™ ×!3Ñ!3°_×5MÑ5MÐV^×VlÑVlÔmØ×Ñ‘h˜x×/Ñ/°×1GÑ1GÐPX×PfÑPfÔgØ×Ñ‘h˜x×/Ñ/°×1IÑ1IÐRZ×RhÑRhÔið2€ˆu�T˜( HÐ,Ñ-Ñ.ó ð, !€
ˆEÓ  ð ØØ#ñ0Ð �u˜T # s (™^Ñ,ó ð
˜Cð 
 C¨$¡Jó 
ñ4 1:Ò:fÓ0gÐ ˜˜i¨™nÑ-Ó gð
Y¨ð 
Y°¸4±ó 
Yð( *IÐ  Ó Hð5Ð.ð 5°3ó 5ð5Ð"7ð 5¸Có 5ð
Ð#9ð ¸có ð6Ð"8ð 6¸Só 6ð
>Ð1ð >°có >ðAÐ-ð A°#ó AðQ�D˜‘Nó QðS˜ð S T¨(¡^ó Sð
 15ñGØ�8˜XÐ%Ñ&¨Ñ-ðGà	ôGr!   