Skip to content

chore(deps): update ACP SDK to 2.0.2 - #676

Merged
benbrandt merged 1 commit into
mainfrom
chore/acp-sdk-2.0.2
Oct 26, 2026
Merged

benbrandt merged 1 commit into
mainfrom
chore/acp-sdk-2.0.2

Conversation

@benbrandt

Copy link
Copy Markdown
Member

Summary

First independent extraction from #655. This PR targets main directly and does not depend on the standard-subagent implementation or any other extraction.

  • Raise the minimum ACP SDK patch from ~2.0.0 to ~2.0.2.
  • Update only the SDK's lockfile version, URL, and integrity. No other dependencies or adapter source files change.
  • SDK 2.0.1/2.0.2 include HTTP stream-conflict isolation, CR-only SSE line-ending support, and request-scoped POST failure handling. This adapter's existing stdio behavior is checked against the new package; no HTTP-specific adapter changes or new subagent behavior are included.

Validation

Run on this branch based directly on main at a77829f, without #655's test configuration or runtime changes:

  • npm ci --ignore-scripts: SDK resolves to 2.0.2; Codex remains 0.164.0 and Vitest remains 5.0.5.
  • npm run typecheck
  • npm test: 1,879 passed, 36 skipped
  • npm run test:integration: 7 passed, using the real Codex app-server with a local mock model
  • npm run build
  • npm run bundle:all: all six targets compile
  • git diff --check

The full live-model E2E suite, direct HTTP transport tests, and execution of every cross-platform bundle were not run. The existing five npm audit findings are outside this dependency-only extraction.

Split plan

This can be reviewed and merged independently. #655 stays open as the reference implementation; subsequent changes will be extracted into separate, independently validated PRs rather than landing that monolithic diff.

@benbrandt
benbrandt merged commit c4e1310 into main Oct 26, 2026
6 checks passed
@benbrandt
benbrandt deleted the chore/acp-sdk-2.0.2 branch October 26, 2026 11:25
benbrandt added a commit that referenced this pull request Oct 26, 2026
## Summary

Second independent extraction from #655. **One file, 11 additions.**
Based directly on `main`; it does not depend on the SDK update in #676
or on any subagent code.

Codex integration fixtures can download plugins containing their own
tests under `tmp/`. Vitest's default repository-wide discovery can
collect those foreign tests. Scope discovery to the repository-owned
`src/__tests__/` and `scripts/` directories instead.

- Reuse `configDefaults.include`, preserving Vitest's supported
test/spec filename patterns rather than narrowing to `.test.ts`.
- Keep the release-tooling tests under `scripts/`.
- Use an ESM `.mjs` configuration, which does not introduce a root-level
TypeScript file outside the application's `rootDir: src`.
- Leave test implementations, skip behavior, command-line exclusions,
dependencies, and production code unchanged.

## Validation

Validated independently on `main` at `a77829f`, using its SDK **2.0.0**,
Codex **0.164.0**, and Vitest **5.0.5**:

- Controlled before/after discovery check using `vitest list --filesOnly
--json`:
- Default discovery included a temporary
`tmp/vitest-discovery-probe.spec.ts`.
- The new configuration excluded only that foreign file; every other
file was preserved.
- An owned `.spec.mjs` probe and `scripts/next-preview-version.test.mjs`
remained discoverable.
- Temporary probes were removed before running the suites and are not
part of this PR.
- `npm run typecheck`
- `npm test`: **1,879 passed**, 36 skipped, matching the unmodified
discovery run on the SDK extraction
- `npm run test:integration`: **7 passed**, with the real Codex
app-server and a local mock model
- `npm run build`
- `git diff --check`

No snapshots changed. The full live-model E2E suite and local
cross-platform bundling were not run for this config-only change.
benbrandt added a commit that referenced this pull request Oct 26, 2026
## Summary

Third standalone extraction from #655, after #676 and #677 landed. Based
directly on current `main` (`12e2d16`), including #678; no subagent
runtime or production files change.

- Add an optional request-body response selector so concurrent root,
child, and title requests can receive the correct scripted responses
without depending on arrival order.
- Support synchronous handlers and handlers that await a response.
Preserve FIFO behavior when no selector is installed; explicit HTTP
errors still take precedence, and an undefined selection is an
unexpected request rather than a queue fallback.
- Return a fixed generic HTTP 500 on handler failure and keep
diagnostics in server-side logs. Do not write replies to disconnected
clients.
- Generalize function-call SSE replies to named/namespaced tools. The
existing shell helper delegates without changing its payload.

## Standalone coverage

Seven direct tests cover FIFO compatibility, concurrent out-of-order
completion, error/path precedence, unhandled requests,
synchronous/asynchronous failure and recovery, and named/namespaced
function serialization. Snapshots contain stable payloads rather than
changing response IDs.

The original #655 only tested handler failures directly; this extraction
adds coverage for the fixture's useful behavior without needing the
later subagent feature.

## Validation

- `npm ci --ignore-scripts`
- `npm run typecheck`
- Focused mock-server/model-request suite: **10 passed**
- `npm test`: **1,915 passed**, 36 skipped
- `npm run test:integration`: **7 passed**, using the real Codex 0.164.0
app-server and local mock model, including existing shell-tool flows
- `npm run build`
- `git diff --check`

Only test infrastructure is changed. The full live-model E2E suite and
local cross-platform bundling were not run for this test-only
extraction. Existing dependency audit findings are outside this scope.
benbrandt added a commit that referenced this pull request Oct 26, 2026
## Summary

Fourth standalone extraction from #655, after #676, #677, and #680
landed. **Two source files, +34/-27 lines.** Based directly on current
`main` (`1685cde`), preserving native child model reporting from #678.

Group the existing command/fuzzy-search/guardian reporters, image
bookkeeping, reasoning deduplication, and message-phase map into
`CodexItemStreamState`.

- Each event handler still allocates exactly one private instance, with
the same seven field types and initializers.
- Every existing access goes through that instance. No state sharing,
injection, lifetime extension, routing changes, or new standard-subagent
code is introduced.
- Plans, errors, tool-call tracking, session state, and subagent
ownership are untouched.

This makes the existing rendering-state boundary explicit and usable
today without landing the later lifecycle changes. It is not the change
that makes child rendering survive parent handler replacement; that
belongs in the complete live-subagent core.

## Behavior-preservation evidence

A source comparison against `main` verified that the constructor and all
method bodies are byte-identical after removing the added
`this.itemStreams.` prefix, and that all seven initializers match their
original declarations. The three reporter classes have no constructor
side effects.

No tests or snapshots were added, updated, or removed. Existing
event-driven suites provide the output-regression coverage, including
AIR and v1/v2 paths.

## Validation

- `npm ci --ignore-scripts`
- `npm run typecheck`
- `npm run build`
- `npm test`: **1,915 passed**, 36 skipped
- `npm run test:integration`: **7 passed**, with the real Codex 0.164.0
app-server and a local mock model
- `npm run bundle:all`: all six targets compile
- Live-model no-tool smoke: ACP text chunks formed
`item-state-refactor-ok`
- `git diff --check`

The full live-model E2E suite and execution of every cross-platform
binary were not run. Existing dependency audit findings are outside this
refactor.
benbrandt added a commit that referenced this pull request Oct 26, 2026
## Scope: standalone live core

Fifth incremental extraction from #655, on current `main` (`091f9b2`),
after #676, #677, #680, and #681 landed. This is the larger atomic
feature slice discussed in the split plan: **43 files, +2,898/-181**,
including 1,573 added test/snapshot lines and 1,301 added runtime lines.
No dependency or generated app-server files change.

### Included

- Standard associations for opted-in non-AIR v1 clients and non-AIR v2
clients. AIR retains its existing opt-ins, private updates, generation
identities, and fallback.
- One opaque conversation ID across assignments, idle work, and handler
replacement. Announce immediate parents before children; buffer
unresolved ancestry rather than flattening it.
- Child-owned streamed-item/tool state, plans, titles, permissions, and
elicitation. Accepted URL completion state survives parent attachment
changes; late approval replies are rejected locally when actual work
ends.
- Empty child capabilities and an allowlist boundary for all client
mutations, including private extensions and raw provider IDs. Known raw
IDs are restricted even while announcement publication is backpressured.
Parent cancellation cascades to observed live children; an actual ending
produces idle, observability loss produces unknown.
- Association-only replay and safe reattachment: current provider
parentage must match through known ancestors, inactive owned children
receive future events without loading them, and copied forks cannot
steal the original runtime. Parent history still replays normally; an
explicit advisory says recorded child transcripts are not included.
- Current child snapshots follow the real successful wire write,
including complete JSON-RPC batches. Same-parent setup execution is
serialized without waiting on each other's shared batch delivery.
Closing a parent fences queued reopen attempts.
- Preserve the model reporting already landed in #678: reuse its source
priority and read-only model option helper. Model observations are not
guessed from spawn arguments or parent values; buffered older settings
cannot replace newer observations.

### Explicitly deferred

No recursive child transcript replay, history/live item reconciliation,
recorded historical work outcomes, new configuration readback/effort
reporting, directed-session messages, or child mutation controls. Those
remain separate changes after this live core is reviewed and landed.

The current RFD explicitly allows live support without complete child
history. Recoverable associations are replayed truthfully; omitted
transcripts are not silently presented as complete.

## Review order

1. Contract selection, connection-owned identities/restrictions, and ACP
mutation dispatch.
2. Live router admission, child-owned rendering/work/request state, and
existing model reporting.
3. Provider subscriptions and ownership verification; no parent
cwd/MCP/instruction overrides when rejoining a child.
4. Conversation-owned interaction handlers and request cancellation
scopes.
5. Session setup lane, batch-write freshness boundary, and
association-only replay.
6. Behavior-focused tests and wire snapshots for both versions.

The async queue-completion gap found while planning the split is fixed
here: a session transition waits for async callbacks and propagates
rejection without breaking the notification lane. A regression
reproduces both ordering and rejection behavior. The old #655 reference
helper must not be copied back over this implementation.

## Validation

Final validation used main's latest lockfile (including #679):

- `npm run typecheck`
- `npm run build`
- `npm test`: **1,959 passed**, 38 skipped
- Focused live/wire/queue suites: **44 passed**, 2 v2-only cases skipped
on v1
- `npm run test:integration`: **15 passed** — eight new real-Codex
0.164.0 cases cover active-child reattachment, fork identity/ownership
isolation, parent cancel/close, and child terminal output/exit across
later parent prompts, on v1 and v2, using a local scripted model
- `npm run bundle:all`: all six targets compile
- Real live-model no-tool smoke completed with `end_turn`
- `git diff --check`

Existing AIR and parent-session golden files are unchanged. The
fixed-command terminal fixture alone uses full-access mode to avoid CI
hosts without sandbox namespace support; production sandbox settings are
unchanged. The full live-model E2E suite and execution of every OS
bundle were not run.

## References

- ACP specification at `8aa92106feba5cdd0da210a87a39dfee4dc24f13`:
[identity, announcement, and automatic
routing](https://github.com/agentclientprotocol/agent-client-protocol/blob/8aa92106feba5cdd0da210a87a39dfee4dc24f13/docs/rfds/subagents.mdx#L166-L246),
[best-effort replay and response
freshness](https://github.com/agentclientprotocol/agent-client-protocol/blob/8aa92106feba5cdd0da210a87a39dfee4dc24f13/docs/rfds/subagents.mdx#L713-L840).
- Official TypeScript SDK checkout
`c7e07388feed7a530f8211d0dae4951cb6d26d09` and published 2.0.2 for
transport/runtime evidence; normative behavior comes from the spec, not
the SDK implementation.
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