o
    i                     @   s  d dl mZ d dlZd dl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'l.m1Z1 d d(l.m2Z2 ee3Z4d)Z5d*Z6d+Z7d,Z8d-Z9d.Z:d/Z;d0d1 Z<d2d3 Z=d4d5d6d7Z>d8d9 Z?d:ee@eAe@e@f f fd;d<ZBd=e@d>eCeDe@ef  d:eCe/ fd?d@ZE	AddBe
dCeDe@ef dDedEe@d:df
dFdGZF	AddBe
dCeDe@ef dHee dEe@d:df
dIdJZG	KddLeDe@ef dMee
 dNeHd:eAeCe0 eCe2 f fdOdPZI	KddQedRed>e@dBe
dSeHd:dfdTdUZJ	VddCeDe@ef dEe@dWe@d:eDe@ef fdXdYZKdHeee@eCeDe@ef  f  d:eCe/ fdZd[ZL	ddHeee@eCeDe@ef  f  d\ee@ d:eAeCe/ eCe@ f fd]d^ZM	dd_ee d`ed:eAeCe/ eCe1 f fdadbZN	ddHeCe d`ed:eAeCe/ eCe0 eCe1 f fdcddZO	dd_ee dCeeDe@ef  d:eDe@ef fdedfZPdged:e@fdhdiZQdged:e@fdjdkZRdled:e@fdmdnZSdoeDe@ef d:eDe@ef fdpdqZTdreCe doeDe@ef d:eCeDe@e@f  fdsdtZUdoeDe@ef d:eHfdudvZVdKdwdBe
dxeHd:dfdydzZW	ddBe
dCeDe@ef d_ee d`ed:df
d{d|ZXd}eCe d:eCe1 fd~dZYdeCe d:eDe@e@f fddZZdddZ[deCe d:eDe@ef fddZ\ddBe
de@fddZ]G dd dZ^G dd dZ_eG dd dZ`dLeDe@ef deDeae@f deDeaeDe@ef f d:e/fddZbecdZddddZedd Zfdee@eCea f d:eafddZg					ddedeeCe@  dee@ dee@ deadead:eAee@ ee@ f fddZhdS )    )	dataclassN)Any)Optional)Union)Span)core
get_logger)format_trace_id)DISPATCH_ON_LLM_TOOL_CHOICE)!DISPATCH_ON_TOOL_CALL_OUTPUT_USED)FILE_FALLBACK_MARKER)IMAGE_FALLBACK_MARKER)INPUT_MESSAGES)INPUT_PROMPT)INPUT_TOKENS_METRIC_KEY)INPUT_TYPE_FILE)INPUT_TYPE_IMAGE)INPUT_TYPE_TEXT)INPUT_VALUE)INSTRUMENTATION_METHOD_AUTO)METADATA)OAI_HANDOFF_TOOL_ARG)OUTPUT_MESSAGES)OUTPUT_TOKENS_METRIC_KEY)OUTPUT_VALUE)PROMPT_MULTIMODAL)&PROMPT_TRACKING_INSTRUMENTATION_METHOD)TAGS)TOOL_DEFINITIONS)TOTAL_TOKENS_METRIC_KEY)	_get_attr)_validate_promptload_data_value)	safe_json)safe_load_jsonMessage)ToolCall)ToolDefinition)
ToolResult)streamtemperaturetop_puser)
backgroundincludemax_output_tokensmax_tool_callsparallel_tool_callsprevious_response_idprompt	reasoningservice_tierstoretexttool_choicetop_logprobs
truncation)audiofrequency_penaltyfunction_call
logit_biaslogprobsmax_completion_tokens
max_tokens
modalitiesnr4   
predictionpresence_penaltyreasoning_effortresponse_formatseedr8   stopr9   stream_optionsr;   r<   web_search_options)best_ofechor?   rA   rB   rD   rF   rH   rK   rL   rM   suffix)timeoutrF   rM   rL   rC   rD   rE   rG   rH   r?   rA   rJ   rK   r;   r4   rB   r<   deployment_idrI   base_urlapi_baseapi_version
model_list)rO   rP   r?   rA   rB   rD   rF   rH   rL   rM   rQ   rU   rV   rW   custom_llm_providerzFAction\s*\d*\s*:[\s]*(.*?)[\s]*Action\s*\d*\s*Input\s*\d*\s*:[\s]*(.*)c                 C   s   i }| d|  p| d|  }| d|  p| d|  }d }|r(|r(|| }| d|  p0|}|d ur9||t< |d urA||t< |d urI||t< |S )Nz%s.response.usage.prompt_tokensz%s.response.usage.input_tokensz#%s.response.usage.completion_tokensz%s.response.usage.output_tokensz%s.response.usage.total_tokens)
get_metricr   r   r    )integration_namespanusageinput_tokensoutput_tokenstotal_tokens r`   V/home/ubuntu/.local/lib/python3.10/site-packages/ddtrace/llmobs/_integrations/utils.pyget_llmobs_metrics_tags   s$   rb   c                 C   s\   i }t | dd }t | dd }t | dd }|d ur||t< |d ur$||t< |d ur,||t< |S )Nprompt_tokenscompletion_tokensr_   )r!   r   r   r    )metricsr\   r]   r^   r_   r`   r`   ra   parse_llmobs_metric_args   s   rf   r/   	assistantsystem)humanairh   c                 C   sP   t | tri }|  D ]
\}}t|||< q|S t | tr$dd | D S t| S )z
    Formats input and output messages for serialization to JSON.
    Specifically, makes sure that any schema messages are converted to strings appropriately.
    c                 S      g | ]}t |qS r`   )format_langchain_io).0messager`   r`   ra   
<listcomp>       z'format_langchain_io.<locals>.<listcomp>)
isinstancedictitemsrl   list"get_content_from_langchain_message)messages	formattedkeyvaluer`   r`   ra   rl      s   

rl   returnc                 C   sp   t | tr| S z#t| di dt| }t| dtt| dd}|r(||fW S |W S  ty7   t|  Y S w )zr
    Attempts to extract the content and role from a message (AIMessage, HumanMessage, SystemMessage) object.
    __dict__contentroletype )rq   strgetattrgetLANGCHAIN_ROLE_MAPPINGAttributeError)rn   r|   r}   r`   r`   ra   ru      s   
ru   r}   r|   c              	   C   s  |rt |trt |d tsg S g }g }g }g }g }|D ]}|dr5t |dtr5||dd q|drft |dtrf|di }tt|dd|di t|dddd}	||	 q|d	rt |d	tr|d	i }
|
d
g }|
dd}|D ].}|d}|d}t|p|ot|pdd	|
  d|d	d}|t|gdd qqd	|
 }|td|| d qt }|r||d< |rd	||d
< | |d< |r|| |r|| |r|| |S )a  
    Extracts out a list of messages from a converse `content` field.

    `content` is a list of `ContentBlock` objects. Each `ContentBlock` object is a union type
    of `text`, `toolUse`, amd more content types. We only support extracting out `text` and `toolUse`.

    For more info, see `ContentBlock` spec
    https://docs.aws.amazon.com/bedrock/latest/APIReference/API_runtime_ContentBlock.html
    r   r:   r   toolUsenameinput	toolUseIdr   	argumentstool_idr~   
toolResultr|   jsonz[Unsupported content type(s): ,])resultr   r~   r/   )tool_resultsr}   z[Unsupported content type: {}]r|   r}   
tool_calls r}   )rq   rt   rr   r   r   appendr)   r+   r%   joinkeysr(   formatextend)r}   r|   rv   content_blockstool_calls_infotool_messagesunsupported_content_messagescontent_blockr   tool_call_infotool_messagetool_message_contentstool_message_idtool_message_contenttool_message_content_texttool_message_content_jsontool_result_infocontent_typern   r`   r`   ra   "get_messages_from_converse_content   st   







r   openair[   kwargscompletionsrZ   c                 C   s|   | dd}t|tr|g}t||d}tddg}| js,|r,t|d|}dd |D }| tdd |D t	|t
|i d	S )
z_Extract prompt/response tags from a completion and set them as temporary "_ml_obs.meta.*" tags.r6   r   
completionr|   choicesc                 S   s"   g | ]}t tt|d ddqS )r:   r   r   )r(   r   r!   )rm   choicer`   r`   ra   ro   :     " z8openai_set_meta_tags_from_completion.<locals>.<listcomp>c                 S   s   g | ]}t |d qS )r   r'   )rm   pr`   r`   ra   ro   =  s    N)r   rq   r   get_metadata_from_kwargsr(   errorr   _set_ctx_itemsr   r   r   )r[   r   r   rZ   r6   
parametersoutput_messagesr   r`   r`   ra   $openai_set_meta_tags_from_completion/  s   

r   rv   c                 C   s  g }| dg D ]T}tt|dd}tt|dd}t||d}t|dd}	|	r0tt|	| f t|\}
}|dkrCt|
||| d	d
 |
rM|
|d< d|d< |rW||d< d|d< |	| qt
||d}| t|t|i | dsv| drt| dp}g }|t| dpg  |r| t| | js|s| ttddg dS t|trd}g }|D ]1}| ddp|}| dd}t||d}t|| d	d\}
}t|
|||  |
r|
|d< |	| q| t| dS t|dg }g }t|D ]J\}}t|di }t|dd}t|ddpd}t|| d	d\}
}t|
|||  tt|t|d}|
r/|
|d< |r:||d< d|d< |	| q| t| dS )zdExtract prompt/response tags from a chat completion and set them as temporary "_ml_obs.meta.*" tags.rv   r|   r   r}   r   tool_call_idNrh   T)is_inputr   r   chattools	functionsr   )llm_spandispatch_llm_choicer   rn   )r   r   r!   r(   r   dispatchr   +_openai_extract_tool_calls_and_results_chatcapture_plain_text_tool_usager   r   r   r   r   _openai_get_tool_definitionsr   _set_ctx_itemr   r   r   rq   rt   	enumerate)r[   r   rv   rZ   input_messagesmr|   r}   processed_messager   extracted_tool_callsextracted_tool_resultsr   r   r   streamed_messagern   _r   idxr   choice_messager`   r`   ra   openai_set_meta_tags_from_chatD  s|   



r   Frn   r   r   c              
   C   s  g }g }t | dg pg D ]z}t |di }t |di }t |di p't |di p'i }t |ddp5t |ddp5d}	t |dd}
t |d	d}|rh|d urh|
rht|trQ|nt|}tt|
|	|t|jt|j	d
f t|trqt
|n|}tt|	|t|
t|d}|| qt | dddkrt | dd}ttt | dd|rt|ndtt | ddtt | d	dd}|| t | di }|rt |di }t
|}tt |dd|d}|| ||fS )Nr   functioncustomr   r   r   r   idr~   trace_idspan_idr   r}   toolr|   r   tool_resultr   r   r   r~   r@   r   r   )r!   rq   r   r%   r   r   r   r
   r   r   r&   r)   r   r+   )rn   r   r   r   r   rawr   r   raw_args	tool_namer   	tool_typetool_args_strr   r   r   r@   r   r`   r`   ra   r     s`   


r   r   tool_results_infor   c              	   C   sF  |sdS zt t|t j}|rt| tr|d d }|dd}|d d d}d	}	t	|dkrB|d  }	| 
t|t|d	d
d |	rdt||	rYt|	nd	d	dd}
|
|
 |rstt|| |f W dS tt|| ||t|jt|jdf W dS W dS W dS  ty   tjd|dd Y dS w )ay  
    Captures plain text tool calls and tool results from a content string.

    This is useful for extracting tool usage from ReAct agents which format tool usage as plain text.
    In this framework, the tool call and result are formatted within the content string as:
    ```
    Action: <tool_name>
    Action Input: <tool_input>
    Observation: <observation>
    ```
    N   *   z
Observation:r   `z "r   r   r   r   r   r   z7Failed to capture plain text tool call from content: %sTexc_info)researchREACT_AGENT_TOOL_CALL_REGEXDOTALLrq   rt   groupstripsplitlenr   r)   r&   r+   r   r   r   r   r   r
   r   r   	Exceptionloggerwarning)r   r   r|   r[   r   action_matchr   tool_input_with_observation
tool_inputobservationr   r`   r`   ra   r     sV   

&r   r   	operationc                    s\   i }t  |dkr |dkrtnt7  n|dkr! |dkrtnt7   fdd|  D }|S )Nr   r   litellmc                    s"   i | ]\}}| v r|t |qS r`   r#   rm   kvkeys_to_includer`   ra   
<dictcomp>  r   z,get_metadata_from_kwargs.<locals>.<dictcomp>)COMMON_METADATA_KEYSOPENAI_METADATA_CHAT_KEYSOPENAI_METADATA_COMPLETION_KEYSLITELLM_METADATA_CHAT_KEYS LITELLM_METADATA_COMPLETION_KEYSrs   )r   rZ   r   metadatar`   r   ra   r     s   r   c                 C   s   t | \}}|S )zParses the input to openai responses api into a list of input messages

    Args:
        messages: the input to openai responses api

    Returns:
        - A list of processed messages
    )%_openai_parse_input_response_messages)rv   	processedr   r`   r`   ra   -openai_get_input_messages_from_response_input  s   r  system_instructionsc              	   C   s  g }g }|r| td|d | s||fS t| tr#t| ddg|fS | D ]}t }d|v rd|v rd}t|d trv|d D ]5}|t|ddpJd7 }|t|d	dpVd7 }|d
d}|tkrj|t|7 }q?|tkrt|t	|7 }q?n|d }|rt||d< |d |d< nud|v rd|v sd|v r|ddp|dt
}	t|	}
t|d |
|dd|d
dd}|d|gd n=d|v rd|v r|d }t|tst|}t|d |rt|nd|dd|d
dd}|d|gd | |d  |r| | q%||fS )a  
    Parses input messages from the openai responses api into a list of processed messages
    and a list of tool call IDs.

    Args:
        messages: A list of output messages

    Returns:
        - A list of processed messages
        - A list of tool call IDs
    rh   r}   r|   r/   r   r|   r}   r   r:   refusalr~   Ncall_idr   r   r   r@   r   r   r   r~   rg   )r}   r   outputfunction_call_output)r   r   r   r~   )r}   r   )r   r(   rq   r   rt   r   r   _extract_image_referencer   _extract_file_referencer   r&   r)   updater%   r+   )rv   r  r  tool_call_idsitemprocessed_itemprocessed_item_contentr|   	item_typearguments_strr   r   r
  r   r`   r`   ra   r  +  s|   







r  responseintegrationc                 C   s<   | sg g fS t | dg }|sg g fS t||\}}}||fS )aU  
    Parses the output to openai responses api into a list of output messages and a list of
    MCP tool definitions returned from the MCP server.

    Args:
        response: An OpenAI response object or dictionary containing output messages

    Returns:
        - A list of processed messages
        - A list of MCP tool definitions
    r
  )r!   &_openai_parse_output_response_messages)r  r  rv   processed_messagesr   mcp_tool_definitionsr`   r`   ra   (openai_get_output_messages_from_response  s   r  c                 C   sJ  g }g }g }| D ]}t  }t|dd}|dkrLd}t|dg p!g D ]}	|tt|	ddp-d7 }|tt|	ddp9d7 }q"|tt|dd|d	 n|d
krm|d
tt|ddt|ddt|dddphdd	 n|dksu|dkrt|dd}
t|dd}t|ddpt|dt}tt|}tt|
|t|tt|ddd}|| ||gdd nf|dkrtt|dd}
tt|dd}t|dt}tt|}tt|dd}t|
||t|d}|| t	|||
dd}||g|gdd n|dkr|
tt|dg  q|t|dd || q|||fS ) a:  
    Parses output messages from the openai responses api into a list of processed messages
    and a list of tool call outputs and a list of MCP tool definitions.

    Args:
        messages: A list of output messages

    Returns:
        - A list of processed messages
        - A list of tool call outputs
    r~   r   rn   r|   r:   r  r}   rg   r  r7   summaryencrypted_contentr   )r  r  r   r@   custom_tool_callr  r   r   r   r   r	  )r   r}   mcp_callr
  mcp_tool_resultr   )r   r   r}   mcp_list_toolsr   r   )r(   r!   r   r  r%   r   r&   r)   r   r+   r   r   )rv   r  r  tool_call_outputsr  r  rn   message_typer:   r|   r  r   raw_argumentsr   r   r
  r   r`   r`   ra   r    s   







r  c                 C   sV   i }|r| dd | D  | s|S dD ]}t| |d }|d ur(t|||< q|S )Nc                 S   s"   i | ]\}}|t t v r||qS r`   )OPENAI_METADATA_RESPONSE_KEYSr   r   r`   r`   ra   r     r   z5openai_get_metadata_from_response.<locals>.<dictcomp>)r-   r2   r.   r;   r=   r:   r/   )r  rs   r   r$   )r  r   r  fieldry   r`   r`   ra   !openai_get_metadata_from_response  s   r&  objc                 C   s   t | ddpt | ddptS )uR   Extract image reference with fallback priority: image_url → file_id → [image].	image_urlNfile_id)r!   r   r'  r`   r`   ra   r    s   r  c                 C   s(   t | ddpt | ddpt | ddptS )u\   Extract file reference with fallback priority: file_url → file_id → filename → [file].file_urlNr)  filename)r!   r   r*  r`   r`   ra   r    s   

r  content_itemc                 C   s\   t | dd}|tkrt| S |tkrt| S |tks|du r,t | dd}|r*t|S dS dS )zBExtract text representation from a content item (text/image/file).r~   Nr:   r   )r!   r   r  r   r  r   r   )r-  r  r:   r`   r`   ra   _extract_content_item_text!  s   r.  	variablesc                 C   s$   | rt | ts	i S dd |  D S )zConverts OpenAI SDK response objects or dicts into simple key-value pairs.

    Example:
        Input:  {"msg": ResponseInputText(text="Hello"), "doc": ResponseInputFile(file_id="file-123")}
        Output: {"msg": "Hello", "doc": "file-123"}
    c                 S   s   i | ]\}}|t |p|qS r`   r.  )rm   rx   ry   r`   r`   ra   r   9  s    z/_normalize_prompt_variables.<locals>.<dictcomp>)rq   rr   rs   )r/  r`   r`   ra   _normalize_prompt_variables/  s   r1  instructionsc                 C   s   g }i }|  D ]\}}|du rqt|}|r%|ttfvr%d| d||< qt| tdd}| D ]A}t|dd}	|	s<q1t|dg }
|
sEq1d	d
 |
D }dd
 |D }|sVq1d|}|D ]}|| }|	||}q]|
|	|d q1|S )a#  
    Extract a chat template from OpenAI response instructions by replacing variable values with placeholders.

    Uses {{variable_name}} when values are available. Falls back to [image]/[file] markers when
    OpenAI strips the values (e.g., by default URL stripping behavior).

    Args:
        instructions: list of instruction messages from the OpenAI response
        variables: Dictionary of variables used in the prompt

    Returns:
        list of chat template messages with placeholders (e.g., {{variable_name}}, [image], [file])
    Nz{{z}}T)rx   reverser}   r   r|   c                 S   rk   r`   r0  )rm   r  r`   r`   ra   ro   c  rp   z<_extract_chat_template_from_instructions.<locals>.<listcomp>c                 S   s   g | ]}|r|qS r`   r`   )rm   partr`   r`   ra   ro   d  rp   r  )rs   r   r   r   sortedr   r   r!   r   replacer   )r2  r/  chat_templatevalue_to_placeholdervar_name	var_value	value_strsorted_valuesinstructionr}   content_items
