fix(bedrock): forward anthropic-beta headers verbatim on the Claude platform messages path

This commit is contained in:
mateo-berri 2026-09-21 11:39:26 -07:00
parent 36b8be7d81
commit e51ccbc759
4 changed files with 42 additions and 8 deletions

View file

@ -12,6 +12,9 @@ from .common_utils import BedrockClaudePlatformMixin, strip_claude_platform_rout
class BedrockClaudePlatformMessagesConfig(BedrockClaudePlatformMixin, AnthropicMessagesConfig):
def should_filter_anthropic_beta_headers(self) -> bool:
return False
def validate_anthropic_messages_environment(
self,
headers: dict,

View file

@ -313,6 +313,41 @@ async def test_anthropic_messages_routes_bedrock_claude_platform_to_messages_api
assert requests[0]["body"]["model"] == "claude-sonnet-4-6"
@pytest.mark.asyncio
async def test_anthropic_messages_bedrock_claude_platform_forwards_anthropic_beta_verbatim():
import litellm
requests = []
async def mock_post(self, url, data=None, headers=None, **kwargs):
requests.append(_capture_request(url=url, headers=headers or {}, data=data))
return _anthropic_response(url)
try:
with patch(
"litellm.llms.custom_httpx.http_handler.AsyncHTTPHandler.post",
new=mock_post,
):
await litellm.anthropic_messages(
model="bedrock/claude_platform/claude-sonnet-4-6",
messages=[{"role": "user", "content": "hello"}],
max_tokens=10,
mcp_servers=[{"type": "url", "url": "https://mcp.example.com/mcp", "name": "example"}],
api_base="https://aws-external-anthropic.us-west-2.api.aws",
api_key="fake-platform-key",
workspace_id="wrkspc_test",
extra_headers={"anthropic-beta": "prompt-caching-scope-2026-01-05,mcp-client-2025-11-20"},
)
finally:
await litellm.close_litellm_async_clients()
assert len(requests) == 1
assert requests[0]["headers"]["anthropic-beta"] == "mcp-client-2025-11-20,prompt-caching-scope-2026-01-05"
assert requests[0]["body"]["mcp_servers"] == [
{"type": "url", "url": "https://mcp.example.com/mcp", "name": "example"}
]
def test_sigv4_no_duplicate_content_type_when_caller_sets_lowercase():
"""
Regression: get_anthropic_headers() supplies "content-type" (lowercase).

View file

@ -272,13 +272,11 @@ def test_github_copilot_config_disables_anthropic_beta_filtering():
because github_copilot has no entry in the beta headers config; a regression
here would silently disable header-gated Anthropic features for Copilot."""
from litellm.anthropic_beta_headers_manager import update_headers_with_filtered_beta
from litellm.llms.anthropic.experimental_pass_through.messages.transformation import (
AnthropicMessagesConfig,
)
from litellm.llms.azure_ai.anthropic.messages_transformation import AzureAnthropicMessagesConfig
config = GithubCopilotAnthropicMessagesConfig()
assert config.should_filter_anthropic_beta_headers() is False
assert AnthropicMessagesConfig().should_filter_anthropic_beta_headers() is True
assert AzureAnthropicMessagesConfig().should_filter_anthropic_beta_headers() is True
config.authenticator = MagicMock()
config.authenticator.get_api_key.return_value = "gh.test-key"

View file

@ -268,12 +268,10 @@ def test_request_maps_reasoning_effort_to_thinking(config):
def test_passthrough_disables_anthropic_beta_filtering(config):
from litellm.llms.anthropic.experimental_pass_through.messages.transformation import (
AnthropicMessagesConfig,
)
from litellm.llms.azure_ai.anthropic.messages_transformation import AzureAnthropicMessagesConfig
assert config.should_filter_anthropic_beta_headers() is False
assert AnthropicMessagesConfig().should_filter_anthropic_beta_headers() is True
assert AzureAnthropicMessagesConfig().should_filter_anthropic_beta_headers() is True
def test_anthropic_beta_survives_provider_filter_on_passthrough_path(config):