o
    hZ\                  
   @  s  d dl mZ d dlZd dlZd dlmZ d dlmZ d dlmZm	Z	m
Z
mZ d dlmZmZ d dlmZ zd dlZW n eyK Z zededZ[ww d d	lmZmZmZ d d
lmZmZmZmZ d dlmZmZm Z  d dl!m"Z" d dl#m$Z$ ddl%m&Z& ddl'm(Z( ddl)m*Z* ddl+m,Z,m-Z-m.Z. ddl/m/Z/ ddl0m1Z1 ddl2m3Z3 ddl4m5Z5m6Z6 ddl7m8Z8 ddl9m:Z: ddl;m<Z<m=Z= ddl>m?Z? ddl@mAZA ddlBmCZC ddlDmEZE ddlFmGZG ddlHmIZI G d d! d!e ZJG d"d# d#e<ZKG d$d% d%ZLdS )&    )annotationsN)AsyncIterator)copy)AnyLiteralcastoverload)InputTokensDetailsOutputTokensDetails)ModelBehaviorErrorz`litellm` is required to use the LitellmModel. You can install it via the optional dependency group: `pip install 'openai-agents[litellm]'`.)	NOT_GIVENAsyncStreamNotGiven)ChatCompletionChunk#ChatCompletionMessageCustomToolCall%ChatCompletionMessageFunctionToolCallChatCompletionMessageParam)
AnnotationAnnotationURLCitationChatCompletionMessage)Function)Response   )_debug)AgentOutputSchemaBase)Handoff)ModelResponseTResponseInputItemTResponseStreamEvent)logger)ModelSettings)	Converter)HEADERSHEADERS_OVERRIDE)ChatCmplStreamHandler)FAKE_RESPONSES_ID)ModelModelTracing)Tool)generation_span)GenerationSpanData)Span)Usage)_to_dump_compatiblec                   @  s&   e Zd ZU dZded< dZded< dS )InternalChatCompletionMessagezs
    An internal subclass to carry reasoning_content and thinking_blocks without modifying the original model.
    strreasoning_contentNzlist[dict[str, Any]] | Nonethinking_blocks)__name__
__module____qualname____doc____annotations__r1    r7   r7   g/var/www/html/openai_agents/venv/lib/python3.10/site-packages/agents/extensions/models/litellm_model.pyr.   7   s   
 r.   c                   @  s   e Zd ZdZ		d:d;dd	Z			d<d=ddZ			d<d>d d!Ze	d?d@d'd(Ze	d?dAd+d(Z	,	dBdCd/d(ZdDd2d3Z	dEd6d7Z
dFd8d9ZdS )GLitellmModelzThis class enables using any model via LiteLLM. LiteLLM allows you to acess OpenAPI,
    Anthropic, Gemini, Mistral, and many other models.
    See supported models here: [litellm models](https://docs.litellm.ai/docs/providers).
    Nmodelr/   base_url
str | Noneapi_keyc                 C  s   || _ || _|| _d S N)r:   r;   r=   )selfr:   r;   r=   r7   r7   r8   __init__F   s   
zLitellmModel.__init__system_instructionsinputstr | list[TResponseInputItem]model_settingsr    tools
list[Tool]output_schemaAgentOutputSchemaBase | Nonehandoffslist[Handoff]tracingr'   previous_response_idconversation_idprompt
Any | Nonereturnr   c                   s  t t| j| t| jpdddB | d}| j||||||||d|
d
I d H }t|jd t	j
jjs9J tjrBtd ntd	tj|jd j d
dd d t|dr|j}|jrtd|j|j|jtt|jddpsddtt|jddp~dddnt }nt }t d |! r|jd j g|j"_#|j$|j%d|j"_t&'t()|jd j}t*||d dW  d    S 1 sw   Y  d S )N litellmr;   
model_implr:   model_configdisabledFstreamrN   r   zReceived model responsez
LLM resp:
   indentensure_ascii
usage   cached_tokens)ra   reasoning_tokens)rb   )requestsinput_tokensoutput_tokenstotal_tokensinput_tokens_detailsoutput_tokens_detailsz*No usage information returned from Litellmrd   re   )outputr_   response_id)+r)   r/   r:   to_json_dictr;   is_disabled_fetch_response
isinstancechoicesrR   typesutilsChoicesr   DONT_LOG_MODEL_DATAr   debugjsondumpsmessage
model_dumphasattrr_   r,   prompt_tokenscompletion_tokensrf   r	   getattrprompt_tokens_detailsr
   completion_tokens_detailswarninginclude_data	span_datarj   rd   re   r!   message_to_output_itemsLitellmConverterconvert_message_to_openair   )r?   rA   rB   rD   rE   rG   rI   rK   rL   rM   rN   span_generationresponseresponse_usager_   itemsr7   r7   r8   get_responseP   s   


$zLitellmModel.get_response#AsyncIterator[TResponseStreamEvent]c                 C s  t t| j| t| jpdddB | de}| j||||||||d|
d
I d H \}}d }t||2 z3 d H W }|V  |j	dkrG|j
}q66 | rV|rV| g|j_|rn|jrv|jj|jjd|j_W d    d S W d    d S W d    d S 1 sw   Y  d S )	NrQ   rR   rS   rU   TrX   zresponse.completedri   )r)   r/   r:   rl   r;   rm   rn   r$   handle_streamtyper   r   ry   r   rj   r_   rd   re   )r?   rA   rB   rD   rE   rG   rI   rK   rL   rM   rN   r   r   rY   final_responsechunkr7   r7   r8   stream_response   sN   

"zLitellmModel.stream_responsespanSpan[GenerationSpanData]rY   Literal[True]1tuple[Response, AsyncStream[ChatCompletionChunk]]c                      d S r>   r7   r?   rA   rB   rD   rE   rG   rI   r   rK   rY   rN   r7   r7   r8   rn         zLitellmModel._fetch_responseLiteral[False]!litellm.types.utils.ModelResponsec                   r   r>   r7   r   r7   r7   r8   rn      r   FboolUlitellm.types.utils.ModelResponse | tuple[Response, AsyncStream[ChatCompletionChunk]]c                   s  |j d uo|j jd u}tj||d}|r| |}|r%|d|dd t|}| r1||j_	|j
r>|r>t|dkr>dn|j
du rEdnd }t|j}t|}|r[dd |D ng }|D ]
}|t| q_t|}tjrwtd	 n)tj|d
dd}tj|d
dd}td| j d| d| d|	 d| d| d |j r|j jnd }d }|	r|jd urd|ji}i }|jrt|j|d< |jrt|j|d< |jrt|jtr||j |j r||j  t!j"d+i d| jd|d|pd d|j#d|j$d|j%d|j&d|j'd| (|d| (|d|d |	d!|d"|d#|j)d$| *|d%| j+d&| j,|I d H }t|t!j-j.j/rE|S t0t1t22 | jd'g |t3krZt4t5d( |nd)|j$|j#g |pdd|j d*}||fS ),N)preserve_thinking_blocksr   system)contentroleTFc                 S     g | ]}t |qS r7   )r!   tool_to_openai.0toolr7   r7   r8   
<listcomp>*      z0LitellmModel._fetch_response.<locals>.<listcomp>zCalling LLMrZ   r[   zCalling Litellm model: r^   z
Tools:
z	
Stream: z
Tool choice: z
Response format: include_usageextra_querymetadatar:   messagesrE   temperaturetop_pfrequency_penaltypresence_penalty
max_tokenstool_choiceresponse_formatparallel_tool_callsrY   stream_optionsreasoning_efforttop_logprobsextra_headersr=   r;   r   )autorequirednoner   )id
created_atr:   objectrj   r   r   r   rE   r   	reasoningr7   )6r   effortr!   items_to_messages_fix_tool_message_orderinginsertr-   r   r   rB   r   lenconvert_tool_choicer   convert_response_formatappendconvert_handoff_toolr   rt   r   ru   rv   rw   r:   r   r   r   r   
extra_bodyro   dictupdate
extra_argsrR   acompletionr   r   r   r   r   _remove_not_givenr   _merge_headersr=   r;   rq   rr   r   r   r%   timer   r   r   )r?   rA   rB   rD   rE   rG   rI   r   rK   rY   rN   r   converted_messagesr   r   r   converted_toolshandoffmessages_json
tools_jsonr   r   extra_kwargsretr   r7   r7   r8   rn      s  



	


	



r    list[ChatCompletionMessageParam]c                 C  s  |s|S i }i }g }t |D ]v\}}t|ts|||f q|d}|dkrc|drc|dg }t|trb|D ]'}	t|	tra|	d}
|
rattttf |	 }|	g|d< |tt
|f||
< q:q|dkr}|d}|ru||f||< q|||f q|||f qt }|D ]}
|
|v r||
 \}}|| qg }t }t |D ]\}}||v rqt|ts|| || q|d}|dkr>|dr>|dg }t|tr8|D ][}	t|	tr7|	d}
|
r|
|v r|
|v r||
 \}}||
 \}}|| || |||
 d  || q|
r7|
|v r7||
 \}}|| |||
 d  q|| q|dkrS||vrM|| || q|| || q|S )a8  
        Fix the ordering of tool messages to ensure tool_use messages come before tool_result messages.

        This addresses the interleaved thinking bug where conversation histories may contain
        tool results before their corresponding tool calls, causing Anthropic API to reject the request.
        r   	assistant
