Skip to content

fix(chat): keep a reply the live stream is not showing - #705

Open
Adam-Dalloul wants to merge 1 commit into
xintaofei:mainfrom
Adam-Dalloul:fix/blank-agent-reply
Open

fix(chat): keep a reply the live stream is not showing#705
Adam-Dalloul wants to merge 1 commit into
xintaofei:mainfrom
Adam-Dalloul:fix/blank-agent-reply

Conversation

@Adam-Dalloul

Copy link
Copy Markdown
Contributor

An agent reply can render blank: the persisted copy is hidden and nothing takes its place.

Two timeline rules hide a persisted assistant turn while a reply streams, the liveOwnsActiveTurn tail strip and the in_flight_user_turn_id partial suppression. Both are sound only because the live stream is showing that same reply, and both asked whether a live message object existed rather than whether it renders anything. status_changed to prompting installs a fresh content: [] live message at the start of every turn and the dispatch mirror pushes it into the runtime store (already pinned by "fires with isLive=true and a fresh non-null liveMessage when a turn starts"), and the mirror never writes a null back over it.

Reproduction, on the sub-agent dialog: open it on a delegation child that already has a round on screen, then let the child start its next turn. LiveTranscriptView marks the session liveOwnsActiveTurn, bridges the empty live message the prompting transition just made, and fetches with preserveLive: true, so the strip runs with nothing to replace what it removes and the visible round vanishes until the first chunk arrives. The child CLI writes its JSONL asynchronously, so a refetch inside that window keeps the same shape.

computeTimeline now builds the streaming tail first and passes the verdict down: a live message suppresses a persisted reply only when it produced an assistant turn. A live message carrying only a mid-turn steering message counts as showing no reply, since that turn is the user's.

9 new tests; 5 of them fail on main and pass here. Full suite green (436 files, 6332 tests), tsc --noEmit clean, eslint clean.

Two timeline rules hide a persisted assistant turn while a reply streams:
the `liveOwnsActiveTurn` tail strip, which drops everything after the last
persisted user turn for a delegation-child viewer, and the
`in_flight_user_turn_id` suppression, which drops the partial assistant turn
OpenCode and Gemini persist mid-stream. Both are sound only because the live
stream is showing that same reply, and both asked whether a live message
OBJECT existed rather than whether it renders anything.

Those two differ, routinely. `status_changed` to `prompting` installs a
fresh `content: []` live message at the start of every turn and the dispatch
mirror pushes it into the runtime store, which
acp-connections-context.test.tsx already pins ("fires with isLive=true and a
fresh non-null liveMessage when a turn starts"). The mirror never writes a
null back over it, so the same object stays in hand through any stretch of a
turn that produces nothing the streaming build renders. In that state the
persisted reply was hidden with nothing put in its place: a blank agent
turn.

The sub-agent dialog reaches it on an ordinary path. `LiveTranscriptView`
marks the session `liveOwnsActiveTurn` on mount, bridges whatever live
message the child's connection holds, and fetches with `preserveLive: true`,
so when the child starts its next turn the strip runs against an empty live
message and the round already on screen disappears until the first chunk
arrives. The child CLI writes its JSONL asynchronously, so a refetch inside
that window keeps the same shape.

`computeTimeline` now builds the streaming tail first and passes the verdict
down: a live message suppresses a persisted reply only when it produced an
assistant turn. Deriving that from the same build is what keeps the two from
disagreeing again. A live message carrying only a mid-turn steering message
counts as showing no reply, since that turn is the user's, not a rendering
of the reply it would otherwise hide.
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