fix(bedrock): strip unsupported Files API betas for Invoke

Bedrock Invoke rejects files-api and code-execution betas; omit them while
keeping other anthropic_beta flags. Add unit tests.

Made-with: Cursor
This commit is contained in:
David Chen 2026-04-01 19:15:26 -07:00
parent cae8613660
commit 22d218d430
No known key found for this signature in database
GPG key ID: 411F0AC27335E3C9
4 changed files with 64 additions and 6 deletions

View file

@ -9,6 +9,7 @@ from litellm.llms.bedrock.chat.invoke_transformations.base_invoke_transformation
from litellm.llms.bedrock.common_utils import (
get_anthropic_beta_from_headers,
remove_custom_field_from_tools,
strip_unsupported_file_api_betas_for_bedrock_invoke,
)
from litellm.types.llms.anthropic import ANTHROPIC_TOOL_SEARCH_BETA_HEADER
from litellm.types.llms.openai import AllMessageValues
@ -143,9 +144,11 @@ class AmazonAnthropicClaudeConfig(AmazonInvokeConfig, AnthropicConfig):
beta_set.add("tool-search-tool-2025-10-19")
# Filter out beta headers that Bedrock Invoke doesn't support
# Uses centralized configuration from anthropic_beta_headers_config.json
beta_list = list(beta_set)
_anthropic_request["anthropic_beta"] = beta_list
beta_list = strip_unsupported_file_api_betas_for_bedrock_invoke(list(beta_set))
if beta_list:
_anthropic_request["anthropic_beta"] = beta_list
else:
_anthropic_request.pop("anthropic_beta", None)
return _anthropic_request

View file

@ -907,6 +907,21 @@ def get_anthropic_beta_from_headers(headers: dict) -> List[str]:
return []
# Anthropic's Files API uses these betas when using file_id / hosted files. Bedrock Invoke
# rejects them with "invalid beta flag". Document blocks with source.url still work without them.
BEDROCK_INVOKE_UNSUPPORTED_FILE_API_BETAS: frozenset[str] = frozenset(
{
"files-api-2025-04-14",
"code-execution-2025-05-22",
}
)
def strip_unsupported_file_api_betas_for_bedrock_invoke(betas: List[str]) -> List[str]:
"""Drop Files-API-only betas from anthropic_beta before Bedrock Invoke."""
return [b for b in betas if b not in BEDROCK_INVOKE_UNSUPPORTED_FILE_API_BETAS]
class CommonBatchFilesUtils:
"""
Common utilities for Bedrock batch and file operations.

View file

@ -27,6 +27,7 @@ from litellm.llms.bedrock.common_utils import (
get_anthropic_beta_from_headers,
is_claude_4_5_on_bedrock,
remove_custom_field_from_tools,
strip_unsupported_file_api_betas_for_bedrock_invoke,
)
from litellm.types.llms.anthropic import ANTHROPIC_TOOL_SEARCH_BETA_HEADER
from litellm.types.llms.openai import AllMessageValues
@ -460,8 +461,11 @@ class AmazonAnthropicClaudeMessagesConfig(
if "tool-search-tool-2025-10-19" in beta_set:
beta_set.add("tool-examples-2025-10-29")
if beta_set:
anthropic_messages_request["anthropic_beta"] = list(beta_set)
beta_list = strip_unsupported_file_api_betas_for_bedrock_invoke(list(beta_set))
if beta_list:
anthropic_messages_request["anthropic_beta"] = beta_list
else:
anthropic_messages_request.pop("anthropic_beta", None)
return anthropic_messages_request

View file

@ -14,7 +14,10 @@ from litellm.llms.bedrock.chat.converse_transformation import AmazonConverseConf
from litellm.llms.bedrock.chat.invoke_transformations.anthropic_claude3_transformation import (
AmazonAnthropicClaudeConfig,
)
from litellm.llms.bedrock.common_utils import get_anthropic_beta_from_headers
from litellm.llms.bedrock.common_utils import (
get_anthropic_beta_from_headers,
strip_unsupported_file_api_betas_for_bedrock_invoke,
)
from litellm.llms.bedrock.messages.invoke_transformations.anthropic_claude3_transformation import (
AmazonAnthropicClaudeMessagesConfig,
)
@ -64,6 +67,39 @@ class TestAnthropicBetaHeaderSupport:
# Beta flags are stored as sets, so order may vary
assert set(result["anthropic_beta"]) == {"context-1m-2025-08-07", "computer-use-2024-10-22"}
def test_invoke_omits_file_api_betas_for_openai_style_file_url(self):
"""Bedrock returns invalid beta flag if Files API betas are sent; URL docs work without them."""
config = AmazonAnthropicClaudeConfig()
messages = [
{
"role": "user",
"content": [
{"type": "text", "text": "What's this file about?"},
{
"type": "file",
"file": {
"file_id": "https://upload.wikimedia.org/wikipedia/commons/2/20/Re_example.pdf"
},
},
],
}
]
result = config.transform_request(
model="anthropic.claude-3-5-sonnet-20241022-v2:0",
messages=messages,
optional_params={},
litellm_params={},
headers={},
)
betas = result.get("anthropic_beta", [])
assert "files-api-2025-04-14" not in betas
assert "code-execution-2025-05-22" not in betas
def test_strip_unsupported_file_api_betas_helper(self):
assert strip_unsupported_file_api_betas_for_bedrock_invoke(
["context-1m-2025-08-07", "files-api-2025-04-14", "code-execution-2025-05-22"]
) == ["context-1m-2025-08-07"]
def test_converse_transformation_anthropic_beta(self):
"""Test that Converse API transformation includes anthropic_beta in additionalModelRequestFields."""
config = AmazonConverseConfig()