Refactor Anthropic Configurations and Add Support for anthropic_beta Headers

- Renamed `AmazonAnthropicClaude3Config` and `AmazonAnthropicClaude3MessagesConfig` to `AmazonAnthropicClaudeConfig` and `AmazonAnthropicClaudeMessagesConfig` respectively for consistency.
- Implemented `get_anthropic_beta_from_headers` function to extract and handle `anthropic-beta` headers across various transformations.
- Updated request transformations in `AmazonConverseConfig` and `AmazonInvokeConfig` to include `anthropic_beta` parameters based on user headers.
- Added tests to ensure proper handling of `anthropic_beta` headers in different scenarios.
This commit is contained in:
Jugal Bhatt 2025-08-13 11:47:59 -07:00
parent 37e57a0e5f
commit 3990f61bed
11 changed files with 389 additions and 13 deletions

View file

@ -584,6 +584,143 @@ Same as [Anthropic API response](../providers/anthropic#usage---thinking--reason
Same as [Anthropic API response](../providers/anthropic#usage---thinking--reasoning_content).
## Usage - Anthropic Beta Features
LiteLLM supports Anthropic's beta features on AWS Bedrock through the `anthropic-beta` header. This enables access to experimental features like:
- **1M Context Window** - Up to 1 million tokens of context (Claude Sonnet 4)
- **Computer Use Tools** - AI that can interact with computer interfaces
- **Token-Efficient Tools** - More efficient tool usage patterns
- **Extended Output** - Up to 128K output tokens
- **Enhanced Thinking** - Advanced reasoning capabilities
### Supported Beta Features
| Beta Feature | Header Value | Compatible Models | Description |
|--------------|-------------|------------------|-------------|
| 1M Context Window | `context-1m-2025-08-07` | Claude Sonnet 4 | Enable 1 million token context window |
| Computer Use (Latest) | `computer-use-2025-01-24` | Claude 3.7 Sonnet | Latest computer use tools |
| Computer Use (Legacy) | `computer-use-2024-10-22` | Claude 3.5 Sonnet v2 | Computer use tools for Claude 3.5 |
| Token-Efficient Tools | `token-efficient-tools-2025-02-19` | Claude 3.7 Sonnet | More efficient tool usage |
| Interleaved Thinking | `interleaved-thinking-2025-05-14` | Claude 4 models | Enhanced thinking capabilities |
| Extended Output | `output-128k-2025-02-19` | Claude 3.7 Sonnet | Up to 128K output tokens |
| Developer Thinking | `dev-full-thinking-2025-05-14` | Claude 4 models | Raw thinking mode for developers |
<Tabs>
<TabItem value="sdk" label="SDK">
**Single Beta Feature**
```python
from litellm import completion
import os
# set env
os.environ["AWS_ACCESS_KEY_ID"] = ""
os.environ["AWS_SECRET_ACCESS_KEY"] = ""
os.environ["AWS_REGION_NAME"] = ""
# Use 1M context window with Claude Sonnet 4
response = completion(
model="bedrock/anthropic.claude-sonnet-4-20250115-v1:0",
messages=[{"role": "user", "content": "Hello! Testing 1M context window."}],
max_tokens=100,
extra_headers={
"anthropic-beta": "context-1m-2025-08-07" # 👈 Enable 1M context
}
)
```
**Multiple Beta Features**
```python
from litellm import completion
# Combine multiple beta features (comma-separated)
response = completion(
model="bedrock/converse/anthropic.claude-3-5-sonnet-20241022-v2:0",
messages=[{"role": "user", "content": "Testing multiple beta features"}],
max_tokens=100,
extra_headers={
"anthropic-beta": "computer-use-2024-10-22,context-1m-2025-08-07"
}
)
```
**Computer Use Tools with Beta Features**
```python
from litellm import completion
# Computer use tools automatically add computer-use-2024-10-22
# You can add additional beta features
response = completion(
model="bedrock/converse/anthropic.claude-3-5-sonnet-20241022-v2:0",
messages=[{"role": "user", "content": "Take a screenshot"}],
tools=[{
"type": "computer_20241022",
"name": "computer",
"display_width_px": 1920,
"display_height_px": 1080
}],
extra_headers={
"anthropic-beta": "context-1m-2025-08-07" # Additional beta feature
}
)
```
</TabItem>
<TabItem value="proxy" label="PROXY">
**Set on YAML Config**
```yaml
model_list:
- model_name: claude-sonnet-4-1m
litellm_params:
model: bedrock/anthropic.claude-sonnet-4-20250115-v1:0
extra_headers:
anthropic-beta: "context-1m-2025-08-07" # 👈 Enable 1M context
- model_name: claude-computer-use
litellm_params:
model: bedrock/converse/anthropic.claude-3-5-sonnet-20241022-v2:0
extra_headers:
anthropic-beta: "computer-use-2024-10-22,context-1m-2025-08-07"
```
**Set on Request**
```python
import openai
client = openai.OpenAI(
api_key="anything",
base_url="http://0.0.0.0:4000"
)
response = client.chat.completions.create(
model="claude-sonnet-4-1m",
messages=[{
"role": "user",
"content": "Testing 1M context window"
}],
extra_headers={
"anthropic-beta": "context-1m-2025-08-07"
}
)
```
</TabItem>
</Tabs>
:::info
Beta features may require special access or permissions in your AWS account. Some features are only available in specific AWS regions. Check the [AWS Bedrock documentation](https://docs.aws.amazon.com/bedrock/latest/userguide/model-parameters-anthropic-claude-messages-request-response.html) for availability and access requirements.
:::
## Usage - Structured Output / JSON mode
<Tabs>

View file

@ -1041,7 +1041,7 @@ from .llms.anthropic.experimental_pass_through.messages.transformation import (
AnthropicMessagesConfig,
)
from .llms.bedrock.messages.invoke_transformations.anthropic_claude3_transformation import (
AmazonAnthropicClaude3MessagesConfig,
AmazonAnthropicClaudeMessagesConfig,
)
from .llms.together_ai.chat import TogetherAIConfig
from .llms.together_ai.completion.transformation import TogetherAITextCompletionConfig
@ -1101,7 +1101,7 @@ from .llms.bedrock.chat.invoke_transformations.anthropic_claude2_transformation
AmazonAnthropicConfig,
)
from .llms.bedrock.chat.invoke_transformations.anthropic_claude3_transformation import (
AmazonAnthropicClaude3Config,
AmazonAnthropicClaudeConfig,
)
from .llms.bedrock.chat.invoke_transformations.amazon_cohere_transformation import (
AmazonCohereConfig,

View file

@ -119,6 +119,7 @@ class BedrockConverseLLM(BaseAWSLLM):
messages=messages,
optional_params=optional_params,
litellm_params=litellm_params,
headers=headers,
)
data = json.dumps(request_data)
@ -185,6 +186,7 @@ class BedrockConverseLLM(BaseAWSLLM):
messages=messages,
optional_params=optional_params,
litellm_params=litellm_params,
headers=headers,
)
data = json.dumps(request_data)
prepped = self.get_request_headers(
@ -390,6 +392,7 @@ class BedrockConverseLLM(BaseAWSLLM):
messages=messages,
optional_params=optional_params,
litellm_params=litellm_params,
headers=extra_headers,
)
data = json.dumps(_data)
prepped = self.get_request_headers(

View file

@ -47,7 +47,7 @@ from litellm.types.utils import (
)
from litellm.utils import add_dummy_tool, has_tool_call_blocks, supports_reasoning
from ..common_utils import BedrockError, BedrockModelInfo, get_bedrock_tool_name
from ..common_utils import BedrockError, BedrockModelInfo, get_bedrock_tool_name, get_anthropic_beta_from_headers
# Computer use tool prefixes supported by Bedrock
BEDROCK_COMPUTER_USE_TOOLS = [
@ -593,12 +593,14 @@ class AmazonConverseConfig(BaseConfig):
return {}
def _transform_request_helper(
self,
model: str,
system_content_blocks: List[SystemContentBlock],
optional_params: dict,
messages: Optional[List[AllMessageValues]] = None,
headers: Optional[dict] = None,
) -> CommonRequestObject:
## VALIDATE REQUEST
"""
@ -651,6 +653,12 @@ class AmazonConverseConfig(BaseConfig):
# Initialize bedrock_tools
bedrock_tools: List[ToolBlock] = []
# Collect anthropic_beta values from user headers
anthropic_beta_list = []
if headers:
user_betas = get_anthropic_beta_from_headers(headers)
anthropic_beta_list.extend(user_betas)
# Only separate tools if computer use tools are actually present
if original_tools and self.is_computer_use_tool_used(original_tools, model):
# Separate computer use tools from regular function tools
@ -663,7 +671,7 @@ class AmazonConverseConfig(BaseConfig):
# Add computer use tools and anthropic_beta if needed (only when computer use tools are present)
if computer_use_tools:
additional_request_params["anthropic_beta"] = ["computer-use-2024-10-22"]
anthropic_beta_list.append("computer-use-2024-10-22")
# Transform computer use tools to proper Bedrock format
transformed_computer_tools = self._transform_computer_use_tools(computer_use_tools)
additional_request_params["tools"] = transformed_computer_tools
@ -671,6 +679,17 @@ class AmazonConverseConfig(BaseConfig):
# No computer use tools, process all tools as regular tools
bedrock_tools = _bedrock_tools_pt(original_tools)
# Set anthropic_beta in additional_request_params if we have any beta features
if anthropic_beta_list:
# Remove duplicates while preserving order
unique_betas = []
seen = set()
for beta in anthropic_beta_list:
if beta not in seen:
unique_betas.append(beta)
seen.add(beta)
additional_request_params["anthropic_beta"] = unique_betas
bedrock_tool_config: Optional[ToolConfigBlock] = None
if len(bedrock_tools) > 0:
tool_choice_values: ToolChoiceValuesBlock = inference_params.pop(
@ -708,6 +727,7 @@ class AmazonConverseConfig(BaseConfig):
messages: List[AllMessageValues],
optional_params: dict,
litellm_params: dict,
headers: Optional[dict] = None,
) -> RequestObject:
messages, system_content_blocks = self._transform_system_message(messages)
## TRANSFORMATION ##
@ -717,6 +737,7 @@ class AmazonConverseConfig(BaseConfig):
system_content_blocks=system_content_blocks,
optional_params=optional_params,
messages=messages,
headers=headers,
)
bedrock_messages = (
@ -747,6 +768,7 @@ class AmazonConverseConfig(BaseConfig):
messages=messages,
optional_params=optional_params,
litellm_params=litellm_params,
headers=headers,
),
)
@ -756,6 +778,7 @@ class AmazonConverseConfig(BaseConfig):
messages: List[AllMessageValues],
optional_params: dict,
litellm_params: dict,
headers: Optional[dict] = None,
) -> RequestObject:
messages, system_content_blocks = self._transform_system_message(messages)
@ -764,6 +787,7 @@ class AmazonConverseConfig(BaseConfig):
system_content_blocks=system_content_blocks,
optional_params=optional_params,
messages=messages,
headers=headers,
)
## TRANSFORMATION ##

View file

@ -831,7 +831,7 @@ class BedrockLLM(BaseAWSLLM):
model=model, messages=messages, custom_llm_provider="anthropic_xml"
) # type: ignore
## LOAD CONFIG
config = litellm.AmazonAnthropicClaude3Config.get_config()
config = litellm.AmazonAnthropicClaudeConfig.get_config()
for k, v in config.items():
if (
k not in inference_params

View file

@ -6,6 +6,7 @@ from litellm.llms.anthropic.chat.transformation import AnthropicConfig
from litellm.llms.bedrock.chat.invoke_transformations.base_invoke_transformation import (
AmazonInvokeConfig,
)
from litellm.llms.bedrock.common_utils import get_anthropic_beta_from_headers
from litellm.types.llms.openai import AllMessageValues
from litellm.types.utils import ModelResponse
@ -17,13 +18,22 @@ else:
LiteLLMLoggingObj = Any
class AmazonAnthropicClaude3Config(AmazonInvokeConfig, AnthropicConfig):
class AmazonAnthropicClaudeConfig(AmazonInvokeConfig, AnthropicConfig):
"""
Reference:
https://us-west-2.console.aws.amazon.com/bedrock/home?region=us-west-2#/providers?model=claude
https://docs.anthropic.com/claude/docs/models-overview#model-comparison
https://docs.aws.amazon.com/bedrock/latest/userguide/model-parameters-anthropic-claude-messages-request-response.html
Supported Params for the Amazon / Anthropic Claude 3 models:
Supported Params for the Amazon / Anthropic Claude models (Claude 3, Claude 4, etc.):
Supports anthropic_beta parameter for beta features like:
- computer-use-2025-01-24 (Claude 3.7 Sonnet)
- computer-use-2024-10-22 (Claude 3.5 Sonnet v2)
- token-efficient-tools-2025-02-19 (Claude 3.7 Sonnet)
- interleaved-thinking-2025-05-14 (Claude 4 models)
- output-128k-2025-02-19 (Claude 3.7 Sonnet)
- dev-full-thinking-2025-05-14 (Claude 4 models)
- context-1m-2025-08-07 (Claude Sonnet 4)
"""
anthropic_version: str = "bedrock-2023-05-31"
@ -50,6 +60,7 @@ class AmazonAnthropicClaude3Config(AmazonInvokeConfig, AnthropicConfig):
drop_params,
)
def transform_request(
self,
model: str,
@ -72,6 +83,11 @@ class AmazonAnthropicClaude3Config(AmazonInvokeConfig, AnthropicConfig):
if "anthropic_version" not in _anthropic_request:
_anthropic_request["anthropic_version"] = self.anthropic_version
# Handle anthropic_beta from user headers
anthropic_beta_list = get_anthropic_beta_from_headers(headers)
if anthropic_beta_list:
_anthropic_request["anthropic_beta"] = anthropic_beta_list
return _anthropic_request
def transform_response(

View file

@ -190,7 +190,7 @@ class AmazonInvokeConfig(BaseConfig, BaseAWSLLM):
] = True # cohere requires stream = True in inference params
request_data = {"prompt": prompt, **inference_params}
elif provider == "anthropic":
return litellm.AmazonAnthropicClaude3Config().transform_request(
return litellm.AmazonAnthropicClaudeConfig().transform_request(
model=model,
messages=messages,
optional_params=optional_params,
@ -293,7 +293,7 @@ class AmazonInvokeConfig(BaseConfig, BaseAWSLLM):
completion_response["generations"][0]["finish_reason"]
)
elif provider == "anthropic":
return litellm.AmazonAnthropicClaude3Config().transform_response(
return litellm.AmazonAnthropicClaudeConfig().transform_response(
model=model,
raw_response=raw_response,
model_response=model_response,

View file

@ -524,3 +524,25 @@ class BedrockEventStreamDecoderBase:
return None
return chunk.decode() # type: ignore[no-any-return]
def get_anthropic_beta_from_headers(headers: dict) -> List[str]:
"""
Extract anthropic-beta header values and convert them to a list.
Supports comma-separated values from user headers.
Used by both converse and invoke transformations for consistent handling
of anthropic-beta headers that should be passed to AWS Bedrock.
Args:
headers (dict): Request headers dictionary
Returns:
List[str]: List of anthropic beta feature strings, empty list if no header
"""
anthropic_beta_header = headers.get("anthropic-beta")
if not anthropic_beta_header:
return []
# Split comma-separated values and strip whitespace
return [beta.strip() for beta in anthropic_beta_header.split(",")]

View file

@ -12,6 +12,7 @@ from litellm.llms.bedrock.chat.invoke_handler import AWSEventStreamDecoder
from litellm.llms.bedrock.chat.invoke_transformations.base_invoke_transformation import (
AmazonInvokeConfig,
)
from litellm.llms.bedrock.common_utils import get_anthropic_beta_from_headers
from litellm.types.router import GenericLiteLLMParams
from litellm.types.utils import GenericStreamingChunk
from litellm.types.utils import GenericStreamingChunk as GChunk
@ -25,12 +26,13 @@ else:
LiteLLMLoggingObj = Any
class AmazonAnthropicClaude3MessagesConfig(
class AmazonAnthropicClaudeMessagesConfig(
AnthropicMessagesConfig,
AmazonInvokeConfig,
):
"""
Call Claude model family in the /v1/messages API spec
Supports anthropic_beta parameter for beta features.
"""
DEFAULT_BEDROCK_ANTHROPIC_API_VERSION = "bedrock-2023-05-31"
@ -127,6 +129,12 @@ class AmazonAnthropicClaude3MessagesConfig(
# 3. `model` is not allowed in request body for bedrock invoke
if "model" in anthropic_messages_request:
anthropic_messages_request.pop("model", None)
# 4. Handle anthropic_beta from user headers
anthropic_beta_list = get_anthropic_beta_from_headers(headers)
if anthropic_beta_list:
anthropic_messages_request["anthropic_beta"] = anthropic_beta_list
return anthropic_messages_request
def get_async_streaming_response_iterator(

View file

@ -3615,7 +3615,7 @@ def get_optional_params( # noqa: PLR0915
elif "anthropic" in bedrock_base_model and bedrock_route == "invoke":
if bedrock_base_model.startswith("anthropic.claude-3"):
optional_params = (
litellm.AmazonAnthropicClaude3Config().map_openai_params(
litellm.AmazonAnthropicClaudeConfig().map_openai_params(
non_default_params=non_default_params,
optional_params=optional_params,
model=model,
@ -6975,7 +6975,7 @@ class ProviderConfigManager:
):
return litellm.AmazonAnthropicConfig()
else:
return litellm.AmazonAnthropicClaude3Config()
return litellm.AmazonAnthropicClaudeConfig()
elif (
bedrock_invoke_provider == "meta" or bedrock_invoke_provider == "llama"
): # amazon / meta llms
@ -7071,7 +7071,7 @@ class ProviderConfigManager:
# The 'BEDROCK' provider corresponds to Amazon's implementation of Anthropic Claude v3.
# This mapping ensures that the correct configuration is returned for BEDROCK.
elif litellm.LlmProviders.BEDROCK == provider:
return litellm.AmazonAnthropicClaude3MessagesConfig()
return litellm.AmazonAnthropicClaudeMessagesConfig()
elif litellm.LlmProviders.VERTEX_AI == provider:
if "claude" in model:
from litellm.llms.vertex_ai.vertex_ai_partner_models.anthropic.experimental_pass_through.transformation import (

View file

@ -0,0 +1,166 @@
"""
Test anthropic_beta header support for AWS Bedrock.
Tests that anthropic-beta headers are correctly processed and passed to AWS Bedrock
for enabling beta features like 1M context window, computer use tools, etc.
"""
import pytest
from unittest.mock import patch, MagicMock
import json
from litellm.llms.bedrock.common_utils import get_anthropic_beta_from_headers
from litellm.llms.bedrock.chat.converse_transformation import AmazonConverseConfig
from litellm.llms.bedrock.chat.invoke_transformations.anthropic_claude3_transformation import AmazonAnthropicClaudeConfig
from litellm.llms.bedrock.messages.invoke_transformations.anthropic_claude3_transformation import AmazonAnthropicClaudeMessagesConfig
class TestAnthropicBetaHeaderSupport:
"""Test anthropic_beta header functionality across Bedrock APIs."""
def test_get_anthropic_beta_from_headers_empty(self):
"""Test header extraction with no headers."""
headers = {}
result = get_anthropic_beta_from_headers(headers)
assert result == []
def test_get_anthropic_beta_from_headers_single(self):
"""Test header extraction with single beta header."""
headers = {"anthropic-beta": "context-1m-2025-08-07"}
result = get_anthropic_beta_from_headers(headers)
assert result == ["context-1m-2025-08-07"]
def test_get_anthropic_beta_from_headers_multiple(self):
"""Test header extraction with multiple comma-separated beta headers."""
headers = {"anthropic-beta": "context-1m-2025-08-07,computer-use-2024-10-22"}
result = get_anthropic_beta_from_headers(headers)
assert result == ["context-1m-2025-08-07", "computer-use-2024-10-22"]
def test_get_anthropic_beta_from_headers_whitespace(self):
"""Test header extraction handles whitespace correctly."""
headers = {"anthropic-beta": " context-1m-2025-08-07 , computer-use-2024-10-22 "}
result = get_anthropic_beta_from_headers(headers)
assert result == ["context-1m-2025-08-07", "computer-use-2024-10-22"]
def test_invoke_transformation_anthropic_beta(self):
"""Test that Invoke API transformation includes anthropic_beta in request."""
config = AmazonAnthropicClaudeConfig()
headers = {"anthropic-beta": "context-1m-2025-08-07,computer-use-2024-10-22"}
result = config.transform_request(
model="anthropic.claude-3-5-sonnet-20241022-v2:0",
messages=[{"role": "user", "content": "Test"}],
optional_params={},
litellm_params={},
headers=headers
)
assert "anthropic_beta" in result
assert result["anthropic_beta"] == ["context-1m-2025-08-07", "computer-use-2024-10-22"]
def test_converse_transformation_anthropic_beta(self):
"""Test that Converse API transformation includes anthropic_beta in additionalModelRequestFields."""
config = AmazonConverseConfig()
headers = {"anthropic-beta": "context-1m-2025-08-07,interleaved-thinking-2025-05-14"}
result = config._transform_request_helper(
model="anthropic.claude-3-5-sonnet-20241022-v2:0",
system_content_blocks=[],
optional_params={},
messages=[{"role": "user", "content": "Test"}],
headers=headers
)
assert "additionalModelRequestFields" in result
additional_fields = result["additionalModelRequestFields"]
assert "anthropic_beta" in additional_fields
assert additional_fields["anthropic_beta"] == ["context-1m-2025-08-07", "interleaved-thinking-2025-05-14"]
def test_messages_transformation_anthropic_beta(self):
"""Test that Messages API transformation includes anthropic_beta in request."""
config = AmazonAnthropicClaudeMessagesConfig()
headers = {"anthropic-beta": "output-128k-2025-02-19"}
result = config.transform_anthropic_messages_request(
model="anthropic.claude-3-5-sonnet-20241022-v2:0",
messages=[{"role": "user", "content": "Test"}],
anthropic_messages_optional_request_params={"max_tokens": 100},
litellm_params={},
headers=headers
)
assert "anthropic_beta" in result
assert result["anthropic_beta"] == ["output-128k-2025-02-19"]
def test_converse_computer_use_compatibility(self):
"""Test that user anthropic_beta headers work with computer use tools."""
config = AmazonConverseConfig()
headers = {"anthropic-beta": "context-1m-2025-08-07"}
# Computer use tools should automatically add computer-use-2024-10-22
tools = [
{
"type": "computer_20241022",
"name": "computer",
"display_width_px": 1024,
"display_height_px": 768
}
]
result = config._transform_request_helper(
model="anthropic.claude-3-5-sonnet-20241022-v2:0",
system_content_blocks=[],
optional_params={"tools": tools},
messages=[{"role": "user", "content": "Test"}],
headers=headers
)
additional_fields = result["additionalModelRequestFields"]
betas = additional_fields["anthropic_beta"]
# Should contain both user-provided and auto-added beta headers
assert "context-1m-2025-08-07" in betas
assert "computer-use-2024-10-22" in betas
assert len(betas) == 2 # No duplicates
def test_no_anthropic_beta_headers(self):
"""Test that transformations work correctly when no anthropic_beta headers are provided."""
config = AmazonConverseConfig()
headers = {}
result = config._transform_request_helper(
model="anthropic.claude-3-5-sonnet-20241022-v2:0",
system_content_blocks=[],
optional_params={},
messages=[{"role": "user", "content": "Test"}],
headers=headers
)
additional_fields = result.get("additionalModelRequestFields", {})
assert "anthropic_beta" not in additional_fields
def test_anthropic_beta_all_supported_features(self):
"""Test that all documented beta features are properly handled."""
supported_features = [
"context-1m-2025-08-07",
"computer-use-2025-01-24",
"computer-use-2024-10-22",
"token-efficient-tools-2025-02-19",
"interleaved-thinking-2025-05-14",
"output-128k-2025-02-19",
"dev-full-thinking-2025-05-14"
]
config = AmazonAnthropicClaudeConfig()
headers = {"anthropic-beta": ",".join(supported_features)}
result = config.transform_request(
model="anthropic.claude-3-5-sonnet-20241022-v2:0",
messages=[{"role": "user", "content": "Test"}],
optional_params={},
litellm_params={},
headers=headers
)
assert "anthropic_beta" in result
assert result["anthropic_beta"] == supported_features