Skip to content

feat(telegram): add require_mention support for group chats - #2508

Closed
ctlst wants to merge 1 commit into
NousResearch:mainfrom
ctlst:feature/telegram-require-mention
Closed

ctlst wants to merge 1 commit into
NousResearch:mainfrom
ctlst:feature/telegram-require-mention

Conversation

@ctlst

@ctlst ctlst commented Mar 22, 2026

Copy link
Copy Markdown
Contributor

What does this PR do?

Adds the same require_mention behavior that Discord already has to the Telegram gateway. In group chats, the bot only responds when @mentioned, replied to, or when a trigger word is detected — preventing it from responding to every message.

This requires BotFather group privacy mode to be turned OFF so the bot receives all group messages. With privacy mode ON (default), Telegram filters messages before they reach the bot, making application-level filtering redundant.

All settings are optional and default to preserving stock behavior — a fresh install with no config changes behaves identically to before this PR.

Related Issue

No existing issue. This was discovered while deploying Hermes in a Telegram group chat where the bot responded to every message without a way to filter.

Type of Change

  • ✨ New feature (non-breaking change that adds functionality)

Changes Made

  • gateway/platforms/telegram.py: Add 4 methods to TelegramAdapter:
    • _is_bot_mentioned(message) — detects @username and text_mention entities
    • _is_reply_to_bot(message) — checks if message replies to bot
    • _strip_bot_mention(text) — removes @botName from message text
    • _should_skip_group_message(message) — orchestrates all filtering (mention, reply, free channels, trigger words)
    • Modified _handle_text_message and _handle_media_message to call skip check early
  • gateway/config.py: Bridge telegram.require_mention, telegram.free_response_channels, and telegram.trigger_words from config.yaml to env vars (same pattern as existing Discord config bridge)
  • tests/gateway/test_telegram_require_mention.py: 28 tests covering all filtering logic

How to Test

  1. Add to config.yaml:
    telegram:
      require_mention: true
      free_response_channels: []
      trigger_words: ["help", "deploy"]
  2. Disable BotFather group privacy mode (/mybots → Bot Settings → Group Privacy → Turn OFF)
  3. Add bot to a group chat
  4. Send a message without @mention — bot should ignore it
  5. @mention the bot — bot should respond, with mention stripped from input
  6. Reply to the bot's message — bot should respond
  7. Send a message containing a trigger word — bot should respond
  8. Run tests: pytest tests/gateway/test_telegram_require_mention.py -v

Checklist

Code

  • I've read the Contributing Guide
  • My commit messages follow Conventional Commits (fix(scope):, feat(scope):, etc.)
  • I searched for existing PRs to make sure this isn't a duplicate
  • My PR contains only changes related to this fix/feature (no unrelated commits)
  • I've run pytest tests/ -q and all tests pass
  • I've added tests for my changes (required for bug fixes, strongly encouraged for features)
  • I've tested on my platform: Arch Linux (Docker container, python 3.11), macOS (local dev)

Documentation & Housekeeping

  • I've updated relevant documentation (README, docs/, docstrings) — or N/A
  • I've updated cli-config.yaml.example if I added/changed config keys — or N/A
  • I've updated CONTRIBUTING.md or AGENTS.md if I changed architecture or workflows — or N/A
  • I've considered cross-platform impact (Windows, macOS) per the compatibility guide — or N/A
  • I've updated tool descriptions/schemas if I changed tool behavior — or N/A

Screenshots / Logs

28 tests passing:

