Summary
Three related improvements for the Feishu extension that significantly improve group chat UX:
- Always reply in thread — Add
reply_in_thread: true to all im.message.reply calls in send.ts
- Parallel group timeline sessions — Use
messageId as topic key for timeline messages (no rootId) so each message gets its own independent session
- Reply to thread root — Use
ctx.rootId || ctx.messageId as replyToMessageId so replies go to the thread root instead of creating nested sub-threads
- Fire-and-forget message handling — Remove
await on message dispatch in WebSocket mode (monitor.ts) so messages are processed in parallel without blocking the event loop
Motivation
Currently in group chats:
- Bot replies appear on the main timeline, cluttering the chat
- Messages are processed sequentially — if one takes 30s, the next one waits
- Replying to a message inside a thread creates a nested sub-thread instead of keeping the conversation flat within the existing thread
- Timeline messages in the same group share a single session, causing context mixing
These issues make the bot unusable in active group chats with multiple concurrent users.
Proposed Changes
1. reply_in_thread: true in send.ts
Add reply_in_thread: true to the data payload in all im.message.reply API calls. This keeps bot responses contained in threads.
2. Parallel group sessions in bot.ts
When topicSessionMode is enabled for a group, use ctx.rootId ?? ctx.messageId as the topic key instead of only ctx.rootId:
- Thread replies (
rootId present): share session by thread root (existing behavior)
- Timeline messages (no
rootId): each message gets its own session via messageId
This enables true parallel processing in group chats.
3. Reply to thread root in bot.ts
Change replyToMessageId: ctx.messageId → replyToMessageId: ctx.rootId || ctx.messageId so that replies within a thread always target the root message, avoiding nested sub-threads.
4. Fire-and-forget in monitor.ts
In the WebSocket message handler, always use fire-and-forget (.catch() without await) regardless of the fireAndForget flag. Combined with per-message sessions (point 2), this is safe and dramatically improves throughput.
Related
Environment
- Feishu extension:
extensions/feishu/src/send.ts, bot.ts, monitor.ts
- Tested with
topicSessionMode: "enabled" in group config
Summary
Three related improvements for the Feishu extension that significantly improve group chat UX:
reply_in_thread: trueto allim.message.replycalls insend.tsmessageIdas topic key for timeline messages (norootId) so each message gets its own independent sessionctx.rootId || ctx.messageIdasreplyToMessageIdso replies go to the thread root instead of creating nested sub-threadsawaiton message dispatch in WebSocket mode (monitor.ts) so messages are processed in parallel without blocking the event loopMotivation
Currently in group chats:
These issues make the bot unusable in active group chats with multiple concurrent users.
Proposed Changes
1.
reply_in_thread: trueinsend.tsAdd
reply_in_thread: trueto thedatapayload in allim.message.replyAPI calls. This keeps bot responses contained in threads.2. Parallel group sessions in
bot.tsWhen
topicSessionModeis enabled for a group, usectx.rootId ?? ctx.messageIdas the topic key instead of onlyctx.rootId:rootIdpresent): share session by thread root (existing behavior)rootId): each message gets its own session viamessageIdThis enables true parallel processing in group chats.
3. Reply to thread root in
bot.tsChange
replyToMessageId: ctx.messageId→replyToMessageId: ctx.rootId || ctx.messageIdso that replies within a thread always target the root message, avoiding nested sub-threads.4. Fire-and-forget in
monitor.tsIn the WebSocket message handler, always use fire-and-forget (
.catch()withoutawait) regardless of thefireAndForgetflag. Combined with per-message sessions (point 2), this is safe and dramatically improves throughput.Related
Environment
extensions/feishu/src/send.ts,bot.ts,monitor.tstopicSessionMode: "enabled"in group config