From 34c93645e9aaed8546032ef52ff71b54b264e454 Mon Sep 17 00:00:00 2001 From: mateo-berri <277851410+mateo-berri@users.noreply.github.com> Date: Fri, 24 Apr 2026 14:30:06 -0700 Subject: [PATCH] fix(openai): gpt-5.5 does not support reasoning_effort=minimal Verified against OpenAI's live Chat Completions API on 2026-04-24: POST /v1/chat/completions {"model": "gpt-5.5", "reasoning_effort": "minimal", ...} -> 400 Unsupported value: 'reasoning_effort' does not support 'minimal' with this model. Supported values are: 'none', 'low', 'medium', 'high', and 'xhigh'. POST /v1/chat/completions {"model": "gpt-5.5-pro", "reasoning_effort": "minimal", ...} -> 400 Unsupported value: 'minimal' is not supported with the 'gpt-5.5-pro' model. Supported values are: 'medium', 'high', and 'xhigh'. Set supports_minimal_reasoning_effort=false on all four entries (gpt-5.5, gpt-5.5-2026-04-23, gpt-5.5-pro, gpt-5.5-pro-2026-04-23) so OpenAIGPT5Config._is_reasoning_effort_level_explicitly_disabled fires and LiteLLM either drops the param (drop_params=True) or raises a local UnsupportedParamsError, instead of round-tripping to OpenAI for a 400. Adds a parametrized test_gpt55_reasoning_effort_flags_match_live_openai_api test that pins supports_{none,minimal,xhigh}_reasoning_effort on each entry to OpenAI's actual API contract. Note: gpt-5.5-pro additionally rejects 'none' and 'low'. 'none' is already handled (supports_none_reasoning_effort=false). 'low' is not representable in the current JSON schema (no supports_low flag); filing separately. --- ...odel_prices_and_context_window_backup.json | 8 ++-- model_prices_and_context_window.json | 8 ++-- .../llm_cost_calc/test_llm_cost_calc_utils.py | 40 +++++++++++++++++++ 3 files changed, 48 insertions(+), 8 deletions(-) diff --git a/litellm/model_prices_and_context_window_backup.json b/litellm/model_prices_and_context_window_backup.json index 49ce5022c56..ffe5b47bac7 100644 --- a/litellm/model_prices_and_context_window_backup.json +++ b/litellm/model_prices_and_context_window_backup.json @@ -19319,7 +19319,7 @@ "supports_web_search": true, "supports_none_reasoning_effort": true, "supports_xhigh_reasoning_effort": true, - "supports_minimal_reasoning_effort": true + "supports_minimal_reasoning_effort": false }, "gpt-5.5-2026-04-23": { "cache_read_input_token_cost": 5e-07, @@ -19367,7 +19367,7 @@ "supports_web_search": true, "supports_none_reasoning_effort": true, "supports_xhigh_reasoning_effort": true, - "supports_minimal_reasoning_effort": true + "supports_minimal_reasoning_effort": false }, "gpt-5.5-pro": { "cache_read_input_token_cost": 6e-06, @@ -19410,7 +19410,7 @@ "supports_web_search": true, "supports_none_reasoning_effort": false, "supports_xhigh_reasoning_effort": true, - "supports_minimal_reasoning_effort": true + "supports_minimal_reasoning_effort": false }, "gpt-5.5-pro-2026-04-23": { "cache_read_input_token_cost": 6e-06, @@ -19453,7 +19453,7 @@ "supports_web_search": true, "supports_none_reasoning_effort": false, "supports_xhigh_reasoning_effort": true, - "supports_minimal_reasoning_effort": true + "supports_minimal_reasoning_effort": false }, "gpt-5.4": { "cache_read_input_token_cost": 2.5e-07, diff --git a/model_prices_and_context_window.json b/model_prices_and_context_window.json index 3733f07a30d..39f85650d1f 100644 --- a/model_prices_and_context_window.json +++ b/model_prices_and_context_window.json @@ -19333,7 +19333,7 @@ "supports_web_search": true, "supports_none_reasoning_effort": true, "supports_xhigh_reasoning_effort": true, - "supports_minimal_reasoning_effort": true + "supports_minimal_reasoning_effort": false }, "gpt-5.5-2026-04-23": { "cache_read_input_token_cost": 5e-07, @@ -19381,7 +19381,7 @@ "supports_web_search": true, "supports_none_reasoning_effort": true, "supports_xhigh_reasoning_effort": true, - "supports_minimal_reasoning_effort": true + "supports_minimal_reasoning_effort": false }, "gpt-5.5-pro": { "cache_read_input_token_cost": 6e-06, @@ -19424,7 +19424,7 @@ "supports_web_search": true, "supports_none_reasoning_effort": false, "supports_xhigh_reasoning_effort": true, - "supports_minimal_reasoning_effort": true + "supports_minimal_reasoning_effort": false }, "gpt-5.5-pro-2026-04-23": { "cache_read_input_token_cost": 6e-06, @@ -19467,7 +19467,7 @@ "supports_web_search": true, "supports_none_reasoning_effort": false, "supports_xhigh_reasoning_effort": true, - "supports_minimal_reasoning_effort": true + "supports_minimal_reasoning_effort": false }, "gpt-5.4": { "cache_read_input_token_cost": 2.5e-07, 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 5e37e2a3424..8b1b39848ea 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 @@ -411,6 +411,46 @@ def test_generic_cost_per_token_gpt55_pro(): ) +@pytest.mark.parametrize( + "model,expected_none,expected_xhigh,expected_minimal", + [ + # Verified against OpenAI's live API on 2026-04-24: + # gpt-5.5 -> supports: none, low, medium, high, xhigh + # gpt-5.5-pro -> supports: medium, high, xhigh + # Neither supports "minimal"; gpt-5.5-pro additionally does not support "none". + # The JSON must reflect this so LiteLLM rejects unsupported values locally + # (or drops them with drop_params=True) instead of round-tripping to OpenAI + # for a 400. + ("gpt-5.5", True, True, False), + ("gpt-5.5-2026-04-23", True, True, False), + ("gpt-5.5-pro", False, True, False), + ("gpt-5.5-pro-2026-04-23", False, True, False), + ], +) +def test_gpt55_reasoning_effort_flags_match_live_openai_api( + model, expected_none, expected_xhigh, expected_minimal +): + """Pin reasoning_effort capability flags to OpenAI's actual API contract. + + Observed via `POST /v1/chat/completions` with reasoning_effort=minimal: + ``Unsupported value: 'reasoning_effort' does not support 'minimal' with + this model``. gpt-5.5-pro additionally rejects 'none' and 'low'. + """ + os.environ["LITELLM_LOCAL_MODEL_COST_MAP"] = "True" + litellm.model_cost = litellm.get_model_cost_map(url="") + + m = litellm.model_cost[model] + assert ( + m.get("supports_none_reasoning_effort") is expected_none + ), f"{model}: supports_none_reasoning_effort expected {expected_none}" + assert ( + m.get("supports_xhigh_reasoning_effort") is expected_xhigh + ), f"{model}: supports_xhigh_reasoning_effort expected {expected_xhigh}" + assert ( + m.get("supports_minimal_reasoning_effort") is expected_minimal + ), f"{model}: supports_minimal_reasoning_effort expected {expected_minimal}" + + @pytest.mark.parametrize( "base_model,dated_model", [