mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-04-25 00:51:20 +00:00
fix(gateway): accept finalize kwarg in all platform edit_message overrides
stream_consumer._send_or_edit unconditionally passes finalize= to adapter.edit_message(), but only DingTalk's override accepted the kwarg. Streaming on Telegram/Discord/Slack/Matrix/Mattermost/Feishu/ WhatsApp raised TypeError the first time a segment break or final edit fired. The REQUIRES_EDIT_FINALIZE capability flag only gates the redundant final edit (and the identical-text short-circuit), not the kwarg itself — so adapters that opt out of finalize still receive the keyword argument and must accept it. Add *, finalize: bool = False to the 7 non-DingTalk signatures; the body ignores the arg since those platforms treat edits as stateless (consistent with the base class contract in base.py). Add a parametrized signature check over every concrete adapter class so a future override cannot silently drop the kwarg — existing tests use MagicMock which swallows any kwarg and cannot catch this. Fixes #12579
This commit is contained in:
parent
fc5fda5e38
commit
6c0c625952
8 changed files with 49 additions and 2 deletions
|
|
@ -1081,6 +1081,8 @@ class DiscordAdapter(BasePlatformAdapter):
|
|||
chat_id: str,
|
||||
message_id: str,
|
||||
content: str,
|
||||
*,
|
||||
finalize: bool = False,
|
||||
) -> SendResult:
|
||||
"""Edit a previously sent Discord message."""
|
||||
if not self._client:
|
||||
|
|
|
|||
|
|
@ -1468,6 +1468,8 @@ class FeishuAdapter(BasePlatformAdapter):
|
|||
chat_id: str,
|
||||
message_id: str,
|
||||
content: str,
|
||||
*,
|
||||
finalize: bool = False,
|
||||
) -> SendResult:
|
||||
"""Edit a previously sent Feishu text/post message."""
|
||||
if not self._client:
|
||||
|
|
|
|||
|
|
@ -825,7 +825,7 @@ class MatrixAdapter(BasePlatformAdapter):
|
|||
|
||||
|
||||
async def edit_message(
|
||||
self, chat_id: str, message_id: str, content: str
|
||||
self, chat_id: str, message_id: str, content: str, *, finalize: bool = False
|
||||
) -> SendResult:
|
||||
"""Edit an existing message (via m.replace)."""
|
||||
|
||||
|
|
|
|||
|
|
@ -304,7 +304,7 @@ class MattermostAdapter(BasePlatformAdapter):
|
|||
)
|
||||
|
||||
async def edit_message(
|
||||
self, chat_id: str, message_id: str, content: str
|
||||
self, chat_id: str, message_id: str, content: str, *, finalize: bool = False
|
||||
) -> SendResult:
|
||||
"""Edit an existing post."""
|
||||
formatted = self.format_message(content)
|
||||
|
|
|
|||
|
|
@ -316,6 +316,8 @@ class SlackAdapter(BasePlatformAdapter):
|
|||
chat_id: str,
|
||||
message_id: str,
|
||||
content: str,
|
||||
*,
|
||||
finalize: bool = False,
|
||||
) -> SendResult:
|
||||
"""Edit a previously sent Slack message."""
|
||||
if not self._app:
|
||||
|
|
|
|||
|
|
@ -1081,6 +1081,8 @@ class TelegramAdapter(BasePlatformAdapter):
|
|||
chat_id: str,
|
||||
message_id: str,
|
||||
content: str,
|
||||
*,
|
||||
finalize: bool = False,
|
||||
) -> SendResult:
|
||||
"""Edit a previously sent Telegram message."""
|
||||
if not self._bot:
|
||||
|
|
|
|||
|
|
@ -655,6 +655,8 @@ class WhatsAppAdapter(BasePlatformAdapter):
|
|||
chat_id: str,
|
||||
message_id: str,
|
||||
content: str,
|
||||
*,
|
||||
finalize: bool = False,
|
||||
) -> SendResult:
|
||||
"""Edit a previously sent message via the WhatsApp bridge."""
|
||||
if not self._running or not self._http_session:
|
||||
|
|
|
|||
|
|
@ -133,6 +133,43 @@ class TestFinalizeCapabilityGate:
|
|||
assert picky.edit_message.call_args[1]["finalize"] is True
|
||||
|
||||
|
||||
class TestEditMessageFinalizeSignature:
|
||||
"""Every concrete platform adapter must accept the ``finalize`` kwarg.
|
||||
|
||||
stream_consumer._send_or_edit always passes ``finalize=`` to
|
||||
``adapter.edit_message(...)`` (see gateway/stream_consumer.py). An
|
||||
adapter that overrides edit_message without accepting finalize raises
|
||||
TypeError the first time streaming hits a segment break or final edit.
|
||||
Guard the contract with an explicit signature check so it cannot
|
||||
silently regress — existing tests use MagicMock which swallows any
|
||||
kwarg and cannot catch this.
|
||||
"""
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"module_path,class_name",
|
||||
[
|
||||
("gateway.platforms.telegram", "TelegramAdapter"),
|
||||
("gateway.platforms.discord", "DiscordAdapter"),
|
||||
("gateway.platforms.slack", "SlackAdapter"),
|
||||
("gateway.platforms.matrix", "MatrixAdapter"),
|
||||
("gateway.platforms.mattermost", "MattermostAdapter"),
|
||||
("gateway.platforms.feishu", "FeishuAdapter"),
|
||||
("gateway.platforms.whatsapp", "WhatsAppAdapter"),
|
||||
("gateway.platforms.dingtalk", "DingTalkAdapter"),
|
||||
],
|
||||
)
|
||||
def test_edit_message_accepts_finalize(self, module_path, class_name):
|
||||
import inspect
|
||||
|
||||
module = pytest.importorskip(module_path)
|
||||
cls = getattr(module, class_name)
|
||||
params = inspect.signature(cls.edit_message).parameters
|
||||
assert "finalize" in params, (
|
||||
f"{class_name}.edit_message must accept 'finalize' kwarg; "
|
||||
f"stream_consumer._send_or_edit passes it unconditionally"
|
||||
)
|
||||
|
||||
|
||||
class TestSendOrEditMediaStripping:
|
||||
"""Verify _send_or_edit strips MEDIA: before sending to the platform."""
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue