o
    ưi&m                     @   s   d Z ddl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 ddlmZ 		ddeeef d	ee d
ee dee ddf
ddZ	ddededee dedeeef f
ddZdS )z<Helpers for handling MCP-aware `/chat/completions` requests.    )AnyListOptionalUnioncast)LiteLLM_Proxy_MCP_Handler)ResponsesAPIRequestUtils)ModelResponse)CustomStreamWrapperNresponseopenai_tools
tool_callstool_resultsreturnc                 C   s   t | tr*t| dsi | _i }|r||d< |r||d< |r!||d< |r(|| jd< dS t | ts1dS t| dr9| js;dS | jD ],}t|dd}|durjt|d	dpQi }|rX||d< |r^||d< |rd||d< t|d	| q>dS )
a  
    Add MCP metadata to response's provider_specific_fields.
    
    This function adds MCP-related information to the response so that
    clients can access which tools were available, which were called, and
    what results were returned.
    
    For ModelResponse: adds to choices[].message.provider_specific_fields
    For CustomStreamWrapper: stores in _hidden_params and automatically adds to 
    final chunk's delta.provider_specific_fields via CustomStreamWrapper._add_mcp_metadata_to_final_chunk()
    _hidden_paramsmcp_list_toolsmcp_tool_callsmcp_call_resultsmcp_metadataNchoicesmessageprovider_specific_fields)
isinstancer
   hasattrr   r	   r   getattrsetattr)r   r   r   r   r   choicer   provider_fields r   e/home/app/Keep/.python/lib/python3.10/site-packages/litellm/responses/mcp/chat_completions_handler.py_add_mcp_metadata_to_response   s>   




r    modelmessagestoolskwargsc                     s2  ddl m} t|\}}|s|d&| ||d|I dH S |dp-|di p*i d}tj|d|d\}}	}
}tj|||d	||	d
I dH \}}tj|dd}|sY|r]|| nd}tj	|d}dd |
 D }| ||dd|}|s|d&i |I dH }t|ttfrt||d |S |dd}|dd}|rt|}d|d< |dur||d< |d&i |I dH }t|tst|trt||d |S ddlm ddlm  G  fddd}|||||||	|
||d|d	||d}G fdddt}G dd dtt|||S t|}d|d< |dur#||d< |d&i |I dH }t|ts5|S tj|d }|sFt||d |S tj|||||	|
||d|d	d!	I dH }|sit|||d" |S tj|||d#}t|}||d$< ||d< |d&i |I dH }t|ttfrt||||d% |S )'an  
    Async completion with MCP integration.

    This function handles MCP tool integration following the same pattern as aresponses_api_with_mcp.
    It's designed to be called from the synchronous completion() function and return a coroutine.

    When MCP tools with server_url="litellm_proxy" are provided, this function will:
    1. Get available tools from the MCP server manager
    2. Transform them to OpenAI format
    3. Call acompletion with the transformed tools
    4. If require_approval="never" and tool calls are returned, automatically execute them
    5. Make a follow-up call with the tool results
    r   acompletion)r!   r"   r#   Nuser_api_key_authmetadatasecret_fields)r)   r#   litellm_trace_id)r'   mcp_tools_with_litellm_proxyr*   mcp_auth_headermcp_server_auth_headersZchat)Ztarget_format)r+   c                 S   s   i | ]\}}|d vr||qS )r%   r   ).0kvr   r   r   
<dictcomp>   s    z(acompletion_with_mcp.<locals>.<dictcomp>T)r!   r"   r#   _skip_mcp_handlerr   r   streamFmock_tool_callsstream_chunk_builderModelResponseStreamc                       sd   e Zd ZdZ fddZdd Zd d fdd	Zd d fd
dZdd ZfddZ	dd Z
dS )z2acompletion_with_mcp.<locals>.MCPStreamingIteratorz_Custom iterator that collects chunks, detects tool calls, and adds MCP metadata to final chunk.c                    s   || _ || _|| _|| _|| _|| _|| _|| _|	| _|
| _	|| _
|| _g | _d | _d | _d | _d| _d| _d | _d | _d| _d S )NF)stream_wrapperr"   tool_server_mapr'   r,   r-   oauth2_headersraw_headerslitellm_call_idr*   r   base_call_argscollected_chunksr   r   complete_responsestream_exhaustedtool_execution_donefollow_up_streamfollow_up_iteratorfollow_up_exhausted)selfr:   r"   r;   r'   r,   r-   r<   r=   r>   r*   r   r?   r8   r   r   __init__   s*   
z;acompletion_with_mcp.<locals>.MCPStreamingIterator.__init__c                    s   | S Nr   rG   r   r   r   	__aiter__   s   z<acompletion_with_mcp.<locals>.MCPStreamingIterator.__aiter__chunkr   c                 S   s   ddl m}m} | js|S t|dr@|jr@|jD ]'}t||r?t|dr?|jr?t|jddp/i }t	|}| j|d< ||j| q|S )z&Add mcp_list_tools to the first chunk.r   StreamingChoicesadd_provider_specific_fieldsr   deltar   Nr   )
litellm.types.utilsrN   rO   r   r   r   r   rP   r   dict)rG   rL   rN   rO   r   existing_fieldsr   r   r   r   _add_mcp_list_tools_to_chunk   s   

zOacompletion_with_mcp.<locals>.MCPStreamingIterator._add_mcp_list_tools_to_chunkc                 S   s   ddl m}m} t|drY|jrY|jD ]E}t||rXt|drX|jrXi }t|jdr@t|jdd}|dur@t|tr>t|ni }|}| j	rJ| j	|d< | j
rR| j
|d< ||j| q|S )	z;Add mcp_tool_calls and mcp_call_results to the final chunk.r   rM   r   rP   r   Nr   r   )rQ   rN   rO   r   r   r   rP   r   rR   r   r   )rG   rL   rN   rO   r   rS   
attr_valuer   r   r   r   %_add_mcp_tool_metadata_to_final_chunk	  s"   


zXacompletion_with_mcp.<locals>.MCPStreamingIterator._add_mcp_tool_metadata_to_final_chunkc                    s  | j st| ds| j | _t| j| jd zS| j I d H }| j	| t
| jdkr2| |}t|doI|joIt|jd doI|jd jd u}|rhd| _ |  I d H  | |}| jrh| jrh|  I d H  |W S  ty   d| _ |  I d H  | jr| jd }| |}| jr| jr|  I d H  | Y S Y nw | jr| js| js| j | _dd	lm} |d
 z| j I d H }dd	lm} |d|  |W S  ty   d| _dd	lm} |d tw | j r| jr| jr| jd u rdd	lm} |d t)N_stream_iteratorr3      r   r   finish_reasonTverbose_loggerz!Follow-up stream iterator createdzFollow-up chunk yielded: zFollow-up stream exhaustedz<Follow-up stream was not created despite having tool results)rB   r   r:   rK   rW   r    r   	__anext__r@   appendlenrT   r   rY   _process_tool_callsrV   r   rA   _prepare_follow_up_callStopAsyncIterationrD   rF   rE   litellm._loggingr\   debugwarning)rG   rL   is_finalZfinal_chunkr\   r   r   r   r]   *  sx   







$z<acompletion_with_mcp.<locals>.MCPStreamingIterator.__anext__c                    s   | j rdS d| _ | jsdS  | j| jd}t|trE|| _tj|d| _| jrGtj	| j
| j| j| j| j| j| j| j| jd	I dH | _dS dS dS )z-Process tool calls after streaming completes.NT)chunksr"   r   	r;   r   r'   r,   r-   r<   r=   r>   r*   )rC   r@   r"   r   r	   rA   r   &_extract_tool_calls_from_chat_responser   _execute_tool_callsr;   r'   r,   r-   r<   r=   r>   r*   r   )rG   rA   r6   r   r   r`   {  s:   
zFacompletion_with_mcp.<locals>.MCPStreamingIterator._process_tool_callsc                    s   | j durdS | jr| jsdS tj| j| j| jd}t| j}||d< d|d< d|d< ddl}|j	di |I dH }t
|trP|| _ ddlm} |d	 dS ddlm} |d
t|  d| _ dS )z6Prepare and initiate follow-up call with tool results.NZoriginal_messagesr   r   r"   Tr4   r2   r   r[   z%Follow-up stream created successfullyz1Follow-up response is not a CustomStreamWrapper: r   )rD   r   rA   r   #_create_follow_up_messages_for_chatr"   rR   r?   litellmr&   r   r
   rc   r\   rd   re   type)rG   follow_up_messagesfollow_up_call_argsrn   Zfollow_up_responser\   r   r   r   ra     s2   



