fix(cli-runner): emit run.progress from raw stdout in Claude live sesβ¦#84550
Closed
SkyWolfDreamer wants to merge 2 commits into
Closed
fix(cli-runner): emit run.progress from raw stdout in Claude live sesβ¦#84550SkyWolfDreamer wants to merge 2 commits into
SkyWolfDreamer wants to merge 2 commits into
Conversation
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
onAssistantDelta, which the parser only invokes fortext_deltacontent blocks. Reasoning-only Opus turns that emit justthinking_deltalines (no user-visible text) bypass the callback, so the diagnostic watchdog still aborts the run after about six minutes even though the CLI is actively streaming reasoning output.handleClaudeStdout, which runs on every raw subprocess chunk before any JSONL parsing. The signal now covers every byte the CLI emits βthinking_delta,tool_use,content_block_start/stop, system events β so any progress, including reasoning-only progress, keeps the watchdog informed.src/agents/cli-runner/claude-live-session.ts(+33 lines) β adds a per-turn diagnostic identity, a throttledemitLiveTurnDiagnosticProgress()helper, and a single emit call at the raw-stdout boundary. Adds a new seam coverage file (+190 lines) driving the live session with thinking-only JSONL.execute.ts)onStdoutpath, the parser internals, and every non-claude-cli backend.Motivation
Addresses the P1 ClawSweeper finding on the prior PR: the live-progress signal needs to cover non-text stream activity. The real reproduction is a
claude-opus-4-7turn with extended reasoning where the model emits six or more minutes ofthinking_deltaevents before producing any user-visible text β exactly the case the prior fix missed.Change Type
Scope
Linked Issue/PR
Related to the prior live-progress fix that hooked the text-delta callback (link will be updated once that PR merges). Checked: this PR fixes a bug or regression.
Real behavior proof
text_delta. Reasoning-only streams emitthinking_deltalines that never reach the prior callback, solastProgressAgeMsgrows paststuckSessionAbortMsand the lane is killed even while real reasoning is streaming.@anthropic-ai/claude-code),claude-opus-4-7andclaude-sonnet-4-6via the live-session mode. The patched build is deployed against the same affected install that was originally hitting the watchdog abort.lastProgressfor the duration of a thinking burst and the watchdog aborted the run at the configuredstuckSessionAbortMs(about six minutes) even while the CLI was actively streaming reasoning. Production runtime logs from that period showedclaude live session turn failed: ... error=AbortErrorafter roughly 360 seconds on Opus reasoning turns with no concurrent text output.claude-opus-4-7with the live-session mode enabled. Command sequence the gateway is running on:cli:live:stdoutprogress events firing on every raw CLI chunk and the watchdog seeing the resulting liveness:The first four lines are the diagnostic system observing the new
cli:live:stdoutreason on long-running lanes, withlastProgressAgestaying low (0β20 s) while the lane runs past 147β302 s of real work.recovery=noneconfirms the watchdog is no longer escalating to abort on these lanes. The last two lines are normal turn completions at 2 m 1 s and 1 m 54 s β durations that would previously have been at risk of abort if they contained reasoning-only intervals.lastProgress=cli:live:stdouton every raw CLI chunk andlastProgressAgestays small while the lane runs. Long claude-opus-4-7 turns complete normally (durations above two minutes observed on the running gateway), noAbortErroris emitted on the affected sessions for the duration of the observation window, andrecovery=nonefor every long-running classification.thinking_deltalines arrive.Root Cause
createCliJsonlStreamingParser'sonAssistantDeltacallback only fires fortext_deltacontent blocks.thinking_delta,tool_use,content_block_start/stop, and system events all pass through the parser but never invoke the delta callback. The prior fix hooked at that text-only boundary, leaving the diagnostic watchdog with no progress signal during reasoning-only phases. Missing guardrail: no regression coverage forced a reasoning-only stream through the live-session path.Regression Test Plan
src/agents/cli-runner/claude-live-session.diagnostic-progress.test.ts(new file): drivesrunClaudeLiveSessionTurnwith a mocked supervisor that feeds JSONLthinking_deltalines through the live session'sonStdout, asserts thatrun.progresswithreason="cli:live:stdout"fires through the throttle window, and asserts thatonAssistantDeltais never invoked β proving the stdout-level emission is strictly more inclusive than the prior text-delta hook.User-visible / Behavior Changes
None. Internal diagnostic signal only.
Diagram
Security Impact
runId,sessionId,sessionKeyfromPreparedCliRunContext.paramsand a staticreasonliteral)Repro + Verification
claude-opus-4-7viaclaude-cli(live-session mode).lastProgress=cli:live:stdouton each raw CLI chunk; long-running sessions are kept alive while the CLI is actively streaming.AbortErroreven while the CLI was emittingthinking_deltalines.Evidence
Human Verification
Verified: the new seam coverage passes against the patched source; the existing cli-runner suite stays clean; the patched-build gateway emits
lastProgress=cli:live:stdoutagainst real claude-cli sessions and the watchdog stays atrecovery=nonefor long-running lanes; durations above two minutes complete normally on Opus. NOT verified: a deliberately-staged reasoning-only turn of more than six minutes against the live gateway (no such turn was deliberately driven during the observation window).Review Conversations
Compatibility / Migration
Backward compatible. No config or migration. The new emit uses only existing run/session identifiers and a static
reasonliteral.Risks and Mitigations
Mitigation: the supervisor-level
noOutputTimeoutMswatchdog (separate from the diagnostic watchdog) still kills truly silent processes; the throttle prevents spam from chatty streams.onAssistantDeltaemission inexecute.tsbecomes redundant for the live-session path (text_delta also passes throughhandleClaudeStdout).Mitigation: redundant but harmless β the throttle bucket suppresses the duplicate emit. Happy to land a follow-up cleanup once both PRs are in.