tests/gateway/test_telegram_require_mention.py::TestIsBotMentioned::test_mentioned_by_username PASSED
tests/gateway/test_telegram_require_mention.py::TestIsBotMentioned::test_mentioned_case_insensitive PASSED
tests/gateway/test_telegram_require_mention.py::TestIsBotMentioned::test_not_mentioned PASSED
tests/gateway/test_telegram_require_mention.py::TestIsBotMentioned::test_different_bot_mentioned PASSED
tests/gateway/test_telegram_require_mention.py::TestIsBotMentioned::test_text_mention PASSED
tests/gateway/test_telegram_require_mention.py::TestIsBotMentioned::test_text_mention_wrong_user PASSED
tests/gateway/test_telegram_require_mention.py::TestIsBotMentioned::test_no_bot PASSED
tests/gateway/test_telegram_require_mention.py::TestIsReplyToBot::test_reply_to_bot PASSED
tests/gateway/test_telegram_require_mention.py::TestIsReplyToBot::test_not_a_reply PASSED
tests/gateway/test_telegram_require_mention.py::TestIsReplyToBot::test_reply_to_other_user PASSED
tests/gateway/test_telegram_require_mention.py::TestStripBotMention::test_strips_mention PASSED
tests/gateway/test_telegram_require_mention.py::TestStripBotMention::test_strips_case_insensitive PASSED
tests/gateway/test_telegram_require_mention.py::TestStripBotMention::test_strips_mention_mid_text PASSED
tests/gateway/test_telegram_require_mention.py::TestStripBotMention::test_no_mention_unchanged PASSED
tests/gateway/test_telegram_require_mention.py::TestStripBotMention::test_no_bot PASSED
tests/gateway/test_telegram_require_mention.py::TestShouldSkipGroupMessage::test_dm_never_skipped PASSED
tests/gateway/test_telegram_require_mention.py::TestShouldSkipGroupMessage::test_group_without_mention_skipped PASSED
tests/gateway/test_telegram_require_mention.py::TestShouldSkipGroupMessage::test_supergroup_without_mention_skipped PASSED
tests/gateway/test_telegram_require_mention.py::TestShouldSkipGroupMessage::test_group_with_mention_not_skipped PASSED
tests/gateway/test_telegram_require_mention.py::TestShouldSkipGroupMessage::test_group_with_reply_not_skipped PASSED
tests/gateway/test_telegram_require_mention.py::TestShouldSkipGroupMessage::test_require_mention_disabled PASSED
tests/gateway/test_telegram_require_mention.py::TestShouldSkipGroupMessage::test_require_mention_default_true PASSED
tests/gateway/test_telegram_require_mention.py::TestShouldSkipGroupMessage::test_free_response_channel PASSED
tests/gateway/test_telegram_require_mention.py::TestShouldSkipGroupMessage::test_not_in_free_response_channel PASSED
tests/gateway/test_telegram_require_mention.py::TestShouldSkipGroupMessage::test_trigger_word_match PASSED
tests/gateway/test_telegram_require_mention.py::TestShouldSkipGroupMessage::test_trigger_word_case_insensitive PASSED
tests/gateway/test_telegram_require_mention.py::TestShouldSkipGroupMessage::test_trigger_word_no_match PASSED
tests/gateway/test_telegram_require_mention.py::TestShouldSkipGroupMessage::test_trigger_words_empty_default PASSED

28 passed in 0.08s

Adds the same require_mention behavior that Discord already has to the
Telegram gateway. In group chats, the bot now only responds when
@mentioned or replied to, preventing it from responding to every message.

NOTE: These features require BotFather group privacy mode to be turned
OFF so the bot receives all group messages. With privacy mode ON
(default), Telegram itself filters messages before they reach the bot,
making application-level filtering redundant.

Configuration (all optional, defaults preserve stock behavior):
- telegram.require_mention in config.yaml (default: true)
- telegram.free_response_channels: chat IDs where bot responds freely
- telegram.trigger_words: words that trigger a response without @mention
- Env var overrides: TELEGRAM_REQUIRE_MENTION, TELEGRAM_FREE_RESPONSE_CHANNELS,
  TELEGRAM_TRIGGER_WORDS

Example config.yaml:
  telegram:
    require_mention: true
    free_response_channels: [-100123456]
    trigger_words: ["help", "deploy"]

Changes:
- gateway/platforms/telegram.py: Add mention detection, reply-to-bot
  check, mention stripping, trigger word matching, and group message
  filtering for both text and media handlers
- gateway/config.py: Bridge telegram settings from config.yaml to env
  vars (require_mention, free_response_channels, trigger_words)
- tests/gateway/test_telegram_require_mention.py: 28 tests covering
  all filtering logic
@ctlst
ctlst marked this pull request as ready for review March 22, 2026 15:35
@teknium1

Copy link
Copy Markdown
Collaborator

Thanks for the contribution @ctlst — closing as redundant. PR #3870 (merged March 29) added telegram.require_mention, mention_patterns (regex wake-words, a superset of your trigger_words), and free_response_chats to main. Your PR proposed the same feature set and helped surface the need. Appreciate the detailed test coverage.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants