Skip to content

fix(telegram): omit message_thread_id in DM topic fallback sends with reply anchor (#35739)#35759

Open
Tranquil-Flow wants to merge 2 commits into
NousResearch:mainfrom
Tranquil-Flow:fix/35739-telegram-dm-media-refix
Open

fix(telegram): omit message_thread_id in DM topic fallback sends with reply anchor (#35739)#35759
Tranquil-Flow wants to merge 2 commits into
NousResearch:mainfrom
Tranquil-Flow:fix/35739-telegram-dm-media-refix

Conversation

@Tranquil-Flow

Copy link
Copy Markdown
Contributor

What

Fixes #35739 — Media messages (images, screenshots, documents) in Telegram DM topics drop into root chat instead of staying in the topic thread.

Root Cause

When telegram_dm_topic_reply_fallback is active and a reply_to_message_id exists, _thread_kwargs_for_send() returned a resolved message_thread_id. The Telegram Bot API rejects message_thread_id in private chats with BadRequest: message thread not found. The retry path (_send_with_dm_topic_reply_anchor_retry) strips both message_thread_id AND reply_to_message_id, causing media to land in the root chat instead of the topic thread.

Text messages didn't have this bug because their send method had an explicit safeguard — but media send methods (send_multiple_images, send_image_file, send_document) lacked it.

Fix

Centralized the fix in _thread_kwargs_for_send() — when DM topic fallback is active with a reply anchor, return message_thread_id: None instead of the resolved thread ID. The reply_to_message_id anchor alone provides sufficient topic routing. This applies globally across all message types (text + media).

Changes

  1. gateway/platforms/telegram.py: Changed _thread_kwargs_for_send() to return {"message_thread_id": None} for the DM topic fallback + reply anchor case (was: {"message_thread_id": cls._message_thread_id_for_send(thread_id)})
  2. tests/gateway/test_telegram_reply_mode.py: Updated 2 existing test expectations to match corrected behavior

Verification

  • Focused tests: 3/3 pass (TestDMTopicFallbackReplyToModetest_thread_kwargs_suppressed_reply_anchor_when_off, test_thread_kwargs_returns_full_when_first, test_thread_kwargs_no_mode_backward_compat)
  • Full suite: 33 passed, 7 async failures are pre-existing (missing pytest-asyncio in this environment), unrelated to fix
  • Files changed: 2 (gateway/platforms/telegram.py, tests/gateway/test_telegram_reply_mode.py)
  • Style: Matches surrounding code. No new dependencies, no AI attribution.
  • Scope: Exactly one focused commit ahead of upstream/main

… reply anchor (NousResearch#35739)

The Bot API rejects message_thread_id in private chats. Previously,
_thread_kwargs_for_send included it for DM topic fallback sends with a
reply anchor, causing the API to reject media sends. The retry path
(_send_with_dm_topic_reply_anchor_retry) then stripped both thread_id
AND the reply anchor, dropping media into the root chat.

Text sends had a workaround via used_thread_fallback, but media methods
lacked it. Centralize the fix in _thread_kwargs_for_send so it applies
to all message types: return message_thread_id=None when the reply
anchor alone provides sufficient routing.
@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/telegram Telegram bot adapter labels May 31, 2026
…ad_id omission (NousResearch#35739)

The centralized _thread_kwargs_for_send fix returns message_thread_id=None
for private-chat DM topic fallback sends with reply anchors. 15 existing
tests in test_telegram_thread_fallback.py still asserted the old behavior
(message_thread_id == 20197). Updated all assertions to expect None,
matching the correct Bot API behavior for private chats.
@j2h4u

j2h4u commented Jun 12, 2026

Copy link
Copy Markdown

I think there is an adjacent direct_messages_topic_id payload bug still present on current main (d5b94d91f after fetch today).

This is slightly different from the reply-anchor/media retry path described here.

Current _thread_kwargs_for_send() still returns message_thread_id: None together with direct_messages_topic_id in the direct-topic branches:

return {
    "message_thread_id": None,
    "direct_messages_topic_id": int(direct_topic_id),
}

Locations on current main:

  • gateway/platforms/telegram.py around lines 664-668
  • gateway/platforms/telegram.py around lines 672-676

In practice this can produce a Bot API payload equivalent to:

{"message_thread_id": null, "direct_messages_topic_id": 306210}

For private Telegram DM topics, message_thread_id should not be present at all when routing through direct_messages_topic_id. Keeping the key present as null can make Telegram treat the request as a message_thread_id send and route to the root DM / All Messages instead of the intended DM topic.

The minimal fix is to omit message_thread_id entirely in those two direct_messages_topic_id branches:

 return {
-    "message_thread_id": None,
     "direct_messages_topic_id": int(direct_topic_id),
 }

The existing tests currently encode the old behavior in at least these places:

  • tests/gateway/test_telegram_thread_fallback.py::test_send_private_dm_topic_uses_direct_messages_topic_id
  • tests/gateway/test_telegram_thread_fallback.py::test_send_dm_topic_fallback_without_anchor_does_not_crash

Those assertions should check that message_thread_id is absent, not None.

We applied this locally and confirmed the live gateway payload no longer includes message_thread_id for direct DM-topic sends.

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 type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Fix media routing to "All Chats" in Telegram DM Topics (Reply Fallback)

3 participants