Skip to content

fix(webhook): forward Telegram DM-topic routing keys from deliver_extra#33396

Closed
briandevans wants to merge 1 commit into
NousResearch:mainfrom
briandevans:fix/webhook-telegram-dm-topic-routing-33375
Closed

fix(webhook): forward Telegram DM-topic routing keys from deliver_extra#33396
briandevans wants to merge 1 commit into
NousResearch:mainfrom
briandevans:fix/webhook-telegram-dm-topic-routing-33375

Conversation

@briandevans

Copy link
Copy Markdown
Contributor

What does this PR do?

PR #32270 (merged 2026-05-25) tightened TelegramAdapter.send() with a fail-loud guard: a private-chat send carrying a thread_id is rejected with Telegram DM topic delivery requires a reply anchor; refusing to send outside the requested topic unless metadata includes one of telegram_reply_to_message_id, direct_messages_topic_id, or telegram_dm_topic_created_for_send. The agent/cron paths populate those keys themselves, but WebhookAdapter._deliver_cross_platform only forwards thread_id, so webhook subscriptions targeting private DM topics fail on every delivery — Hermes accepts the webhook (HTTP 202, delivered: true) and the cross-platform send is refused before reaching Telegram.

Forward the four DM-topic routing keys straight through from deliver_extra to the metadata dict so webhook routes can express the opt-out the same way the agent path can. Mirrors TelegramAdapter._is_private_dm_topic_send predicate precedence: telegram_reply_to_message_id (anchor) > direct_messages_topic_id (true Bot-API DM topic) > telegram_dm_topic_created_for_send (Hermes-created DM topic) > telegram_dm_topic_reply_fallback (reply_to_mode='off' opt-in). Legacy single-key thread_id / message_thread_id forwarding is unchanged.

Related Issue

Fixes #33375

Type of Change

  • 🐛 Bug fix (non-breaking change that fixes an issue)
  • ✨ New feature (non-breaking change that adds functionality)
  • 🔒 Security fix
  • 📝 Documentation update
  • ✅ Tests (adding or improving test coverage)
  • ♻️ Refactor (no behavior change)
  • 🎯 New skill (bundled or hub)

Changes Made

  • gateway/platforms/webhook.py — in _deliver_cross_platform, forward telegram_reply_to_message_id, telegram_dm_topic_created_for_send, telegram_dm_topic_reply_fallback, and direct_messages_topic_id from deliver_extra into metadata so the Telegram adapter's anchor-required guard can route or opt out per the route config.
  • tests/gateway/test_webhook_adapter.py — add four cases to TestDeliverCrossPlatformThreadId covering each opt-out key path: reply-anchor forwarding, Bot-API DM-topic opt-out (direct_messages_topic_id + telegram_dm_topic_created_for_send), Hermes-created DM-topic + reply anchor (telegram_dm_topic_reply_fallback), and keys-without-thread_id.

How to Test

  1. Configure a webhook route whose deliver: telegram deliver_extra includes both chat_id (a private user id) and message_thread_id (a DM-topic id from web.telegram.org), and a Telegram bot in Hermes.
  2. Before this PR: fire the webhook with a signed curl. Hermes returns {"delivered": true, "status": 202} but logs Telegram DM topic delivery requires a reply anchor; refusing to send outside the requested topic and nothing reaches Telegram.
  3. Add telegram_reply_to_message_id (or telegram_dm_topic_created_for_send: true) to the same deliver_extra block on this PR's branch — the send goes through and lands in the requested topic.
  4. uv run --with pytest --with pytest-xdist --with pytest-asyncio python3 -m pytest tests/gateway/test_webhook_adapter.py -v — 69 passed (5 new in TestDeliverCrossPlatformThreadId, plus the existing 64). Regression guard: stashing only the production change leaves the 4 new assertion-based tests failing with Expected: send(... metadata={...}) Actual: send(... metadata=None), restoring it flips them back to passing.

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 focused tests for the touched code and all pass
  • I've added tests for my changes (required for bug fixes, strongly encouraged for features)
  • I've tested on my platform: macOS 15.x

