mirror of
https://github.com/BerriAI/litellm.git
synced 2026-09-12 23:01:41 +00:00
fix(bedrock): stop claiming native web_search support on Bedrock
AmazonAnthropicClaudeMessagesConfig inherited handles_web_search_natively() == True from the base Anthropic Messages config, so the web-search interception short-circuit skipped Bedrock and forwarded Anthropic's web_search_20250305 server tool straight to AWS. Bedrock hosts none of the web_search server tools on any of its APIs, so the request is rejected with a deterministic 400. Override the flag to False so interception stays in play, which is the only way the tool can be served on Bedrock. AmazonMantleMessagesConfig subclasses this config and picks up the same answer. Resolves LIT-5391
This commit is contained in:
parent
ea6c18baa5
commit
446a790aa4
3 changed files with 56 additions and 14 deletions
|
|
@ -77,6 +77,15 @@ class AmazonAnthropicClaudeMessagesConfig(
|
|||
BaseAnthropicMessagesConfig.__init__(self, **kwargs)
|
||||
AmazonInvokeConfig.__init__(self, **kwargs)
|
||||
|
||||
def handles_web_search_natively(self) -> bool:
|
||||
"""
|
||||
Bedrock does not host Anthropic's ``web_search_20250305`` server tool on
|
||||
any of its APIs, so forwarding it reaches AWS and is rejected. Reporting
|
||||
False keeps the web-search interception short-circuit in play, which is
|
||||
the only way this tool can be served on Bedrock.
|
||||
"""
|
||||
return False
|
||||
|
||||
def validate_anthropic_messages_environment(
|
||||
self,
|
||||
headers: dict,
|
||||
|
|
|
|||
|
|
@ -122,27 +122,41 @@ 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.
|
||||
async def test_short_circuits_bedrock(self):
|
||||
"""Bedrock → short-circuit fires.
|
||||
|
||||
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.
|
||||
Bedrock does not host Anthropic's web_search_20250305 server tool on any
|
||||
of its APIs, so forwarding the request reaches AWS and is rejected with a
|
||||
400. Short-circuiting is the only way the tool can be served there, so a
|
||||
regression that makes the bedrock config claim native handling again puts
|
||||
the deterministic 400 straight back.
|
||||
"""
|
||||
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",
|
||||
)
|
||||
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,
|
||||
)
|
||||
|
||||
assert result is None
|
||||
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 not None
|
||||
block_types = [b["type"] for b in result["content"]]
|
||||
assert "server_tool_use" in block_types
|
||||
assert "web_search_tool_result" in block_types
|
||||
mock_search.assert_called_once_with("Search for something")
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_does_not_short_circuit_no_messages(self):
|
||||
|
|
|
|||
|
|
@ -2580,3 +2580,22 @@ def test_replayed_intercepted_search_turn_leaves_no_unsupported_block_for_bedroc
|
|||
assert "server_tool_use" not in serialized
|
||||
assert expected_evidence in serialized
|
||||
assert "Rome was founded in 753 BC." in serialized
|
||||
|
||||
|
||||
def test_bedrock_messages_config_does_not_handle_web_search_natively():
|
||||
"""Bedrock hosts none of Anthropic's ``web_search_*`` server tools, so the
|
||||
config must report ``handles_web_search_natively() is False``. That is what
|
||||
keeps the web-search interception short-circuit in play; when it reported
|
||||
True the tool was forwarded verbatim and AWS rejected the request. The
|
||||
mantle subclass inherits the same answer, and the direct Anthropic config
|
||||
must keep reporting True so the fix stays scoped to Bedrock."""
|
||||
from litellm.llms.anthropic.experimental_pass_through.messages.transformation import (
|
||||
AnthropicMessagesConfig,
|
||||
)
|
||||
from litellm.llms.bedrock.messages.mantle_transformation import (
|
||||
AmazonMantleMessagesConfig,
|
||||
)
|
||||
|
||||
assert AmazonAnthropicClaudeMessagesConfig().handles_web_search_natively() is False
|
||||
assert AmazonMantleMessagesConfig().handles_web_search_natively() is False
|
||||
assert AnthropicMessagesConfig().handles_web_search_natively() is True
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue