From 22d218d430ee3d937c8d2841f369de76946f66d4 Mon Sep 17 00:00:00 2001 From: David Chen Date: Wed, 1 Apr 2026 19:15:26 -0700 Subject: [PATCH] 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 --- .../anthropic_claude3_transformation.py | 9 +++-- litellm/llms/bedrock/common_utils.py | 15 ++++++++ .../anthropic_claude3_transformation.py | 8 +++- .../bedrock/test_anthropic_beta_support.py | 38 ++++++++++++++++++- 4 files changed, 64 insertions(+), 6 deletions(-) diff --git a/litellm/llms/bedrock/chat/invoke_transformations/anthropic_claude3_transformation.py b/litellm/llms/bedrock/chat/invoke_transformations/anthropic_claude3_transformation.py index 7936b6ea644..e8cdd548a1e 100644 --- a/litellm/llms/bedrock/chat/invoke_transformations/anthropic_claude3_transformation.py +++ b/litellm/llms/bedrock/chat/invoke_transformations/anthropic_claude3_transformation.py @@ -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 diff --git a/litellm/llms/bedrock/common_utils.py b/litellm/llms/bedrock/common_utils.py index 9666aa68c99..dfd92234312 100644 --- a/litellm/llms/bedrock/common_utils.py +++ b/litellm/llms/bedrock/common_utils.py @@ -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. diff --git a/litellm/llms/bedrock/messages/invoke_transformations/anthropic_claude3_transformation.py b/litellm/llms/bedrock/messages/invoke_transformations/anthropic_claude3_transformation.py index a890cf2a04d..35980053156 100644 --- a/litellm/llms/bedrock/messages/invoke_transformations/anthropic_claude3_transformation.py +++ b/litellm/llms/bedrock/messages/invoke_transformations/anthropic_claude3_transformation.py @@ -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 diff --git a/tests/test_litellm/llms/bedrock/test_anthropic_beta_support.py b/tests/test_litellm/llms/bedrock/test_anthropic_beta_support.py index 509db357c2a..3764f5bb2c2 100644 --- a/tests/test_litellm/llms/bedrock/test_anthropic_beta_support.py +++ b/tests/test_litellm/llms/bedrock/test_anthropic_beta_support.py @@ -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()