From 3990f61bede87c1b085c2ccbb9c688a37f085f05 Mon Sep 17 00:00:00 2001 From: Jugal Bhatt Date: Wed, 13 Aug 2025 11:47:59 -0700 Subject: [PATCH] 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. --- docs/my-website/docs/providers/bedrock.md | 137 +++++++++++++++ litellm/__init__.py | 4 +- litellm/llms/bedrock/chat/converse_handler.py | 3 + .../bedrock/chat/converse_transformation.py | 28 ++- litellm/llms/bedrock/chat/invoke_handler.py | 2 +- .../anthropic_claude3_transformation.py | 20 ++- .../base_invoke_transformation.py | 4 +- litellm/llms/bedrock/common_utils.py | 22 +++ .../anthropic_claude3_transformation.py | 10 +- litellm/utils.py | 6 +- .../bedrock/test_anthropic_beta_support.py | 166 ++++++++++++++++++ 11 files changed, 389 insertions(+), 13 deletions(-) create mode 100644 tests/test_litellm/llms/bedrock/test_anthropic_beta_support.py diff --git a/docs/my-website/docs/providers/bedrock.md b/docs/my-website/docs/providers/bedrock.md index 9797d678ebb..13fe93ec60d 100644 --- a/docs/my-website/docs/providers/bedrock.md +++ b/docs/my-website/docs/providers/bedrock.md @@ -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 | + + + + +**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 + } +) +``` + + + + +**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" + } +) +``` + + + + +:::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 diff --git a/litellm/__init__.py b/litellm/__init__.py index 06d71ff4328..a9699d93a11 100644 --- a/litellm/__init__.py +++ b/litellm/__init__.py @@ -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, diff --git a/litellm/llms/bedrock/chat/converse_handler.py b/litellm/llms/bedrock/chat/converse_handler.py index cd351ca16a7..4cbc0fe3cbe 100644 --- a/litellm/llms/bedrock/chat/converse_handler.py +++ b/litellm/llms/bedrock/chat/converse_handler.py @@ -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( diff --git a/litellm/llms/bedrock/chat/converse_transformation.py b/litellm/llms/bedrock/chat/converse_transformation.py index 84762e0b99a..c124f1c7d8b 100644 --- a/litellm/llms/bedrock/chat/converse_transformation.py +++ b/litellm/llms/bedrock/chat/converse_transformation.py @@ -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 ## diff --git a/litellm/llms/bedrock/chat/invoke_handler.py b/litellm/llms/bedrock/chat/invoke_handler.py index b8dac7c3cd7..42cdb34fc1a 100644 --- a/litellm/llms/bedrock/chat/invoke_handler.py +++ b/litellm/llms/bedrock/chat/invoke_handler.py @@ -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 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 738490aa7bb..9b13d3df08e 100644 --- a/litellm/llms/bedrock/chat/invoke_transformations/anthropic_claude3_transformation.py +++ b/litellm/llms/bedrock/chat/invoke_transformations/anthropic_claude3_transformation.py @@ -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( diff --git a/litellm/llms/bedrock/chat/invoke_transformations/base_invoke_transformation.py b/litellm/llms/bedrock/chat/invoke_transformations/base_invoke_transformation.py index 16f146206b1..742e9285126 100644 --- a/litellm/llms/bedrock/chat/invoke_transformations/base_invoke_transformation.py +++ b/litellm/llms/bedrock/chat/invoke_transformations/base_invoke_transformation.py @@ -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, diff --git a/litellm/llms/bedrock/common_utils.py b/litellm/llms/bedrock/common_utils.py index 2a8fdc148bd..e122517698d 100644 --- a/litellm/llms/bedrock/common_utils.py +++ b/litellm/llms/bedrock/common_utils.py @@ -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(",")] 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 09c6673cc5d..4fa8517a090 100644 --- a/litellm/llms/bedrock/messages/invoke_transformations/anthropic_claude3_transformation.py +++ b/litellm/llms/bedrock/messages/invoke_transformations/anthropic_claude3_transformation.py @@ -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( diff --git a/litellm/utils.py b/litellm/utils.py index fb4f1662a73..317c50e0d00 100644 --- a/litellm/utils.py +++ b/litellm/utils.py @@ -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 ( diff --git a/tests/test_litellm/llms/bedrock/test_anthropic_beta_support.py b/tests/test_litellm/llms/bedrock/test_anthropic_beta_support.py new file mode 100644 index 00000000000..1b9e1b5284c --- /dev/null +++ b/tests/test_litellm/llms/bedrock/test_anthropic_beta_support.py @@ -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 \ No newline at end of file