Skip to content

fix: handle forum/topics in Telegram DM thread routing#18021

Merged
steipete merged 1 commit intoopenclaw:mainfrom
8BlT:fix/telegram-dm-forum-thread-routing
Feb 16, 2026
Merged

fix: handle forum/topics in Telegram DM thread routing#18021
steipete merged 1 commit intoopenclaw:mainfrom
8BlT:fix/telegram-dm-forum-thread-routing

Conversation

@8BlT
Copy link
Contributor

@8BlT 8BlT commented Feb 16, 2026

Fixes #17980

Problem

resolveTelegramThreadSpec did not check isForum in the non-group (DM) path. When a Telegram DM chat has forum/topics enabled (e.g. Saved Messages, business accounts), messages arrive with is_forum: true and a message_thread_id, but the function returned scope: "dm" — causing all topics to collapse into a single flat session.

Fix

Added an isForum check in the DM path of resolveTelegramThreadSpec:

  • DM + isForum + messageThreadId → returns { id, scope: "forum" } so each topic gets its own session and buildTelegramThreadParams includes message_thread_id in API calls.
  • DM + messageThreadId (no forum) → unchanged behavior, returns { id, scope: "dm" } preserving thread session routing (threadId not saved in deliveryContext for DM topics (Topics in Private Chats) #8891).
  • Plain DM → unchanged, returns { scope: "dm" }.

Tests

Added 5 new test cases for resolveTelegramThreadSpec covering all DM/group/forum combinations. All existing tests (39 total across 3 related test files) pass.

Greptile Summary

Fixed resolveTelegramThreadSpec to properly handle DM chats with forum/topics enabled (e.g., Saved Messages, business accounts). The function now checks isForum in the DM path and returns scope: "forum" when both isForum and messageThreadId are present, ensuring each topic gets its own session. This prevents all topics from collapsing into a single flat DM session while preserving existing thread session routing behavior for non-forum DM threads (issue #8891).

Key changes:

  • Added isForum check in DM path before evaluating messageThreadId
  • DM + isForum + messageThreadId → returns { id, scope: "forum" }
  • DM + messageThreadId (no forum) → unchanged, returns { id, scope: "dm" }
  • Plain DM → unchanged, returns { scope: "dm" }
  • Added comprehensive test coverage with 5 new test cases covering all DM/forum/thread combinations

Confidence Score: 5/5

  • This PR is safe to merge with minimal risk
  • The fix is narrowly scoped, well-tested, and logically sound. It adds a single isForum check to correctly route DM forum topics while preserving all existing behaviors. The 5 new tests comprehensively cover all DM/group/forum/thread combinations, and the change aligns perfectly with how buildTelegramThreadParams already handles the forum vs dm scope distinction. The logic correctly prioritizes the forum check before the non-forum thread check, preventing forum topics from incorrectly falling through to the DM thread path.
  • No files require special attention

Last reviewed commit: 405f507

(3/5) Reply to the agent's comments like "Can you suggest a fix for this @greptileai?" or ask follow-up questions!

resolveTelegramThreadSpec now checks isForum in the non-group path.
DMs with forum/topics enabled return scope 'forum' so each topic
gets its own session, while plain DM threads keep scope 'dm'.
@openclaw-barnacle openclaw-barnacle bot added channel: telegram Channel integration: telegram size: XS labels Feb 16, 2026
@8BlT 8BlT marked this pull request as ready for review February 16, 2026 12:00
mekenthompson pushed a commit to mekenthompson/openclaw that referenced this pull request Feb 16, 2026
Apply fix from openclaw/openclaw PR openclaw#18021.
When a DM chat has is_forum=true, return scope 'forum' instead of 'dm'
so message_thread_id is preserved for topic-enabled bot DMs.

Fixes openclaw#17980
@steipete steipete merged commit e20b87f into openclaw:main Feb 16, 2026
26 checks passed
@8BlT 8BlT deleted the fix/telegram-dm-forum-thread-routing branch February 17, 2026 00:27
@mekenthompson
Copy link

⚠️ This fix is incomplete — buildTelegramThreadParams still strips DM thread IDs

Thanks for the quick fix on resolveTelegramThreadSpec — the scope detection for DM forums is correct. However, there's a second issue downstream that this PR doesn't address: buildTelegramThreadParams returns undefined for all scope: "dm" threads, which means replies to DM topics are sent without message_thread_id and land in the main chat instead of the topic thread.

The problem

In helpers.ts, buildTelegramThreadParams:

if (thread.scope === "dm") {
    return undefined; // ← drops ALL DM thread IDs, including topic threads
}

With this PR merged, DM forum topics now correctly get scope: "forum" and route to separate sessions. But non-forum DM threads (regular reply threads in private chats) still get scope: "dm" with a thread ID — and that ID gets silently dropped when building API params. The bot knows which topic it's in (session routing works) but sends the reply to the wrong place.

Suggested fix

Change buildTelegramThreadParams to pass through positive DM thread IDs instead of stripping them all:

if (thread.scope === "dm") {
    return normalized > 0 ? { message_thread_id: normalized } : undefined;
}

This way:

  • DM topics (thread ID > 0) → message_thread_id included → reply lands in correct topic
  • Plain DMs (no thread ID) → still returns undefined → no change

Additional context

I hit this in production with a bot DM that has forum/topics enabled. After applying PR #18021, sessions routed correctly (each topic got its own session) but all replies went to the main chat. Adding the buildTelegramThreadParams fix resolved it fully.

The delivery.test.ts test for this case was also asserting the wrong thing — it expected DM threads to NOT include message_thread_id, which masked the bug:

- it("does not include message_thread_id for DMs (threads don't exist in private chats)", ...
-   thread: { id: 1, scope: "dm" },
-   expect.not.objectContaining({ message_thread_id: 1 })
+ it("includes message_thread_id for DM topics", ...
+   thread: { id: 42, scope: "dm" },
+   expect.objectContaining({ message_thread_id: 42 })

Happy to open a follow-up PR if that's easier.

@mekenthompson
Copy link

This is already addressed by PR #18586 (fix(telegram): include DM topic thread id in replies), which was merged shortly before this PR.

Timeline:

Between the two PRs, the full fix from #17980 is on main:

  • Inbound (resolveTelegramThreadSpec): DM + isForum + messageThreadIdscope: "forum"
  • Outbound (buildTelegramThreadParams): DM scope threads with positive IDs → message_thread_id included ✅

Test coverage was also updated in #18586 across helpers.test.ts, delivery.test.ts, and draft-stream.test.ts.

@ngutman
Copy link
Contributor

ngutman commented Feb 17, 2026

Reverted in 9f907320c.

This PR was accidentally merged into main, so we reverted it.

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

Labels

channel: telegram Channel integration: telegram size: XS

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Telegram DM with forum/topics enabled loses thread routing after v2026.2.15

4 participants

Comments