text_parts	full_textplaceholderr`   r`   ra   (_extract_chat_template_from_instructions<  s6   
rB  c                 C   sB   | rt | ts	dS |  D ]}t|dd}|ttfv r dS qdS )zACheck if prompt variables contain multimodal inputs (image/file).Fr~   NT)rq   rr   valuesr!   r   r   )r/  ry   r  r`   r`   ra   _has_multimodal_inputst  s   rD  is_multimodalrF  c                C   s@   t ti}|r
d|t< | t}|r|| dS | t| dS )zSet prompt tracking telemetry tags on a span.

    Args:
        span: The span to tag
        is_multimodal: Whether the prompt contains image/file inputs
    trueN)r   r   r   _get_ctx_itemr   r  r   )r[   rF  new_tagsexisting_tagsr`   r`   ra   set_prompt_tracking_tags  s   
rK  c              
   C   s  | dg }|s|rd|v rt|dg }|rt|}t|}d|v r0|dtt|d dd | t|t	t
||i | d}|rzIt|}| di }t|}	|ry| dsy| d	syt|dd
}|ryt|}
t||
}|ry||d< |
|d< t|dd}| t| t| |	d W n tttfy } ztd| W Y d
}~nd
}~ww | js|s| ttddg d
S | t	pi }|t
| | t	| t||\}}| t| t| dpg }|s|r| t||  d
S d
S )zXExtract input/output tags from response and set them as temporary "_ml_obs.meta.*" tags.r   r6   r2  r   rh   r   r/  r7  templateNF)strict_validationrE  z1Failed to validate prompt for OpenAI response: %sr   r   r   )r   r!   r$   r  insertr(   r   r   r   r   r&  rr   rD  r1  rB  r"   r   r   rK  	TypeError
ValueErrorr   r   debugr   r   rH  r  r  r   r   )r[   r   r  r  
input_datar2  r   prompt_datar/  has_multimodalnormalized_variablesr7  validated_prompter  r   r  r   r`   r`   ra   "openai_set_meta_tags_from_response  s\   



rX  r   c                 C   s   g }| D ]y}t |dd r*t |di }ttt |ddtt |ddt |di d}nGt |dd rNt |di }ttt |ddtt |ddt |di d}n#ttt |ddtt |ddt |di pnt |di pnt |d	i d}t| sxq|| q|S )
Nr   r   r   descriptionr   )r   rY  schemar   r   input_schema)r!   r*   r   anyrC  r   )r   tool_definitionsr   r   tool_definitioncustom_toolr`   r`   ra   r     s8   



r   streamed_chunksc                 C   sb   | sddiS dd dd | D i}t| d ddr!| d j|d< t| d d	r/| d j|d	< |S )
zhConstructs a completion dictionary of form {"text": "...", "finish_reason": "..."} from streamed chunks.r:   r   c                 s   s"    | ]}t |d dr|jV  qdS )r:   N)r   r:   )rm   cr`   r`   ra   	<genexpr>  s     zCopenai_construct_completion_from_streamed_chunks.<locals>.<genexpr>finish_reasonNr   r\   )r   r   rd  hasattrr\   )r`  r   r`   r`   ra   0openai_construct_completion_from_streamed_chunks  s   rf  c           
         sT  |r | s|  t|dddd | d d  t|dd7  < dS |s$dS t|dd t|dd}t|d	d}t|d
d}t|dd}t|ddpMt|dd}t fddt| D d}|du r ||d}	|rp|dd|	d
< n	|ry|dd|	d< |  |	 d}|r| | d
 d  t|dd7  < dS |r| | d d  t|dd7  < dS dS )zKBuilds a tool_call dictionary from streamed function_call/tool_call chunks.r   r   r   r   r   Nindexr   r~   r   r   c                 3   s$    | ]\}}|d   kr|V  qdS )rg  Nr`   )rm   r   	tool_calltool_call_idxr`   ra   rb    s   " zAopenai_construct_tool_call_from_streamed_chunk.<locals>.<genexpr>)rg  r   r~   )r   r   rc  r   )r   r   nextr   )
stored_tool_callstool_call_chunkfunction_call_chunkr   r   r@   custom_callfunction_namelist_idx	call_dictr`   ri  ra   .openai_construct_tool_call_from_streamed_chunk  sB   
$$rs  c                 C   sN  dg d}| D ]}t |ddr|j|d< t |ddsqt |ddr+|ds+|j|d< t |jddr=|ds=|jj|d< t |ddrM|dsM|j|d< t |jd	d}|r_|d	  |7  < qt |jd
d}|rpt|d |d t |jdd}|szq|D ]
}t|d |d q|q|d r|d jdd d n|	dd |d	 
 |d	< |S )zConstructs a chat completion message dictionary from streamed chunks.
    The resulting message dictionary is of form:
    {"content": "...", "role": "...", "tool_calls": [...], "finish_reason": "..."}
    r   )r|   r   r\   Ndeltarg  r}   rd  r|   r@   r   )rn  )rm  c                 S   s   |  ddS )Nrg  r   )r   )xr`   r`   ra   <lambda>C  s    z?openai_construct_message_from_streamed_chunks.<locals>.<lambda>)rx   )r!   r\   r   rg  rt  r}   rd  rs  sortpopr   )r`  rn   chunkchunk_contentr@   r   rh  r`   r`   ra   -openai_construct_message_from_streamed_chunks%  s<   



r{  r   	span_kindc                 C   sH   |dkrdS |  t}|  t}|r| t| |r"| t| dS dS )z?Helper to update the input and output value for workflow spans.workflowN)rH  r   r   r   r   r   )r[   r|  r   r   r`   r`   ra   (update_proxy_workflow_input_output_valueJ  s   

r~  c                   @   s\  e Zd ZdZdd ZedefddZedefddZedefd	d
Z	edefddZ
edee fddZedeeee f fddZedee fddZedee fddZedefddZedefddZedeee  fddZedeee  fddZedefddZedeeef fdd Zedefd!d"Zedee fd#d$Zedee fd%d&Zedeeeef  fd'd(Zedeeeef  fd)d*Zedeeeef  fd+d,Zdee fd-d.Z deeeef  fd/d0Z!de"ee# ee f fd1d2Z$de"ee# ee% ee& f fd3d4Z'dee fd5d6Z(d7S )8OaiSpanAdapteraN  Adapter for Oai Agents SDK Span objects that the llmobs integration code will use.
    This is to consolidate the code where we access oai library types which provides a clear starting point for
    troubleshooting data issues.
    It is also handy for providing defaults when we bump into missing data or unexpected data shapes.
    c                 C   
   || _ d S N)_raw_oai_span)selfoai_spanr`   r`   ra   __init__]     
