Skip to content

feat(telegram): isolate forum topic threads into separate conversations#326

Open
toanalien wants to merge 5 commits intospacedriveapp:mainfrom
toanalien:feat/telegram-thread-chat
Open

feat(telegram): isolate forum topic threads into separate conversations#326
toanalien wants to merge 5 commits intospacedriveapp:mainfrom
toanalien:feat/telegram-thread-chat

Conversation

@toanalien
Copy link
Contributor

Summary

  • Each Telegram forum topic (supergroup with Topics enabled) now gets its own isolated conversation with separate history
  • Bot replies are routed back to the correct topic instead of falling into the main chat
  • Typing indicators are scoped to the correct topic
  • Documentation added for multiple bot instances and forum topic behavior

- Add `thread_id: Option<ThreadId>` field to `ActiveStream` struct
- Extract thread ID via `extract_thread_id()` helper for topic messages
- Scope `conversation_id` to thread: `telegram:{chat_id}:{thread_id}`
- Store `telegram_thread_id` in metadata when `is_topic_message`
- Pass thread ID to all outbound send functions: `send_formatted`,
  `send_plain_text`, `send_poll`, `send_audio`, `send_document`,
  `send_chat_action`
- Route typing indicator and stream placeholder to correct forum topic
- Add "Multiple Telegram Instances" section with UI and TOML config examples
- Add "Threads (Group Topics)" section explaining forum topic isolation behavior
- Extend troubleshooting table with 2 new rows covering thread-related issues
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Mar 5, 2026

Walkthrough

Adds documentation for running multiple Telegram bot instances and implements Telegram forum topic threading in the adapter, propagating an optional thread_id through inbound/outbound paths, metadata, and message-sending helpers.

Changes

Cohort / File(s) Summary
Documentation
docs/content/docs/(messaging)/telegram-setup.mdx
Added "Multiple Telegram Instances" section with UI steps and TOML examples; added troubleshooting entries for named-instance routing and topic/privacy issues.
Telegram Threading Support
src/messaging/telegram.rs
Added extraction and propagation of optional thread_id through message handling, updated conversation keying, metadata, ActiveStream, and made send helpers (send_poll, send_plain_text, send_formatted, and others) thread-aware via updated signatures and API calls.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main change: isolating Telegram forum topic threads into separate conversations, which is reflected in both the code changes (thread_id propagation) and documentation updates.
Description check ✅ Passed The description is directly related to the changeset, covering the key aspects: forum topic isolation, conversation separation, reply routing, typing indicators, and documentation updates.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

.metadata
.get("telegram_thread_id")
.and_then(|v| v.as_i64())
.map(|v| v as i32)?;
Copy link
Contributor

Choose a reason for hiding this comment

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

Nice addition. Small robustness tweak: as i32 will truncate on overflow; I'd rather try_from and ignore unexpected values.

Suggested change
.map(|v| v as i32)?;
let id = message
.metadata
.get("telegram_thread_id")
.and_then(|v| v.as_i64())
.and_then(|v| i32::try_from(v).ok())
.filter(|&v| v > 0)?;

