mirror of
https://github.com/BerriAI/litellm.git
synced 2026-09-14 23:21:35 +00:00
fix: filter unsupported beta headers for Bedrock Invoke API (#19877)
- Add whitelist-based filtering for anthropic_beta headers - Only allow Bedrock-supported beta flags (computer-use, tool-search, etc.) - Filter out unsupported flags like mcp-servers, structured-outputs - Remove output_format parameter from Bedrock Invoke requests - Force tool-based structured outputs when response_format is used Fixes #16726
This commit is contained in:
parent
54a83e75cc
commit
4717f742eb
2 changed files with 141 additions and 1 deletions
|
|
@ -53,13 +53,26 @@ class AmazonAnthropicClaudeConfig(AmazonInvokeConfig, AnthropicConfig):
|
|||
model: str,
|
||||
drop_params: bool,
|
||||
) -> dict:
|
||||
return AnthropicConfig.map_openai_params(
|
||||
# Force tool-based structured outputs for Bedrock Invoke
|
||||
# (similar to VertexAI fix in #19201)
|
||||
# Bedrock Invoke doesn't support output_format parameter
|
||||
original_model = model
|
||||
if "response_format" in non_default_params:
|
||||
# Use a model name that forces tool-based approach
|
||||
model = "claude-3-sonnet-20240229"
|
||||
|
||||
optional_params = AnthropicConfig.map_openai_params(
|
||||
self,
|
||||
non_default_params,
|
||||
optional_params,
|
||||
model,
|
||||
drop_params,
|
||||
)
|
||||
|
||||
# Restore original model name
|
||||
model = original_model
|
||||
|
||||
return optional_params
|
||||
|
||||
|
||||
def transform_request(
|
||||
|
|
@ -90,6 +103,8 @@ class AmazonAnthropicClaudeConfig(AmazonInvokeConfig, AnthropicConfig):
|
|||
|
||||
_anthropic_request.pop("model", None)
|
||||
_anthropic_request.pop("stream", None)
|
||||
# Bedrock Invoke doesn't support output_format parameter
|
||||
_anthropic_request.pop("output_format", None)
|
||||
if "anthropic_version" not in _anthropic_request:
|
||||
_anthropic_request["anthropic_version"] = self.anthropic_version
|
||||
|
||||
|
|
@ -117,6 +132,26 @@ class AmazonAnthropicClaudeConfig(AmazonInvokeConfig, AnthropicConfig):
|
|||
if "opus-4" in model.lower() or "opus_4" in model.lower():
|
||||
beta_set.add("tool-search-tool-2025-10-19")
|
||||
|
||||
# Filter out beta headers that Bedrock Invoke doesn't support
|
||||
# AWS Bedrock only supports a specific whitelist of beta flags
|
||||
# Reference: https://docs.aws.amazon.com/bedrock/latest/userguide/model-parameters-anthropic-claude-messages-request-response.html
|
||||
BEDROCK_SUPPORTED_BETAS = {
|
||||
"computer-use-2024-10-22", # Legacy computer use
|
||||
"computer-use-2025-01-24", # Current computer use (Claude 3.7 Sonnet)
|
||||
"token-efficient-tools-2025-02-19", # Tool use (Claude 3.7+ and Claude 4+)
|
||||
"interleaved-thinking-2025-05-14", # Interleaved thinking (Claude 4+)
|
||||
"output-128k-2025-02-19", # 128K output tokens (Claude 3.7 Sonnet)
|
||||
"dev-full-thinking-2025-05-14", # Developer mode for raw thinking (Claude 4+)
|
||||
"context-1m-2025-08-07", # 1 million tokens (Claude Sonnet 4)
|
||||
"context-management-2025-06-27", # Context management (Claude Sonnet/Haiku 4.5)
|
||||
"effort-2025-11-24", # Effort parameter (Claude Opus 4.5)
|
||||
"tool-search-tool-2025-10-19", # Tool search (Claude Opus 4.5)
|
||||
"tool-examples-2025-10-29", # Tool use examples (Claude Opus 4.5)
|
||||
}
|
||||
|
||||
# Only keep beta headers that Bedrock supports
|
||||
beta_set = {beta for beta in beta_set if beta in BEDROCK_SUPPORTED_BETAS}
|
||||
|
||||
if beta_set:
|
||||
_anthropic_request["anthropic_beta"] = list(beta_set)
|
||||
|
||||
|
|
|
|||
|
|
@ -464,3 +464,108 @@ def test_opus_4_5_model_detection():
|
|||
for model in non_opus_4_5_models:
|
||||
assert not config._is_claude_opus_4_5(model), \
|
||||
f"Should not detect {model} as Opus 4.5"
|
||||
|
||||
|
||||
def test_structured_outputs_beta_header_filtered_for_bedrock_invoke():
|
||||
"""
|
||||
Test that unsupported beta headers are filtered out for Bedrock Invoke API.
|
||||
|
||||
Bedrock Invoke API only supports a specific whitelist of beta flags and returns
|
||||
"invalid beta flag" error for others (e.g., structured-outputs, mcp-servers).
|
||||
This test ensures unsupported headers are filtered while keeping supported ones.
|
||||
|
||||
Fixes: https://github.com/BerriAI/litellm/issues/16726
|
||||
"""
|
||||
config = AmazonAnthropicClaudeConfig()
|
||||
|
||||
messages = [{"role": "user", "content": "test"}]
|
||||
|
||||
# Test 1: structured-outputs beta header (unsupported)
|
||||
headers = {"anthropic-beta": "structured-outputs-2025-11-13"}
|
||||
|
||||
result = config.transform_request(
|
||||
model="anthropic.claude-4-0-sonnet-20250514-v1:0",
|
||||
messages=messages,
|
||||
optional_params={},
|
||||
litellm_params={},
|
||||
headers=headers,
|
||||
)
|
||||
|
||||
# Verify structured-outputs beta is filtered out
|
||||
anthropic_beta = result.get("anthropic_beta", [])
|
||||
assert not any("structured-outputs" in beta for beta in anthropic_beta), \
|
||||
f"structured-outputs beta should be filtered, got: {anthropic_beta}"
|
||||
|
||||
# Test 2: mcp-servers beta header (unsupported - the main issue from #16726)
|
||||
headers = {"anthropic-beta": "mcp-servers-2025-12-04"}
|
||||
|
||||
result = config.transform_request(
|
||||
model="anthropic.claude-4-0-sonnet-20250514-v1:0",
|
||||
messages=messages,
|
||||
optional_params={},
|
||||
litellm_params={},
|
||||
headers=headers,
|
||||
)
|
||||
|
||||
# Verify mcp-servers beta is filtered out
|
||||
anthropic_beta = result.get("anthropic_beta", [])
|
||||
assert not any("mcp-servers" in beta for beta in anthropic_beta), \
|
||||
f"mcp-servers beta should be filtered, got: {anthropic_beta}"
|
||||
|
||||
# Test 3: Mix of supported and unsupported beta headers
|
||||
headers = {"anthropic-beta": "computer-use-2024-10-22,mcp-servers-2025-12-04,structured-outputs-2025-11-13"}
|
||||
|
||||
result = config.transform_request(
|
||||
model="anthropic.claude-4-0-sonnet-20250514-v1:0",
|
||||
messages=messages,
|
||||
optional_params={},
|
||||
litellm_params={},
|
||||
headers=headers,
|
||||
)
|
||||
|
||||
# Verify only supported betas are kept
|
||||
anthropic_beta = result.get("anthropic_beta", [])
|
||||
assert not any("structured-outputs" in beta for beta in anthropic_beta), \
|
||||
f"structured-outputs beta should be filtered, got: {anthropic_beta}"
|
||||
assert not any("mcp-servers" in beta for beta in anthropic_beta), \
|
||||
f"mcp-servers beta should be filtered, got: {anthropic_beta}"
|
||||
assert any("computer-use" in beta for beta in anthropic_beta), \
|
||||
f"computer-use beta should be kept, got: {anthropic_beta}"
|
||||
|
||||
|
||||
def test_output_format_removed_from_bedrock_invoke_request():
|
||||
"""
|
||||
Test that output_format parameter is removed from Bedrock Invoke requests.
|
||||
|
||||
Bedrock Invoke API doesn't support the output_format parameter (only supported
|
||||
in Anthropic Messages API). This test ensures it's removed to prevent errors.
|
||||
"""
|
||||
config = AmazonAnthropicClaudeConfig()
|
||||
|
||||
messages = [{"role": "user", "content": "test"}]
|
||||
|
||||
# Create a request with output_format via map_openai_params
|
||||
non_default_params = {
|
||||
"response_format": {"type": "json_object"}
|
||||
}
|
||||
optional_params = {}
|
||||
|
||||
# This should trigger tool-based structured outputs
|
||||
optional_params = config.map_openai_params(
|
||||
non_default_params=non_default_params,
|
||||
optional_params=optional_params,
|
||||
model="anthropic.claude-4-0-sonnet-20250514-v1:0",
|
||||
drop_params=False,
|
||||
)
|
||||
|
||||
result = config.transform_request(
|
||||
model="anthropic.claude-4-0-sonnet-20250514-v1:0",
|
||||
messages=messages,
|
||||
optional_params=optional_params,
|
||||
litellm_params={},
|
||||
headers={},
|
||||
)
|
||||
|
||||
# Verify output_format is not in the request
|
||||
assert "output_format" not in result, \
|
||||
f"output_format should be removed for Bedrock Invoke, got keys: {result.keys()}"
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue