From b94efc33991ed8a6056e3a5e198e07ab7f70571b Mon Sep 17 00:00:00 2001 From: agustin18 Date: Sun, 27 Sep 2026 19:14:50 +0000 Subject: [PATCH 1/6] fix(websearch): strip Claude Code instructional prefix in short-circuit search Signed-off-by: agustin18 --- .../websearch_interception/handler.py | 26 ++++++++- .../test_websearch_short_circuit.py | 58 +++++++++++++++++++ 2 files changed, 83 insertions(+), 1 deletion(-) diff --git a/litellm/integrations/websearch_interception/handler.py b/litellm/integrations/websearch_interception/handler.py index 6ebf485d717..6a4929a6b22 100644 --- a/litellm/integrations/websearch_interception/handler.py +++ b/litellm/integrations/websearch_interception/handler.py @@ -8,6 +8,7 @@ server-side using litellm router's search tools. import asyncio import math +import re import uuid from collections.abc import AsyncIterator, Mapping, Sequence from dataclasses import dataclass @@ -92,6 +93,11 @@ WEBSEARCH_NATIVE_BLOCKS_METADATA_KEY: Final = "websearch_native_blocks" _RESPONSE_CONTENT_FIELD: Final = "content" +_CLAUDE_CODE_SEARCH_PREFIX_RE: Final = re.compile( + r"^\s*(?:Perform\s+a\s+)?(?:web\s+)?search\s+for\s+(?:the\s+)?query:\s*", + re.IGNORECASE, +) + _ResponseT: Final = TypeVar("_ResponseT") @@ -288,6 +294,20 @@ class WebSearchInterceptionLogger(CustomLogger): """ return validated_max_agentic_loops(max_agentic_loops, field="websearch_interception_params.max_agentic_loops") + @classmethod + def _extract_short_circuit_query(cls, raw_message: str) -> str: + """Extract the intended search terms from a short-circuit user message. + + Clients such as Claude Code format standalone WebSearch requests with an + instructional wrapper (e.g. 'Perform a web search for the query: '). + Strip known instructional prefixes so the search backend receives only + the intended search terms rather than query wrapper keywords. + """ + cleaned = _CLAUDE_CODE_SEARCH_PREFIX_RE.sub("", raw_message).strip() + if (cleaned.startswith('"') and cleaned.endswith('"')) or (cleaned.startswith("'") and cleaned.endswith("'")): + cleaned = cleaned[1:-1].strip() + return cleaned if cleaned else raw_message.strip() + async def try_short_circuit_search( self, model: str, @@ -358,7 +378,11 @@ class WebSearchInterceptionLogger(CustomLogger): get_last_user_message, ) - query: Final = get_last_user_message(cast(list[AllMessageValues], messages)) + raw_query: Final = get_last_user_message(cast(list[AllMessageValues], messages)) + if not raw_query: + return None + + query: Final = self._extract_short_circuit_query(raw_query) if not query: return None diff --git a/tests/unit/integrations/websearch_interception/test_websearch_short_circuit.py b/tests/unit/integrations/websearch_interception/test_websearch_short_circuit.py index 8294add60c7..2616a81ce96 100644 --- a/tests/unit/integrations/websearch_interception/test_websearch_short_circuit.py +++ b/tests/unit/integrations/websearch_interception/test_websearch_short_circuit.py @@ -392,3 +392,61 @@ class TestShortCircuitEntryPoint: assert result is not None text_block = next(b for b in result["content"] if b["type"] == "text") assert text_block["text"] == "results" + + @pytest.mark.asyncio + @pytest.mark.parametrize( + "raw_prompt,expected_query", + [ + ( + "Perform a web search for the query: LiteLLM latest version release", + "LiteLLM latest version release", + ), + ( + 'Perform a web search for the query: "who is the maintainer of litellm"', + "who is the maintainer of litellm", + ), + ( + " perform a web search for the query: fastapi SSE streaming ", + "fastapi SSE streaming", + ), + ( + "Search for the query: python 3.13 changelog", + "python 3.13 changelog", + ), + ( + "Search for Claude Code releases", + "Search for Claude Code releases", + ), + ], + ) + async def test_short_circuits_strips_claude_code_instructional_prefix( + self, raw_prompt, expected_query + ): + """Claude Code wraps standalone searches in 'Perform a web search for the query: ...'. + The short-circuit path must extract only the actual query terms so search backends + receive the intended query rather than instructional prefix words. + """ + logger = WebSearchInterceptionLogger(enabled_providers=["github_copilot"]) + + with patch.object( + logger, "_execute_search", new_callable=AsyncMock + ) as mock_search: + mock_search.return_value = ("Results", None) + + result = await logger.try_short_circuit_search( + model="github_copilot/claude-sonnet-4", + messages=[{"role": "user", "content": raw_prompt}], + tools=[ + {"type": "web_search_20250305", "name": "web_search", "max_uses": 8} + ], + custom_llm_provider="github_copilot", + ) + + assert result is not None + mock_search.assert_called_once_with(expected_query) + tool_use_block = next( + (b for b in result["content"] if b["type"] == "server_tool_use"), None + ) + if tool_use_block is not None: + assert tool_use_block["input"]["query"] == expected_query + From c65292e69982ce47b1300ceacbb7244109c0182c Mon Sep 17 00:00:00 2001 From: agustin18 Date: Sun, 27 Sep 2026 19:22:14 +0000 Subject: [PATCH 2/6] fix(websearch): preserve quotes for unwrapped search queries Signed-off-by: agustin18 --- litellm/integrations/websearch_interception/handler.py | 7 +++++-- .../test_websearch_short_circuit.py | 8 ++++++++ 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/litellm/integrations/websearch_interception/handler.py b/litellm/integrations/websearch_interception/handler.py index 6a4929a6b22..cf46f5827f0 100644 --- a/litellm/integrations/websearch_interception/handler.py +++ b/litellm/integrations/websearch_interception/handler.py @@ -303,8 +303,11 @@ class WebSearchInterceptionLogger(CustomLogger): Strip known instructional prefixes so the search backend receives only the intended search terms rather than query wrapper keywords. """ - cleaned = _CLAUDE_CODE_SEARCH_PREFIX_RE.sub("", raw_message).strip() - if (cleaned.startswith('"') and cleaned.endswith('"')) or (cleaned.startswith("'") and cleaned.endswith("'")): + prefix = _CLAUDE_CODE_SEARCH_PREFIX_RE.match(raw_message) + cleaned = (raw_message[prefix.end() :] if prefix else raw_message).strip() + if prefix and ( + (cleaned.startswith('"') and cleaned.endswith('"')) or (cleaned.startswith("'") and cleaned.endswith("'")) + ): cleaned = cleaned[1:-1].strip() return cleaned if cleaned else raw_message.strip() diff --git a/tests/unit/integrations/websearch_interception/test_websearch_short_circuit.py b/tests/unit/integrations/websearch_interception/test_websearch_short_circuit.py index 2616a81ce96..81d3aa0b26f 100644 --- a/tests/unit/integrations/websearch_interception/test_websearch_short_circuit.py +++ b/tests/unit/integrations/websearch_interception/test_websearch_short_circuit.py @@ -417,6 +417,14 @@ class TestShortCircuitEntryPoint: "Search for Claude Code releases", "Search for Claude Code releases", ), + ( + '"LiteLLM latest version release"', + '"LiteLLM latest version release"', + ), + ( + "'fastapi SSE streaming'", + "'fastapi SSE streaming'", + ), ], ) async def test_short_circuits_strips_claude_code_instructional_prefix( From e542343994ecffadf2b50cdf598d7367f7bfcd82 Mon Sep 17 00:00:00 2001 From: agustin18 Date: Sun, 27 Sep 2026 19:33:24 +0000 Subject: [PATCH 3/6] test(websearch): replace mock with pure unit tests and cover empty queries Signed-off-by: agustin18 --- .../websearch_interception/handler.py | 3 +- .../test_websearch_short_circuit.py | 207 +++++++++--------- 2 files changed, 101 insertions(+), 109 deletions(-) diff --git a/litellm/integrations/websearch_interception/handler.py b/litellm/integrations/websearch_interception/handler.py index cf46f5827f0..c534115181a 100644 --- a/litellm/integrations/websearch_interception/handler.py +++ b/litellm/integrations/websearch_interception/handler.py @@ -309,7 +309,8 @@ class WebSearchInterceptionLogger(CustomLogger): (cleaned.startswith('"') and cleaned.endswith('"')) or (cleaned.startswith("'") and cleaned.endswith("'")) ): cleaned = cleaned[1:-1].strip() - return cleaned if cleaned else raw_message.strip() + return cleaned if (cleaned or prefix) else raw_message.strip() + async def try_short_circuit_search( self, diff --git a/tests/unit/integrations/websearch_interception/test_websearch_short_circuit.py b/tests/unit/integrations/websearch_interception/test_websearch_short_circuit.py index 81d3aa0b26f..3f17d1b8aad 100644 --- a/tests/unit/integrations/websearch_interception/test_websearch_short_circuit.py +++ b/tests/unit/integrations/websearch_interception/test_websearch_short_circuit.py @@ -26,9 +26,7 @@ class TestTryShortCircuitSearch: """Single web_search_20250305 tool → short-circuit fires""" logger = WebSearchInterceptionLogger(enabled_providers=["github_copilot"]) - with patch.object( - logger, "_execute_search", new_callable=AsyncMock - ) as mock_search: + with patch.object(logger, "_execute_search", new_callable=AsyncMock) as mock_search: mock_search.return_value = ( "Title: Result\nURL: https://example.com\nSnippet: test", None, @@ -36,12 +34,8 @@ class TestTryShortCircuitSearch: result = await logger.try_short_circuit_search( model="github_copilot/claude-sonnet-4", - messages=[ - {"role": "user", "content": "Search for Claude Code releases"} - ], - tools=[ - {"type": "web_search_20250305", "name": "web_search", "max_uses": 8} - ], + messages=[{"role": "user", "content": "Search for Claude Code releases"}], + tools=[{"type": "web_search_20250305", "name": "web_search", "max_uses": 8}], custom_llm_provider="github_copilot", ) @@ -113,9 +107,7 @@ class TestTryShortCircuitSearch: result = await logger.try_short_circuit_search( model="github_copilot/claude-sonnet-4", messages=[{"role": "user", "content": "Search for something"}], - tools=[ - {"type": "web_search_20250305", "name": "web_search", "max_uses": 8} - ], + tools=[{"type": "web_search_20250305", "name": "web_search", "max_uses": 8}], custom_llm_provider="github_copilot", ) @@ -129,16 +121,12 @@ class TestTryShortCircuitSearch: 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"] - ) + 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} - ], + tools=[{"type": "web_search_20250305", "name": "web_search", "max_uses": 8}], custom_llm_provider="bedrock", ) @@ -152,30 +140,49 @@ class TestTryShortCircuitSearch: result = await logger.try_short_circuit_search( model="github_copilot/claude-sonnet-4", messages=[], - tools=[ - {"type": "web_search_20250305", "name": "web_search", "max_uses": 8} - ], + tools=[{"type": "web_search_20250305", "name": "web_search", "max_uses": 8}], custom_llm_provider="github_copilot", ) assert result is None + @pytest.mark.asyncio + @pytest.mark.parametrize( + "empty_prompt", + [ + " ", + "Perform a web search for the query: ", + 'Perform a web search for the query: ""', + ], + ) + async def test_does_not_short_circuit_empty_or_whitespace_user_message( + self, empty_prompt: str + ): + """User message that is whitespace or empty query → returns None without executing search.""" + logger = WebSearchInterceptionLogger(enabled_providers=["github_copilot"]) + + result = await logger.try_short_circuit_search( + model="github_copilot/claude-sonnet-4", + messages=[{"role": "user", "content": empty_prompt}], + tools=[{"type": "web_search_20250305", "name": "web_search", "max_uses": 8}], + custom_llm_provider="github_copilot", + ) + + assert result is None + + @pytest.mark.asyncio async def test_search_failure_returns_error_text(self): """Search failure → response with error message, not exception""" logger = WebSearchInterceptionLogger(enabled_providers=["github_copilot"]) - with patch.object( - logger, "_execute_search", new_callable=AsyncMock - ) as mock_search: + with patch.object(logger, "_execute_search", new_callable=AsyncMock) as mock_search: mock_search.side_effect = RuntimeError("Tavily API error") result = await logger.try_short_circuit_search( model="github_copilot/claude-sonnet-4", messages=[{"role": "user", "content": "Search for something"}], - tools=[ - {"type": "web_search_20250305", "name": "web_search", "max_uses": 8} - ], + tools=[{"type": "web_search_20250305", "name": "web_search", "max_uses": 8}], custom_llm_provider="github_copilot", ) @@ -188,9 +195,7 @@ class TestTryShortCircuitSearch: """Synthetic response has all required AnthropicMessagesResponse fields""" logger = WebSearchInterceptionLogger(enabled_providers=["github_copilot"]) - with patch.object( - logger, "_execute_search", new_callable=AsyncMock - ) as mock_search: + with patch.object(logger, "_execute_search", new_callable=AsyncMock) as mock_search: mock_search.return_value = ("search results here", None) result = await logger.try_short_circuit_search( @@ -218,6 +223,66 @@ class TestTryShortCircuitSearch: # --------------------------------------------------------------------------- +class TestQueryExtraction: + """Direct unit tests for query extraction without application test doubles.""" + + @pytest.mark.parametrize( + "raw_prompt,expected_query", + [ + ( + "Perform a web search for the query: LiteLLM latest version release", + "LiteLLM latest version release", + ), + ( + 'Perform a web search for the query: "who is the maintainer of litellm"', + "who is the maintainer of litellm", + ), + ( + " perform a web search for the query: fastapi SSE streaming ", + "fastapi SSE streaming", + ), + ( + "Search for the query: python 3.13 changelog", + "python 3.13 changelog", + ), + ( + "web search for query: litellm", + "litellm", + ), + ( + "Search for Claude Code releases", + "Search for Claude Code releases", + ), + ( + '"LiteLLM latest version release"', + '"LiteLLM latest version release"', + ), + ( + "'fastapi SSE streaming'", + "'fastapi SSE streaming'", + ), + ( + "Perform a web search for the query: ", + "", + ), + ( + 'Perform a web search for the query: ""', + "", + ), + ( + "", + "", + ), + ], + ) + def test_extract_short_circuit_query_strips_claude_code_prefix(self, raw_prompt: str, expected_query: str): + """Claude Code wraps standalone searches in 'Perform a web search for the query: ...'. + _extract_short_circuit_query must extract only the actual query terms and preserve + exact-phrase quotes when no wrapper was present, without application doubles. + """ + assert WebSearchInterceptionLogger._extract_short_circuit_query(raw_prompt) == expected_query + + # --------------------------------------------------------------------------- # Integration with entry point # --------------------------------------------------------------------------- @@ -251,9 +316,7 @@ class TestShortCircuitEntryPoint: ) logger = WebSearchInterceptionLogger(enabled_providers=["github_copilot"]) - with patch.object( - logger, "_execute_search", new_callable=AsyncMock - ) as mock_search: + with patch.object(logger, "_execute_search", new_callable=AsyncMock) as mock_search: mock_search.return_value = ("results", None) with patch("litellm.callbacks", [logger]): result = await _try_websearch_short_circuit( @@ -279,9 +342,7 @@ class TestShortCircuitEntryPoint: ) logger = WebSearchInterceptionLogger(enabled_providers=["github_copilot"]) - with patch.object( - logger, "_execute_search", new_callable=AsyncMock - ) as mock_search: + with patch.object(logger, "_execute_search", new_callable=AsyncMock) as mock_search: mock_search.return_value = ("streaming results", None) with patch("litellm.callbacks", [logger]): result = await _try_websearch_short_circuit( @@ -344,9 +405,7 @@ class TestShortCircuitEntryPoint: ) logger = WebSearchInterceptionLogger(enabled_providers=["github_copilot"]) - with patch.object( - logger, "_execute_search", new_callable=AsyncMock - ) as mock_search: + with patch.object(logger, "_execute_search", new_callable=AsyncMock) as mock_search: mock_search.return_value = ("streaming results", None) with patch("litellm.callbacks", [logger]): # Simulate what anthropic_messages() does: original_stream=True @@ -374,9 +433,7 @@ class TestShortCircuitEntryPoint: ) logger = WebSearchInterceptionLogger(enabled_providers=["github_copilot"]) - with patch.object( - logger, "_execute_search", new_callable=AsyncMock - ) as mock_search: + with patch.object(logger, "_execute_search", new_callable=AsyncMock) as mock_search: mock_search.return_value = ("results", None) with patch("litellm.callbacks", [logger]): # Simulate the caller having derived custom_llm_provider from @@ -392,69 +449,3 @@ class TestShortCircuitEntryPoint: assert result is not None text_block = next(b for b in result["content"] if b["type"] == "text") assert text_block["text"] == "results" - - @pytest.mark.asyncio - @pytest.mark.parametrize( - "raw_prompt,expected_query", - [ - ( - "Perform a web search for the query: LiteLLM latest version release", - "LiteLLM latest version release", - ), - ( - 'Perform a web search for the query: "who is the maintainer of litellm"', - "who is the maintainer of litellm", - ), - ( - " perform a web search for the query: fastapi SSE streaming ", - "fastapi SSE streaming", - ), - ( - "Search for the query: python 3.13 changelog", - "python 3.13 changelog", - ), - ( - "Search for Claude Code releases", - "Search for Claude Code releases", - ), - ( - '"LiteLLM latest version release"', - '"LiteLLM latest version release"', - ), - ( - "'fastapi SSE streaming'", - "'fastapi SSE streaming'", - ), - ], - ) - async def test_short_circuits_strips_claude_code_instructional_prefix( - self, raw_prompt, expected_query - ): - """Claude Code wraps standalone searches in 'Perform a web search for the query: ...'. - The short-circuit path must extract only the actual query terms so search backends - receive the intended query rather than instructional prefix words. - """ - logger = WebSearchInterceptionLogger(enabled_providers=["github_copilot"]) - - with patch.object( - logger, "_execute_search", new_callable=AsyncMock - ) as mock_search: - mock_search.return_value = ("Results", None) - - result = await logger.try_short_circuit_search( - model="github_copilot/claude-sonnet-4", - messages=[{"role": "user", "content": raw_prompt}], - tools=[ - {"type": "web_search_20250305", "name": "web_search", "max_uses": 8} - ], - custom_llm_provider="github_copilot", - ) - - assert result is not None - mock_search.assert_called_once_with(expected_query) - tool_use_block = next( - (b for b in result["content"] if b["type"] == "server_tool_use"), None - ) - if tool_use_block is not None: - assert tool_use_block["input"]["query"] == expected_query - From 5fd3e07583ce6cb1ef882077eae3ab16aedaf653 Mon Sep 17 00:00:00 2001 From: agustin18 Date: Sun, 27 Sep 2026 19:38:26 +0000 Subject: [PATCH 4/6] style(websearch): fix ruff formatting blank line in handler Signed-off-by: agustin18 --- litellm/integrations/websearch_interception/handler.py | 1 - 1 file changed, 1 deletion(-) diff --git a/litellm/integrations/websearch_interception/handler.py b/litellm/integrations/websearch_interception/handler.py index c534115181a..266dea59b8a 100644 --- a/litellm/integrations/websearch_interception/handler.py +++ b/litellm/integrations/websearch_interception/handler.py @@ -311,7 +311,6 @@ class WebSearchInterceptionLogger(CustomLogger): cleaned = cleaned[1:-1].strip() return cleaned if (cleaned or prefix) else raw_message.strip() - async def try_short_circuit_search( self, model: str, From 25a63544657b67a6d2c882a35566e5f98effbe62 Mon Sep 17 00:00:00 2001 From: agustin18 Date: Sun, 27 Sep 2026 19:57:45 +0000 Subject: [PATCH 5/6] refactor(websearch): enforce Final annotations, prevent rebinding, and retain e2e coverage Signed-off-by: agustin18 --- .../websearch_interception/handler.py | 16 ++++--- .../test_websearch_short_circuit.py | 43 +++++++++++++++++-- 2 files changed, 49 insertions(+), 10 deletions(-) diff --git a/litellm/integrations/websearch_interception/handler.py b/litellm/integrations/websearch_interception/handler.py index 266dea59b8a..53c7c32f0f9 100644 --- a/litellm/integrations/websearch_interception/handler.py +++ b/litellm/integrations/websearch_interception/handler.py @@ -303,13 +303,17 @@ class WebSearchInterceptionLogger(CustomLogger): Strip known instructional prefixes so the search backend receives only the intended search terms rather than query wrapper keywords. """ - prefix = _CLAUDE_CODE_SEARCH_PREFIX_RE.match(raw_message) - cleaned = (raw_message[prefix.end() :] if prefix else raw_message).strip() - if prefix and ( - (cleaned.startswith('"') and cleaned.endswith('"')) or (cleaned.startswith("'") and cleaned.endswith("'")) + prefix_match: Final[re.Match[str] | None] = _CLAUDE_CODE_SEARCH_PREFIX_RE.match(raw_message) + stripped_prefix: Final[str] = ( + raw_message[prefix_match.end() :].strip() if prefix_match is not None else raw_message.strip() + ) + if prefix_match is not None and ( + (stripped_prefix.startswith('"') and stripped_prefix.endswith('"')) + or (stripped_prefix.startswith("'") and stripped_prefix.endswith("'")) ): - cleaned = cleaned[1:-1].strip() - return cleaned if (cleaned or prefix) else raw_message.strip() + return stripped_prefix[1:-1].strip() + + return stripped_prefix if (stripped_prefix or prefix_match is not None) else raw_message.strip() async def try_short_circuit_search( self, diff --git a/tests/unit/integrations/websearch_interception/test_websearch_short_circuit.py b/tests/unit/integrations/websearch_interception/test_websearch_short_circuit.py index 3f17d1b8aad..a3702bbd29b 100644 --- a/tests/unit/integrations/websearch_interception/test_websearch_short_circuit.py +++ b/tests/unit/integrations/websearch_interception/test_websearch_short_circuit.py @@ -155,9 +155,7 @@ class TestTryShortCircuitSearch: 'Perform a web search for the query: ""', ], ) - async def test_does_not_short_circuit_empty_or_whitespace_user_message( - self, empty_prompt: str - ): + async def test_does_not_short_circuit_empty_or_whitespace_user_message(self, empty_prompt: str): """User message that is whitespace or empty query → returns None without executing search.""" logger = WebSearchInterceptionLogger(enabled_providers=["github_copilot"]) @@ -170,7 +168,6 @@ class TestTryShortCircuitSearch: assert result is None - @pytest.mark.asyncio async def test_search_failure_returns_error_text(self): """Search failure → response with error message, not exception""" @@ -449,3 +446,41 @@ class TestShortCircuitEntryPoint: assert result is not None text_block = next(b for b in result["content"] if b["type"] == "text") assert text_block["text"] == "results" + + @pytest.mark.asyncio + @pytest.mark.parametrize( + "raw_prompt,expected_query", + [ + ( + "Perform a web search for the query: LiteLLM latest version release", + "LiteLLM latest version release", + ), + ( + 'Perform a web search for the query: "who is the maintainer of litellm"', + "who is the maintainer of litellm", + ), + ( + '"LiteLLM latest version release"', + '"LiteLLM latest version release"', + ), + ], + ) + async def test_short_circuits_strips_claude_code_instructional_prefix(self, raw_prompt: str, expected_query: str): + """Verify end-to-end that try_short_circuit_search forwards the cleaned query to search.""" + logger = WebSearchInterceptionLogger(enabled_providers=["github_copilot"]) + + with patch.object(logger, "_execute_search", new_callable=AsyncMock) as mock_search: + mock_search.return_value = ("Results", None) + + result = await logger.try_short_circuit_search( + model="github_copilot/claude-sonnet-4", + messages=[{"role": "user", "content": raw_prompt}], + tools=[{"type": "web_search_20250305", "name": "web_search", "max_uses": 8}], + custom_llm_provider="github_copilot", + ) + + assert result is not None + mock_search.assert_called_once_with(expected_query) + tool_use_block = next((b for b in result["content"] if b["type"] == "server_tool_use"), None) + if tool_use_block is not None: + assert tool_use_block["input"]["query"] == expected_query From 10fbe70c6a3b45c386027f4d954eab14204c93f1 Mon Sep 17 00:00:00 2001 From: agustin18 Date: Sun, 27 Sep 2026 20:56:07 +0000 Subject: [PATCH 6/6] test(websearch): assert server_tool_use block unconditionally Signed-off-by: agustin18 --- .../websearch_interception/test_websearch_short_circuit.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/tests/unit/integrations/websearch_interception/test_websearch_short_circuit.py b/tests/unit/integrations/websearch_interception/test_websearch_short_circuit.py index a3702bbd29b..4ae815186c3 100644 --- a/tests/unit/integrations/websearch_interception/test_websearch_short_circuit.py +++ b/tests/unit/integrations/websearch_interception/test_websearch_short_circuit.py @@ -481,6 +481,5 @@ class TestShortCircuitEntryPoint: assert result is not None mock_search.assert_called_once_with(expected_query) - tool_use_block = next((b for b in result["content"] if b["type"] == "server_tool_use"), None) - if tool_use_block is not None: - assert tool_use_block["input"]["query"] == expected_query + tool_use_block = next(b for b in result["content"] if b["type"] == "server_tool_use") + assert tool_use_block["input"]["query"] == expected_query