From c574b028c11fa6385a694acf9dc0d9fe552da87c Mon Sep 17 00:00:00 2001 From: chengyongru Date: Fri, 5 Jun 2026 14:12:10 +0800 Subject: [PATCH] fix(feishu): allow punctuation after mention placeholders maintainer edit: Keep the shared-prefix guard for Feishu numbered mention keys while still resolving placeholders followed by punctuation, matching the previous user-visible mention behavior. --- nanobot/channels/feishu.py | 6 ++++-- tests/channels/test_feishu_mentions.py | 6 ++++++ 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/nanobot/channels/feishu.py b/nanobot/channels/feishu.py index f8868dbaf..060ba2bb5 100644 --- a/nanobot/channels/feishu.py +++ b/nanobot/channels/feishu.py @@ -485,7 +485,9 @@ class FeishuChannel(BaseChannel): key = mention.key or None if not key: continue - pattern = rf"{re.escape(key)}(?=\s|$)" + # Feishu placeholders are numbered keys like @_user_1. Keep + # punctuation-adjacent mentions valid without matching @_user_10. + pattern = rf"{re.escape(key)}(?![A-Za-z0-9_])" if not re.search(pattern, text): continue @@ -532,7 +534,7 @@ class FeishuChannel(BaseChannel): candidate = text.lstrip() for mention in mentions: key = getattr(mention, "key", None) or "" - if not key or not re.match(rf"{re.escape(key)}(?=\s|$)", candidate): + if not key or not re.match(rf"{re.escape(key)}(?![A-Za-z0-9_])", candidate): continue if not self._is_bot_mention_event(mention): continue diff --git a/tests/channels/test_feishu_mentions.py b/tests/channels/test_feishu_mentions.py index a49e76ee6..0404e87ec 100644 --- a/tests/channels/test_feishu_mentions.py +++ b/tests/channels/test_feishu_mentions.py @@ -44,6 +44,12 @@ class TestResolveMentions: assert "@_user_1" not in result assert "@_user_2" not in result + def test_mention_before_punctuation_replaced(self): + text = "hello @_user_1, are you there?" + mentions = [_mention("@_user_1", "Alice", open_id="ou_a")] + result = FeishuChannel._resolve_mentions(text, mentions) + assert result == "hello @Alice (ou_a), are you there?" + def test_no_mentions_returns_text(self): assert FeishuChannel._resolve_mentions("hello world", None) == "hello world" assert FeishuChannel._resolve_mentions("hello world", []) == "hello world"