o
    gc                     @   s  zd dl Z W n ey   edw 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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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(m)Z) d dl*m+Z+ e,dZ-eG dd dZ.eG dd de.Z/ee.e/f Z0e	ee0f Z1G dd deZ2dd Z3dede	e4ef fddZ5dee$e	f deee6df ee6df f fddZ7de"fd d!Z8d"e9de6fd#d$Z:d%ee	e4ef  d&edee4 fd'd(Z;d)e9de4fd*d+Z<dS ),    NzEPlease install LangChain to use this feature: 'pip install langchain')	dataclass)AnyDictListOptionalSequenceTupleUnioncast)UUID)BaseCallbackHandler)AgentActionAgentFinish)Document)	AIMessageBaseMessageFunctionMessageHumanMessageSystemMessageToolMessage)ChatGeneration	LLMResult)	BaseModel)default_client)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%   U/var/www/visachat/venv/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   #   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S )GenerationMetadataNprovidermodelmodel_paramsbase_url)r(   r)   r*   r0   r   r+   r,   r1   r2   r   r   r3   r%   r%   r%   r&   r/   5   s   
 r/   c                   @   s  e Zd ZU dZeed< 	 e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
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.
    _client_distinct_id	_trace_id_trace_input_trace_name_properties_runs_parent_treeNF)distinct_idtrace_id
propertiesprivacy_modegroupsclientr=   r>   r?   r@   rA   c                C   sT   |pt }|du rtd|| _|| _|| _|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.
        NzPostHog client is required)
r   
ValueErrorr5   r6   r7   r:   _privacy_mode_groupsr;   r<   )r$   rB   r=   r>   r?   r@   rA   posthog_clientr%   r%   r&   __init__e   s   


zCallbackHandler.__init__)parent_run_idmetadata
serializedinputsrun_idrH   rI   c                K   s:   | j d|||d | || | j||||fi | d S )Non_chain_start)rK   _log_debug_event_set_parent_of_run_set_trace_or_span_metadata)r$   rJ   rK   rL   rH   rI   kwargsr%   r%   r&   rM      s   
zCallbackHandler.on_chain_start)rH   outputsrR   c                K   $   | j d|||d | ||| d S )Non_chain_end)rS   rO   "_pop_run_and_capture_trace_or_span)r$   rS   rL   rH   rR   r%   r%   r&   rU         zCallbackHandler.on_chain_enderrorc                K   rT   )Non_chain_errorrY   rV   r$   rY   rL   rH   rR   r%   r%   r&   rZ      rX   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>rO   rP   _set_llm_metadata)r$   rJ   r]   rL   rH   rR   r"   r%   r%   r&   r^      s   	z#CallbackHandler.on_chat_model_startpromptsc                K   s8   | j d|||d | || | j|||fi | d S )Non_llm_start)rf   rd   )r$   rJ   rf   rL   rH   rR   r%   r%   r&   rg      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)rh   N)rO   )r$   rh   rL   rH   rR   r%   r%   r&   ri      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)rj   rR   NrO   _pop_run_and_capture_generation)r$   rj   rL   rH   rR   r%   r%   r&   rk      s   zCallbackHandler.on_llm_endc                K   rT   )Non_llm_errorr[   rl   r\   r%   r%   r&   rn      rX   zCallbackHandler.on_llm_error	input_strc                K   .   | j d|||d | j||||fi | d S )Non_tool_start)ro   rO   rQ   )r$   rJ   ro   rL   rH   rI   rR   r%   r%   r&   rq         
zCallbackHandler.on_tool_startoutputc                K   rT   )Non_tool_end)rt   rV   )r$   rt   rL   rH   rR   r%   r%   r&   ru      rX   zCallbackHandler.on_tool_end)rH   tagsrv   c                K   rT   )Non_tool_errorr[   rV   r$   rY   rL   rH   rv   rR   r%   r%   r&   rw      s   	zCallbackHandler.on_tool_errorqueryc                K   rp   )Non_retriever_start)ry   rr   )r$   rJ   ry   rL   rH   rI   rR   r%   r%   r&   rz     rs   z"CallbackHandler.on_retriever_start	documentsc                K   rT   )Non_retriever_end)r{   rV   )r$   r{   rL   rH   rR   r%   r%   r&   r|     rX   z CallbackHandler.on_retriever_endc                K   s$   | j d|||d | ||| dS )zRun when Retriever errors.on_retriever_errorr[   NrV   rx   r%   r%   r&   r}   #  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~   NrN   )r$   r~   rL   rH   rR   r%   r%   r&   r   0  s   	zCallbackHandler.on_agent_actionfinishc                K   rT   )Non_agent_finish)r   rV   )r$   r   rL   rH   rR   r%   r%   r&   r   =  rX   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$   rL   rH   r%   r%   r&   rP   H  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$   rL   r%   r%   r&   _pop_parent_of_runO  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$   rL   idr%   r%   r&   _find_root_runX  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$   rJ   r"   rL   rH   rR   default_namerun_namer%   r%   r&   rQ   a  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||_t|tr7|d }	r-|	|_|d }
r7|
|_	z|d d }|d urE||_
W n	 tyO   Y nw || j|< d S )N
generationr   ls_model_namels_providerrR   openai_api_base)r   r/   r   
isinstancedictr   r2   getr1   r0   r3   r   r;   )r$   rJ   rL   r]   rI   r   rR   r   r   r1   r0   r3   r%   r%   r&   re   m  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$   rL   r!   runr%   r%   r&   _pop_run_metadata  s   z!CallbackHandler._pop_run_metadatac                 C   s   | j p| |}|s|S |S N)r7   r   )r$   rL   r>   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$   r>   rL   rH   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   r/   r   r   _capture_trace_or_spanr   )r$   rL   rH   rS   r>   r   r%   r%   r&   rW     s   



