mirror of
https://github.com/BerriAI/litellm.git
synced 2026-08-28 05:25:59 +00:00
fix(bedrock): reject Anthropic server-side web_search tool with actionable error (#36473)
* fix(bedrock): reject Anthropic server-side web_search tool with actionable error Bedrock's Anthropic Messages endpoints cannot execute Anthropic's server-side web_search tool, so forwarding it returns an opaque "The provided request is not valid" 400 from Bedrock. Fail fast in the invoke transform with an error that names the unsupported tool, the model, and links the web search interception docs as the fix. * refactor(bedrock): address review nits on web_search guard typing
This commit is contained in:
parent
f1ed4690bb
commit
20354bfcdc
2 changed files with 92 additions and 0 deletions
|
|
@ -67,6 +67,8 @@ class AmazonAnthropicClaudeMessagesConfig(
|
|||
|
||||
DEFAULT_BEDROCK_ANTHROPIC_API_VERSION = "bedrock-2023-05-31"
|
||||
|
||||
WEBSEARCH_INTERCEPTION_DOCS_URL = "https://docs.litellm.ai/docs/integrations/websearch_interception"
|
||||
|
||||
@property
|
||||
def custom_llm_provider(self) -> str | None:
|
||||
return "bedrock"
|
||||
|
|
@ -572,6 +574,45 @@ class AmazonAnthropicClaudeMessagesConfig(
|
|||
|
||||
return filtered_betas
|
||||
|
||||
@staticmethod
|
||||
def _reject_unsupported_web_search_tools(anthropic_messages_request: dict[str, object], model: str) -> None:
|
||||
"""
|
||||
Bedrock's Anthropic endpoints cannot execute Anthropic's server-side
|
||||
``web_search_*`` tool; forwarding it returns an opaque
|
||||
"The provided request is not valid" 400 from Bedrock. Fail fast with an
|
||||
error that names the problem and the fix instead.
|
||||
|
||||
When web search interception is enabled
|
||||
(``litellm_settings.callbacks: ["websearch_interception"]``), the tool
|
||||
is converted to a regular function tool before this transform runs, so
|
||||
this guard never fires.
|
||||
"""
|
||||
from litellm.integrations.websearch_interception.tools import (
|
||||
is_anthropic_native_web_search_tool,
|
||||
)
|
||||
|
||||
tools: Final = anthropic_messages_request.get("tools")
|
||||
if not isinstance(tools, list):
|
||||
return
|
||||
web_search_tool: Final = next(
|
||||
(t for t in tools if isinstance(t, dict) and is_anthropic_native_web_search_tool(t)),
|
||||
None,
|
||||
)
|
||||
if web_search_tool is None:
|
||||
return
|
||||
raise litellm.BadRequestError(
|
||||
message=(
|
||||
f"Bedrock does not support Anthropic's server-side web search tool "
|
||||
f"(tool type '{web_search_tool.get('type')}', model '{model}'). "
|
||||
"To use web search with this model, enable LiteLLM's web search interception "
|
||||
"so the proxy executes the search instead: "
|
||||
f"{AmazonAnthropicClaudeMessagesConfig.WEBSEARCH_INTERCEPTION_DOCS_URL}. "
|
||||
"Alternatively, remove the web_search tool from the request."
|
||||
),
|
||||
model=model,
|
||||
llm_provider="bedrock",
|
||||
)
|
||||
|
||||
def _strip_unsupported_bedrock_invoke_fields(
|
||||
self,
|
||||
anthropic_messages_request: dict,
|
||||
|
|
@ -630,6 +671,8 @@ class AmazonAnthropicClaudeMessagesConfig(
|
|||
############## BEDROCK Invoke SPECIFIC TRANSFORMATION ###
|
||||
#########################################################
|
||||
|
||||
self._reject_unsupported_web_search_tools(anthropic_messages_request=anthropic_messages_request, model=model)
|
||||
|
||||
# 1. anthropic_version is required for all claude models
|
||||
if "anthropic_version" not in anthropic_messages_request:
|
||||
anthropic_messages_request["anthropic_version"] = self.DEFAULT_BEDROCK_ANTHROPIC_API_VERSION
|
||||
|
|
|
|||
|
|
@ -2580,3 +2580,52 @@ 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
|
||||
|
||||
|
||||
@pytest.mark.parametrize("tool_type", ["web_search_20250305", "web_search_20260209"])
|
||||
def test_bedrock_invoke_messages_rejects_server_web_search_tool(tool_type: str):
|
||||
"""Bedrock can't execute Anthropic's server-side web search; the transform
|
||||
must raise an actionable 400 pointing at the interception docs instead of
|
||||
letting Bedrock return an opaque "provided request is not valid"."""
|
||||
import litellm
|
||||
from litellm.types.router import GenericLiteLLMParams
|
||||
|
||||
cfg = AmazonAnthropicClaudeMessagesConfig()
|
||||
with pytest.raises(litellm.BadRequestError) as exc_info:
|
||||
cfg.transform_anthropic_messages_request(
|
||||
model="us.anthropic.claude-haiku-4-5-20251001-v1:0",
|
||||
messages=[{"role": "user", "content": "search the web for litellm"}],
|
||||
anthropic_messages_optional_request_params={
|
||||
"max_tokens": 128,
|
||||
"tools": [{"type": tool_type, "name": "web_search", "max_uses": 5}],
|
||||
},
|
||||
litellm_params=GenericLiteLLMParams(),
|
||||
headers={},
|
||||
)
|
||||
assert "https://docs.litellm.ai/docs/integrations/websearch_interception" in str(exc_info.value)
|
||||
assert "us.anthropic.claude-haiku-4-5-20251001-v1:0" in str(exc_info.value)
|
||||
|
||||
|
||||
def test_bedrock_invoke_messages_allows_converted_websearch_function_tool():
|
||||
"""The interception hook rewrites web_search into a plain custom tool
|
||||
(litellm_web_search); that converted shape must pass through untouched."""
|
||||
from litellm.types.router import GenericLiteLLMParams
|
||||
|
||||
cfg = AmazonAnthropicClaudeMessagesConfig()
|
||||
result = cfg.transform_anthropic_messages_request(
|
||||
model="us.anthropic.claude-haiku-4-5-20251001-v1:0",
|
||||
messages=[{"role": "user", "content": "search the web for litellm"}],
|
||||
anthropic_messages_optional_request_params={
|
||||
"max_tokens": 128,
|
||||
"tools": [
|
||||
{
|
||||
"name": "litellm_web_search",
|
||||
"description": "Search the web",
|
||||
"input_schema": {"type": "object", "properties": {"query": {"type": "string"}}},
|
||||
}
|
||||
],
|
||||
},
|
||||
litellm_params=GenericLiteLLMParams(),
|
||||
headers={},
|
||||
)
|
||||
assert result["tools"][0]["name"] == "litellm_web_search"
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue