feat: announce autonomous turn ends via _session/turn_ended - #997
Open
wingleeio wants to merge 1 commit into
Open
feat: announce autonomous turn ends via _session/turn_ended#997wingleeio wants to merge 1 commit into
wingleeio wants to merge 1 commit into
Conversation
An autonomous cycle — a task-notification followup, or a peer/ coordinator/observer message the model handled on its own — streams its output as out-of-turn session/update frames, but its turn-end has no session/prompt response to ride: the SDK's result message was consumed silently. A client can then only guess at the boundary from stream silence, and shows the session as "working" for however long its own watchdog waits after the agent already finished (in comet's case: two minutes of phantom working after every background-task notification). Emit a `_session/turn_ended` extension notification (per the ACP `_` extension conventions, like `_session/steering`) from the autonomous-result lane, carrying the sessionId, the result's own stop reason (the accumulated stopReason belongs to the user-turn lifecycle and may still hold the previous turn's value), and the origin under `_meta`. Only sent when no user turn is active or queued — a live turn's end rides its own prompt response, and a deferred-settle hold consumes the followup's result. Best-effort: a client that cannot take the extension never kills the consumer loop; unknown methods are ignored by spec. Tested: an idle background wake announces exactly once with the right session and origin; a background result consumed during a live prompt does not announce.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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.
Problem
An autonomous cycle — a task-notification followup, or a peer/coordinator/observer message the model handled on its own — streams its output as out-of-turn
session/updateframes, but its turn-end has nowhere to go: there is nosession/promptresponse for it to ride, so the SDK'sresultmessage is consumed silently by the autonomous-result lane.A client can then only guess at the turn boundary from stream silence. In practice it shows the session as "working" for however long its own silence watchdog waits after the agent already finished — in comet's case, two minutes of phantom "working" after every background-task notification (that client's report and root-cause trace: the adapter's autonomous lane breaks without emitting; journal shows output with no terminal event until the next user prompt).
Change
Emit a
_session/turn_endedextension notification (_-prefixed per the ACP extension conventions, like_session/steering) from the autonomous-result lane:sessionId, the result's ownstop_reason(the accumulatedstopReasonbelongs to the user-turn lifecycle and may still hold the previous turn's value at this point), and the origin under_meta["_claude/origin"].emittedAssistantTextreset.Tests
Verified end-to-end against a patched comet client: background
sleep 8task → prompt turn settles → wake streams "finished" →_session/turn_ended→ client status settles immediately (previously: a 120s watchdog was the only settle path).