o
    3i                     @   s  zd dl Z W n ey   edw 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mZmZmZ d dlmZ zd dlmZmZ d dlmZ W n eefye   d dlmZ d dlmZmZ Y nw d dlmZ d d	lmZmZmZmZm Z m!Z!m"Z" d d
l#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/m0Z0 e1dZ2eG dd dZ3eG dd de3Z4ee3e4f Z5e
ee5f Z6G dd deZ7dd Z8de9e! de9e:e;e	f  fddZ<dede:e;e	f fddZ=eG d d! d!Z>		d:d"ee'e:f d#ee; d$ee; de>fd%d&Z?	d:d'e%d#ee; d$ee; de>fd(d)Z@d*e0d+eAd,eee;eBef  d-ee
e;e	f  d.e
e;e	f f
d/d0ZCd1eAdeBfd2d3ZDd4ee
e;e	f  d5e	dee; fd6d7ZEd+eAde;fd8d9ZFdS );    NzJPlease install LangChain to use this feature: 'pip install langchain-core')	dataclass)AnyDictListOptionalSequenceUnioncast)UUID)AgentActionAgentFinish)BaseCallbackHandler)Document)	AIMessageBaseMessageFunctionMessageHumanMessageSystemMessageToolCallToolMessage)ChatGeneration	LLMResult)	BaseModel)setup)sanitize_langchain)get_model_paramswith_privacy_mode)Clientposthogc                   @   sP   e Zd ZU eed< 	 eed< 	 ee ed< 	 ee ed< 	 edefddZ	dS )	SpanMetadataname
start_timeend_timeinputreturnc                 C   s   | j sdS | j | j S )Nr   )r"   r!   )self r&   l/lsinfo/ai/hellotax_ai/llm_service/venv_embed/lib/python3.10/site-packages/posthog/ai/langchain/callbacks.pylatency?   s   zSpanMetadata.latencyN)
__name__
__module____qualname__str__annotations__floatr   r   propertyr(   r&   r&   r&   r'   r   4   s   
 r   c                   @   s   e Zd ZU dZee ed< 	 dZee ed< 	 dZee	ee
f  ed< 	 dZee ed< 	 dZeee	ee
f   ed< 	 dZee	ee
f  ed< dS )GenerationMetadataNprovidermodelmodel_paramsbase_urltoolsposthog_properties)r)   r*   r+   r1   r   r,   r-   r2   r3   r   r   r4   r5   r   r6   r&   r&   r&   r'   r0   F   s   
 r0   c                   @   s  e Zd ZU dZeed< 	 eeee	e
f  ed< 	 eeee	ee
f  ed< 	 ee ed< 	 ee ed< 	 eeeef  ed< 	 eed< 	 ee
e
f ed	< 	 	
djd
d
d
dd
ddee deeee	e
f  deeee	ee
f  deeeef  dedeeeef  fddZd
d
ddeeef deeef de
dee
 deeeef  f
ddZd
ddeeef de
dee
 defd d!Zd
dd"ede
dee
 defd#d$Zd
ddeeef d%eee  de
dee
 fd&d'Zd
ddeeef d(ee de
dee
 def
d)d*Zd
dd+ede
dee
 ded,ef
d-d.Zd
dd/ede
dee
 defd0d1Zd
dd"ede
dee
 defd2d3Zd
d
ddeeeef  d4ede
dee
 deeeef  ded,efd5d6Zd
dd7ede
dee
 ded,ef
d8d9Zd
d
d:d"ede
dee
 d;eee  ded,efd<d=Z d
d
ddeeeef  d>ede
dee
 deeeef  ded,efd?d@Z!d
ddAe"e# de
dee
 defdBdCZ$d
d
d:d"ede
dee
 d;eee  ded,efdDdEZ%d
ddFe&de
dee
 ded,ef
dGdHZ'd
ddIe(de
dee
 ded,ef
dJdKZ)djde
dee
 fdLdMZ*de
fdNdOZ+de
d,e
fdPdQZ,	
djdeeeef  dRede
dee
 fdSdTZ-	
	
dkdeeef de
d%eeeeef  ee f deeeef  dUeeeef  f
dVdWZ.de
d,ee/ fdXdYZ0de
fdZd[Z1dede
dee
 fd\d]Z2de
dee
 defd^d_Z3dede
d`e4dedee
 f
dadbZ5de
dee
 d/eeef fdcddZ6	
djdede
d`e7d7eeef dee
 f
dedfZ8	
djdgede
dee
 fdhdiZ9d
S )lCallbackHandlerzG
    The PostHog LLM observability callback handler for LangChain.
    
_ph_client_distinct_id	_trace_id_trace_input_trace_name_properties_runs_parent_treeNF)distinct_idtrace_id
propertiesprivacy_modegroupsclientr@   rA   rB   rC   rD   c                C   sB   |pt  | _|| _|| _|pi | _|| _|pi | _i | _i | _dS )a  
        Args:
            client: PostHog client instance.
            distinct_id: Optional distinct ID of the user to associate the trace with.
            trace_id: Optional trace ID to use for the event.
            properties: Optional additional metadata to use for the trace.
            privacy_mode: Whether to redact the input and output of the trace.
            groups: Optional additional PostHog groups to use for the trace.
        N)	r   r8   r9   r:   r=   _privacy_mode_groupsr>   r?   )r%   rE   r@   rA   rB   rC   rD   r&   r&   r'   __init__z   s   


zCallbackHandler.__init__)parent_run_idmetadata
serializedinputsrun_idrI   rJ   c                K   :   | j d|||d | || | j||||fi | d S )Non_chain_start)rL   _log_debug_event_set_parent_of_run_set_trace_or_span_metadata)r%   rK   rL   rM   rI   rJ   kwargsr&   r&   r'   rO         

zCallbackHandler.on_chain_start)rI   outputsrT   c                K   $   | j d|||d | ||| d S )Non_chain_end)rV   rQ   "_pop_run_and_capture_trace_or_span)r%   rV   rM   rI   rT   r&   r&   r'   rX         zCallbackHandler.on_chain_enderrorc                K   rW   )Non_chain_errorr\   rY   r%   r\   rM   rI   rT   r&   r&   r'   r]      r[   zCallbackHandler.on_chain_errormessagesc                K   sF   | j d|||d | || dd |D }| j|||fi | d S )Non_chat_model_start)r`   c                 S   s   g | ]}|D ]}t |qqS r&   )_convert_message_to_dict).0rowmessager&   r&   r'   
<listcomp>   s
    z7CallbackHandler.on_chat_model_start.<locals>.<listcomp>rQ   rR   _set_llm_metadata)r%   rK   r`   rM   rI   rT   r#   r&   r&   r'   ra      s   	z#CallbackHandler.on_chat_model_startpromptsc                K   s8   | j d|||d | || | j|||fi | d S )Non_llm_start)ri   rg   )r%   rK   ri   rM   rI   rT   r&   r&   r'   rj      s   	zCallbackHandler.on_llm_starttokenr$   c                K   s   | j d|||d dS )z?Run on new LLM token. Only available when streaming is enabled.on_llm_new_token)rk   N)rQ   )r%   rk   rM   rI   rT   r&   r&   r'   rl      s   	z CallbackHandler.on_llm_new_tokenresponsec                K   s&   | j d||||d | ||| dS )z
        The callback works for both streaming and non-streaming runs. For streaming runs, the chain must set `stream_usage=True` in the LLM.
        
on_llm_end)rm   rT   NrQ   _pop_run_and_capture_generation)r%   rm   rM   rI   rT   r&   r&   r'   rn      s   
zCallbackHandler.on_llm_endc                K   rW   )Non_llm_errorr^   ro   r_   r&   r&   r'   rq      r[   zCallbackHandler.on_llm_error	input_strc                K   rN   )Non_tool_start)rr   rP   )r%   rK   rr   rM   rI   rJ   rT   r&   r&   r'   rs     s   

zCallbackHandler.on_tool_startoutputc                K   rW   )Non_tool_end)rt   rY   )r%   rt   rM   rI   rT   r&   r&   r'   ru     r[   zCallbackHandler.on_tool_end)rI   tagsrv   c                K   rW   )Non_tool_errorr^   rY   r%   r\   rM   rI   rv   rT   r&   r&   r'   rw     s   	zCallbackHandler.on_tool_errorqueryc                K   rN   )Non_retriever_start)ry   rP   )r%   rK   ry   rM   rI   rJ   rT   r&   r&   r'   rz   *  rU   z"CallbackHandler.on_retriever_start	documentsc                K   rW   )Non_retriever_end)r{   rY   )r%   r{   rM   rI   rT   r&   r&   r'   r|   :  s   z CallbackHandler.on_retriever_endc                K   s$   | j d|||d | ||| dS )zRun when Retriever errors.on_retriever_errorr^   NrY   rx   r&   r&   r'   r}   G  s   
z"CallbackHandler.on_retriever_erroractionc                K   s:   | j d|||d | || | jd|||fi | dS )zRun on agent action.on_agent_action)r~   NrP   )r%   r~   rM   rI   rT   r&   r&   r'   r   T  s   	zCallbackHandler.on_agent_actionfinishc                K   rW   )Non_agent_finish)r   rY   )r%   r   rM   rI   rT   r&   r&   r'   r   a  r[   zCallbackHandler.on_agent_finishc                 C   s   |dur|| j |< dS dS )zd
        Set the parent run ID for a chain run. If there is no parent, the run is the root.
        Nr?   )r%   rM   rI   r&   r&   r'   rR   l  s   z"CallbackHandler._set_parent_of_runc                 C   s(   z	| j | W dS  ty   Y dS w )z;
        Remove the parent run ID for a chain run.
        N)r?   popKeyError)r%   rM   r&   r&   r'   _pop_parent_of_runs  s
   z"CallbackHandler._pop_parent_of_runc                 C   s&   |}|| j v r| j | }|| j v s|S )z3
        Finds the root ID of a chain run.
        r   )r%   rM   idr&   r&   r'   _find_root_run|  s
   


zCallbackHandler._find_root_runr#   c                 K   sB   |d u rdnd}t |fi |p|}t||t d d| j|< d S )Ntracespanr    r#   r!   r"   )_get_langchain_run_namer   timer>   )r%   rK   r#   rM   rI   rT   default_namerun_namer&   r&   r'   rS     s
   z+CallbackHandler._set_trace_or_span_metadatainvocation_paramsc                 K   s   t |fi |p	d}t||t d d}t|tr(t||_|d }	r(|	|_t|trG|d }
r7|
|_	|d }rA||_
|d|_z|d d }|d urU||_W n	 ty_   Y nw || j|< d S )	N
generationr   r5   ls_model_namels_providerr6   rT   openai_api_base)r   r0   r   
isinstancedictr   r3   getr5   r2   r1   r6   r4   r   r>   )r%   rK   rM   r`   rJ   r   rT   r   r   r5   r2   r1   r4   r&   r&   r'   rh     s.   	


z!CallbackHandler._set_llm_metadatac                 C   sH   t   }z| j|}W n ty   td|  Y d S w ||_|S )NzNo run metadata found for run )r   r>   r   r   logwarningr"   )r%   rM   r"   runr&   r&   r'   _pop_run_metadata  s   z!CallbackHandler._pop_run_metadatac                 C   s   | j p| |}|s|S |S N)r:   r   )r%   rM   rA   r&   r&   r'   _get_trace_id  s   zCallbackHandler._get_trace_idc                 C   s   |dur|| j vr|S |S )zr
        Replace the parent run ID with the trace ID for second level runs when a custom trace ID is set.
        Nr   )r%   rA   rM   rI   r&   r&   r'   _get_parent_run_id  s   z"CallbackHandler._get_parent_run_idc                 C   sf   |  |}| | | |}|sd S t|tr#td| d d S | ||||| ||| d S )NRun zB is a generation, but attempted to be captured as a trace or span.)	r   r   r   r   r0   r   r   _capture_trace_or_spanr   )r%   rM   rI   rV   rA   r   r&   r&   r'   rZ     s"   




z2CallbackHandler._pop_run_and_capture_trace_or_spanr   c                 C   s   |d u rdnd}|t | j| jt|j|j|j|dd}|d ur$||d< | jr-|| j t	|t
rHt||d< d|d< t| j|| j| j|}n|d urVt | j| j||d	< | jd u r_d
|d< | jj| jpf|||| jd d S )Nz	$ai_tracez$ai_span	langchain)$ai_trace_idz$ai_input_state$ai_latency$ai_span_name$ai_span_id$ai_framework$ai_parent_id	$ai_errorT$ai_is_errorz$ai_output_stateF$process_person_profiler@   eventrB   rD   )r   r8   rF   r   r#   r(   r    r=   updater   BaseException_stringify_exception(_capture_exception_and_update_propertiesr9   rG   capture)r%   rA   rM   r   rV   rI   
event_nameevent_propertiesr&   r&   r'   r     sH   




z&CallbackHandler._capture_trace_or_spanc                 C   sf   |  |}| | | |}|sd S t|ts#td| d d S | ||||| ||| d S )Nr   zC is not a generation, but attempted to be captured as a generation.)	r   r   r   r   r0   r   r   _capture_generationr   )r%   rM   rI   rm   rA   r   r&   r&   r'   rp     s"   




z/CallbackHandler._pop_run_and_capture_generationc           
      C   sv  |||j ||j|j|jt| j| jt|jd|j	|j
dd}t|jtr*||j |jr2|j|d< | jr;|| j | jd u rDd|d< t|tret||d< t||d< d	|d
< t| j|| j| j|}nFt||j|j}|j|d< |j|d< |j|d< |j|d< |j|d< |jd }t|d trdd |D }	ndd |D }	t| j| j|	|d< | jj| jp|d|| jd d S )N   r   )r   r   r   r   z$ai_providerz	$ai_modelz$ai_model_parametersz	$ai_input$ai_http_statusr   z$ai_base_urlr   z	$ai_toolsFr   r   r   Tr   z$ai_input_tokensz$ai_output_tokensz$ai_cache_creation_input_tokensz$ai_cache_read_input_tokensz$ai_reasoning_tokensc                 S   s   g | ]
}t tt|jqS r&   )rb   r	   r   re   rc   r   r&   r&   r'   rf   k  s    z7CallbackHandler._capture_generation.<locals>.<listcomp>c                 S   s   g | ]}t |qS r&   )_extract_raw_responser   r&   r&   r'   rf   p  s    z$ai_output_choicesz$ai_generationr   ) r    r1   r2   r3   r   r8   rF   r   r#   r(   r4   r   r6   r   r   r5   r=   r9   r   _get_http_statusr   r   rG   _parse_usageinput_tokensoutput_tokenscache_write_tokenscache_read_tokensreasoning_tokensgenerationsr   r   )
r%   rA   rM   r   rt   rI   r   usagegeneration_resultcompletionsr&   r&   r'   r   ,  st   	


	






z#CallbackHandler._capture_generationr   c              
   K   s>   t d| dt|d d  dt|d d  d|  d S )NzEvent: z
, run_id:    z, parent_run_id: z
, kwargs: )r   debugr,   )r%   r   rM   rI   rT   r&   r&   r'   rQ     s   2z CallbackHandler._log_debug_eventr   NN):r)   r*   r+   __doc__r   r-   r   r   r,   intr
   r.   r   r   RunMetadataStorageboolrH   rO   rX   r   r]   r   r   ra   rj   rl   r   rn   rq   rs   ru   listrw   rz   r   r   r|   r}   r   r   r   r   rR   r   r   rS   rh   RunMetadatar   r   r   rZ   r   r   rp   r0   r   rQ   r&   r&   r&   r'   r7   Z   sv  
 
"













	



	





	


 




2



Wr7   c                 C   s8   | j dur| j  dkr| j  S t| dr| jjS dS )z<Extract the response from the last response of the LLM call.N re   )textstriphasattrre   additional_kwargs)last_responser&   r&   r'   r     s
   

r   
tool_callsr$   c                 C   s(   zdd | D W S  t y   |  Y S w )Nc              	   S   s0   g | ]}d |d |d t |d ddqS )functionr   r    args)r    	arguments)typer   r   )jsondumps)rc   	tool_callr&   r&   r'   rf     s    	z1_convert_lc_tool_calls_to_oai.<locals>.<listcomp>)r   )r   r&   r&   r'   _convert_lc_tool_calls_to_oai  s   	r   re   c                 C   s   t | trd| jd}nCt | tr"d| jd}| jr!t| j|d< n-t | tr.d| jd}n!t | tr:d| jd}nt | trFd| jd}n	| j	t
| jd}| jrX|| j d|v rd|d sdd	|d< |S )
Nuser)rolecontent	assistantr   systemtoolr   r   r   )r   r   r   r   r   r   r   r   r   r   r,   r   r   )re   message_dictr&   r&   r'   rb     s*   




rb   c                   @   sJ   e Zd ZU ee ed< ee ed< ee ed< ee ed< ee ed< dS )
ModelUsager   r   r   r   r   N)r)   r*   r+   r   r   r-   r&   r&   r&   r'   r     s   
 r   r   r1   r2   c                    sT  t | tr| j} g d}i  |D ]\}}|| v r+| | }t |tr%t|n|}| |< qd| v rIt | d trI| d d d< | d d d< d| v r]t | d tr]| d d d< dd	d
