Ë
    tPêjK  ã                   ó  — U d dl Z d dlZd dlZd dlmZ d dlmZmZmZmZ d dl	m
Z
 d dlm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 erd dlmZ eez  ZneZdZeed<   dZeed<   dZeed<   dZeed<    G d„ de«      Z y)é    N)Údatetime)ÚTYPE_CHECKINGÚAnyÚFinalÚOptional)Úverbose_logger)Ú_utils)ÚLangfuseLLMObsOTELAttributes)ÚOpenTelemetryÚOpenTelemetryConfig)Úsafe_json_loads)ÚLangfuseSpanAttributes)ÚStandardCallbackDynamicParams)ÚSpanz*https://cloud.langfuse.com/api/public/otelÚLANGFUSE_CLOUD_EU_ENDPOINTz-https://us.cloud.langfuse.com/api/public/otelÚLANGFUSE_CLOUD_US_ENDPOINTzx-langfuse-ingestion-versionÚ!LANGFUSE_INGESTION_VERSION_HEADERÚ4ÚLANGFUSE_INGESTION_VERSIONc            	       ó°  ‡ — e Zd Zd ˆ fd„	Zedefd„«       Zededefd„«       Zededefd	„«       Z	edefd
„«       Z
edefd„«       Zededz  fd„«       Zdefd„Zed!d„«       Zededededz  ddfd„«       Zedededefd„«       Zededeeef   fd„«       Zedeeef   defd„«       Zdededz  fd„Zdeded   fd„Zdedededz  fd„Zd„ Zd„ Zˆ xZS )"ÚLangfuseOtelLoggerNc                 óL   •— |€| j                  «       }t        ‰| �  |d|i|¤Ž y )NÚconfig)Ú/_create_open_telemetry_config_from_langfuse_envÚsuperÚ__init__)Úselfr   ÚargsÚkwargsÚ	__class__s       €úp/home/oem/CyberBrain26-unified/.venv/lib/python3.12/site-packages/litellm/integrations/langfuse/langfuse_otel.pyr   zLangfuseOtelLogger.__init__"   s/   ø€ ð ˆ>Ø×IÑIÓKˆFÜ‰Ñ¨Ð8 Ð8°Ó8ó    Úspanc                 ó�   — t        j                  | ||t        «       | j                  dd«       t        j                  | ||¬«       y)z 
        Sets OpenTelemetry span attributes for Langfuse observability.
        Uses the same attribute setting logic as Arize Phoenix for consistency.
        zlangfuse.observation.typeÚ
generation©r#   r   Úresponse_objN)r	   Úset_attributesr
   Úset_attributer   Ú!_set_langfuse_specific_attributesr&   s      r!   Úset_langfuse_otel_attributesz/LangfuseOtelLogger.set_langfuse_otel_attributes)   sB   € ô 	×Ñ˜d F¨LÔ:VÔWØ×ÑÐ6¸ÔEô
 	×<Ñ<À$ÈvÐdpÐ<Õqr"   r   Úreturnc                 óÖ   — | j                  di «      xs i }|j                  d«      xs i }|�t        |t        «      si }	 ddlm} |j                  ||«      }|S # t        $ r Y |S w xY w)a”  
        Extracts Langfuse metadata from the standard LiteLLM kwargs structure.

        1. Reads kwargs["litellm_params"]["metadata"] if present and is a dict.
        2. Enriches it with any `langfuse_*` request-header params via the
           existing LangFuseLogger.add_metadata_from_header helper so that proxy
           users get identical behaviour across vanilla and OTEL integrations.
        Úlitellm_paramsÚmetadatar   )ÚLangFuseLogger)ÚgetÚ
isinstanceÚdictÚ&litellm.integrations.langfuse.langfuser0   Úadd_metadata_from_headerÚ	Exception)r   r.   r/   Ú	_LFLoggers       r!   Ú_extract_langfuse_metadataz-LangfuseOtelLogger._extract_langfuse_metadata8   s�   € ð !'§
¡
Ð+;¸RÓ @Ò FÀBˆØ!×%Ñ% jÓ1Ò7°RˆàÐ¤:¨h¼Ô#=ØˆHð	õð !×9Ñ9¸.È(ÓSˆHð
 ˆøô	 ò 	ààˆð		ús   ÁA Á	A(Á'A(r/   c                 óØ  — ddl m} t        j                  t        j                  t        j
                  t        j                  t        j                  t        j                  t        j                  t        j                  t        j                  t        j                  t        j                  t        j                  t        j                  t        j                   t        j"                  dœ}|j%                  d«      �|j%                  d«      n|j%                  d«      }|�" || t        j&                  j(                  |«       |j+                  «       D ]|  \  }}||v sŒ||   €Œ||   }|dk(  r"t-        |t.        «      r|j1                  dd	«      }t-        |t2        t4        f«      r	 t7        j8                  |«      } || |j(                  |«       Œ~ y# t:        $ r t/        |«      }Y Œ-w xY w)
z/Helper to set metadata attributes from mapping.r   ©Úsafe_set_attribute)Úgeneration_nameÚgeneration_idÚparent_observation_idÚ
mask_inputÚmask_outputÚtrace_user_idÚ
session_idÚtagsÚ
trace_nameÚtrace_idÚtrace_metadataÚtrace_releaseÚexisting_trace_idÚupdate_trace_keysÚdebug_langfuseÚtrace_versionNÚversionrE   ú-Ú )Ú!litellm.integrations.arize._utilsr;   r   ÚGENERATION_NAMEÚGENERATION_IDÚPARENT_OBSERVATION_IDÚ
MASK_INPUTÚMASK_OUTPUTÚTRACE_USER_IDÚ
SESSION_IDÚTAGSÚ
TRACE_NAMEÚTRACE_IDÚTRACE_METADATAÚRELEASEÚEXISTING_TRACE_IDÚUPDATE_TRACE_KEYSÚDEBUG_LANGFUSEr1   ÚVERSIONÚvalueÚitemsr2   ÚstrÚreplaceÚlistr3   ÚjsonÚdumpsr6   )r#   r/   r;   ÚmappingrL   ÚkeyÚ	enum_attrr`   s           r!   Ú_set_metadata_attributesz+LangfuseOtelLogger._set_metadata_attributesU   s‹  € õ 	Iô  6×EÑEÜ3×AÑAÜ%;×%QÑ%QÜ0×;Ñ;Ü1×=Ñ=Ü3×AÑAÜ0×;Ñ;Ü*×/Ñ/Ü0×;Ñ;Ü.×7Ñ7Ü4×CÑCÜ3×;Ñ;Ü!7×!IÑ!IÜ!7×!IÑ!IÜ4×CÑCñ
ˆð& .6¯\©\¸/Ó-JÐ-VˆH�L‰L˜Ô)Ð\d×\hÑ\hÐirÓ\sð 	ð ÐÙ˜tÔ%;×%CÑ%C×%IÑ%IÈ7ÔSà%Ÿm™m›oò 	A‰NˆC�Ø�hŠ 8¨C¡=Ñ#<Ø  ™�Ø˜*Ò$¬°E¼3Ô)?à!ŸM™M¨#¨rÓ2�Eä˜e¤d¬D \Ô2ð+Ü $§
¡
¨5Ó 1˜ñ # 4¨¯©¸%Õ@ñ	Aøô %ò +Ü # E£
šð+ús   Æ&GÇG)Ç(G)c                 ó&  — ddl m} ddlm} |rt	        |d«      sy|j                  dg «      }|�rg|d   }|j                  di «      }|j                  d«      }|rÇg }|D ]—  }	|	j                  d	i «      }
|
j                  d
d«      }	 t        |t        «      rt        j                  |«      n|}|j                  dd«      |
j                  dd«      |	j                  dd«      d|dœ}|j                  |«       Œ™  || t        j                  j                   ||«      «       nvi }|j                  d«      r|j                  d«      |d<   |j                  d«      �|j                  d«      |d<   |r( || t        j                  j                   ||«      «       |j                  dg «      }|�rIg }|D �]  }t	        |d«      sŒ|j                  }|dk(  rIt	        |d«      r=|j                   D ]-  }t	        |d«      sŒ|j                  d|j"                  dœ«       Œ/ Œk|dk(  r:|j                  t%        |dd«      t%        t%        |di g«      d   dd«      dœ«       Œª|dk(  sŒ°t%        |d
d«      }t        |t        «      rt'        |i ¬«      n|}t%        |dd«      t%        |dd«      t%        |dd«      d|dœ}|j                  |«       �Œ |r) || t        j                  j                   ||«      «       yyy# t        j                  $ r i }Y �Œaw xY w)z,Helper to set observation output attributes.r   r:   ©Ú
safe_dumpsr1   NÚchoicesÚmessageÚ
tool_callsÚfunctionÚ	argumentsz{}ÚidrN   ÚnameÚfunction_call)rs   rt   Úcall_idÚtyperr   ÚroleÚcontentÚoutputrw   Ú	reasoningÚsummaryÚtextÚreasoning_summary)rx   ry   Ú	assistant)Údefaultrv   )rO   r;   Ú*litellm.litellm_core_utils.safe_json_dumpsrm   Úhasattrr1   r2   rb   re   ÚloadsÚJSONDecodeErrorÚappendr   ÚOBSERVATION_OUTPUTr`   rw   r|   r}   Úgetattrr   )r#   r'   r;   rm   rn   Úfirst_choicero   rp   Útransformed_tool_callsÚ	tool_callrq   Úarguments_strÚarguments_objÚlangfuse_tool_callÚoutput_datarz   Úoutput_items_dataÚitemÚ	item_typer|   s                       r!   Ú_set_observation_outputz*LangfuseOtelLogger._set_observation_output€   s4  € õ 	IÝIá¤7¨<¸Ô#?Øà%×)Ñ)¨)°RÓ8ˆÚØ")¨!¡*ˆLØ)×-Ñ-¨i¸Ó<ˆGØ '§¡¨LÓ 9ˆJÙØ02Ð&Ø!+ò F�IØ(Ÿ}™}¨Z¸Ó<�HØ$,§L¡L°¸dÓ$C�Mð+ÜEOÐP]Ô_bÔEc¬¯
©
°=Ô(AÐiv˜ð +×.Ñ.¨t°RÓ8Ø (§¡¨V°RÓ 8Ø#,§=¡=°°rÓ#:Ø /Ø%2ñ*Ð&ð +×1Ñ1Ð2DÕEðFñ #ØÜ*×=Ñ=×CÑCÙÐ5Ó6õð &(�Ø—;‘;˜vÔ&Ø*1¯+©+°fÓ*=�K Ñ'Ø—;‘;˜yÓ)Ð5Ø-4¯[©[¸Ó-C�K 	Ñ*ÙÙ&ØÜ.×AÑA×GÑGÙ" ;Ó/ôð %×(Ñ(¨°2Ó6ˆÚØ35ÐØó !E�Ü˜4 Õ(Ø $§	¡	�IØ  KÒ/´G¸DÀ)Ô4LØ'+§|¡|ò "˜GÜ& w°Õ7Ø 1× 8Ñ 8à0CØ3:·<±<ñ%&õ!"ñ"ð # iÒ/Ø)×0Ñ0ä(/°°f¸kÓ(JÜ+2´7¸4ÀÈRÈDÓ3QÐRSÑ3TÐV\Ð^`Ó+añõð # oÓ5Ü(/°°kÀ4Ó(H˜ô  *¨-¼Ô=ô ,¨MÀ2ÕFà!.ð &ô #*¨$°°bÓ"9Ü$+¨D°&¸"Ó$=Ü'.¨t°YÀÓ'CØ$3Ø)6ñ.Ð*ð *×0Ñ0Ð1CÖDðC!EñD !Ù"ØÜ*×=Ñ=×CÑCÙÐ0Ó1õð !ðI øô;  ×/Ñ/ò +Ø(*›ð+ús   Â'K7Ë7LÌLc                 óî  — ddl m} ddlm} |j	                  d«      }|r|j	                  d«      ndxs t
        j                  j	                  d«      }|r" || t        j                  j                  |«       t        j                  |«      }t        j                  | |¬«       |j	                  d	«      }|r( || t        j                  j                   ||«      «       t        j                  | |¬
«       y)aH  
        Sets Langfuse specific metadata attributes onto the OTEL span.

        All keys supported by the vanilla Langfuse integration are mapped to
        OTEL-safe attribute names defined in LangfuseSpanAttributes.  Complex
        values (lists/dicts) are serialised to JSON strings for OTEL
        compatibility.
        r   r:   rl   Ú standard_callback_dynamic_paramsÚlangfuse_environmentNÚLANGFUSE_TRACING_ENVIRONMENT)r#   r/   Úmessages)r#   r'   )rO   r;   r�   rm   r1   ÚosÚenvironr   ÚLANGFUSE_ENVIRONMENTr`   r   r8   rj   ÚOBSERVATION_INPUTr’   )	r#   r   r'   r;   rm   Údynamic_paramsr•   r/   r—   s	            r!   r*   z4LangfuseOtelLogger._set_langfuse_specific_attributesÝ   s×   € õ 	IÝIà &§
¡
Ð+MÓ Nˆá:HˆN×ÑÐ5Ô6Èdò'<ä�Z‰Z�^‰^Ð:Ó;ð 	ñ  ÙØÜ&×;Ñ;×AÑAØ$ôô -×GÑGÈÓOˆÜ×3Ñ3¸ÈÐ3ÔQà Ÿ*™* ZÓ0ˆÙÙØÜ&×8Ñ8×>Ñ>Ù˜8Ó$ôô 	×2Ñ2¸È<Ð2ÕXr"   c                  ó‚   — t         j                  j                  d«      xs t         j                  j                  d«      S )z¿
        Returns the Langfuse OTEL host based on environment variables.

        Returned in the following order of precedence:
        1. LANGFUSE_OTEL_HOST
        2. LANGFUSE_HOST
        ÚLANGFUSE_OTEL_HOSTÚLANGFUSE_HOST)r˜   r™   r1   © r"   r!   Ú_get_langfuse_otel_hostz*LangfuseOtelLogger._get_langfuse_otel_host  s*   € ô �z‰z�~‰~Ð2Ó3ÒV´r·z±z·~±~ÀoÓ7VÐVr"   c                 ó  — ddl m} t        j                  j	                  dd«      }t        j                  j	                  dd«      }|r|s |j
                  «       S t        j                  ||t        j                  «       ¬«      S )zˆ
        Creates OpenTelemetryConfig from Langfuse environment variables.
        Does NOT modify global environment variables.
        r   )r   ÚLANGFUSE_PUBLIC_KEYNÚLANGFUSE_SECRET_KEY©Ú
public_keyÚ
secret_keyÚlangfuse_host)	Ú"litellm.integrations.opentelemetryr   r˜   r™   r1   Úfrom_envr   Ú_build_langfuse_otel_configr¡   )r   r   r¦   r§   s       r!   r   zBLangfuseOtelLogger._create_open_telemetry_config_from_langfuse_env  ss   € õ
 	KäŸJ™JŸN™NÐ+@À$ÓGˆ
ÜŸJ™JŸN™NÐ+@À$ÓGˆ
á¡à/Ð&×/Ñ/Ó1Ð1ä!×=Ñ=Ø!Ø!Ü,×DÑDÓFð >ó 
ð 	
r"   r   c                  óô   — t         j                  j                  dd«      } t         j                  j                  dd«      }| r|st        d«      ‚t        j                  | |t        j                  «       ¬«      S )a2  
        Retrieves the Langfuse OpenTelemetry configuration based on environment variables.

        Environment Variables:
            LANGFUSE_PUBLIC_KEY: Required. Langfuse public key for authentication.
            LANGFUSE_SECRET_KEY: Required. Langfuse secret key for authentication.
            LANGFUSE_HOST: Optional. Custom Langfuse host URL. Defaults to US cloud.

        Returns:
            OpenTelemetryConfig: A Pydantic model containing Langfuse OTEL configuration.

        Raises:
            ValueError: If required keys are missing.
        r£   Nr¤   z_LANGFUSE_PUBLIC_KEY and LANGFUSE_SECRET_KEY must be set for Langfuse OpenTelemetry integration.r¥   )r˜   r™   r1   Ú
ValueErrorr   r«   r¡   ©r¦   r§   s     r!   Úget_langfuse_otel_configz+LangfuseOtelLogger.get_langfuse_otel_config!  so   € ô  ŸJ™JŸN™NÐ+@À$ÓGˆ
ÜŸJ™JŸN™NÐ+@À$ÓGˆ
á¡ÜØqóð ô "×=Ñ=Ø!Ø!Ü,×DÑDÓFð >ó 
ð 	
r"   r¦   r§   r¨   c           	      óZ  — |rC|j                  d«      r|nd|› �}|j                  d«      › d�}t        j                  d|«       nt        }t        j                  d|«       t
        j                  | |¬«      }t        d|t
        j                  t
        j                  |«      «      ¬	«      S )
z³
        Builds an OTLP HTTP config pointing at the Langfuse OTEL endpoint for the
        given host (US cloud when no host is provided), authorized with the given keys.
        Úhttpzhttps://ú/z/api/public/otelz*Using Langfuse OTEL endpoint from host: %sz$Using Langfuse US cloud endpoint: %sr®   Ú	otlp_http)ÚexporterÚendpointÚheaders)
Ú
startswithÚrstripr   Údebugr   r   Ú"_get_langfuse_authorization_headerr   Ú_format_otel_headersÚ_build_langfuse_otel_headers)r¦   r§   r¨   Únormalized_hostrµ   Úauth_headers         r!   r«   z.LangfuseOtelLogger._build_langfuse_otel_config?  s±   € ñ Ø6C×6NÑ6NÈvÔ6V¡]Ð^fÐgtÐfuÐ\vˆOØ)×0Ñ0°Ó5Ð6Ð6FÐGˆHÜ× Ñ Ð!MÈxÕXä1ˆHÜ× Ñ Ð!GÈÔRä/×RÑRØ!¨jð Só 
ˆô #Ø ØÜ&×;Ñ;Ü"×?Ñ?ÀÓLóô
ð 	
r"   c                 ó|   — | › d|› �}t        j                  |j                  «       «      j                  «       }d|› �S )zJ
        Get the authorization header for Langfuse OpenTelemetry.
        ú:zBasic )Úbase64Ú	b64encodeÚencodeÚdecode)r¦   r§   Úauth_stringr¾   s       r!   rº   z5LangfuseOtelLogger._get_langfuse_authorization_header[  sC   € ð
 !+˜|¨1¨Z¨LÐ9ˆÜ#×-Ñ-¨k×.@Ñ.@Ó.BÓC×JÑJÓLˆØ˜�}Ð%Ð%r"   r¾   c                 ó   — d| t         t        iS )zÓ
        Build the OTLP header set Langfuse expects.

        `x-langfuse-ingestion-version: 4` selects Langfuse's v4 ingestion path;
        without it spans fall back to the older transformation path.
        ÚAuthorization)r   r   )r¾   s    r!   r¼   z/LangfuseOtelLogger._build_langfuse_otel_headersd  s   € ð ˜[Ü-Ô/Ið
ð 	
r"   r¶   c                 óN   — dj                  d„ | j                  «       D «       «      S )zX
        Serialize a header mapping into the comma-separated OTLP header string
        ú,c              3   ó0   K  — | ]  \  }}|› d |› �–— Œ y­w)ú=Nr    )Ú.0rh   r`   s      r!   ú	<genexpr>z:LangfuseOtelLogger._format_otel_headers.<locals>.<genexpr>v  s   è ø€ ÒK©Z¨S°%˜3˜%˜q  Ô(ÑKùs   ‚)Újoinra   )r¶   s    r!   r»   z'LangfuseOtelLogger._format_otel_headersq  s   € ð
 �x‰xÑK¸7¿=¹=»?ÔKÓKÐKr"   r”   c                 óÌ   — i }|j                  d«      }|j                  d«      }|r=|r;t        j                  ||¬«      }|j                  t        j	                  |«      «       |S )zÙ
        Construct dynamic Langfuse headers from standard callback dynamic params

        This is used for team/key based logging.

        Returns:
            dict: A dictionary of dynamic Langfuse headers
        Úlangfuse_public_keyÚlangfuse_secret_keyr®   )r1   r   rº   Úupdater¼   )r   r”   Údynamic_headersÚdynamic_langfuse_public_keyÚdynamic_langfuse_secret_keyr¾   s         r!   Úconstruct_dynamic_otel_headersz1LangfuseOtelLogger.construct_dynamic_otel_headersx  sr   € ð "$ˆà-M×-QÑ-QÐRgÓ-hÐ#Ø-M×-QÑ-QÐRgÓ-hÐ#Ù&Ñ+FÜ!3×!VÑ!VØ6Ø6ð "Wó "ˆKð ×"Ñ"Ô#5×#RÑ#RÐS^Ó#_Ô`àÐr"   c                 óÆ   — |j                  d«      }|j                  d«      }|r|sy|j                  d«      xs | j                  «       }t        j                  |||¬«      S )az  
        Build a full per-request OTLP config from team/key dynamic Langfuse credentials.

        Key-scoped credentials must define the export target, not just the auth
        headers: without this, a proxy with no global LANGFUSE_* env vars keeps its
        init-time fallback exporter (console), so key-level langfuse_otel silently
        never reaches Langfuse.
        rÐ   rÑ   Nr¨   r¥   )r1   r¡   r   r«   )r   r”   r¦   r§   r¨   s        r!   Úconstruct_dynamic_otel_configz0LangfuseOtelLogger.construct_dynamic_otel_config�  sn   € ð =×@Ñ@ÐAVÓWˆ
Ø<×@Ñ@ÐAVÓWˆ
Ù¡Øà?×CÑCÀOÓTÒvÐX\×XtÑXtÓXvˆÜ!×=Ñ=Ø!Ø!Ø'ð >ó 
ð 	
r"   Ú
start_timec                  ó   — y)aq  
        Override to prevent creating empty proxy request spans.

        Langfuse should only receive spans for actual LLM calls, not for
        internal proxy operations (auth, postgres, proxy_pre_call, etc.).

        By returning None, we prevent the parent span from being created,
        which in turn prevents empty traces from being sent to Langfuse.
        Nr    )r   rÙ   r¶   s      r!   Ú)create_litellm_proxy_request_started_spanz<LangfuseOtelLogger.create_litellm_proxy_request_started_span§  s   € ð r"   c              �   ó   K  — y­w)zC
        Langfuse should not receive service success logs.
        Nr    ©r   r   r   s      r!   Úasync_service_success_hookz-LangfuseOtelLogger.async_service_success_hook·  ó   è ø� ùó   ‚c              �   ó   K  — y­w)zC
        Langfuse should not receive service failure logs.
        Nr    rÝ   s      r!   Úasync_service_failure_hookz-LangfuseOtelLogger.async_service_failure_hook¼  rß   rà   )N)r,   r   )Ú__name__Ú
__module__Ú__qualname__r   Ústaticmethodr   r+   r3   r8   rj   r’   r*   rb   r¡   r   r   r¯   r«   rº   r¼   r»   r   rÖ   r   rØ   r   rÛ   rÞ   râ   Ú__classcell__)r    s   @r!   r   r   !   s  ø„ õ9ð ðr¨4ò ró ðrð ð¨4ð °Dò ó ðð8 ð(A tð (A°tò (Aó ð(AðT ðZ dò Zó ðZðx ð"Y°ò "Yó ð"YðH ðW S¨4¡Zò Wó ðWð
ÐATó 
ð( ò
ó ð
ð: ð
Øð
Ø%(ð
Ø9<¸t¹ð
à	ò
ó ð
ð6 ð&°sð &Èð &ÐPSò &ó ð&ð ð

°#ð 

¸$¸sÀC¸x¹.ò 

ó ð

ð ðL d¨3°¨8¡nð L¸ò Ló ðLðØ0Mðà	�‰óð0
Ø0Mð
à	Ð'Ñ	(ó
ð.àðð ðð 
�‰ó	ò ö
r"   r   )!rÁ   re   r˜   r   Útypingr   r   r   r   Úlitellm._loggingr   Úlitellm.integrations.arizer	   Ú6litellm.integrations.langfuse.langfuse_otel_attributesr
   r©   r   r   Ú*litellm.litellm_core_utils.safe_json_loadsr   Ú(litellm.types.integrations.langfuse_otelr   Úlitellm.types.utilsr   Úopentelemetry.tracer   Ú_Spanr   Ú__annotations__r   r   r   r   r    r"   r!   ú<module>rò      s†   ðÜ Û Û 	Ý ß 6Ó 6å +Ý -õ÷ RÝ Fõõ >áÝ1à�3‰;�Dà€Dð %QÐ ˜EÓ PØ$SÐ ˜EÓ SØ+IÐ ! 5Ó IØ$'Ð ˜EÓ 'ô^˜õ ^r"   