From 32cb6f0cd91adfb5554be251490b9b5d5ea60a19 Mon Sep 17 00:00:00 2001 From: Jonathan Barazany Date: Fri, 20 Mar 2026 01:07:20 +0200 Subject: [PATCH] fix: guard short-circuit against providers with native agentic loop MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Skip short-circuit for providers that have a BaseAnthropicMessagesConfig (bedrock, vertex_ai, azure_ai, anthropic) — they use the agentic loop which includes a follow-up LLM synthesis step. Short-circuiting would return raw search text instead of an LLM-synthesized answer. - Add fallback to litellm.get_llm_provider() for custom_llm_provider derivation when litellm_params is overwritten by kwargs. - Add test for bedrock guard. Addresses Greptile review comments #3 and #4. --- .../websearch_interception/handler.py | 23 +++++++++++++++++++ .../messages/handler.py | 9 +++++++- .../test_websearch_short_circuit.py | 23 +++++++++++++++++++ 3 files changed, 54 insertions(+), 1 deletion(-) diff --git a/litellm/integrations/websearch_interception/handler.py b/litellm/integrations/websearch_interception/handler.py index b557d8c0e77..34396849e24 100644 --- a/litellm/integrations/websearch_interception/handler.py +++ b/litellm/integrations/websearch_interception/handler.py @@ -29,6 +29,7 @@ from litellm.types.integrations.websearch_interception import ( WebSearchInterceptionConfig, ) from litellm.types.utils import LlmProviders +from litellm.utils import ProviderConfigManager class WebSearchInterceptionLogger(CustomLogger): @@ -106,6 +107,28 @@ class WebSearchInterceptionLogger(CustomLogger): ): return None + # Only short-circuit for providers without native Anthropic Messages + # support. Providers that have a BaseAnthropicMessagesConfig (bedrock, + # vertex_ai, azure_ai, anthropic) already use the agentic loop, which + # includes a follow-up LLM call to synthesize the answer from search + # results. Short-circuiting those would skip that synthesis step and + # return raw search text — a regression for existing users. + try: + provider_enum = LlmProviders(provider_str) + anthropic_config = ( + ProviderConfigManager.get_provider_anthropic_messages_config( + model=model, provider=provider_enum + ) + ) + if anthropic_config is not None: + verbose_logger.debug( + f"WebSearchInterception: Skipping short-circuit for {provider_str} " + "(provider has native Anthropic Messages support, using agentic loop)" + ) + return None + except (ValueError, Exception): + pass # unknown provider enum → safe to short-circuit + # All tools must be web search tools if not all(is_web_search_tool(t) for t in tools): return None diff --git a/litellm/llms/anthropic/experimental_pass_through/messages/handler.py b/litellm/llms/anthropic/experimental_pass_through/messages/handler.py index dcd9214cf8c..dae2b5da1f8 100644 --- a/litellm/llms/anthropic/experimental_pass_through/messages/handler.py +++ b/litellm/llms/anthropic/experimental_pass_through/messages/handler.py @@ -205,11 +205,18 @@ async def anthropic_messages( # Extract modified parameters tools = request_kwargs.pop("tools", tools) stream = request_kwargs.pop("stream", stream) - # Propagate the provider derived inside pre-request hooks, if not already set + # Propagate the provider derived inside pre-request hooks, if not already set. + # The litellm_params dict may have been overwritten by **kwargs in + # _execute_pre_request_hooks, so fall back to get_llm_provider() if needed. if not custom_llm_provider: custom_llm_provider = request_kwargs.get("litellm_params", {}).get( "custom_llm_provider" ) + if not custom_llm_provider: + try: + _, custom_llm_provider, _, _ = litellm.get_llm_provider(model=model) + except Exception: + pass # Remove litellm_params from kwargs (only needed for hooks) request_kwargs.pop("litellm_params", None) # Merge back any other modifications diff --git a/tests/test_litellm/integrations/websearch_interception/test_websearch_short_circuit.py b/tests/test_litellm/integrations/websearch_interception/test_websearch_short_circuit.py index cb90b254e40..82c1c9839e7 100644 --- a/tests/test_litellm/integrations/websearch_interception/test_websearch_short_circuit.py +++ b/tests/test_litellm/integrations/websearch_interception/test_websearch_short_circuit.py @@ -114,6 +114,29 @@ class TestTryShortCircuitSearch: assert result is None + @pytest.mark.asyncio + async def test_does_not_short_circuit_bedrock(self): + """Bedrock has native agentic loop support → NOT short-circuited. + + Providers with a BaseAnthropicMessagesConfig (bedrock, vertex_ai, etc.) + use the agentic loop which includes a follow-up LLM synthesis step. + The short-circuit must not fire for them. + """ + logger = WebSearchInterceptionLogger( + enabled_providers=["bedrock", "github_copilot"] + ) + + result = await logger.try_short_circuit_search( + model="bedrock/us.anthropic.claude-sonnet-4-5-20250929-v1:0", + messages=[{"role": "user", "content": "Search for something"}], + tools=[ + {"type": "web_search_20250305", "name": "web_search", "max_uses": 8} + ], + custom_llm_provider="bedrock", + ) + + assert result is None + @pytest.mark.asyncio async def test_does_not_short_circuit_no_messages(self): """Empty messages → NOT short-circuited"""