From 0b637f7d902bfc10b1a8b831eefa52600adfe9bf Mon Sep 17 00:00:00 2001 From: system Date: Tue, 16 Jun 2026 16:51:03 +0900 Subject: [PATCH] =?UTF-8?q?fix(slack):=20re-apply=20bang=E2=86=92slash=20r?= =?UTF-8?q?ewrite=20after=20mention=20strip?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When a user types `@bot !model ...` the message text starts with `<@BOT_UID>`, so the early bang-rewrite pass (which only fires when text starts with `!`) is skipped entirely. After the bot mention is stripped the leading `!` becomes visible, but no second rewrite pass was run, leaving the command as a plain text message instead of a COMMAND-typed dispatch. Fix: after stripping the bot mention, check whether the resulting text starts with `!` and, if it resolves to a known gateway command via `is_gateway_known_command`, rewrite it to `/cmd ...` and sync `original_text` so the downstream `MessageType.COMMAND` detection fires correctly. Reproducer: send `@bot !model jp.anthropic.claude-opus-4 --provider bedrock` in a Slack channel — previously silently ignored, now dispatched as `/model jp.anthropic.claude-opus-4 --provider bedrock`. --- gateway/platforms/slack.py | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/gateway/platforms/slack.py b/gateway/platforms/slack.py index ad1de2a25a1a..26f4dc51bb1b 100644 --- a/gateway/platforms/slack.py +++ b/gateway/platforms/slack.py @@ -2525,6 +2525,27 @@ async def _handle_slack_message(self, event: dict) -> None: if is_mentioned: # Strip the bot mention from the text text = text.replace(f"<@{bot_uid}>", "").strip() + # Re-apply the ``!cmd`` → ``/cmd`` rewrite after stripping the bot + # mention. When a user types ``@bot !model ...`` the original text + # starts with ``<@...>`` so the earlier bang-rewrite pass (which + # only fires when the text starts with ``!``) is skipped. After + # mention-stripping the leading ``!`` is visible, so we run the + # same logic again here to normalise it to a slash command. + if text.startswith("!"): + try: + from hermes_cli.commands import is_gateway_known_command + + first_token = text[1:].split(maxsplit=1)[0] + cmd_name = first_token.split("@", 1)[0].lower() + if ( + cmd_name + and "/" not in cmd_name + and is_gateway_known_command(cmd_name) + ): + text = "/" + text[1:] + original_text = text # keep original_text in sync for MessageType detection + except Exception: # pragma: no cover - defensive + pass # Register this thread so all future messages auto-trigger the bot. # Skipped in strict mode: strict_mention=true bots must be # re-mentioned every turn, so remembering the thread would