Skip to content

feat(telegram): non-streaming tool+commentary progress accumulator#89890

Closed
anagnorisis2peripeteia wants to merge 12 commits into
openclaw:mainfrom
anagnorisis2peripeteia:feat/non-streaming-tool-progress-accumulator
Closed

feat(telegram): non-streaming tool+commentary progress accumulator#89890
anagnorisis2peripeteia wants to merge 12 commits into
openclaw:mainfrom
anagnorisis2peripeteia:feat/non-streaming-tool-progress-accumulator

Conversation

@anagnorisis2peripeteia

@anagnorisis2peripeteia anagnorisis2peripeteia commented Jun 3, 2026

Copy link
Copy Markdown
Contributor

Summary

The non-streaming counterpart to persistProgress: when streaming.mode is off, nothing streams during a turn, so tool and commentary progress were lost entirely. This accumulates the commentary + tool-progress lines silently as the turn runs and delivers them as their own message — commentary first, then the tool lines — immediately before the final answer. The user gets the whole progress lane once, when the answer is ready.

What it does (with streaming.mode: "off" + streaming.progress.persistProgress: true):

  • Accumulate silently — on onItemEvent (preamble/commentary) and onToolStart, append to a per-turn log gated on persistProgress. Nothing is sent mid-turn (stream is off).
  • Deliver as a set before the answeremitPersistedProgressSet flushes the accumulated lane as its own durable message ahead of the final answer, but only when there is no live draft stream (so the stream-on persist path in feat(streaming): opt-in persistProgress mode for tool+commentary lines #89850 doesn't double-emit).
  • Run callbacks with the stream off — progress callbacks are allowed to fire when source delivery is suppressed and persistProgress is set, so the accumulator actually runs in mode:off.
  • Guard-free opt-in resolvers — adds resolveChannelStreamingProgressCommentaryEnabled and resolveChannelStreamingProgressToolProgressEnabled, which read the commentary / toolProgress opt-ins without the progress-mode guard (the public guarded resolvers only read them in progress mode). The stream-off accumulator gates each lane on its toggle, so commentary:false or toolProgress:false omits that lane from the accumulated set; the public guarded resolvers are unchanged (live-draft behavior preserved).

Tests

  • tsgo clean
  • channel-streaming.test.ts — added a regression for the toolProgress gate (toolProgress:false omits the tool lane; guard-free and mode-independent); 29/29 pass
  • bot-message-dispatch.test.ts — 103/104 pass; the one failure (records streamed final replies into the prompt context cache) is a pre-existing Windows /tmp store-roundtrip issue that reproduces on the unmodified base commit (it is green on Linux CI).

Proof

Captured via a local recreation of the Mantis (telegram-desktop-proof) flow on crabbox, with streaming.mode: "off" + persistProgress: true (the separate streamkey). Bot DM, claude-cli backend, opus-4.8 / max thinking.

Nothing streams during the turn; at final-send the whole lane lands as one set, commentary first, then the tool reads, with the answer as a separate message below it:

stream-off: commentary+tool lane accumulated as its own set, then the answer below

Observed:

💭 I'll read each file and summarize it.
📖 Read … README.md
📖 Read … package.json
📖 Read … tsconfig.json

(separate message) Here's a one-line summary of each: …

Motion (silent turn → the set + answer arrive together at the end): recording

Gateway trace confirms the lane accumulated and emitted with no live stream: emitSet persist=true hasStream=false logLen=4 streamMode=off (1 commentary line + 3 tool lines).

Stacking

Built on #89850 (streaming.progress.persistProgress), which is built on #89834 (claude-cli commentary producer) and #90883 (commentary delivery + render). This branch is rebased on the current #89850 head, so its own diff is just the stream-off accumulator (bot-message-dispatch.ts) + the guard-free resolver (streaming.ts). Merge #90883#89834#89850 first.

Issues

Part of the #87326 progress UX work.

@openclaw-barnacle openclaw-barnacle Bot added channel: telegram Channel integration: telegram size: XS triage: needs-real-behavior-proof Candidate: external PR needs after-fix proof from a real setup. labels Jun 3, 2026
@clawsweeper

clawsweeper Bot commented Jun 3, 2026

Copy link
Copy Markdown
Contributor

Codex review: needs maintainer review before merge. Reviewed June 6, 2026, 2:59 PM ET / 18:59 UTC.

Summary
The PR adds an opt-in Telegram stream-off progress accumulator, shared streaming.progress.persistProgress config/resolvers, CLI commentary bridging, docs, generated config metadata, and focused regression tests.

PR surface: Source +321, Tests +591, Docs +1, Generated 0. Total +913 across 23 files.

Reproducibility: not applicable. as a feature PR. Source inspection confirms current main lacks this off-mode persistence path, and the supplied Telegram proof shows the proposed after-fix behavior.

Review metrics: 2 noteworthy metrics.

  • Shared Config Surface: 1 added shared streaming.progress option. A new channel progress key affects config/schema/docs expectations across channels even though this implementation is Telegram-first.
  • Open Stack Dependencies: 3 prerequisite PRs named. The final reviewed diff and Telegram delivery behavior depend on the prerequisite stack landing in order.

Merge readiness
Overall: 🐚 platinum hermit
Proof: 🦞 diamond lobster ✨ media proof bonus
Patch quality: 🐚 platinum hermit
Result: ready for maintainer review.

Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch.

Rank-up moves:

  • Refresh the branch after the prerequisite stack lands so maintainers can review the final isolated diff.
  • Get maintainer acceptance on whether persistProgress should be shared channel progress config or Telegram-scoped for now.

Mantis proof suggestion
A maintainer-run Telegram Desktop capture would independently verify the visible stream-off ordering and media isolation on the final stacked branch. A maintainer can ask Mantis to capture proof by posting a new PR comment that starts with the OpenClaw Mantis account mention, followed by:

telegram desktop proof: verify streaming.mode off with persistProgress sends one text-only progress message before the final answer and does not copy answer media.

Risk before merge

Maintainer options:

  1. Accept The Shared Progress Contract (recommended)
    Maintainers can accept streaming.progress.persistProgress as a shared channel progress option, then require this branch to be refreshed on the landed prerequisites before merge.
  2. Narrow The Config Surface
    If maintainers do not want a shared channel contract yet, narrow the option and docs to Telegram-owned behavior before merge and leave a later SDK/API decision for other channels.
  3. Pause Until The Stack Lands
    Maintainers can pause review until the three prerequisite PRs land so this branch shows only the stream-off accumulator delta.

Next step before merge

  • [P2] Human review is needed for the shared config/API contract, Telegram delivery-order semantics, and stacked merge order; there is no narrow automated repair to queue.

Security
Cleared: No concrete security or supply-chain concern was found; the diff does not add dependencies, workflows, lockfiles, secret handling, release scripts, or downloaded-code execution paths.

Review details

Best possible solution:

Land or update the prerequisite stack first, then refresh this branch and either explicitly accept the shared persistProgress channel contract or narrow it before merging.

Do we have a high-confidence way to reproduce the issue?

Not applicable as a feature PR. Source inspection confirms current main lacks this off-mode persistence path, and the supplied Telegram proof shows the proposed after-fix behavior.

Is this the best way to solve the issue?

Unclear until maintainer API review. The stream-off accumulator is a plausible narrow Telegram implementation, but the shared persistProgress contract and stacked merge order require maintainer acceptance.

AGENTS.md: found and applied where relevant.

Codex review notes: model gpt-5.5, reasoning high; reviewed against f2677d55ecf0.

Label changes

Label justifications:

  • P2: This is a normal-priority opt-in Telegram progress UX improvement with meaningful but bounded blast radius.
  • merge-risk: 🚨 compatibility: The PR adds a shared config/API surface and generated channel metadata that maintainers must accept as a compatibility contract.
  • merge-risk: 🚨 message-delivery: The PR changes Telegram delivery ordering by adding an opt-in durable progress message before final replies in stream-off turns.
  • rating: 🐚 platinum hermit: Overall readiness is 🐚 platinum hermit; proof is 🦞 diamond lobster and patch quality is 🐚 platinum hermit.
  • status: 👀 ready for maintainer look: ClawSweeper has no concrete contributor-facing blocker left for this PR. Sufficient (recording): The PR body and inspected Telegram Desktop images show after-fix real behavior for the central stream-off path and media isolation; the linked recording supports the silent-turn-to-final delivery flow.
  • proof: sufficient: Contributor real behavior proof is sufficient. The PR body and inspected Telegram Desktop images show after-fix real behavior for the central stream-off path and media isolation; the linked recording supports the silent-turn-to-final delivery flow.
  • proof: 🎥 video: Contributor real behavior proof includes video or recording evidence. The PR body and inspected Telegram Desktop images show after-fix real behavior for the central stream-off path and media isolation; the linked recording supports the silent-turn-to-final delivery flow.
  • mantis: telegram-visible-proof: Mantis should capture Telegram visible proof. This PR changes visible Telegram chat ordering and message content, so Telegram Desktop proof is useful and already supplied.
Evidence reviewed

PR surface:

Source +321, Tests +591, Docs +1, Generated 0. Total +913 across 23 files.

View PR surface stats
Area Files Added Removed Net
Source 12 329 8 +321
Tests 8 591 0 +591
Docs 2 3 2 +1
Config 0 0 0 0
Generated 1 17 17 0
Other 0 0 0 0
Total 23 940 27 +913

Acceptance criteria:

What I checked:

  • Repository policy applied: Read the full root AGENTS.md, scoped guides for extensions/, src/agents, src/channels, src/plugin-sdk, and docs/, plus Telegram maintainer notes; the review applied the Telegram real-proof requirement and compatibility-sensitive config/API guidance. (AGENTS.md:1)
  • Current main lacks the requested capability: Current main has no persistProgress, guard-free progress resolver, stream-off accumulator, or lossless spill symbols, so this PR is not superseded by main. (f2677d55ecf0)
  • Current Telegram dispatch behavior: On current main, Telegram progress is tied to an active answer draft via resolveChannelStreamingPreviewToolProgress; there is no stream-off durable progress flush path. (extensions/telegram/src/bot-message-dispatch.ts:950, f2677d55ecf0)
  • PR stream-off accumulator: The PR diff adds persistProgressEnabled, streamOffPersistEnabled, a per-turn persistedProgressLog, and a common final-delivery flush that sends accumulated progress as a text-only durable message before final content. (extensions/telegram/src/bot-message-dispatch.ts:908, 86b71f2f3c80)
  • Shared config/API surface: The PR adds persistProgress to the shared channel progress config type and schema, which is compatibility-sensitive because it becomes a channel-agnostic contract while Telegram is the first full implementation. (src/config/types.base.ts:70, 86b71f2f3c80)
  • Sibling channel check: Discord uses createChannelProgressDraftCompositor, while Slack, Matrix, and MS Teams use formatChannelProgressDraftText directly, so the shared resolver/config change deserves maintainer API review across channel progress surfaces. (extensions/discord/src/monitor/message-handler.draft-preview.ts:86, f2677d55ecf0)

Likely related people:

  • vincentkoc: Current-main blame in this shallow checkout points the central Telegram streaming, channel streaming resolver, and CLI parser regions to Vincent Koc's latest main snapshot; use as a routing hint, not blame. (role: recent area contributor; confidence: medium; commits: 7a62cd5efc4d; files: extensions/telegram/src/bot-message-dispatch.ts, src/channels/streaming.ts, src/agents/cli-output.ts)
What the crustacean ranks mean
  • 🦀 challenger crab: rare, exceptional readiness with strong proof, clean implementation, and convincing validation.
  • 🦞 diamond lobster: very strong readiness with only minor maintainer review expected.
  • 🐚 platinum hermit: good normal PR, likely mergeable with ordinary maintainer review.
  • 🦐 gold shrimp: useful signal, but proof or patch confidence is still limited.
  • 🦪 silver shellfish: thin signal; proof, validation, or implementation needs work.
  • 🧂 unranked krab: not merge-ready because proof is missing/unusable or there are serious correctness or safety concerns.
  • 🌊 off-meta tidepool: rating does not apply to this item.

Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics.

How this review workflow works
  • ClawSweeper keeps one durable marker-backed review comment per issue or PR.
  • Re-runs edit this comment so the latest verdict, findings, and automation markers stay together instead of adding duplicate bot comments.
  • A fresh review can be triggered by eligible @clawsweeper re-review comments, exact-item GitHub events, scheduled/background review runs, or manual workflow dispatch.
  • PR/issue authors and users with repository write access can comment @clawsweeper re-review or @clawsweeper re-run on an open PR or issue to request a fresh review only.
  • Maintainers can also comment @clawsweeper review to request a fresh review only.
  • Fresh-review commands do not start repair, autofix, rebase, CI repair, or automerge.
  • Maintainer-only repair and merge flows require explicit commands such as @clawsweeper autofix, @clawsweeper automerge, @clawsweeper fix ci, or @clawsweeper address review.
  • Maintainers can comment @clawsweeper explain to ask for more context, or @clawsweeper stop to stop active automation.

@clawsweeper clawsweeper Bot added rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. mantis: telegram-visible-proof Mantis should capture Telegram visible proof. P2 Normal backlog priority with limited blast radius. merge-risk: 🚨 compatibility 🚨 May break existing users, config, migrations, defaults, or upgrade paths. merge-risk: 🚨 message-delivery 🚨 May drop, duplicate, misroute, suppress, or wrongly target messages. labels Jun 3, 2026
@anagnorisis2peripeteia

Copy link
Copy Markdown
Contributor Author

@clawsweeper re-review

@clawsweeper

clawsweeper Bot commented Jun 3, 2026

Copy link
Copy Markdown
Contributor

🦞🧹
ClawSweeper re-review requested.

I asked ClawSweeper to review this item again.
Action: item re-review queued (workflow sweep.yml, event repository_dispatch).
Result: the existing ClawSweeper review comment will be edited in place when the review finishes.

Re-review progress:

@anagnorisis2peripeteia

Copy link
Copy Markdown
Contributor Author

@clawsweeper re-review

@clawsweeper

clawsweeper Bot commented Jun 3, 2026

Copy link
Copy Markdown
Contributor

🦞🧹
ClawSweeper re-review requested.

I asked ClawSweeper to review this item again.
Action: item re-review queued (workflow sweep.yml, event repository_dispatch).
Result: the existing ClawSweeper review comment will be edited in place when the review finishes.

Re-review progress:

@anagnorisis2peripeteia

Copy link
Copy Markdown
Contributor Author

@clawsweeper re-review

@clawsweeper

clawsweeper Bot commented Jun 3, 2026

Copy link
Copy Markdown
Contributor

🦞🧹
ClawSweeper re-review requested.

I asked ClawSweeper to review this item again.
Action: item re-review queued (workflow sweep.yml, event repository_dispatch).
Result: the existing ClawSweeper review comment will be edited in place when the review finishes.

Re-review progress:

Inter-tool commentary (assistant text emitted before a tool call, surfaced by
the CLI parser as a stream:"item", kind:"preamble" agent event) landed on the
agent-event bus with no subscriber and was silently dropped: runCliAgentWithLifecycle
bridges the assistant, reasoning, and tool streams to channel callbacks, but the
item/preamble stream had no bridge. Add createCommentaryEventBridge to forward it
to onItemEvent, so CLI commentary reaches the channel's commentary render hook.

This is the CLI-dispatch delivery half of the commentary feature: the parser
emission (claude-cli) feeds the bus; this bridge delivers it to the channel.
Addresses the claude-cli case of intermediate-text-lost (openclaw#87326 / openclaw#84486).
Commentary lines carry noCompact so the progress-draft renderer does not compact
them like tool lines — assistant prose renders in full, spilling to a new message
at the channel limit rather than truncating mid-sentence.
Detect text accumulated before tool_use blocks in the Claude CLI
streaming parser and emit it as commentary via a new onCommentaryText
callback. This enables the same commentary progress display that the
Codex backend already provides through preamble item events.

- Add onCommentaryText optional callback to createCliJsonlStreamingParser
- Flush accumulated assistantText as commentary when content_block_start
  with tool_use type is encountered
- Track last flushed position to avoid duplicate emissions on consecutive
  tool_use blocks without intervening text
- Wire the callback in both execute.ts (regular CLI spawn + live session)
  and claude-live-session.ts, emitting AgentItemEventData with
  kind=preamble and progressText
- Add 3 test cases covering: text before tool_use, empty text before
  tool_use, and consecutive tool_use dedup
anagnorisis2peripeteia added a commit to anagnorisis2peripeteia/openclaw that referenced this pull request Jun 6, 2026
@anagnorisis2peripeteia
anagnorisis2peripeteia force-pushed the feat/non-streaming-tool-progress-accumulator branch from 8692ed4 to 4034483 Compare June 6, 2026 13:07
@anagnorisis2peripeteia

Copy link
Copy Markdown
Contributor Author

Updated: stream-off accumulation now works — fixed the double-wrap (tool lines) and the progress-mode guard (commentary), added a guard-free resolveChannelStreamingProgressCommentaryEnabled for the off path, and rebased onto the amended #89850. Proof (commentary-first set delivered before the answer with the stream off) is in the body. @clawsweeper re-review

@clawsweeper

clawsweeper Bot commented Jun 6, 2026

Copy link
Copy Markdown
Contributor

🦞👀
ClawSweeper picked this up.

Command router queued. I will update this comment with the next step.

@openclaw-barnacle openclaw-barnacle Bot added docs Improvements or additions to documentation agents Agent runtime and tooling labels Jun 6, 2026
@clawsweeper

clawsweeper Bot commented Jun 6, 2026

Copy link
Copy Markdown
Contributor

🦞👀
ClawSweeper picked this up.

Command router queued. I will update this comment with the next step.

@openclaw-barnacle openclaw-barnacle Bot removed the proof: sufficient ClawSweeper judged the real behavior proof convincing. label Jun 6, 2026
@clawsweeper clawsweeper Bot added status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. and removed status: ⏳ waiting on author ClawSweeper has contributor-facing work open and is waiting for author action. labels Jun 6, 2026
anagnorisis2peripeteia added a commit to anagnorisis2peripeteia/openclaw that referenced this pull request Jun 6, 2026
@anagnorisis2peripeteia

Copy link
Copy Markdown
Contributor Author

Added real-behavior proof for the media-final path (Telegram Desktop, stream-off + persistProgress):

stream-off progress set (text-only) ahead of a media/photo final answer

The accumulated progress set is delivered first as a single text-only message (💭 commentary interleaved with 📖 tool reads); the answer's photo (sendPhoto) is a separate message — the progress set does not carry the answer's media. This confirms the text-only-payload fix isolates the progress set from answer-content fields, with a media final.

Note on strict media-only (no answer text): a safety-conscious model won't reliably emit text-free media on command (it treated "reply with only this" as link-laundering and refused), so the no-text branch of the common-path flush is covered deterministically by the dispatch regression flushes the stream-off persisted progress set even for a media-only final answer (exercises the info.kind === "final" flush with a media-only payload and no answer-text segment).

@clawsweeper re-review

@clawsweeper

clawsweeper Bot commented Jun 6, 2026

Copy link
Copy Markdown
Contributor

🦞🧹
ClawSweeper re-review requested.

I asked ClawSweeper to review this item again.
Action: item re-review queued (workflow sweep.yml, event repository_dispatch).
Result: the existing ClawSweeper review comment will be edited in place when the review finishes.

Re-review progress:

@clawsweeper clawsweeper Bot added proof: 📸 screenshot Contributor real behavior proof includes screenshot evidence. rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. and removed proof: 🎥 video Contributor real behavior proof includes video or recording evidence. rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. labels Jun 6, 2026
Moving the progress-set flush to the common final path made it fire on the
bare absence of an answer-lane draft (!answerLane.stream), which is also true
in partial/progress turns that lack a live draft (e.g. selected-quote replies)
— so those turns could get a surprise durable progress message.

Gate accumulation, suppressed-source callback forwarding, and emission on a
single streamOffPersistEnabled = persistProgressEnabled && streamMode === 'off'
so the accumulator only ever engages in genuine stream-off turns. Regression:
a no-draft partial-mode turn with persistProgress emits no progress set.
@anagnorisis2peripeteia

Copy link
Copy Markdown
Contributor Author

Fixed the [P2/P1] no-draft leak (bot-message-dispatch.ts:1772): the stream-off accumulator was gated on the bare absence of a draft (!answerLane.stream), which is also true in partial/progress turns that lack a live draft (e.g. selected-quote replies). It's now gated on a single streamOffPersistEnabled = persistProgressEnabled && streamMode === "off" across accumulation, suppressed-source callback forwarding, and emission — so it only ever engages in genuine stream-off turns. Regression added: a no-draft partial-mode turn with persistProgress emits no progress set.

On the strict media-only proof: a safety-conscious model won't emit text-free media on command (asked to "reply with only this," it refused as link-laundering), so a true no-caption media-only final isn't naturally elicitable in the proof harness. The closest real capture is the media-with-caption one above (which proves the progress set stays text-only and the photo lands only on the answer — the payload-isolation fix), and the strict no-text branch of the common-path flush is covered deterministically by the dispatch regression flushes the stream-off persisted progress set even for a media-only final answer. Per the review's own note, the remaining proof/stack/config items need human maintainer review.

@clawsweeper re-review

@clawsweeper

clawsweeper Bot commented Jun 6, 2026

Copy link
Copy Markdown
Contributor

🦞🧹
ClawSweeper re-review requested.

I asked ClawSweeper to review this item again.
Action: item re-review queued (workflow sweep.yml, event repository_dispatch).
Result: the existing ClawSweeper review comment will be edited in place when the review finishes.

Re-review progress:

@clawsweeper clawsweeper Bot added proof: sufficient ClawSweeper judged the real behavior proof convincing. proof: 🎥 video Contributor real behavior proof includes video or recording evidence. rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR. and removed proof: 📸 screenshot Contributor real behavior proof includes screenshot evidence. rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. labels Jun 6, 2026
@openclaw-barnacle openclaw-barnacle Bot removed the triage: needs-real-behavior-proof Candidate: external PR needs after-fix proof from a real setup. label Jun 6, 2026
@clawsweeper clawsweeper Bot added rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. and removed rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. labels Jun 6, 2026
@anagnorisis2peripeteia
anagnorisis2peripeteia marked this pull request as ready for review June 6, 2026 18:51
@obviyus

obviyus commented Jun 11, 2026

Copy link
Copy Markdown
Contributor

Closing as superseded by #91976, which just landed — with /verbose on, commentary and CLI tool summaries now arrive as durable standalone messages in streaming.mode: "off" as well, covering this PR's use case without the persistProgress config surface. Thanks @anagnorisis2peripeteia!

@obviyus obviyus closed this Jun 11, 2026
@anagnorisis2peripeteia
anagnorisis2peripeteia deleted the feat/non-streaming-tool-progress-accumulator branch July 13, 2026 12:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

agents Agent runtime and tooling channel: telegram Channel integration: telegram docs Improvements or additions to documentation mantis: telegram-visible-proof Mantis should capture Telegram visible proof. merge-risk: 🚨 compatibility 🚨 May break existing users, config, migrations, defaults, or upgrade paths. merge-risk: 🚨 message-delivery 🚨 May drop, duplicate, misroute, suppress, or wrongly target messages. P2 Normal backlog priority with limited blast radius. proof: sufficient ClawSweeper judged the real behavior proof convincing. proof: 🎥 video Contributor real behavior proof includes video or recording evidence. rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. size: L status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants