#8205: fix: flush followup messages incrementally
stale
Cluster:
Telegram Message Handling Fixes
Fixes #7698
## Problem
Followup messages were buffered until the entire agent run completed, then delivered all at once. Users saw no incremental feedback during long-running tasks.
## Solution
Added `onBlockReply` callback to `runEmbeddedPiAgent` call in `followup-runner.ts`. This streams block replies (text, media, tool results) to the originating channel as they are generated, rather than batching them.
Key changes:
- Added `handleBlockReply` function that immediately delivers payloads via `deliverOutboundPayloads`
- Track streamed payloads with `streamedPayloadKeys` Set to prevent duplicate delivery
- Filter already-streamed payloads from final `sendReply` call
## Testing
Tested with Telegram channel - messages now appear incrementally as the agent generates them.
<!-- greptile_comment -->
<h2>Greptile Overview</h2>
<h3>Greptile Summary</h3>
This PR enables incremental delivery of follow-up agent output by wiring an `onBlockReply` callback into `runEmbeddedPiAgent` from `src/auto-reply/reply/followup-runner.ts`. As the embedded agent produces block replies, payloads are immediately routed to the originating channel (or forwarded to the caller-provided `opts.onBlockReply`) instead of waiting for the run to complete. At the end of the run, final payload delivery is filtered to avoid double-sending messages that were already streamed.
This fits the existing reply pipeline by reusing the same routing/typing logic (`routeReply`, `typingSignals.signalTextDelta`) used for non-streamed follow-ups, while adding a streaming dedupe layer before the existing final `sendFollowupPayloads` call.
<h3>Confidence Score: 3/5</h3>
- This PR is likely safe to merge, but the new deduplication and failure-path semantics could cause dropped or mis-deduped payloads in some channel configurations.
- Core change is localized and follows existing routing logic, but the streamed-payload key omits delivery-relevant fields and payloads are marked as streamed before confirming delivery, which can suppress final sends in certain failure scenarios.
- src/auto-reply/reply/followup-runner.ts
<!-- greptile_other_comments_section -->
<sub>(4/5) You can add custom instructions or style guidelines for the agent [here](https://app.greptile.com/review/github)!</sub>
<!-- /greptile_comment -->
Most Similar PRs
#14216: fix(messaging): check both pipeline and direct keys for reply deduping
by F1xTrack · 2026-02-11
79.2%
#17953: fix(telegram): prevent silent message loss and duplicate messages i...
by zuyan9 · 2026-02-16
79.0%
#5080: fix(reply): fix duplicate block replies by unblocking coalesced pay...
by yassine20011 · 2026-01-31
77.9%
#9092: fix: skip retry when block content already streamed to user
by benleavett · 2026-02-04
77.7%
#9171: Fix: Route tool result deliveries through BlockReplyPipeline for pr...
by vishaltandale00 · 2026-02-04
76.8%
#7760: fix(agents): resolve message ordering conflict during tool execution
by aryan877 · 2026-02-03
76.8%
#13638: fix: pass delivery context to cron isolated agent subagents
by dario-github · 2026-02-10
76.6%
#8175: fix: suppress raw API errors for non-owners
by Rakshi2609 · 2026-02-03
76.6%
#7758: fix: prevent opts closure reuse across messages in shared followup ...
by Alexwang-sol · 2026-02-03
76.5%
#12180: fix: merge multi-block assistant texts into single reply
by 1960697431 · 2026-02-08
76.4%