tool_callsr   r   tool_call_idr   )	enumeratero   r   r   getlistr   r/   r   r   r   setadd)r?   r   tool_call_messagestool_result_messagesother_messagesirx   r   r   	tool_calltool_idsingle_tool_msgr   paired_tool_result_indicestool_result_idx_fixed_messagesused_indicesoriginal_messagetool_call_msgtool_result_msgr7   r7   r8   r     s   	





















z'LitellmModel._fix_tool_message_orderingvaluer   c                 C  s   t |trd S |S r>   )ro   r   )r?   r   r7   r7   r8   r     s   
zLitellmModel._remove_not_givenc                 C  s   i t |jpi t pi S r>   )r"   r   r#   r   )r?   rD   r7   r7   r8   r     s   zLitellmModel._merge_headers)NN)r:   r/   r;   r<   r=   r<   )NNN)rA   r<   rB   rC   rD   r    rE   rF   rG   rH   rI   rJ   rK   r'   rL   r<   rM   r<   rN   rO   rP   r   )rA   r<   rB   rC   rD   r    rE   rF   rG   rH   rI   rJ   rK   r'   rL   r<   rM   r<   rN   rO   rP   r   r>   )rA   r<   rB   rC   rD   r    rE   rF   rG   rH   rI   rJ   r   r   rK   r'   rY   r   rN   rO   rP   r   )rA   r<   rB   rC   rD   r    rE   rF   rG   rH   rI   rJ   r   r   rK   r'   rY   r   rN   rO   rP   r   )FN)rA   r<   rB   rC   rD   r    rE   rF   rG   rH   rI   rJ   r   r   rK   r'   rY   r   rN   rO   rP   r   )r   r   rP   r   )r   r   rP   r   )rD   r    )r2   r3   r4   r5   r@   r   r   r   rn   r   r   r   r7   r7   r7   r8   r9   @   s4    c0 

sr9   c                   @  s6   e Zd ZedddZeddd	ZedddZdS )r   rx   litellm.types.utils.MessagerP   r   c           	   
   C  s&  |j dkrtd|j  |jrdd |jD nd }|dd }|r(|dd nd }d}t|dr7|jr7|j}d }t|d	r|jrg }|jD ]8}t|trZ|	t
tttf | qFi }t|d
rit|j }nt|drs| }ndt|i}|	| qFt|j|d| ||dd |||dS )Nr   zUnsupported role: c                 S  r   r7   )r   convert_tool_call_to_openair   r7   r7   r8   r   
  r   z>LitellmConverter.convert_message_to_openai.<locals>.<listcomp>provider_specific_fieldsrefusalrQ   r0   r1   __dict__ry   thinkingaudio)r   r   r   r   r   r   r0   r1   )r   r   r   r   rz   r0   r1   ro   r   r   r   r/   r   r   r   ry   r.   r   convert_annotations_to_openai)	clsrx   r   r   r   r0   r1   block
block_dictr7   r7   r8   r      sF   






z*LitellmConverter.convert_message_to_openailist[Annotation] | Nonec                 C  s"   | dd }|s
d S dd |D S )Nr   c              
   S  sD   g | ]}t d t|d  d |d  d |d  d |d  d ddqS )url_citationstart_index	end_indexurltitle)r   r   r   r   )r   r   )r   r   )r   
annotationr7   r7   r8   r   A  s    




zBLitellmConverter.convert_annotations_to_openai.<locals>.<listcomp>)r   )r   rx   r   r7   r7   r8   r   7  s   
z.LitellmConverter.convert_annotations_to_openair   1litellm.types.utils.ChatCompletionMessageToolCallr   c                 C  s$   t |jdt|jjp
d|jjddS )NfunctionrQ   )name	arguments)r   r   r  )r   r   r   r  r  r  )r   r   r7   r7   r8   r   N  s   
z,LitellmConverter.convert_tool_call_to_openaiN)rx   r   rP   r   )rx   r   rP   r   )r   r  rP   r   )r2   r3   r4   classmethodr   r   r   r7   r7   r7   r8   r     s    6r   )M
__future__r   rv   r   collections.abcr   r   typingr   r   r   r   %openai.types.responses.response_usager	   r
   agents.exceptionsr   rR   ImportError_eopenair   r   r   openai.types.chatr   r   r   r   )openai.types.chat.chat_completion_messager   r   r   <openai.types.chat.chat_completion_message_function_tool_callr   openai.types.responsesr   rQ   r   agent_outputr   rI   r   r   r   r   r   r   rD   r    models.chatcmpl_converterr!   models.chatcmpl_helpersr"   r#   models.chatcmpl_stream_handlerr$   models.fake_idr%   models.interfacer&   r'   r   r(   rK   r)   tracing.span_datar*   tracing.spansr+   r_   r,   
util._jsonr-   r.   r9   r   r7   r7   r7   r8   <module>   s\    	   B