o
    ưi6                     @   sb   d Z ddlZddl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 G dd dZdS )	zo
WebSearch Tool Transformation

Transforms between Anthropic/OpenAI tool_use format and LiteLLM search format.
    N)AnyDictListOptionalTupleUnion)verbose_logger)LITELLM_WEB_SEARCH_TOOL_NAME)SearchResponsec                   @   sL  e Zd ZdZe	ddedededeee	e
 f fddZededeee	e
 f fd	d
Zededeee	e
 f fddZe		dde	e
 de	e dedee	e
  dee
ee
e	e
 f f f
ddZe	dde	e
 de	e dee	e
  dee
e
f fddZede	e
 de	e dee
e	e
 f fddZededefddZdS )WebSearchTransformationu   
    Transformation class for WebSearch tool interception.

    Handles transformation between:
    - Anthropic tool_use format → LiteLLM search requests
    - OpenAI tool_calls format → LiteLLM search requests
    - LiteLLM SearchResponse → Anthropic/OpenAI tool_result format
    	anthropicresponsestreamresponse_formatreturnc                 C   s2   |rt d dg fS |dkrt| S t| S )a  
        Transform model response to extract WebSearch tool calls.

        Detects if response contains WebSearch tool_use/tool_calls blocks and extracts
        the search queries for execution.

        Args:
            response: Model response (dict, AnthropicMessagesResponse, or ModelResponse)
            stream: Whether response is streaming
            response_format: Response format - "anthropic" or "openai" (default: "anthropic")

        Returns:
            (has_websearch, tool_calls):
                has_websearch: True if WebSearch tool_use found
                tool_calls: List of tool_use/tool_calls dicts with id, name, input/function

        Note:
            Streaming requests are handled by converting stream=True to stream=False
            in the WebSearchInterceptionLogger.async_log_pre_api_call hook before
            the API request is made. This means by the time this method is called,
            streaming requests have already been converted to non-streaming.
        zKWebSearchInterception: Unexpected streaming response, skipping interceptionFopenai)r   warningr   _detect_from_openai_response#_detect_from_non_streaming_response)r   r   r    r   q/home/app/Keep/.python/lib/python3.10/site-packages/litellm/integrations/websearch_interception/transformation.pytransform_request   s   

z)WebSearchTransformation.transform_requestc           	      C   s   t | tr| dg }nt| dstd dg fS | jpg }|s*td dg fS g }|D ]Y}t |trK|d}|d}|d}|di }nt|dd	}t|dd	}t|dd	}t|di }|d
kr|tddfv r|d
||d}|	| td| d|d   q.t
|dk|fS )z3Parse non-streaming response for WebSearch tool_usecontentz8WebSearchInterception: Response has no content attributeFz1WebSearchInterception: Response has empty contenttypenameidinputNtool_use	WebSearch
web_search)r   r   r   r   WebSearchInterception: Found z tool_use with id=r   )
isinstancedictgethasattrr   debugr   getattrr	   appendlen)	r   r   
tool_callsblockZ
block_typeZ
block_nameZblock_idZblock_input	tool_callr   r   r   r   B   sL   








z;WebSearchTransformation._detect_from_non_streaming_responsec              	   C   sD  t | tr| dg }nt| dstd dg fS | jpg }|s*td dg fS |d }t |tr:|di }nt|dd}|sKtd dg fS t |trW|d	g }nt|d	dp^g }|sjtd
 dg fS g }|D ]}t |tr|d}|d}|di }	t |	tr|	dnt|	dd}
t |	tr|	dnt|	dd}n&t|dd}t|dd}t|dd}	|	rt|	ddnd}
|	rt|	ddnd}|dkr|
tddfv rt |t	rzt
|}W n t
jy   td|  i }Y nw |pi }|d|
|
|d|d}|| td|
 d|  qnt|dk|fS )z4Parse OpenAI-style response for WebSearch tool_callschoicesz8WebSearchInterception: Response has no choices attributeFz1WebSearchInterception: Response has empty choicesr   messageNz2WebSearchInterception: First choice has no messager)   z0WebSearchInterception: Message has no tool_callsr   r   functionr   	argumentsr   r   z;WebSearchInterception: Failed to parse function arguments: r   r/   )r   r   r   r.   r   r    z tool_call with id=)r!   r"   r#   r$   r   r%   r,   r&   r	   strjsonloadsJSONDecodeErrorr   r'   r(   )r   r,   Zfirst_choicer-   Zopenai_tool_callsr)   r+   Ztool_idZ	tool_typer.   Zfunction_nameZfunction_argumentsr/   Ztool_call_dictr   r   r   r   {   s   







 "


z4WebSearchTransformation._detect_from_openai_responseNr)   search_resultsthinking_blocksc                 C   s$   |dkr
t | |S t j| ||dS )a  
        Transform LiteLLM search results to Anthropic/OpenAI tool_result format.

        Builds the assistant and user/tool messages needed for the agentic loop
        follow-up request.

        Args:
            tool_calls: List of tool_use/tool_calls dicts from transform_request
            search_results: List of search result strings (one per tool_call)
            response_format: Response format - "anthropic" or "openai" (default: "anthropic")
            thinking_blocks: Optional list of thinking/redacted_thinking blocks
                from the model's response. When present, prepended to the
                assistant message content (required by Anthropic API when
                thinking is enabled).

        Returns:
            (assistant_message, user_or_tool_messages):
                For Anthropic: assistant_message with tool_use blocks, user_message with tool_result blocks
                For OpenAI: assistant_message with tool_calls, tool_messages list with tool results
        r   )r6   )r   _transform_response_openai_transform_response_anthropic)r)   r5   r   r6   r   r   r   transform_response   s   z*WebSearchTransformation.transform_responsec                    sZ   g }|r	| | | dd D  d|d}d fddttD d}||fS )zKTransform to Anthropic format (single user message with tool_result blocks)c                 S   s&   g | ]}d |d |d |d dqS )r   r   r   r   )r   r   r   r   r   .0Ztcr   r   r   
<listcomp>  s    zIWebSearchTransformation._transform_response_anthropic.<locals>.<listcomp>	assistant)roler   userc                    $   g | ]}d | d  | dqS )Ztool_resultr   )r   Ztool_use_idr   r   r;   ir5   r)   r   r   r<   (      
)extendranger(   )r)   r5   r6   Zassistant_contentassistant_messageZuser_messager   rC   r   r8     s"   

z5WebSearchTransformation._transform_response_anthropicc                    s8   ddd D d} fddt tD }||fS )zNTransform to OpenAI format (assistant with tool_calls, separate tool messages)r=   c              	   S   sJ   g | ]!}|d  d|d t |d trt|d nt|d ddqS )r   r.   r   r   r0   )r   r   r.   )r!   r"   r2   dumpsr1   r:   r   r   r   r<   =  s    	&zFWebSearchTransformation._transform_response_openai.<locals>.<listcomp>)r>   r)   c                    r@   )Ztoolr   )r>   Ztool_call_idr   r   rA   rC   r   r   r<   K  rD   )rF   r(   )r)   r5   rG   Ztool_messagesr   rC   r   r7   4  s   	
	z2WebSearchTransformation._transform_response_openairesultc                 C   s6   t | dr| jrddd | jD }|S t| }|S )z
        Format SearchResponse as text for tool_result content.

        Args:
            result: SearchResponse from litellm.asearch()

        Returns:
            Formatted text with Title, URL, Snippet for each result
        resultsz

c                 S   s(   g | ]}d |j  d|j d|j qS )zTitle: z
URL: z

Snippet: )titleurlsnippet)r;   rr   r   r   r<   e  s    zBWebSearchTransformation.format_search_response.<locals>.<listcomp>)r$   rJ   joinr1   )rI   Zsearch_result_textr   r   r   format_search_responseV  s   	z.WebSearchTransformation.format_search_response)r   )r   N)N)__name__
__module____qualname____doc__staticmethodr   boolr1   r   r   r   r   r   r   r   r   r9   r8   r7   r
   rP   r   r   r   r   r      sx    	)8b
#

1!r   )rT   r2   typingr   r   r   r   r   r   Zlitellm._loggingr   Zlitellm.constantsr	   Z+litellm.llms.base_llm.search.transformationr
   r   r   r   r   r   <module>   s     