From 90b03f6c67931846ee901dde4d0b8cebc708db19 Mon Sep 17 00:00:00 2001 From: Sameer Kankute Date: Fri, 13 Mar 2026 13:40:29 +0530 Subject: [PATCH] Revert "feat(openai): drop reasoning_effort for gpt-5.4 when tools present" This reverts commit 14b52b131883f87f01fcacd1c6553c149e701da3. --- docs/my-website/docs/providers/openai.md | 4 +- docs/my-website/docs/reasoning_content.md | 4 +- .../llms/openai/chat/gpt_5_transformation.py | 10 ---- .../chat/test_openai_gpt_transformation.py | 11 ++-- .../llms/openai/test_gpt5_transformation.py | 58 ++----------------- 5 files changed, 13 insertions(+), 74 deletions(-) diff --git a/docs/my-website/docs/providers/openai.md b/docs/my-website/docs/providers/openai.md index 80931ad8217..9d557303ef2 100644 --- a/docs/my-website/docs/providers/openai.md +++ b/docs/my-website/docs/providers/openai.md @@ -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( diff --git a/docs/my-website/docs/reasoning_content.md b/docs/my-website/docs/reasoning_content.md index 8bf59f66a33..5dd40122c71 100644 --- a/docs/my-website/docs/reasoning_content.md +++ b/docs/my-website/docs/reasoning_content.md @@ -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. ::: diff --git a/litellm/llms/openai/chat/gpt_5_transformation.py b/litellm/llms/openai/chat/gpt_5_transformation.py index 3f33d6183f3..e3b38050236 100644 --- a/litellm/llms/openai/chat/gpt_5_transformation.py +++ b/litellm/llms/openai/chat/gpt_5_transformation.py @@ -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: diff --git a/tests/test_litellm/llms/openai/chat/test_openai_gpt_transformation.py b/tests/test_litellm/llms/openai/chat/test_openai_gpt_transformation.py index 0f743b1a93b..c66b67cf4c5 100644 --- a/tests/test_litellm/llms/openai/chat/test_openai_gpt_transformation.py +++ b/tests/test_litellm/llms/openai/chat/test_openai_gpt_transformation.py @@ -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): diff --git a/tests/test_litellm/llms/openai/test_gpt5_transformation.py b/tests/test_litellm/llms/openai/test_gpt5_transformation.py index 7c731e4e00a..aca328ee435 100644 --- a/tests/test_litellm/llms/openai/test_gpt5_transformation.py +++ b/tests/test_litellm/llms/openai/test_gpt5_transformation.py @@ -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(