From 19199cd38d826ad146ee9e4a0cdfed78e347ff10 Mon Sep 17 00:00:00 2001 From: Teknium <127238744+teknium1@users.noreply.github.com> Date: Mon, 13 Apr 2026 23:11:13 -0700 Subject: [PATCH] fix: clamp 'minimal' reasoning effort to 'low' on Responses API (#9429) GPT-5.4 supports none/low/medium/high/xhigh but not 'minimal'. Users may configure 'minimal' via OpenRouter conventions, which would cause a 400 on native OpenAI. Clamp to 'low' in the codex_responses path before sending. --- run_agent.py | 6 ++ .../test_run_agent_codex_responses.py | 63 +++++++++++++++++++ 2 files changed, 69 insertions(+) diff --git a/run_agent.py b/run_agent.py index 592253464..626951b27 100644 --- a/run_agent.py +++ b/run_agent.py @@ -6143,6 +6143,12 @@ class AIAgent: elif self.reasoning_config.get("effort"): reasoning_effort = self.reasoning_config["effort"] + # Clamp effort levels not supported by the Responses API model. + # GPT-5.4 supports none/low/medium/high/xhigh but not "minimal". + # "minimal" is valid on OpenRouter and GPT-5 but fails on 5.2/5.4. + _effort_clamp = {"minimal": "low"} + reasoning_effort = _effort_clamp.get(reasoning_effort, reasoning_effort) + kwargs = { "model": self.model, "instructions": instructions, diff --git a/tests/run_agent/test_run_agent_codex_responses.py b/tests/run_agent/test_run_agent_codex_responses.py index 0fca9e4df..785d85886 100644 --- a/tests/run_agent/test_run_agent_codex_responses.py +++ b/tests/run_agent/test_run_agent_codex_responses.py @@ -287,6 +287,69 @@ def test_build_api_kwargs_codex(monkeypatch): assert "extra_body" not in kwargs +def test_build_api_kwargs_codex_clamps_minimal_effort(monkeypatch): + """'minimal' reasoning effort is clamped to 'low' on the Responses API. + + GPT-5.4 supports none/low/medium/high/xhigh but NOT 'minimal'. + Users may configure 'minimal' via OpenRouter conventions, so the Codex + Responses path must clamp it to the nearest supported level. + """ + _patch_agent_bootstrap(monkeypatch) + + agent = run_agent.AIAgent( + model="gpt-5-codex", + base_url="https://chatgpt.com/backend-api/codex", + api_key="codex-token", + quiet_mode=True, + max_iterations=4, + skip_context_files=True, + skip_memory=True, + reasoning_config={"enabled": True, "effort": "minimal"}, + ) + agent._cleanup_task_resources = lambda task_id: None + agent._persist_session = lambda messages, history=None: None + agent._save_trajectory = lambda messages, user_message, completed: None + agent._save_session_log = lambda messages: None + + kwargs = agent._build_api_kwargs( + [ + {"role": "system", "content": "You are Hermes."}, + {"role": "user", "content": "Ping"}, + ] + ) + + assert kwargs["reasoning"]["effort"] == "low" + + +def test_build_api_kwargs_codex_preserves_supported_efforts(monkeypatch): + """Effort levels natively supported by the Responses API pass through unchanged.""" + _patch_agent_bootstrap(monkeypatch) + + for effort in ("low", "medium", "high", "xhigh"): + agent = run_agent.AIAgent( + model="gpt-5-codex", + base_url="https://chatgpt.com/backend-api/codex", + api_key="codex-token", + quiet_mode=True, + max_iterations=4, + skip_context_files=True, + skip_memory=True, + reasoning_config={"enabled": True, "effort": effort}, + ) + agent._cleanup_task_resources = lambda task_id: None + agent._persist_session = lambda messages, history=None: None + agent._save_trajectory = lambda messages, user_message, completed: None + agent._save_session_log = lambda messages: None + + kwargs = agent._build_api_kwargs( + [ + {"role": "system", "content": "sys"}, + {"role": "user", "content": "hi"}, + ] + ) + assert kwargs["reasoning"]["effort"] == effort, f"{effort} should pass through unchanged" + + def test_build_api_kwargs_copilot_responses_omits_openai_only_fields(monkeypatch): agent = _build_copilot_agent(monkeypatch) kwargs = agent._build_api_kwargs([{"role": "user", "content": "hi"}])