Skip to content

feat: add Telegram Secretary Mode (Business API) support - #46728

Open
kxnkxv wants to merge 1 commit into
NousResearch:mainfrom
kxnkxv:feat/telegram-secretary-mode
Open

feat: add Telegram Secretary Mode (Business API) support#46728
kxnkxv wants to merge 1 commit into
NousResearch:mainfrom
kxnkxv:feat/telegram-secretary-mode

Conversation

@kxnkxv

@kxnkxv kxnkxv commented Jun 15, 2026

Copy link
Copy Markdown

Summary

Adds Telegram Secretary Mode (Business API) support to Hermes Agent, letting users connect the bot to their Telegram account so it can read and reply to messages in authorised chats on their behalf.

What was added

  • _handle_business_connection — Tracks BusinessConnection lifecycle (user connects/disconnects the bot). Logged and stored in _business_connections dict.
  • _handle_business_message — Routes incoming business_message updates through the existing text/command/media handler pipeline. Tracks chat_id → business_connection_id mapping for reply context.
  • _effective_update_message — Falls back to update.business_message when no update.effective_message or update.message is present.
  • business_connection_id in send() and _send_message_with_thread_fallback — Injects the tracked business_connection_id so replies are sent on behalf of the account owner (required by Telegram Business API).
  • secretary_mode config bridge — YAML telegram: secretary_mode: true is bridged into PlatformConfig.extra so the adapter can opt in.
  • PTB v22+ type-safe dispatch — Uses filters.UpdateType.BUSINESS_MESSAGE (PTB 22+) with a fallback TypeHandler for older versions.

Configuration

Enable in ~/.hermes/config.yaml:

telegram:
  secretary_mode: true

Then activate Secretary Mode for your bot via @Botfather → Bot Settings → Secretary Mode, and select which chats to grant access to.

Testing

  • ✅ Syntax: Python compile passes
  • ✅ Imports: Module loads without errors in venv (PTB v22.6)
  • ✅ New methods present in AST scan: _handle_business_connection, _handle_business_message
  • _effective_update_message extended with business_message fallback
  • business_connection_id injected in both send() paths (Markdown and plain-text fallback)

Documentation

Type safety

LSP diagnostics show warnings for the except ImportError fallback path (pre-existing pattern — filters, Application, _app, etc. are all Any/None when PTB is not installed). The primary install path has full type coverage.

Enable via config.extra.secretary_mode: true or telegram: secretary_mode: true.

This adds:
- _handle_business_connection — tracks BusinessConnection lifecycle
  (user connects/disconnects the bot as a secretary)
- _handle_business_message — routes business_message updates
  through the standard text/command/media handlers
- _effective_update_message fallback for business_message
- business_connection_id injection in send() and
  _send_message_with_thread_fallback so outgoing replies
  are sent on behalf of the account owner
- _business_chat_to_conn mapping so reply-to-business-message
  works without the account owner needing to manually forward
  the connection context
- Config bridge secretary_mode from YAML → PlatformConfig.extra

Uses filters.UpdateType.BUSINESS_MESSAGE (PTB v22+) for
type-safe dispatch, with a TypeHandler fallback for older
versions.

Docs: https://core.telegram.org/bots/features#secretary-bots

@teknium1 teknium1 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for implementing the Secretary Mode ingress and reply idea. The feature is still absent from current main, but this patch needs substantive salvage before it can run safely.

Problems

  • gateway/platforms/telegram.py:37 imports TypeHandler as _TypeHandler, while the enabled registration path calls TypeHandler(...) at lines 1650 and 1664. With PTB already installed, TypeHandler is undefined and enabling the feature raises NameError.
  • gateway/platforms/telegram.py:6144-6149 routes all business updates without a sender_business_bot guard; the PR source has no bot-echo classification.
  • Business media is routed at line 6148, but _handle_media_message() returns unless update.message is present at lines 5623-5626, rather than using business_message.
  • Current main moved this adapter to plugins/platforms/telegram/adapter.py in 5600105478ffde29d7566b45421b100eaa29c4ef; its YAML bridge now belongs in that plugin's _apply_yaml_config().

Suggested changes

  • Port the work to the plugin surface, bind the handler correctly, carry the connection ID through session metadata, and cover text/media/bot-echo/outbound paths with tests.

Automated hermes-sweeper review.

MessageHandler as TelegramMessageHandler,
ContextTypes,
filters,
TypeHandler as _TypeHandler,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TypeHandler is imported only as _TypeHandler, but the enabled registration path below invokes TypeHandler(...). On the normal installed-PTB import path, TypeHandler is never bound, so enabling secretary_mode raises NameError during adapter connection.


# Process as a regular message — the existing handlers work
# because _effective_update_message falls back to business_message.
if msg.text and (not msg.text.startswith("/")):

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This routes every business text update as customer input. Add bot-echo classification before dispatch (for the relayed business updates created by this adapter's own replies), otherwise the agent can process its own output as a new request.

await self._handle_text_message(update, context)
elif msg.text and msg.text.startswith("/"):
await self._handle_command(update, context)
elif msg.photo or msg.video or msg.audio or msg.voice or msg.document or msg.sticker:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

_handle_media_message() still returns unless update.message exists (lines 5623-5626 in this PR), while this update uses business_message. Business media therefore never reaches the normal media pipeline.

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

Labels

comp/gateway Gateway runner, session dispatch, delivery P3 Low — cosmetic, nice to have platform/telegram Telegram bot adapter sweeper:blast-moderate Sweeper blast radius: moderate — a subsystem or single platform sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades sweeper:risk-message-delivery Sweeper risk: may drop, duplicate, misroute, or suppress messages sweeper:risk-security-boundary Sweeper risk: may affect sandboxing, auth, credentials, or sensitive data type/feature New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants