The core crate includes a small ACP v2 agent and client that run together over
stdio. Both require unstable_protocol_v2; the agent also requires stdio,
and the client requires process:
simple_agent_v2.rsimplements initialization and the complete baseline session lifecycle.v2_one_shot_client.rsinitializes the agent, creates a session, sends one prompt, renders text output, waits for the matching session to become idle, and closes it.
Build both examples from the repository root:
cargo build -p agent-client-protocol \
--features process,stdio,unstable_protocol_v2 \
--examplesThen point the client at the agent executable:
./target/debug/examples/v2_one_shot_client \
--command ./target/debug/examples/simple_agent_v2 \
"Hello from ACP v2"The result shows the two independent parts of a v2 prompt:
Prompt accepted; waiting for session output and completion...
Echo: Hello from ACP v2
Session is idle: Some(EndTurn)
The agent writes only JSON-RPC to stdout because ACP uses stdout as the wire. Write logs and diagnostics to stderr when extending it.
The client installs its session/update and session/request_permission
handlers before it opens a session. Permission requests are part of the
baseline client surface and have no capability marker; this non-interactive
example cancels them explicitly. It then follows this sequence:
- Send
initializeand verify that the agent advertised session support. - Send
session/newand retain the returned command handle and session ID. - Send
session/promptand await its response. This only confirms acceptance. - Ignore queued updates for that new session until its foreground state becomes
runningorrequires_action. Work may start blocked and end without ever running. The active update may already be queued when prompt acceptance arrives. - Project subsequent message updates, and treat the next matching
state_updatewithidleas completion of foreground work. An idle update queued before active work is only the session's earlier ready state. Background updates may still arrive afterward. - Send
session/closewhen the client no longer needs the active session.
Real clients normally maintain one shared update projection for every session.
Do not install a temporary handler after sending a prompt: updates can arrive
before the prompt response and are not scoped to a prompt or turn ID.
Within that projection, message chunks append by messageId; a later message
snapshot with concrete content replaces the accumulated chunks, null clears
them, and omitted content preserves them. Rendering chunks and then rendering a
snapshot again would duplicate output. An empty content array is also a
replacement. Identical chunks append again; chunk updates are not automatically
idempotent. The example renders messages in first-seen order, even when the
first update for a message only carries metadata.
Run just test from the repository root to execute the example's unit tests
alongside the workspace suite. They cover interleaved message IDs, metadata-only
updates, content replacement and clearing, and repeated chunks.
Advertising AgentCapabilities::session(SessionCapabilities::new()) commits an
agent to the baseline session surface. The example handles:
session/newsession/listsession/resumesession/closesession/promptsession/cancelsession/updatenotifications sent to the client
The prompt handler validates and marks the session busy, responds to
session/prompt immediately, and moves the actual work into a spawned task so
the connection can continue dispatching cancellation and other traffic. That
task sends the accepted user message, a running update, output, and finally an
idle update with a stop reason.
The example keeps history in memory and supports replay from the start. Every successful resume sends a current idle-state snapshot after any replay and before the response, even without replay. A production agent should replace this with durable session storage, synchronize its actual foreground state, define its supported replay cursors, and make resource cleanup and cancellation robust across process failure.
For the connection APIs, proxy routing, and compatibility details surrounding these examples, continue with Protocol V2.