[1/2] feat(eve)!: key Telegram group sessions chat-wide - #3020
Conversation
|
@Lukavyi is attempting to deploy a commit to the Vercel Team on Vercel. A member of the Team first needs to authorize it. |
f7be94d to
a735858
Compare
acb66a2 to
711f76b
Compare
711f76b to
b55920e
Compare
|
Pushed 304b1ea: a reply to a bot message now carries its text as |
304b1ea to
fc95f4a
Compare
Telegram group and supergroup inbound messages keyed the session to the bot message being replied to, or to the mention itself. Every fresh mention therefore started a new session with one message of context, while private chats already keep one continuous session per chat. Groups now key to the chat plus forum topic, the same way private chats do. Mentions, replies to bot messages, callback queries, and outbound sends all resume that session. The message_thread_id that non-forum supergroups stamp on replies is a reply chain, not a topic, and does not split the session. Proactive targets can still pin a thread through conversationId. Related to vercel#874 Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015P6RBuagWTMzBmJLCiYKW9 Signed-off-by: Taras Lukavyi <lukavyi@me.com>
…orm prompt is pending A reply to a bot message went through respond() with only the synthetic telegram_reply:<id> response. When that id was not a registered freeform prompt, the adapter resolved nothing, returned undefined, and the session re-parked without a turn, so the reply was dropped. The initial channel sent the text as message on the same delivery; vercel#1597 replaced that with respond() and lost it. With chat-wide group sessions a reply to the bot is the natural follow-up, so carry the text as message again: the adapter still resolves a pending freeform answer first and otherwise runs the text as a normal turn. Pass state and title so a reply can start a session with a usable chat id when none owns the address. Also correct the TelegramReceiveTarget docstring: conversationId pins a caller-selected id that inbound messages never route to, and initialMessage no longer starts a separate thread in groups. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015P6RBuagWTMzBmJLCiYKW9 Signed-off-by: Taras Lukavyi <lukavyi@me.com>
fc95f4a to
9114ab6
Compare
|
Ready for review. @benpankow (recent Telegram HITL work) @ruiconti (merged #897, which this relies on): could one of you take a look? #3023 stacks on top with the observe half. |
Summary
A Telegram bot in a group has no memory between mentions. Group and supergroup inbound messages key the session to the bot message being replied to, or to the mention itself when it is not a reply (
conversationIdForMessageintelegram/state.ts), and outbound group sends re-key the session to the posted message id. Every fresh@botmention therefore starts a new session with one message of context, while private chats already keep one continuous session per chat since #377.This makes groups behave like private chats: one session per chat, or per forum topic, keyed to
telegram:<chatId>:<messageThreadId>:. Mentions, replies to bot messages, HITL callback queries, and outbound sends all resume that session, so the bot remembers what it said earlier in the chat.Non-forum supergroups stamp
message_thread_idon replies (the reply-chain root, not a topic). The thread id now counts as a session discriminator only when Telegram marks the message withis_topic_message, so a reply chain does not fragment the chat-wide session.isTopicMessageis exposed onTelegramMessageandTelegramMessageReferencefor this.The per-bot-message anchoring is removed rather than kept behind an option, following the reasoning in Telegram: group mentions start a new session per bot message; key groups chat-wide like private chats #874: it is reproducible in userland (
conversationIdon a proactivereceivetarget still pins a thread, and Let the host pick the session for an inbound turn (continuation token override) #671 would cover inbound), while the reverse was not possible without patching channel internals. A late reply to an old bot message also resumed a session blind to everything since, so the anchoring was not correct even for the multi-thread case it served.Second commit: a reply to a bot message is delivered with its text as
messagealongside the synthetictelegram_reply:<id>response again. The initial channel did this; feat(eve)!: unify public session operation APIs #1597 switched the reply path torespond()with only the response, so a reply that was not an answer to a pending ForceReply prompt resolved to nothing in the adapter and the session re-parked without a turn. With chat-wide sessions a reply to the bot is the ordinary follow-up, so this matters more than before. The adapter already had the fallback and the test for it.Behavior change for existing group bots, hence the
minorchangeset and the!in the commit. Existing parked group sessions keep their old anchored tokens; new mentions start on the chat-wide token.We have run chat-wide group keying as a
patchedDependenciespatch in production on two group bots since July.Related to #874 (option 1 there). #671 is the more general mechanism; this is the smaller change that fixes the group use case now.
How this lines up with the other channels
channel:threadTstenant:conversation:rootActivityIdchannel:interactionIdchat:topic:botMessageIdchat:topic:Slack and Teams key a session to the smallest container the platform itself shows: a thread. Telegram has no threads outside forum topics, and instead of taking the nearest visible container (chat or topic) the channel synthesized its own boundary from the reply chain to a bot message. Users cannot see that boundary, which is why a plain
@botmention that is not a reply reads as "the same conversation" to them and as "a new session" to eve. Teams had the same class of bug in #211 (a follow-up mention in a thread lost context) and it was fixed as a bug, not made an option.The Telegram and Discord channels share one shape from the initial commit (
conversationIdstate,anchor()after outbound posts, the sameconversationId/initialMessageguard). Discord is interaction-only, so "one session per bot post" is the natural unit there. Telegram inherited that unit for groups; private chats were exempted from the start, and #377 later kept the group anchoring as-is while fixing proactive private chats. After this change Telegram behaves like Slack and Teams, and Discord stays the justified exception.Validation
New coverage: a fresh mention, a reply to a bot message (freeform HITL path), a mention inside a forum topic (
is_topic_message: truekeeps the topic), a reply-chainmessage_thread_idin a non-forum supergroup (stays chat-wide), a HITL callback query, and an outbound post that must not re-key the session. The existing anchoring tests were rewritten to assert chat-wide tokens; the one that asserted re-keying to the posted message id was dropped, and the explicit-conversationIdgroup test now asserts the id is preserved instead of overwritten.Checklist
CONTRIBUTING.mdevepackagegit commit --signoff)🤖 Generated with Claude Code
https://claude.ai/code/session_015P6RBuagWTMzBmJLCiYKW9