diff --git a/agent/agent_runtime_helpers.py b/agent/agent_runtime_helpers.py index 61551a65dc9a..2932864b4798 100644 --- a/agent/agent_runtime_helpers.py +++ b/agent/agent_runtime_helpers.py @@ -1793,10 +1793,12 @@ def copy_reasoning_content_for_api(agent, source_msg: dict, api_msg: dict) -> No # doesn't 400 the user on the next turn. existing = source_msg.get("reasoning_content") if isinstance(existing, str): - if existing == "" and agent._needs_thinking_reasoning_pad(): - api_msg["reasoning_content"] = " " - else: - api_msg["reasoning_content"] = existing + needs_thinking_pad = agent._needs_thinking_reasoning_pad() + if needs_thinking_pad: + if existing == "": + api_msg["reasoning_content"] = " " + else: + api_msg["reasoning_content"] = existing return needs_thinking_pad = agent._needs_thinking_reasoning_pad() @@ -1827,7 +1829,7 @@ def copy_reasoning_content_for_api(agent, source_msg: dict, api_msg: dict) -> No # This must happen before the unconditional empty-string fallback so # genuine reasoning content is not overwritten (#15812 regression in # PR #15478). - if isinstance(normalized_reasoning, str) and normalized_reasoning: + if needs_thinking_pad and isinstance(normalized_reasoning, str) and normalized_reasoning: api_msg["reasoning_content"] = normalized_reasoning return diff --git a/tests/run_agent/test_deepseek_reasoning_content_echo.py b/tests/run_agent/test_deepseek_reasoning_content_echo.py index 0efdb2c5a185..1597e87ebb8d 100644 --- a/tests/run_agent/test_deepseek_reasoning_content_echo.py +++ b/tests/run_agent/test_deepseek_reasoning_content_echo.py @@ -160,11 +160,8 @@ def test_deepseek_stale_empty_placeholder_upgraded_to_space(self) -> None: agent._copy_reasoning_content_for_api(source, api_msg) assert api_msg["reasoning_content"] == " " - def test_non_thinking_provider_preserves_empty_reasoning_content_verbatim(self) -> None: - """The stale-placeholder upgrade ONLY fires when the active provider - enforces thinking-mode echo. On non-thinking providers, an empty - reasoning_content must still round-trip verbatim. - """ + def test_non_thinking_provider_strips_empty_reasoning_content(self) -> None: + """Providers that don't require the echo must not receive reasoning_content.""" agent = _make_agent( provider="openrouter", model="anthropic/claude-sonnet-4.6", @@ -177,7 +174,51 @@ def test_non_thinking_provider_preserves_empty_reasoning_content_verbatim(self) } api_msg: dict = {} agent._copy_reasoning_content_for_api(source, api_msg) - assert api_msg["reasoning_content"] == "" + assert "reasoning_content" not in api_msg + + @pytest.mark.parametrize( + "provider,model,base_url", + [ + ("custom", "groq/compound", "https://api.groq.com/openai/v1"), + ("groq", "groq/compound", "https://api.groq.com/openai/v1"), + ("custom", "qwen-3-235b-a22b-instruct-2507", "https://api.cerebras.ai/v1"), + ("cerebras", "qwen-3-235b-a22b-instruct-2507", "https://api.cerebras.ai/v1"), + ], + ) + def test_openai_compatible_custom_providers_strip_reasoning_content( + self, provider: str, model: str, base_url: str + ) -> None: + agent = _make_agent(provider=provider, model=model, base_url=base_url) + source = { + "role": "assistant", + "content": "prior answer", + "reasoning_content": "thinking from another provider", + } + api_msg: dict = {} + agent._copy_reasoning_content_for_api(source, api_msg) + assert "reasoning_content" not in api_msg + + @pytest.mark.parametrize( + "provider,model,base_url", + [ + ("custom", "groq/compound", "https://api.groq.com/openai/v1"), + ("groq", "groq/compound", "https://api.groq.com/openai/v1"), + ("custom", "qwen-3-235b-a22b-instruct-2507", "https://api.cerebras.ai/v1"), + ("cerebras", "qwen-3-235b-a22b-instruct-2507", "https://api.cerebras.ai/v1"), + ], + ) + def test_openai_compatible_custom_providers_do_not_promote_reasoning( + self, provider: str, model: str, base_url: str + ) -> None: + agent = _make_agent(provider=provider, model=model, base_url=base_url) + source = { + "role": "assistant", + "content": "prior answer", + "reasoning": "thinking from another provider", + } + api_msg: dict = {} + agent._copy_reasoning_content_for_api(source, api_msg) + assert "reasoning_content" not in api_msg def test_deepseek_reasoning_field_promoted(self) -> None: """When only 'reasoning' is set, it gets promoted to reasoning_content."""