Documentation & Housekeeping

  • I've updated relevant documentation (README, docs/, docstrings) — N/A; behavior change is internal to the cross-platform dispatcher
  • I've updated cli-config.yaml.example if I added/changed config keys — N/A; the deliver_extra keys are already documented in the issue
  • I've updated CONTRIBUTING.md or AGENTS.md if I changed architecture or workflows — N/A
  • I've considered cross-platform impact (Windows, macOS) per the compatibility guide — N/A; pure-Python dict plumbing
  • I've updated tool descriptions/schemas if I changed tool behavior — N/A

Related / Positioning

Audited siblings: tools/send_message_tool.py and gateway/delivery.py already build their own metadata dicts that include the opt-out keys when applicable; gateway/platforms/webhook.py::_deliver_cross_platform was the only cross-platform metadata builder missing this. No widening needed.

Copilot AI review requested due to automatic review settings May 27, 2026 18:15

Copilot AI 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.

Pull request overview

Note

Copilot was unable to run its full agentic suite in this review.

Forwards Telegram DM-topic routing signals from deliver_extra through webhook delivery metadata so the Telegram adapter's anchor-required guard can be satisfied or opted out of by webhook routes.

Changes:

  • Extend _deliver_cross_platform to forward four Telegram-specific keys (telegram_reply_to_message_id, telegram_dm_topic_created_for_send, telegram_dm_topic_reply_fallback, direct_messages_topic_id) into the send metadata.
  • Add four async tests covering forwarding of reply anchor, DM-topic opt-out flags, reply fallback marker, and DM-topic keys without a thread_id.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.

File Description
gateway/platforms/webhook.py Forwards Telegram DM-topic signals from deliver_extra into send metadata.
tests/gateway/test_webhook_adapter.py Adds tests verifying each forwarded key reaches the adapter's send metadata.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@alt-glitch alt-glitch added type/bug Something isn't working P2 Medium — degraded but workaround exists comp/gateway Gateway runner, session dispatch, delivery platform/webhook Webhook / API server platform/telegram Telegram bot adapter labels May 27, 2026
@briandevans briandevans force-pushed the fix/webhook-telegram-dm-topic-routing-33375 branch from f68e862 to 4d40e2a Compare May 28, 2026 23:11
PR NousResearch#32270 (2026-05-25) introduced a fail-loud guard in
`TelegramAdapter.send()`: a private-chat send carrying a thread_id is
rejected with "requires a reply anchor" unless metadata includes one of
`telegram_reply_to_message_id`, `direct_messages_topic_id`, or
`telegram_dm_topic_created_for_send`. The agent/cron paths populate
those keys themselves, but `WebhookAdapter._deliver_cross_platform` only
forwarded `thread_id`, so any webhook subscription targeting a private
DM topic now fails on every delivery — Hermes accepts the webhook
(`HTTP 202`, `delivered: true`), then the cross-platform send is
refused before it ever hits Telegram.

Plumb the four DM-topic routing keys straight through from
`deliver_extra` to the metadata dict. Webhook route configs are the
only place the operator can express the opt-out, so this is the
canonical place to wire them in.

Mirrors `TelegramAdapter.send()` predicate precedence:
`telegram_reply_to_message_id` (anchor) > `direct_messages_topic_id`
(true Bot-API DM topic) > `telegram_dm_topic_created_for_send`
(Hermes-created DM topic) > `telegram_dm_topic_reply_fallback`
(reply_to_mode='off' opt-in). Legacy single-key `thread_id` /
`message_thread_id` forwarding is unchanged.
@briandevans briandevans force-pushed the fix/webhook-telegram-dm-topic-routing-33375 branch from 4d40e2a to 2de512d Compare May 30, 2026 00:11
@briandevans

Copy link
Copy Markdown
Contributor Author

Closing to focus the queue on security/file-safety work where civilian merges are landing. Happy to reopen if maintainers want this picked up.

@briandevans briandevans closed this Jun 8, 2026
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 P2 Medium — degraded but workaround exists platform/telegram Telegram bot adapter platform/webhook Webhook / API server type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug] Webhook adapter drops telegram_reply_to_message_id from deliver_extra; all DM-topic webhook deliveries fail

3 participants