Skip to content

fix(acp)!: v1 session stream reports prompt errors and full responses - #474

Open
benbrandt wants to merge 5 commits into
mainfrom
cleanup-v1-sessions
Open

benbrandt wants to merge 5 commits into
mainfrom
cleanup-v1-sessions

Conversation

@benbrandt

@benbrandt benbrandt commented Oct 31, 2026 •

Copy link
Copy Markdown
Member

Part of the 5.0 public-API cleanup. This PR covers the v1 session API.

Addressed

  • F05 + F21: v1::SessionMessage rework.
    • An error response to session/prompt used to close the whole connection. It now arrives on the session stream as SessionMessage::PromptResponse(Result<PromptResponse, Error>), which also keeps usage and _meta.
    • SessionMessage::SessionMessage(Dispatch) is renamed to SessionMessage::Message(v1::Dispatch), with v1-typed request handles.
    • read_to_string returns the prompt's error.
    • New send_prompt_blocks.
  • F40: v1::SessionBlockState is sealed.
  • F29 (docs only): the v1::ActiveSession docs now say it has no cancel/mode/config/close/fork helpers and show how to send those messages through connection().
  • F22: the v1 on_proxy_session_start callback receives the full NewSessionResponse, and start_session_proxy returns it. Before, both gave only the SessionId.
  • F65: RestoreSessionBuilder is no longer exported. v1::LoadSessionBuilder / v1::ResumeSessionBuilder are the names, which matches v2::ResumeSessionBuilder.
  • F70 (docs only): the v1 load/resume builders document that they have no with_mcp_server and no proxy helpers, and point to the proxy builder's with_mcp_server. Adding them means threading a runner type parameter and proxy setup through the restore builders, which is not a small change. Adding a defaulted type parameter later is additive.
  • F07: v1 Builder::with_mcp_server (proxy-global) appends its declaration to the raw mcpServers array, using the same path as v2. Before, it re-serialized typed setup requests and dropped fields the schema types don't model. This one is non-breaking.

Updated md/migration-v5.md, rustdoc, the concepts pages, the cookbook and yopo.

New tests:

  • a prompt error reaches the stream and leaves the connection and other sessions working
  • the full PromptResponse arrives with _meta
  • v1 raw-append unit tests
  • an end-to-end conductor test (v1_chain_equivalence.rs): a v1 proxy built with with_mcp_server forwards session/new, and the agent receives the unmodeled fields together with the appended declaration. I checked that this test fails when the old typed re-serialization is put back.

Skipped

None.

Checks

These pass: fmt, both clippy runs, the cargo hack feature powerset at depth 2, workspace tests with all features, core tests with no default features, rustdoc -D warnings for core, and mdbook build.

Two known failures, neither caused by this PR:

  • agent-client-protocol-derive --lib aborts under the local kache runner. It does the same on main.
  • cargo doc -p agent-client-protocol-cookbook with -D warnings fails on unresolved agent_client_protocol::* links in lines this PR does not touch. It looks like the same failure happens on main; I did not confirm that.

🤖 Generated with Claude Code

benbrandt and others added 5 commits October 31, 2026 11:54
`Builder::with_mcp_server` on a v1 proxy parsed `session/new`,
`session/load`, `session/resume` and `session/fork` into the v1 schema
types and re-serialized them, so fields those types do not model (for
example `systemPrompt` without its schema feature, or future fields)
were dropped before the request reached the agent.

The v1 handler now validates the typed request and appends its
declaration to the raw `mcpServers` array, sharing the raw-append path
with the v2 handler.

Co-Authored-By: Claude <noreply@anthropic.com>
`v1::ActiveSession::send_prompt` returned the `session/prompt` result
through `?` inside the response callback, so an ordinary error response
closed the whole connection and every session on it, and the caller
never saw the error. The success path also kept only the stop reason.

- `SessionMessage::StopReason(StopReason)` is now
  `SessionMessage::PromptResponse(Result<PromptResponse, Error>)`, sent
  on the session stream for both outcomes. It keeps `usage` and `_meta`.
- `SessionMessage::SessionMessage(Dispatch)` is now
  `SessionMessage::Message(v1::Dispatch)` with v1-typed request handles.
- `read_to_string` returns the prompt's error.
- Add `send_prompt_blocks` for non-text prompts.
- Seal `v1::SessionBlockState`.
- Document that `v1::ActiveSession` has no cancel, mode, config, close
  or fork helpers and how to send those messages.

BREAKING CHANGE: `v1::SessionMessage` variants are renamed and reshaped:
`SessionMessage(Dispatch)` becomes `Message(v1::Dispatch)` (call
`.into_raw()` before `MatchDispatch::new`) and `StopReason(StopReason)`
becomes `PromptResponse(Result<PromptResponse, Error>)`.
`read_to_string` now returns prompt errors. `v1::SessionBlockState` is
sealed.

Co-Authored-By: Claude <noreply@anthropic.com>
…e builder exports

- `v1::SessionBuilder::on_proxy_session_start` passes a clone of the
  complete `NewSessionResponse` to its callback, and
  `start_session_proxy` returns it, instead of only the `SessionId`.
  The v2 equivalents already receive the full response.
- `RestoreSessionBuilder` is no longer exported. `v1::LoadSessionBuilder`
  and `v1::ResumeSessionBuilder` are the only names for it, matching
  `v2::ResumeSessionBuilder`.
- Document that the v1 load and resume builders have no
  `with_mcp_server` or proxy helpers, and point to the proxy builder's
  `with_mcp_server` instead.

BREAKING CHANGE: the `v1::SessionBuilder::on_proxy_session_start`
callback takes a `NewSessionResponse` instead of a `SessionId`, and
`start_session_proxy` returns `NewSessionResponse`. Read
`response.session_id` for the ID. `v1::RestoreSessionBuilder` is removed
from the public API; use `v1::LoadSessionBuilder` or
`v1::ResumeSessionBuilder`.

Co-Authored-By: Claude <noreply@anthropic.com>
…link

Run session/new through a conductor chain whose v1 proxy uses
with_mcp_server, and assert the agent receives unmodeled fields
together with the appended MCP declaration.

Co-Authored-By: Claude <noreply@anthropic.com>
systemPrompt is modeled as a struct when unstable features are on, so
the all-features build rejected the string value.

Co-Authored-By: Claude <noreply@anthropic.com>

This branch has not been deployed

No deployments
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