Skip to content

fix(session): show a message sent mid-turn in the transcript - #12

Open
Adam-Dalloul wants to merge 1 commit into
xintaofei:mainfrom
Adam-Dalloul:fix/mid-turn-message-in-transcript
Open

Adam-Dalloul wants to merge 1 commit into
xintaofei:mainfrom
Adam-Dalloul:fix/mid-turn-message-in-transcript

Conversation

@Adam-Dalloul

Copy link
Copy Markdown

A message sent while the agent is still replying never appears in the
transcript. It only shows up after the turn ends, once the transcript
reconciles with the server, and until then the answer to it keeps streaming
into the same assistant bubble, so two separate replies read as one run-on
paragraph.

The cause is that feedback_submitted is never decoded: it falls into the
AcpEvent.unknown catch-all and the handler drops it. The server does record
the message (it projects a mid-turn user_message_chunk as its own user turn),
which is why a reload shows it and the live view does not.

This decodes the event and, when the note is already delivered on submission
(the native steering channel, where the agent has the text as a user message
rather than as a check_user_feedback tool result), splices it into the live
turn at the point it arrived. That closes the run the agent was writing and
starts the reply to it in a new one, which is the same split the server's own
projection makes. It is idempotent by note id, since the submit is broadcast to
every attached client including the sender, and ignored outside a running turn.
The turn's transcript is replaced by the server's copy once it settles, so
nothing doubles on reload or on re-entering the session.

This mirrors xintaofei/codeg#636, so the two clients behave the same way.

One boundary worth stating: iOS still cannot send mid-turn itself, since
send() refuses while a turn is in flight and the compose button is Stop. What
this fixes today is the cross-client case, a message sent from desktop or web
while the phone is watching the same turn.

Not compiled. I have no macOS or Xcode available, and the repo has no test
target and no CI, so this was verified by reading: every symbol and signature it
touches was checked against the tree, the new cases cover every exhaustive
switch over AcpEvent, LiveSegment and RenderPart, and the branch merges
cleanly with the other open PRs.

A message sent while the agent is still replying never appeared in the
transcript. The client does not decode feedback_submitted at all, so the event
falls into the AcpEvent .unknown catch-all and the handler drops it. The
message only surfaces once the turn ends and the transcript reconciles with the
server, which projects a mid-turn user_message_chunk as its own user turn. And
because no user turn lands between the two halves of the reply, the answer to
that message keeps streaming into the same assistant bubble, so two separate
replies read as one run-on paragraph.

Decode the event, and when the note is already delivered on submission (the
native steering channel, where the agent has the text as a user message rather
than as a check_user_feedback tool result), splice it into the live turn at the
point it arrived. That closes the run the agent was writing and starts the
reply to it in a fresh one, which is the same split the server's own projection
makes, so the live view and a reload agree. It is idempotent by note id, since
the submit is broadcast to every attached client including the sender, and it
is ignored outside a running turn, where there is nothing to split and
appending would graft the message onto a finished reply. The waiting shimmer
moves to the tail of the turn, so interrupting the agent no longer leaves the
transcript looking stalled.

The turn's transcript is replaced wholesale by the server's copy when it
settles, so nothing doubles on reload or on re-entering the session. The
unreconciled fallback splits its snapshot the same way rather than folding a
whole interrupted reply into one assistant turn.

iOS itself still cannot send mid-turn: send() refuses while a turn is in flight
and the compose button is Stop. What this fixes today is the cross-client case,
a message sent from desktop or web while the phone is watching the same turn.
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