openclaw - 💡(How to fix) Fix Telegram streaming: intermediate text blocks between tool calls are silently lost (overwritten by final block)

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…

Root Cause

PR #32890 removed the archive + forceNewMessage logic from onAssistantMessageStart in bot-message-dispatch.ts to prevent inter-tool narration from leaking into chat as separate messages. But it removed ALL interleaved delivery — not just the transient narration.

The stream now reuses a single preview across all text blocks in a turn. The streamText function in lane-delivery-text-deliverer.ts updates that preview in place for non-final blocks (isFinal=false) but never commits them as real messages before the final block overwrites them. The onAssistantMessageStart handler only calls rotateLaneForNewMessage when the lane is already finalized — which never happens for intermediate blocks.

Fix Action

Fix / Workaround

PR #32890 removed the archive + forceNewMessage logic from onAssistantMessageStart in bot-message-dispatch.ts to prevent inter-tool narration from leaking into chat as separate messages. But it removed ALL interleaved delivery — not just the transient narration.

  • extensions/telegram/src/bot-message-dispatch.tsonAssistantMessageStart handler — only rotates when answerLane.finalized is true
  • extensions/telegram/src/lane-delivery-text-deliverer.tsstreamText() — updates preview in place for non-final blocks, only commits on isFinal=true
  • extensions/telegram/src/draft-stream.tsonSupersededPreview callback — deletes superseded previews when forceNewMessage() is called
RAW_BUFFERClick to expand / collapse

Problem

When the model produces text → calls tools → produces more text → calls more tools → delivers final text, all intermediate text blocks share the same streaming preview message and are overwritten by subsequent blocks. Only the final text is visible to the user. Meaningful intermediate content (summaries, findings, explanations) is silently lost.

This is a regression from PR #32890.

Steps to reproduce

  1. Ask the agent to browse multiple websites in one turn
  2. Agent writes "Let me check site A..." → streams to preview
  3. Agent calls browser tools
  4. Agent writes "Site A shows X. Now checking site B..." → overwrites preview
  5. Agent calls more tools
  6. Agent writes "Done. Sites A and B show X and Y." → overwrites preview again, finalizes
  7. User sees only: "Let me check site A..." and "Done." — the intermediate summary is lost

Any turn where the model produces multiple meaningful text blocks separated by tool calls will silently lose text.

Root cause

PR #32890 removed the archive + forceNewMessage logic from onAssistantMessageStart in bot-message-dispatch.ts to prevent inter-tool narration from leaking into chat as separate messages. But it removed ALL interleaved delivery — not just the transient narration.

The stream now reuses a single preview across all text blocks in a turn. The streamText function in lane-delivery-text-deliverer.ts updates that preview in place for non-final blocks (isFinal=false) but never commits them as real messages before the final block overwrites them. The onAssistantMessageStart handler only calls rotateLaneForNewMessage when the lane is already finalized — which never happens for intermediate blocks.

Relevant code

  • extensions/telegram/src/bot-message-dispatch.tsonAssistantMessageStart handler — only rotates when answerLane.finalized is true
  • extensions/telegram/src/lane-delivery-text-deliverer.tsstreamText() — updates preview in place for non-final blocks, only commits on isFinal=true
  • extensions/telegram/src/draft-stream.tsonSupersededPreview callback — deletes superseded previews when forceNewMessage() is called

Prior art

  • #25592 "Text between tool calls leaks to messaging channels" — the original issue
  • PR #32890 "fix(telegram): reuse preview message across tool-use rounds to prevent inter-tool text leak" — the fix that caused this regression
  • PR #87072 "feat(telegram): opt-in interleaved progress lane" — partly addresses this but is opt-in and progress-focused

Expected behavior

Text blocks delivered with info.kind === "block" (non-final) should either be finalized as real messages before a new text block starts, or be cumulatively preserved so the user sees all text the model produced.

Environment

  • OpenClaw: 2026.5.26 (10ad3aa) — also reproducible on main as of 2026-05-27
  • Channel: Telegram (streaming mode: partial)

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

FAQ

Expected behavior

Text blocks delivered with info.kind === "block" (non-final) should either be finalized as real messages before a new text block starts, or be cumulatively preserved so the user sees all text the model produced.

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING