From b6344c319b82d84f6fe8e34a90ab9948ad4feb0d Mon Sep 17 00:00:00 2001 From: Sameer Kankute Date: Fri, 6 Mar 2026 22:17:11 +0530 Subject: [PATCH 1/7] feat(openai): normalize reasoning_effort dict to string for chat completion API The OpenAI chat completion API expects reasoning_effort as a string ('none', 'low', 'medium', 'high', 'xhigh'). Config/deployments may pass the Responses API format: {'effort': 'high', 'summary': 'detailed'}. Fix BadRequestError when model config uses dict format by extracting the 'effort' value before passing to the API. Made-with: Cursor --- .../llms/openai/chat/gpt_5_transformation.py | 31 ++++++- .../openai/chat/o_series_transformation.py | 13 +++ ...odel_prices_and_context_window_backup.json | 85 ++----------------- .../llms/openai/test_gpt5_transformation.py | 25 ++++++ 4 files changed, 76 insertions(+), 78 deletions(-) diff --git a/litellm/llms/openai/chat/gpt_5_transformation.py b/litellm/llms/openai/chat/gpt_5_transformation.py index 358a94016a..af02235c34 100644 --- a/litellm/llms/openai/chat/gpt_5_transformation.py +++ b/litellm/llms/openai/chat/gpt_5_transformation.py @@ -1,6 +1,6 @@ """Support for OpenAI gpt-5 model family.""" -from typing import Optional +from typing import Optional, Union import litellm from litellm.utils import _supports_factory @@ -8,6 +8,23 @@ from litellm.utils import _supports_factory from .gpt_transformation import OpenAIGPTConfig +def _normalize_reasoning_effort_for_chat_completion( + value: Union[str, dict, None], +) -> Optional[str]: + """Convert reasoning_effort to the string format expected by OpenAI chat completion API. + + The chat completion API expects a simple string: 'none', 'low', 'medium', 'high', or 'xhigh'. + Config/deployments may pass the Responses API format: {'effort': 'high', 'summary': 'detailed'}. + """ + if value is None: + return None + if isinstance(value, str): + return value + if isinstance(value, dict) and "effort" in value: + return value["effort"] + return None + + class OpenAIGPT5Config(OpenAIGPTConfig): """Configuration for gpt-5 models including GPT-5-Codex variants. @@ -127,10 +144,20 @@ class OpenAIGPT5Config(OpenAIGPTConfig): drop_params=drop_params, ) - reasoning_effort = ( + # Normalize reasoning_effort: chat completion API expects a string, not a dict + # (e.g. {'effort': 'high', 'summary': 'detailed'} -> 'high') + raw_reasoning_effort = ( non_default_params.get("reasoning_effort") or optional_params.get("reasoning_effort") ) + normalized = _normalize_reasoning_effort_for_chat_completion(raw_reasoning_effort) + if raw_reasoning_effort is not None and normalized is not None: + if "reasoning_effort" in non_default_params: + non_default_params["reasoning_effort"] = normalized + if "reasoning_effort" in optional_params: + optional_params["reasoning_effort"] = normalized + + reasoning_effort = normalized or raw_reasoning_effort if reasoning_effort is not None and reasoning_effort == "xhigh": if not self._supports_reasoning_effort_level(model, "xhigh"): if litellm.drop_params or drop_params: diff --git a/litellm/llms/openai/chat/o_series_transformation.py b/litellm/llms/openai/chat/o_series_transformation.py index 0c5ee90b33..8c8321d434 100644 --- a/litellm/llms/openai/chat/o_series_transformation.py +++ b/litellm/llms/openai/chat/o_series_transformation.py @@ -24,6 +24,7 @@ from litellm.utils import ( supports_system_messages, ) +from .gpt_5_transformation import _normalize_reasoning_effort_for_chat_completion from .gpt_transformation import OpenAIGPTConfig @@ -104,6 +105,18 @@ class OpenAIOSeriesConfig(OpenAIGPTConfig): model: str, drop_params: bool, ): + # Normalize reasoning_effort: chat completion API expects a string, not a dict + raw_reasoning_effort = ( + non_default_params.get("reasoning_effort") + or optional_params.get("reasoning_effort") + ) + normalized = _normalize_reasoning_effort_for_chat_completion(raw_reasoning_effort) + if raw_reasoning_effort is not None and normalized is not None: + if "reasoning_effort" in non_default_params: + non_default_params["reasoning_effort"] = normalized + if "reasoning_effort" in optional_params: + optional_params["reasoning_effort"] = normalized + if "max_tokens" in non_default_params: optional_params["max_completion_tokens"] = non_default_params.pop( "max_tokens" diff --git a/litellm/model_prices_and_context_window_backup.json b/litellm/model_prices_and_context_window_backup.json index 93fb78d76d..03e03bf51e 100644 --- a/litellm/model_prices_and_context_window_backup.json +++ b/litellm/model_prices_and_context_window_backup.json @@ -20632,7 +20632,6 @@ "supports_tool_choice": true, "supports_service_tier": true, "supports_vision": true, - "supports_web_search": true, "supports_none_reasoning_effort": true, "supports_xhigh_reasoning_effort": false }, @@ -20671,7 +20670,6 @@ "supports_tool_choice": true, "supports_service_tier": true, "supports_vision": true, - "supports_web_search": true, "supports_none_reasoning_effort": true, "supports_xhigh_reasoning_effort": false }, @@ -20709,7 +20707,6 @@ "supports_system_messages": true, "supports_tool_choice": false, "supports_vision": true, - "supports_web_search": true, "supports_none_reasoning_effort": true, "supports_xhigh_reasoning_effort": false }, @@ -20749,9 +20746,9 @@ "supports_tool_choice": true, "supports_service_tier": true, "supports_vision": true, - "supports_web_search": true, "supports_none_reasoning_effort": true, - "supports_xhigh_reasoning_effort": true + "supports_xhigh_reasoning_effort": true, + "supports_web_search": true }, "gpt-5.2-2025-12-11": { "cache_read_input_token_cost": 1.75e-07, @@ -20789,9 +20786,9 @@ "supports_tool_choice": true, "supports_service_tier": true, "supports_vision": true, - "supports_web_search": true, "supports_none_reasoning_effort": true, - "supports_xhigh_reasoning_effort": true + "supports_xhigh_reasoning_effort": true, + "supports_web_search": true }, "gpt-5.2-chat-latest": { "cache_read_input_token_cost": 1.75e-07, @@ -20826,9 +20823,9 @@ "supports_system_messages": true, "supports_tool_choice": true, "supports_vision": true, - "supports_web_search": true, "supports_none_reasoning_effort": false, - "supports_xhigh_reasoning_effort": false + "supports_xhigh_reasoning_effort": false, + "supports_web_search": true }, "gpt-5.3-chat-latest": { "cache_read_input_token_cost": 1.75e-07, @@ -20863,9 +20860,9 @@ "supports_system_messages": true, "supports_tool_choice": true, "supports_vision": true, - "supports_web_search": true, "supports_none_reasoning_effort": false, - "supports_xhigh_reasoning_effort": false + "supports_xhigh_reasoning_effort": false, + "supports_web_search": true }, "gpt-5.2-pro": { "input_cost_per_token": 2.1e-05, @@ -21005,71 +21002,7 @@ "supports_system_messages": true, "supports_tool_choice": true, "supports_service_tier": true, - "supports_vision": true, - "supports_none_reasoning_effort": true, - "supports_xhigh_reasoning_effort": true - }, - "gpt-5.4-pro": { - "cache_read_input_token_cost": 2e-06, - "input_cost_per_token": 2e-05, - "litellm_provider": "openai", - "max_input_tokens": 1050000, - "max_output_tokens": 128000, - "max_tokens": 128000, - "mode": "responses", - "output_cost_per_token": 0.00012, - "supported_endpoints": [ - "/v1/responses" - ], - "supported_modalities": [ - "text", - "image" - ], - "supported_output_modalities": [ - "text" - ], - "supports_function_calling": true, - "supports_native_streaming": true, - "supports_parallel_function_calling": true, - "supports_pdf_input": true, - "supports_prompt_caching": true, - "supports_reasoning": true, - "supports_response_schema": true, - "supports_system_messages": true, - "supports_tool_choice": true, - "supports_vision": true, - "supports_web_search": true - }, - "gpt-5.4-pro-2026-03-05": { - "cache_read_input_token_cost": 2e-06, - "input_cost_per_token": 2e-05, - "litellm_provider": "openai", - "max_input_tokens": 1050000, - "max_output_tokens": 128000, - "max_tokens": 128000, - "mode": "responses", - "output_cost_per_token": 0.00012, - "supported_endpoints": [ - "/v1/responses" - ], - "supported_modalities": [ - "text", - "image" - ], - "supported_output_modalities": [ - "text" - ], - "supports_function_calling": true, - "supports_native_streaming": true, - "supports_parallel_function_calling": true, - "supports_pdf_input": true, - "supports_prompt_caching": true, - "supports_reasoning": true, - "supports_response_schema": true, - "supports_system_messages": true, - "supports_tool_choice": true, - "supports_vision": true, - "supports_web_search": true + "supports_vision": true }, "gpt-5.4-pro": { "cache_read_input_token_cost": 3e-06, diff --git a/tests/test_litellm/llms/openai/test_gpt5_transformation.py b/tests/test_litellm/llms/openai/test_gpt5_transformation.py index 4b64239d0e..415325d0da 100644 --- a/tests/test_litellm/llms/openai/test_gpt5_transformation.py +++ b/tests/test_litellm/llms/openai/test_gpt5_transformation.py @@ -324,6 +324,31 @@ def test_gpt5_4_pro_allows_reasoning_effort_xhigh(config: OpenAIConfig): assert params["reasoning_effort"] == "xhigh" +def test_gpt5_normalizes_reasoning_effort_dict_to_string(config: OpenAIConfig): + """Chat completion API expects reasoning_effort as a string, not a dict. + + Config/deployments may pass Responses API format: {'effort': 'high', 'summary': 'detailed'}. + """ + params = config.map_openai_params( + non_default_params={"reasoning_effort": {"effort": "high", "summary": "detailed"}}, + optional_params={}, + model="gpt-5.4", + drop_params=False, + ) + assert params["reasoning_effort"] == "high" + + +def test_gpt5_normalizes_reasoning_effort_dict_from_optional_params(config: OpenAIConfig): + """reasoning_effort dict in optional_params (e.g. from model config) is normalized.""" + params = config.map_openai_params( + non_default_params={}, + optional_params={"reasoning_effort": {"effort": "medium", "summary": "detailed"}}, + model="gpt-5.4", + drop_params=False, + ) + assert params["reasoning_effort"] == "medium" + + def test_gpt5_4_pro_rejects_non_default_temperature(config: OpenAIConfig): with pytest.raises(litellm.utils.UnsupportedParamsError): config.map_openai_params( From 14b52b131883f87f01fcacd1c6553c149e701da3 Mon Sep 17 00:00:00 2001 From: Sameer Kankute Date: Fri, 6 Mar 2026 22:20:47 +0530 Subject: [PATCH 2/7] feat(openai): drop reasoning_effort for gpt-5.4 when tools present Function calls not supported with reasoning_effort != 'none' on gpt-5.4. Drop reasoning_effort when tools are in the request (small minority of volume). Made-with: Cursor --- .../llms/openai/chat/gpt_5_transformation.py | 17 +++++++ .../llms/openai/test_gpt5_transformation.py | 50 +++++++++++++++++++ 2 files changed, 67 insertions(+) diff --git a/litellm/llms/openai/chat/gpt_5_transformation.py b/litellm/llms/openai/chat/gpt_5_transformation.py index af02235c34..beb76f3d80 100644 --- a/litellm/llms/openai/chat/gpt_5_transformation.py +++ b/litellm/llms/openai/chat/gpt_5_transformation.py @@ -64,6 +64,12 @@ class OpenAIGPT5Config(OpenAIGPTConfig): model_name = model.split("/")[-1] return model_name.startswith("gpt-5.2") or model_name.startswith("gpt-5.4") + @classmethod + def is_model_gpt_5_4_model(cls, model: str) -> bool: + """Check if the model is a gpt-5.4 variant (including pro).""" + model_name = model.split("/")[-1] + return model_name.startswith("gpt-5.4") + @classmethod def _supports_reasoning_effort_level(cls, model: str, level: str) -> bool: """Check if the model supports a specific reasoning_effort level. @@ -179,6 +185,17 @@ class OpenAIGPT5Config(OpenAIGPTConfig): "max_tokens" ) + # gpt-5.4: function calls not supported when reasoning_effort != "none" + # Drop reasoning_effort when tools are present (small minority of volume) + if self.is_model_gpt_5_4_model(model): + has_tools = bool( + non_default_params.get("tools") or optional_params.get("tools") + ) + if has_tools and reasoning_effort not in (None, "none"): + non_default_params.pop("reasoning_effort", None) + optional_params.pop("reasoning_effort", None) + reasoning_effort = None + # gpt-5.1/5.2 support logprobs, top_p, top_logprobs only when reasoning_effort="none" supports_none = self._supports_reasoning_effort_level(model, "none") if supports_none: diff --git a/tests/test_litellm/llms/openai/test_gpt5_transformation.py b/tests/test_litellm/llms/openai/test_gpt5_transformation.py index 415325d0da..b136f8774b 100644 --- a/tests/test_litellm/llms/openai/test_gpt5_transformation.py +++ b/tests/test_litellm/llms/openai/test_gpt5_transformation.py @@ -349,6 +349,56 @@ def test_gpt5_normalizes_reasoning_effort_dict_from_optional_params(config: Open assert params["reasoning_effort"] == "medium" +def test_gpt5_4_drops_reasoning_effort_when_tools_present(config: OpenAIConfig): + """gpt-5.4: function calls not supported with reasoning_effort != 'none'. Drop reasoning_effort.""" + tools = [{"type": "function", "function": {"name": "test", "description": "test"}}] + params = config.map_openai_params( + non_default_params={"reasoning_effort": "high", "tools": tools}, + optional_params={}, + model="gpt-5.4", + drop_params=False, + ) + assert "reasoning_effort" not in params + assert params["tools"] == tools + + +def test_gpt5_4_keeps_reasoning_effort_when_no_tools(config: OpenAIConfig): + """reasoning_effort is kept when tools are not present.""" + params = config.map_openai_params( + non_default_params={"reasoning_effort": "high"}, + optional_params={}, + model="gpt-5.4", + drop_params=False, + ) + assert params["reasoning_effort"] == "high" + + +def test_gpt5_4_keeps_reasoning_effort_none_with_tools(config: OpenAIConfig): + """reasoning_effort='none' is kept when tools are present.""" + tools = [{"type": "function", "function": {"name": "test", "description": "test"}}] + params = config.map_openai_params( + non_default_params={"reasoning_effort": "none", "tools": tools}, + optional_params={}, + model="gpt-5.4", + drop_params=False, + ) + assert params["reasoning_effort"] == "none" + assert params["tools"] == tools + + +def test_gpt5_2_keeps_reasoning_effort_with_tools(config: OpenAIConfig): + """gpt-5.2: reasoning_effort drop only applies to gpt-5.4, not gpt-5.2.""" + tools = [{"type": "function", "function": {"name": "test", "description": "test"}}] + params = config.map_openai_params( + non_default_params={"reasoning_effort": "high", "tools": tools}, + optional_params={}, + model="gpt-5.2", + drop_params=False, + ) + assert params["reasoning_effort"] == "high" + assert params["tools"] == tools + + def test_gpt5_4_pro_rejects_non_default_temperature(config: OpenAIConfig): with pytest.raises(litellm.utils.UnsupportedParamsError): config.map_openai_params( From d8f139fe4dfadb2f60727bf5e8c6ccbf0196917c Mon Sep 17 00:00:00 2001 From: Sameer Kankute Date: Fri, 6 Mar 2026 22:26:14 +0530 Subject: [PATCH 3/7] feat(openai): add 272K tier pricing for GPT-5.4/5.4-pro Prompts >272K input tokens priced at 2x input, 1.5x output for full session (standard, batch, flex). Applies to models with 1.05M context window (gpt-5.4, gpt-5.4-pro). - Add input/output_cost_per_token_above_272k_tokens to model_prices - Add above_272k fields to ModelInfoBase and get_model_info extraction - Add test_generic_cost_per_token_gpt54_above_272k_tokens Made-with: Cursor --- ...odel_prices_and_context_window_backup.json | 24 +++++++++++++++++ litellm/types/utils.py | 7 +++++ litellm/utils.py | 9 +++++++ model_prices_and_context_window.json | 24 +++++++++++++++++ .../llm_cost_calc/test_llm_cost_calc_utils.py | 26 +++++++++++++++++++ tests/test_litellm/test_utils.py | 10 +++++++ 6 files changed, 100 insertions(+) diff --git a/litellm/model_prices_and_context_window_backup.json b/litellm/model_prices_and_context_window_backup.json index 03e03bf51e..f1ca7cd83b 100644 --- a/litellm/model_prices_and_context_window_backup.json +++ b/litellm/model_prices_and_context_window_backup.json @@ -20932,16 +20932,22 @@ }, "gpt-5.4": { "cache_read_input_token_cost": 2.5e-07, + "cache_read_input_token_cost_above_272k_tokens": 5e-07, "cache_read_input_token_cost_priority": 5e-07, + "cache_read_input_token_cost_above_272k_tokens_priority": 1e-06, "input_cost_per_token": 2.5e-06, + "input_cost_per_token_above_272k_tokens": 5e-06, "input_cost_per_token_priority": 5e-06, + "input_cost_per_token_above_272k_tokens_priority": 1e-05, "litellm_provider": "openai", "max_input_tokens": 1050000, "max_output_tokens": 128000, "max_tokens": 128000, "mode": "responses", "output_cost_per_token": 1.5e-05, + "output_cost_per_token_above_272k_tokens": 2.25e-05, "output_cost_per_token_priority": 2.25e-05, + "output_cost_per_token_above_272k_tokens_priority": 3.375e-05, "supported_endpoints": [ "/v1/chat/completions", "/v1/batch", @@ -20970,16 +20976,22 @@ }, "gpt-5.4-2026-03-05": { "cache_read_input_token_cost": 2.5e-07, + "cache_read_input_token_cost_above_272k_tokens": 5e-07, "cache_read_input_token_cost_priority": 5e-07, + "cache_read_input_token_cost_above_272k_tokens_priority": 1e-06, "input_cost_per_token": 2.5e-06, + "input_cost_per_token_above_272k_tokens": 5e-06, "input_cost_per_token_priority": 5e-06, + "input_cost_per_token_above_272k_tokens_priority": 1e-05, "litellm_provider": "openai", "max_input_tokens": 1050000, "max_output_tokens": 128000, "max_tokens": 128000, "mode": "responses", "output_cost_per_token": 1.5e-05, + "output_cost_per_token_above_272k_tokens": 2.25e-05, "output_cost_per_token_priority": 2.25e-05, + "output_cost_per_token_above_272k_tokens_priority": 3.375e-05, "supported_endpoints": [ "/v1/chat/completions", "/v1/batch", @@ -21006,16 +21018,22 @@ }, "gpt-5.4-pro": { "cache_read_input_token_cost": 3e-06, + "cache_read_input_token_cost_above_272k_tokens": 6e-06, "cache_read_input_token_cost_priority": 6e-06, + "cache_read_input_token_cost_above_272k_tokens_priority": 1.2e-05, "input_cost_per_token": 3e-05, + "input_cost_per_token_above_272k_tokens": 6e-05, "input_cost_per_token_priority": 6e-05, + "input_cost_per_token_above_272k_tokens_priority": 1.2e-04, "litellm_provider": "openai", "max_input_tokens": 1050000, "max_output_tokens": 128000, "max_tokens": 128000, "mode": "responses", "output_cost_per_token": 1.8e-04, + "output_cost_per_token_above_272k_tokens": 2.7e-04, "output_cost_per_token_priority": 2.7e-04, + "output_cost_per_token_above_272k_tokens_priority": 4.05e-04, "supported_endpoints": [ "/v1/chat/completions", "/v1/batch", @@ -21045,16 +21063,22 @@ }, "gpt-5.4-pro-2026-03-05": { "cache_read_input_token_cost": 3e-06, + "cache_read_input_token_cost_above_272k_tokens": 6e-06, "cache_read_input_token_cost_priority": 6e-06, + "cache_read_input_token_cost_above_272k_tokens_priority": 1.2e-05, "input_cost_per_token": 3e-05, + "input_cost_per_token_above_272k_tokens": 6e-05, "input_cost_per_token_priority": 6e-05, + "input_cost_per_token_above_272k_tokens_priority": 1.2e-04, "litellm_provider": "openai", "max_input_tokens": 1050000, "max_output_tokens": 128000, "max_tokens": 128000, "mode": "responses", "output_cost_per_token": 1.8e-04, + "output_cost_per_token_above_272k_tokens": 2.7e-04, "output_cost_per_token_priority": 2.7e-04, + "output_cost_per_token_above_272k_tokens_priority": 4.05e-04, "supported_endpoints": [ "/v1/chat/completions", "/v1/batch", diff --git a/litellm/types/utils.py b/litellm/types/utils.py index 4a7be0d677..fb646f7534 100644 --- a/litellm/types/utils.py +++ b/litellm/types/utils.py @@ -183,12 +183,16 @@ class ModelInfoBase(ProviderSpecificModelInfo, total=False): float ] # OpenAI priority service tier pricing cache_read_input_token_cost_above_200k_tokens: Optional[float] + cache_read_input_token_cost_above_272k_tokens: Optional[float] input_cost_per_character: Optional[float] # only for vertex ai models input_cost_per_audio_token: Optional[float] input_cost_per_token_above_128k_tokens: Optional[float] # only for vertex ai models input_cost_per_token_above_200k_tokens: Optional[ float ] # only for vertex ai gemini-2.5-pro models + input_cost_per_token_above_272k_tokens: Optional[ + float + ] # GPT-5.4/5.4-pro: prompts >272K priced at 2x input input_cost_per_character_above_128k_tokens: Optional[ float ] # only for vertex ai models @@ -213,6 +217,9 @@ class ModelInfoBase(ProviderSpecificModelInfo, total=False): output_cost_per_token_above_200k_tokens: Optional[ float ] # only for vertex ai gemini-2.5-pro models + output_cost_per_token_above_272k_tokens: Optional[ + float + ] # GPT-5.4/5.4-pro: prompts >272K priced at 1.5x output output_cost_per_character_above_128k_tokens: Optional[ float ] # only for vertex ai models diff --git a/litellm/utils.py b/litellm/utils.py index d764cc81e7..72423f8483 100644 --- a/litellm/utils.py +++ b/litellm/utils.py @@ -5639,6 +5639,9 @@ def _get_model_info_helper( # noqa: PLR0915 cache_read_input_token_cost_above_200k_tokens=_model_info.get( "cache_read_input_token_cost_above_200k_tokens", None ), + cache_read_input_token_cost_above_272k_tokens=_model_info.get( + "cache_read_input_token_cost_above_272k_tokens", None + ), cache_read_input_token_cost_flex=_model_info.get( "cache_read_input_token_cost_flex", None ), @@ -5657,6 +5660,9 @@ def _get_model_info_helper( # noqa: PLR0915 input_cost_per_token_above_200k_tokens=_model_info.get( "input_cost_per_token_above_200k_tokens", None ), + input_cost_per_token_above_272k_tokens=_model_info.get( + "input_cost_per_token_above_272k_tokens", None + ), input_cost_per_query=_model_info.get("input_cost_per_query", None), input_cost_per_second=_model_info.get("input_cost_per_second", None), input_cost_per_audio_token=_model_info.get( @@ -5703,6 +5709,9 @@ def _get_model_info_helper( # noqa: PLR0915 output_cost_per_token_above_200k_tokens=_model_info.get( "output_cost_per_token_above_200k_tokens", None ), + output_cost_per_token_above_272k_tokens=_model_info.get( + "output_cost_per_token_above_272k_tokens", None + ), output_cost_per_second=_model_info.get("output_cost_per_second", None), output_cost_per_video_per_second=_model_info.get( "output_cost_per_video_per_second", None diff --git a/model_prices_and_context_window.json b/model_prices_and_context_window.json index 03e03bf51e..f1ca7cd83b 100644 --- a/model_prices_and_context_window.json +++ b/model_prices_and_context_window.json @@ -20932,16 +20932,22 @@ }, "gpt-5.4": { "cache_read_input_token_cost": 2.5e-07, + "cache_read_input_token_cost_above_272k_tokens": 5e-07, "cache_read_input_token_cost_priority": 5e-07, + "cache_read_input_token_cost_above_272k_tokens_priority": 1e-06, "input_cost_per_token": 2.5e-06, + "input_cost_per_token_above_272k_tokens": 5e-06, "input_cost_per_token_priority": 5e-06, + "input_cost_per_token_above_272k_tokens_priority": 1e-05, "litellm_provider": "openai", "max_input_tokens": 1050000, "max_output_tokens": 128000, "max_tokens": 128000, "mode": "responses", "output_cost_per_token": 1.5e-05, + "output_cost_per_token_above_272k_tokens": 2.25e-05, "output_cost_per_token_priority": 2.25e-05, + "output_cost_per_token_above_272k_tokens_priority": 3.375e-05, "supported_endpoints": [ "/v1/chat/completions", "/v1/batch", @@ -20970,16 +20976,22 @@ }, "gpt-5.4-2026-03-05": { "cache_read_input_token_cost": 2.5e-07, + "cache_read_input_token_cost_above_272k_tokens": 5e-07, "cache_read_input_token_cost_priority": 5e-07, + "cache_read_input_token_cost_above_272k_tokens_priority": 1e-06, "input_cost_per_token": 2.5e-06, + "input_cost_per_token_above_272k_tokens": 5e-06, "input_cost_per_token_priority": 5e-06, + "input_cost_per_token_above_272k_tokens_priority": 1e-05, "litellm_provider": "openai", "max_input_tokens": 1050000, "max_output_tokens": 128000, "max_tokens": 128000, "mode": "responses", "output_cost_per_token": 1.5e-05, + "output_cost_per_token_above_272k_tokens": 2.25e-05, "output_cost_per_token_priority": 2.25e-05, + "output_cost_per_token_above_272k_tokens_priority": 3.375e-05, "supported_endpoints": [ "/v1/chat/completions", "/v1/batch", @@ -21006,16 +21018,22 @@ }, "gpt-5.4-pro": { "cache_read_input_token_cost": 3e-06, + "cache_read_input_token_cost_above_272k_tokens": 6e-06, "cache_read_input_token_cost_priority": 6e-06, + "cache_read_input_token_cost_above_272k_tokens_priority": 1.2e-05, "input_cost_per_token": 3e-05, + "input_cost_per_token_above_272k_tokens": 6e-05, "input_cost_per_token_priority": 6e-05, + "input_cost_per_token_above_272k_tokens_priority": 1.2e-04, "litellm_provider": "openai", "max_input_tokens": 1050000, "max_output_tokens": 128000, "max_tokens": 128000, "mode": "responses", "output_cost_per_token": 1.8e-04, + "output_cost_per_token_above_272k_tokens": 2.7e-04, "output_cost_per_token_priority": 2.7e-04, + "output_cost_per_token_above_272k_tokens_priority": 4.05e-04, "supported_endpoints": [ "/v1/chat/completions", "/v1/batch", @@ -21045,16 +21063,22 @@ }, "gpt-5.4-pro-2026-03-05": { "cache_read_input_token_cost": 3e-06, + "cache_read_input_token_cost_above_272k_tokens": 6e-06, "cache_read_input_token_cost_priority": 6e-06, + "cache_read_input_token_cost_above_272k_tokens_priority": 1.2e-05, "input_cost_per_token": 3e-05, + "input_cost_per_token_above_272k_tokens": 6e-05, "input_cost_per_token_priority": 6e-05, + "input_cost_per_token_above_272k_tokens_priority": 1.2e-04, "litellm_provider": "openai", "max_input_tokens": 1050000, "max_output_tokens": 128000, "max_tokens": 128000, "mode": "responses", "output_cost_per_token": 1.8e-04, + "output_cost_per_token_above_272k_tokens": 2.7e-04, "output_cost_per_token_priority": 2.7e-04, + "output_cost_per_token_above_272k_tokens_priority": 4.05e-04, "supported_endpoints": [ "/v1/chat/completions", "/v1/batch", diff --git a/tests/test_litellm/litellm_core_utils/llm_cost_calc/test_llm_cost_calc_utils.py b/tests/test_litellm/litellm_core_utils/llm_cost_calc/test_llm_cost_calc_utils.py index 2e033b6f06..91e8da886d 100644 --- a/tests/test_litellm/litellm_core_utils/llm_cost_calc/test_llm_cost_calc_utils.py +++ b/tests/test_litellm/litellm_core_utils/llm_cost_calc/test_llm_cost_calc_utils.py @@ -295,6 +295,32 @@ def test_generic_cost_per_token_above_200k_tokens(): ) +def test_generic_cost_per_token_gpt54_above_272k_tokens(): + """GPT-5.4/5.4-pro: prompts >272K input tokens priced at 2x input, 1.5x output.""" + model = "gpt-5.4" + custom_llm_provider = "openai" + os.environ["LITELLM_LOCAL_MODEL_COST_MAP"] = "True" + litellm.model_cost = litellm.get_model_cost_map(url="") + + model_cost_map = litellm.model_cost[model] + prompt_tokens = 273000 # Above 272K threshold + completion_tokens = 1000 + usage = Usage( + prompt_tokens=prompt_tokens, + completion_tokens=completion_tokens, + total_tokens=prompt_tokens + completion_tokens, + ) + prompt_cost, completion_cost = generic_cost_per_token( + model=model, + usage=usage, + custom_llm_provider=custom_llm_provider, + ) + expected_prompt = model_cost_map["input_cost_per_token_above_272k_tokens"] * prompt_tokens + expected_completion = model_cost_map["output_cost_per_token_above_272k_tokens"] * completion_tokens + assert round(prompt_cost, 10) == round(expected_prompt, 10) + assert round(completion_cost, 10) == round(expected_completion, 10) + + def test_generic_cost_per_token_anthropic_prompt_caching(): model = "claude-sonnet-4@20250514" usage = Usage( diff --git a/tests/test_litellm/test_utils.py b/tests/test_litellm/test_utils.py index 952cf5ed70..70818af547 100644 --- a/tests/test_litellm/test_utils.py +++ b/tests/test_litellm/test_utils.py @@ -513,6 +513,8 @@ def validate_model_cost_values(model_data, exceptions=None): "output_cost_per_token_above_128k_tokens", "input_cost_per_token_above_200k_tokens", "output_cost_per_token_above_200k_tokens", + "input_cost_per_token_above_272k_tokens", + "output_cost_per_token_above_272k_tokens", "input_cost_per_character_above_128k_tokens", "output_cost_per_character_above_128k_tokens", "input_cost_per_image_above_128k_tokens", @@ -603,6 +605,7 @@ def test_aaamodel_prices_and_context_window_json_is_valid(): "cache_creation_input_token_cost_above_200k_tokens": {"type": "number"}, "cache_read_input_token_cost": {"type": "number"}, "cache_read_input_token_cost_above_200k_tokens": {"type": "number"}, + "cache_read_input_token_cost_above_272k_tokens": {"type": "number"}, "cache_creation_input_token_cost_above_1hr_above_200k_tokens": {"type": "number"}, "cache_read_input_audio_token_cost": {"type": "number"}, "cache_read_input_token_cost_per_audio_token": {"type": "number"}, @@ -618,16 +621,20 @@ def test_aaamodel_prices_and_context_window_json_is_valid(): "input_cost_per_image_above_128k_tokens": {"type": "number"}, "input_cost_per_image_token": {"type": "number"}, "input_cost_per_token_above_200k_tokens": {"type": "number"}, + "input_cost_per_token_above_272k_tokens": {"type": "number"}, "cache_read_input_token_cost_flex": {"type": "number"}, "cache_read_input_token_cost_priority": {"type": "number"}, "cache_read_input_token_cost_above_200k_tokens_priority": {"type": "number"}, + "cache_read_input_token_cost_above_272k_tokens_priority": {"type": "number"}, "input_cost_per_token_flex": {"type": "number"}, "input_cost_per_token_priority": {"type": "number"}, "input_cost_per_token_above_200k_tokens_priority": {"type": "number"}, + "input_cost_per_token_above_272k_tokens_priority": {"type": "number"}, "input_cost_per_audio_token_priority": {"type": "number"}, "output_cost_per_token_flex": {"type": "number"}, "output_cost_per_token_priority": {"type": "number"}, "output_cost_per_token_above_200k_tokens_priority": {"type": "number"}, + "output_cost_per_token_above_272k_tokens_priority": {"type": "number"}, "input_cost_per_pixel": {"type": "number"}, "input_cost_per_query": {"type": "number"}, "input_cost_per_request": {"type": "number"}, @@ -694,6 +701,7 @@ def test_aaamodel_prices_and_context_window_json_is_valid(): "output_cost_per_token": {"type": "number"}, "output_cost_per_token_above_128k_tokens": {"type": "number"}, "output_cost_per_token_above_200k_tokens": {"type": "number"}, + "output_cost_per_token_above_272k_tokens": {"type": "number"}, "output_cost_per_image_above_1024_and_1024_pixels": {"type": "number"}, "output_cost_per_image_above_1024_and_1024_pixels_and_premium_image": { "type": "number" @@ -732,6 +740,8 @@ def test_aaamodel_prices_and_context_window_json_is_valid(): "supports_web_search": {"type": "boolean"}, "supports_url_context": {"type": "boolean"}, "supports_reasoning": {"type": "boolean"}, + "supports_none_reasoning_effort": {"type": "boolean"}, + "supports_xhigh_reasoning_effort": {"type": "boolean"}, "supports_service_tier": {"type": "boolean"}, "supports_preset": {"type": "boolean"}, "tool_use_system_prompt_tokens": {"type": "number"}, From 91fc91c9c34e60dd85156edc0bd1ceecae2f2078 Mon Sep 17 00:00:00 2001 From: Sameer Kankute Date: Fri, 6 Mar 2026 22:27:09 +0530 Subject: [PATCH 4/7] Fixed o file --- litellm/llms/openai/chat/o_series_transformation.py | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/litellm/llms/openai/chat/o_series_transformation.py b/litellm/llms/openai/chat/o_series_transformation.py index 8c8321d434..0c5ee90b33 100644 --- a/litellm/llms/openai/chat/o_series_transformation.py +++ b/litellm/llms/openai/chat/o_series_transformation.py @@ -24,7 +24,6 @@ from litellm.utils import ( supports_system_messages, ) -from .gpt_5_transformation import _normalize_reasoning_effort_for_chat_completion from .gpt_transformation import OpenAIGPTConfig @@ -105,18 +104,6 @@ class OpenAIOSeriesConfig(OpenAIGPTConfig): model: str, drop_params: bool, ): - # Normalize reasoning_effort: chat completion API expects a string, not a dict - raw_reasoning_effort = ( - non_default_params.get("reasoning_effort") - or optional_params.get("reasoning_effort") - ) - normalized = _normalize_reasoning_effort_for_chat_completion(raw_reasoning_effort) - if raw_reasoning_effort is not None and normalized is not None: - if "reasoning_effort" in non_default_params: - non_default_params["reasoning_effort"] = normalized - if "reasoning_effort" in optional_params: - optional_params["reasoning_effort"] = normalized - if "max_tokens" in non_default_params: optional_params["max_completion_tokens"] = non_default_params.pop( "max_tokens" From a7967801b00ebb1cdfea420c0e3bb06b2ddc4198 Mon Sep 17 00:00:00 2001 From: Sameer Kankute Date: Fri, 6 Mar 2026 22:29:25 +0530 Subject: [PATCH 5/7] Fixed o file --- litellm/model_prices_and_context_window_backup.json | 1 + model_prices_and_context_window.json | 1 + 2 files changed, 2 insertions(+) diff --git a/litellm/model_prices_and_context_window_backup.json b/litellm/model_prices_and_context_window_backup.json index f1ca7cd83b..56ca783ad6 100644 --- a/litellm/model_prices_and_context_window_backup.json +++ b/litellm/model_prices_and_context_window_backup.json @@ -20632,6 +20632,7 @@ "supports_tool_choice": true, "supports_service_tier": true, "supports_vision": true, + "supports_web_search": true, "supports_none_reasoning_effort": true, "supports_xhigh_reasoning_effort": false }, diff --git a/model_prices_and_context_window.json b/model_prices_and_context_window.json index f1ca7cd83b..56ca783ad6 100644 --- a/model_prices_and_context_window.json +++ b/model_prices_and_context_window.json @@ -20632,6 +20632,7 @@ "supports_tool_choice": true, "supports_service_tier": true, "supports_vision": true, + "supports_web_search": true, "supports_none_reasoning_effort": true, "supports_xhigh_reasoning_effort": false }, From dd7ab3f01f3c4e2cd94beb041c76628614a0904d Mon Sep 17 00:00:00 2001 From: Sameer Kankute Date: Fri, 6 Mar 2026 22:46:32 +0530 Subject: [PATCH 6/7] Fix model map --- ...model_prices_and_context_window_backup.json | 18 ++++++++++-------- model_prices_and_context_window.json | 18 ++++++++++-------- 2 files changed, 20 insertions(+), 16 deletions(-) diff --git a/litellm/model_prices_and_context_window_backup.json b/litellm/model_prices_and_context_window_backup.json index 56ca783ad6..b5d75476dc 100644 --- a/litellm/model_prices_and_context_window_backup.json +++ b/litellm/model_prices_and_context_window_backup.json @@ -20671,6 +20671,7 @@ "supports_tool_choice": true, "supports_service_tier": true, "supports_vision": true, + "supports_web_search": true, "supports_none_reasoning_effort": true, "supports_xhigh_reasoning_effort": false }, @@ -20708,6 +20709,7 @@ "supports_system_messages": true, "supports_tool_choice": false, "supports_vision": true, + "supports_web_search": true, "supports_none_reasoning_effort": true, "supports_xhigh_reasoning_effort": false }, @@ -20747,9 +20749,9 @@ "supports_tool_choice": true, "supports_service_tier": true, "supports_vision": true, + "supports_web_search": true, "supports_none_reasoning_effort": true, - "supports_xhigh_reasoning_effort": true, - "supports_web_search": true + "supports_xhigh_reasoning_effort": true }, "gpt-5.2-2025-12-11": { "cache_read_input_token_cost": 1.75e-07, @@ -20787,9 +20789,9 @@ "supports_tool_choice": true, "supports_service_tier": true, "supports_vision": true, + "supports_web_search": true, "supports_none_reasoning_effort": true, - "supports_xhigh_reasoning_effort": true, - "supports_web_search": true + "supports_xhigh_reasoning_effort": true }, "gpt-5.2-chat-latest": { "cache_read_input_token_cost": 1.75e-07, @@ -20824,9 +20826,9 @@ "supports_system_messages": true, "supports_tool_choice": true, "supports_vision": true, + "supports_web_search": true, "supports_none_reasoning_effort": false, - "supports_xhigh_reasoning_effort": false, - "supports_web_search": true + "supports_xhigh_reasoning_effort": false }, "gpt-5.3-chat-latest": { "cache_read_input_token_cost": 1.75e-07, @@ -20861,9 +20863,9 @@ "supports_system_messages": true, "supports_tool_choice": true, "supports_vision": true, + "supports_web_search": true, "supports_none_reasoning_effort": false, - "supports_xhigh_reasoning_effort": false, - "supports_web_search": true + "supports_xhigh_reasoning_effort": false }, "gpt-5.2-pro": { "input_cost_per_token": 2.1e-05, diff --git a/model_prices_and_context_window.json b/model_prices_and_context_window.json index 56ca783ad6..b5d75476dc 100644 --- a/model_prices_and_context_window.json +++ b/model_prices_and_context_window.json @@ -20671,6 +20671,7 @@ "supports_tool_choice": true, "supports_service_tier": true, "supports_vision": true, + "supports_web_search": true, "supports_none_reasoning_effort": true, "supports_xhigh_reasoning_effort": false }, @@ -20708,6 +20709,7 @@ "supports_system_messages": true, "supports_tool_choice": false, "supports_vision": true, + "supports_web_search": true, "supports_none_reasoning_effort": true, "supports_xhigh_reasoning_effort": false }, @@ -20747,9 +20749,9 @@ "supports_tool_choice": true, "supports_service_tier": true, "supports_vision": true, + "supports_web_search": true, "supports_none_reasoning_effort": true, - "supports_xhigh_reasoning_effort": true, - "supports_web_search": true + "supports_xhigh_reasoning_effort": true }, "gpt-5.2-2025-12-11": { "cache_read_input_token_cost": 1.75e-07, @@ -20787,9 +20789,9 @@ "supports_tool_choice": true, "supports_service_tier": true, "supports_vision": true, + "supports_web_search": true, "supports_none_reasoning_effort": true, - "supports_xhigh_reasoning_effort": true, - "supports_web_search": true + "supports_xhigh_reasoning_effort": true }, "gpt-5.2-chat-latest": { "cache_read_input_token_cost": 1.75e-07, @@ -20824,9 +20826,9 @@ "supports_system_messages": true, "supports_tool_choice": true, "supports_vision": true, + "supports_web_search": true, "supports_none_reasoning_effort": false, - "supports_xhigh_reasoning_effort": false, - "supports_web_search": true + "supports_xhigh_reasoning_effort": false }, "gpt-5.3-chat-latest": { "cache_read_input_token_cost": 1.75e-07, @@ -20861,9 +20863,9 @@ "supports_system_messages": true, "supports_tool_choice": true, "supports_vision": true, + "supports_web_search": true, "supports_none_reasoning_effort": false, - "supports_xhigh_reasoning_effort": false, - "supports_web_search": true + "supports_xhigh_reasoning_effort": false }, "gpt-5.2-pro": { "input_cost_per_token": 2.1e-05, From 7d524fe5a81a308cc84173d6e266f25a567efeb8 Mon Sep 17 00:00:00 2001 From: Sameer Kankute Date: Fri, 6 Mar 2026 22:49:37 +0530 Subject: [PATCH 7/7] Fix model map --- litellm/model_prices_and_context_window_backup.json | 8 ++++---- model_prices_and_context_window.json | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/litellm/model_prices_and_context_window_backup.json b/litellm/model_prices_and_context_window_backup.json index b5d75476dc..7e2590f696 100644 --- a/litellm/model_prices_and_context_window_backup.json +++ b/litellm/model_prices_and_context_window_backup.json @@ -20946,7 +20946,7 @@ "max_input_tokens": 1050000, "max_output_tokens": 128000, "max_tokens": 128000, - "mode": "responses", + "mode": "chat", "output_cost_per_token": 1.5e-05, "output_cost_per_token_above_272k_tokens": 2.25e-05, "output_cost_per_token_priority": 2.25e-05, @@ -20990,7 +20990,7 @@ "max_input_tokens": 1050000, "max_output_tokens": 128000, "max_tokens": 128000, - "mode": "responses", + "mode": "chat", "output_cost_per_token": 1.5e-05, "output_cost_per_token_above_272k_tokens": 2.25e-05, "output_cost_per_token_priority": 2.25e-05, @@ -21032,7 +21032,7 @@ "max_input_tokens": 1050000, "max_output_tokens": 128000, "max_tokens": 128000, - "mode": "responses", + "mode": "chat", "output_cost_per_token": 1.8e-04, "output_cost_per_token_above_272k_tokens": 2.7e-04, "output_cost_per_token_priority": 2.7e-04, @@ -21077,7 +21077,7 @@ "max_input_tokens": 1050000, "max_output_tokens": 128000, "max_tokens": 128000, - "mode": "responses", + "mode": "chat", "output_cost_per_token": 1.8e-04, "output_cost_per_token_above_272k_tokens": 2.7e-04, "output_cost_per_token_priority": 2.7e-04, diff --git a/model_prices_and_context_window.json b/model_prices_and_context_window.json index b5d75476dc..7e2590f696 100644 --- a/model_prices_and_context_window.json +++ b/model_prices_and_context_window.json @@ -20946,7 +20946,7 @@ "max_input_tokens": 1050000, "max_output_tokens": 128000, "max_tokens": 128000, - "mode": "responses", + "mode": "chat", "output_cost_per_token": 1.5e-05, "output_cost_per_token_above_272k_tokens": 2.25e-05, "output_cost_per_token_priority": 2.25e-05, @@ -20990,7 +20990,7 @@ "max_input_tokens": 1050000, "max_output_tokens": 128000, "max_tokens": 128000, - "mode": "responses", + "mode": "chat", "output_cost_per_token": 1.5e-05, "output_cost_per_token_above_272k_tokens": 2.25e-05, "output_cost_per_token_priority": 2.25e-05, @@ -21032,7 +21032,7 @@ "max_input_tokens": 1050000, "max_output_tokens": 128000, "max_tokens": 128000, - "mode": "responses", + "mode": "chat", "output_cost_per_token": 1.8e-04, "output_cost_per_token_above_272k_tokens": 2.7e-04, "output_cost_per_token_priority": 2.7e-04, @@ -21077,7 +21077,7 @@ "max_input_tokens": 1050000, "max_output_tokens": 128000, "max_tokens": 128000, - "mode": "responses", + "mode": "chat", "output_cost_per_token": 1.8e-04, "output_cost_per_token_above_272k_tokens": 2.7e-04, "output_cost_per_token_priority": 2.7e-04,