zJacompletion_with_mcp.<locals>.MCPStreamingIterator._prepare_follow_up_callN)__name__
__module____qualname____doc__rH   rK   rT   rV   r]   r`   ra   r   )r9   r7   r   r   MCPStreamingIterator   s    !Q%rv   r>   )r:   r"   r;   r'   r,   r-   r<   r=   r>   r*   r   r?   c                       s@   e Zd Z fddZdd ZfddZdd Zd	d
 Z  ZS )z.acompletion_with_mcp.<locals>.MCPStreamWrapperc                    sx   t  jd t|ddt|dd t|dd t|dd t|dd t|dd d || _|| _t|d	r4|j| _d | _d | _d S )
Nr!   unknownlogging_objcustom_llm_providerstream_options	make_call_response_headers)Zcompletion_streamr!   rx   ry   rz   r{   r|   r   )	superrH   r   _original_wrapper_custom_iteratorr   r   _sync_iterator
_sync_loop)rG   Zoriginal_wrapperZcustom_iterator	__class__r   r   rH     s   





	

z7acompletion_with_mcp.<locals>.MCPStreamWrapper.__init__c                 S   s   | j S rI   )r   rJ   r   r   r   rK     s   z8acompletion_with_mcp.<locals>.MCPStreamWrapper.__aiter__c                    s`   | j d u r-dd l}z| | _W n ty$   | | _|| j Y nw  | j| j| _ | j S )Nr   )r   asyncioget_event_loopr   RuntimeErrornew_event_loopset_event_loopr   )rG   r   _SyncIteratorWrapperr   r   __iter__  s   

z7acompletion_with_mcp.<locals>.MCPStreamWrapper.__iter__c                 S   s   | j d u r	|   t| j S rI   )r   r   nextrJ   r   r   r   __next__  s   

z7acompletion_with_mcp.<locals>.MCPStreamWrapper.__next__c                 S   s   t | j|S rI   )r   r~   )rG   namer   r   r   __getattr__  s   z:acompletion_with_mcp.<locals>.MCPStreamWrapper.__getattr__)	rr   rs   rt   rH   rK   r   r   r   __classcell__r   r   r   r   MCPStreamWrapper  s    r   c                   @   s$   e Zd Zdd Zdd Zdd ZdS )z2acompletion_with_mcp.<locals>._SyncIteratorWrapperc                 S   s   || _ || _d | _d S rI   )_async_iterator_loop	_iterator)rG   Zasync_iteratorloopr   r   r   rH   
  s   
z;acompletion_with_mcp.<locals>._SyncIteratorWrapper.__init__c                 S   s   | S rI   r   rJ   r   r   r   r     s   z;acompletion_with_mcp.<locals>._SyncIteratorWrapper.__iter__c                 S   s\   | j d u r| j }t|dr| j|| _ n|| _ z
| j| j  W S  ty-   tw )N	__await__)	r   r   rK   r   r   run_until_completer]   rb   StopIteration)rG   Zaiter_resultr   r   r   r     s   


z;acompletion_with_mcp.<locals>._SyncIteratorWrapper.__next__N)rr   rs   rt   rH   r   r   r   r   r   r   r   	  s    r   rh   ri   )r   r   r   rl   r"   )r   r   r   r   r   )rn   r&   r   Z_parse_mcp_toolsgetr   Z extract_mcp_headers_from_requestZ+_process_mcp_tools_without_openai_transformZ_transform_mcp_tools_to_openaiZ_should_auto_execute_toolsitemsr   r	   r
   r    poprR   Zlitellm.mainr7   rQ   r9   r   rj   rk   rm   ) r!   r"   r#   r$   Zlitellm_acompletionr+   Zother_toolsr'   r,   r-   r<   r=   Zdeduplicated_mcp_toolsr;   r   Z	all_toolsZshould_auto_executeZclean_kwargsr?   r   r4   r5   Zinitial_call_argsZinitial_streamrv   iteratorr   Zinitial_responser   r   rp   rq   r   )r9   r   r7   r   acompletion_with_mcpR   s&  



		

 z/
r   )NNrI   )ru   typingr   r   r   r   r   Z/litellm.responses.mcp.litellm_proxy_mcp_handlerr   Zlitellm.responses.utilsr   rQ   r	   Zlitellm.utilsr
   r    strr   r   r   r   r   <module>   s>    

B
