Skip to content

fix(assistant): streaming-render bugs in CLI-backed runs#9

Merged
juacker merged 1 commit into
mainfrom
fix/cli-streaming-render
May 21, 2026
Merged

fix(assistant): streaming-render bugs in CLI-backed runs#9
juacker merged 1 commit into
mainfrom
fix/cli-streaming-render

Conversation

@juacker
Copy link
Copy Markdown
Owner

@juacker juacker commented May 21, 2026

Follow-up to #8. Both fixes were originally pushed to `feat/cli-support` after the merge, so neither landed in `main`. Bringing them across.

Summary

Two streaming-rendering bugs surfaced while watching a long Claude Code run from the workspace view:

  1. Disappearing text mid-stream. `Workspace.jsx` polls a snapshot every 5s, which calls `loadSessionData` (`sessionStore.js`). That helper was re-creating the session state via `createInitialSessionState`, which resets `streamingTextByMessageId` to `{}`. Mid-stream this wiped every accumulated delta on each tick — text flashed in, vanished on the next 5s boundary, then re-accumulated until the next wipe. Now `loadSessionData` preserves `streamingTextByMessageId` and `isStreaming` from prior state; both are cleared naturally by `completeMessage` / `setRunStatus` when the run terminates.

  2. No paragraph breaks between Claude content blocks. Claude's stream-json splits one assistant message into multiple `content_block` segments (text → tool_use → text → ...). Our parser in `local_agent.rs::handle_claude_event` only handled `content_block_delta` and `push_str`-ed every text fragment into one string with no separator, so `"...PR test(assistant): add workspace_tasks.rs pure function tests #6."` in one block ran straight into `"Good — PR test(assistant): add workspace_tasks.rs pure function tests #6 was merged..."` from the next block. Now also handle `content_block_start`: when a text block opens after existing text content, insert a paragraph break before its deltas.

Test plan

  • `cargo fmt --check` + `cargo clippy --lib -- -D warnings` clean
  • `cargo test --lib` — 301 pass, 1 ignored
  • ESLint on `sessionStore.js` clean
  • Manual: open a workspace, send a Claude-backed message, watch the text grow monotonically with no flicker at the 5s polling boundaries
  • Manual: ask Claude to do a multi-tool turn ("look at the repo and tell me what changed"); text between tool calls should appear as separate paragraphs

…aragraph-break Claude blocks

Two streaming-rendering bugs surfaced while watching a long Claude Code run
from the workspace view:

1. The workspace polls a snapshot every 5s. `loadSessionData` was
   re-creating the session state via `createInitialSessionState`, which
   resets `streamingTextByMessageId` to {}. Mid-stream this wiped every
   accumulated delta on each tick — text would briefly flash, vanish on
   the next 5s boundary, then re-accumulate until the next wipe.
   Preserve the in-flight streaming map and `isStreaming` flag across
   snapshot loads; both are cleared naturally by completeMessage /
   setRunStatus when the run actually terminates.

2. Claude's stream-json splits one assistant message into multiple
   content_blocks (text → tool_use → text → ...). Our parser only handled
   `content_block_delta` events and concatenated every text fragment
   into one string with no separator, so "...PR #6." in one block ran
   straight into "Good — PR #6 was merged..." in the next block as a
   single paragraph. Now also handle `content_block_start`: when a new
   text block opens after existing text content, insert a paragraph
   break before its deltas.
@juacker juacker merged commit 7d59519 into main May 21, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant