diff --git a/litellm/llms/anthropic/chat/transformation.py b/litellm/llms/anthropic/chat/transformation.py index fd1859f7d17..44f1e3337d4 100644 --- a/litellm/llms/anthropic/chat/transformation.py +++ b/litellm/llms/anthropic/chat/transformation.py @@ -195,6 +195,7 @@ class AnthropicConfig(AnthropicModelInfo, BaseConfig): "speed", "context_management", "cache_control", + "service_tier", ] if ( @@ -1068,6 +1069,11 @@ class AnthropicConfig(AnthropicModelInfo, BaseConfig): elif param == "cache_control" and isinstance(value, dict): # Pass through top-level cache_control for automatic prompt caching optional_params["cache_control"] = value + elif param == "service_tier" and isinstance(value, str): + # Pass through service_tier to the Anthropic API. + # Anthropic validates the value and returns an error for + # unsupported tiers. + optional_params["service_tier"] = value ## handle thinking tokens self.update_optional_params_with_thinking_tokens( diff --git a/litellm/types/llms/anthropic.py b/litellm/types/llms/anthropic.py index 5b8044911e5..91c23fd65eb 100644 --- a/litellm/types/llms/anthropic.py +++ b/litellm/types/llms/anthropic.py @@ -364,6 +364,7 @@ class AnthropicMessagesRequestOptionalParams(TypedDict, total=False): speed: Optional[str] # Fast mode support for Opus models output_config: Optional[AnthropicOutputConfig] # Configuration for Claude's output behavior cache_control: Optional[Dict[str, Any]] # Automatic prompt caching + service_tier: Optional[str] # Service tier for priority capacity (e.g. "auto", "standard_only") class AnthropicMessagesRequest(AnthropicMessagesRequestOptionalParams, total=False): diff --git a/tests/test_litellm/llms/anthropic/chat/test_anthropic_chat_transformation.py b/tests/test_litellm/llms/anthropic/chat/test_anthropic_chat_transformation.py index 6f03f630b5f..99571bf260f 100644 --- a/tests/test_litellm/llms/anthropic/chat/test_anthropic_chat_transformation.py +++ b/tests/test_litellm/llms/anthropic/chat/test_anthropic_chat_transformation.py @@ -3300,3 +3300,56 @@ def test_map_tool_helper_empty_parameters_get_default(): assert result is not None assert result["input_schema"]["type"] == "object" assert result["input_schema"].get("properties") == {} + + +@pytest.mark.parametrize("service_tier", ["auto", "standard_only"]) +def test_service_tier_forwarded_to_anthropic(service_tier: str): + """ + service_tier must be forwarded as-is to the Anthropic API request body. + + Fixes https://github.com/BerriAI/litellm/issues/23398 + """ + config = AnthropicConfig() + + result = config.map_openai_params( + non_default_params={"service_tier": service_tier}, + optional_params={}, + model="claude-sonnet-4-6", + drop_params=False, + ) + + assert result.get("service_tier") == service_tier + + +def test_service_tier_in_supported_params(): + """ + service_tier must appear in get_supported_openai_params so it is not + silently dropped before map_openai_params is called. + + Fixes https://github.com/BerriAI/litellm/issues/23398 + """ + config = AnthropicConfig() + assert "service_tier" in config.get_supported_openai_params( + model="claude-sonnet-4-6" + ) + + +@pytest.mark.parametrize("service_tier", ["default", "flex", "scale"]) +def test_service_tier_any_string_forwarded_to_anthropic(service_tier: str): + """ + service_tier is forwarded as-is to the Anthropic API for all string + values. Anthropic validates the value and returns an error for + unsupported tiers. + + Fixes https://github.com/BerriAI/litellm/issues/23398 + """ + config = AnthropicConfig() + + result = config.map_openai_params( + non_default_params={"service_tier": service_tier}, + optional_params={}, + model="claude-sonnet-4-6", + drop_params=False, + ) + + assert result.get("service_tier") == service_tier