{"repo":"NousResearch/hermes-agent","public_id":"25574","display_label":"Config option for reasoning output display format","summary":"These members add a configurable option to control how reasoning output is displayed, with at least one implementation rendering it as subtext in Discord. The work covers both the config option design and specific rendering style variants.","subsystem":"gateway","counts":{"members":3,"open_issues":0,"open_issues_distinct":0,"open_prs":0,"closed_issues":1,"merged_prs":1,"attempt_prs":1},"landed_fix":{"status":"merged_to_main","basis":"structural","pr":51168,"merged_at":"2026-06-23T17:44:03+00:00"},"resolution":{"state":"unresolved","by":null},"freshness":{"state":"verified","last_verified_at":"2026-06-23T17:44:03+00:00","is_stale":false},"grouping":{"backbone":"STRUCTURAL_SPANNING","link_density":0.6666666666666666},"fix_edges":[{"issue_number":25574,"pr_number":51168,"tier":"verified","basis":"superseded_ref","confidence":0.9,"recoverable_from_timeline":false,"pr_merged_at":"2026-06-23T17:44:03+00:00"}],"members":[{"kind":"issue","number":25574,"title":"Add display.reasoning_format config option (code vs quote)","url":null,"state":"closed"},{"kind":"pr","number":25933,"title":"feat(display): add reasoning_format config option for reasoning output style (#25574)","url":null,"state":"closed","close_reason":{"refs":[{"kind":"commit","value":"6cc07b6cd0344e63340aa003a5e90a5bdefe14c0","number":0},{"kind":"pr","value":"#51168","number":51168},{"kind":"pr","value":"#25574","number":25574}],"category":"implemented_elsewhere","implication":"superseded"},"merged":false},{"kind":"pr","number":51168,"title":"feat(discord): render reasoning as -# subtext via display.reasoning_style","url":null,"state":"merged","close_reason":{"category":"merged"},"merged":true,"is_fix_pr":true,"fix_tier":"verified","files_changed":["gateway/display_config.py","gateway/run.py","hermes_cli/config.py","tests/gateway/test_display_config.py"],"fix_hunks":[{"file":"gateway/display_config.py","hunks":["@@ -34,6 +34,12 @@\n     \"tool_progress\": \"all\",\n     \"tool_progress_grouping\": \"accumulate\",  # \"accumulate\" = edit one bubble; \"separate\" = one msg per tool\n     \"show_reasoning\": False,\n+    # How a reasoning/thinking summary is rendered when show_reasoning is on.\n+    #   \"code\"      -> 💭 **Reasoning:** + fenced code block (legacy default)\n+    #   \"blockquote\"-> each line prefixed with \"> \"\n+    #   \"subtext\"   -> each line prefixed with \"-# \" (Discord small grey subtext)\n+    # Discord defaults to \"subtext\"; everywhere else defaults to \"code\".\n+    \"reasoning_style\": \"code\",\n     \"tool_preview_length\": 0,\n     \"streaming\": None,  # None = follow top-level streaming config\n     # Gateway-only assistant/status chatter controls. These default on for","@@ -111,7 +117,10 @@\n         \"tool_progress\": \"off\",\n         \"busy_ack_detail\": False,\n     },\n-    \"discord\":     _TIER_HIGH,\n+    # Discord has a native \"subtext\" primitive (-# small grey text) that reads\n+    # as metadata rather than content, so reasoning summaries default to it\n+    # here instead of the fenced code block used elsewhere.\n+    \"discord\":     {**_TIER_HIGH, \"reasoning_style\": \"subtext\"},\n \n     # Tier 2 — edit support, often customer/workspace channels\n     # Slack: tool_progress off by default — Bolt posts cannot be edited like CLI;","@@ -242,6 +251,9 @@ def _normalise(setting: str, value: Any) -> Any:\n     if setting == \"tool_progress_grouping\":\n         val = str(value).lower()\n         return val if val in (\"accumulate\", \"separate\") else \"accumulate\"\n+    if setting == \"reasoning_style\":\n+        val = str(value).lower()\n+        return val if val in (\"code\", \"blockquote\", \"subtext\") else \"code\"\n     if setting == \"tool_preview_length\":\n         try:\n             return int(value)"]},{"file":"gateway/run.py","hunks":["@@ -9727,7 +9727,31 @@ async def _handle_message_with_agent(self, event, source, _quick_key: str, run_g\n                         display_reasoning += f\"\\n_... ({len(lines) - 15} more lines)_\"\n                     else:\n                         display_reasoning = last_reasoning.strip()\n-                    response = f\"💭 **Reasoning:**\\n```\\n{display_reasoning}\\n```\\n\\n{response}\"\n+                    # Render style is per-platform: Discord defaults to \"-# \"\n+                    # subtext (native small grey metadata text); other\n+                    # platforms keep the fenced code block.\n+                    try:\n+                        from gateway.display_config import resolve_display_setting\n+                        _reasoning_style = resolve_display_setting(\n+                            _load_gateway_config(),\n+                            _platform_config_key(source.platform),\n+                            \"reasoning_style\",\n+                            \"code\",\n+                        )\n+                    except Exception:\n+                        _reasoning_style = \"code\"\n+                    if _reasoning_style == \"subtext\":\n+                        _quoted = \"\\n\".join(\n+                            f\"-# {ln}\" if ln else \"-#\" for ln in display_reasoning.splitlines()\n+                        )\n+                        response = f\"-# 💭 Reasoning\\n{_quoted}\\n\\n{response}\"\n+                    elif _reasoning_style == \"blockquote\":\n+                        _quoted = \"\\n\".join(\n+                            f\"> {ln}\" if ln else \">\" for ln in display_reasoning.splitlines()\n+                        )\n+                        response = f\"> 💭 **Reasoning:**\\n{_quoted}\\n\\n{response}\"\n+                    else:\n+                        response = f\"💭 **Reasoning:**\\n```\\n{display_reasoning}\\n```\\n\\n{response}\"\n \n             # Runtime-metadata footer — only on the FINAL message of the turn.\n             # Off by default (display.runtime_footer.enabled=false).  When"]},{"file":"hermes_cli/config.py","hunks":["@@ -1667,6 +1667,12 @@ def _ensure_hermes_home_managed(home: Path):\n         # applies where tool_progress is already enabled. Per-platform override\n         # via display.platforms.<platform>.tool_progress_grouping.\n         \"tool_progress_grouping\": \"accumulate\",\n+        # How a reasoning/thinking summary renders when show_reasoning is on.\n+        # \"code\" (default) = 💭 fenced code block; \"blockquote\" = \"> \" lines;\n+        # \"subtext\" = \"-# \" lines (Discord small grey metadata text). Discord\n+        # defaults to \"subtext\"; override per-platform via\n+        # display.platforms.<platform>.reasoning_style.\n+        \"reasoning_style\": \"code\",\n         # Auto-delete system-notice replies (e.g. \"✨ New session started!\",\n         # \"♻ Restarting gateway…\", \"⚡ Stopped…\") after N seconds on platforms\n         # that support message deletion (currently Telegram; other platforms"]},{"file":"tests/gateway/test_display_config.py","hunks":["@@ -510,3 +510,48 @@ def test_case_insensitive(self):\n             resolve_display_setting(config, \"telegram\", \"tool_progress_grouping\")\n             == \"separate\"\n         )\n+\n+\n+class TestReasoningStyle:\n+    \"\"\"Per-platform reasoning render style (code | blockquote | subtext).\"\"\"\n+\n+    def test_discord_defaults_to_subtext(self):\n+        from gateway.display_config import resolve_display_setting\n+\n+        assert resolve_display_setting({}, \"discord\", \"reasoning_style\") == \"subtext\"\n+\n+    def test_other_platforms_default_to_code(self):\n+        from gateway.display_config import resolve_display_setting\n+\n+        for plat in (\"telegram\", \"slack\", \"matrix\", \"api_server\"):\n+            assert (\n+                resolve_display_setting({}, plat, \"reasoning_style\") == \"code\"\n+            ), plat\n+\n+    def test_platform_override_wins(self):\n+        from gateway.display_config import resolve_display_setting\n+\n+        config = {\"display\": {\"platforms\": {\"discord\": {\"reasoning_style\": \"blockquote\"}}}}\n+        assert (\n+            resolve_display_setting(config, \"discord\", \"reasoning_style\") == \"blockquote\"\n+        )\n+\n+    def test_global_override(self):\n+        from gateway.display_config import resolve_display_setting\n+\n+        config = {\"display\": {\"reasoning_style\": \"subtext\"}}\n+        assert (\n+            resolve_display_setting(config, \"telegram\", \"reasoning_style\") == \"subtext\"\n+        )\n+\n+    def test_invalid_value_falls_back_to_code(self):\n+        from gateway.display_config import resolve_display_setting\n+\n+        config = {\"display\": {\"reasoning_style\": \"bogus\"}}\n+        assert resolve_display_setting(config, \"telegram\", \"reasoning_style\") == \"code\"\n+\n+    def test_case_insensitive(self):\n+        from gateway.display_config import resolve_display_setting\n+\n+        config = {\"display\": {\"reasoning_style\": \"SUBTEXT\"}}\n+        assert resolve_display_setting(config, \"telegram\", \"reasoning_style\") == \"subtext\"\n"]}]}],"trust":{"default_tier":"verified","includes_suggested":false}}