mirror of
https://github.com/BerriAI/litellm.git
synced 2026-10-08 03:08:45 +00:00
Merge remote-tracking branch 'origin/litellm_internal_staging' into litellm_/vibrant-booth-d4258b
This commit is contained in:
commit
0d2eaddd64
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