z2CallbackHandler._pop_run_and_capture_trace_or_spanr   c                 C   s   |d u rdnd}|t | j| j|j|j|j|d}|d ur!||d< | jr*|| j t|t	r:t
||d< d|d< n|d urHt | j| j||d< | jd u rQd	|d
< | jj| jpX|||| jd d S )Nz	$ai_tracez$ai_span)$ai_trace_idz$ai_input_state$ai_latency$ai_span_name$ai_span_id$ai_parent_id	$ai_errorT$ai_is_errorz$ai_output_stateF$process_person_profiler=   eventr?   rA   )r   r5   rD   r"   r'   r   r:   updater   BaseException_stringify_exceptionr6   capturerE   )r$   r>   rL   r   rS   rH   
event_nameevent_propertiesr%   r%   r&   r     s0   



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   r/   r   r   _capture_generationr   )r$   rL   rH   rj   r>   r   r%   r%   r&   rm     s   



z/CallbackHandler._pop_run_and_capture_generationc                 C   s  |||j ||j|j|jt| j| j|jd|j|j	d}t
|tr1t||d< t||d< d|d< n3t|\}}||d< ||d< |jd	 }	t
|	d	 trSd
d |	D }
ndd |	D }
t| j| j|
|d< | jrm|| j | jd u rvd|d< | jj| jp}|d|| jd d S )N   )r   r   r   r   z$ai_providerz	$ai_modelz$ai_model_parametersz	$ai_input$ai_http_statusr   z$ai_base_urlr   r   Tr   z$ai_input_tokensz$ai_output_tokensc                 S   s   g | ]
}t tt|jqS r%   )r_   r
   r   rb   r`   r   r%   r%   r&   rc     s    z7CallbackHandler._capture_generation.<locals>.<listcomp>c                 S   s   g | ]}t |qS r%   )_extract_raw_esponser   r%   r%   r&   rc     s    z$ai_output_choicesFr   z$ai_generationr   )r   r0   r1   r2   r   r5   rD   r"   r'   r3   r   r   _get_http_statusr   _parse_usagegenerationsr   r:   r   r6   r   rE   )r$   r>   rL   r   rt   rH   r   input_tokensoutput_tokensgeneration_resultcompletionsr%   r%   r&   r     sH   	




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   rL   rH   rR   r%   r%   r&   rO     s   2z CallbackHandler._log_debug_eventr   NN):r(   r)   r*   __doc__r   r,   r   r	   r+   intr-   r   r   r   RunMetadataStorageboolrG   rM   rU   r   rZ   r   r   r^   rg   ri   r   rk   rn   rq   ru   listrw   rz   r   r   r|   r}   r   r   r   r   rP   r   r   rQ   re   RunMetadatar   r   r   rW   r   r   rm   r/   r   rO   r%   r%   r%   r&   r4   E   s^  
 
%













	



	





	




%



<r4   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 rb   )textstriphasattrrb   additional_kwargs)last_responser%   r%   r&   r   $  s
   

r   rb   r#   c                 C   s   t | trd| jd}n9t | trd| jd}n-t | tr$d| jd}n!t | tr0d| jd}nt | tr<d| jd}n	| jt| jd}| j	rN|
| j	 |S )Nuser)rolecontent	assistantsystemtoolfunction)r   r   r   r   r   r   r   typer+   r   r   )rb   message_dictr%   r%   r&   r_   1  s   




r_   usagec                 C   sl   t | tr| j} g d}i }|D ]\}}|| v r+| | }t |tr%t|n|}|||< q|d|dfS )N))r   r"   )r   rt   )prompt_token_countr"   )candidates_token_countrt   )inputTokenCountr"   )outputTokenCountrt   )input_token_countr"   )generated_token_countrt   r"   rt   )r   r   __dict__r   sumr   )r   conversion_listparsed_usage	model_keytype_keycaptured_countfinal_countr%   r%   r&   _parse_usage_modelF  s   
r   rj   c                 C   s   ddg}d}| j d ur|D ]}| j |rt| j | } nqt| drz| jD ]R}|D ]M}|jr>d|jv r>t|jd } n;t|di }t|di }t|trU|dd nd }t|trb|dd nd }	t|dd }
|po|	po|
}|rxt|} nq+q'|S )	Ntoken_usager   r   r   usage_metadatarb   response_metadataz amazon-bedrock-invocationMetrics)	
llm_outputr   r   r   r   generation_infogetattrr   r   )rj   llm_usage_keys	llm_usagekeyr   generation_chunkmessage_chunkr   bedrock_anthropic_usagebedrock_titan_usageollama_usagechunk_usager%   r%   r&   r   h  s@   


r   rY   c                 C   s   t | dt | dd}|S )Nstatus_codecoder   )r   )rY   r   r%   r%   r&   r     s   r   rJ   rR   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)rJ   rR   r%   r%   r&   r     s   
r   	exceptionc                 C   s&   t | }|r| jj d| S | jjS )Nz: )r+   	__class__r(   )r   descriptionr%   r%   r&   r     s   r   )=	langchainImportErrorModuleNotFoundErrorloggingr   dataclassesr   typingr   r   r   r   r   r   r	   r
   uuidr   langchain.callbacks.baser   langchain.schema.agentr   r   langchain_core.documentsr   langchain_core.messagesr   r   r   r   r   r   langchain_core.outputsr   r   pydanticr   r   r   posthog.ai.utilsr   r   posthog.clientr   	getLoggerr   r   r/   r   r   r4   r   r+   r_   r   r   r   r   r   r   r   r%   r%   r%   r&   <module>   sR    (
 
   b

"(&