zOaiSpanAdapter.__init__rz   c                 C      | j jS )zGet the span ID.)r  r   r  r`   r`   ra   r   `     zOaiSpanAdapter.span_idc                 C   r  zGet the trace ID.)r  r   r  r`   r`   ra   r   e  r  zOaiSpanAdapter.trace_idc                 C   s4   t | jdrt | jjdr| jjjS d| j S )zGet the span name.	span_datar   zopenai_agents.{})re  r  r  r   r   	span_typelowerr  r`   r`   ra   r   j  s   
zOaiSpanAdapter.namec                 C   s(   t | jdrt | jjdr| jjjS dS )zGet the span type.r  r~   r   )re  r  r  r~   r  r`   r`   ra   r  q  s   
zOaiSpanAdapter.span_typec                 C   s   ddddddd}| | jS )Nr   agentllmtask)r   r  handoffr  	guardrailr   )r   r  )r  kind_mappingr`   r`   ra   llmobs_span_kindx  s   zOaiSpanAdapter.llmobs_span_kindc                 C       t | jdsdS t| jjddS )zGet the span data input.r  r   r   re  r  r   r  r  r`   r`   ra   r        zOaiSpanAdapter.inputc                 C   r  )zGet the span data output.r  Nr
  r  r  r`   r`   ra   r
    r  zOaiSpanAdapter.outputc                 C   r  )zGet the span data response.r  Nr  r  r  r`   r`   ra   r    r  zOaiSpanAdapter.responsec                 C   r  )zGet the span data from_agent.r  r   
from_agentr  r  r`   r`   ra   r    r  zOaiSpanAdapter.from_agentc                 C   r  )zGet the span data to_agent.r  r   to_agentr  r  r`   r`   ra   r    r  zOaiSpanAdapter.to_agentc                 C   r  )zGet the span data handoffs.r  Nhandoffsr  r  r`   r`   ra   r    r  zOaiSpanAdapter.handoffsc                 C   r  )zGet the span data tools.r  Nr   r  r  r`   r`   ra   r     r  zOaiSpanAdapter.toolsc                 C   r  )z#Get the span data for custom spans.r  Ndatar  r  r`   r`   ra   r    r  zOaiSpanAdapter.datac                 C   s   | j }|si S t|S )z,Get the custom span data in a formatted way.)r  r$   )r  r  r`   r`   ra   formatted_custom_data  s   z$OaiSpanAdapter.formatted_custom_datac                 C   s   | j sdS | j jS )z&Get the output text from the response.r   )r  output_textr  r`   r`   ra   response_output_text  s   z#OaiSpanAdapter.response_output_textc                 C   s   | j sdS t| j ddS )z.Get the system instructions from the response.Nr2  )r  r   r  r`   r`   ra   response_system_instructions  s   z+OaiSpanAdapter.response_system_instructionsc                 C   s8   t | jdsdS | jdkr| jrt | jdr| jjS dS )z(Get the model name formatted for LLMObs.r  Nr  model)re  r  r  r  r  r  r`   r`   ra   llmobs_model_name  s   z OaiSpanAdapter.llmobs_model_namec                 C   s   t | jdsdS i }| jdkrT| jrTt | jdrT| jj}t |dr&|j|d< t |dr0|j|d< t |dr:|j|d< t|di pEt|d	i }t|d
d}|durT||d< |rX|S dS )z4Get metrics from the span data formatted for LLMObs.r  Nr  r\   r]   r^   r_   completion_tokens_detailsoutput_tokens_detailsreasoning_tokensreasoning_output_tokens)	re  r  r  r  r\   r]   r^   r_   r!   )r  re   r\   reasoning_output_tokens_detailsr  r`   r`   ra   llmobs_metrics  s$   





zOaiSpanAdapter.llmobs_metricsc                 C   s   t | jdsdS i }| jdkr?| jr?dD ]}t | j|r,t| j|}|dur,t|||< qt | jdr?| jjr?t| jj|d< | jdkrZt | jjdrZt| jjdd}|rZ|| |r^|S dS )z5Get metadata from the span data formatted for LLMObs.r  Nr  )r-   r2   r.   r   r;   r=   r:   r   r  )	re  r  r  r  r   r$   r:   r  r  )r  r  r%  ry   custom_datar`   r`   ra   llmobs_metadata  s"   
zOaiSpanAdapter.llmobs_metadatac                 C      t | jdr
| jjS dS )zGet span error if it exists.r   N)re  r  r   r  r`   r`   ra   r        zOaiSpanAdapter.errorc                 C      | j sdS | j dS )z)Get the error message if an error exists.Nrn   r   r   r  r`   r`   ra   get_error_message     z OaiSpanAdapter.get_error_messagec                 C   r  )z&Get the error data if an error exists.Nr  r  r  r`   r`   ra   get_error_data  r  zOaiSpanAdapter.get_error_datac                 C   s   t | j| jS )zReturns processed input messages for LLM Obs LLM spans.

        Returns:
            - A list of processed messages
            - A list of tool call IDs for span linking purposes
        )r  r   r  r  r`   r`   ra   llmobs_input_messages!  s   z$OaiSpanAdapter.llmobs_input_messagesc                 C   sF   | j r| j jsg g g fS | j j}|sg g g fS t|ts|g}t|S )zReturns processed output messages for LLM Obs LLM spans.

        Returns:
            - A list of processed messages
            - A list of tool calls for span linking purposes
            - A list of MCP tool definitions
        )r  r
  rq   rt   r  )r  rv   r`   r`   ra   llmobs_output_messages*  s   


z%OaiSpanAdapter.llmobs_output_messagesc              	   C   s   | j r| jsdS z|  \}}|rt|dkr"|d dW S W dS W dS  ttfyA   ddlm} |t	}|j
ddd Y dS w )	zConverts Response span data to an input value for top level trace.

        Returns:
            The input content if found, None otherwise.
        Nr   rc  r|   r   z5Failed to process input messages from `response` spanTr   )r  r   r  r   r   r   
IndexErrorddtrace.internal.loggerr	   __name__r   )r  rv   r   r	   r   r`   r`   ra   llmobs_trace_input>  s    z!OaiSpanAdapter.llmobs_trace_inputN))r  
__module____qualname____doc__r  propertyr   r   r   r   r  r   r  r   rt   r   r   r
  r  r  r  r  r   r  rr   r  r  r  r  r  r  r   r  r  tupler(   r  r)   r*   r  r  r`   r`   r`   ra   r  V  s`    
$	r  c                   @   s|   e Zd ZdZdd ZedefddZedefddZede	e fd	d
Z
ede	eeef  fddZedd ZdS )OaiTraceAdapterzAdapter for OpenAI Agents SDK Trace objects.

    This class provides a clean interface for the integration code to interact with
    OpenAI Agents SDK Trace objects without needing to know their internal structure.
    c                 C   r  r  _trace)r  	oai_tracer`   r`   ra   r  Z  r  zOaiTraceAdapter.__init__rz   c                 C   r  r  )r  r   r  r`   r`   ra   r   ]  r  zOaiTraceAdapter.trace_idc                 C   s   t | jddS )zGet the trace name.r   zAgent workflow)r   r  r  r`   r`   ra   r   b  s   zOaiTraceAdapter.namec              	   C   s,   z	| j  dW S  ttfy   Y dS w )zGet the group ID if it exists.group_idN)r  exportr   r   KeyErrorr  r`   r`   ra   r  g  s
   zOaiTraceAdapter.group_idc                 C   r  )z$Get the trace metadata if it exists.r  N)re  r  r  r  r`   r`   ra   r  o  r  zOaiTraceAdapter.metadatac                 C   s   | j S )z$Get the raw OpenAI Agents SDK trace.r  r  r`   r`   ra   	raw_tracet  s   zOaiTraceAdapter.raw_traceN)r  r  r  r  r  r  r   r   r   r   r  rr   r   r  r  r`   r`   r`   ra   r  S  s    r  c                   @   sT   e Zd ZU dZeed< eed< 	 dZee ed< dZee	 ed< dZ
ee	 ed< dS )LLMObsTraceInfozNMetadata for llmobs trace used for setting root span attributes and span linksr   r   Ncurrent_top_level_agent_span_idinput_oai_spanoutput_oai_span)r  r  r  r  r   __annotations__r  r   r  r  r  r`   r`   r`   ra   r  z  s   
 r  text_blockstool_blocksc              
      s   t | dg }t| d d} fdd|D }||r#dd|ini  g }|D ]F}||}|s4q*|d}	i }
|	d	urWzt|	}
W n tjtfyV   d|	i}
Y nw t	|d
d|dd|
rf|
ni dd}|
| q*|rw||d< |S )a  Process a message and its content blocks into LLM Obs message format.

    Args:
        message: A message to be processed containing role and content block indices
        text_blocks: Mapping of content block indices to their text content
        tool_blocks: Mapping of content block indices to their tool usage data

    Returns:
        dict containing the processed message with content and optional tool calls
    content_block_indiciesr}   )r}   c                    s   g | ]
}| v r | qS r`   r`   )rm   r   r  r`   ra   ro     s    z=get_final_message_converse_stream_message.<locals>.<listcomp>r|   r   r   Nr   r   r   )r   r   r   r~   r   )r5  r   r(   r  r   r   loadsJSONDecodeErrorrP  r)   r   )rn   r  r  indicesmessage_outputtext_contentsr   r   
tool_blockr   	tool_argsr   r`   r  ra   )get_final_message_converse_stream_message  s6   




r  z[\w']+|[.,!?;~@#$%^&*()+/-]c                 C   sx   d}|r|D ]}t |dd}||7 }q|S | r:t| ts*t| tr-t| d tr-| g} | D ]
}t |}||7 }q/|S )zCompute token span metrics on streamed chat/completion requests.
    Only required if token usage is not provided in the streamed response.
    r   r|   r   )_est_tokensr   rq   r   rt   int)promptsrv   num_prompt_tokensr   rc   r6   r`   r`   ra   _compute_prompt_tokens  s   
"
r  c                 C   s:   d}| D ]}| ddp| dd}t|}||7 }q|S )zGCompute/Estimate the completion token count from the streamed response.r   r|   r   r:   )r   r  )completions_or_messagesnum_completion_tokensr   r|   rd   r`   r`   ra   _compute_completion_tokens  s   
r  r6   c                 C   sp   | sdS d}t | tr&t| d }tt| d }td| d|  d S t | tr6t | d tr6t| S |S )u'  
    Provide a very rough estimate of the number of tokens in a string prompt.
    Note that if the prompt is passed in as a token array (list of ints), the token count
    is just the length of the token array.
    Assumes 1) English text, 2) 1 token ~= 4 chars, and 3) 1 token ~= ¾ words
    r      g      ?g      ?g      ?r   )rq   r   r   _punc_regexfindallroundrt   r  )r6   
est_tokensest1est2r`   r`   ra   r    s   
r  r      instanceinternal_variable_namesdefault_variable_namedefault_module_nameframe_start_offsetframe_search_depthc                 C   s6  z|du rg }|}|}t  }|du r||fW S t|D ]}	|j}|du r,||f  W S qt|D ]R}	|du r9 nKz6t |}
|j D ])\}}|dsVt |sV||v rWqD|| u rm|}t 	|
j
}||f  W   W S qDW n ttttfy   |j}Y q1w |j}q1||fW S  ty   td ||f Y S w )a  
    Attempts to find the variable name and module name for an instance by inspecting the call stack.

    Args:
        instance: The instance to find the variable name for
        internal_variable_names: list of variable names to skip (e.g., ["instance", "self", "step"])
        default_variable_name: Default name to use if variable name cannot be found
        default_module_name: Default module name to use if module cannot be determined
        frame_start_offset: How many frames to skip from the current frame
        frame_search_depth: Maximum number of frames to search through

    Returns:
        tuple of (variable_name, module_name)
    N__z&Failed to extract prompt variable name)inspectcurrentframerangef_backgetframeinfof_localsrs   
startswithismodulegetmodulenamer,  rP  r   OSErrorrO  r   r   r   )r  r  r  r  r  r  variable_namemodule_namecurrent_framer   
frame_infor9  r:  r`   r`   ra   $extract_instance_metadata_from_stack  sJ   



r  )r   )NF)F)r   r   r  )NN)r   )NNNr   r  )idataclassesr   r  r   r   typingr   r   r   ddtrace._trace.spanr   ddtrace.internalr   r  r	   ddtrace.internal.utils.formatsr
   ddtrace.llmobs._constantsr   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r    ddtrace.llmobs._utilsr!   r"   r$   r%   r&   ddtrace.llmobs.typesr(   r)   r*   r+   r  r   r   r$  r   r   r   r   r   rb   rf   r   rl   r   r  ru   rt   rr   r   r   r   boolr   r   r   r  r  r  r  r&  r  r  r.  r1  rB  rD  rK  rX  r   rf  rs  r{  r~  r  r  r  r  r  compiler  r  r  r  r  r`   r`   r`   ra   <module>   s   &H



O

A
>




Y

b


"

8

?#
&% ~'



-


