Variant-sibling messages: switch between regenerated bot replies in place - #1997
Open
AlexGogin wants to merge 3 commits into
Open
Variant-sibling messages: switch between regenerated bot replies in place#1997AlexGogin wants to merge 3 commits into
AlexGogin wants to merge 3 commits into
Conversation
Correlation store for groups of real, independently-persisted messages that represent alternative answers to the same prompt, of which only one is shown at a time. Tracks the ordered member list and the active member per group, plus a registry of the peers whose messages may be grouped this way. Deliberately independent of grouped_id/GroupedMessages, which drive native album rendering and are not safe to repurpose for this.
For a message that has variant siblings the cell now draws an "i/N" counter centred under the bubble, two tap zones flanking it to page between siblings, and a stack of cards peeking out behind the bubble. The reload side button reuses the existing Forward/Share side-button geometry and slot. The counter is also mirrored onto the accessibility node, since the footer counter itself is drawn on the canvas and is invisible to TalkBack. A message without siblings takes no extra measure or draw work.
Non-active members of a variant group are dropped from the render list on both the cache-reload and the live path, and a message that supersedes its siblings evicts the resident one through the existing deletion primitive, so only the active variant is ever visible. Paging swaps a cached sibling into the list in place, without the unread-count and scroll-to-bottom side effects a genuinely new message would carry. Three triggers reach the same dispatch point: the counter arrows, a swipe-left on the message, and a long-press menu item. All of them are gated on the sender being a registered variant-authoring peer, so every other chat behaves exactly as before.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Conversational bots have changed what people expect from a chat. A bot that generates its
answers is not a menu tree — the same question can be answered several ways, and users now
routinely ask for another take. Every major assistant interface treats that as a basic
primitive: ChatGPT, DeepSeek and Qwen all let you regenerate an answer and page between the
variants in place, without the conversation turning into a wall of near-duplicates.
Telegram has no way to express this. A bot that regenerates has to send a new message, so the
chat fills with slight variations of the same reply and the thread of the conversation is lost.
The gap is not cosmetic: it is the difference between a bot that feels like a conversation and
one that feels like a log. This PR closes that gap natively, for every bot on the platform.
The mechanism is generic. Messages known to be variants of one answer are correlated in a
per-account store; one of them is visible, the siblings are kept out of the render list. The
bubble shows a small
i/Ncounter in its footer, arrow tap-zones flank the counter, a swipepages forward, and a reload side-button asks the bot for another variant. Nothing changes for a
message that was never regenerated — the counter and the outline are gated on group size
greater than one, so there is no extra draw cost.
Everything reuses what is already in the codebase rather than introducing parallel machinery:
the side-button geometry is the existing Forward/Share slot, the arrow hit-test mirrors
checkDateMotionEvent, the drawable registers through the same path as every other side-buttonicon, and eviction of superseded siblings goes through the existing
processDeletedMessagesprimitive, touching only the render list and never
MessagesStorage.grouped_id/GroupedMessageswere deliberately not reused: those positional flags drive thealbum/collage layout, which shows all members at once — the opposite of a sequential pager.
That was verified before writing the code, not assumed.
The feature has been tested on developer devices and found working: regeneration, paging in
both directions, the
i/Ncounter, and the eviction of superseded siblings all behave asdescribed above on real hardware, not only in review.
What this PR deliberately leaves to you. A variant group needs a signal for "this bot
produces alternatives". Any client-side choice of a TL flag bit is wrong by construction — the
schema is yours, and the bit I originally used locally (
flags2bit 21) is the one 12.9.0 gaveto
linked_community_id. So the mechanism here is driven through a small seam instead, andwiring it to a real server-side signal is a decision only you can make. The client side is
complete and self-contained either way.
On the interaction design. The counter, the arrows and the reload button are placed to fit
the existing bubble geometry, but they are one reading of how this should look and feel. If
variant paging belongs somewhere else in Telegram's interaction language — a different affordance,
a different gesture, a different place in the bubble — I would rather it be shaped your way than
mine. The underlying mechanism does not depend on the presentation: the store, the sibling
filtering and the eviction path stay the same whatever the surface ends up being.