Revert "feat(openai): drop reasoning_effort for gpt-5.4 when tools present"

This reverts commit 14b52b1318.
This commit is contained in:
Sameer Kankute 2026-03-13 13:40:29 +05:30
parent 92d39c308c
commit 90b03f6c67
5 changed files with 13 additions and 74 deletions

View file

@ -638,9 +638,7 @@ This is useful when you want to use [Responses API](https://platform.openai.com/
:::tip gpt-5.4 + reasoning_effort + function tools
LiteLLM drops `reasoning_effort` from `gpt-5.4` requests to `litellm.completion()` that include tools, since that combination is supported in the Responses API.
If you need reasoning **and** tools together, use the responses bridge instead:
OpenAI does not support `reasoning_effort` with function tools for `gpt-5.4` in `/v1/chat/completions`. Use the responses bridge instead:
```python
response = litellm.completion(

View file

@ -594,9 +594,7 @@ Expected Response
:::tip gpt-5.4: reasoning_effort + function tools
LiteLLM drops `reasoning_effort` from `gpt-5.4` requests to `litellm.completion()` that include tools, since that combination is supported in the Responses API.
If you need reasoning **and** tools together, use `openai/responses/gpt-5.4` to route through the Responses API instead. See [Responses API Bridge](/docs/providers/openai#openai-chat-completion-to-responses-api-bridge) for details.
OpenAI does not support `reasoning_effort` with function tools for `gpt-5.4` in `/v1/chat/completions`. Use `openai/responses/gpt-5.4` to route through the Responses API instead. See [Responses API Bridge](/docs/providers/openai#openai-chat-completion-to-responses-api-bridge) for details.
:::

View file

@ -223,16 +223,6 @@ class OpenAIGPT5Config(OpenAIGPTConfig):
"max_tokens"
)
# gpt-5.4: reasoning_effort + tools is only supported in the Responses API
# Drop reasoning_effort when tools are present in chat completions
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 effective_effort is not None:
non_default_params.pop("reasoning_effort", None)
optional_params.pop("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:

View file

@ -9,11 +9,11 @@ import pytest
sys.path.insert(0, os.path.abspath("../../../../.."))
from litellm.llms.openai.chat.gpt_5_transformation import OpenAIGPT5Config
from litellm.llms.openai.chat.gpt_transformation import (
OpenAIChatCompletionStreamingHandler,
OpenAIGPTConfig,
)
from litellm.llms.openai.chat.gpt_5_transformation import OpenAIGPT5Config
class TestOpenAIGPTConfig:
@ -460,8 +460,11 @@ class TestGPT5ReasoningEffortPreservation:
assert "reasoning_effort" not in non_default_params
def test_reasoning_effort_dict_none_dropped_for_gpt5_4_with_tools(self):
"""none-dict with tools on gpt-5.4: reasoning_effort is dropped."""
def test_reasoning_effort_dict_none_treated_as_none_for_tools(self):
"""none-dict: {"effort": "none", "summary": "detailed"} is treated as effort=none.
Tool-drop guard should NOT fire; reasoning_effort should be kept.
"""
tools = [{"type": "function", "function": {"name": "test", "description": "test"}}]
non_default_params = {"reasoning_effort": {"effort": "none", "summary": "detailed"}, "tools": tools}
optional_params = {}
@ -473,7 +476,7 @@ class TestGPT5ReasoningEffortPreservation:
drop_params=False,
)
assert "reasoning_effort" not in non_default_params
assert non_default_params.get("reasoning_effort") == {"effort": "none", "summary": "detailed"}
assert non_default_params.get("tools") == tools
def test_reasoning_effort_dict_none_treated_as_none_for_sampling(self):

View file

@ -366,10 +366,10 @@ def test_gpt5_xhigh_dict_accepted_for_supported_model(config: OpenAIConfig):
def test_gpt5_none_dict_with_tools_no_tool_drop(config: OpenAIConfig):
"""Dict with effort='none' and tools: reasoning_effort dropped for gpt-5.4.
"""Dict with effort='none' and tools: no tool-drop, reasoning_effort preserved.
gpt-5.4 drops all reasoning_effort when tools are present,
since that combination is only supported in the Responses API.
Regression: effective_effort='none' must be used for tool-drop guard so
{"effort": "none", "summary": "detailed"} is not incorrectly treated as non-none.
"""
tools = [{"type": "function", "function": {"name": "test", "description": "test"}}]
params = config.map_openai_params(
@ -378,7 +378,7 @@ def test_gpt5_none_dict_with_tools_no_tool_drop(config: OpenAIConfig):
model="gpt-5.4",
drop_params=False,
)
assert "reasoning_effort" not in params
assert params["reasoning_effort"] == {"effort": "none", "summary": "detailed"}
assert params["tools"] == tools
@ -414,56 +414,6 @@ def test_gpt5_preserves_reasoning_effort_dict_with_summary_from_optional_params(
assert params["reasoning_effort"] == {"effort": "medium", "summary": "detailed"}
def test_gpt5_4_drops_reasoning_effort_when_user_sends_reasoning_and_tools(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_drops_reasoning_effort_none_with_tools(config: OpenAIConfig):
"""reasoning_effort='none' is also dropped when tools are present for gpt-5.4."""
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 "reasoning_effort" not in params
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(