mirror of
https://github.com/BerriAI/litellm.git
synced 2026-09-05 08:07:05 +00:00
fix(openai): default reasoning_effort to none for gpt-5.4+ function tools on chat completions
This commit is contained in:
parent
93b5ca9612
commit
da5189dc0d
2 changed files with 88 additions and 0 deletions
|
|
@ -114,6 +114,12 @@ class OpenAIGPT5Config(OpenAIGPTConfig):
|
|||
except (ValueError, IndexError):
|
||||
return False
|
||||
|
||||
@staticmethod
|
||||
def _has_function_tools(tools: Union[list, None]) -> bool:
|
||||
if not tools:
|
||||
return False
|
||||
return any(isinstance(tool, dict) and (tool.get("type") == "function" or "function" in tool) for tool in tools)
|
||||
|
||||
@classmethod
|
||||
def _supports_reasoning_effort_level(cls, model: str, level: str) -> bool:
|
||||
"""Check if the model supports a specific reasoning_effort level.
|
||||
|
|
@ -212,6 +218,16 @@ class OpenAIGPT5Config(OpenAIGPTConfig):
|
|||
raw_reasoning_effort = non_default_params.get("reasoning_effort") or optional_params.get("reasoning_effort")
|
||||
effective_effort = _get_effort_level(raw_reasoning_effort)
|
||||
|
||||
if (
|
||||
effective_effort is None
|
||||
and self.is_model_gpt_5_4_plus_model(model)
|
||||
and self._has_function_tools(non_default_params.get("tools"))
|
||||
and self._supports_reasoning_effort_level(model, "none")
|
||||
):
|
||||
non_default_params["reasoning_effort"] = "none"
|
||||
raw_reasoning_effort = "none"
|
||||
effective_effort = "none"
|
||||
|
||||
# Normalize dict reasoning_effort to string for Chat Completions API.
|
||||
# Example: {"effort": "high", "summary": "detailed"} -> "high"
|
||||
if isinstance(raw_reasoning_effort, dict) and "effort" in raw_reasoning_effort:
|
||||
|
|
|
|||
|
|
@ -274,6 +274,78 @@ def test_gpt5_drops_reasoning_effort_xhigh_when_requested(config: OpenAIConfig):
|
|||
assert "reasoning_effort" not in params
|
||||
|
||||
|
||||
FUNCTION_TOOL = {
|
||||
"type": "function",
|
||||
"function": {
|
||||
"name": "get_capital",
|
||||
"parameters": {"type": "object", "properties": {"country": {"type": "string"}}},
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@pytest.mark.parametrize("model", ["gpt-5.6-sol", "gpt-5.6-luna", "gpt-5.6-terra", "gpt-5.4"])
|
||||
def test_gpt5_4_plus_function_tools_default_reasoning_effort_none(config: OpenAIConfig, model: str):
|
||||
"""gpt-5.4+ reject function tools with a non-'none' reasoning_effort on chat completions.
|
||||
|
||||
Regression for https://github.com/BerriAI/litellm/issues/33221: when the caller omits
|
||||
reasoning_effort, litellm must default it to 'none' so tool calls succeed instead of
|
||||
hitting 'Function tools with reasoning_effort are not supported ... in /v1/chat/completions'.
|
||||
"""
|
||||
params = config.map_openai_params(
|
||||
non_default_params={"tools": [FUNCTION_TOOL]},
|
||||
optional_params={},
|
||||
model=model,
|
||||
drop_params=False,
|
||||
)
|
||||
assert params["reasoning_effort"] == "none"
|
||||
|
||||
|
||||
def test_gpt5_4_plus_function_tools_preserves_explicit_reasoning_effort(config: OpenAIConfig):
|
||||
"""An explicit reasoning_effort must not be overwritten by the tools default.
|
||||
|
||||
(Explicit effort + tools is routed to the Responses API bridge upstream; the chat
|
||||
mapping itself must leave the caller's value untouched.)
|
||||
"""
|
||||
params = config.map_openai_params(
|
||||
non_default_params={"tools": [FUNCTION_TOOL], "reasoning_effort": "high"},
|
||||
optional_params={},
|
||||
model="gpt-5.6-sol",
|
||||
drop_params=False,
|
||||
)
|
||||
assert params["reasoning_effort"] == "high"
|
||||
|
||||
|
||||
def test_gpt5_4_plus_without_tools_does_not_default_reasoning_effort(config: OpenAIConfig):
|
||||
params = config.map_openai_params(
|
||||
non_default_params={},
|
||||
optional_params={},
|
||||
model="gpt-5.6-sol",
|
||||
drop_params=False,
|
||||
)
|
||||
assert "reasoning_effort" not in params
|
||||
|
||||
|
||||
def test_gpt5_4_plus_non_function_tools_do_not_default_reasoning_effort(config: OpenAIConfig):
|
||||
params = config.map_openai_params(
|
||||
non_default_params={"tools": [{"type": "custom", "custom": {"name": "x"}}]},
|
||||
optional_params={},
|
||||
model="gpt-5.6-sol",
|
||||
drop_params=False,
|
||||
)
|
||||
assert "reasoning_effort" not in params
|
||||
|
||||
|
||||
def test_gpt5_1_function_tools_do_not_default_reasoning_effort(config: OpenAIConfig):
|
||||
"""The tools default is scoped to gpt-5.4+; gpt-5.1 must keep its existing behavior."""
|
||||
params = config.map_openai_params(
|
||||
non_default_params={"tools": [FUNCTION_TOOL]},
|
||||
optional_params={},
|
||||
model="gpt-5.1",
|
||||
drop_params=False,
|
||||
)
|
||||
assert "reasoning_effort" not in params
|
||||
|
||||
|
||||
# GPT-5.1 temperature handling tests
|
||||
def test_gpt5_1_model_detection(gpt5_config: OpenAIGPT5Config):
|
||||
"""Test that models supporting reasoning_effort='none' are correctly detected via model map."""
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue