Skip to content

Telegram streaming: intermediate text blocks between tool calls are silently lost (overwritten by final block) #87326

@AbdelftahZowail

Description

@AbdelftahZowail

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

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)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions