Skip to content

feat: add ACP v2 adapter and session fork support - #433

Open
nyssance wants to merge 10 commits into
agentclientprotocol:mainfrom
nyssance:feat/acp-v2
Open

feat: add ACP v2 adapter and session fork support#433
nyssance wants to merge 10 commits into
agentclientprotocol:mainfrom
nyssance:feat/acp-v2

Conversation

@nyssance

Copy link
Copy Markdown

Summary

  • add a dedicated ACP v2 entry point while preserving the existing v1 entry point
  • translate Codex app-server events into ACP v2 message, tool-call, plan, usage, and four-state lifecycle updates
  • implement session/fork through Codex thread/fork, including post-fork cleanup on initialization failure
  • align generated app-server types and runtime mappings with Codex 0.149.1
  • normalize legacy diff/message payloads at the v2 boundary and propagate asynchronous prompt failures

Compatibility

  • v1 consumers continue to use the existing entry point
  • v2 clients can omit mcpServers
  • deprecated _codex/current_mode_update is no longer emitted; standard config option updates are used

Verification

  • npm run typecheck
  • npm test — 470 passed, 29 skipped
  • npm run build
  • real-Codex fork E2E coverage is included under the gated e2e suite

session/fork registers on the v2 entry, declares capabilities.session.fork,
and installs the forked session through the same create path as new/resume
(fork source travels as forkFromSessionId so every "sessionId" in request
branch keeps meaning "opening an existing id"). Forked sessions inherit
history, so goal republication and title source follow the resume posture.

current_mode_update is no longer forwarded as a private dialect: mode
changes already travel via config_option_update (MODE_CONFIG_ID) and no
consumer reads the old shape.

Covers: v2 adapter unit tests (fork mapping, capability passthrough,
dialect drop) and a gated real E2E (spawned start:v2, fork carries the
source session's memory into a new independent id).
ACP v2's NewSessionRequest makes mcpServers optional; the v1 request type
happens to require it, and newSession passed it raw into
createSessionConfig where .length threw. Caught live driving session/new
over the v2 entry without the field.
thread/fork loads and subscribes the new thread on the app-server side;
a failure in the remaining initialization (model listing, auth state)
previously left that subscription alive — the resume-path cleanup is
keyed on the requested session id, which a fork never has. Both layers
now close the forked thread best-effort before rethrowing.
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