Skip to content

fix(agents): queued CLI reasoning bridge + thinking token progress for claude-cli's withheld-text wire - #100148

Merged
obviyus merged 2 commits into
mainfrom
fix/cli-reasoning-followup-bridge
Jul 5, 2026
Merged

obviyus merged 2 commits into
mainfrom
fix/cli-reasoning-followup-bridge

Conversation

@obviyus

@obviyus obviyus commented Jul 5, 2026

Copy link
Copy Markdown
Contributor

Related: #99401, #68374, #97526

What Problem This Solves

Fixes an issue where /reasoning stream on claude-cli backends produced nothing on any surface — users enabled reasoning, saw tool progress and the final answer, but never any thinking. Two defects and one upstream reality:

  1. Queued/followup CLI runs never bridged reasoning events (the feat(cli): render claude CLI native thinking with /reasoning gating #99401 bridge covered only the direct execution path), so turns queued behind an active run dropped reasoning even where it worked.
  2. Claude CLI 2.1.x withholds thinking text from its non-interactive surface entirely: every stream thinking_delta carries thinking: "" plus estimated_tokens; assistant snapshots and even the on-disk session transcripts store thinking blocks with empty text and only a continuity signature (verified on live captures from 2.1.200 and 2.1.201, and across production transcripts). feat(cli): render claude CLI native thinking with /reasoning gating #99401's parser awaited API-shaped thinking text that this CLI generation never emits — its fixtures modeled a wire that does not ship.

Why This Change Was Made

  • One shared CLI reasoning bridge (createCliReasoningStreamBridge) now serves both the direct and followup paths; the followup gap is closed.
  • The parser converts empty-text thinking_delta frames with estimated_tokens into a distinct thinking-progress signal (cumulative per message; real-wire capture proves the estimates are per-frame, so summation is correct). No fake text is synthesized.
  • Telegram renders it as an ambient status in the existing progress window — 🧠 Thinking… (~N tokens) — gated only on the window being active, like tool lines: it is run metadata, not reasoning content, so no /reasoning opt-in is required.
  • The feat(cli): render claude CLI native thinking with /reasoning gating #99401 text path is intentionally preserved untouched: if a future CLI restores thinking text on the wire, full text streaming lights up with zero further changes. Indexless-delta robustness (synthetic block index from content_block_start/stop) is included as defense.

User Impact

CLI-backed agents now show live thinking activity during long reasoning stretches instead of a dead-silent window. Actual reasoning text remains unavailable on claude-cli by upstream design — operators wanting readable reasoning need the embedded API backend, where the existing pipeline already works.

Evidence

  • Real-wire fixture captured from claude CLI (test/fixtures/cli/claude-2.1-thinking-progress.jsonl); fail-confirmed: pre-fix the fixture produces zero signals, post-fix cumulative 50/200/300.
  • Followup-path fail-confirm: queued CLI thinking events produced [] pre-fix.
  • Suites green: cli-output, spawn, supervisor-capture, cli-dispatch, execution, followup-runner, telegram dispatch; oxlint + git diff --check clean; re-verified post-rebase.
  • Production diagnosis trail (5 instrumented canary rounds + local CLI E2E) established the withheld-text contract across stream, snapshots, and transcripts.

Note for #68374/#97526 followers: native reasoning text from claude-cli is blocked upstream, not in OpenClaw — this ships the honest telemetry the wire actually provides.

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 maintainer Maintainer-authored PR size: L

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant