mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-05-24 05:41:40 +00:00
fix: follow-up for salvaged PR #22263
- Restore allowed_chats gate before thread_id check so ignored_threads applies universally (even to guest mentions). - Compute _message_mentions_bot once in _should_process_message to eliminate redundant second entity scan when guest_mode=true and the message does not mention the bot. - Remove redundant _is_group_chat from _is_guest_mention (caller already verified the message is a group chat). - Update _telegram_allowed_chats docstring to note guest_mode exception. - Add test coverage: bot_command entity, text_mention entity, caption_entities, and ignored_threads + guest_mode interaction. - Add nik1t7n to AUTHOR_MAP.
This commit is contained in:
parent
55f518e521
commit
dae94fa652
4 changed files with 71 additions and 9 deletions
|
|
@ -3147,8 +3147,9 @@ class TelegramAdapter(BasePlatformAdapter):
|
||||||
def _telegram_allowed_chats(self) -> set[str]:
|
def _telegram_allowed_chats(self) -> set[str]:
|
||||||
"""Return the whitelist of group/supergroup chat IDs the bot will respond in.
|
"""Return the whitelist of group/supergroup chat IDs the bot will respond in.
|
||||||
|
|
||||||
When non-empty, group messages from chats NOT in this set are silently
|
When non-empty, group messages from chats NOT in this set are
|
||||||
ignored — even if the bot is @mentioned. DMs are never filtered.
|
silently ignored unless ``guest_mode`` is enabled and the bot is
|
||||||
|
explicitly @mentioned. DMs are never filtered.
|
||||||
Empty set means no restriction (fully backward compatible).
|
Empty set means no restriction (fully backward compatible).
|
||||||
"""
|
"""
|
||||||
raw = self.config.extra.get("allowed_chats")
|
raw = self.config.extra.get("allowed_chats")
|
||||||
|
|
@ -3296,12 +3297,12 @@ class TelegramAdapter(BasePlatformAdapter):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def _is_guest_mention(self, message: Message) -> bool:
|
def _is_guest_mention(self, message: Message) -> bool:
|
||||||
"""Return True for the narrow guest-mode bypass: group + explicit bot mention."""
|
"""Return True for the narrow guest-mode bypass: explicit bot mention.
|
||||||
return (
|
|
||||||
self._telegram_guest_mode()
|
The caller (:meth:`_should_process_message`) has already verified
|
||||||
and self._is_group_chat(message)
|
the message is a group chat, so that check is not repeated here.
|
||||||
and self._message_mentions_bot(message)
|
"""
|
||||||
)
|
return self._telegram_guest_mode() and self._message_mentions_bot(message)
|
||||||
|
|
||||||
def _clean_bot_trigger_text(self, text: Optional[str]) -> Optional[str]:
|
def _clean_bot_trigger_text(self, text: Optional[str]) -> Optional[str]:
|
||||||
if not text or not self._bot or not getattr(self._bot, "username", None):
|
if not text or not self._bot or not getattr(self._bot, "username", None):
|
||||||
|
|
@ -3344,6 +3345,9 @@ class TelegramAdapter(BasePlatformAdapter):
|
||||||
logger.warning("[%s] Ignoring non-numeric Telegram message_thread_id: %r", self.name, thread_id)
|
logger.warning("[%s] Ignoring non-numeric Telegram message_thread_id: %r", self.name, thread_id)
|
||||||
|
|
||||||
chat_id_str = str(getattr(getattr(message, "chat", None), "id", ""))
|
chat_id_str = str(getattr(getattr(message, "chat", None), "id", ""))
|
||||||
|
|
||||||
|
# Resolve guest-mode mention bypass once so _message_mentions_bot
|
||||||
|
# is not called redundantly in the normal flow below.
|
||||||
guest_mention = self._is_guest_mention(message)
|
guest_mention = self._is_guest_mention(message)
|
||||||
|
|
||||||
# allowed_chats check (whitelist). When set, group messages from chats
|
# allowed_chats check (whitelist). When set, group messages from chats
|
||||||
|
|
@ -3352,6 +3356,7 @@ class TelegramAdapter(BasePlatformAdapter):
|
||||||
allowed = self._telegram_allowed_chats()
|
allowed = self._telegram_allowed_chats()
|
||||||
if allowed and chat_id_str not in allowed:
|
if allowed and chat_id_str not in allowed:
|
||||||
return guest_mention
|
return guest_mention
|
||||||
|
|
||||||
if guest_mention:
|
if guest_mention:
|
||||||
return True
|
return True
|
||||||
if chat_id_str in self._telegram_free_response_chats():
|
if chat_id_str in self._telegram_free_response_chats():
|
||||||
|
|
@ -3360,7 +3365,9 @@ class TelegramAdapter(BasePlatformAdapter):
|
||||||
return True
|
return True
|
||||||
if self._is_reply_to_bot(message):
|
if self._is_reply_to_bot(message):
|
||||||
return True
|
return True
|
||||||
if self._message_mentions_bot(message):
|
# When guest_mode is True, _is_guest_mention already called
|
||||||
|
# _message_mentions_bot above — skip the redundant second call.
|
||||||
|
if not self._telegram_guest_mode() and self._message_mentions_bot(message):
|
||||||
return True
|
return True
|
||||||
return self._message_matches_mention_patterns(message)
|
return self._message_matches_mention_patterns(message)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -76,6 +76,7 @@ AUTHOR_MAP = {
|
||||||
"ngusev@astralinux.ru": "NikolayGusev-astra",
|
"ngusev@astralinux.ru": "NikolayGusev-astra",
|
||||||
"liuguangyong201@hellobike.com": "liuguangyong93",
|
"liuguangyong201@hellobike.com": "liuguangyong93",
|
||||||
"2093036+exiao@users.noreply.github.com": "exiao",
|
"2093036+exiao@users.noreply.github.com": "exiao",
|
||||||
|
"20nik.nosov21@gmail.com": "nik1t7n",
|
||||||
"thunderggnn@gmail.com": "ggnnggez",
|
"thunderggnn@gmail.com": "ggnnggez",
|
||||||
"haozhe4547@gmail.com": "ehz0ah",
|
"haozhe4547@gmail.com": "ehz0ah",
|
||||||
"kevyan1998@gmail.com": "kyan12",
|
"kevyan1998@gmail.com": "kyan12",
|
||||||
|
|
|
||||||
|
|
@ -827,3 +827,40 @@ class TestTelegramGuestMentionGating:
|
||||||
)
|
)
|
||||||
|
|
||||||
assert adapter._should_process_message(message) is False
|
assert adapter._should_process_message(message) is False
|
||||||
|
|
||||||
|
def test_guest_mode_allows_bot_command_entity_outside_allowed_chats(self):
|
||||||
|
"""``/cmd@botname`` is a ``bot_command`` entity, not ``mention``."""
|
||||||
|
adapter = _guest_test_adapter(guest_mode=True, allowed_chats=["-100200"])
|
||||||
|
text = "/status@hermes_bot"
|
||||||
|
message = _guest_group_message(
|
||||||
|
text,
|
||||||
|
chat_id=-100201,
|
||||||
|
entities=[SimpleNamespace(type="bot_command", offset=0, length=len(text))],
|
||||||
|
)
|
||||||
|
|
||||||
|
assert adapter._should_process_message(message) is True
|
||||||
|
|
||||||
|
def test_guest_mode_allows_text_mention_entity_outside_allowed_chats(self):
|
||||||
|
"""MessageEntity(type=text_mention) tags a user by ID — recognised as mention."""
|
||||||
|
adapter = _guest_test_adapter(guest_mode=True, allowed_chats=["-100200"])
|
||||||
|
message = _guest_group_message(
|
||||||
|
"hey there",
|
||||||
|
chat_id=-100201,
|
||||||
|
entities=[SimpleNamespace(type="text_mention", offset=0, length=3, user=SimpleNamespace(id=999))],
|
||||||
|
)
|
||||||
|
|
||||||
|
assert adapter._should_process_message(message) is True
|
||||||
|
|
||||||
|
def test_guest_mode_allows_mention_in_caption_outside_allowed_chats(self):
|
||||||
|
"""Media caption @mention should bypass allowed_chats via guest_mode."""
|
||||||
|
adapter = _guest_test_adapter(guest_mode=True, allowed_chats=["-100200"])
|
||||||
|
text = "look @hermes_bot"
|
||||||
|
message = _guest_group_message(
|
||||||
|
text="",
|
||||||
|
chat_id=-100201,
|
||||||
|
entities=[],
|
||||||
|
)
|
||||||
|
message.caption = text
|
||||||
|
message.caption_entities = [_guest_mention_entity(text)]
|
||||||
|
|
||||||
|
assert adapter._should_process_message(message) is True
|
||||||
|
|
|
||||||
|
|
@ -186,6 +186,23 @@ def test_guest_mode_defaults_to_false_for_allowed_chat_bypass():
|
||||||
assert adapter._should_process_message(mentioned) is False
|
assert adapter._should_process_message(mentioned) is False
|
||||||
|
|
||||||
|
|
||||||
|
def test_guest_mode_mention_dropped_in_ignored_thread():
|
||||||
|
"""A guest mention in an ignored thread is still dropped — thread gate runs first."""
|
||||||
|
adapter = _make_adapter(
|
||||||
|
require_mention=True,
|
||||||
|
allowed_chats=["-200"],
|
||||||
|
guest_mode=True,
|
||||||
|
ignored_threads=[42],
|
||||||
|
)
|
||||||
|
mentioned = _group_message(
|
||||||
|
"hi @hermes_bot",
|
||||||
|
chat_id=-201,
|
||||||
|
entities=[_mention_entity("hi @hermes_bot")],
|
||||||
|
thread_id=42,
|
||||||
|
)
|
||||||
|
assert adapter._should_process_message(mentioned) is False
|
||||||
|
|
||||||
|
|
||||||
def test_ignored_threads_drop_group_messages_before_other_gates():
|
def test_ignored_threads_drop_group_messages_before_other_gates():
|
||||||
adapter = _make_adapter(require_mention=False, free_response_chats=["-200"], ignored_threads=[31, "42"])
|
adapter = _make_adapter(require_mention=False, free_response_chats=["-200"], ignored_threads=[31, "42"])
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue