{"repo":"NousResearch/hermes-agent","public_id":"27995","display_label":"Matrix multi-bot infinite reply loop issue","summary":"A bug where MATRIX_AUTO_THREAD causes infinite reply loops when multiple bots share a Matrix room, along with a proposed fix using a thread_require_mention option to prevent this behavior.","subsystem":null,"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":28580,"merged_at":"2026-05-19T07:04:23+00:00"},"resolution":{"state":"resolved","by":"pr-28580"},"freshness":{"state":"verified","last_verified_at":"2026-05-19T07:04:23+00:00","is_stale":false},"grouping":{"backbone":"STRUCTURAL_SPANNING","link_density":0.6666666666666666},"fix_edges":[{"issue_number":27995,"pr_number":28580,"tier":"verified","basis":"closing_ref","confidence":0.95,"recoverable_from_timeline":true,"pr_merged_at":"2026-05-19T07:04:23+00:00"}],"members":[{"kind":"issue","number":27995,"title":"bug: MATRIX_AUTO_THREAD enables infinite reply loops when multiple bots share a Matrix room","url":null,"state":"closed"},{"kind":"pr","number":27996,"title":"fix(matrix): implement thread_require_mention to prevent multi-agent reply loops","url":null,"state":"closed","close_reason":{"refs":[{"kind":"commit","value":"276e6cc52d4a8e0a6818bc3ba82a947013fb757c","number":0},{"kind":"pr","value":"#28580","number":28580}],"category":"merged_via","implication":"superseded"},"merged":false},{"kind":"pr","number":28580,"title":"fix(matrix): implement thread_require_mention to prevent multi-agent reply loops (#27996)","url":null,"state":"merged","close_reason":{"category":"merged"},"merged":true,"is_fix_pr":true,"fix_tier":"verified","files_changed":["gateway/platforms/matrix.py"],"fix_hunks":[{"file":"gateway/platforms/matrix.py","hunks":["@@ -380,6 +380,7 @@ def __init__(self, config: PlatformConfig):\n         self._require_mention: bool = os.getenv(\n             \"MATRIX_REQUIRE_MENTION\", \"true\"\n         ).lower() not in {\"false\", \"0\", \"no\"}\n+        self._thread_require_mention: bool = self._parse_thread_require_mention(config)\n         free_rooms_raw = config.extra.get(\"free_response_rooms\")\n         if free_rooms_raw is None:\n             free_rooms_raw = os.getenv(\"MATRIX_FREE_RESPONSE_ROOMS\", \"\")","@@ -468,6 +469,27 @@ def _is_duplicate_event(self, event_id) -> bool:\n         self._processed_events_set.add(event_id)\n         return False\n \n+    @staticmethod\n+    def _parse_thread_require_mention(config) -> bool:\n+        \"\"\"Parse thread_require_mention from config.extra or env var.\n+\n+        Handles both YAML booleans and string values (``\\\"true\\\"``, ``\\\"false\\\"``,\n+        ``\\\"yes\\\"``, ``\\\"no\\\"``, ``\\\"on\\\"``, ``\\\"off\\\"``, ``\\\"1\\\"``, ``\\\"0\\\"``).\n+        Falls back to ``MATRIX_THREAD_REQUIRE_MENTION`` env var, default ``false``.\n+        Mirrors Discord adapter's parsing pattern.\n+        \"\"\"\n+        configured = config.extra.get(\"thread_require_mention\")\n+        if configured is not None:\n+            if isinstance(configured, bool):\n+                return configured\n+            if isinstance(configured, str):\n+                return configured.lower() not in {\"false\", \"0\", \"no\", \"off\"}\n+            # int, float, etc. — truthiness fallback\n+            return bool(configured)\n+        return os.getenv(\n+            \"MATRIX_THREAD_REQUIRE_MENTION\", \"false\"\n+        ).lower() in {\"true\", \"1\", \"yes\", \"on\"}\n+\n     # ------------------------------------------------------------------\n     # E2EE helpers\n     # ------------------------------------------------------------------","@@ -1701,6 +1723,21 @@ async def _resolve_message_context(\n                     )\n                     return None\n \n+            # Thread-level @mention gating: even in a bot-participated thread,\n+            # require @mention when thread_require_mention is enabled.\n+            # Prevents infinite reply loops in multi-agent shared rooms\n+            # where multiple bots all participate in the same thread.\n+            elif (self._thread_require_mention and in_bot_thread\n+                  and not is_free_room):\n+                if not is_mentioned:\n+                    logger.debug(\n+                        \"Matrix: ignoring message %s in thread %s — \"\n+                        \"no @mention (thread_require_mention=true)\",\n+                        event_id,\n+                        thread_id,\n+                    )\n+                    return None\n+\n         # DM mention-thread.\n         if is_dm and not thread_id and self._dm_mention_threads and is_mentioned:\n             thread_id = event_id\n"]}]}],"trust":{"default_tier":"verified","includes_suggested":false}}