{"repo":"NousResearch/hermes-agent","public_id":"15812","display_label":"DeepSeek/Kimi reasoning field promotion bug fixes","summary":"Multiple fixes and related regression reports targeting correct placement and promotion of the reasoning_content field in DeepSeek/Kimi assistant messages, particularly during tool-call turns. The cluster centers on a specific regression introduced by an earlier change and subsequent attempts to restore correct behavior.","subsystem":null,"counts":{"members":5,"open_issues":0,"open_issues_distinct":0,"open_prs":0,"closed_issues":1,"merged_prs":2,"attempt_prs":2},"landed_fix":{"status":"merged_to_main","basis":"structural","pr":15478},"resolution":{"state":"resolved","by":"pr-16097"},"freshness":{"state":"verified","last_verified_at":"2026-04-26T15:25:23+00:00","is_stale":false},"grouping":{"backbone":"STRUCTURAL_SPANNING","link_density":0.4},"fix_edges":[{"issue_number":15213,"pr_number":15478,"tier":"verified","basis":"closing_ref","confidence":0.95,"recoverable_from_timeline":true},{"issue_number":15812,"pr_number":15478,"tier":"verified","basis":"superseded_ref","confidence":0.9,"recoverable_from_timeline":false},{"issue_number":15812,"pr_number":16097,"tier":"verified","basis":"closing_ref","confidence":0.95,"recoverable_from_timeline":true}],"members":[{"kind":"issue","number":15812,"title":"regression: #15749 breaks reasoning field promotion for DeepSeek/Kimi tool-call messages","url":null,"state":"closed"},{"kind":"pr","number":15478,"title":"fix: DeepSeek/Kimi thinking mode requires reasoning_content on ALL assistant messages","url":null,"state":"merged","close_reason":{"category":"merged","implication":"superseded"},"merged":true,"is_fix_pr":true,"fix_tier":"verified","files_changed":["run_agent.py","tests/run_agent/test_deepseek_reasoning_content_echo.py"],"fix_hunks":[{"file":"run_agent.py","hunks":["@@ -7785,7 +7785,17 @@ def _copy_reasoning_content_for_api(self, source_msg: dict, api_msg: dict) -> No\n             api_msg[\"reasoning_content\"] = normalized_reasoning\n             return\n \n-        # 4. reasoning_content was present but not a string (e.g. None after\n+        # 4. DeepSeek / Kimi thinking mode: all assistant messages need\n+        # reasoning_content. Inject \"\" to satisfy the provider's requirement\n+        # when no explicit reasoning content is present.\n+        if (\n+            self._needs_kimi_tool_reasoning()\n+            or self._needs_deepseek_tool_reasoning()\n+        ):\n+            api_msg[\"reasoning_content\"] = \"\"\n+            return\n+\n+        # 5. reasoning_content was present but not a string (e.g. None after\n         # context compaction).  Don't pass null to the API.\n         api_msg.pop(\"reasoning_content\", None)\n "]},{"file":"tests/run_agent/test_deepseek_reasoning_content_echo.py","hunks":["@@ -88,13 +88,13 @@ def test_deepseek_tool_call_poisoned_history_gets_empty_string(self) -> None:\n         agent._copy_reasoning_content_for_api(source, api_msg)\n         assert api_msg.get(\"reasoning_content\") == \"\"\n \n-    def test_deepseek_assistant_no_tool_call_left_alone(self) -> None:\n-        \"\"\"Plain assistant turns without tool_calls don't get padded.\"\"\"\n+    def test_deepseek_assistant_no_tool_call_gets_padded(self) -> None:\n+        \"\"\"DeepSeek thinking mode pads ALL assistant turns, even without tool_calls.\"\"\"\n         agent = _make_agent(provider=\"deepseek\", model=\"deepseek-v4-flash\")\n         source = {\"role\": \"assistant\", \"content\": \"hello\"}\n         api_msg: dict = {}\n         agent._copy_reasoning_content_for_api(source, api_msg)\n-        assert \"reasoning_content\" not in api_msg\n+        assert api_msg.get(\"reasoning_content\") == \"\"\n \n     def test_deepseek_explicit_reasoning_content_preserved(self) -> None:\n         \"\"\"When reasoning_content is already set, it's copied verbatim.\"\"\"\n"]}]},{"kind":"pr","number":15830,"title":"fix(reasoning): promote reasoning field before empty-pad for DeepSeek/Kimi (#15812)","url":null,"state":"closed","close_reason":{"refs":[{"kind":"commit","value":"93a2d6b30","number":0},{"kind":"commit","value":"d58b305ad","number":0},{"kind":"commit","value":"ad0ac8947","number":0},{"kind":"commit","value":"5ae608152","number":0},{"kind":"commit","value":"ad0ac8947","number":0},{"kind":"commit","value":"9daa0620a","number":0},{"kind":"commit","value":"63bf7a29b","number":0},{"kind":"pr","value":"#16500","number":16500}],"category":"implemented_elsewhere","implication":"superseded"},"merged":false},{"kind":"pr","number":15883,"title":"fix(run_agent): prevent reasoning_content regression in DeepSeek/Kimi tool-call replay (#15812)","url":null,"state":"closed","close_reason":{"refs":[{"kind":"commit","value":"63bf7a29b","number":0},{"kind":"pr","value":"#16097","number":16097},{"kind":"pr","value":"#15478","number":15478}],"category":"merged_via","implication":"superseded"},"merged":false},{"kind":"pr","number":16097,"title":"fix(run_agent): restore reasoning field promotion on DeepSeek/Kimi tool-call turns (salvage #15883)","url":null,"state":"merged","close_reason":{"category":"merged","implication":"superseded"},"merged":true,"is_fix_pr":true,"fix_tier":"verified","files_changed":["run_agent.py","scripts/release.py"]}],"trust":{"default_tier":"verified","includes_suggested":false}}