返回 DeepSeek-Reasonix
ACP.md
根目录 / docs / ACP.md
1 # ACP editor integration
2
3 <a href="../README.md">README</a>
4 &nbsp;·&nbsp;
5 <a href="./ACP.zh-CN.md">简体中文</a>
6 &nbsp;·&nbsp;
7 <a href="./GUIDE.md">Guide</a>
8 &nbsp;·&nbsp;
9 <a href="https://agentclientprotocol.com/">ACP specification</a>
10
11 Reasonix implements Agent Client Protocol (ACP) v1 as an NDJSON JSON-RPC 2.0
12 agent over standard input and output. Editors and other ACP hosts launch the
13 process, open one or more workspace-scoped sessions, and receive streamed
14 messages, tool activity, plans, permission requests, and configuration updates.
15
16 Session status usage objects may include structured `costQuote` (original
17 currency, `originalTotals`, identity/official-table valuations,
18 `costComplete`, `displayComplete`, `displayStatus`, and `billingMode`) alongside legacy
19 `estimatedCost` / `currency` aliases that mirror the selected display valuation.
20 See [Billing](./BILLING.md).
21
22 ## Start the agent
23
24 An ACP host should launch one of these commands:
25
26 ```sh
27 reasonix acp
28 reasonix acp --model deepseek-pro
29 reasonix acp
30 ```
31
32 `--model` selects the startup model when the client does not override it.
33 Ordinary requests always enter the executor. There is no automatic simple /
34 light / full task mode. Verification obligations come from real tool actions.
35
36 Standard output is reserved for ACP messages. Reasonix sends diagnostics to
37 standard error, so hosts must not merge the two streams. Run `reasonix setup`
38 beforehand when no provider is configured; the initialize response also
39 advertises a terminal authentication method that launches `reasonix setup`.
40
41 ## Initialize and negotiate capabilities
42
43 Clients should call `initialize` before opening a session. Reasonix advertises
44 the following capability shape (irrelevant fields omitted):
45
46 ```json
47 {
48 "protocolVersion": 1,
49 "agentCapabilities": {
50 "loadSession": true,
51 "sessionCapabilities": {
52 "list": {},
53 "resume": {},
54 "close": {},
55 "delete": {}
56 },
57 "promptCapabilities": {
58 "image": false,
59 "audio": false,
60 "embeddedContext": true
61 },
62 "mcpCapabilities": {
63 "http": true,
64 "sse": false
65 },
66 "_meta": {
67 "reasonix.io": {
68 "sessionSteer": {
69 "method": "_reasonix.io/session/steer"
70 }
71 }
72 }
73 }
74 }
75 ```
76
77 When the client advertises `fs.readTextFile`, `fs.writeTextFile`, or
78 `terminal`, Reasonix routes eligible file operations through the editor's
79 unsaved buffers and eligible foreground commands through a client-owned
80 terminal. Every file tool takes part — reads, edits and writes alike — so an
81 edit applies to what the editor currently shows instead of to the last saved
82 copy on disk. A non-UTF-8 file is not eligible: the ACP file methods are
83 text-only, so it stays on the local encoding-preserving path and keeps its
84 original charset. Without those client capabilities, the normal workspace
85 tools run locally inside the Reasonix process.
86
87 ## Opt-in MCP interaction extension
88
89 Hosts supporting MCP elicitation advertise this in `initialize.clientCapabilities`:
90
91 ```json
92 {"_meta":{"reasonix.io":{"mcpInteraction":{"supported":true,"schemaVersion":1}}}}
93 ```
94
95 Reasonix advertises the matching capability under
96 `agentCapabilities._meta.reasonix.io.mcpInteraction`, including the method
97 `_reasonix.io/mcp/request_interaction`. Negotiated sessions use the interactive
98 MCP host profile. Clients without this exact opt-in keep the core profile and
99 receive no new reverse requests. This applies to new, loaded and rebuilt sessions.
100
101 The reverse request contains `sessionId`, `promptId`, `turnId`, `server`, `mode`
102 and `message`, plus `requestedSchema` for a form or `url` and `elicitationId` for
103 URL mode. Respond with `{"action":"accept","content":{}}`,
104 `{"action":"decline"}` or `{"action":"cancel"}`. Validate the requested form;
105 URL flows require user interaction and must not send credentials as form content.
106 Hosts that cannot render a requested interaction should cancel it.
107
108 Replies belong to the originating controller and turn. Cancellation, malformed
109 replies and rejected URLs cancel the interaction; content is ignored unless the
110 action is `accept`. Reasonix persists the decision through the controller before
111 releasing its MCP waiter. This does not replace standard
112 `session/request_permission` or change tool permission policy. The negotiated
113 host profile affects MCP capability/cache identity; transcript schema is unchanged.
114
115 ## Session lifecycle
116
117 Each ACP session owns an independent Reasonix controller, workspace root, model,
118 collaboration mode, approval mode, MCP set, and persisted transcript. State does
119 not leak between sessions.
120
121 | Method | Behavior |
122 | --- | --- |
123 | `session/new` | Opens a session for an absolute `cwd` and returns its configuration state. |
124 | `session/load` | Opens a persisted ACP session and replays its transcript as `session/update` notifications. |
125 | `session/resume` | Opens a persisted session without replaying the transcript. |
126 | `session/prompt` | Runs one turn and streams updates until it returns a stop reason. |
127 | `session/cancel` | Cancels the active turn; this is a notification. |
128 | `session/list` | Lists live and persisted ACP sessions, optionally filtered by absolute `cwd`. |
129 | `session/close` | Stops a live session and releases resources without deleting history. |
130 | `session/delete` | Stops the session and removes its persisted ACP history. |
131
132 `session/new`, `session/load`, and `session/resume` may include `mcpServers`.
133 Reasonix accepts stdio, Streamable HTTP, and legacy SSE servers. ACP's official `[{"name":"...","value":"..."}]`
134 shape is supported for stdio `env` and HTTP `headers`; the older object-map
135 shape remains accepted for compatibility.
136
137 ## Session controls
138
139 Reasonix exposes independent controls instead of combining unrelated choices in
140 one mode selector:
141
142 | Control | Values | Wire surface |
143 | --- | --- | --- |
144 | Collaboration mode | `normal`, `plan`, `goal` | `modes` and `session/set_mode` |
145 | Model | Configured `provider/model` entries | `configOptions` with id `model` |
146 | Reasoning effort | Provider-supported levels or `auto` | `configOptions` with id `effort` |
147 | Permission preset | `read-only`, `workspace-write`, `danger-full-access` | `configOptions` with id `tool_approval` |
148
149 Use `session/set_config_option` for model, effort, and tool approval.
150 Its parameters are `sessionId`, `configId` and `value`, where `configId` is the
151 `id` of the option as advertised in `configOptions`:
152
153 ```json
154 {
155 "jsonrpc": "2.0",
156 "id": 3,
157 "method": "session/set_config_option",
158 "params": {
159 "sessionId": "session-id",
160 "configId": "tool_approval",
161 "value": "danger-full-access"
162 }
163 }
164 ```
165
166 Note that the field is `configId`, not `optionId`. The result is the full
167 refreshed `configOptions` array. An unknown id returns `-32602 InvalidParams`.
168
169 Model and effort changes rebuild the session controller while preserving its
170 history and the other axes. Tool-approval changes update the gate in place
171 without rebuilding the controller.
172
173 Execution modes are gone. For one compatibility version, clients that still
174 send `session/set_config_option` with `configId` `agent_preset` or `work_mode`
175 (including legacy aliases `profile`, `runtime_profile`, `token_mode`) receive a
176 successful no-op: nothing switches, nothing rebuilds, and the result carries a
177 `deprecatedNotice` explaining the adaptive standard execution.
178 The returned `configOptions` list does not advertise these retired selectors or
179 `quality_floor`. A known legacy `quality_floor` value is accepted as the same
180 no-op, while unknown values still return `InvalidParams`.
181
182 For older clients, `session/set_model` remains available. The legacy
183 `session/set_mode` values `default` and `auto` are also accepted as Normal +
184 Read only and Normal + Workspace access respectively; new clients should use
185 the independent selectors above. Legacy permission values are accepted only as
186 input migration aliases and are never advertised in `configOptions`.
187
188 ## Prompts, updates, and approvals
189
190 `session/prompt` accepts text blocks and embedded text resources. Images and
191 audio are not advertised. During a turn, Reasonix may send:
192
193 - agent message and thought chunks;
194 - pending and completed tool-call updates;
195 - complete plan updates derived from `todo_write`;
196 - available slash commands;
197 - current-mode and configuration-option updates; and
198 - `session/request_permission` requests for permission-gated tools and user
199 questions.
200
201 Hosts should keep the `session/prompt` request open until Reasonix returns its
202 stop reason, while continuing to process requests and notifications in both
203 directions.
204
205 Reasonix emits only ACP v1 stop reasons. Model completion ends the ordinary
206 turn without a host readiness check or recovery action. An explicit model-round limit (`max_steps`) sends a `[warning]`, returns
207 `max_turn_requests`, and records a paused vendor outcome. A host task-time,
208 token, or cost budget also sends a `[warning]` and records a paused outcome,
209 but returns `end_turn` because ACP v1 has no task-budget-specific stop reason.
210 The completion validator has been removed. A clean model stop without tool
211 calls returns `end_turn`; a response with tool calls continues through the
212 agent loop, and a truly empty response is retried at the frozen-request
213 boundary. Legacy `completion_validation`, `completion_evaluator_model`, and
214 `REASONIX_COMPLETION_VALIDATION_MODE` settings remain readable but are ignored
215 and are no longer emitted. Host-owned readiness, budget, tool-safety, and
216 recovery boundaries remain active.
217 Client cancellation returns `cancelled`, even when the interrupted runner exits
218 without an error. Other provider, tool, or runtime failures return a JSON-RPC
219 `-32603 InternalError` whose message contains a bounded, credential-redacted
220 cause; they do not return a successful prompt result with a non-standard
221 `stopReason`.
222
223 When the status phase is `readiness_paused`, resume that exact check with a
224 `session/prompt` request whose optional `action` is
225 `"final_readiness_recovery"`. Sending `/continue-checks` as the sole text block
226 is the compatibility form. Both forms consume a one-shot, persisted host
227 checkpoint; ordinary prompt text never inherits it, and a stale action after a
228 newer user turn is rejected as JSON-RPC `-32600 InvalidRequest` without
229 publishing or persisting a synthetic status turn.
230
231 ## Mid-turn steering extension
232
233 Reasonix exposes mid-turn guidance as an ACP v1 vendor extension. It is not a
234 core ACP method, and it is not the still-unreleased ACP v2 `session/inject`
235 proposal.
236
237 ### Discover support
238
239 Read the method name from:
240
241 ```text
242 agentCapabilities._meta["reasonix.io"].sessionSteer.method
243 ```
244
245 Do not assume the extension exists, and do not call the unnamespaced
246 `session/steer` name. ACP reserves non-underscore method names for the core
247 protocol.
248
249 ### Send guidance
250
251 Call the advertised method while `session/prompt` is active:
252
253 ```json
254 {
255 "jsonrpc": "2.0",
256 "id": 2,
257 "method": "_reasonix.io/session/steer",
258 "params": {
259 "sessionId": "session-id",
260 "prompt": [
261 {"type": "text", "text": "use email instead of username"}
262 ]
263 }
264 }
265 ```
266
267 A persistent session returns an item id and disposition:
268
269 ```json
270 {"itemId":"inbox-item-id","disposition":"steer_accepted"}
271 ```
272
273 Reasonix durably commits the guidance before returning. `steer_accepted` means
274 the active turn accepted it; `queued_followup` means that admission lost a race
275 or no turn was active, so the same item remains queued for a later turn. A
276 pathless compatibility session may omit `itemId` and still returns
277 `steer_accepted`. Applied guidance is persisted in normal history; transcript
278 replay shows the original user text, not Reasonix's internal steer marker.
279
280 | Condition | JSON-RPC result |
281 | --- | --- |
282 | Active prompt accepted durable guidance | `{"itemId":"...","disposition":"steer_accepted"}` |
283 | Guidance persisted but active admission was rejected | `{"itemId":"...","disposition":"queued_followup"}` |
284 | Unknown session or empty prompt | `-32602 InvalidParams` |
285 | Pathless compatibility session has no active prompt | `-32600 InvalidRequest` |
286 | Client calls `session/steer` | `-32601 MethodNotFound` |
287
288 On `InvalidRequest`, the compatibility session did not queue the guidance.
289
290 ## Durable session inbox extension
291
292 Discover the versioned queue at
293 `agentCapabilities._meta["reasonix.io"].sessionInbox`. Schema version 1
294 advertises method names in its `methods` map; clients must use those advertised
295 names rather than constructing vendor method strings.
296
297 | Key | Purpose | Main parameters |
298 | --- | --- | --- |
299 | `enqueue` | Persist a follow-up or steer | `sessionId`, `text`, optional `intent`, `idempotencyKey` |
300 | `list` | Read metadata, capacity, pause and recovery state | `sessionId` |
301 | `get` | Read one full envelope on demand | `sessionId`, `itemId` |
302 | `update` / `delete` | Edit or delete pending work | `sessionId`, `itemId` |
303 | `move` | Reorder pending work | `sessionId`, `itemId`, zero-based `toIndex` |
304 | `setPaused` | Pause or resume dispatch | `sessionId`, `paused` |
305 | `retry` / `refresh` | Retry uncertain work or re-freeze references | `sessionId`, `itemId` |
306
307 `enqueue` returns `itemId`, `disposition`, `position`, `paused`, and
308 `idempotent`. List responses contain previews and byte counts, never prompt
309 bodies. A recovered inbox is paused; clients should let users inspect it before
310 calling `setPaused` with `false`.
311
312 ## Runtime reload and extension surface
313
314 Reasonix advertises two more extension points in
315 `agentCapabilities._meta["reasonix.io"]`:
316
317 - `sessionReloadExtensions` — the vendor method
318 `_reasonix.io/session/reloadExtensions`. Calling it reloads the session's
319 agent runtime (extensions, tools, skills, commands, hooks, providers) with
320 the same fail-atomic semantics as the CLI `/reload` command: while a turn
321 or rebuild is active exactly one reload is queued (`{"queued": true}`) and
322 runs when the session goes idle; otherwise the runtime is rebuilt and
323 swapped atomically, and a failed rebuild keeps the previous runtime. After
324 a successful reload Reasonix pushes a fresh `available_commands_update`.
325 - `extensionSurface` — structured extension UI support. Clients that also
326 advertise `reasonix.io.extensionSurface` in their initialize `_meta`
327 receive structured extension surface payloads; clients without it receive
328 equivalent text fallbacks (`agent_message_chunk` for cards and statuses,
329 permission requests for extension forms), so no client-side handling is
330 required to stay compatible.
331
332 Extension actions declared by installed plugins are exposed as
333 `/<plugin>:<action>` in `available_commands_update` and can be invoked like
334 any other slash command.
335
336 ## Compatibility and cache behavior
337
338 | Surface | Older or non-Reasonix clients | Conclusion |
339 | --- | --- | --- |
340 | Existing ACP v1 methods | Their names and response shapes are unchanged. | Compatible |
341 | Capability `_meta` | Unknown metadata may be ignored. | Compatible |
342 | Persisted transcripts | Transcript schema is unchanged; the inbox is a versioned sidecar. | Compatible |
343 | CLI, Desktop, and Bot steering | Rejected steers remain durable follow-ups. | Compatible |
344
345 Steering appends a user-requested message to normal conversation history. It
346 does not change the system prompt, tool schemas, tool order, or other stable
347 provider-prefix bytes. The next provider request necessarily misses the suffix
348 that did not previously exist, just like any normal new user message, while the
349 earlier prefix remains reusable.
350
351 ## Client integration checklist
352
353 1. Launch `reasonix acp` with separate stdin, stdout, and stderr streams.
354 2. Call `initialize` and honor both standard and `_meta` capabilities.
355 3. Open sessions with absolute workspace paths and keep their ids isolated.
356 4. Process agent-to-client filesystem, terminal, and permission requests while
357 a prompt is running.
358 5. Show steer UI only when the Reasonix capability is advertised and a prompt
359 is active.
360 6. Branch on the steer `disposition`; both accepted steer and queued follow-up
361 are durable, but only the former can affect the active turn.
362 7. Use `session/close` for resource cleanup and `session/delete` only when the
363 user intends to remove persisted history.
364
364 lines MARKDOWN