From 7fc9f1c34de90e72e618dcbf560540219e2ab652 Mon Sep 17 00:00:00 2001 From: Syed Ali Abbas Rahil Date: Fri, 11 Sep 2026 12:03:26 +0900 Subject: [PATCH] fix(gpt-5): enforce supports_none_reasoning_effort for reasoning_effort=none Adds a missing capability gate so that reasoning_effort="none" is dropped or refused when the model map marks supports_none_reasoning_effort=false (e.g. gpt-5, gpt-5-mini) instead of being forwarded to the provider and surfacing as a 400. --- .../llms/openai/chat/gpt_5_transformation.py | 13 ++++ .../openai/test_gpt5_reasoning_effort_none.py | 61 +++++++++++++++++++ 2 files changed, 74 insertions(+) create mode 100644 tests/test_litellm/llms/openai/test_gpt5_reasoning_effort_none.py diff --git a/litellm/llms/openai/chat/gpt_5_transformation.py b/litellm/llms/openai/chat/gpt_5_transformation.py index b02f953425d..1a3a7261bc3 100644 --- a/litellm/llms/openai/chat/gpt_5_transformation.py +++ b/litellm/llms/openai/chat/gpt_5_transformation.py @@ -300,6 +300,19 @@ class OpenAIGPT5Config(OpenAIGPTConfig): message=(f"reasoning_effort={effective_effort} is not supported for this model."), status_code=400, ) + elif effective_effort == "none": + # "none" is a declared capability: if the model map says the model does not + # support it, drop or refuse rather than forwarding it to the provider. + # Example: gpt-5 and gpt-5-mini are marked supports_none_reasoning_effort=false. + if not self._supports_reasoning_effort_level(model, effective_effort): + if litellm.drop_params or drop_params: + non_default_params.pop("reasoning_effort", None) + optional_params.pop("reasoning_effort", None) + else: + raise litellm.utils.UnsupportedParamsError( + message=(f"reasoning_effort={effective_effort} is not supported for this model."), + status_code=400, + ) ################################################################ # max_tokens is not supported for gpt-5 models on OpenAI API diff --git a/tests/test_litellm/llms/openai/test_gpt5_reasoning_effort_none.py b/tests/test_litellm/llms/openai/test_gpt5_reasoning_effort_none.py new file mode 100644 index 00000000000..c2f86c53905 --- /dev/null +++ b/tests/test_litellm/llms/openai/test_gpt5_reasoning_effort_none.py @@ -0,0 +1,61 @@ +import pytest + +import litellm +from litellm.litellm_core_utils.get_model_cost_map import get_model_cost_map +from litellm.llms.openai.openai import OpenAIConfig + + +@pytest.fixture() +def config() -> OpenAIConfig: + return OpenAIConfig() + + +@pytest.fixture(autouse=True) +def use_local_model_cost_map(monkeypatch: pytest.MonkeyPatch): + monkeypatch.setenv("LITELLM_LOCAL_MODEL_COST_MAP", "True") + monkeypatch.setattr(litellm, "model_cost", get_model_cost_map(url=litellm.model_cost_map_url)) + litellm.add_known_models(model_cost_map=litellm.model_cost) + + +def test_gpt5_rejects_reasoning_effort_none_for_unsupported_models(config: OpenAIConfig): + """Models marked supports_none_reasoning_effort=false must not forward reasoning_effort=none.""" + for model in ("gpt-5", "gpt-5-mini"): + with pytest.raises(litellm.utils.UnsupportedParamsError): + config.map_openai_params( + non_default_params={"reasoning_effort": "none"}, + optional_params={}, + model=model, + drop_params=False, + ) + + # Dict form {"effort": "none"} should be gated the same way. + with pytest.raises(litellm.utils.UnsupportedParamsError): + config.map_openai_params( + non_default_params={"reasoning_effort": {"effort": "none", "summary": "detailed"}}, + optional_params={}, + model=model, + drop_params=False, + ) + + +def test_gpt5_drops_reasoning_effort_none_when_requested(config: OpenAIConfig): + """drop_params=True should strip unsupported reasoning_effort=none instead of raising.""" + for model in ("gpt-5", "gpt-5-mini"): + params = config.map_openai_params( + non_default_params={"reasoning_effort": "none"}, + optional_params={}, + model=model, + drop_params=True, + ) + assert "reasoning_effort" not in params + + +def test_gpt5_1_passes_through_reasoning_effort_none(config: OpenAIConfig): + """Models marked supports_none_reasoning_effort=true still forward reasoning_effort=none.""" + params = config.map_openai_params( + non_default_params={"reasoning_effort": "none"}, + optional_params={}, + model="gpt-5.1", + drop_params=False, + ) + assert params["reasoning_effort"] == "none"