Expand description
AcpController: manages agent CLIs that speak the Agent Client Protocol (ACP).
ACP is a JSON-RPC 2.0 protocol over stdin/stdout — the “LSP for AI agents.” Instead of custom per-provider output parsing, ACP provides a standardized protocol for session management, prompting, and streaming events.
Lifecycle:
- Spawn the ACP agent process (e.g.,
gemini --acp,openclaw acp) - Send
initializerequest, receive capabilities - Send
initializednotification - Create a session via
session/create - For each user turn: send
session/prompt, streamsession/updatenotifications - On close: send
shutdown+exit
I/O model (similar to PersistentSubprocessController):
- stdin_writer: sends JSON-RPC requests/notifications to agent
- stdout_reader: reads JSON-RPC responses/notifications, persists + broadcasts
- process_waiter: monitors process lifecycle
See: https://github.com/agentclientprotocol/agent-client-protocol
Structs§
- AcpController
- AcpController manages an ACP-speaking agent process.
- AcpInner 🔒
- Inner state protected by mutex.
Constants§
- ACP_
OUTPUT_ SUBJECT - MPS file subject name for ACP output.
- BLOCK_
CONTROLLER_ ACP - TURN_
ENDED_ 🔒BY_ ERROR - Written to the output after an error that ended the turn (no prompt left
running, or the session couldn’t open). The translator ends a turn on a
stopReason; it can’t tell from an error alone, which may answer only a mid-turn steering prompt while the first one still runs.
Functions§
- initialize_
params 🔒 initialize: the protocol version and what this client can do. AgentMux offers no file system or terminal to the agent; it runs its own tools.- is_
session_ 🔒replay - Whether a line from the agent is part of a
session/loadreplay: the agent streams the earlier conversation assession/updates before it answers the load, and the load’s own answer is not one of them. - meta_
string_ 🔒list - A meta value that is a string array, or a JSON string encoding one.
- prompt_
params 🔒 session/promptparams: the prompt is an array of content blocks.- reply_
to_ 🔒agent_ request - The reply to a request the agent sends us, if
jsonis one (it has bothmethodandid). AgentMux approves tool use by default, as it does for every harness: the firstallow_alwaysoption, elseallow_once, else cancelled. Anything else (fs/*,terminal/*, which this client does not offer) gets “method not found”, so the agent never waits on us. - resolve_
prompt_ 🔒and_ check_ idle - Remove
resolved_idfrom the set of outstanding (sent, not yet resolved) prompts and report whether the set is now EMPTY — i.e. whether every prompt sent so far has now been resolved, by either a realstopReasoncompletion or a JSON-RPCerrorrejection, meaning the turn has genuinely ended. Extracted as a pure function over a plainHashSetso this exact logic is directly unit-testable; call sites wrap it with the shared mutex around the realoutstanding_prompt_ids. - session_
cwd 🔒 - The absolute directory ACP’s
session/newandsession/loadtake ascwd: the pane’s working directory (~expanded; a relative one resolved against the server’s, asCommand::current_dirresolves it), else the directory the agent process itself starts in. - session_
request 🔒 session/new, orsession/loadofresumewhen the agent can load one.