Skip to content

chat: preserve independent steering messages - #512

Merged
Giuseppe Cianci (Giuspepe) merged 5 commits into
mainfrom
gcianci/steering-message-list
Oct 15, 2026
Merged

Giuseppe Cianci (Giuspepe) merged 5 commits into
mainfrom
gcianci/steering-message-list

Conversation

@Giuspepe

@Giuspepe Giuseppe Cianci (Giuspepe) commented Oct 9, 2026 •

Copy link
Copy Markdown
Contributor

Problem

AHP has one pending steeringMessage slot. 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:

user: say bar
user: say foo
assistant: bar; foo

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.kind and store steering and queued messages together in ChatState.queuedMessages. Missing kind means 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 steeringMessage slot 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 5a396685 and 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 generate and npm test passed. The root suite has 568 passing tests.
  • npm --prefix clients/typescript test passed 77 tests. npm --prefix clients/typescript run build passed.
  • In clients/rust, cargo test --workspace passed.
  • In clients/go, go test -count=1 ./... passed.
  • In clients/kotlin, JAVA_HOME=/opt/homebrew/opt/openjdk@17/libexec/openjdk.jdk/Contents/Home ./gradlew test --rerun-tasks --no-daemon --console=plain passed.
  • In clients/dotnet, dotnet test passed 648 tests.
  • swift build passed. Local swift test remains 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.

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>
Comment thread types/channels-chat/state.ts Outdated
* Independently submitted steering messages, in host acceptance order.
* Requires negotiated {@link InitializeResult.steeringMessages} support.
*/
steeringMessages?: PendingMessage[];

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 it pendingMessages (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.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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>

@connor4312 Connor Peet (connor4312) left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

couple concrete changes and some wording!

Comment thread types/channels-chat/reducer.ts
Comment thread types/channels-chat/reducer.ts
Comment thread types/channels-chat/state.ts
Comment thread types/channels-chat/state.ts Outdated
Comment thread types/channels-chat/state.ts
Comment thread types/channels-chat/state.ts Outdated
Comment thread types/channels-chat/actions.ts Outdated
Comment thread types/channels-chat/actions.ts Outdated
Comment thread types/channels-chat/actions.ts Outdated
Comment thread types/channels-chat/actions.ts Outdated
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>

@connor4312 Connor Peet (connor4312) left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One comment then I think this should be good to go

@@ -0,0 +1,31 @@
{

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The naming of these files does not match the existing test cases

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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>
@Giuspepe
Giuseppe Cianci (Giuspepe) merged commit 5d542f9 into main Oct 15, 2026
9 checks passed
@Giuspepe
Giuseppe Cianci (Giuspepe) deleted the gcianci/steering-message-list branch October 15, 2026 16:20
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.

2 participants