o
    i                     @   s  d dl mZ d dlZd dlmZ d dlmZ d dlmZ d dlmZ d dl	m
Z
 d dlmZ d d	lmZ d d
lmZ d dlmZ d dlmZ d dlmZ d dlmZ d dlmZ d dlmZ d dlmZ d dlmZ d dlmZ d dlmZ d dlmZ d dlmZ d dlmZ d dlm Z  d dlm!Z! d dlm"Z" d dlm#Z# d dlm$Z$ d dlm%Z% d dlm&Z& d dlm'Z' d d lm(Z( d d!l)m*Z* d d"l+m,Z, d d#l+m-Z- d d$l+m.Z. d d%l+m/Z/ d d&l+m0Z0 d d'l1m2Z2 d d(l1m3Z3 d d)l1m4Z4 d d*l1m5Z5 d d+l6m7Z7 d d,l6m8Z8 d d-l6m9Z9 d d.l6m:Z: d d/l;m<Z< ee=Z>d0Z?d1Z@d2ZAd3ZBd4ZCd5ZDd6ZEd7ZFd8ZGd9ZHd:d;d<d=ZIg d>ZJg d?ZKd@dA ZLdLdCeMe dDeNdEeMe fdFdGZOdHdI ZPG dJdK dKe*ZQdS )M    )defaultdictN)Any)Optional)Union)WeakKeyDictionary)core)
get_logger)ArgumentError)get_argument_value)format_trace_id)LLMObs)DISPATCH_ON_LLM_TOOL_CHOICE)DISPATCH_ON_TOOL_CALL)!DISPATCH_ON_TOOL_CALL_OUTPUT_USED)INPUT_DOCUMENTS)INPUT_MESSAGES)INPUT_PROMPT)INPUT_TOKENS_METRIC_KEY)INPUT_VALUE)METADATA)METRICS)
MODEL_NAME)MODEL_PROVIDER)OUTPUT_DOCUMENTS)OUTPUT_MESSAGES)OUTPUT_TOKENS_METRIC_KEY)OUTPUT_VALUE)PROXY_REQUEST)	SPAN_KIND)
SPAN_LINKS)TOTAL_TOKENS_METRIC_KEY)BaseLLMIntegration)LANGCHAIN_ROLE_MAPPING)$extract_instance_metadata_from_stack)format_langchain_io)set_prompt_tracking_tags)(update_proxy_workflow_input_output_value)	_get_attr)_get_nearest_llmobs_ancestor)_validate_prompt)	safe_json)Document)Message)ToolCall)	_SpanLink)Spanzlangchain.request.api_keyzlangchain.request.modelzlangchain.request.providerzlangchain.tokens.total_costzlangchain.request.type	anthropicamazon_bedrockopenaiazurevertexaiuser	assistantsystem)humanair7   )llmchatchain	embedding	retrievaltoolrunnable_lambda)api_baseapi_hostanthropic_api_urlbase_urlendpointendpoint_urlcerebras_api_basegroq_api_baseinference_server_urlopenai_api_baseupstage_api_basexai_api_basec                 C   s,   t | dr
t| jS t | drt| jS | S )aW  
    Extracts the bound object from a RunnableBinding or RunnableAssign instance.
    LangChain will sometimes stick things we trace (chat models) in these runnables,
    and they will show up as steps in the chain instead of the model instance itself.

    Additionally, these can be nested, so we need to extract the innermost instance.
    boundmapper)hasattr_extract_instancerM   rN   instance rS   Z/home/ubuntu/.local/lib/python3.10/site-packages/ddtrace/llmobs/_integrations/langchain.pyrP   Y   s
   



rP   Tstepsnestedreturnc                 C   sz   g }| D ]6}t |}t|dr5t|di }g }| D ]}t |}|| q|r/|| q|| q|| q|S )z
    Flattens the contents of a chain into non-RunnableBindings and non-RunnableParallel steps.
    RunnableParrallel steps are extracted and can either be nested into sublists or flattened.
    steps__)rP   rO   getattrvaluesappendextend)rU   rV   flattened_stepsstepparallel_stepsflattened_parallel_stepsparallel_steprS   rS   rT   _flattened_chain_stepsh   s   
rb   c                 C   s   | ot | dS )z5Determines if the given instance is a chain instance.rU   )rO   rQ   rS   rS   rT   _is_chain_instance   s   rc   c                   @   s  e Zd ZU dZe Zeed< 	 defddZ		d]dede	e
 d	eee
f d
ee
 deddfddZdeddfddZdedee	e ef fddZdede	e defddZdedede	e deddf
ddZdede	e de	e dede	e f
ddZ	d^dede	e deded ee	e  ddfd!d"Zd#e
ddfd$d%Zd#e
defd&d'Zded	eee
f ddfd(d)Zd*eee
f deee
f fd+d,Z	-d_dede	e
 d	eee
f d.e
d/eddfd0d1Z	-d_dede	e
 d	eee
f d2e
d/eddfd3d4Zd5e
de	e fd6d7Z de	e! fd8d9Z"ded:e
ddfd;d<Z#	-d_dede	e
 d	eee
f d=e$e	e% e	e	e%  df d/eddfd>d?Z&	-d_dede	e
 d	eee
f d@e$e	e
 df d/eddfdAdBZ'dedCeee
f dDe(ddfdEdFZ)dede	e
 d	eee
f d
e
ddf
dGdHZ*				d`dedIedJee dKee dLee ddfdMdNZ+dCeee
f deeeef fdOdPZ,dQdR Z-deeeeef ee f fdSdTZ.d	eee
f dee fdUdVZ/de	e
 d	eee
f fdWdXZ0de	e
 d	eee
f fdYdZZ1defd[d\Z2dS )aLangChainIntegration	langchain
_instancesspanc                 C   s   | j sd S t|}|| j|< t|}|r| j|nd }|d u s$t|s&d S t|di }||t|< z	t|d| W d S  t	yJ   ||j
d< Y d S w )N_datadog_spans)llmobs_enabledrP   rf   r(   getrc   rY   idsetattr	Exception__dict__)selfrR   rg   parent_spanparent_instancespansrS   rS   rT   record_instance   s   
z$LangChainIntegration.record_instanceN argskwargsresponse	operationrW   c                    s  | j sdS |tvrtd| dS | | |t d}d} r\ tr)d}n' t	r5|dkr5d}nt
 fdd	ttfD rEd
}n|dkrP trPd}t|p[|tdu }|dkrx| j|||||d t||rsd dS d dS |dkr| j|||||d t||rd dS d dS |dkr| j||||d dS |dkr| j|||||d dS |dkr| j|||||d dS |dkr| j|||d dS |dkr| |||| dS dS )z@Sets meta tags and metrics for span events to be sent to LLMObs.NzUnsupported operation : %sFcustombedrockr:   r4   c                 3   s    | ]}| v V  qd S NrS   ).0providermodel_providerrS   rT   	<genexpr>       z8LangChainIntegration._llmobs_set_tags.<locals>.<genexpr>r2   r;   r0   T)is_workflowworkflowr<   )outputsr=   r>   r?   )tool_inputstool_outputr@   )ri   SUPPORTED_OPERATIONSlogwarning
_set_linksget_tagPROVIDER
startswithBEDROCK_PROVIDER_NAMEVERTEXAI_PROVIDER_NAMEanyOPENAI_PROVIDER_NAMEAZURE_OAI_PROVIDER_NAMEANTHROPIC_PROVIDER_NAMEr   _integration_is_enabled_get_ctx_itemr   _llmobs_set_tags_from_llmr&    _llmobs_set_tags_from_chat_model _llmobs_set_meta_tags_from_chain$_llmobs_set_meta_tags_from_embedding,_llmobs_set_meta_tags_from_similarity_search_llmobs_set_meta_tags_from_tool*_llmobs_set_meta_tags_from_runnable_lambda)ro   rg   ru   rv   rw   rx   r   llmobs_integrationrS   r~   rT   _llmobs_set_tags   sJ   	


z%LangChainIntegration._llmobs_set_tagsc                 C   sd   | j |}|s
dS t|}|du rdS | ||\}}| ||| | |||| | | dS )a  
        Sets span links for the given LangChain span, by doing the following:
        1. Determine the invoker spans, and if the invoker spans are from the output of those spans or inputs.
        2. Set the input links from the invoker spans, and either from the input or output of the invoker spans.
        3. Set the output span links, which could involve overwriting span links from a previous output step in a chain.
        N)rf   rj   r(   _get_invoker_spans_set_input_links_set_output_links_clear_instance_recordings)ro   rg   rR   rp   invoker_spansfrom_outputrS   rS   rT   r      s   zLangChainIntegration._set_linksrp   c                    sl  | j |}|du st|s|gdfS t|dg }t|}d}|d }d}t|di  t|tkrt|trCtfdd|D st| v sYt|tr[t fd	d|D r[|}|d
7 }|t	|krfn|| }t|tkrt|trCtfdd|D rC|dkr|gdfS || }	t|	trg }
|	D ]} t|}|r|

| q|
dfS  t|	 gdfS )a  
        Gets a list of invoker spans, and whether the current instance is from the output of the invoker spans.
        Will return:
        - A list of just the parent span if there is no parent langchain instance, or that instance is not a chain.
        - A list of invoker spans if the current instance is from the output of the invoker spans.

        The current instance is from the output of the invoker spans if the instance is part of a chain and not
          the first traced step.
        NFrU   r   rh   c                 3   s     | ]}t |t  kV  qd S r{   rk   r|   sub_steprQ   rS   rT   r     s    z:LangChainIntegration._get_invoker_spans.<locals>.<genexpr>c                 3   s    | ]	}t | v V  qd S r{   r   r   )chain_spansrS   rT   r     s       T)rf   rj   rc   rY   rb   rk   
isinstancelistr   lenr[   )ro   rR   rp   parent_langchain_instancerU   flatmap_chain_stepscurr_idx	curr_stepprev_traced_step_idxinvoker_stepsr   r^   rg   rS   )r   rR   rT   r      sR   




z'LangChainIntegration._get_invoker_spansr   r   c                 C   s   | j |||rdnddd dS )z3Sets the input links for the given span (to: input)outputinput)rg   
from_spans	link_fromlink_toN)_set_span_links)ro   rg   r   r   rS   rS   rT   r     s   

z%LangChainIntegration._set_input_linksc                 C   s8   | tpg }| ||||}| j||gdd|d dS )a  
        Sets the output links for the parent span of the given span (to: output)
        This is done by removing span links of previous steps in the chain from the parent span (if it is a chain).
        We add output->output span links at every step.
        r   )rg   r   r   r   popped_span_link_indicesN)r   r   _get_popped_span_link_indicesr   )ro   rg   rp   r   r   parent_linkspop_indicesrS   rS   rT   r   &  s   
z&LangChainIntegration._set_output_linksr   c                    sP   | j |}|r
|sg S t|}t|sg S dd |D   fddt|D S )a  
        Returns a list of indices to pop from the parent span links list
        This is determined by if the parent span represents a chain, and if there are steps before the step
        represented by the span that need to be removed.

        This is a temporary stopgap until we trace virtually every step in the chain, and we know the last
        step will be the last one traced.
        c                 S   s   g | ]}t |jqS rS   )strspan_id)r|   rg   rS   rS   rT   
<listcomp>J  s    zFLangChainIntegration._get_popped_span_link_indices.<locals>.<listcomp>c                    s    g | ]\}}|d   v r|qS )r   rS   r|   ilinkinvoker_span_idsrS   rT   r   K       )rf   rj   rP   rc   	enumerate)ro   rp   r   r   r   rq   rS   r   rT   r   7  s   z2LangChainIntegration._get_popped_span_link_indicesr   r   r   r   c                    sX   | tpg }rfddt|D } fdd|D }|r*|t||  dS dS )zDSets the span links on the given span along with the existing links.c                    s   g | ]
\}}| vr|qS rS   rS   r   )r   rS   rT   r   Y      z8LangChainIntegration._set_span_links.<locals>.<listcomp>c                    s4   g | ]}|d urt t|jt|j ddqS )N)fromto)trace_idr   
attributes)r.   r   r   r   r   )r|   	from_span)r   r   rS   rT   r   [  s    N)r   r   r   _set_ctx_item)ro   rg   r   r   r   r   existing_linkslinksrS   )r   r   r   rT   r   M  s   	
z$LangChainIntegration._set_span_linksrR   c                 C   s(   t |sdS t|drt|d dS dS )a\  
        Deletes the references of steps in a chain from the instance id to span mapping.

        The relevant instances will be recorded again if they are reused in another chain when
        the other chain is invoked.

        We attempt to remove the current instance as well if it has no parent or its parent instance is not a chain.
        Nrh   )rc   rO   delattr)ro   rR   rS   rS   rT   r   h  s
   	
z/LangChainIntegration._clear_instance_recordingsc                 C   sN   zt |g dddddd\}}W n ty   td Y dS w | d| S )	a  
        Attempts to find the variable name used for the prompt template instance by inspecting
        the caller's frame locals and globals, and returns it in the format:
        {integration_name}.{reflected_module/file_name}.{reflected_variable_name}
        )rR   ro   r^   unknown_prompt_templatere      
   )rR   internal_variable_namesdefault_variable_namedefault_module_nameframe_start_offsetframe_search_depthz&Failed to extract prompt variable name.)r#   rm   r   r   )ro   rR   variable_namemodule_namerS   rS   rT   _get_prompt_variable_namew  s   
z.LangChainIntegration._get_prompt_variable_namec                 C   sb   | dd }|s
d S | |}| D ]}|r nt|tsq| |}q|r/|t| d S d S )Nz_dd.identifying_params)pop_llmobs_extract_parametersrZ   r   dictr   r   )ro   rg   rv   identifying_paramsmetadatavalrS   rS   rT   _llmobs_set_metadata  s   

z)LangChainIntegration._llmobs_set_metadata
parametersc                 C   sv   i }d }d }d|v r|d }dD ]}||v r|| } nq|d ur+|dkr+t ||d< |d ur9|dkr9t||d< |S )Ntemperature)
max_tokens	maxTokensmax_completion_tokensNoner   )floatint)ro   r   r   r   r   max_token_keyrS   rS   rT   r     s   z/LangChainIntegration._llmobs_extract_parametersFcompletionsr   c              
   C   s:  |rt nt}|r
tnt}|d}t||d|rdnd}	t|	ts&t|	ts)|	g}	|r1| 	|	}
ndd |	D }
|
t|r?dndt|tpGd	t|tpNd	||
i | || |jrh||td	d
g d S |rqt|d
g}n$dd |jD }|s| |\}}}|dkrt|t|t|i}|t| ||| d S )Nlangchain.request.streamr   r   promptsc                 S      g | ]	}t t|d qS )content)r,   r   )r|   promptrS   rS   rT   r         zBLangChainIntegration._llmobs_set_tags_from_llm.<locals>.<listcomp>r   r:   rt   r   c                 S   s   g | ]
}t |d  jdqS )r   r   )r,   text)r|   
completionrS   rS   rT   r     r   )r   r   r   r   r   r
   r   r   r   _handle_stream_input_messages_set_ctx_itemsr   r   MODELr   r   r   errorr   r,   generations$check_token_usage_chat_or_llm_resultr   r   r    r   )ro   rg   ru   rv   r   r   input_tag_keyoutput_tag_keystreamr   input_messagesmessage_contentinput_tokensoutput_tokenstotal_tokensmetricsrS   rS   rT   r     s@   
	z.LangChainIntegration._llmobs_set_tags_from_llmchat_completionsc                 C   s  | t|rdndt|tpdt|tpdi | || |r#tnt	}|r)t
nt}|d}g }	|rAt||dd}
| |
}	n[t||dddd	pKg }
t|
tsT|
g}
|
D ]E}|D ]@}t|trg|d
dnt|d
d}t|dtt|ddd}|	tt|t|d t|dd}|s|rtt||f qZqV|||	 |jr||tddg d S g }|r|j}|jj dd! }||t|t|ddg d S d\}}}d}|s| "|\}}}|dk}t#dd }t|dg D ]}|D ]~}|j$}t|dt|j%d}tt|j&|d}| '|}|sG|D ]$}tt(|dd|ddt)|di t*|j+t|j,df q|rG||d< || |sv|sv| -|\}}|d u r_q|\}}}||| d< ||| d< ||| d< qq|s|st.dd |/ D }t.d d |/ D }t.d!d |/ D }||| |s|dkrt0|t1|t2|i}|t3| d S d S d S )"Nr   r:   rt   r   r   r   messagesToptionalr   roletype)r   r  tool_call_idr   MessageChunkr   r   r   Fc                   S   s   t tS r{   )r   r   rS   rS   rS   rT   <lambda>  s    zGLangChainIntegration._llmobs_set_tags_from_chat_model.<locals>.<lambda>r   tool_idname	arguments)r   r   
tool_callsr  r  r  c                 s       | ]}|d  V  qdS )r  NrS   r|   vrS   rS   rT   r   A  r   zHLangChainIntegration._llmobs_set_tags_from_chat_model.<locals>.<genexpr>c                 s   r  )r  NrS   r  rS   rS   rT   r   B  r   c                 s   r  )r  NrS   r  rS   rS   rT   r   C  r   )4r   r   r   r   r   r   r   r   r   r   r   r   r
   r   r   r   r   rj   rY   ROLE_MAPPINGr[   r,   r   r'   r   dispatchr   r   r   r   	__class____name__replacelowerr   r   messager  r   _extract_tool_callsr   r*   r   r   r   check_token_usage_ai_messagesumrZ   r   r   r    r   )ro   rg   ru   rv   r  r   r   r   r   r  chat_messagesmessage_setr  r   r  r  output_messagesr  r  r  tokens_set_top_leveltokens_per_choice_run_idchat_completionchat_completion_msgoutput_messagetool_calls_info	tool_calltokensrun_idr  rS   rS   rT   r     s   

 






#z5LangChainIntegration._llmobs_set_tags_from_chat_modelr(  c                 C   sb   t |dd}g }|r/t|ts|g}|D ]}t|dd|di |ddd}|| q|S )z5Extracts tool calls from a langchain chat completion.r  Nr  rt   ru   rk   )r  r  r  )rY   r   r   r-   rj   r[   )ro   r(  r  r*  r+  tool_call_inforS   rS   rT   r  O  s   



z(LangChainIntegration._extract_tool_callsc                 C   s   g }t |dr| }nt|ts|g}|D ]@}t }d\}}t|tr2t|dd}|d}nt |drAt|j}|j	j
}nt|}||d< |d urQ||d< || q|S )Nto_messages)NNr   rt   r  )rO   r/  r   r   r,   r   r   rj   r   r  r  r[   )ro   inputsr  inpinp_messager   r  rS   rS   rT   r   _  s(   






z2LangChainIntegration._handle_stream_input_messagesr   c                 C   sf   | drt||dd}n|}d}|d urt|}d}|js&|d ur&t|}|tdt|t|i d S )Nr   r   r   rt   r   )r   r
   r$   r   r   r   r   r   )ro   rg   ru   rv   r   r0  formatted_inputsformatted_outputsrS   rS   rT   r   x  s   
z5LangChainIntegration._llmobs_set_meta_tags_from_chainoutput_embeddingc              
   C   s  | t|rdndt|tpdt|tpdi |rtnt}t	}z	t
||dd}W n ty:   t
||dd}Y nw z7t|tsOt|trqtdd |D rq|r\t|}	|||	 nt|trd|g}d	d
 |D }
|||
 W n ty   td Y nw |js|d u r||d d S z&t|d tr|g}d}n|}t|}t|d }||d|| W d S  ttfy   td| Y d S w )Nr   r=   rt   r   textsr   c                 s   s    | ]}t |tV  qd S r{   r   r   )r|   r   rS   rS   rT   r     s    zLLangChainIntegration._llmobs_set_meta_tags_from_embedding.<locals>.<genexpr>c                 S   r   )r   )r+   r   )r|   docrS   rS   rT   r     r   zMLangChainIntegration._llmobs_set_meta_tags_from_embedding.<locals>.<listcomp>z0Failed to serialize embedding input data to JSONr   z'[{} embedding(s) returned with size {}]zFailed to write output vectors)r   r   r   r   r   r   r   r   r   r   r
   r	   r   r   r   allr$   r   	TypeErrorr   r   r   r   r   format
IndexError)ro   rg   ru   rv   r5  r   r   r   input_textsr3  input_documentsoutput_valuesembeddings_countembedding_dimrS   rS   rT   r     s^   



z9LangChainIntegration._llmobs_set_meta_tags_from_embeddingoutput_documentsc              
   C   s  | t|rdndt|tpdt|tpdi t||dd}|d ur.t|}|	t
| |js8|r8t|ts@|	td d S |rO|	tdt| d S g }|D ]%}	t|	jd}
t|	dd|
d< t|	d	i }|d
|
d |
d
< ||
 qS|	tt| |	tdt| d S )Nr   r>   rt   r   queryz[{} document(s) retrieved]r8  rk   r   r  )r   r   r   r   r   r   r   r
   r$   r   r   r   r   r   r   r<  r   r+   page_contentrY   rj   r[   r   )ro   rg   ru   rv   rC  r   input_queryr3  	documentsdr9  r   rS   rS   rT   r     s2   zALangChainIntegration._llmobs_set_meta_tags_from_similarity_searchr   r   c           
   
   C   s   | trtt| tni }d}|d urJ| |\}}}tt||d||f |	dr6|	d|d< |	drB|	d|d< t
|	di }d}	|jsW|d urWt
|}	|tdt|t|t|	i d S )	Nrt   functionconfigtool_configinfo	tool_infor   r?   )r   r   jsonloadsr   #_extract_tool_call_args_from_inputsr   r  r   rj   r$   r   r   r   r   r   )
ro   rg   r   r   r   formatted_input	tool_namer  	tool_argsr4  rS   rS   rT   r     s.   "

z4LangChainIntegration._llmobs_set_meta_tags_from_toolc              	   C   s0   t ||dd}|tdtt|tt|i d S )Nr   r0  task)r
   r   r   r   r*   r   )ro   rg   ru   rv   rw   r0  rS   rS   rT   r     s   z?LangChainIntegration._llmobs_set_meta_tags_from_runnable_lambdainterface_typer}   modelapi_keyc                 K   s0   |dur
| t| |dur| t| dS dS )zYSet base level tags that should be present on all LangChain spans (if they are not None).N)_set_tag_strr   r   )ro   rg   rU  r}   rV  rW  rv   rS   rS   rT   _set_base_span_tags	  s
   
z(LangChainIntegration._set_base_span_tagsc                 C   s   | di }d\}}}t|tr&|}| di }t|tr%| ddp$d}nt|ddp-d}t|ddp5d}tt|di p>i }|||fS )z
        Extract tool name, tool id, and tool args from a tool call input.

        If the tool input is a string, then the entire string is assumed to be the tool call args.
        r   )rt   rt   rt   rL  r  rt   rk   ru   )rj   r   r   r   r'   r*   )ro   r   
tool_inputrR  r  rS  rM  rS   rS   rT   rP    s   



z8LangChainIntegration._extract_tool_call_args_from_inputsc              
   C   s   t |di }|du rdS |d|d|di }|du s#t|ts%dS |ddp2|d	dp2d}|d
dp@|ddp@d}|d|| pJd}|||fS )zFChecks for token usage on the top-level ChatResult or LLMResult object
llm_outputNr  token_usageusage_metadatausageprompt_tokensr   r  completion_tokensr  r  )rY   rj   r   r   )ro   resultr[  r\  r  r  r  rS   rS   rT   r   +  s   
z9LangChainIntegration.check_token_usage_chat_or_llm_resultc           	      C   s   t |dd}t |ddpt |dd}|r d|ddd nd}t |di }|p3|d	p3|d
}|du s=t|tsAd|fS |ddpL|dd}|ddpX|dd}|d|| }|||f|fS )z.Checks for token usage on an AI message objectr]  Nrk   r-  rt   -r   response_metadatar^  r\  r  r  r   r_  r  r`  r  )rY   joinsplitrj   r   r   )	ro   
ai_messager^  r-  run_id_baserc  r  r  r  rS   rS   rT   r   <  s    z1LangChainIntegration.check_token_usage_ai_messagec                 K   s8   | d}d }tD ]
}t||d p|}q	|rt|S d S )NrR   )rj   LANGCHAIN_BASE_URL_FIELDSrY   r   )ro   rv   rR   rD   fieldrS   rS   rT   _get_base_urlQ  s
   
