{"repo":"NousResearch/hermes-agent","public_id":"12290","display_label":"edit_message missing finalize kwarg across platform adapters","summary":"Multiple platform adapters (WhatsApp, Telegram, Discord, Slack, Matrix, Mattermost) do not accept a 'finalize' keyword argument in their edit_message implementations. Issues and fixes address adding this missing parameter consistently across all adapters.","subsystem":"gateway","counts":{"members":6,"open_issues":0,"open_issues_distinct":0,"open_prs":0,"closed_issues":3,"merged_prs":1,"attempt_prs":2},"landed_fix":{"status":"merged_to_main","basis":"structural","pr":12854},"resolution":{"state":"partially_resolved","by":"pr-12854"},"freshness":{"state":"stale","last_verified_at":"2026-04-20T05:46:47+00:00","is_stale":true},"grouping":{"backbone":"STRUCTURAL_PARTIAL","link_density":0.272},"fix_edges":[{"issue_number":12579,"pr_number":12854,"tier":"verified","basis":"closing_ref","confidence":0.95,"recoverable_from_timeline":true}],"members":[{"kind":"issue","number":12290,"title":"fix(mattermost): edit_message rejects finalize kwarg after DingTalk AI Cards merge","url":null,"state":"closed"},{"kind":"issue","number":12579,"title":"edit_message missing finalize parameter in Telegram/Discord/Slack/Matrix adapters","url":null,"state":"closed"},{"kind":"issue","number":12925,"title":"WhatsApp streaming broken in v0.10.0: edit_message() rejects 'finalize' kwarg","url":null,"state":"closed"},{"kind":"pr","number":12601,"title":"fix(gateway): accept finalize kwarg in all platform edit_message overrides","url":null,"state":"closed","close_reason":{"refs":[{"kind":"pr","value":"#12854","number":12854}],"category":"merged_via","implication":"superseded"},"merged":false},{"kind":"pr","number":12828,"title":"fix(gateway): add missing finalize parameter to edit_message in all platform adapters","url":null,"state":"closed","close_reason":{"refs":[{"kind":"pr","value":"#12854","number":12854},{"kind":"pr","value":"#12601","number":12601}],"category":"superseded_by_pr","implication":"superseded"},"merged":false},{"kind":"pr","number":12854,"title":"fix(gateway): accept finalize kwarg in all platform edit_message overrides","url":null,"state":"merged","close_reason":{"category":"merged","implication":"superseded"},"merged":true,"is_fix_pr":true,"fix_tier":"verified","files_changed":["gateway/platforms/discord.py","gateway/platforms/feishu.py","gateway/platforms/matrix.py","gateway/platforms/mattermost.py","gateway/platforms/slack.py","gateway/platforms/telegram.py","gateway/platforms/whatsapp.py","scripts/release.py","tests/gateway/test_stream_consumer.py"],"fix_hunks":[{"file":"gateway/platforms/discord.py","hunks":["@@ -1081,6 +1081,8 @@ async def edit_message(\n         chat_id: str,\n         message_id: str,\n         content: str,\n+        *,\n+        finalize: bool = False,\n     ) -> SendResult:\n         \"\"\"Edit a previously sent Discord message.\"\"\"\n         if not self._client:"]},{"file":"gateway/platforms/feishu.py","hunks":["@@ -1468,6 +1468,8 @@ async def edit_message(\n         chat_id: str,\n         message_id: str,\n         content: str,\n+        *,\n+        finalize: bool = False,\n     ) -> SendResult:\n         \"\"\"Edit a previously sent Feishu text/post message.\"\"\"\n         if not self._client:"]},{"file":"gateway/platforms/matrix.py","hunks":["@@ -825,7 +825,7 @@ async def stop_typing(self, chat_id: str) -> None:\n \n \n     async def edit_message(\n-        self, chat_id: str, message_id: str, content: str\n+        self, chat_id: str, message_id: str, content: str, *, finalize: bool = False\n     ) -> SendResult:\n         \"\"\"Edit an existing message (via m.replace).\"\"\"\n "]},{"file":"gateway/platforms/mattermost.py","hunks":["@@ -304,7 +304,7 @@ async def send_typing(\n         )\n \n     async def edit_message(\n-        self, chat_id: str, message_id: str, content: str\n+        self, chat_id: str, message_id: str, content: str, *, finalize: bool = False\n     ) -> SendResult:\n         \"\"\"Edit an existing post.\"\"\"\n         formatted = self.format_message(content)"]},{"file":"gateway/platforms/slack.py","hunks":["@@ -316,6 +316,8 @@ async def edit_message(\n         chat_id: str,\n         message_id: str,\n         content: str,\n+        *,\n+        finalize: bool = False,\n     ) -> SendResult:\n         \"\"\"Edit a previously sent Slack message.\"\"\"\n         if not self._app:"]},{"file":"gateway/platforms/telegram.py","hunks":["@@ -1081,6 +1081,8 @@ async def edit_message(\n         chat_id: str,\n         message_id: str,\n         content: str,\n+        *,\n+        finalize: bool = False,\n     ) -> SendResult:\n         \"\"\"Edit a previously sent Telegram message.\"\"\"\n         if not self._bot:"]},{"file":"gateway/platforms/whatsapp.py","hunks":["@@ -655,6 +655,8 @@ async def edit_message(\n         chat_id: str,\n         message_id: str,\n         content: str,\n+        *,\n+        finalize: bool = False,\n     ) -> SendResult:\n         \"\"\"Edit a previously sent message via the WhatsApp bridge.\"\"\"\n         if not self._running or not self._http_session:"]},{"file":"scripts/release.py","hunks":["@@ -219,6 +219,7 @@\n     \"[redacted:email]\": \"iacker\",\n     \"[redacted:email]\": \"sontianye\",\n     \"[redacted:email]\": \"jackjin1997\",\n+    \"[redacted:email]\": \"jackjin1997\",\n     \"[redacted:email]\": \"danieldoderlein\",\n     \"[redacted:email]\": \"lrawnsley\",\n     \"[redacted:email]\": \"taeuk178\","]},{"file":"tests/gateway/test_stream_consumer.py","hunks":["@@ -133,6 +133,43 @@ async def test_identical_text_skip_respects_adapter_flag(self):\n         assert picky.edit_message.call_args[1][\"finalize\"] is True\n \n \n+class TestEditMessageFinalizeSignature:\n+    \"\"\"Every concrete platform adapter must accept the ``finalize`` kwarg.\n+\n+    stream_consumer._send_or_edit always passes ``finalize=`` to\n+    ``adapter.edit_message(...)`` (see gateway/stream_consumer.py).  An\n+    adapter that overrides edit_message without accepting finalize raises\n+    TypeError the first time streaming hits a segment break or final edit.\n+    Guard the contract with an explicit signature check so it cannot\n+    silently regress — existing tests use MagicMock which swallows any\n+    kwarg and cannot catch this.\n+    \"\"\"\n+\n+    @pytest.mark.parametrize(\n+        \"module_path,class_name\",\n+        [\n+            (\"gateway.platforms.telegram\", \"TelegramAdapter\"),\n+            (\"gateway.platforms.discord\", \"DiscordAdapter\"),\n+            (\"gateway.platforms.slack\", \"SlackAdapter\"),\n+            (\"gateway.platforms.matrix\", \"MatrixAdapter\"),\n+            (\"gateway.platforms.mattermost\", \"MattermostAdapter\"),\n+            (\"gateway.platforms.feishu\", \"FeishuAdapter\"),\n+            (\"gateway.platforms.whatsapp\", \"WhatsAppAdapter\"),\n+            (\"gateway.platforms.dingtalk\", \"DingTalkAdapter\"),\n+        ],\n+    )\n+    def test_edit_message_accepts_finalize(self, module_path, class_name):\n+        import inspect\n+\n+        module = pytest.importorskip(module_path)\n+        cls = getattr(module, class_name)\n+        params = inspect.signature(cls.edit_message).parameters\n+        assert \"finalize\" in params, (\n+            f\"{class_name}.edit_message must accept 'finalize' kwarg; \"\n+            f\"stream_consumer._send_or_edit passes it unconditionally\"\n+        )\n+\n+\n class TestSendOrEditMediaStripping:\n     \"\"\"Verify _send_or_edit strips MEDIA: before sending to the platform.\"\"\"\n \n"]}]}],"trust":{"default_tier":"verified","includes_suggested":false}}