Skip to content

agentHost: preserve multiple pending steering messages - #340669

Merged
Giuseppe Cianci (Giuspepe) merged 13 commits into
mainfrom
agents/fix-codex-harness-steering-bug
Oct 16, 2026
Merged

Giuseppe Cianci (Giuspepe) merged 13 commits into
mainfrom
agents/fix-codex-harness-steering-bug

Conversation

@Giuspepe

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

Copy link
Copy Markdown
Contributor

with this pr

all steering messages are shown

steering-fixed.mp4

chatgpt app (reference behavior showing multiple steering messages)

Screen.Recording.2026-10-12.at.16.43.03.mov

current behavior before this pr

only the latest steering message is shown

Screen.Recording.2026-10-12.at.16.42.08.mov

Problem

Sending a second steering message while Codex is working hides the first pending message, even though the model may receive both.

In the before-fix reproduction, the user asks for five timed shell calls and sends steering messages while Codex works. Only the last one, say baz, remains visible, but the assistant replies:

foo bar baz. Continuing the timed sequence.

AHP's single steering slot replaces each earlier message. Codex can still have those messages buffered, so the pending UI no longer reflects what was sent.

Fix

Use the shared pending queue from microsoft/agent-host-protocol#512, as suggested in review. queuedMessages holds both kinds, distinguished by PendingMessage.kind, using the existing actions. Adding B keeps A visible; consuming A removes only A.

  • Group steering messages before queued follow-ups in the UI, preserving each message's attachments, sender, and ID.
  • Deduplicate the legacy steeringMessage mirror in UI projection, provider delivery, and session context. The shared list owns each entry's content, kind, and order.
  • Deliver steering individually when the provider is ready. Match Codex receipts by submission ID, including identical prompts; retain text matching for older app servers.
  • Clear all pending steering on cancellation, including Claude prompts accepted but not yet pulled by the SDK. Keep queued follow-ups. Clear rejected local submissions without losing another pending message.
  • Omit empty completed response rows between consumed messages and their duplicate checkpoint spacing. Keep errors, cancelled responses, actual response content, and request timestamps.

This pins the landed AHP commit 5d542f9e from the merged protocol PR. There is no new capability or enqueue flag. AHP mirrors the latest steering update in the deprecated singleton for 1.0.0 clients; updated clients use the complete list without duplicating that mirror. Syncing from the landed commit changed only the pin; the previously validated protocol sources are identical.

Tests

The original disappearance regression was red for Codex, Copilot, and Claude configurations. The new spacing and rejected-submission regressions were also red before their fixes and are now green. Cancellation coverage includes provider handoff without SDK consumption, followed by cancellation and a later queued turn.

After merging main at 640a33ebdea, the selected 4,555-test suite passed, with 19 pending tests. Another 97 focused protocol/Copilot tests passed. The new mirror-deduplication tests were red before the fix and are green now. Build, client type-check, changed-file lint, and commit hygiene passed.

Reverified live on October 15 with Codex in Code OSS Dev 1.143.0 on macOS: say bar and say baz each appeared exactly once while pending and after consumption, and both were acknowledged. DOM checks found no response row between them; their gap was 28.5px, including the request timestamp. A fresh 44-second recording, screenshots, and Playwright trace were saved locally. Existing attached recordings are preserved above.

Live Copilot/Claude runs and full product smoke suites were not run.

Validation commands

All commands below passed:

npm run build-fast
npm run build-fast -- --client-only
npm run typecheck-client

# Run while the merge was open: passed for 49 TypeScript files.
git diff --name-only --diff-filter=ACM MERGE_HEAD -- '*.ts' | xargs npm run eslint -- \
  src/vs/platform/agentHost/test/common/agentSessionMessage.test.ts
npm run eslint -- \
  src/vs/platform/agentHost/common/state/protocol/channels-tcp/commands.ts \
  src/vs/platform/agentHost/common/state/protocol/channels-tcp/notifications.ts \
  src/vs/platform/agentHost/common/state/protocol/channels-tcp/state.ts \
  src/vs/platform/agentHost/common/state/protocol/window-exempt.generated.ts
# Passed for the four newly synced files.

env -u COPILOT_HOME ./scripts/test.sh \
  --run src/vs/platform/agentHost/test/common/agentSessionMessage.test.ts \
  --run src/vs/platform/agentHost/test/node/chatContributions.test.ts \
  --run src/vs/platform/agentHost/test/node/agentSideEffects.test.ts \
  --run src/vs/platform/agentHost/test/node/agentService.test.ts \
  --run src/vs/platform/agentHost/test/node/agentHostTurnTelemetry.test.ts \
  --run src/vs/platform/agentHost/test/node/sessionServerTools.test.ts \
  --run src/vs/platform/agentHost/test/node/protocolServerHandler.test.ts \
  --run src/vs/platform/agentHost/test/node/reducers.test.ts \
  --run src/vs/platform/agentHost/test/node/codex/codexAgent.test.ts \
  --run src/vs/platform/agentHost/test/node/copilotAgent.test.ts \
  --run src/vs/platform/agentHost/test/node/claudeAgent.test.ts \
  --run src/vs/workbench/contrib/chat/test/browser/agentSessions/agentHostChatContribution.test.ts \
  --run src/vs/workbench/contrib/chat/test/browser/widget/chatListWidget.test.ts \
  --run src/vs/workbench/contrib/chat/test/browser/widget/chatListRenderer.test.ts \
  --run src/vs/workbench/contrib/chat/test/common/model/chatViewModel.test.ts \
  --run src/vs/sessions/contrib/remoteSessions/test/browser/remoteSessionMessageRouter.test.ts \
  --run src/vs/sessions/contrib/remoteSessions/test/common/remoteSessionInspection.test.ts \
  --reporter dot
# 4,555 passed; 19 pending.

env -u COPILOT_HOME ./scripts/test.sh \
  --run src/vs/platform/agentHost/test/node/protocolServerHandler.test.ts \
  --run src/vs/platform/agentHost/test/node/copilotAgentSession.test.ts \
  --grep 'TCP connections|steer|Steer|pending|buffer' --reporter dot
# 97 passed.

Use capability-negotiated AHP steering lists rather than replacing a single pending slot. Preserve legacy-host submissions locally until the slot clears, correlate Codex receipts by submission ID, and defer provider handoff until ready.

Vendor the companion AHP contract at 57241b5a and cover per-message consumption, legacy coexistence, reconnects, and attachment rewriting.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 Changes recommended

Rejected submissions and Codex readiness races can leave steering messages permanently pending.

2 open findings
What changed in this PR

Fixes disappearing Agent Host steering messages by introducing negotiated independent steering-message lists while retaining compatibility with legacy hosts.

Changes:

  • Vendors the draft AHP steering-list protocol and capability negotiation.
  • Preserves, routes, correlates, and consumes multiple steering messages independently.
  • Expands provider, synchronization, replay, attachment, and remote-session tests.
File Description
src/​vs/​workbench/​contrib/​chat/​test/​browser/​agentSessions/​agentHostChatContribution.test.ts Tests list and legacy synchronization.
src/​vs/​workbench/​contrib/​chat/​browser/​agentSessions/​agentHost/​agentHostSessionHandler.ts Synchronizes local and remote steering lists.
src/​vs/​sessions/​contrib/​remoteSessions/​test/​common/​remoteSessionInspection.test.ts Tests listed-steering status.
src/​vs/​sessions/​contrib/​remoteSessions/​common/​remoteSessionInspection.ts Treats steering lists as queued work.
src/​vs/​platform/​agentHost/​test/​node/​sessionServerTools.test.ts Tests multiple tool-submitted steering messages.
src/​vs/​platform/​agentHost/​test/​node/​protocolServerHandler.test.ts Tests negotiation, filtering, and replay.
src/​vs/​platform/​agentHost/​test/​node/​copilotAgentSession.test.ts Tests failed-steering cleanup.
src/​vs/​platform/​agentHost/​test/​node/​codex/​codexAgent.test.ts Tests readiness and ID correlation.
src/​vs/​platform/​agentHost/​test/​node/​chatContributions.test.ts Tests queue-drain delivery and retry.
src/​vs/​platform/​agentHost/​test/​node/​agentSideEffects.test.ts Tests per-ID consumption.
src/​vs/​platform/​agentHost/​test/​node/​agentService.test.ts Tests attachments and mutation rejection.
src/​vs/​platform/​agentHost/​node/​shared/​sessionServerTools.ts Submits independent steering actions.
src/​vs/​platform/​agentHost/​node/​protocolServerHandler.ts Negotiates and projects steering capability.
src/​vs/​platform/​agentHost/​node/​copilot/​copilotAgentSession.ts Clears failed or skipped steering.
src/​vs/​platform/​agentHost/​node/​copilot/​copilotAgent.ts Reports provider readiness.
src/​vs/​platform/​agentHost/​node/​codex/​codexAgent.ts Correlates echoes and defers handoff.
src/​vs/​platform/​agentHost/​node/​claude/​claudeAgent.ts Reports provider readiness.
src/​vs/​platform/​agentHost/​node/​chatContributions/​queueDrain/​queueDrainContribution.ts Delivers listed steering without duplication.
src/​vs/​platform/​agentHost/​node/​agentSideEffects.ts Removes the consumed steering entry.
src/​vs/​platform/​agentHost/​node/​agentService.ts Validates and rewrites steering actions.
src/​vs/​platform/​agentHost/​common/​state/​sessionState.ts Exposes listed steering in merged state.
src/​vs/​platform/​agentHost/​common/​state/​protocol/​version/​registry.ts Registers new action versions.
src/​vs/​platform/​agentHost/​common/​state/​protocol/​common/​commands.ts Defines capability negotiation.
src/​vs/​platform/​agentHost/​common/​state/​protocol/​common/​actions.ts Adds steering action types.
src/​vs/​platform/​agentHost/​common/​state/​protocol/​channels-chat/​state.ts Adds the steering list state.
src/​vs/​platform/​agentHost/​common/​state/​protocol/​channels-chat/​reducer.ts Reduces list set/removal actions.
src/​vs/​platform/​agentHost/​common/​state/​protocol/​channels-chat/​actions.ts Defines list action contracts.
src/​vs/​platform/​agentHost/​common/​state/​protocol/​action-origin.generated.ts Updates generated action unions.
src/​vs/​platform/​agentHost/​common/​state/​protocol/​.ahp-version Pins the draft protocol commit.
src/​vs/​platform/​agentHost/​common/​agentSessionMessage.ts Unifies legacy and listed lookup.
src/​vs/​platform/​agentHost/​common/​agent.ts Adds provider deferral semantics.
src/​vs/​platform/​agentHost/​browser/​agentHostProtocolClient.ts Advertises steering-list support.

🧠 Review effort: Balanced


💡 Configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread src/vs/platform/agentHost/node/codex/codexAgent.ts
Keep the upstream Copilot startup buffer for the legacy slot while handing independent list submissions to providers separately. Preserve relay snapshot projection and verify startup, cancellation, and duplicate-cleanup behavior.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@github-actions

github-actions Bot commented Oct 9, 2026 •

Copy link
Copy Markdown
Contributor

Base: 57c2e57c Current: c0b7effc

No screenshot changes.

Resolve the agent-host session handler import overlap by retaining both built-in Ask agent URI unwrapping and independent pending steering message projection.

Validated the merged client build, typecheck, targeted ESLint, and 108 steering/Ask URI tests. The AHP 1.1.0 development references remain current; no protocol bump or source-pin change is required.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 Changes recommended

Independent steering-created turns are misclassified in telemetry, and the vendored protocol dependency remains an unaccepted draft.

3 open findings

🧠 Review effort: Balanced

Comment thread src/vs/platform/agentHost/node/agentSideEffects.ts Outdated
@Giuspepe
Giuseppe Cianci (Giuspepe) marked this pull request as ready for review October 12, 2026 15:02
@vs-code-engineering

Copy link
Copy Markdown
Contributor

📬 CODENOTIFY

The following users are being notified based on files changed in this PR:

TylerLeonhardt

Matched files:

  • src/vs/platform/agentHost/node/claude/claudeAgent.ts

Check both pending steering representations before provider turn-start reduction consumes the matching message. Cover legacy and list-backed promotion in the turn telemetry regression.

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.

Reviewed security, correctness, and meaningful simplification. No blocking findings; one important, non-blocking Claude cancellation-cleanup issue is noted inline.

Written by Connor's agent running GPT-6.1 Sol

@Giuspepe
Giuseppe Cianci (Giuspepe) marked this pull request as draft October 14, 2026 10:03
Adopt kind-tagged pending messages without new steering actions or capabilities. Clear accepted steering on cancellation and rejected local submissions, and keep consecutive consumed messages compact.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Use the shared steering selector in the fake host and assert that both steering and queued entries remain pending.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@Giuspepe
Giuseppe Cianci (Giuspepe) marked this pull request as ready for review October 14, 2026 13:07
Sync AHP 5a396685 and deduplicate its legacy mirror in pending steering, client projection, and context snapshots. Preserve transcript caching and compact consumed-message rendering. Keep the newly synced optional TCP command explicitly unsupported.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Keep 5d542f9e, which includes the per-chat configuration protocol pinned by main and the merged steering changes. Regenerating from that commit matches the merged protocol sources.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Preserve per-message steering tracking alongside upstream placeholder-title handling. Include the shared-list steering entry and legacy mirror in the new model-option compatibility snapshot assertions.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Retain the pending-steering helper alongside the new canvas-close request type.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
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.

5 participants