fix(gateway): reconcile flood-controlled partial stream instead of duplicating the final reply - #65451
Closed
AlexxRussell wants to merge 1 commit into
Closed
Conversation
…ng the final reply When Telegram flood control disables progressive streaming edits mid answer, the stream consumer leaves a partial message on screen but never confirms final delivery. None of the post-stream suppression flags (streamed, previewed, content_delivered) are set, so the normal final send re-delivers the whole answer on top of the visible partial and the user sees the reply twice. Reconcile instead: when a partial is on screen (already_sent with a message_id) and delivery was never confirmed, edit the existing streamed message to the final content (finalize=True splits on overflow) rather than sending a fresh duplicate. The decision lives in gateway/stream_reconcile.should_reconcile_partial, which is pure and unit tested; any edit failure falls through to the normal send path.
Contributor
|
Thanks for the focused investigation and the reproduction details. Automated hermes-sweeper review found that current
Closing as implemented on main. |
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.
What does this PR do?
Fixes a Telegram duplicate-delivery bug in the gateway's post-stream path.
When Telegram flood control disables progressive streaming edits mid answer (the stream consumer's flood-strike limit), the consumer leaves a partial message on screen but never confirms final delivery. None of the post-stream suppression flags (
streamed,previewed,content_delivered) are set, so the normal final send re-delivers the entire answer on top of the visible partial. The user sees a truncated reply, then the whole reply again once the flood-control wait expires.This PR reconciles instead of re-sending: when the final response is ready and a partial is on screen (
already_sentwith amessage_id) but delivery was never confirmed, the gateway edits the existing streamed message to the final content (finalize=True, which splits on overflow) and marks the response delivered. The decision predicate lives in a new pure module,gateway/stream_reconcile.should_reconcile_partial, so it is unit-testable. Any edit failure logs a warning and falls through to the existing send path, so the worst case is exactly today's behavior.Observed live on a production gateway: a 6,375 char reply had progressive edits disabled after repeated RetryAfter strikes, the partial stayed on screen, and the final send duplicated the full answer (split, plain) roughly 3 minutes later after an 82s flood wait. With this change the partial is edited into the final reply and no duplicate is sent.
Relationship to existing work
gateway/run.py. It covers the case those paths cannot see, when edits were disabled mid-turn and no finalized edit is attempted at all. They compose: adapter-level improvements reduce how often the partial scenario arises, and this reconcile stops the duplication when it does.Related Issue
None filed; root-caused from live gateway logs. Happy to open one if that helps tracking.
Type of Change
Changes Made
gateway/stream_reconcile.py(new):should_reconcile_partial(...), a pure predicate that returns True only when a partial is on screen and delivery was never confirmed. It returns False for empty, failed, transformed, and already-delivered cases so all existing suppress/send behavior is untouched.gateway/run.py: after the existing transformed-response edit branch, a guarded branch that edits the streamed partial into the final response and setsalready_sent, with warning + fall-through to the normal send on any error.tests/gateway/test_stream_reconcile.py(new): the reconcile case plus the negative matrix (each delivery-confirmed flag, nothing on screen, empty/failed/transformed).How to Test
python -m pytest tests/gateway/test_stream_reconcile.py -q -o addopts=(4 passed).Running in production on a single-box deployment since late June; long flood-controlled replies no longer duplicate.
Checklist
Code
fix(gateway):)Documentation & Housekeeping
cli-config.yaml.exampleif I added/changed config keys: N/ACONTRIBUTING.mdorAGENTS.mdif I changed architecture or workflows: N/A