ddd}tdi  fdd| D }	d}
|r|	 dkrd}
n
|rd|	 v rd}
|
r|	j
r|	jpd|	jpd }|dkrt|	j
| d|	_
|	S )N))r   r#   )r   rt   cache_creation_input_tokenscache_writecache_read_input_tokens
cache_read)prompt_token_countr#   )candidates_token_countrt   )cached_content_token_countr   )thoughts_token_count	reasoning)inputTokenCountr#   )outputTokenCountrt   )cacheCreationInputTokenCountr   )cacheReadInputTokenCountr   )prompt_tokensr#   )completion_tokensrt   r   r   )input_token_countr#   )generated_token_countrt   input_token_detailscache_creationr   r   output_token_detailsr   r   r   r   r   r   )r#   rt   r   r   r   c                    s    i | ]\}}|  |pd qS )r   )r   )rc   
mapped_keydataclass_keyparsed_usager&   r'   
<dictcomp>  s    z&_parse_usage_model.<locals>.<dictcomp>F	anthropicTr   r&   )r   r   __dict__r   sumr   r   r   itemslowerr   r   r   max)r   r1   r2   conversion_list	model_keytype_keycaptured_countfinal_countfield_mappingnormalized_usageis_anthropiccache_tokensr&   r   r'   _parse_usage_model  s^   






r  rm   c                 C   s0  ddg}t d d d d d d}| jd ur(|D ]}| j|r't| j| ||} nqt| dr| jD ]e}d|v rAt|d ||} |S |D ]Q}|jrXd|jv rXt|jd ||} n=t|di }t|di }	t|	t	ro|	dd nd }
t|	t	r||	dd nd }t|dd }|
p|p|}|rt|||} nqCq0|S )	Ntoken_usager   )r   r   r   r   r   r   usage_metadatare   response_metadataz amazon-bedrock-invocationMetrics)
r   
llm_outputr   r  r   r   generation_infogetattrr   r   )rm   r1   r2   llm_usage_keys	llm_usagekeyr   generation_chunkmessage_chunkr  bedrock_anthropic_usagebedrock_titan_usageollama_usagechunk_usager&   r&   r'   r   /  sl   


'
	
r   rE   	exceptionr@   rD   r   c                 C   s(   | j r| j||||d}|r||d< |S )N)r@   rD   rB   z$exception_event_id)enable_exception_autocapturecapture_exception)rE   r  r@   rD   r   exception_idr&   r&   r'   r   r  s   r   r\   c                 C   s   t | dt | dd}|S )Nstatus_codecoder   )r  )r\   r"  r&   r&   r'   r     s   r   rK   rT   c              	   K   sr   d|v r|d dur|d S | du rdS z| d W S  t tfy$   Y nw z| d d W S  t tfy8   Y dS w )aw  Retrieve the name of a serialized LangChain runnable.

    The prioritization for the determination of the run name is as follows:
    - The value assigned to the "name" key in `kwargs`.
    - The value assigned to the "name" key in `serialized`.
    - The last entry of the value assigned to the "id" key in `serialized`.
    - "<unknown>".

    Args:
        serialized (Optional[Dict[str, Any]]): A dictionary containing the runnable's serialized data.
        **kwargs (Any): Additional keyword arguments, potentially including the 'name' override.

    Returns:
        str: The determined name of the Langchain runnable.
    r    Nr   r   )r   	TypeError)rK   rT   r&   r&   r'   r     s   
r   c                 C   s&   t | }|r| jj d| S | jjS )Nz: )r,   	__class__r)   )r  descriptionr&   r&   r'   r     s   r   r   )Glangchain_coreImportErrorModuleNotFoundErrorr   loggingr   dataclassesr   typingr   r   r   r   r   r   r	   uuidr
   langchain_core.agentsr   r   langchain_core.callbacks.baser   langchain.callbacks.baselangchain.schema.agentlangchain_core.documentsr   langchain_core.messagesr   r   r   r   r   r   r   langchain_core.outputsr   r   pydanticr   r   r   posthog.ai.sanitizationr   posthog.ai.utilsr   r   posthog.clientr   	getLoggerr   r   r0   r   r   r7   r   r   r   r,   r   rb   r   r  r   r   r   r   r   r   r   r&   r&   r&   r'   <module>   s    $	$	
    5



`
C


!