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
This commit is contained in:
Sameer Kankute
2026-03-06 22:20:47 +05:30
parent b6344c319b
commit 14b52b1318
2 changed files with 67 additions and 0 deletions
@@ -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:
@@ -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(