agent_client_protocol_schema/client.rs
1//! Methods and notifications the client handles/receives.
2//!
3//! This module defines the Client trait and all associated types for implementing
4//! a client that interacts with AI coding agents via the Agent Client Protocol (ACP).
5
6use std::{path::PathBuf, sync::Arc};
7
8use derive_more::{Display, From};
9use schemars::JsonSchema;
10use serde::{Deserialize, Serialize};
11use serde_json::value::RawValue;
12
13use crate::{
14 ContentBlock, ExtNotification, Plan, SessionId, SessionModeId, ToolCall, ToolCallUpdate,
15 ext::ExtRequest,
16};
17
18// Session updates
19
20/// Notification containing a session update from the agent.
21///
22/// Used to stream real-time progress and results during prompt processing.
23///
24/// See protocol docs: [Agent Reports Output](https://agentclientprotocol.com/protocol/prompt-turn#3-agent-reports-output)
25#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq)]
26#[schemars(extend("x-side" = "client", "x-method" = SESSION_UPDATE_NOTIFICATION))]
27#[serde(rename_all = "camelCase")]
28pub struct SessionNotification {
29 /// The ID of the session this update pertains to.
30 pub session_id: SessionId,
31 /// The actual update content.
32 pub update: SessionUpdate,
33 /// Extension point for implementations
34 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
35 pub meta: Option<serde_json::Value>,
36}
37
38/// Different types of updates that can be sent during session processing.
39///
40/// These updates provide real-time feedback about the agent's progress.
41///
42/// See protocol docs: [Agent Reports Output](https://agentclientprotocol.com/protocol/prompt-turn#3-agent-reports-output)
43#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq)]
44#[serde(tag = "sessionUpdate", rename_all = "snake_case")]
45#[schemars(extend("discriminator" = {"propertyName": "sessionUpdate"}))]
46pub enum SessionUpdate {
47 /// A chunk of the user's message being streamed.
48 UserMessageChunk(ContentChunk),
49 /// A chunk of the agent's response being streamed.
50 AgentMessageChunk(ContentChunk),
51 /// A chunk of the agent's internal reasoning being streamed.
52 AgentThoughtChunk(ContentChunk),
53 /// Notification that a new tool call has been initiated.
54 ToolCall(ToolCall),
55 /// Update on the status or results of a tool call.
56 ToolCallUpdate(ToolCallUpdate),
57 /// The agent's execution plan for complex tasks.
58 /// See protocol docs: [Agent Plan](https://agentclientprotocol.com/protocol/agent-plan)
59 Plan(Plan),
60 /// Available commands are ready or have changed
61 AvailableCommandsUpdate(AvailableCommandsUpdate),
62 /// The current mode of the session has changed
63 ///
64 /// See protocol docs: [Session Modes](https://agentclientprotocol.com/protocol/session-modes)
65 CurrentModeUpdate(CurrentModeUpdate),
66}
67
68/// The current mode of the session has changed
69///
70/// See protocol docs: [Session Modes](https://agentclientprotocol.com/protocol/session-modes)
71#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
72#[serde(rename_all = "camelCase")]
73#[schemars(inline)]
74pub struct CurrentModeUpdate {
75 /// The ID of the current mode
76 pub current_mode_id: SessionModeId,
77 /// Extension point for implementations
78 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
79 pub meta: Option<serde_json::Value>,
80}
81
82/// A streamed item of content
83#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq)]
84#[serde(rename_all = "camelCase")]
85#[schemars(inline)]
86pub struct ContentChunk {
87 /// A single item of content
88 pub content: ContentBlock,
89 /// Extension point for implementations
90 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
91 pub meta: Option<serde_json::Value>,
92}
93
94/// Available commands are ready or have changed
95#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
96#[serde(rename_all = "camelCase")]
97#[schemars(inline)]
98pub struct AvailableCommandsUpdate {
99 /// Commands the agent can execute
100 pub available_commands: Vec<AvailableCommand>,
101 /// Extension point for implementations
102 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
103 pub meta: Option<serde_json::Value>,
104}
105
106/// Information about a command.
107#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
108#[serde(rename_all = "camelCase")]
109pub struct AvailableCommand {
110 /// Command name (e.g., `create_plan`, `research_codebase`).
111 pub name: String,
112 /// Human-readable description of what the command does.
113 pub description: String,
114 /// Input for the command if required
115 pub input: Option<AvailableCommandInput>,
116 /// Extension point for implementations
117 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
118 pub meta: Option<serde_json::Value>,
119}
120
121/// The input specification for a command.
122#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
123#[serde(untagged, rename_all = "camelCase")]
124pub enum AvailableCommandInput {
125 /// All text that was typed after the command name is provided as input.
126 #[schemars(rename = "UnstructuredCommandInput")]
127 Unstructured {
128 /// A hint to display when the input hasn't been provided yet
129 hint: String,
130 },
131}
132
133// Permission
134
135/// Request for user permission to execute a tool call.
136///
137/// Sent when the agent needs authorization before performing a sensitive operation.
138///
139/// See protocol docs: [Requesting Permission](https://agentclientprotocol.com/protocol/tool-calls#requesting-permission)
140#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq)]
141#[schemars(extend("x-side" = "client", "x-method" = SESSION_REQUEST_PERMISSION_METHOD_NAME))]
142#[serde(rename_all = "camelCase")]
143pub struct RequestPermissionRequest {
144 /// The session ID for this request.
145 pub session_id: SessionId,
146 /// Details about the tool call requiring permission.
147 pub tool_call: ToolCallUpdate,
148 /// Available permission options for the user to choose from.
149 pub options: Vec<PermissionOption>,
150 /// Extension point for implementations
151 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
152 pub meta: Option<serde_json::Value>,
153}
154
155/// An option presented to the user when requesting permission.
156#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
157pub struct PermissionOption {
158 /// Unique identifier for this permission option.
159 #[serde(rename = "optionId")]
160 pub id: PermissionOptionId,
161 /// Human-readable label to display to the user.
162 pub name: String,
163 /// Hint about the nature of this permission option.
164 pub kind: PermissionOptionKind,
165 /// Extension point for implementations
166 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
167 pub meta: Option<serde_json::Value>,
168}
169
170/// Unique identifier for a permission option.
171#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq, Hash, Display, From)]
172#[serde(transparent)]
173#[from(Arc<str>, String, &'static str)]
174pub struct PermissionOptionId(pub Arc<str>);
175
176/// The type of permission option being presented to the user.
177///
178/// Helps clients choose appropriate icons and UI treatment.
179#[derive(Debug, Clone, Copy, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
180#[serde(rename_all = "snake_case")]
181pub enum PermissionOptionKind {
182 /// Allow this operation only this time.
183 AllowOnce,
184 /// Allow this operation and remember the choice.
185 AllowAlways,
186 /// Reject this operation only this time.
187 RejectOnce,
188 /// Reject this operation and remember the choice.
189 RejectAlways,
190}
191
192/// Response to a permission request.
193#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
194#[schemars(extend("x-side" = "client", "x-method" = SESSION_REQUEST_PERMISSION_METHOD_NAME))]
195#[serde(rename_all = "camelCase")]
196pub struct RequestPermissionResponse {
197 /// The user's decision on the permission request.
198 // This extra-level is unfortunately needed because the output must be an object
199 pub outcome: RequestPermissionOutcome,
200 /// Extension point for implementations
201 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
202 pub meta: Option<serde_json::Value>,
203}
204
205/// The outcome of a permission request.
206#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
207#[serde(tag = "outcome", rename_all = "snake_case")]
208#[schemars(extend("discriminator" = {"propertyName": "outcome"}))]
209pub enum RequestPermissionOutcome {
210 /// The prompt turn was cancelled before the user responded.
211 ///
212 /// When a client sends a `session/cancel` notification to cancel an ongoing
213 /// prompt turn, it MUST respond to all pending `session/request_permission`
214 /// requests with this `Cancelled` outcome.
215 ///
216 /// See protocol docs: [Cancellation](https://agentclientprotocol.com/protocol/prompt-turn#cancellation)
217 Cancelled,
218 /// The user selected one of the provided options.
219 #[serde(rename_all = "camelCase")]
220 Selected {
221 /// The ID of the option the user selected.
222 option_id: PermissionOptionId,
223 },
224}
225
226// Write text file
227
228/// Request to write content to a text file.
229///
230/// Only available if the client supports the `fs.writeTextFile` capability.
231#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
232#[schemars(extend("x-side" = "client", "x-method" = FS_WRITE_TEXT_FILE_METHOD_NAME))]
233#[serde(rename_all = "camelCase")]
234pub struct WriteTextFileRequest {
235 /// The session ID for this request.
236 pub session_id: SessionId,
237 /// Absolute path to the file to write.
238 pub path: PathBuf,
239 /// The text content to write to the file.
240 pub content: String,
241 /// Extension point for implementations
242 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
243 pub meta: Option<serde_json::Value>,
244}
245
246/// Response to `fs/write_text_file`
247#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
248#[serde(rename_all = "camelCase")]
249#[schemars(extend("x-side" = "client", "x-method" = FS_WRITE_TEXT_FILE_METHOD_NAME))]
250#[serde(default)]
251pub struct WriteTextFileResponse {
252 /// Extension point for implementations
253 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
254 pub meta: Option<serde_json::Value>,
255}
256
257// Read text file
258
259/// Request to read content from a text file.
260///
261/// Only available if the client supports the `fs.readTextFile` capability.
262#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
263#[schemars(extend("x-side" = "client", "x-method" = FS_READ_TEXT_FILE_METHOD_NAME))]
264#[serde(rename_all = "camelCase")]
265pub struct ReadTextFileRequest {
266 /// The session ID for this request.
267 pub session_id: SessionId,
268 /// Absolute path to the file to read.
269 pub path: PathBuf,
270 /// Line number to start reading from (1-based).
271 #[serde(default, skip_serializing_if = "Option::is_none")]
272 pub line: Option<u32>,
273 /// Maximum number of lines to read.
274 #[serde(default, skip_serializing_if = "Option::is_none")]
275 pub limit: Option<u32>,
276 /// Extension point for implementations
277 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
278 pub meta: Option<serde_json::Value>,
279}
280
281/// Response containing the contents of a text file.
282#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
283#[schemars(extend("x-side" = "client", "x-method" = FS_READ_TEXT_FILE_METHOD_NAME))]
284#[serde(rename_all = "camelCase")]
285pub struct ReadTextFileResponse {
286 pub content: String,
287 /// Extension point for implementations
288 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
289 pub meta: Option<serde_json::Value>,
290}
291
292// Terminals
293
294#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq, Hash, Display, From)]
295#[serde(transparent)]
296#[from(Arc<str>, String, &'static str)]
297pub struct TerminalId(pub Arc<str>);
298
299/// Request to create a new terminal and execute a command.
300#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
301#[serde(rename_all = "camelCase")]
302#[schemars(extend("x-side" = "client", "x-method" = TERMINAL_CREATE_METHOD_NAME))]
303pub struct CreateTerminalRequest {
304 /// The session ID for this request.
305 pub session_id: SessionId,
306 /// The command to execute.
307 pub command: String,
308 /// Array of command arguments.
309 #[serde(default, skip_serializing_if = "Vec::is_empty")]
310 pub args: Vec<String>,
311 /// Environment variables for the command.
312 #[serde(default, skip_serializing_if = "Vec::is_empty")]
313 pub env: Vec<crate::EnvVariable>,
314 /// Working directory for the command (absolute path).
315 #[serde(default, skip_serializing_if = "Option::is_none")]
316 pub cwd: Option<PathBuf>,
317 /// Maximum number of output bytes to retain.
318 ///
319 /// When the limit is exceeded, the Client truncates from the beginning of the output
320 /// to stay within the limit.
321 ///
322 /// The Client MUST ensure truncation happens at a character boundary to maintain valid
323 /// string output, even if this means the retained output is slightly less than the
324 /// specified limit.
325 #[serde(default, skip_serializing_if = "Option::is_none")]
326 pub output_byte_limit: Option<u64>,
327 /// Extension point for implementations
328 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
329 pub meta: Option<serde_json::Value>,
330}
331
332/// Response containing the ID of the created terminal.
333#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
334#[serde(rename_all = "camelCase")]
335#[schemars(extend("x-side" = "client", "x-method" = TERMINAL_CREATE_METHOD_NAME))]
336pub struct CreateTerminalResponse {
337 /// The unique identifier for the created terminal.
338 pub terminal_id: TerminalId,
339 /// Extension point for implementations
340 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
341 pub meta: Option<serde_json::Value>,
342}
343
344/// Request to get the current output and status of a terminal.
345#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
346#[serde(rename_all = "camelCase")]
347#[schemars(extend("x-side" = "client", "x-method" = TERMINAL_OUTPUT_METHOD_NAME))]
348pub struct TerminalOutputRequest {
349 /// The session ID for this request.
350 pub session_id: SessionId,
351 /// The ID of the terminal to get output from.
352 pub terminal_id: TerminalId,
353 /// Extension point for implementations
354 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
355 pub meta: Option<serde_json::Value>,
356}
357
358/// Response containing the terminal output and exit status.
359#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
360#[serde(rename_all = "camelCase")]
361#[schemars(extend("x-side" = "client", "x-method" = TERMINAL_OUTPUT_METHOD_NAME))]
362pub struct TerminalOutputResponse {
363 /// The terminal output captured so far.
364 pub output: String,
365 /// Whether the output was truncated due to byte limits.
366 pub truncated: bool,
367 /// Exit status if the command has completed.
368 pub exit_status: Option<TerminalExitStatus>,
369 /// Extension point for implementations
370 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
371 pub meta: Option<serde_json::Value>,
372}
373
374/// Request to release a terminal and free its resources.
375#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
376#[serde(rename_all = "camelCase")]
377#[schemars(extend("x-side" = "client", "x-method" = TERMINAL_RELEASE_METHOD_NAME))]
378pub struct ReleaseTerminalRequest {
379 /// The session ID for this request.
380 pub session_id: SessionId,
381 /// The ID of the terminal to release.
382 pub terminal_id: TerminalId,
383 /// Extension point for implementations
384 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
385 pub meta: Option<serde_json::Value>,
386}
387
388/// Response to terminal/release method
389#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
390#[serde(rename_all = "camelCase")]
391#[schemars(extend("x-side" = "client", "x-method" = TERMINAL_RELEASE_METHOD_NAME))]
392pub struct ReleaseTerminalResponse {
393 /// Extension point for implementations
394 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
395 pub meta: Option<serde_json::Value>,
396}
397
398/// Request to kill a terminal command without releasing the terminal.
399#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
400#[serde(rename_all = "camelCase")]
401#[schemars(extend("x-side" = "client", "x-method" = TERMINAL_KILL_METHOD_NAME))]
402pub struct KillTerminalCommandRequest {
403 /// The session ID for this request.
404 pub session_id: SessionId,
405 /// The ID of the terminal to kill.
406 pub terminal_id: TerminalId,
407 /// Extension point for implementations
408 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
409 pub meta: Option<serde_json::Value>,
410}
411
412/// Response to terminal/kill command method
413#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
414#[serde(rename_all = "camelCase")]
415#[schemars(extend("x-side" = "client", "x-method" = TERMINAL_KILL_METHOD_NAME))]
416pub struct KillTerminalCommandResponse {
417 /// Extension point for implementations
418 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
419 pub meta: Option<serde_json::Value>,
420}
421
422/// Request to wait for a terminal command to exit.
423#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
424#[serde(rename_all = "camelCase")]
425#[schemars(extend("x-side" = "client", "x-method" = TERMINAL_WAIT_FOR_EXIT_METHOD_NAME))]
426pub struct WaitForTerminalExitRequest {
427 /// The session ID for this request.
428 pub session_id: SessionId,
429 /// The ID of the terminal to wait for.
430 pub terminal_id: TerminalId,
431 /// Extension point for implementations
432 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
433 pub meta: Option<serde_json::Value>,
434}
435
436/// Response containing the exit status of a terminal command.
437#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
438#[serde(rename_all = "camelCase")]
439#[schemars(extend("x-side" = "client", "x-method" = TERMINAL_WAIT_FOR_EXIT_METHOD_NAME))]
440pub struct WaitForTerminalExitResponse {
441 /// The exit status of the terminal command.
442 #[serde(flatten)]
443 pub exit_status: TerminalExitStatus,
444 /// Extension point for implementations
445 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
446 pub meta: Option<serde_json::Value>,
447}
448
449/// Exit status of a terminal command.
450#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
451#[serde(rename_all = "camelCase")]
452pub struct TerminalExitStatus {
453 /// The process exit code (may be null if terminated by signal).
454 pub exit_code: Option<u32>,
455 /// The signal that terminated the process (may be null if exited normally).
456 pub signal: Option<String>,
457 /// Extension point for implementations
458 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
459 pub meta: Option<serde_json::Value>,
460}
461
462// Capabilities
463
464/// Capabilities supported by the client.
465///
466/// Advertised during initialization to inform the agent about
467/// available features and methods.
468///
469/// See protocol docs: [Client Capabilities](https://agentclientprotocol.com/protocol/initialization#client-capabilities)
470#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
471#[serde(rename_all = "camelCase")]
472pub struct ClientCapabilities {
473 /// File system capabilities supported by the client.
474 /// Determines which file operations the agent can request.
475 #[serde(default)]
476 pub fs: FileSystemCapability,
477 /// Whether the Client support all `terminal/*` methods.
478 #[serde(default)]
479 pub terminal: bool,
480 /// Extension point for implementations
481 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
482 pub meta: Option<serde_json::Value>,
483}
484
485/// File system capabilities that a client may support.
486///
487/// See protocol docs: [FileSystem](https://agentclientprotocol.com/protocol/initialization#filesystem)
488#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
489#[serde(rename_all = "camelCase")]
490pub struct FileSystemCapability {
491 /// Whether the Client supports `fs/read_text_file` requests.
492 #[serde(default)]
493 pub read_text_file: bool,
494 /// Whether the Client supports `fs/write_text_file` requests.
495 #[serde(default)]
496 pub write_text_file: bool,
497 /// Extension point for implementations
498 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
499 pub meta: Option<serde_json::Value>,
500}
501
502// Method schema
503
504/// Names of all methods that clients handle.
505///
506/// Provides a centralized definition of method names used in the protocol.
507#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
508pub struct ClientMethodNames {
509 /// Method for requesting permission from the user.
510 pub session_request_permission: &'static str,
511 /// Notification for session updates.
512 pub session_update: &'static str,
513 /// Method for writing text files.
514 pub fs_write_text_file: &'static str,
515 /// Method for reading text files.
516 pub fs_read_text_file: &'static str,
517 /// Method for creating new terminals.
518 pub terminal_create: &'static str,
519 /// Method for getting terminals output.
520 pub terminal_output: &'static str,
521 /// Method for releasing a terminal.
522 pub terminal_release: &'static str,
523 /// Method for waiting for a terminal to finish.
524 pub terminal_wait_for_exit: &'static str,
525 /// Method for killing a terminal.
526 pub terminal_kill: &'static str,
527}
528
529/// Constant containing all client method names.
530pub const CLIENT_METHOD_NAMES: ClientMethodNames = ClientMethodNames {
531 session_update: SESSION_UPDATE_NOTIFICATION,
532 session_request_permission: SESSION_REQUEST_PERMISSION_METHOD_NAME,
533 fs_write_text_file: FS_WRITE_TEXT_FILE_METHOD_NAME,
534 fs_read_text_file: FS_READ_TEXT_FILE_METHOD_NAME,
535 terminal_create: TERMINAL_CREATE_METHOD_NAME,
536 terminal_output: TERMINAL_OUTPUT_METHOD_NAME,
537 terminal_release: TERMINAL_RELEASE_METHOD_NAME,
538 terminal_wait_for_exit: TERMINAL_WAIT_FOR_EXIT_METHOD_NAME,
539 terminal_kill: TERMINAL_KILL_METHOD_NAME,
540};
541
542/// Notification name for session updates.
543pub(crate) const SESSION_UPDATE_NOTIFICATION: &str = "session/update";
544/// Method name for requesting user permission.
545pub(crate) const SESSION_REQUEST_PERMISSION_METHOD_NAME: &str = "session/request_permission";
546/// Method name for writing text files.
547pub(crate) const FS_WRITE_TEXT_FILE_METHOD_NAME: &str = "fs/write_text_file";
548/// Method name for reading text files.
549pub(crate) const FS_READ_TEXT_FILE_METHOD_NAME: &str = "fs/read_text_file";
550/// Method name for creating a new terminal.
551pub(crate) const TERMINAL_CREATE_METHOD_NAME: &str = "terminal/create";
552/// Method for getting terminals output.
553pub(crate) const TERMINAL_OUTPUT_METHOD_NAME: &str = "terminal/output";
554/// Method for releasing a terminal.
555pub(crate) const TERMINAL_RELEASE_METHOD_NAME: &str = "terminal/release";
556/// Method for waiting for a terminal to finish.
557pub(crate) const TERMINAL_WAIT_FOR_EXIT_METHOD_NAME: &str = "terminal/wait_for_exit";
558/// Method for killing a terminal.
559pub(crate) const TERMINAL_KILL_METHOD_NAME: &str = "terminal/kill";
560
561/// All possible requests that an agent can send to a client.
562///
563/// This enum is used internally for routing RPC requests. You typically won't need
564/// to use this directly - instead, use the methods on the [`Client`] trait.
565///
566/// This enum encompasses all method calls from agent to client.
567#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
568#[serde(untagged)]
569#[schemars(extend("x-docs-ignore" = true))]
570pub enum AgentRequest {
571 /// Writes content to a text file in the client's file system.
572 ///
573 /// Only available if the client advertises the `fs.writeTextFile` capability.
574 /// Allows the agent to create or modify files within the client's environment.
575 ///
576 /// See protocol docs: [Client](https://agentclientprotocol.com/protocol/overview#client)
577 WriteTextFileRequest(WriteTextFileRequest),
578 /// Reads content from a text file in the client's file system.
579 ///
580 /// Only available if the client advertises the `fs.readTextFile` capability.
581 /// Allows the agent to access file contents within the client's environment.
582 ///
583 /// See protocol docs: [Client](https://agentclientprotocol.com/protocol/overview#client)
584 ReadTextFileRequest(ReadTextFileRequest),
585 /// Requests permission from the user for a tool call operation.
586 ///
587 /// Called by the agent when it needs user authorization before executing
588 /// a potentially sensitive operation. The client should present the options
589 /// to the user and return their decision.
590 ///
591 /// If the client cancels the prompt turn via `session/cancel`, it MUST
592 /// respond to this request with `RequestPermissionOutcome::Cancelled`.
593 ///
594 /// See protocol docs: [Requesting Permission](https://agentclientprotocol.com/protocol/tool-calls#requesting-permission)
595 RequestPermissionRequest(RequestPermissionRequest),
596 /// Executes a command in a new terminal
597 ///
598 /// Only available if the `terminal` Client capability is set to `true`.
599 ///
600 /// Returns a `TerminalId` that can be used with other terminal methods
601 /// to get the current output, wait for exit, and kill the command.
602 ///
603 /// The `TerminalId` can also be used to embed the terminal in a tool call
604 /// by using the `ToolCallContent::Terminal` variant.
605 ///
606 /// The Agent is responsible for releasing the terminal by using the `terminal/release`
607 /// method.
608 ///
609 /// See protocol docs: [Terminals](https://agentclientprotocol.com/protocol/terminals)
610 CreateTerminalRequest(CreateTerminalRequest),
611 /// Gets the terminal output and exit status
612 ///
613 /// Returns the current content in the terminal without waiting for the command to exit.
614 /// If the command has already exited, the exit status is included.
615 ///
616 /// See protocol docs: [Terminals](https://agentclientprotocol.com/protocol/terminals)
617 TerminalOutputRequest(TerminalOutputRequest),
618 /// Releases a terminal
619 ///
620 /// The command is killed if it hasn't exited yet. Use `terminal/wait_for_exit`
621 /// to wait for the command to exit before releasing the terminal.
622 ///
623 /// After release, the `TerminalId` can no longer be used with other `terminal/*` methods,
624 /// but tool calls that already contain it, continue to display its output.
625 ///
626 /// The `terminal/kill` method can be used to terminate the command without releasing
627 /// the terminal, allowing the Agent to call `terminal/output` and other methods.
628 ///
629 /// See protocol docs: [Terminals](https://agentclientprotocol.com/protocol/terminals)
630 ReleaseTerminalRequest(ReleaseTerminalRequest),
631 /// Waits for the terminal command to exit and return its exit status
632 ///
633 /// See protocol docs: [Terminals](https://agentclientprotocol.com/protocol/terminals)
634 WaitForTerminalExitRequest(WaitForTerminalExitRequest),
635 /// Kills the terminal command without releasing the terminal
636 ///
637 /// While `terminal/release` will also kill the command, this method will keep
638 /// the `TerminalId` valid so it can be used with other methods.
639 ///
640 /// This method can be helpful when implementing command timeouts which terminate
641 /// the command as soon as elapsed, and then get the final output so it can be sent
642 /// to the model.
643 ///
644 /// Note: `terminal/release` when `TerminalId` is no longer needed.
645 ///
646 /// See protocol docs: [Terminals](https://agentclientprotocol.com/protocol/terminals)
647 KillTerminalCommandRequest(KillTerminalCommandRequest),
648 /// Handles extension method requests from the agent.
649 ///
650 /// Allows the Agent to send an arbitrary request that is not part of the ACP spec.
651 /// Extension methods provide a way to add custom functionality while maintaining
652 /// protocol compatibility.
653 ///
654 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
655 ExtMethodRequest(ExtRequest),
656}
657
658/// All possible responses that a client can send to an agent.
659///
660/// This enum is used internally for routing RPC responses. You typically won't need
661/// to use this directly - the responses are handled automatically by the connection.
662///
663/// These are responses to the corresponding `AgentRequest` variants.
664#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
665#[serde(untagged)]
666#[schemars(extend("x-docs-ignore" = true))]
667pub enum ClientResponse {
668 WriteTextFileResponse(#[serde(default)] WriteTextFileResponse),
669 ReadTextFileResponse(ReadTextFileResponse),
670 RequestPermissionResponse(RequestPermissionResponse),
671 CreateTerminalResponse(CreateTerminalResponse),
672 TerminalOutputResponse(TerminalOutputResponse),
673 ReleaseTerminalResponse(#[serde(default)] ReleaseTerminalResponse),
674 WaitForTerminalExitResponse(WaitForTerminalExitResponse),
675 KillTerminalResponse(#[serde(default)] KillTerminalCommandResponse),
676 ExtMethodResponse(#[schemars(with = "serde_json::Value")] Arc<RawValue>),
677}
678
679/// All possible notifications that an agent can send to a client.
680///
681/// This enum is used internally for routing RPC notifications. You typically won't need
682/// to use this directly - use the notification methods on the [`Client`] trait instead.
683///
684/// Notifications do not expect a response.
685#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
686#[serde(untagged)]
687#[allow(clippy::large_enum_variant)]
688#[schemars(extend("x-docs-ignore" = true))]
689pub enum AgentNotification {
690 /// Handles session update notifications from the agent.
691 ///
692 /// This is a notification endpoint (no response expected) that receives
693 /// real-time updates about session progress, including message chunks,
694 /// tool calls, and execution plans.
695 ///
696 /// Note: Clients SHOULD continue accepting tool call updates even after
697 /// sending a `session/cancel` notification, as the agent may send final
698 /// updates before responding with the cancelled stop reason.
699 ///
700 /// See protocol docs: [Agent Reports Output](https://agentclientprotocol.com/protocol/prompt-turn#3-agent-reports-output)
701 SessionNotification(SessionNotification),
702 /// Handles extension notifications from the agent.
703 ///
704 /// Allows the Agent to send an arbitrary notification that is not part of the ACP spec.
705 /// Extension notifications provide a way to send one-way messages for custom functionality
706 /// while maintaining protocol compatibility.
707 ///
708 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
709 ExtNotification(ExtNotification),
710}