From d34daeeda0671c187dc962f3ee48a40fd947167b Mon Sep 17 00:00:00 2001 From: Pradyumna Yadav Date: Fri, 13 Mar 2026 02:10:38 +0530 Subject: [PATCH] fix: forward service_tier param to Anthropic API (#23401) * fix: forward service_tier param to Anthropic API service_tier was silently dropped because it was missing from AnthropicConfig.get_supported_openai_params(). Add it to the supported params list and add a passthrough mapping in map_openai_params() so it is forwarded as-is to the request body. Fixes #23398 * fix: add service_tier to AnthropicMessagesRequestOptionalParams TypedDict * fix: restrict service_tier to Anthropic-valid values only * fix: honour drop_params flag for invalid service_tier values on Anthropic When drop_params=False, passing an unrecognised service_tier (e.g. the OpenAI-specific "default"/"flex"/"scale") now raises UnsupportedParamsError instead of silently discarding the value. When drop_params=True the value is still silently dropped. Also tightens the TypedDict field from Optional[str] to Optional[Literal["auto", "standard_only"]] for static analysis. Fixes https://github.com/BerriAI/litellm/issues/23398 Co-Authored-By: Claude Sonnet 4.6 * fix: silently drop unrecognised service_tier values for backward-compatibility * fix: raise UnsupportedParamsError for invalid service_tier when drop_params=False * values check for service tier * verbose logging for supported values of service_tier * support future additions to service_tier values * fix: forward service_tier param to Anthropic API as pure passthrough --------- Co-authored-by: Claude Sonnet 4.6 --- litellm/llms/anthropic/chat/transformation.py | 6 +++ litellm/types/llms/anthropic.py | 1 + .../test_anthropic_chat_transformation.py | 53 +++++++++++++++++++ 3 files changed, 60 insertions(+) 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