Skip to content

Appendix C · ACP Message Fields Reference

Field-level lookup for every message Agentao's ACP server and client emit. For the end-to-end story (handshake → prompt → streaming → cancel) see Part 3. This appendix is the speed-lookup you open when you're in the middle of debugging a malformed message.

Conventions:

  • = request; = response; = server-to-client notification
  • All messages are JSON-RPC 2.0 over NDJSON on stdio
  • {…} = object; […] = array; T|U = union; ? = optional

C.1 initialize

Handshake. MUST be first call.

→ Request

FieldTypeReqNotes
protocolVersionintyesAgentao speaks 1. bool rejected explicitly.
clientCapabilitiesobjectyesClient-side feature flags (e.g. fs: {readFile, writeFile})
clientInfoobjectno{name, version, title} — purely informational

← Response

FieldTypeNotes
protocolVersionintNegotiated — usually echoes request; never errors on mismatch
agentCapabilitiesobjectSee below
authMethods[]Empty in v1 — Agentao does no ACP-level auth
agentInfoobject{name: "agentao", title: "Agentao", version}
_meta["_agentao.cn/extensions"][{method, description}]Vendor methods advertised under _meta (ACP's standard extension channel); includes _agentao.cn/ask_user

agentCapabilities block (v0.2.x)

FieldValueMeaning
loadSessiontruesession/load supported — see 7.2
promptCapabilities.imagefalsev1 baseline text-only
promptCapabilities.audiofalse
promptCapabilities.embeddedContextfalse
mcpCapabilities.ssetrueSSE MCP transport usable
mcpCapabilities.httpfalseHTTP MCP transport NOT supported

C.2 session/new

Create a fresh session.

→ Request

FieldTypeReqNotes
cwdstringyesAbsolute path, must exist and be a directory
mcpServers[object]yes ([] ok)Per-session MCP server configs

mcpServers[i] shape

FieldTypeNotes
namestringNon-empty
type"stdio" / "http" / "sse"http advertised by some clients but rejected by agent per mcpCapabilities
commandstringstdio only
args[string]stdio only
env[{name, value}]stdio only — note list of name/value objects, not a map
urlstringsse / http only
headers[{name, value}]sse / http only

← Response

FieldTypeNotes
sessionIdstringUUID. Keep it — needed for every subsequent call
configOptions[object]Model/provider selection options (configId: "model"); drive a switch via session/set_config_option. Empty list if the agent can't enumerate a catalog

Common failures

JSON-RPC codeCause
-32002Called before initialize (SERVER_NOT_INITIALIZED)
-32602cwd not absolute / doesn't exist / mcpServers malformed

Startup resume. When the server was launched with agentao --acp --resume [SESSION_ID], the first session/new resumes a persisted session instead of starting blank: it replays history as session/update notifications and returns the persisted sessionId. A miss (empty store / unknown id / corrupt file / id already active) silently degrades to a normal fresh session. See 3.2 → Resume a session on startup.

C.3 session/prompt

Run one user turn. Returns when the agent stops.

→ Request

FieldTypeReqNotes
sessionIdstringyesFrom session/new or session/load
prompt[ContentBlock]yesSee below

ContentBlock shape

FieldTypeNotes
type"text"Only text supported in v1 baseline
textstringThe user message

← Response

FieldTypeNotes
stopReasonstring"end_turn", "max_tokens", "cancelled", or other

C.4 session/update ⇠ notification

Server-to-client streaming updates during a prompt turn.

Params

FieldTypeNotes
sessionIdstringThe active session
updateobjectVariants keyed by sessionUpdate

Variants (update.sessionUpdate)

ValueAgentao eventExtra fields
user_message_chunk(replay)content: {type:"text", text}
agent_message_chunkLLM_TEXTcontent: {type:"text", text}
agent_thought_chunkTHINKING / ERRORcontent: {type:"text", text}
tool_callTOOL_STARTtoolCallId, title, kind, status:"pending", rawInput
tool_call_updateTOOL_OUTPUT / TOOL_COMPLETEtoolCallId, status, optional content[] append

tool_call.kind (closed enum)

read, edit, delete, move, search, execute, think, fetch, switch_mode, other. Agentao maps its tool names into this enum — see agentao/acp/transport.py.

tool_call_update.status

ValueWhen
in_progressStreaming output chunk
completedTool succeeded
failedTool raised / returned error

C.5 session/request_permission ⇠ notification

Server asks client to confirm a tool call.

Params

FieldTypeNotes
sessionIdstring
toolCallobjectSame shape as session/update.tool_call
options[{optionId, name, kind}]Typically ["allow", "allow_always", "reject"]

Expected response (client → server)

FieldTypeNotes
outcome.outcome"selected" or "cancelled"
outcome.optionIdstringRequired when selected

Cancellation rule: if the client never answers and the turn is cancelled, the agent resolves all pending permission requests with cancelled. See 7.2 pitfall.

C.6 session/cancel

Abort the current turn and all pending permission requests.

→ Request

FieldTypeNotes
sessionIdstring

← Response

Empty object {}. The ongoing session/prompt eventually resolves with stopReason: "cancelled".

C.7 session/load

Resume a session by id. Only usable when the agent advertises loadSession: true in its capabilities.

→ Request

FieldTypeNotes
sessionIdstringMust have been created earlier
cwdstringAbsolute path; must match the session's original cwd
mcpServers[object]Re-declare — fingerprint must match prior session/new

← Response

{configOptions: [...]} — the same model/provider selection options as session/new (empty list if no catalog). The agent also replays prior turns as session/update notifications (reconstructed from persisted history) before it's ready for the next session/prompt.

Fingerprint rule

mcpServers is hashed during session/new. If session/load passes a different set (added / removed / reordered), Agentao may either reject the call or silently re-init — depends on implementation phase. When in doubt, use the same list you originally passed.

C.8 session/set_config_option

Switch the model (and optionally the provider) via the ACP-standard config-option mechanism. Credentials never travel on the wire — the agent resolves them server-side from a host-injected provider_resolver (default: environment).

→ Request

FieldTypeReqNotes
sessionIdstringyesActive session
configIdstringyesMust be "model"; any other value → -32600 Invalid Request
valuestringyesprovider/model (e.g. openai/gpt-4o) or a bare model (keeps the current provider). Split on the first /; provider is lower-cased, model kept as-is

apiKey, baseUrl, _meta, and any other field are rejected (-32602; extra="forbid" + handler whitelist) — "credentials resolve server-side and never travel on the wire".

← Response

FieldTypeNotes
configOptions[object]Refreshed selection options (same shape as session/new), reflecting the new currentValue

Resolution & errors

  • provider/model: the agent calls provider_resolver(provider_id){api_key, base_url?}, then swaps provider + model. The default resolver accepts only the configured LLM_PROVIDER (case-insensitive) and reads {PREFIX}_API_KEY / {PREFIX}_BASE_URL; any other provider → -32600 cannot resolve provider '<id>'. Inject a richer resolver to support more providers.
  • bare model: model-only switch (provider unchanged) via the same path as _agentao.cn/set_model.
  • On resolver failure the server logs only the provider id + exception type, never the message (it could embed a key).

ConfigOption shape (entries in configOptions)

FieldTypeNotes
idstring"model"
namestring"Model"
category"mode" | "model" | "thought_level""model"
type"select"only select in v1
currentValuestring?provider/model of the live model
options[{value, name?, description?}]Catalog choices; value is provider/model. Default catalog = the single current env model; richer catalog host-injected

C.9 _agentao.cn/set_model (extension)

Agentao-specific free-form model switch — the vendor sibling of session/set_config_option's bare-value path. Secret-free; shares the same core code path.

→ Request

FieldTypeReqNotes
sessionIdstringyesActive session
modelstringyesAny model id the current provider accepts (stripped). Free-form — not validated against a catalog

apiKey, baseUrl, _meta are rejected (-32602).

← Response

FieldTypeNotes
modelstringThe active model id after the switch (agent.llm.model)

C.10 session/set_mode

Set the session's ACP modeId. The field is the ACP-standard modeId (not mode) and is an open string — a UI/behavioural selector that need not map to an Agentao permission preset.

→ Request

FieldTypeReqNotes
sessionIdstringyesActive session
modeIdstringyesNon-empty. On an exact match to a permission preset (read-only / workspace-write / full-access / plan) the agent applies it; any other value (e.g. code, ask) is persisted and echoed without changing permission posture

← Response

FieldTypeNotes
modeIdstringEchoes the persisted value

Notes

  • A recognized preset requires the session to have a PermissionEngine, else -32600 Invalid Request. Unknown modeIds need no engine — they are pure UI state.
  • Per-session: each session owns its own engine, so a preset change on session A never affects session B.

C.11 _agentao.cn/ask_user ⇠ notification (extension)

Agentao-specific. Server asks the user a free-form question.

Params

FieldTypeNotes
sessionIdstring
questionstringFree-form text

Expected response

FieldTypeNotes
answerstringFree-form user reply

If the user is unavailable, clients may return the sentinel "(user unavailable)" (constant ASK_USER_UNAVAILABLE_SENTINEL).

C.12 JSON-RPC error codes (quick reference)

CodeNameMeaning
-32700Parse errorInvalid JSON received by server
-32600Invalid RequestJSON is valid but not a JSON-RPC Request
-32601Method not foundThe method doesn't exist / isn't available
-32602Invalid paramsInvalid method parameter(s)
-32603Internal errorInternal JSON-RPC error
-32002Server not initializedSession method called before initialize

Map these to AcpErrorCode per Appendix D.2.


Appendix D · Error codes · Appendix E · Migration