if let Some(ThreadId(MessageId(tid))) = message.thread_id {
metadata.insert(
"telegram_thread_id".into(),
serde_json::Value::Number(tid.into()),
Copy link
Contributor

Choose a reason for hiding this comment

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

tid here is an i32; Value::Number(tid.into()) relies on serde_json::Number: From<i32>. To avoid surprising trait issues, Value::from(tid) is simpler.

Suggested change
serde_json::Value::Number(tid.into()),
serde_json::Value::from(tid),

Spacebot reads messages from all topics the bot can see. Each topic maintains its own conversation context, so the bot won't mix up discussions between topics.

<Callout type="info">
Telegram doesn't support creating named threads via the Bot API. Spacebot replies within the same topic where the message was sent, keeping replies in context.
Copy link
Contributor

Choose a reason for hiding this comment

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

Nit: Telegram does expose forum-topic APIs (e.g. createForumTopic). If the intent is "Spacebot doesn't create topics", maybe rephrase.

Suggested change
Telegram doesn't support creating named threads via the Bot API. Spacebot replies within the same topic where the message was sent, keeping replies in context.
Telegram supports forum-topic APIs in the Bot API, but Spacebot doesn’t create/manage topics yet. Spacebot replies within the same topic where the message was sent, keeping replies in context.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (1)
docs/content/docs/(messaging)/telegram-setup.mdx (1)

215-226: Optional: add one line clarifying topic-mode log conversation_id format.

A brief note that topic messages can appear as telegram:<chat_id>:<thread_id> in logs would reduce confusion when users are trying to extract chat IDs.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/content/docs/`(messaging)/telegram-setup.mdx around lines 215 - 226, Add
a single clarifying sentence under the "Threads (Group Topics)" section (near
the "Spacebot reads messages from all topics..." paragraph) stating the
log/conversation_id format for topic-mode messages so users can extract
chat/thread IDs; specifically note that topic messages may appear as
conversation_id values like telegram:<chat_id>:<thread_id> in logs and tooling.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/messaging/telegram.rs`:
- Around line 103-108: The metadata extraction uses unchecked casts (v as i32)
for "telegram_thread_id" and "telegram_message_id" which can silently wrap;
replace those .map(|v| v as i32) conversions with a checked conversion like
.and_then(|v| i32::try_from(v).ok()) so overflow yields None instead of
incorrect values; update the chains that build ThreadId(MessageId(...)) and any
similar use in the same file (e.g., where telegram_message_id is converted) to
use i32::try_from and preserve the surrounding Option handling.
- Around line 365-373: Rename the abbreviated local bindings to full names
across the file: change any pattern like "if let Some(tid) = thread_id" to "if
let Some(thread_id_value) = thread_id" and rename any short request builders
bound as "req" to "request" (e.g., where you build request with
self.bot.send_audio(...), self.bot.send_message(...), etc.). Update all matching
occurrences listed (the blocks around the shown diff and the other line ranges
mentioned) so the new binding names are used consistently (e.g., call
message_thread_id(thread_id_value) and continue using "request" for the
builder), adjusting any subsequent uses of the old identifiers to the new names
to preserve compilation.

---

Nitpick comments:
In `@docs/content/docs/`(messaging)/telegram-setup.mdx:
- Around line 215-226: Add a single clarifying sentence under the "Threads
(Group Topics)" section (near the "Spacebot reads messages from all topics..."
paragraph) stating the log/conversation_id format for topic-mode messages so
users can extract chat/thread IDs; specifically note that topic messages may
appear as conversation_id values like telegram:<chat_id>:<thread_id> in logs and
tooling.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: e6f87da5-938d-4a72-82ea-c94737c8633f

📥 Commits

Reviewing files that changed from the base of the PR and between 7f22fcb and 6bb8dc3.

📒 Files selected for processing (2)
  • docs/content/docs/(messaging)/telegram-setup.mdx
  • src/messaging/telegram.rs

Comment on lines +365 to +373
if let Some(tid) = thread_id {
request = request.message_thread_id(tid);
}
request.send().await
} else {
self.bot.send_audio(chat_id, input_file).send().await
let mut request = self.bot.send_audio(chat_id, input_file);
if let Some(tid) = thread_id {
request = request.message_thread_id(tid);
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

rg -nP '\b(tid|req)\b' src/messaging/telegram.rs | head -30

Repository: spacedriveapp/spacebot

Length of output: 1988


Rename abbreviated locals to match Rust coding guidelines (tidthread_id_value, reqrequest).

Per coding guidelines, avoid abbreviating variable names. Replace tid (for thread_id extraction) and req (for request builders) with their full names throughout the file for consistency and readability. This applies to the new thread-routing blocks at lines 365–373, 388–390, 408–410, 431–433, 470–474, 565–568, 1012–1014, 1239–1241, 1283–1285, and the existing pattern-matching uses at lines 265–266 and 850–853.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/messaging/telegram.rs` around lines 365 - 373, Rename the abbreviated
local bindings to full names across the file: change any pattern like "if let
Some(tid) = thread_id" to "if let Some(thread_id_value) = thread_id" and rename
any short request builders bound as "req" to "request" (e.g., where you build
request with self.bot.send_audio(...), self.bot.send_message(...), etc.). Update
all matching occurrences listed (the blocks around the shown diff and the other
line ranges mentioned) so the new binding names are used consistently (e.g.,
call message_thread_id(thread_id_value) and continue using "request" for the
builder), adjusting any subsequent uses of the old identifiers to the new names
to preserve compilation.

- Replace v as i32 with i32::try_from(v).ok() for safe overflow handling
  in extract_message_id and extract_thread_id
- Rename req → request in StreamStart and send_chat_action paths
- Add conversation_id format note to docs (telegram:<chat_id>:<thread_id>)
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

♻️ Duplicate comments (1)
docs/content/docs/(messaging)/telegram-setup.mdx (1)

228-228: ⚠️ Potential issue | 🟡 Minor

Line 228: Rephrase Bot API capability statement to avoid factual mismatch.

Telegram Bot API does expose forum-topic methods; this should say Spacebot currently does not create/manage topics, rather than Telegram not supporting it.

Proposed wording
-Telegram doesn't support creating named threads via the Bot API. Spacebot replies within the same topic where the message was sent, keeping replies in context.
+Telegram supports forum-topic APIs in the Bot API, but Spacebot doesn’t create or manage topics yet. Spacebot replies within the same topic where the message was sent, keeping replies in context.
Does the Telegram Bot API currently include forum-topic management methods (for example createForumTopic / editForumTopic / closeForumTopic)?
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/content/docs/`(messaging)/telegram-setup.mdx at line 228, Replace the
sentence "Telegram doesn't support creating named threads via the Bot API." with
a factual rephrase stating that Spacebot itself does not create or manage forum
topics (e.g., "Spacebot currently does not create or manage forum topics; it
replies within the same topic where the message was sent, keeping replies in
context."), and optionally note that Telegram's Bot API does include forum-topic
methods (such as createForumTopic/editForumTopic/closeForumTopic) if you want to
acknowledge the platform capability.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@docs/content/docs/`(messaging)/telegram-setup.mdx:
- Line 228: Replace the sentence "Telegram doesn't support creating named
threads via the Bot API." with a factual rephrase stating that Spacebot itself
does not create or manage forum topics (e.g., "Spacebot currently does not
create or manage forum topics; it replies within the same topic where the
message was sent, keeping replies in context."), and optionally note that
Telegram's Bot API does include forum-topic methods (such as
createForumTopic/editForumTopic/closeForumTopic) if you want to acknowledge the
platform capability.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 08471342-2553-4447-ac81-dc5b1b554b89

📥 Commits

Reviewing files that changed from the base of the PR and between 6bb8dc3 and 51e1e2b.

📒 Files selected for processing (2)
  • docs/content/docs/(messaging)/telegram-setup.mdx
  • src/messaging/telegram.rs

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