Ë
    tPêjD& ã                   ó@  — U d Z ddlZddlZddlZddlmZmZmZ ddlm	Z	m
Z
mZmZmZ 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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' ddl(m)Z)m*Z*m+Z+m,Z, ddl-m.Z.m/Z/m0Z0 ddl1m2Z2 ddl3m4Z4m5Z5m6Z6m7Z7 ddl8m9Z9 e	r$ddl:m;Z< ddl=m>Z> ddl?m@Z@ ddlAmBZB ddl3mCZC ddl8mDZD dZEeeFd<   dZGeeFd<    G d„ de«      ZH G d„ d e«      ZI G d!„ d"e«      ZJ G d#„ d$ed%¬&«      ZK G d'„ d(e«      ZL G d)„ d*e«      ZM G d+„ d,e«      ZNy)-zß
WebSearch Interception Handler

CustomLogger that intercepts WebSearch tool calls for models that don't
natively support web search (e.g., Bedrock/Claude) and executes them
server-side using litellm router's search tools.
é    N)ÚAsyncIteratorÚMappingÚSequence)ÚTYPE_CHECKINGÚAnyÚFinalÚ	TypedDictÚcast)ÚReadOnly)Úverbose_logger©Úmessages)ÚLITELLM_WEB_SEARCH_TOOL_NAME)ÚCustomLogger)Úget_litellm_web_search_toolÚ"get_litellm_web_search_tool_openaiÚ%get_litellm_web_search_tool_responsesÚ#is_anthropic_native_web_search_toolÚis_web_search_toolÚ"is_web_search_tool_chat_completionÚis_web_search_tool_responses)ÚWebSearchTransformation©Úvalidated_max_agentic_loops)ÚSearchResponse)ÚCHAT_COMPLETION_AGENTIC_SURFACEÚRESPONSES_AGENTIC_SURFACEÚAgenticLoopPlanÚAgenticLoopRequestPatch)ÚAnthropicSearchQueryÚAnthropicServerToolUseBlockÚWebSearchInterceptionConfig)ÚAllMessageValues)ÚAgenticLoopParamsÚ	CallTypesÚLlmProvidersÚ!StandardLoggingUserAPIKeyMetadata)ÚProviderConfigManager)ÚLogging)ÚBaseAnthropicMessagesConfig)ÚUserAPIKeyAuth)ÚAnthropicMessagesResponse)ÚModelResponse)ÚCustomStreamWrapperÚ*_websearch_interception_emit_native_blocksÚ WEBSEARCH_EMIT_NATIVE_BLOCKS_KEYÚwebsearch_native_blocksÚ$WEBSEARCH_NATIVE_BLOCKS_METADATA_KEYc                   ó.   — e Zd ZU eeeef      dz  ed<   y)Ú_PlanMetadataViewNr1   )Ú__name__Ú
__module__Ú__qualname__r   r   ÚstrÚobjectÚ__annotations__© ó    úx/home/oem/CyberBrain26-unified/.venv/lib/python3.12/site-packages/litellm/integrations/websearch_interception/handler.pyr4   r4   Q   s   … Ø% g¨c°6¨kÑ&:Ñ;¸dÑBÔBr<   r4   c                   ó   — e Zd ZU eed<   y)Ú_AgenticLoopParamsViewÚagentic_loop_paramsN)r5   r6   r7   r$   r:   r;   r<   r=   r?   r?   U   s   … Ø*Ô*r<   r?   c                   ó   — e Zd ZU eed<   y)Ú_WebSearchSettingsViewÚwebsearch_interception_paramsN)r5   r6   r7   r"   r:   r;   r<   r=   rB   rB   Y   s   … Ø#>Ô>r<   rB   c                   ó2   — e Zd ZU eed<   eeef   dz  ed<   y)Ú_SearchToolConfigÚsearch_tool_nameNÚlitellm_params)r5   r6   r7   r8   r:   r   r9   r;   r<   r=   rE   rE   ]   s   … ØÓØ˜C ˜KÑ(¨4Ñ/Ô/r<   rE   F)Útotalc                   óL   — e Zd ZU dZee   ed<   eeeef      ed<   ee   ed<   y)Ú_DeploymentKwargsViewzFTyped reads of the untyped request kwargs seen by the deployment hook.Úcustom_llm_providerrG   ÚmodelN)	r5   r6   r7   Ú__doc__r   r8   r:   r   r9   r;   r<   r=   rJ   rJ   b   s-   … ÙPà! #™Ó&Ø˜W S¨& [Ñ1Ñ2Ó2Ø�C‰=Ôr<   rJ   c                   ó(   — e Zd ZU dZeedz     ed<   y)Ú_UserAuthViewzETyped read of the optional team attached to the caller's auth object.NÚteam_id)r5   r6   r7   rM   r   r8   r:   r;   r<   r=   rO   rO   j   s   … ÙOà�c˜D‘jÑ!Ô!r<   rO   c                   ó¦  ‡ — e Zd ZdZ	 	 	 dXdeeez     dz  dedz  dedz  fˆ fd„Ze	de
dedz  fd„«       Z	 dYd	ed
ee   dee   dz  dedz  deee
f   dz  deee
f   dz  fd„Zdeeef   dedz  deee
f   dz  fd„Zdeee
f   deeee
f      deee
f   dz  fd„Zededd fd„«       Ze	deee
f   de
fd„«       Zede
deeee
f      de
fd„«       Zd	ed
ee   dededz  fd„Zde
d	ed
ee   dee   dz  dedededeeef   fd„Zde
d	ed
ee   dee   dz  dedededeeef   fd„Zde
d	ed
ee   dee   dz  dedededeeef   fd„Zded	ed
ee   de
dd d!ed"d#dededd$fd%„Zded	ed
ee   de
dd d!ed"d#dedede fd&„Z!de
d'e dede
fd(„Z"e	d)ee   d*ee#dz     deeee
f   d+f   fd,„«       Z$e	d-eee
f   defd.„«       Z%e	d/ed0e#dz  deeee
f   eee
f   f   fd1„«       Z&e	ded2eeee
f      defd3„«       Z'ded	ed
ee   de
d4ed"d#dededd5fd6„Z(ded	ed
ee   de
d4ed"d#dedede fd7„Z)ded	ed
ee   de
d4ed"d#dedede fd8„Z*d	ed
eee   z  d)ee   d4edede+fd9„Z,e	d
eee   z  dee   fd:„«       Z-e	d;e
defd<„«       Z.e	d4ededefd=„«       Z/e	dedefd>„«       Z0d	ed
ee   d)ee   d?ee   d!ed"d#dededd$fd@„Z1d	ed
ee   d)ee   d?ee   d!ed"d#dedee+ee#dz     f   fdA„Z2	 dYd/edeee
f   dz  deee#dz  f   fdB„Z3dCeee
f   deee
f   dz  ddfdD„Z4e	dEdFdedz  deee
f   fdG„«       Z5e	dCeee
f   dz  dedz  fdH„«       Z6e	deee
f   dz  ddIfdJ„«       Z7dKe
ddLfdM„Z8dNee9   dOeddLfdP„Z:	 dZd	ed
ee   d)ee   d4ed"d#dededQedd5fdR„Z;	 dZd	ed
ee   d)ee   d4ededQede+fdS„Z<deee#dz  f   fdT„Z=e	dUeeef   dVeee
f   dd fdW„«       Z>ˆ xZ?S )[ÚWebSearchInterceptionLoggerab  
    CustomLogger that intercepts WebSearch tool calls for models that don't
    natively support web search.

    Implements agentic loop:
    1. Detects WebSearch tool_use in model response
    2. Executes litellm.asearch() for each query using router's search tools
    3. Makes follow-up request with search results
    4. Returns final response
    NÚenabled_providersrF   Úmax_agentic_loopsc                 ó  •— t         ‰| �  «        |€!t        j                  j                  g| _        n1|D �cg c]   }t        |t        «      r|j                  n|‘Œ" c}| _        || _        | j                  |«      | _	        d| _
        yc c}w )a÷  
        Args:
            enabled_providers: List of LLM providers to enable interception for.
                              Use LlmProviders enum values (e.g., [LlmProviders.BEDROCK])
                              If None or empty list, enables for ALL providers.
                              Default: None (all providers enabled)
            search_tool_name: Name of search tool configured in router's search_tools.
                             If None, will attempt to use first available search tool.
            max_agentic_loops: How many follow-up model calls one intercepted request
                              may chain before the loop is refused and the turn ends.
                              If None, LiteLLM's default of 3 applies.
        NF)ÚsuperÚ__init__r&   ÚBEDROCKÚvaluerS   Ú
isinstancerF   Ú_validated_max_agentic_loopsrT   Ú_request_has_websearch)ÚselfrS   rF   rT   ÚpÚ	__class__s        €r=   rW   z$WebSearchInterceptionLogger.__init__|   s~   ø€ ô$ 	‰ÑÔàÐ$Ü&2×&:Ñ&:×&@Ñ&@Ð%AˆDÕ"à]nÖ%oÐXY´¸A¼|Ô1L a§g¢gÐRSÑ&SÒ%oˆDÔ"Ø 0ˆÔØ!%×!BÑ!BÐCTÓ!UˆÔØ&+ˆÕ#ùò &ps   ·%B	Úreturnc                 ó   — t        | d¬«      S )zZ
        Reject loop ceilings the agentic loop cannot honor, at config load time.
        z/websearch_interception_params.max_agentic_loops)Úfieldr   )rT   s    r=   r[   z8WebSearchInterceptionLogger._validated_max_agentic_loops˜   s   € ô
 +Ð+<ÐDuÔvÐvr<   rL   r   ÚtoolsrK   Úkwargsc           
   ƒ   óp  K  — |sy|xs d}| j                   �|| j                   vry	 t        |«      }t        j                  ||¬«      }|�'|j	                  «       rt        j                  d|«       yt        d„ |D «       «      syddl
m}	  |	t        t        t           |«      «      }
|
syt        j                  d||
«       t        d	„ |D «       d«      }	 |€| j!                  |
«      ƒ d{  –—† \  }}n| j!                  |
|¬
«      ƒ d{  –—† \  }}g }|�tdt%        j&                  «       j(                  › �}|j+                  d«      xs d}|j-                  d||d|
idœ«       |j-                  t/        j0                  ||¬«      «       |j-                  d|dœ«       dt%        j&                  «       › �dd||dddddœdœ}t        j                  dt3        |«      |du«       |S # t        t        f$ r Y �Œ†w xY w7 �Œ7 Œó# t        $ r(}t        j"                  d|«       d|› �d}}Y d}~�Œd}~ww xY w­w)ud  
        Short-circuit web-search-only requests by executing the search directly.

        Claude Code sends web search as a separate, standalone /v1/messages
        request with a simple prompt and only web_search tool(s). For providers
        that don't natively support web search (e.g. github_copilot), there is
        no need to route this through the backend LLM â€” we can detect the
        pattern, execute the search via Tavily/Perplexity, and return a
        synthetic Anthropic response immediately.

        Args:
            model: Model name from the request
            messages: Messages list from the request
            tools: Tools list from the request
            custom_llm_provider: Provider name

        Returns:
            An AnthropicMessagesResponse dict if short-circuited, or None to
            continue normal processing.
        NÚ )rL   ÚproviderzpWebSearchInterception: Skipping short-circuit for %s (provider handles web search natively via the agentic loop)c              3   ó2   K  — | ]  }t        |«      –— Œ y ­w©N©r   ©Ú.0Úts     r=   ú	<genexpr>zGWebSearchInterceptionLogger.try_short_circuit_search.<locals>.<genexpr>Ý   s   è ø€ Ò8¨QÔ% a×(Ñ8ùó   ‚r   )Úget_last_user_messagezNWebSearchInterception: Short-circuit search detected (provider=%s, query='%s')c              3   ó8   K  — | ]  }t        |«      sŒ|–— Œ y ­wri   ©r   rk   s     r=   rn   zGWebSearchInterceptionLogger.try_short_circuit_search.<locals>.<genexpr>ô   s   è ø€ ÒH�1Ô!DÀQÕ!GŒQÑHùs   ‚“©rd   z6WebSearchInterception: Short-circuit search failed: %súSearch failed: Ú	srvtoolu_ÚnameÚ
web_searchÚserver_tool_useÚquery)ÚtypeÚidrv   Úinput©Útool_use_idÚsearch_responseÚtext)rz   r€   Úmsg_ÚmessageÚ	assistantÚend_turn)Úinput_tokensÚoutput_tokens)r{   rz   ÚrolerL   ÚcontentÚstop_reasonÚstop_sequenceÚusagezpWebSearchInterception: Short-circuit search completed, returning synthetic response (%s chars, native_blocks=%s))rS   r&   r(   Ú&get_provider_anthropic_messages_configÚhandles_web_search_nativelyr   ÚdebugÚ
ValueErrorÚ	ExceptionÚallÚ8litellm.litellm_core_utils.prompt_templates.common_utilsrp   r
   Úlistr#   ÚnextÚ_execute_searchÚerrorÚuuidÚuuid4ÚhexÚgetÚappendr   Ú"build_web_search_tool_result_blockÚlen)r]   rL   r   rc   rK   rd   Úprovider_strÚprovider_enumÚanthropic_configrp   ry   Únative_toolÚsearch_result_textÚ
structuredÚerˆ   r~   Ú	tool_nameÚresponses                      r=   Útry_short_circuit_searchz4WebSearchInterceptionLogger.try_short_circuit_searchŸ   s{  è ø€ ñ8 Øð 2Ò7°RˆØ×!Ñ!Ð-°,Àd×F\ÑF\Ñ2\Øð	Ü#/°Ó#=ˆMÜ&;×&bÑ&bØ mô'Ðð  Ð+Ð0@×0\Ñ0\Ô0^Ü×$Ñ$ð GØ ôð ô
 Ñ8°%Ô8Ô8Øõ	
ñ -¬T´$Ô7GÑ2HÈ(Ó-SÓTˆÙØä×ÑØ\Ð^jÐlqô	
ô "ÙH˜ÔHØó
ˆð	IØˆ~Ø7;×7KÑ7KÈEÓ7R×1RÑ.Ð"¡Jà7;×7KÑ7KÈEÐZ`Ð7KÓ7a×1aÑ.Ð" Jð
 35ˆØÐ"Ø#,¬T¯Z©Z«\×-=Ñ-=Ð,>Ð!?ˆKØ*Ÿ™¨vÓ6ÒF¸,ˆIØ�N‰Nà-Ø%Ø%Ø% uÐ-ñ	ôð �N‰NÜ'×JÑJØ +Ø$.ôôð 	�‰ Ð0BÑCÔDð œŸ™›˜Ð'ØØØØØ%Ø!Ø&'¸!Ñ<ñ	.
ˆô 	×ÑØ~ÜÐ"Ó#Ø˜tÐ#ô	
ð
 ˆøôa œIÐ&ò 	Úð	úðF 2Sùà1aùÜò 	IÜ× Ñ Ð!YÐ[\Ô]Ø/>¸q¸cÐ-BÀD 
Öûð	Iüsy   ‚%H6¨A
G' Á2A$H6ÃH Ã-G=Ã.H ÄH ÄH ÄCH6Ç'G:Ç6H6Ç9G:Ç:H6Ç=H È H È	H3ÈH.È(H6È.H3È3H6Ú	call_typec           	   ƒ   ó¶  K  — |j                  dd«      |j                  di «      |j                  dd«      dœ}|d   xs |d   j                  dd«      }|s	 t        j                  |d   ¬«      \  }}}}|| j                  vry|j                  d«      }|sy|t
        j                  t
        j                  fv r| j                  ||¬	«      S t        d
„ |D «       «      }|syt        j                  d«       t        d„ |D «       «      r	d|t        <   g }|D ]v  }	t        |	«      rXt        «       }
|j                  |
«       t        j                  d|	j                  dd«      |	j                  dd«      t         «       Œf|j                  |	«       Œx ||d<   |j                  d«      rt        j                  d«       d|d<   d|d<   |S # t        $ r d}Y �Œ_w xY w­w)aE  
        Pre-call hook to convert native Anthropic web_search tools to regular tools.

        This prevents Bedrock from trying to execute web search server-side (which fails).
        Instead, we convert it to a regular tool so the model returns tool_use blocks
        that we can intercept and execute ourselves.
        rK   rf   rG   rL   )rK   rG   rL   )rL   Nrc   )rd   rc   c              3   ó2   K  — | ]  }t        |«      –— Œ y ­wri   rj   rk   s     r=   rn   zMWebSearchInterceptionLogger.async_pre_call_deployment_hook.<locals>.<genexpr>P  ó   è ø€ Ò"H¸QÔ#5°a×#8Ñ"Hùro   zMWebSearchInterception: Converting native web_search tools to LiteLLM standardc              3   ó2   K  — | ]  }t        |«      –— Œ y ­wri   rr   rk   s     r=   rn   zMWebSearchInterceptionLogger.async_pre_call_deployment_hook.<locals>.<genexpr>\  ó   è ø€ ÒE¸!Ô2°1×5ÑEùro   Tú3WebSearchInterception: Converted %s (type=%s) to %srv   Úunknownrz   ÚnoneÚstreamúMWebSearchInterception: deployment hook converting stream=True to stream=FalseFÚ(_websearch_interception_converted_stream)rš   ÚlitellmÚget_llm_providerr�   rS   r%   Ú	responsesÚ
aresponsesÚ_convert_responses_toolsÚanyr   rŽ   r0   r   r   r›   r   )r]   rd   r¨   Úkwargs_viewrK   Ú_rc   Úhas_websearchÚconverted_toolsÚtoolÚconverted_tools              r=   Úasync_pre_call_deployment_hookz:WebSearchInterceptionLogger.async_pre_call_deployment_hook+  s÷  è ø€ ð $*§:¡:Ð.CÀRÓ#HØ$Ÿj™jÐ)9¸2Ó>Ø—Z‘Z ¨Ó,ñ5
ˆð
 *Ð*?Ñ@ò 
ÀKÐP`ÑDa×DeÑDeØ! 2óE
Ðñ #ð)Ü/6×/GÑ/GÈkÐZaÑNbÔ/cÑ,�Ð&¨¨1ð  d×&<Ñ&<Ñ<Øð <B¿:¹:ÀgÓ;NˆÙØàœ×,Ñ,¬i×.BÑ.BÐCÑCØ×0Ñ0¸ÀeÐ0ÓLÐLô  #Ñ"HÀ%Ô"HÓHˆáØä×ÑÐlÔmô ÑE¸uÔEÔEØ7;ˆFÔ3Ñ4ð "$ˆØò 	-ˆDÜ! $Ô'ä!CÓ!E�Ø×&Ñ& ~Ô6Ü×$Ñ$ØIØ—H‘H˜V YÓ/Ø—H‘H˜V VÓ,Ü0õ	ð  ×&Ñ& tÕ,ð	-ð *ˆˆw‰à�:‰:�hÔÜ× Ñ Ð!pÔqØ$ˆF�8ÑØAEˆFÐ=Ñ>àˆøôk ò )Ø&(Ó#ð)üs+   ‚AGÁG Á6EGÇGÇGÇGÇGc                 ó  — t        d„ |D «       «      syt        j                  d«       |D �cg c]  }t        |«      r
t	        «       n|‘Œ }}i |¥d|i¥}|j                  d«      rt        j                  d«       d|d<   d|d	<   |S c c}w )
zMConvert Responses API web search tools to the LiteLLM standard function tool.c              3   ó2   K  — | ]  }t        |«      –— Œ y ­wri   ©r   )rl   r¾   s     r=   rn   zGWebSearchInterceptionLogger._convert_responses_tools.<locals>.<genexpr>}  s   è ø€ ÒH¸$Ô/°×5ÑHùro   NzPWebSearchInterception: Converting Responses web_search tools to LiteLLM standardrc   r±   r²   FTr³   )r¹   r   rŽ   r   r   rš   )r]   rd   rc   r¾   r½   Úconverted_kwargss         r=   r¸   z4WebSearchInterceptionLogger._convert_responses_toolsy  s§   € ô ÑHÀ%ÔHÔHØä×ÑÐoÔpð qvö"
ØhlÔ7SÐTXÔ7YÔ1Ô3Ð_cÑcð"
ˆð "
ð #G VÐ"F¨W°oÑ"FÐà�:‰:�hÔÜ× Ñ Ð!pÔqØ).Ð˜XÑ&ØKOÐÐGÑHàÐùò"
s   ­BÚconfigc                 ó  — |j                  dd«      }|j                  dd«      }|j                  dd«      }d}|�&g }|D ]  }	 t        |«      }|j                  |«       Œ!  | |||¬«      S # t        $ r |j                  |«       Y ŒIw xY w)að  
        Initialize WebSearchInterceptionLogger from proxy config.yaml parameters.

        Args:
            config: Configuration dictionary from litellm_settings.websearch_interception_params

        Returns:
            Configured WebSearchInterceptionLogger instance

        Example:
            From proxy_config.yaml:
                litellm_settings:
                  websearch_interception_params:
                    enabled_providers: ["bedrock"]
                    search_tool_name: "my-perplexity-search"
                    max_agentic_loops: 5

            Usage:
                config = litellm_settings.get("websearch_interception_params", {})
                logger = WebSearchInterceptionLogger.from_config_yaml(config)
        rS   NrF   rT   )rS   rF   rT   )rš   r&   r›   r�   )ÚclsrÅ   Úenabled_providers_strrF   rT   rS   rg   rŸ   s           r=   Úfrom_config_yamlz,WebSearchInterceptionLogger.from_config_yaml�  s²   € ð0 (.§z¡zÐ2EÀtÓ'LÐØ"(§*¡*Ð-?ÀÓ"FÐØ#)§:¡:Ð.AÀ4Ó#HÐð >BÐØ Ð,Ø "ÐØ1ò 7�ð7ä$0°Ó$:�MØ%×,Ñ,¨]Õ;ð	7ñ Ø/Ø-Ø/ô
ð 	
øô	 "ò 7à%×,Ñ,¨XÖ6ð7ús   ÁA,Á,B	ÂB	r¾   c                 ó°   — | j                  d«      }| j                  d«      dk(  r!t        |t        «      r|j                  d«      S | j                  d«      S )z@Effective tool name, handling OpenAI ``function`` wrapper shape.Úfunctionrz   rv   ©rš   rZ   Údict)r¾   Úfns     r=   Ú
_tool_namez&WebSearchInterceptionLogger._tool_name¾  sI   € ð —H‘H˜ZÓ(ˆØ�8‰8�FÓ˜zÒ)¬j¸¼TÔ.BØ—6‘6˜&“>Ð!Ø�x‰x˜ÓÐr<   Útool_choicer½   c                 óÖ   — t        |t        «      r|j                  d«      dk7  r|S |D �ch c]  }| j                  |«      ’Œ }}|j                  d«      |v r|S i |¥dt        i¥S c c}w )aý  Repoint a forced ``tool_choice`` at ``litellm_web_search`` when it
        names a web-search tool that was just converted away.

        Native clients (e.g. Claude Code) force the search tool via
        ``tool_choice={"type": "tool", "name": "web_search"}``. Since the tool
        definition gets renamed to ``litellm_web_search``, an unrewritten
        ``tool_choice`` points at a tool that no longer exists, which Anthropic
        rejects with "Tool 'web_search' not found in provided tools".
        rz   r¾   rv   )rZ   rÍ   rš   rÏ   r   )rÇ   rÐ   r½   rm   Úconverted_namess        r=   Ú_sync_forced_tool_choicez4WebSearchInterceptionLogger._sync_forced_tool_choiceÆ  sp   € ô ˜+¤tÔ,°·±ÀÓ0GÈ6Ò0QØÐØ=LÖ!M¸ #§.¡.°Õ"3Ð!MˆÐ!MØ�?‰?˜6Ó" oÑ5ØÐØD�+ÐD˜vÔ'CÑDÐDùò "Ns   «A&c           	   ƒ   óH  K  — |j                  di «      j                  dd«      }t        j                  d|| j                  xs d«       | j                  �0|| j                  vr"t        j                  d|| j                  «       y|j                  d«      }|syt	        d	„ |D «       «      }|syt        j                  d
|«       |j                  d«      }| j
                  �|€| j
                  |d<   t	        d„ |D «       «      r	d|t        <   g }|D ]v  }	t        |	«      rXt        «       }
|j                  |
«       t        j                  d|	j                  dd«      |	j                  dd«      t        «       Œf|j                  |	«       Œx ||d<   t        j                  d|D �cg c]  }|j                  d«      ‘Œ c}«       d|v r$| j                  |j                  d«      |«      |d<   |j                  d«      rt        j                  d«       d|d<   d|d<   |S c c}w ­w)a†  
        Pre-request hook to convert native web search tools to LiteLLM standard.

        This hook is called before the API request is made, allowing us to:
        1. Detect native web search tools (web_search_20250305, etc.)
        2. Convert them to LiteLLM standard format (litellm_web_search)
        3. Convert stream=True to stream=False for interception

        This prevents providers like Bedrock from trying to execute web search
        natively (which fails), and ensures our agentic loop can intercept tool_use.

        Returns:
            Modified kwargs dict with converted tools, or None if no modifications needed
        rG   rK   rf   z^WebSearchInterception: Pre-request hook called - custom_llm_provider=%s - enabled_providers=%sÚALLNz7WebSearchInterception: Skipping - provider %s not in %src   c              3   ó2   K  — | ]  }t        |«      –— Œ y ­wri   rj   rk   s     r=   rn   zEWebSearchInterceptionLogger.async_pre_request_hook.<locals>.<genexpr>ü  r«   ro   zAWebSearchInterception: Pre-request hook triggered for provider=%srT   c              3   ó2   K  — | ]  }t        |«      –— Œ y ­wri   rr   rk   s     r=   rn   zEWebSearchInterceptionLogger.async_pre_request_hook.<locals>.<genexpr>  r­   ro   Tr®   rv   r¯   rz   r°   z1WebSearchInterception: Tools after conversion: %srÐ   r±   z=WebSearchInterception: Converting stream=True to stream=FalseFr³   )rš   r   rŽ   rS   r¹   rT   r0   r   r   r›   r   rÓ   )r]   rL   r   rd   rK   rc   r¼   Údeployment_max_agentic_loopsr½   r¾   Ústandard_toolrm   s               r=   Úasync_pre_request_hookz2WebSearchInterceptionLogger.async_pre_request_hookØ  s'  è ø€ ð  &,§Z¡ZÐ0@À"Ó%E×%IÑ%IÐJ_ÐacÓ%dÐä×ÑØlØØ×"Ñ"Ò+ eô	
ð ×!Ñ!Ð-Ð2EÈT×McÑMcÑ2cÜ× Ñ ØIÐK^Ð`d×`vÑ`vôð ð —z‘z 'Ó*ˆÙØô  #Ñ"HÀ%Ô"HÓHˆÙØä×ÑÐ`ÐbuÔvà.4¯j©jÐ9LÓ.MÐ$Ø×!Ñ!Ð-Ð2NÐ2VØ*.×*@Ñ*@ˆFÐ&Ñ'ô ÑE¸uÔEÔEØ7;ˆFÔ3Ñ4ð ;=ˆØò 	-ˆDÜ! $Ô'Ü ;Ó =�Ø×&Ñ& }Ô5Ü×$Ñ$ØIØ—H‘H˜V YÓ/Ø—H‘H˜V VÓ,Ü0õ	ð  ×&Ñ& tÕ,ð	-ð *ˆˆw‰Ü×ÑØ?ÐYhÖAiÐTUÀ!Ç%Á%ÈÅ-ÒAiô	
ð ˜FÑ"Ø$(×$AÑ$AÀ&Ç*Á*È]ÓB[Ð]lÓ$mˆF�=Ñ!ð �:‰:�hÔÜ× Ñ Ð!`ÔaØ$ˆF�8ÑØAEˆFÐ=Ñ>àˆùò Bjùs   ‚F"H"Æ$H
Æ<A&H"r¦   r±   c           	   ƒ   ó  K  — |j                  d«      t        k(  r | j                  |||||||¬«      ƒ d {  –—† S |j                  d«      t        k(  r | j	                  |||||||¬«      ƒ d {  –—† S t        j                  d||«       t        j                  dt        |«      «       | j                  �3|| j                  vr%t        j                  d|| j                  «       di fS t        d„ |xs g D «       «      }|st        j                  d«       di fS t        j                  ||d	¬
«      \  }	}
|	st        j                  d«       di fS t        j                  dt        |
«      «       g }t        |t        «      r|j                  dg «      }nt        |dg «      xs g }|D ]£  }t        |t        «      r|j                  d«      }nt        |dd «      }|dv sŒ7t        |t        «      r|j!                  |«       ŒYd|i}|dk(  r!t        |dd«      |d<   t        |dd«      |d<   nt        |dd«      |d<   |j!                  |«       Œ¥ |rt        j                  dt        |«      «       |
d|d	|dœ}d|fS 7 �ŒC7 �Œ­w)NÚ_agentic_loop_api_surface)r¦   rL   r   rc   r±   rK   rd   z:WebSearchInterception: Hook called! provider=%s, stream=%sú(WebSearchInterception: Response type: %súEWebSearchInterception: Skipping provider %s (not in enabled list: %s)Fc              3   ó2   K  — | ]  }t        |«      –— Œ y ­wri   rj   rk   s     r=   rn   zLWebSearchInterceptionLogger.async_should_run_agentic_loop.<locals>.<genexpr>\  s   è ø€ Ò'UÀ!Ô(:¸1×(=Ñ'Uùro   z4WebSearchInterception: No web search tool in requestÚ	anthropic©r¦   r±   Úresponse_formatzAWebSearchInterception: No WebSearch tool_use detected in responseúQWebSearchInterception: Detected %s WebSearch tool call(s), executing agentic looprˆ   rz   )ÚthinkingÚredacted_thinkingrä   rf   Ú	signatureÚdatazCWebSearchInterception: Extracted %s thinking block(s) from responseÚ	websearch)Ú
tool_callsÚ	tool_typerg   râ   Úthinking_blocksT)rš   r   Ú-async_should_run_chat_completion_agentic_loopr   Ú'async_should_run_responses_agentic_loopr   rŽ   rz   rS   r¹   r   Útransform_requestr�   rZ   rÍ   Úgetattrr›   )r]   r¦   rL   r   rc   r±   rK   rd   Úhas_websearch_toolÚshould_interceptré   rë   rˆ   ÚblockÚ
block_typeÚthinking_block_dictÚ
tools_dicts                    r=   Úasync_should_run_agentic_loopz9WebSearchInterceptionLogger.async_should_run_agentic_loop-  sÒ  è ø€ ð �:‰:Ð1Ó2Ô6UÒUØ×KÑKØ!ØØ!ØØØ$7Øð Ló ÷ ð ð �:‰:Ð1Ó2Ô6OÒOØ×EÑEØ!ØØ!ØØØ$7Øð Fó ÷ ð ô 	×ÑÐYÐ[nÐpvÔwÜ×ÑÐGÌÈhËÔXð
 ×!Ñ!Ð-Ð2EÈT×McÑMcÑ2cÜ× Ñ ØWØ#Ø×&Ñ&ôð
 ˜"�9Ðô %(Ñ'UÈÊÐQSÔ'UÓ$UÐÙ!Ü× Ñ Ð!WÔXØ˜"�9Ðô (?×'PÑ'PØØØ'ô(
Ñ$Ð˜*ñ  Ü× Ñ Ð!dÔeØ˜"�9Ðä×ÑØ_ÔadÐeoÓapô	
ð .0ˆÜ�h¤Ô%Ø—l‘l 9¨bÓ1‰Gä˜h¨	°2Ó6Ò<¸"ˆGàò 	@ˆEÜ˜%¤Ô&Ø"ŸY™Y vÓ.‘
ä$ U¨F°DÓ9�
àÐ>Ò>Ü˜e¤TÔ*Ø#×*Ñ*¨5Õ1ð 28¸Ð0DÐ'Ø! ZÒ/Ü:AÀ%ÈÐUWÓ:XÐ+¨JÑ7Ü;BÀ5È+ÐWYÓ;ZÐ+¨KÒ8ä6=¸eÀVÈRÓ6PÐ+¨FÑ3Ø#×*Ñ*Ð+>Õ?ð%	@ñ( Ü× Ñ ØUÔWZÐ[jÓWkôð %Ø$Ø+Ø*Ø.ñ
ˆ
ð �ZÐÐðGùðûs)   ‚4I?¶I9·7I?Á.I<Á/E-I?ÇBI?É<I?c              ƒ   ó  K  — t        j                  d||«       t        j                  dt        |«      «       | j                  �3|| j                  vr%t        j                  d|| j                  «       di fS t	        d„ |xs g D «       «      }|st        j                  d«       di fS t        j                  ||d¬«      \  }	}
|	st        j                  d	«       di fS t        j                  d
t        |
«      «       |
d|ddœ}d|fS ­w)z³
        Check if WebSearch tool interception is needed for Chat Completions API.

        Similar to async_should_run_agentic_loop but for OpenAI-style chat completions.
        zJWebSearchInterception: Chat completion hook called! provider=%s, stream=%srÝ   rÞ   Fc              3   ó2   K  — | ]  }t        |«      –— Œ y ­wri   )r   rk   s     r=   rn   z\WebSearchInterceptionLogger.async_should_run_chat_completion_agentic_loop.<locals>.<genexpr>¼  s   è ø€ Ò'eÐRSÔ(JÈ1×(MÑ'eùro   z<WebSearchInterception: No litellm_web_search tool in requestÚopenairá   zCWebSearchInterception: No WebSearch tool_calls detected in responserã   rè   ©ré   rê   rg   râ   T)r   rŽ   rz   rS   r¹   r   rî   r�   ©r]   r¦   rL   r   rc   r±   rK   rd   rð   rñ   ré   rõ   s               r=   rì   zIWebSearchInterceptionLogger.async_should_run_chat_completion_agentic_loop�  s,  è ø€ ô  	×ÑØXÐZmÐouô	
ô 	×ÑÐGÌÈhËÔXð ×!Ñ!Ð-Ð2EÈT×McÑMcÑ2cÜ× Ñ ØWØ#Ø×&Ñ&ôð
 ˜"�9Ðô %(Ñ'eÐX]ÒXcÐacÔ'eÓ$eÐÙ!Ü× Ñ Ð!_Ô`Ø˜"�9Ðô (?×'PÑ'PØØØ$ô(
Ñ$Ð˜*ñ  Ü× Ñ Ð!fÔgØ˜"�9Ðä×ÑØ_ÔadÐeoÓapô	
ð %Ø$Ø+Ø'ñ	
ˆ
ð �ZÐÐùs   ‚DD	c              ƒ   óØ  K  — t        j                  d||«       | j                  �3|| j                  vr%t        j                  d|| j                  «       di fS t        d„ |xs g D «       «      }|st        j                  d«       di fS t	        j
                  ||d¬«      \  }	}
|	st        j                  d«       di fS t        j                  d	t        |
«      «       |
d
|ddœ}d|fS ­w)z@Check if WebSearch interception is needed for the Responses API.zDWebSearchInterception: Responses hook called! provider=%s, stream=%srÞ   Fc              3   ó2   K  — | ]  }t        |«      –— Œ y ­wri   rÃ   rk   s     r=   rn   zVWebSearchInterceptionLogger.async_should_run_responses_agentic_loop.<locals>.<genexpr>ð  s   è ø€ Ò'_ÈAÔ(DÀQ×(GÑ'_ùro   zFWebSearchInterception: No litellm_web_search tool in responses requestr¶   rá   zNWebSearchInterception: No WebSearch function_call detected in responses outputzUWebSearchInterception: Detected %s WebSearch function_call(s), executing agentic looprè   rú   T)r   rŽ   rS   r¹   r   rî   r�   rû   s               r=   rí   zCWebSearchInterceptionLogger.async_should_run_responses_agentic_loopÙ  s  è ø€ ô 	×ÑØRÐTgÐioô	
ð ×!Ñ!Ð-Ð2EÈT×McÑMcÑ2cÜ× Ñ ØWØ#Ø×&Ñ&ôð
 ˜"�9Ðä$'Ñ'_ÐRWÒR]Ð[]Ô'_Ó$_ÐÙ!Ü× Ñ Ð!iÔjØ˜"�9Ðä'>×'PÑ'PØØØ'ô(
Ñ$Ð˜*ñ  Ü× Ñ Ð!qÔrØ˜"�9Ðä×ÑØcÔehÐisÓetô	
ð
 %Ø$Ø+Ø*ñ	
ˆ
ð �ZÐÐùs   ‚C(C*Ú"anthropic_messages_provider_configz"BaseAnthropicMessagesConfig | NoneÚ*anthropic_messages_optional_request_paramsÚlogging_objzLiteLLMLoggingObj | Nonez1AnthropicMessagesResponse | AsyncIterator[object]c
           
   ƒ   ó¼   K  — |d   }
|j                  dg «      }t        j                  dt        |
«      «       | j	                  |||
|||||	¬«      ƒ d{  –—† S 7 Œ­w)z�
        Execute agentic loop with WebSearch execution for Anthropic Messages API.

        This is the legacy method for Anthropic-style responses.
        ré   rë   z?WebSearchInterception: Executing agentic loop for %s search(es))rL   r   ré   rë   rÿ   r   r±   rd   N)rš   r   rŽ   r�   Ú_execute_agentic_loop)r]   rc   rL   r   r¦   rþ   rÿ   r   r±   rd   ré   rë   s               r=   Úasync_run_agentic_loopz2WebSearchInterceptionLogger.async_run_agentic_loop  su   è ø€ ð$ " ,Ñ/ˆ
Ø!&§¡Ð+<¸bÓ!Aˆä×ÑÐ^Ô`cÐdnÓ`oÔpà×/Ñ/ØØØ!Ø+Ø7aØ#ØØð 0ó 	
÷ 	
ð 		
ð 	
úó   ‚AAÁAÁAc
           
   ƒ   óò  K  — |	j                  d«      t        k(  r!| j                  ||||||||	¬«      ƒ d {  –—† S |	j                  d«      t        k(  r!| j	                  ||||||||	¬«      ƒ d {  –—† S |d   }
|j                  dg «      }| j                  |||
||||	¬«      ƒ d {  –—† \  }}dddœ}|	j                  t        «      r| j                  |
|¬	«      |t        <   t        d
||¬«      S 7 Œ¹7 Œ‚7 ŒM­w)NrÜ   )rc   rL   r   r¦   Úoptional_paramsr   r±   rd   ré   rë   ©rL   r   ré   rë   rÿ   r   rd   rè   rà   ©rê   râ   ©ré   Ústructured_resultsT©Úrun_agentic_loopÚrequest_patchÚmetadata)
rš   r   Ú-async_build_chat_completion_agentic_loop_planr   Ú'async_build_responses_agentic_loop_planÚ_build_anthropic_request_patchr0   Ú_build_native_result_blocksr2   r   )r]   rc   rL   r   r¦   rþ   rÿ   r   r±   rd   ré   rë   r  r
  r  s                  r=   Úasync_build_agentic_loop_planz9WebSearchInterceptionLogger.async_build_agentic_loop_plan-  sY  è ø€ ð �:‰:Ð1Ó2Ô6UÒUØ×KÑKØØØ!Ø!Ø JØ'ØØð Ló 	÷ 	ð 	ð �:‰:Ð1Ó2Ô6OÒOØ×EÑEØØØ!Ø!Ø JØ'ØØð Fó 	÷ 	ð 	ð " ,Ñ/ˆ
Ø!&§¡Ð+<¸bÓ!AˆØ26×2UÑ2UØØØ!Ø+Ø7aØ#Øð 3Vó 3
÷ -
Ñ)ˆÐ)ð %Ø*ñ.
ˆð �:‰:Ô6Ô7Ø=A×=]Ñ=]Ø%Ø#5ð >^ó >ˆHÔ9Ñ:ô
 Ø!Ø'Øô
ð 	
ðe	øð	øð-
ús4   ‚5C7·C1¸8C7Á0C3Á16C7Â'C5Â(A
C7Ã3C7Ã5C7Úplanc              ƒ   ó‚   K  — d|j                   j                  t        «      i}|d   }|s|S | j                  ||«      S ­w)aâ  
        Inject Anthropic-native ``web_search_tool_result`` blocks into the
        final response when the originating client used a native
        ``web_search_*`` tool.

        See ``WebSearchTransformation.build_web_search_tool_result_block`` for
        the block shape. The blocks are prepended to ``response.content`` so
        Anthropic-native clients (Claude Desktop, the Anthropic SDK) can
        render citations / sources alongside the model's textual reply.
        r1   )r  rš   r2   Ú_inject_native_blocks)r]   r¦   r  rd   Úmetadata_viewÚnative_blockss         r=   Ú%async_post_agentic_loop_response_hookzAWebSearchInterceptionLogger.async_post_agentic_loop_response_hookr  sL   è ø€ ð" & t§}¡}×'8Ñ'8Ô9]Ó'^ð3
ˆð  -Ð-FÑGˆÙØˆOØ×)Ñ)¨(°MÓBÐBùs   ‚=?ré   r
  .c                 ó>   ‡— t        ˆfd„t        | «      D «       «      S )a˜  
        Build a ``server_tool_use`` + ``web_search_tool_result`` pair per tool_call.

        The pair is what Anthropic's spec requires: a bare result block, or one
        keyed by the model's ``toolu_...`` id instead of a ``srvtoolu_...`` one,
        is rejected on replay ("String should match pattern '^srvtoolu_'") and
        leaves native clients without a search to attach the sources to.
        c              3   ó¬   •K  — | ]K  \  }}t         j                  t         j                  |«      |t        ‰«      k  r‰|   nd ¬«      D ]  }|–— Œ ŒM y ­w)N)ry   r   )rR   Ú_native_result_pairÚ_tool_call_queryr�   )rl   ÚiÚ	tool_callrò   r
  s       €r=   rn   zJWebSearchInterceptionLogger._build_native_result_blocks.<locals>.<genexpr>—  sj   øè ø€ ò 
á��9Ü4×HÑHÜ1×BÑBÀ9ÓMØ9:¼SÐASÓ=TÒ9TÐ 2°1Ò 5ÐZ^ð Ió ò
ð ô ð
Øñ
ùs   ƒAA)ÚtupleÚ	enumerater	  s    `r=   r  z7WebSearchInterceptionLogger._build_native_result_blocksŠ  s$   ø€ ô ó 
ä )¨*Ó 5ô
ó 
ð 	
r<   r  c                 ó�   — | j                  d«      }t        |t        «      sy|j                  d«      }t        |t        «      r|S dS )Nr|   rf   ry   )rš   rZ   r   r8   )r  Ú
tool_inputry   s      r=   r  z,WebSearchInterceptionLogger._tool_call_query   s?   € à%ŸM™M¨'Ó2ˆ
Ü˜*¤gÔ.ØØ!—~‘~ gÓ.ˆÜ" 5¬#Ô.ˆuÐ6°BÐ6r<   ry   r   c                 ó¼   — dt        j                  «       j                  › �}t        |t	        | ¬«      ¬«      j                  «       t        j                  ||¬«      fS )Nru   )ry   )r{   r|   r}   )r—   r˜   r™   r!   r    Ú
model_dumpr   rœ   )ry   r   r~   s      r=   r  z/WebSearchInterceptionLogger._native_result_pair¨  sU   € ð
  )¬¯©«×)9Ñ)9Ð(:Ð;ˆä'¨;Ô>RÐY^Ô>_Ô`×kÑkÓmÜ#×FÑFØ'Ø /ôð
ð 	
r<   r  c                 ój  — |s| S t        | t        «      r1| j                  d«      xs g }t        |«      t        |«      z   | d<   | S t	        | dd«      xs g }	 t        |«      t        |«      z   | _        | S # t        t        f$ r- t        j                  dt        | «      j                  «       Y | S w xY w)z?Prepend native blocks to response content, dict or object form.rˆ   NzNWebSearchInterception: could not inject native blocks into response of type %s)rZ   rÍ   rš   r“   rï   rˆ   ÚAttributeErrorÚ	TypeErrorr   rŽ   rz   r5   )r¦   r  Úexistings      r=   r  z1WebSearchInterceptionLogger._inject_native_blocks¶  s¸   € ñ ØˆOÜ�h¤Ô%Ø—|‘| IÓ.Ò4°"ˆHÜ"& }Ó"5¼¸X»Ñ"FˆH�YÑØˆOÜ˜8 Y°Ó5Ò;¸ˆð	Ü# MÓ2´T¸(³^ÑCˆHÔð ˆøô ¤	Ð*ò 	ô × Ñ Ø`Ü�X“×'Ñ'õð ˆð	ús   ÁA6 Á68B2Â1B2r  z#ModelResponse | CustomStreamWrapperc	           
   ƒ   ó¼   K  — |d   }	|j                  dd«      }
t        j                  dt        |	«      «       | j	                  |||	|||||
¬«      ƒ d{  –—† S 7 Œ­w)z«
        Execute agentic loop with WebSearch execution for Chat Completions API.

        Similar to async_run_agentic_loop but for OpenAI-style chat completions.
        ré   râ   rù   zOWebSearchInterception: Executing chat completion agentic loop for %s search(es))rL   r   ré   r  r   r±   rd   râ   N)rš   r   rŽ   r�   Ú%_execute_chat_completion_agentic_loop)r]   rc   rL   r   r¦   r  r   r±   rd   ré   râ   s              r=   Ú&async_run_chat_completion_agentic_loopzBWebSearchInterceptionLogger.async_run_chat_completion_agentic_loopË  sz   è ø€ ð" " ,Ñ/ˆ
Ø!&§¡Ð+<¸hÓ!Gˆä×ÑØ]Ô_bÐcmÓ_nô	
ð ×?Ñ?ØØØ!Ø+Ø#ØØØ+ð @ó 	
÷ 	
ð 		
ð 	
úr  c	              ƒ   óœ   K  — |d   }	|j                  dd«      }
| j                  |||	|||
¬«      ƒ d {  –—† }t        d|d|
dœ¬«      S 7 Œ­w)	Nré   râ   rù   ©rL   r   ré   r  rd   râ   Trè   r  r  )rš   Ú$_build_chat_completion_request_patchr   )r]   rc   rL   r   r¦   r  r   r±   rd   ré   râ   r  s               r=   r  zIWebSearchInterceptionLogger.async_build_chat_completion_agentic_loop_planî  sr   è ø€ ð " ,Ñ/ˆ
Ø!&§¡Ð+<¸hÓ!GˆØ%)×%NÑ%NØØØ!Ø+ØØ+ð &Oó &
÷  
ˆô Ø!Ø'Ø#.À?ÑSô
ð 	
ð 
ús   ‚2A´A
µAc	              ƒ   óv   K  — |d   }	| j                  |||	||¬«      ƒ d {  –—† }
t        d|
dddœ¬«      S 7 Œ­w)Nré   )rL   r   ré   r  rd   Trè   r¶   r  r  )Ú_build_responses_request_patchr   )r]   rc   rL   r   r¦   r  r   r±   rd   ré   r  s              r=   r  zCWebSearchInterceptionLogger.async_build_responses_agentic_loop_plan	  s^   è ø€ ð " ,Ñ/ˆ
Ø%)×%HÑ%HØØØ!Ø+Øð &Ió &
÷  
ˆô Ø!Ø'Ø#.À;ÑOô
ð 	
ð 
ús   ‚9¡7¢9c              ƒ   ó–  K  — |D �cg c]^  }t        |j                  d«      t        «      r-|d   j                  d«      r| j                  |d   d   |¬«      n| j	                  «       ‘Œ` }}t        j                  dt        |«      «       t        j                  |ddiŽƒ d{  –—† }|D �	cg c]  }	| j                  |	«      ‘Œ }
}	t        ||
«      D ���cg c]K  \  }}d|j                  d	«      t        |j                  d
d«      dœd|j                  d	«      |dœfD ]  }|‘Œ ŒM }}}}| j                  |«      |z   }|j                  d«      }|j                  «       D ��ci c]  \  }}|dvr||“Œ }}}|j                  «       D ��ci c]  \  }}|j                  d«      s|dvr||“Œ }}}|}d|vr)t        |j                  d«      t         «      r
|d   › d|› �}t        j                  d|t        |«      t        |
«      «       t#        ||t        |t$        «      r|nd||¬«      S c c}w 7 �Œ‹c c}	w c c}}}w c c}}w c c}}w ­w)z@Execute litellm.asearch() and build a Responses API rerun patch.r|   ry   rs   zDWebSearchInterception: Executing %s responses search(es) in parallelÚreturn_exceptionsTNÚfunction_callÚcall_idÚ	argumentsrf   )rz   r5  rv   r6  Úfunction_call_output)rz   r5  Úoutputrc   >   rc   r±   rÐ   Úmodel_alias_mapÚstream_responseÚcustom_prompt_dictÚ_websearch_interception>   Úacompletionr9  rK   Úlitellm_logging_objrÜ   ú/rK   zXWebSearchInterception: Built responses request patch model=%s input_items=%d searches=%d)rL   r   rc   r  rd   )rZ   rš   rÍ   r•   Ú_create_empty_search_resultr   rŽ   r�   ÚasyncioÚgatherÚ_extract_search_textÚzipr   Ú_normalize_responses_inputÚitemsÚ
startswithr8   r   r“   )r]   rL   r   ré   r  rd   r  Úsearch_tasksÚsearch_resultsÚresultÚsearch_textsÚsearch_textÚitemÚfollowup_itemsÚ
input_listÚtools_paramÚkÚvÚoptional_params_cleanÚkwargs_for_followupÚfull_model_names                        r=   r1  z:WebSearchInterceptionLogger._build_responses_request_patch"  s›  è ø€ ð (ö
ð ô ˜iŸm™m¨GÓ4´dÔ;À	È'Ñ@R×@VÑ@VÐW^Ô@_ð ×$Ñ$ Y¨wÑ%7¸Ñ%@ÈÐ$ÔPà×5Ñ5Ó7ñ8ð
ˆð 
ô 	×ÑÐcÔehÐiuÓevÔwÜ&-§n¡n°lÐ&[ÐVZÑ&[× [ˆàO]Ö^ÀV˜t×8Ñ8¸Õ@Ð^ˆÐ^ô +.¨j¸,Ó*G÷!
ð !
á&�	˜;ð ,Ø(Ÿ}™}¨YÓ7Ü8Ø!*§¡¨{¸BÓ!?ñ	ð 3Ø(Ÿ}™}¨YÓ7Ø)ñðò!
ð ò ð!
Øð!
ˆò !
ð$ !×;Ñ;¸HÓEÈÑVˆ
à,×0Ñ0°Ó9ˆð (×-Ñ-Ó/÷(
á��1ØÐvÑvð ˆq‰Dð(
Ðñ (
ð Ÿ™›÷&
á��1Ø—<‘<Ð 9Ô:Øðñð ˆq‰Dð&
Ðñ &
ð  ˆØ�eÑ¤
¨6¯:©:Ð6KÓ+LÌcÔ RØ!'Ð(=Ñ!>Ð ?¸qÀÀÐHˆOä×ÑØfØÜ�
‹OÜ�Óô		
ô 'Ø!ØÜ!+¨K¼Ô!>‘+ÀDØ1Ø&ô
ð 	
ùòE
ð !\ûâ^ùô!
ùó*(
ùó&
ùsU   ‚I	‡A#H)Á*9I	Â#H.Â$I	Â,H1ÃI	ÃAH6Ä&<I	Å"H=Å3I	Æ	"IÆ+BI	È1I	c                 óh   — t        | t        «      rd| dœgS t        | t        «      rt        | «      S g S )NÚuser)r‡   rˆ   )rZ   r8   r“   r   s    r=   rE  z6WebSearchInterceptionLogger._normalize_responses_inputu  s3   € ä�h¤Ô$Ø#°Ñ9Ð:Ð:Ü�h¤Ô%Ü˜“>Ð!Øˆ	r<   rJ  c                 ó,  — t        | t        «      rt        j                  d| «       d| › �S t        | t        «      r0t        | «      dk(  r"| \  }}t        |t        «      r|S t        |«      S t        j                  dt        | «      «       t        | «      S )Nz=WebSearchInterception: Responses search failed with error: %srt   é   z7WebSearchInterception: Unexpected search result type %s)	rZ   r�   r   r–   r   r�   r8   rŽ   rz   )rJ  Ú
text_valuer»   s      r=   rC  z0WebSearchInterceptionLogger._extract_search_text}  sƒ   € ä�fœiÔ(Ü× Ñ Ð!`ÐbhÔiØ$ V HÐ-Ð-Ü�fœeÔ$¬¨V«¸Ò)9Ø"‰MˆJ˜Ü!+¨J¼Ô!<�:ÐQÄ#ÀjÃ/ÐQÜ×ÑÐVÔX\Ð]cÓXdÔeÜ�6‹{Ðr<   c                 ó„  — | j                  d|j                  dd«      «      }| j                  d«      }|rŠt        |t        «      rz|j                  d«      }|�gt        |t        t        f«      rQt        j                  |«      r<|dkD  r7||k  r2t        j                  |«      dz   }t        j                  d|||«       |}|S )záExtract max_tokens and validate against thinking.budget_tokens.

        Anthropic API requires ``max_tokens > thinking.budget_tokens``.
        If the constraint is violated, auto-adjust to ``budget_tokens + 1024``.
        Ú
max_tokensé   rä   Úbudget_tokensr   zvWebSearchInterception: max_tokens=%s <= thinking.budget_tokens=%s, adjusting to %s to satisfy Anthropic API constraint)
rš   rZ   rÍ   ÚintÚfloatÚmathÚisfiniteÚceilr   rŽ   )r  rd   r\  Úthinking_paramr^  Úadjusteds         r=   Ú_resolve_max_tokensz/WebSearchInterceptionLogger._resolve_max_tokensˆ  sÀ   € ð *×-Ñ-ØØ�J‰J�| TÓ*ó
ˆ
ð !0× 3Ñ 3°JÓ ?ˆÙœj¨¼Ô>Ø#1×#5Ñ#5°oÓ#FˆMàÐ)Ü˜}¬s´E¨lÔ;Ü—M‘M -Ô0Ø! AÒ%à Ò.Ü&*§i¡i°Ó&>ÀÑ&E�HÜ"×(Ñ(ðNà"Ø%Ø ôð "*�JØÐr<   c                 óŠ   — dh}| j                  «       D ��ci c]  \  }}|j                  d«      rŒ||vsŒ||“Œ! c}}S c c}}w )uÕ  Build kwargs for the follow-up call, excluding internal keys.

        ``litellm_logging_obj`` MUST be excluded so the follow-up call creates
        its own ``Logging`` instance via ``function_setup``.  Reusing the
        initial call's logging object triggers the dedup flag
        (``has_logged_async_success``) which silently prevents the initial
        call's spend from being recorded â€” the root cause of the
        SpendLog / AWS billing mismatch.
        r>  r<  )rF  rG  )rd   Ú_internal_keysrQ  rR  s       r=   Ú_prepare_followup_kwargsz4WebSearchInterceptionLogger._prepare_followup_kwargs«  sL   € ð "7Ð 7ˆà#Ÿ\™\›^÷
Ù�Q˜°1·<±<Ð@YÕ3ZÐ_`ÐhvÒ_vˆAˆq‰Dó
ð 	
ùó 
s   —?±?¶?rë   c	           	   ƒ   ó¢  K  — | j                  |||||||¬«      ƒ d{  –—† \  }	}
|	j                  €t        d«      ‚t        |«      }|j	                  |	j
                  «       |	j                  }|€$t        t        dz  |j                  dd«      «      }n|j                  dd«       |€ t        t        |j                  dd«      «      }t        j                  d||	j                  |	j                  xs |dœ|¤|	j                  ¤Žƒ d{  –—† }|j                  t        «      r%| j!                  ||
¬«      }| j#                  ||«      }|S 7 �Œ,7 ŒC­w)	ú?Legacy path: execute search + build patch + run follow-up call.r  Nú1WebSearchInterception: missing follow-up messagesr\  r]  )r\  r   rL   r	  r;   )r  r   r�   rÍ   Úupdater  r\  r
   r_  Úpoprš   Úanthropic_messagesÚacreaterL   rd   r0   r  r  )r]   rL   r   ré   rë   rÿ   r   r±   rd   r  r
  r  r\  r¦   r  s                  r=   r  z1WebSearchInterceptionLogger._execute_agentic_loop»  sv  è ø€ ð 37×2UÑ2UØØØ!Ø+Ø7aØ#Øð 3Vó 3
÷ -
Ñ)ˆÐ)ð ×!Ñ!Ð)ÜÐPÓQÐQä!%Ð&PÓ!QˆØ×Ñ˜}×<Ñ<Ô=Ø"×-Ñ-ˆ
ØÐÜœc D™j¨/×*=Ñ*=¸lÈDÓ*QÓR‰Jà×Ñ ¨dÔ3ØÐÜœc 6§:¡:¨l¸DÓ#AÓBˆJäL^×LfÑLfð M
Ø!Ø"×+Ñ+Ø×%Ñ%Ò.¨ñM
ð ð	M
ð
 ×"Ñ"ñM
÷ G
ˆð �:‰:Ô6Ô7Ø#'×#CÑ#CØ%Ø#5ð $Dó $ˆMð ×1Ñ1°(¸MÓJˆHàˆðQ-
ùð,G
ús#   ‚EžE
ŸC*EÄ	EÄ
AEÅEc           	   ƒ   ój  K  — g }|D ]‰  }	|	d   j                  d«      }
|
r9t        j                  d|
«       |j                  | j	                  |
|¬«      «       ŒRt        j                  d|	d   «       |j                  | j                  «       «       Œ‹ t        j                  dt        |«      «       t        j                  |dd	iŽƒ d
{  –—† }g }g }t        |«      D �]  \  }}t        |t        «      r=t        j                  d||«       |j                  d|› �«       |j                  d
«       ŒTt        |t        «      rqt        |«      dk(  rc|\  }}|j                  t        |t        «      rt        t        |«      n
t        |«      «       |j                  t        |t         «      r|nd
«       ŒÕt        j                  dt#        |«      |«       |j                  t        |«      «       |j                  d
«       �Œ" t%        j&                  |||¬«      \  }}||t        t(        |«      gz   }t+        |dd
«      xs |j                  dd«      }|}| j-                  ||«      }t        j                  d|«       |j/                  «       D ��ci c]  \  }}|dk7  sŒ||“Œ }}}| j1                  |«      }|�3d|j2                  j                  di «      i}|d   j                  d|«      }t        j                  d||t        |«      t        |«      «       t5        |||||¬«      }||fS 7 �Œ`c c}}w ­w)až  
        Execute litellm.search() and build follow-up request patch.

        Returns the patch alongside the parallel list of structured
        ``SearchResponse`` objects (one per tool_call, ``None`` when the
        search failed or the tool_call had no query). The caller uses these
        to optionally build Anthropic-native ``web_search_tool_result``
        content blocks for the final response.
        r|   ry   ú4WebSearchInterception: Queuing search for query='%s'rs   ú0WebSearchInterception: Tool call %s has no queryr{   ú:WebSearchInterception: Executing %s search(es) in parallelr3  TNú6WebSearchInterception: Search %s failed with error: %srt   rY  ú<WebSearchInterception: Unexpected result type %s at index %s)ré   rI  rë   Úlitellm_call_idr¯   z@WebSearchInterception: Using max_tokens=%s for follow-up requestr\  r@   rL   zbWebSearchInterception: Built anthropic request patch [call_id=%s model=%s messages=%d searches=%d])rL   r   r\  r  rd   )rš   r   rŽ   r›   r•   r@  r�   rA  rB  r!  rZ   r�   r–   r   r8   r
   r   rz   r   Útransform_responserÍ   rï   rf  rF  ri  Úmodel_call_detailsr   )r]   rL   r   ré   rë   rÿ   r   rd   rH  r  ry   rI  Úfinal_search_resultsr
  r  rJ  rZ  Ústructured_valueÚassistant_messageÚuser_messageÚfollow_up_messagesÚ_call_idrU  r\  rQ  rR  Ú"optional_params_without_max_tokensrT  Úagentic_viewÚpatchs                                 r=   r  z:WebSearchInterceptionLogger._build_anthropic_request_patchñ  sF  è ø€ ð* !ˆØ#ò 	HˆIØ˜gÑ&×*Ñ*¨7Ó3ˆEÙÜ×$Ñ$Ð%[Ð]bÔcØ×#Ñ# D×$8Ñ$8¸ÀvÐ$8Ó$NÕOä×$Ñ$Ð%WÐYbÐcgÑYhÔià×#Ñ# D×$DÑ$DÓ$FÕGð	Hô 	×ÑÐYÔ[^Ð_kÓ[lÔmÜ&-§n¡n°lÐ&[ÐVZÑ&[× [ˆð
 24ÐØACÐÜ" >Ó2ó 	0‰IˆAˆvÜ˜&¤)Ô,Ü×$Ñ$Ð%]Ð_`ÐbhÔiØ$×+Ñ+¨o¸f¸XÐ,FÔGØ"×)Ñ)¨$Õ/Ü˜F¤EÔ*¬s°6«{¸aÒ/?Ø/5Ñ,�
Ð,Ø$×+Ñ+ÄZÐPZÔ\_ÔE`¬D´°jÔ,AÔfiÐjtÓfuÔvØ"×)Ñ)¼jÐIYÔ[iÔ>jÑ*:ÐptÕuô ×$Ñ$Ð%cÔeiÐjpÓeqÐstÔuØ$×+Ñ+¬C°«KÔ8Ø"×)Ñ)¨$Ö/ð	0ô" +B×*TÑ*TØ!Ø/Ø+ô+
Ñ'Ð˜<ð %-Ð0AÄ4ÌÈlÓC[Ð/\Ñ$\Ðô " +Ð/@À$ÓGÒsÈ6Ï:É:ÐVgÐirÓKsˆàˆà ×4Ñ4Ð5_ÐagÓhˆ
ä×ÑÐ_ÐakÔlð H×MÑMÓO÷5
Ù�Q˜ÐSTÐXdÓSdˆAˆq‰Dð5
Ð*ñ 5
ð &*×%BÑ%BÀ6Ó%JÐàÐ"à% {×'EÑ'E×'IÑ'IÐJ_ÐacÓ'dð;ˆLð +Ð+@ÑA×EÑEÀgÈuÓUˆOÜ×ÑØpØØÜÐ"Ó#ÜÐ$Ó%ô	
ô /Ø!Ø'Ø!Ø>Ø&ô
ˆð Ð(Ð(Ð(ðC !\ûóR5
ùs,   ‚CL3Ã
L*ÃGL3ÊL-ÊL-Ê"B	L3Ì-L3c              ƒ   ó¼  K  — 	 	 ddl m} | j                  |¬«      }d}i }| j                  |¬«      }|�K| j                  ||¬«      ƒ d{  –—†  t        |j                  di «      xs i «      }|j                  d«      }|sd	}t        j                  d
|«       t        j                  d||«       | j                  |«      }|€dn| j                  ||¬«      }	|j                  «       D �
�ci c]  \  }
}|
dk7  r|�|
|“Œ }}
}|	€ t        j                  d||dœ|¤Žƒ d{  –—† n t        j                  d|||	dœ|¤Žƒ d{  –—† }t        j                   |«      }t        j                  d|t#        |«      «       ||fS # t        $ r t        j                  d«       d}Y �Œ—w xY w7 �Œ[c c}}
w 7 ŒŽ7 Œo# t$        $ r}t        j&                  d||«       ‚ d}~ww xY w­w)a	  
        Execute a single web search using router's search tools.

        Returns both the formatted text (fed back to the model in the follow-up
        call) and the structured ``SearchResponse`` (preserved so callers can
        build Anthropic-native ``web_search_tool_result`` blocks for clients
        that requested a native ``web_search_*`` tool). The structured value
        is None on the failure path so callers can still emit an empty result
        block rather than dropping the search entirely.
        r   )Ú
llm_routerz~WebSearchInterception: Could not import llm_router from proxy_server, falling back to direct litellm.asearch() with perplexityN)Úsearch_tool)r…  rd   rG   Úsearch_providerÚ
perplexityzXWebSearchInterception: No search tools configured in router, using default provider '%s'zDWebSearchInterception: Executing search for '%s' using provider '%s')Úuser_api_key_authrF   )ry   r†  )ry   r†  Úlitellm_metadataz>WebSearchInterception: Search completed for '%s', got %s charsz1WebSearchInterception: Search failed for '%s': %sr;   )Úlitellm.proxy.proxy_serverr„  ÚImportErrorr   rŽ   Ú_select_search_tool_from_routerÚ_selected_search_tool_nameÚ_authorize_search_toolrÍ   rš   Ú"_get_user_api_key_auth_from_kwargsÚ_build_search_request_metadatarF  r´   Úasearchr   Úformat_search_responser�   r�   r–   )r]   ry   rd   r„  r…  r†  Úsearch_litellm_paramsrF   rˆ  Úsearch_metadataÚkeyrY   Úsearch_kwargsrJ  r¢   r¤   s                   r=   r•   z+WebSearchInterceptionLogger._execute_searchV  sL  è ø€ ðA	ð"ÝAð "&×!EÑ!EÐQ[Ð!EÓ!\ˆKØ*.ˆOØ46Ð!Ø&*×&EÑ&EÐR]Ð&EÓ&^ÐØÐ&Ø×1Ñ1¸kÐRXÐ1ÓY×YÐYÜ(,¨[¯_©_Ð=MÈrÓ-RÒ-XÐVXÓ(YÐ%Ø"7×";Ñ";Ð<MÓ"N�ñ #Ø".�Ü×$Ñ$ØnØ#ôô
 × Ñ ØVÐX]Ð_nôð (,×'NÑ'NÈvÓ'VÐð %Ð,ñ à×8Ñ8Ø&7Ø%5ð 9ó ð ð #8×"=Ñ"=Ó"?÷$á�C˜ØÐ+Ò+°Ð0Að �U‘
ð$ˆMñ $ð #Ð*ô —o‘oÐd¨EÀ?ÑdÐVcÑd×dÐdä"Ÿ?™?ð ØØ$3Ø%4ñð $ñ	÷ ð ô )@×(VÑ(VÐW]Ó(^Ðä× Ñ ØPÐRWÔY\Ð]oÓYpôð & vÐ-Ð-øôu ò "Ü×$Ñ$ðOôð "“
ð"úð Zûó0$ð eøðùô ò 	Ü× Ñ Ð!TÐV[Ð]^Ô_Øûð	üsƒ   ‚G…E? ‹A F3 ÁF&ÁB F3 Ã,F)Ä  F3 Ä F/Ä! F3 ÅF1Å<F3 Å>GÅ? F#ÆF3 Æ"F#Æ#F3 Æ)F3 Æ1F3 Æ3	GÆ<GÇGÇGr…  c           
   ƒ   óf  K  — |j                  d«      }t        |t        «      r|sy | j                  |«      }|€y ddlm}m}m}  |||¬«      ƒ d {  –—†  dt        |dd «      i}|d   }	|	r=ddl	m
}
m}m}  ||	|
|t        |dd «      |¬«      ƒ d {  –—† } |||¬	«      ƒ d {  –—†  y y 7 ŒX7 Œ7 Œ
­w)
NrF   r   )Úcan_key_call_search_toolÚcan_team_call_search_toolÚget_team_object)rF   Úvalid_tokenrP   )Úprisma_clientÚproxy_logging_objÚuser_api_key_cacheÚparent_otel_span)rP   rœ  rž  rŸ  r�  )rF   Úteam_object)rš   rZ   r8   r�  Úlitellm.proxy.auth.auth_checksr˜  r™  rš  rï   rŠ  rœ  r�  rž  )r]   r…  rd   rF   rˆ  r˜  r™  rš  Ú	auth_viewrP   rœ  r�  rž  r   s                 r=   rŽ  z2WebSearchInterceptionLogger._authorize_search_tool¦  sò   è ø€ ð
 #.§/¡/Ð2DÓ"EÐÜÐ*¬CÔ0Ñ8HØà#'×#JÑ#JÈ6Ó#RÐØÐ$Ø÷	
ñ 	
ñ 'Ø-Ø)ô
÷ 	
ð 	
ð
 ,5´gÐ>OÐQZÐ\`Ó6aÐ*bˆ	Ø" 9Ñ-ˆÙ÷ñ ñ (7ØØ+Ø#5Ü!(Ð):Ð<NÐPTÓ!UØ"3ô(÷ "ˆKñ ,Ø!1Ø'ô÷ ñ ð ð	
øð"øðús6   ‚AB1ÁB+Á?B1ÂB-ÂB1Â$B/Â%B1Â-B1Â/B1rˆ  r+   c                 óZ   — ddl m} |j                  | ¬«      }i |¥|| j                  | dœ¥S )a  
        Spend-tracking metadata for the intercepted search, so its provider cost is logged
        and billed against the key/user/team that made the originating LLM request instead
        of being dropped by the proxy's spend hook for lack of an owner.
        r   )ÚLiteLLMProxyRequestSetup)Úuser_api_key_dict)Úmodel_groupÚuser_api_keyrˆ  )Ú$litellm.proxy.litellm_pre_call_utilsr¤  Ú'get_sanitized_user_information_from_keyÚapi_key)rˆ  rF   r¤  Úuser_api_key_metadatas       r=   r�  z:WebSearchInterceptionLogger._build_search_request_metadataÓ  sG   € õ 	Rð %×LÑLÐ_pÐLÓqð 	ð
Ø#ð
à+Ø-×5Ñ5Ø!2ò	
ð 	
r<   c                 óV   — | €y | j                  d«      }t        |t        «      r|r|S d S )NrF   )rš   rZ   r8   )r…  rF   s     r=   r�  z6WebSearchInterceptionLogger._selected_search_tool_nameé  s5   € àÐØØ"-§/¡/Ð2DÓ"EÐÜ#-Ð.>ÄÔ#DÑIYÐÐcÐ_cÐcr<   zUserAPIKeyAuth | Nonec                 óR  — | sy dD ]<  }| j                  |«      }t        |t        «      sŒ%|j                  d«      €Œ7|d   c S  | j                  d«      }t        |t        «      sy dD ]<  }|j                  |«      }t        |t        «      sŒ%|j                  d«      €Œ7|d   c S  y )N)r  r‰  rˆ  rG   rÌ   )rd   Úmetadata_keyr  rG   s       r=   r�  z>WebSearchInterceptionLogger._get_user_api_key_auth_from_kwargsð  s±   € áØà<ò 	5ˆLØ—z‘z ,Ó/ˆHÜ˜(¤DÕ)¨h¯l©lÐ;NÓ.OÑ.[ØÐ 3Ñ4Ò4ð	5ð
 !'§
¡
Ð+;Ó <ˆÜ˜.¬$Ô/Øà<ò 	5ˆLØ%×)Ñ)¨,Ó7ˆHÜ˜(¤DÕ)¨h¯l©lÐ;NÓ.OÑ.[ØÐ 3Ñ4Ò4ð	5ð
 r<   r„  z_SearchToolConfig | Nonec                 óx   — |�t        |d«      sy t        t        |d«      xs g «      }| j                  |d¬«      S )NÚsearch_toolsÚrouter)r°  Úsource)Úhasattrr“   rï   Ú_select_search_tool_from_list)r]   r„  r°  s      r=   rŒ  z;WebSearchInterceptionLogger._select_search_tool_from_router  sA   € ØÐ¤W¨Z¸Ô%HØÜ"¤7¨:°~Ó#FÒ#LÈ"ÓMˆØ×1Ñ1¸|ÐT\Ð1Ó]Ð]r<   r°  r²  c                 óð  — | j                   r |D �cg c]#  }|j                  d«      | j                   k(  sŒ"|‘Œ% }}|rO|d   j                  di «      xs i j                  d«      }t        j                  d| j                   ||«       |d   S t        j                  d| j                   |«       |rC|d   }|j                  di «      xs i j                  d«      }t        j                  d||«       |S y c c}w )NrF   r   rG   r†  zHWebSearchInterception: Found search tool '%s' from %s with provider '%s'zfWebSearchInterception: Search tool '%s' not found in %s, falling back to first available or perplexityzSWebSearchInterception: Using first available search tool from %s with provider '%s')rF   rš   r   rŽ   )r]   r°  r²  r¾   Úmatching_toolsr†  Ú
first_tools          r=   r´  z9WebSearchInterceptionLogger._select_search_tool_from_list  s  € ð
 × Ò Ø/;Öu t¸t¿x¹xÐHZÓ?[Ð_c×_tÑ_tÓ?tšdÐuˆNÐuÙØ#1°!Ñ#4×#8Ñ#8Ð9IÈ2Ó#NÒ#TÐRT×"YÑ"YÐZkÓ"l�Ü×$Ñ$Ø^Ø×)Ñ)ØØ#ô	ð & aÑ(Ð(Ü× Ñ ØxØ×%Ñ%Øôñ Ø ,¨Q¡ˆJØ)Ÿ~™~Ð.>ÀÓCÒIÀr×NÑNÐO`ÓaˆOÜ× Ñ ØeØØôð
 Ðàùò5 vs
   ‘#C3µC3râ   c	              ƒ   óv  K  — | j                  ||||||¬«      ƒ d{  –—† }	|	j                  €t        d«      ‚t        |«      }
|
j	                  |	j
                  «       |
j                  dd«       t        j                  d|	j                  xs ||	j                  dœ|
¤|	j                  ¤Žƒ d{  –—† S 7 Œ—7 Œ­w)rk  r.  Nrl  rÐ   )rL   r   r;   )r/  r   r�   rÍ   rm  r  rn  r´   r=  rL   rd   )r]   rL   r   ré   r  r   r±   rd   râ   r  Úparamss              r=   r+  zAWebSearchInterceptionLogger._execute_chat_completion_agentic_loop-  sÒ   è ø€ ð &*×%NÑ%NØØØ!Ø+ØØ+ð &Oó &
÷  
ˆð ×!Ñ!Ð)ÜÐPÓQÐQÜ˜_Ó-ˆØ�‰�m×3Ñ3Ô4Ø�
‰
�= $Ô'Ü×(Ñ(ð 
Ø×%Ñ%Ò.¨Ø"×+Ñ+ñ
ð ð
ð ×"Ñ"ñ	
÷ 
ð 	
ð 
øð
ús"   ‚B9�B5žBB9Â0B7Â1B9Â7B9c              ƒ   ó,  K  — g }|D ]û  }d}	d|v r(t        |d   t        «      r|d   j                  d«      }	nLd|v rH|d   }
t        |
t        «      r3|
j                  di «      }t        |t        «      r|j                  d«      }	|	r9t        j                  d|	«       |j                  | j                  |	|¬«      «       Œ¸t        j                  d|j                  d	«      «       |j                  | j                  «       «       Œý t        j                  d
t        |«      «       t        j                  |ddiŽƒ d{  –—† }g }t        |«      D ]Ù  \  }}t        |t        «      r,t        j                  d||«       |j                  d|› �«       ŒBt        |t        «      rNt        |«      dk(  r@|\  }}|j                  t        |t        «      rt!        t        |«      n
t        |«      «       Œ t        j                  dt#        |«      |«       |j                  t        |«      «       ŒÛ t%        j&                  |||¬«      \  }}|dk(  r||gz   t!        t(        t           |«      z   }n||t!        t        |«      gz   }t        j                  d«       t        j                  dt        |«      «       h d£}|j+                  «       D ��ci c]  \  }}|j-                  d«      rŒ||vsŒ||“Œ! }}}|}d|v r!|d   }|j-                  |«      sd|vr|› d|› �}t        j                  d|t        |«      «       |j                  d«      }|j+                  «       D ��ci c]  \  }}|dvr||“Œ }}}|�||d<   t/        ||||¬«      S 7 �ŒIc c}}w c c}}w ­w)z?Execute litellm.search() and build chat-completion rerun patch.Nr|   ry   rË   r6  rr  rs   rs  r{   rt  r3  Tru  rt   rY  rv  )ré   rI  râ   rù   zSWebSearchInterception: Making follow-up chat completion request with search resultsz3WebSearchInterception: Follow-up messages count: %s>   r=  r9  r:  r;  rK   r>  r<  r<  rK   r?  zOWebSearchInterception: Built chat completion request patch model=%s messages=%drc   >   rc   Ú
extra_bodyrÐ   r9  r:  r;  )rL   r   r  rd   )rZ   rÍ   rš   r   rŽ   r›   r•   r@  r�   rA  rB  r!  r�   r–   r   r8   r
   rz   r   rx  r“   rF  rG  r   )r]   rL   r   ré   r  rd   râ   rH  r  ry   ÚfuncÚargsrI  rz  r  rJ  rZ  r»   r|  Útool_messages_or_userr~  Úinternal_paramsrQ  rR  rT  rU  rK   rP  rS  s                                r=   r/  z@WebSearchInterceptionLogger._build_chat_completion_request_patchM  s¾  è ø€ ð !ˆØ#ò 	HˆIàˆEØ˜)Ñ#¬
°9¸WÑ3EÄtÔ(LØ! 'Ñ*×.Ñ.¨wÓ7‘Ø˜yÑ(Ø  Ñ,�Ü˜d¤DÔ)ØŸ8™8 K°Ó4�DÜ! $¬Ô-Ø $§¡¨Ó 1˜áÜ×$Ñ$Ð%[Ð]bÔcØ×#Ñ# D×$8Ñ$8¸ÀvÐ$8Ó$NÕOä×$Ñ$Ð%WÐYb×YfÑYfÐgkÓYlÔmà×#Ñ# D×$DÑ$DÓ$FÕGð%	Hô* 	×ÑÐYÔ[^Ð_kÓ[lÔmÜ&-§n¡n°lÐ&[ÐVZÑ&[× [ˆð 24ÐÜ" >Ó2ò 		9‰IˆAˆvÜ˜&¤)Ô,Ü×$Ñ$Ð%]Ð_`ÐbhÔiØ$×+Ñ+¨o¸f¸XÐ,FÕGÜ˜F¤EÔ*¬s°6«{¸aÒ/?Ø &‘�
˜AØ$×+Ñ+ÄZÐPZÔ\_ÔE`¬D´°jÔ,AÔfiÐjtÓfuÕvä×$Ñ$Ð%cÔeiÐjpÓeqÐstÔuØ$×+Ñ+¬C°«KÕ8ð		9ô $×6Ñ6Ø!Ø/Ø+ô
ñ	
ØØ!ð ˜hÒ&Ø!)Ð->Ð,?Ñ!?Ä$ÄtÌDÁzÐShÓBiÑ!iÑð "*Ø!Ü”TÐ0Ó1ð-ñ "Ðô
 	×ÑÐrÔsÜ×ÑÐRÔTWÐXjÓTkÔlò"
ˆð $Ÿ\™\›^÷&
Ù�Q˜°1·<±<Ð@YÕ3ZÐ_`ÐhwÒ_wˆAˆq‰Dð&
Ðñ &
ð  ˆØ  FÑ*Ø)/Ð0EÑ)FÐØ×#Ñ#Ð$7Ô8¸SÈÑ=MØ%8Ð$9¸¸5¸'Ð"B�ä×ÑØ]ØÜÐ"Ó#ô	
ð -×0Ñ0°Ó9ˆð (×-Ñ-Ó/÷(
á��1Øðñð ˆq‰Dð(
Ðñ (
ð Ð"Ø-8Ð! 'Ñ*ä&Ø!Ø'Ø1Ø&ô	
ð 	
ðg !\ûód&
ùó"(
ùs>   ‚D:NÄ<NÄ=FNË	NË#NË(NË-A.NÍNÍ,NÎNc              ƒ   ó   K  — y­w)z<Create an empty search result for tool calls without queries)zNo search query providedNr;   )r]   s    r=   r@  z7WebSearchInterceptionLogger._create_empty_search_resultÊ  s   è ø€ ð 0ùs   ‚Úlitellm_settingsÚcallback_specific_paramsc                 ó¦   — i }d| v rd| d   i}|d   }n*d|v r&t        |d   t        «      rt        t        |d   «      }t        j                  |«      S )aÒ  
        Static method to initialize WebSearchInterceptionLogger from proxy config.

        Used in callback_utils.py to simplify initialization logic.

        Args:
            litellm_settings: Dictionary containing litellm_settings from proxy_config.yaml
            callback_specific_params: Dictionary containing callback-specific parameters

        Returns:
            Configured WebSearchInterceptionLogger instance

        Example:
            From callback_utils.py:
                websearch_obj = WebSearchInterceptionLogger.initialize_from_proxy_config(
                    litellm_settings=litellm_settings,
                    callback_specific_params=callback_specific_params
                )
        rC   Úwebsearch_interception)rZ   rÍ   r
   r"   rR   rÉ   )rÁ  rÂ  Úwebsearch_paramsÚsettings_views       r=   Úinitialize_from_proxy_configz8WebSearchInterceptionLogger.initialize_from_proxy_configÐ  s}   € ð2 9;ÐØ*Ð.>Ñ>à/Ð1AÐBaÑ1bð<ˆMð  -Ð-LÑMÑØ%Ð)AÑAÄjØ$Ð%=Ñ>ÄôG
ô  $Ü+Ø(Ð)AÑBó Ðô +×;Ñ;Ð<LÓMÐMr<   )NNNri   )rù   )@r5   r6   r7   rM   r“   r&   r8   r_  rW   Ústaticmethodr9   r[   rÍ   r   r§   r   r%   rÀ   r   r¸   Úclassmethodr"   rÉ   rÏ   rÓ   rÚ   Úboolr   rö   rì   rí   r  r   r  r  r   r  r  r  r  r,  r  r  r   r1  rE  rC  rf  ri  r  r  r•   rŽ  r�  r�  r�  rŒ  rE   r´  r+  r/  r@  rÇ  Ú__classcell__)r_   s   @r=   rR   rR   p   s$  ø„ ñ	ð >BØ'+Ø(,ñ	,à ¨sÑ 2Ñ3°dÑ:ð,ð  ™*ð,ð  ™:õ	,ð8 ðw¸ð wÀ3ÈÁ:ò wó ðwð /3ñJàðJð �t‘*ðJð �D‰z˜DÑ ð	Jð
 ! 4™ZðJð ˜˜V˜Ñ$ tÑ+ðJð 
ˆc�6ˆkÑ	˜TÑ	!óJðXLØ˜3 ˜8‘nðLØ1:¸TÑ1AðLà	ˆc�6ˆkÑ	˜TÑ	!óLð\ Ø˜c 6˜kÑ*ð Ø3;¸DÀÀfÀÑ<MÑ3Nð à	ˆc�6ˆkÑ	˜TÑ	!ó ð, ð,
Ð&Að ,
ÐFcò ,
ó ð,
ð\ ð ˜  f Ñ-ð  °&ò  ó ð ð ðE°6ð EÈHÐU\Ð]`ÐbhÐ]hÑUiÑLjð EÐouò Eó ðEð"S°#ð SÀÀdÁð SÐUYð SÐ^bÐeiÑ^ió Sðjn àðn ð ðn ð �t‘*ð	n ð
 �D‰z˜DÑ ðn ð ðn ð !ðn ð ðn ð 
ˆt�TˆzÑ	ón ð`: àð: ð ð: ð �t‘*ð	: ð
 �D‰z˜DÑ ð: ð ð: ð !ð: ð ð: ð 
ˆt�TˆzÑ	ó: ðx0 àð0 ð ð0 ð �t‘*ð	0 ð
 �D‰z˜DÑ ð0 ð ð0 ð !ð0 ð ð0 ð 
ˆt�TˆzÑ	ó0 ðd 
àð 
ð ð 
ð �t‘*ð	 
ð
 ð 
ð -Qð 
ð 59ð 
ð 0ð 
ð ð 
ð ð 
ð 
=ó 
ðDC
àðC
ð ðC
ð �t‘*ð	C
ð
 ðC
ð -QðC
ð 59ðC
ð 0ðC
ð ðC
ð ðC
ð 
óC
ðJCàðCð ðCð ð	Cð
 
óCð0 ð
Ø˜‘Jð
à  °$Ñ!6Ñ7ð
ð 
ˆw�s˜F�{Ñ# SÐ(Ñ	)ò
ó ð
ð* ð7 G¨C°¨KÑ$8ð 7¸Sò 7ó ð7ð ð
Øð
à'¨$Ñ.ð
ð 
ˆw�s˜F�{Ñ# W¨S°&¨[Ñ%9Ð9Ñ	:ò
ó ð
ð ð¨ð ¸HÀWÈSÐRXÈ[ÑEYÑ<Zð Ð_bò ó ðð(!
àð!
ð ð!
ð �t‘*ð	!
ð
 ð!
ð ð!
ð 0ð!
ð ð!
ð ð!
ð 
/ó!
ðF
àð
ð ð
ð �t‘*ð	
ð
 ð
ð ð
ð 0ð
ð ð
ð ð
ð 
ó
ð6
àð
ð ð
ð �t‘*ð	
ð
 ð
ð ð
ð 0ð
ð ð
ð ð
ð 
ó
ð2Q
àðQ
ð ˜˜T™
Ñ"ðQ
ð ˜‘Jð	Q
ð
 ðQ
ð ðQ
ð 
!óQ
ðf ð¨S°4¸±:Ñ-=ð À$ÀtÁ*ò ó ðð ð Vð °ò ó ðð ð Øð àð ð 
ò ó ð ðD ð
¨ð 
°$ò 
ó ð
ð4àð4ð �t‘*ð4ð ˜‘Jð	4ð
 ˜d™ð4ð 59ð4ð 0ð4ð ð4ð ð4ð 
=ó4ðlc)àðc)ð �t‘*ðc)ð ˜‘Jð	c)ð
 ˜d™ðc)ð 59ðc)ð 0ðc)ð ðc)ð 
Ð&¨¨^¸dÑ-BÑ(CÐCÑ	Dóc)ðL AEñNØðNØ")¨#¨v¨+Ñ"6¸Ñ"=ðNà	ˆs�N TÑ)Ð)Ñ	*óNð`+à˜S &˜[Ñ)ð+ð ˜˜V˜Ñ$ tÑ+ð+ð 
ó	+ðZ ð
Ø+ð
à ™*ð
ð 
��f�Ñ	ò
ó ð
ð* ðd°¸¸V¸Ñ0DÀtÑ0Kð dÐPSÐVZÑPZò dó ðdð ð°7¸3À¸;Ñ3GÈ$Ñ3Nð ÐSjò ó ðð(^¸&ð ^ÐE_ó ^ð àÐ,Ñ-ð ð ð ð 
$ó	 ðV  (ñ
àð
ð �t‘*ð
ð ˜‘Jð	
ð
 ð
ð 0ð
ð ð
ð ð
ð ð
ð 
/ó
ðN  (ñ{
àð{
ð �t‘*ð{
ð ˜‘Jð	{
ð
 ð{
ð ð{
ð ð{
ð 
!ó{
ðz0à	ˆs�N TÑ)Ð)Ñ	*ó0ð ð'NØ! #Ð'BÐ"BÑCð'Nà")¨#¨v¨+Ñ"6ð'Nð 
'ò'Nó ô'Nr<   rR   )OrM   rA  ra  r—   Úcollections.abcr   r   r   Útypingr   r   r   r	   r
   Útyping_extensionsr   r´   Úlitellm._loggingr   Úlitellm.anthropic_interfacer   ro  Úlitellm.constantsr   Ú"litellm.integrations.custom_loggerr   Ú1litellm.integrations.websearch_interception.toolsr   r   r   r   r   r   r   Ú:litellm.integrations.websearch_interception.transformationr   Ú0litellm.litellm_core_utils.agentic_loop_settingsr   Ú+litellm.llms.base_llm.search.transformationr   Ú(litellm.types.integrations.custom_loggerr   r   r   r   Ú1litellm.types.integrations.websearch_interceptionr    r!   r"   Úlitellm.types.llms.openair#   Úlitellm.types.utilsr$   r%   r&   r'   Úlitellm.utilsr(   Ú*litellm.litellm_core_utils.litellm_loggingr)   ÚLiteLLMLoggingObjÚ7litellm.llms.base_llm.anthropic_messages.transformationr*   Úlitellm.proxy._typesr+   Ú8litellm.types.llms.anthropic_messages.anthropic_responser,   r-   r.   r0   r:   r2   r4   r?   rB   rE   rJ   rO   rR   r;   r<   r=   ú<module>rá     s  ðòó Û Û ß <Ñ <ß =Õ =å &ã Ý +Ý FÝ :Ý ;÷÷ ñ õõõ G÷ó ÷ñ õ
 7÷ó õ 0áÝWõõ 4õõ 2Ý1ð +WÐ   %Ó Vð /HÐ $ eÓ GôC˜	ô Cô+˜Yô +ô?˜Yô ?ô0˜	¨õ 0ô
˜Iô ô"�Iô "ôHN ,õ HNr<   