z"LangChainIntegration._get_base_urlc              	   C   s(  d\}}}t |drt|jtr|j}tt|ddtr|durtt|ddtrg }t|jt|jkr<t	d dS t
|j|jD ]K\}	}
t|
dd}|sZt |
drZt|
j}|s^d}t |	d	rm|||	jd
 qCt |	drt |	jdr||t|	jjpdd
 qCg }t	d  |r|nd}i }tt|ddtr|j}dd | D }t||dddd}t|trtt|ddtrt|jdkr|jd |i}|s|r|r|s|rt|tsdS | |}||||dur|ndg g |d}z
t|d| W dS  ttfy   td Y dS w )zdOn prompt template invoke, store the template on the result so its available to consuming .invoke().)NNNtemplater  Nz_Instance messages and result messages have different lengths; message placeholder not supportedr  r  unknownr   )r  r   r   rt   z!Failed to parse template messagesr   c                 S   s    i | ]\}}t |tr||qS rS   r7  )r|   keyvaluerS   rS   rT   
<dictcomp>  r   zFLangChainIntegration.handle_prompt_template_invoke.<locals>.<dictcomp>r   r   Tr	  input_variablesr   )	variablesrk  chat_templaterk   rag_context_variablesrag_query_variablestags_dd.prompt_templatez4Could not attach prompt metadata to resulting prompt)rO   r   rk  r   rY   r   r   r  r   debugzipr"   rj   r  r[   r   r   r   r   itemsr
   rp  r   object__setattr__AttributeErrorr;  r   )ro   rR   ra  ru   rv   rr  rk  rq  r  mrr  ru  r   	prompt_idr   rS   rS   rT   handle_prompt_template_invokeX  s   




z2LangChainIntegration.handle_prompt_template_invokec                 C   s@   d}t ||dddd}|rt|dd}|rt|d| dS dS )zeOn llm invoke, take any template from the input prompt value and make it available to llm.generate().Nr   r   Tr	  rv  )r
   rY   rz  r{  )ro   rR   ru   rv   rk  prompt_inputrS   rS   rT   handle_llm_invoke  s   z&LangChainIntegration.handle_llm_invokec              
   C   sv   t |dd}|dur9|}zt|dd}|t| t| W dS  ty8 } ztd| W Y d}~dS d}~ww dS )z
        On llm.generate(), BEFORE you call .generate(), take any template we have and write it to the span.
        Since child spans may need to read the tagged data, we must tag before calling the wrapped function.
        rv  NT)strict_validationz#Failed to validate langchain prompt)rY   r)   r   r   r%   rm   r   rw  )ro   rR   rg   prompt_value_metar   erS   rS   rT   llmobs_set_prompt_tag  s   z*LangChainIntegration.llmobs_set_prompt_tag)Nrt   r{   )F)rt   NNN)3r  
__module____qualname___integration_namer   rf   __annotations__r/   rs   r   r   r   r   r   r   r   tupleboolr   r   r   r.   r   r   r   r   r   r   r   r   r   r-   r  r,   r   r   r   r   r   r   rz  r   r   rY  rP  r   r   rj  r  r  r  rS   rS   rS   rT   rd      s(  
 

52"	


"

3

v

?

"$


$$P	rd   )T)Rcollectionsr   rN  typingr   r   r   weakrefr   ddtrace.internalr   ddtrace.internal.loggerr   ddtrace.internal.utilsr	   r
   ddtrace.internal.utils.formatsr   ddtrace.llmobsr   ddtrace.llmobs._constantsr   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r    !ddtrace.llmobs._integrations.baser!   "ddtrace.llmobs._integrations.utilsr"   r#   r$   r%   r&   ddtrace.llmobs._utilsr'   r(   r)   r*   ddtrace.llmobs.typesr+   r,   r-   r.   ddtrace.tracer/   r  r   API_KEYr   r   
TOTAL_COSTTYPEr   r   r   r   r   r  r   rh  rP   r   r  rb   rc   rd   rS   rS   rS   rT   <module>   s     