Repository navigation
chat: preserve independent steering messages - #512
Conversation
Preserve individual pending steering submissions alongside the legacy slot. Negotiate support explicitly, add per-ID actions for AHP 1.1.0, and keep schemas and native reducers aligned through shared fixtures. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
| * Independently submitted steering messages, in host acceptance order. | ||
| * Requires negotiated {@link InitializeResult.steeringMessages} support. | ||
| */ | ||
| steeringMessages?: PendingMessage[]; |
There was a problem hiding this comment.
Alternate design: we add PendingMessageKind to PendingMessage and then the queuedMessages becomes an array of both steering and queued messages. The downsides are:
- we have both steering and queued messages in an array called
queuedMessages-- would have preferred to call itpendingMessages(fixable in v2) - pending messages can be included after queued messages, even though they will generally be processed first. Just a little complexity UI's will need to present
But on the plus side, it's consistent with the existing set of ChatPendingMessage*Action actions that we have and the existing PendingMessageKind enum. We should have just went with that design from the get-go, it's a lot nicer.
There was a problem hiding this comment.
Implemented in 475e5dd. PendingMessage.kind now distinguishes steering and queued entries in queuedMessages, using the existing set/remove/reorder actions. I removed the separate steering list, new actions, and capabilities; there is no enqueue flag. Missing kind defaults to queued, and the old singleton is retained only for old snapshots. All six SDK language CI jobs pass. The companion VS Code PR groups steering first and pins this commit.
Use PendingMessage.kind and the existing pending-message actions for one ID-keyed queuedMessages list. Preserve same-ID positions and require matching kinds for removal without writing the deprecated snapshot slot. Replace the draft steering list, actions and capability negotiation; restore the unrelated Go capability-marker generator change. Document the coordinated host/client migration and raw versus display ordering, with shared regression fixtures across SDKs. Addresses the approved design review on #512. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Connor Peet (connor4312)
left a comment
There was a problem hiding this comment.
couple concrete changes and some wording!
Apply the review wording verbatim and keep the latest steering entry mirrored for older clients. Cover updates, removals, kind transitions, and turn consumption across the shared reducer fixtures. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Connor Peet (connor4312)
left a comment
There was a problem hiding this comment.
One comment then I think this should be good to go
| @@ -0,0 +1,31 @@ | |||
| { | |||
There was a problem hiding this comment.
The naming of these files does not match the existing test cases
There was a problem hiding this comment.
thanks, just fixed it. maybe this is something we can mention in AGENTS.md so it doesn't happen again
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Problem
AHP has one pending
steeringMessageslot. Setting B replaces A, even if the provider has already buffered A. In VS Code, the earlier pending message disappears while Codex may still act on both.The before-fix Codex transcript from the ChatGPT app shows why separate submissions matter. While running timed shell calls, it records these inputs and reply:
The two inputs have different message IDs within the same Codex turn. They remain separate user-message items even though the assistant answers both in one reply.
Change
Following Connor's review, add optional
PendingMessage.kindand store steering and queued messages together inChatState.queuedMessages. Missingkindmeans queued, so existing queued snapshots still load.Reuse the existing pending-message actions. A new ID appends; the same ID updates in place. Removal matches both ID and kind. Starting a turn consumes its matching
queuedMessageId, regardless of kind. Clients group steering entries first without needing to change the stored order.There is no new action, capability, or enqueue flag. For 1.0.0 clients, each steering set also replaces the deprecated
steeringMessageslot with the latest entry. Matching removal or turn consumption clears it; changing that ID to queued input clears it too. Updated clients deduplicate this mirror by ID and use the shared list's order and kinds. Older clients retain a latest-message view, not the full multi-message experience.This targets the existing AHP 1.1.0 development version. It does not change provider turn boundaries, publish a release, or change SDK package versions or released compatibility baselines.
Companion implementation: microsoft/vscode#340669. It pins this PR's commit
5a396685and should land after the protocol change.Tests
Shared fixtures cover mixed queues, per-ID updates, kind transitions, mismatched removals, reordering, consumption, and old snapshots. The new compatibility regressions were red before the mirror was restored and are green now. The root suite passes 568 tests. All six language CI jobs pass for
5a396685.Validation commands
Local validation for
5a396685:npm run generateandnpm testpassed. The root suite has 568 passing tests.npm --prefix clients/typescript testpassed 77 tests.npm --prefix clients/typescript run buildpassed.clients/rust,cargo test --workspacepassed.clients/go,go test -count=1 ./...passed.clients/kotlin,JAVA_HOME=/opt/homebrew/opt/openjdk@17/libexec/openjdk.jdk/Contents/Home ./gradlew test --rerun-tasks --no-daemon --console=plainpassed.clients/dotnet,dotnet testpassed 648 tests.swift buildpassed. Localswift testremains unavailable because the installed Command Line Tools lack XCTest. The hosted Swift CI job passed.Package publishing and live external-host integration were not tested.