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};
11
12use crate::{
13    ContentBlock, ExtNotification, ExtRequest, ExtResponse, IntoOption, Meta, Plan, SessionId,
14    SessionModeId, ToolCall, ToolCallUpdate,
15};
16
17// Session updates
18
19/// Notification containing a session update from the agent.
20///
21/// Used to stream real-time progress and results during prompt processing.
22///
23/// See protocol docs: [Agent Reports Output](https://agentclientprotocol.com/protocol/prompt-turn#3-agent-reports-output)
24#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq)]
25#[schemars(extend("x-side" = "client", "x-method" = SESSION_UPDATE_NOTIFICATION))]
26#[serde(rename_all = "camelCase")]
27#[non_exhaustive]
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    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
34    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
35    /// these keys.
36    ///
37    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
38    #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
39    pub meta: Option<Meta>,
40}
41
42impl SessionNotification {
43    #[must_use]
44    pub fn new(session_id: impl Into<SessionId>, update: SessionUpdate) -> Self {
45        Self {
46            session_id: session_id.into(),
47            update,
48            meta: None,
49        }
50    }
51
52    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
53    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
54    /// these keys.
55    ///
56    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
57    #[must_use]
58    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
59        self.meta = meta.into_option();
60        self
61    }
62}
63
64/// Different types of updates that can be sent during session processing.
65///
66/// These updates provide real-time feedback about the agent's progress.
67///
68/// See protocol docs: [Agent Reports Output](https://agentclientprotocol.com/protocol/prompt-turn#3-agent-reports-output)
69#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq)]
70#[serde(tag = "sessionUpdate", rename_all = "snake_case")]
71#[schemars(extend("discriminator" = {"propertyName": "sessionUpdate"}))]
72#[non_exhaustive]
73pub enum SessionUpdate {
74    /// A chunk of the user's message being streamed.
75    UserMessageChunk(ContentChunk),
76    /// A chunk of the agent's response being streamed.
77    AgentMessageChunk(ContentChunk),
78    /// A chunk of the agent's internal reasoning being streamed.
79    AgentThoughtChunk(ContentChunk),
80    /// Notification that a new tool call has been initiated.
81    ToolCall(ToolCall),
82    /// Update on the status or results of a tool call.
83    ToolCallUpdate(ToolCallUpdate),
84    /// The agent's execution plan for complex tasks.
85    /// See protocol docs: [Agent Plan](https://agentclientprotocol.com/protocol/agent-plan)
86    Plan(Plan),
87    /// Available commands are ready or have changed
88    AvailableCommandsUpdate(AvailableCommandsUpdate),
89    /// The current mode of the session has changed
90    ///
91    /// See protocol docs: [Session Modes](https://agentclientprotocol.com/protocol/session-modes)
92    CurrentModeUpdate(CurrentModeUpdate),
93}
94
95/// The current mode of the session has changed
96///
97/// See protocol docs: [Session Modes](https://agentclientprotocol.com/protocol/session-modes)
98#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
99#[serde(rename_all = "camelCase")]
100#[non_exhaustive]
101pub struct CurrentModeUpdate {
102    /// The ID of the current mode
103    pub current_mode_id: SessionModeId,
104    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
105    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
106    /// these keys.
107    ///
108    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
109    #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
110    pub meta: Option<Meta>,
111}
112
113impl CurrentModeUpdate {
114    #[must_use]
115    pub fn new(current_mode_id: impl Into<SessionModeId>) -> Self {
116        Self {
117            current_mode_id: current_mode_id.into(),
118            meta: None,
119        }
120    }
121
122    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
123    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
124    /// these keys.
125    ///
126    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
127    #[must_use]
128    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
129        self.meta = meta.into_option();
130        self
131    }
132}
133
134/// A streamed item of content
135#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq)]
136#[serde(rename_all = "camelCase")]
137#[non_exhaustive]
138pub struct ContentChunk {
139    /// A single item of content
140    pub content: ContentBlock,
141    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
142    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
143    /// these keys.
144    ///
145    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
146    #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
147    pub meta: Option<Meta>,
148}
149
150impl ContentChunk {
151    #[must_use]
152    pub fn new(content: ContentBlock) -> Self {
153        Self {
154            content,
155            meta: None,
156        }
157    }
158
159    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
160    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
161    /// these keys.
162    ///
163    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
164    #[must_use]
165    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
166        self.meta = meta.into_option();
167        self
168    }
169}
170
171/// Available commands are ready or have changed
172#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
173#[serde(rename_all = "camelCase")]
174#[non_exhaustive]
175pub struct AvailableCommandsUpdate {
176    /// Commands the agent can execute
177    pub available_commands: Vec<AvailableCommand>,
178    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
179    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
180    /// these keys.
181    ///
182    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
183    #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
184    pub meta: Option<Meta>,
185}
186
187impl AvailableCommandsUpdate {
188    #[must_use]
189    pub fn new(available_commands: Vec<AvailableCommand>) -> Self {
190        Self {
191            available_commands,
192            meta: None,
193        }
194    }
195
196    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
197    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
198    /// these keys.
199    ///
200    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
201    #[must_use]
202    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
203        self.meta = meta.into_option();
204        self
205    }
206}
207
208/// Information about a command.
209#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
210#[serde(rename_all = "camelCase")]
211#[non_exhaustive]
212pub struct AvailableCommand {
213    /// Command name (e.g., `create_plan`, `research_codebase`).
214    pub name: String,
215    /// Human-readable description of what the command does.
216    pub description: String,
217    /// Input for the command if required
218    pub input: Option<AvailableCommandInput>,
219    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
220    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
221    /// these keys.
222    ///
223    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
224    #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
225    pub meta: Option<Meta>,
226}
227
228impl AvailableCommand {
229    pub fn new(name: impl Into<String>, description: impl Into<String>) -> Self {
230        Self {
231            name: name.into(),
232            description: description.into(),
233            input: None,
234            meta: None,
235        }
236    }
237
238    /// Input for the command if required
239    #[must_use]
240    pub fn input(mut self, input: impl IntoOption<AvailableCommandInput>) -> Self {
241        self.input = input.into_option();
242        self
243    }
244
245    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
246    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
247    /// these keys.
248    ///
249    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
250    #[must_use]
251    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
252        self.meta = meta.into_option();
253        self
254    }
255}
256
257/// The input specification for a command.
258#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
259#[serde(untagged, rename_all = "camelCase")]
260#[non_exhaustive]
261pub enum AvailableCommandInput {
262    /// All text that was typed after the command name is provided as input.
263    Unstructured(UnstructuredCommandInput),
264}
265
266/// All text that was typed after the command name is provided as input.
267#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
268#[serde(rename_all = "camelCase")]
269#[non_exhaustive]
270pub struct UnstructuredCommandInput {
271    /// A hint to display when the input hasn't been provided yet
272    pub hint: String,
273    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
274    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
275    /// these keys.
276    ///
277    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
278    #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
279    pub meta: Option<Meta>,
280}
281
282impl UnstructuredCommandInput {
283    pub fn new(hint: impl Into<String>) -> Self {
284        Self {
285            hint: hint.into(),
286            meta: None,
287        }
288    }
289
290    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
291    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
292    /// these keys.
293    ///
294    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
295    #[must_use]
296    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
297        self.meta = meta.into_option();
298        self
299    }
300}
301
302// Permission
303
304/// Request for user permission to execute a tool call.
305///
306/// Sent when the agent needs authorization before performing a sensitive operation.
307///
308/// See protocol docs: [Requesting Permission](https://agentclientprotocol.com/protocol/tool-calls#requesting-permission)
309#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq)]
310#[schemars(extend("x-side" = "client", "x-method" = SESSION_REQUEST_PERMISSION_METHOD_NAME))]
311#[serde(rename_all = "camelCase")]
312#[non_exhaustive]
313pub struct RequestPermissionRequest {
314    /// The session ID for this request.
315    pub session_id: SessionId,
316    /// Details about the tool call requiring permission.
317    pub tool_call: ToolCallUpdate,
318    /// Available permission options for the user to choose from.
319    pub options: Vec<PermissionOption>,
320    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
321    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
322    /// these keys.
323    ///
324    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
325    #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
326    pub meta: Option<Meta>,
327}
328
329impl RequestPermissionRequest {
330    #[must_use]
331    pub fn new(
332        session_id: impl Into<SessionId>,
333        tool_call: ToolCallUpdate,
334        options: Vec<PermissionOption>,
335    ) -> Self {
336        Self {
337            session_id: session_id.into(),
338            tool_call,
339            options,
340            meta: None,
341        }
342    }
343
344    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
345    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
346    /// these keys.
347    ///
348    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
349    #[must_use]
350    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
351        self.meta = meta.into_option();
352        self
353    }
354}
355
356/// An option presented to the user when requesting permission.
357#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
358#[serde(rename_all = "camelCase")]
359#[non_exhaustive]
360pub struct PermissionOption {
361    /// Unique identifier for this permission option.
362    pub option_id: PermissionOptionId,
363    /// Human-readable label to display to the user.
364    pub name: String,
365    /// Hint about the nature of this permission option.
366    pub kind: PermissionOptionKind,
367    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
368    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
369    /// these keys.
370    ///
371    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
372    #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
373    pub meta: Option<Meta>,
374}
375
376impl PermissionOption {
377    pub fn new(
378        option_id: impl Into<PermissionOptionId>,
379        name: impl Into<String>,
380        kind: PermissionOptionKind,
381    ) -> Self {
382        Self {
383            option_id: option_id.into(),
384            name: name.into(),
385            kind,
386            meta: None,
387        }
388    }
389
390    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
391    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
392    /// these keys.
393    ///
394    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
395    #[must_use]
396    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
397        self.meta = meta.into_option();
398        self
399    }
400}
401
402/// Unique identifier for a permission option.
403#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq, Hash, Display, From)]
404#[serde(transparent)]
405#[from(Arc<str>, String, &'static str)]
406#[non_exhaustive]
407pub struct PermissionOptionId(pub Arc<str>);
408
409impl PermissionOptionId {
410    pub fn new(id: impl Into<Arc<str>>) -> Self {
411        Self(id.into())
412    }
413}
414
415/// The type of permission option being presented to the user.
416///
417/// Helps clients choose appropriate icons and UI treatment.
418#[derive(Debug, Clone, Copy, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
419#[serde(rename_all = "snake_case")]
420#[non_exhaustive]
421pub enum PermissionOptionKind {
422    /// Allow this operation only this time.
423    AllowOnce,
424    /// Allow this operation and remember the choice.
425    AllowAlways,
426    /// Reject this operation only this time.
427    RejectOnce,
428    /// Reject this operation and remember the choice.
429    RejectAlways,
430}
431
432/// Response to a permission request.
433#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
434#[schemars(extend("x-side" = "client", "x-method" = SESSION_REQUEST_PERMISSION_METHOD_NAME))]
435#[serde(rename_all = "camelCase")]
436#[non_exhaustive]
437pub struct RequestPermissionResponse {
438    /// The user's decision on the permission request.
439    // This extra-level is unfortunately needed because the output must be an object
440    pub outcome: RequestPermissionOutcome,
441    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
442    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
443    /// these keys.
444    ///
445    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
446    #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
447    pub meta: Option<Meta>,
448}
449
450impl RequestPermissionResponse {
451    #[must_use]
452    pub fn new(outcome: RequestPermissionOutcome) -> Self {
453        Self {
454            outcome,
455            meta: None,
456        }
457    }
458
459    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
460    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
461    /// these keys.
462    ///
463    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
464    #[must_use]
465    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
466        self.meta = meta.into_option();
467        self
468    }
469}
470
471/// The outcome of a permission request.
472#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
473#[serde(tag = "outcome", rename_all = "snake_case")]
474#[schemars(extend("discriminator" = {"propertyName": "outcome"}))]
475#[non_exhaustive]
476pub enum RequestPermissionOutcome {
477    /// The prompt turn was cancelled before the user responded.
478    ///
479    /// When a client sends a `session/cancel` notification to cancel an ongoing
480    /// prompt turn, it MUST respond to all pending `session/request_permission`
481    /// requests with this `Cancelled` outcome.
482    ///
483    /// See protocol docs: [Cancellation](https://agentclientprotocol.com/protocol/prompt-turn#cancellation)
484    Cancelled,
485    /// The user selected one of the provided options.
486    #[serde(rename_all = "camelCase")]
487    Selected(SelectedPermissionOutcome),
488}
489
490/// The user selected one of the provided options.
491#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
492#[serde(rename_all = "camelCase")]
493#[non_exhaustive]
494pub struct SelectedPermissionOutcome {
495    /// The ID of the option the user selected.
496    pub option_id: PermissionOptionId,
497    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
498    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
499    /// these keys.
500    ///
501    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
502    #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
503    pub meta: Option<Meta>,
504}
505
506impl SelectedPermissionOutcome {
507    #[must_use]
508    pub fn new(option_id: impl Into<PermissionOptionId>) -> Self {
509        Self {
510            option_id: option_id.into(),
511            meta: None,
512        }
513    }
514
515    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
516    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
517    /// these keys.
518    ///
519    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
520    #[must_use]
521    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
522        self.meta = meta.into_option();
523        self
524    }
525}
526
527// Write text file
528
529/// Request to write content to a text file.
530///
531/// Only available if the client supports the `fs.writeTextFile` capability.
532#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
533#[schemars(extend("x-side" = "client", "x-method" = FS_WRITE_TEXT_FILE_METHOD_NAME))]
534#[serde(rename_all = "camelCase")]
535#[non_exhaustive]
536pub struct WriteTextFileRequest {
537    /// The session ID for this request.
538    pub session_id: SessionId,
539    /// Absolute path to the file to write.
540    pub path: PathBuf,
541    /// The text content to write to the file.
542    pub content: String,
543    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
544    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
545    /// these keys.
546    ///
547    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
548    #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
549    pub meta: Option<Meta>,
550}
551
552impl WriteTextFileRequest {
553    pub fn new(
554        session_id: impl Into<SessionId>,
555        path: impl Into<PathBuf>,
556        content: impl Into<String>,
557    ) -> Self {
558        Self {
559            session_id: session_id.into(),
560            path: path.into(),
561            content: content.into(),
562            meta: None,
563        }
564    }
565
566    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
567    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
568    /// these keys.
569    ///
570    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
571    #[must_use]
572    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
573        self.meta = meta.into_option();
574        self
575    }
576}
577
578/// Response to `fs/write_text_file`
579#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
580#[serde(default, rename_all = "camelCase")]
581#[schemars(extend("x-side" = "client", "x-method" = FS_WRITE_TEXT_FILE_METHOD_NAME))]
582#[non_exhaustive]
583pub struct WriteTextFileResponse {
584    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
585    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
586    /// these keys.
587    ///
588    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
589    #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
590    pub meta: Option<Meta>,
591}
592
593impl WriteTextFileResponse {
594    #[must_use]
595    pub fn new() -> Self {
596        Self::default()
597    }
598
599    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
600    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
601    /// these keys.
602    ///
603    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
604    #[must_use]
605    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
606        self.meta = meta.into_option();
607        self
608    }
609}
610
611// Read text file
612
613/// Request to read content from a text file.
614///
615/// Only available if the client supports the `fs.readTextFile` capability.
616#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
617#[schemars(extend("x-side" = "client", "x-method" = FS_READ_TEXT_FILE_METHOD_NAME))]
618#[serde(rename_all = "camelCase")]
619#[non_exhaustive]
620pub struct ReadTextFileRequest {
621    /// The session ID for this request.
622    pub session_id: SessionId,
623    /// Absolute path to the file to read.
624    pub path: PathBuf,
625    /// Line number to start reading from (1-based).
626    #[serde(skip_serializing_if = "Option::is_none")]
627    pub line: Option<u32>,
628    /// Maximum number of lines to read.
629    #[serde(skip_serializing_if = "Option::is_none")]
630    pub limit: Option<u32>,
631    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
632    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
633    /// these keys.
634    ///
635    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
636    #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
637    pub meta: Option<Meta>,
638}
639
640impl ReadTextFileRequest {
641    pub fn new(session_id: impl Into<SessionId>, path: impl Into<PathBuf>) -> Self {
642        Self {
643            session_id: session_id.into(),
644            path: path.into(),
645            line: None,
646            limit: None,
647            meta: None,
648        }
649    }
650
651    /// Line number to start reading from (1-based).
652    #[must_use]
653    pub fn line(mut self, line: impl IntoOption<u32>) -> Self {
654        self.line = line.into_option();
655        self
656    }
657
658    /// Maximum number of lines to read.
659    #[must_use]
660    pub fn limit(mut self, limit: impl IntoOption<u32>) -> Self {
661        self.limit = limit.into_option();
662        self
663    }
664
665    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
666    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
667    /// these keys.
668    ///
669    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
670    #[must_use]
671    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
672        self.meta = meta.into_option();
673        self
674    }
675}
676
677/// Response containing the contents of a text file.
678#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
679#[schemars(extend("x-side" = "client", "x-method" = FS_READ_TEXT_FILE_METHOD_NAME))]
680#[serde(rename_all = "camelCase")]
681#[non_exhaustive]
682pub struct ReadTextFileResponse {
683    pub content: String,
684    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
685    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
686    /// these keys.
687    ///
688    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
689    #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
690    pub meta: Option<Meta>,
691}
692
693impl ReadTextFileResponse {
694    pub fn new(content: impl Into<String>) -> Self {
695        Self {
696            content: content.into(),
697            meta: None,
698        }
699    }
700
701    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
702    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
703    /// these keys.
704    ///
705    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
706    #[must_use]
707    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
708        self.meta = meta.into_option();
709        self
710    }
711}
712
713// Terminals
714
715#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq, Hash, Display, From)]
716#[serde(transparent)]
717#[from(Arc<str>, String, &'static str)]
718#[non_exhaustive]
719pub struct TerminalId(pub Arc<str>);
720
721impl TerminalId {
722    pub fn new(id: impl Into<Arc<str>>) -> Self {
723        Self(id.into())
724    }
725}
726
727/// Request to create a new terminal and execute a command.
728#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
729#[serde(rename_all = "camelCase")]
730#[schemars(extend("x-side" = "client", "x-method" = TERMINAL_CREATE_METHOD_NAME))]
731#[non_exhaustive]
732pub struct CreateTerminalRequest {
733    /// The session ID for this request.
734    pub session_id: SessionId,
735    /// The command to execute.
736    pub command: String,
737    /// Array of command arguments.
738    #[serde(default, skip_serializing_if = "Vec::is_empty")]
739    pub args: Vec<String>,
740    /// Environment variables for the command.
741    #[serde(default, skip_serializing_if = "Vec::is_empty")]
742    pub env: Vec<crate::EnvVariable>,
743    /// Working directory for the command (absolute path).
744    #[serde(skip_serializing_if = "Option::is_none")]
745    pub cwd: Option<PathBuf>,
746    /// Maximum number of output bytes to retain.
747    ///
748    /// When the limit is exceeded, the Client truncates from the beginning of the output
749    /// to stay within the limit.
750    ///
751    /// The Client MUST ensure truncation happens at a character boundary to maintain valid
752    /// string output, even if this means the retained output is slightly less than the
753    /// specified limit.
754    #[serde(skip_serializing_if = "Option::is_none")]
755    pub output_byte_limit: Option<u64>,
756    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
757    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
758    /// these keys.
759    ///
760    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
761    #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
762    pub meta: Option<Meta>,
763}
764
765impl CreateTerminalRequest {
766    pub fn new(session_id: impl Into<SessionId>, command: impl Into<String>) -> Self {
767        Self {
768            session_id: session_id.into(),
769            command: command.into(),
770            args: Vec::new(),
771            env: Vec::new(),
772            cwd: None,
773            output_byte_limit: None,
774            meta: None,
775        }
776    }
777
778    /// Array of command arguments.
779    #[must_use]
780    pub fn args(mut self, args: Vec<String>) -> Self {
781        self.args = args;
782        self
783    }
784
785    /// Environment variables for the command.
786    #[must_use]
787    pub fn env(mut self, env: Vec<crate::EnvVariable>) -> Self {
788        self.env = env;
789        self
790    }
791
792    /// Working directory for the command (absolute path).
793    #[must_use]
794    pub fn cwd(mut self, cwd: impl IntoOption<PathBuf>) -> Self {
795        self.cwd = cwd.into_option();
796        self
797    }
798
799    /// Maximum number of output bytes to retain.
800    ///
801    /// When the limit is exceeded, the Client truncates from the beginning of the output
802    /// to stay within the limit.
803    ///
804    /// The Client MUST ensure truncation happens at a character boundary to maintain valid
805    /// string output, even if this means the retained output is slightly less than the
806    /// specified limit.
807    #[must_use]
808    pub fn output_byte_limit(mut self, output_byte_limit: impl IntoOption<u64>) -> Self {
809        self.output_byte_limit = output_byte_limit.into_option();
810        self
811    }
812
813    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
814    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
815    /// these keys.
816    ///
817    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
818    #[must_use]
819    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
820        self.meta = meta.into_option();
821        self
822    }
823}
824
825/// Response containing the ID of the created terminal.
826#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
827#[serde(rename_all = "camelCase")]
828#[schemars(extend("x-side" = "client", "x-method" = TERMINAL_CREATE_METHOD_NAME))]
829#[non_exhaustive]
830pub struct CreateTerminalResponse {
831    /// The unique identifier for the created terminal.
832    pub terminal_id: TerminalId,
833    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
834    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
835    /// these keys.
836    ///
837    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
838    #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
839    pub meta: Option<Meta>,
840}
841
842impl CreateTerminalResponse {
843    #[must_use]
844    pub fn new(terminal_id: impl Into<TerminalId>) -> Self {
845        Self {
846            terminal_id: terminal_id.into(),
847            meta: None,
848        }
849    }
850
851    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
852    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
853    /// these keys.
854    ///
855    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
856    #[must_use]
857    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
858        self.meta = meta.into_option();
859        self
860    }
861}
862
863/// Request to get the current output and status of a terminal.
864#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
865#[serde(rename_all = "camelCase")]
866#[schemars(extend("x-side" = "client", "x-method" = TERMINAL_OUTPUT_METHOD_NAME))]
867#[non_exhaustive]
868pub struct TerminalOutputRequest {
869    /// The session ID for this request.
870    pub session_id: SessionId,
871    /// The ID of the terminal to get output from.
872    pub terminal_id: TerminalId,
873    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
874    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
875    /// these keys.
876    ///
877    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
878    #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
879    pub meta: Option<Meta>,
880}
881
882impl TerminalOutputRequest {
883    #[must_use]
884    pub fn new(session_id: impl Into<SessionId>, terminal_id: impl Into<TerminalId>) -> Self {
885        Self {
886            session_id: session_id.into(),
887            terminal_id: terminal_id.into(),
888            meta: None,
889        }
890    }
891
892    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
893    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
894    /// these keys.
895    ///
896    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
897    #[must_use]
898    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
899        self.meta = meta.into_option();
900        self
901    }
902}
903
904/// Response containing the terminal output and exit status.
905#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
906#[serde(rename_all = "camelCase")]
907#[schemars(extend("x-side" = "client", "x-method" = TERMINAL_OUTPUT_METHOD_NAME))]
908#[non_exhaustive]
909pub struct TerminalOutputResponse {
910    /// The terminal output captured so far.
911    pub output: String,
912    /// Whether the output was truncated due to byte limits.
913    pub truncated: bool,
914    /// Exit status if the command has completed.
915    pub exit_status: Option<TerminalExitStatus>,
916    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
917    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
918    /// these keys.
919    ///
920    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
921    #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
922    pub meta: Option<Meta>,
923}
924
925impl TerminalOutputResponse {
926    pub fn new(output: impl Into<String>, truncated: bool) -> Self {
927        Self {
928            output: output.into(),
929            truncated,
930            exit_status: None,
931            meta: None,
932        }
933    }
934
935    /// Exit status if the command has completed.
936    #[must_use]
937    pub fn exit_status(mut self, exit_status: impl IntoOption<TerminalExitStatus>) -> Self {
938        self.exit_status = exit_status.into_option();
939        self
940    }
941
942    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
943    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
944    /// these keys.
945    ///
946    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
947    #[must_use]
948    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
949        self.meta = meta.into_option();
950        self
951    }
952}
953
954/// Request to release a terminal and free its resources.
955#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
956#[serde(rename_all = "camelCase")]
957#[schemars(extend("x-side" = "client", "x-method" = TERMINAL_RELEASE_METHOD_NAME))]
958#[non_exhaustive]
959pub struct ReleaseTerminalRequest {
960    /// The session ID for this request.
961    pub session_id: SessionId,
962    /// The ID of the terminal to release.
963    pub terminal_id: TerminalId,
964    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
965    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
966    /// these keys.
967    ///
968    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
969    #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
970    pub meta: Option<Meta>,
971}
972
973impl ReleaseTerminalRequest {
974    #[must_use]
975    pub fn new(session_id: impl Into<SessionId>, terminal_id: impl Into<TerminalId>) -> Self {
976        Self {
977            session_id: session_id.into(),
978            terminal_id: terminal_id.into(),
979            meta: None,
980        }
981    }
982
983    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
984    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
985    /// these keys.
986    ///
987    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
988    #[must_use]
989    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
990        self.meta = meta.into_option();
991        self
992    }
993}
994
995/// Response to terminal/release method
996#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
997#[serde(rename_all = "camelCase")]
998#[schemars(extend("x-side" = "client", "x-method" = TERMINAL_RELEASE_METHOD_NAME))]
999#[non_exhaustive]
1000pub struct ReleaseTerminalResponse {
1001    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1002    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1003    /// these keys.
1004    ///
1005    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1006    #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
1007    pub meta: Option<Meta>,
1008}
1009
1010impl ReleaseTerminalResponse {
1011    #[must_use]
1012    pub fn new() -> Self {
1013        Self::default()
1014    }
1015
1016    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1017    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1018    /// these keys.
1019    ///
1020    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1021    #[must_use]
1022    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1023        self.meta = meta.into_option();
1024        self
1025    }
1026}
1027
1028/// Request to kill a terminal command without releasing the terminal.
1029#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1030#[serde(rename_all = "camelCase")]
1031#[schemars(extend("x-side" = "client", "x-method" = TERMINAL_KILL_METHOD_NAME))]
1032#[non_exhaustive]
1033pub struct KillTerminalCommandRequest {
1034    /// The session ID for this request.
1035    pub session_id: SessionId,
1036    /// The ID of the terminal to kill.
1037    pub terminal_id: TerminalId,
1038    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1039    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1040    /// these keys.
1041    ///
1042    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1043    #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
1044    pub meta: Option<Meta>,
1045}
1046
1047impl KillTerminalCommandRequest {
1048    #[must_use]
1049    pub fn new(session_id: impl Into<SessionId>, terminal_id: impl Into<TerminalId>) -> Self {
1050        Self {
1051            session_id: session_id.into(),
1052            terminal_id: terminal_id.into(),
1053            meta: None,
1054        }
1055    }
1056
1057    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1058    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1059    /// these keys.
1060    ///
1061    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1062    #[must_use]
1063    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1064        self.meta = meta.into_option();
1065        self
1066    }
1067}
1068
1069/// Response to terminal/kill command method
1070#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1071#[serde(rename_all = "camelCase")]
1072#[schemars(extend("x-side" = "client", "x-method" = TERMINAL_KILL_METHOD_NAME))]
1073#[non_exhaustive]
1074pub struct KillTerminalCommandResponse {
1075    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1076    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1077    /// these keys.
1078    ///
1079    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1080    #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
1081    pub meta: Option<Meta>,
1082}
1083
1084impl KillTerminalCommandResponse {
1085    #[must_use]
1086    pub fn new() -> Self {
1087        Self::default()
1088    }
1089
1090    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1091    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1092    /// these keys.
1093    ///
1094    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1095    #[must_use]
1096    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1097        self.meta = meta.into_option();
1098        self
1099    }
1100}
1101
1102/// Request to wait for a terminal command to exit.
1103#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1104#[serde(rename_all = "camelCase")]
1105#[schemars(extend("x-side" = "client", "x-method" = TERMINAL_WAIT_FOR_EXIT_METHOD_NAME))]
1106#[non_exhaustive]
1107pub struct WaitForTerminalExitRequest {
1108    /// The session ID for this request.
1109    pub session_id: SessionId,
1110    /// The ID of the terminal to wait for.
1111    pub terminal_id: TerminalId,
1112    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1113    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1114    /// these keys.
1115    ///
1116    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1117    #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
1118    pub meta: Option<Meta>,
1119}
1120
1121impl WaitForTerminalExitRequest {
1122    #[must_use]
1123    pub fn new(session_id: impl Into<SessionId>, terminal_id: impl Into<TerminalId>) -> Self {
1124        Self {
1125            session_id: session_id.into(),
1126            terminal_id: terminal_id.into(),
1127            meta: None,
1128        }
1129    }
1130
1131    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1132    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1133    /// these keys.
1134    ///
1135    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1136    #[must_use]
1137    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1138        self.meta = meta.into_option();
1139        self
1140    }
1141}
1142
1143/// Response containing the exit status of a terminal command.
1144#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1145#[serde(rename_all = "camelCase")]
1146#[schemars(extend("x-side" = "client", "x-method" = TERMINAL_WAIT_FOR_EXIT_METHOD_NAME))]
1147#[non_exhaustive]
1148pub struct WaitForTerminalExitResponse {
1149    /// The exit status of the terminal command.
1150    #[serde(flatten)]
1151    pub exit_status: TerminalExitStatus,
1152    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1153    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1154    /// these keys.
1155    ///
1156    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1157    #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
1158    pub meta: Option<Meta>,
1159}
1160
1161impl WaitForTerminalExitResponse {
1162    #[must_use]
1163    pub fn new(exit_status: TerminalExitStatus) -> Self {
1164        Self {
1165            exit_status,
1166            meta: None,
1167        }
1168    }
1169
1170    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1171    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1172    /// these keys.
1173    ///
1174    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1175    #[must_use]
1176    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1177        self.meta = meta.into_option();
1178        self
1179    }
1180}
1181
1182/// Exit status of a terminal command.
1183#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1184#[serde(rename_all = "camelCase")]
1185#[non_exhaustive]
1186pub struct TerminalExitStatus {
1187    /// The process exit code (may be null if terminated by signal).
1188    pub exit_code: Option<u32>,
1189    /// The signal that terminated the process (may be null if exited normally).
1190    pub signal: Option<String>,
1191    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1192    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1193    /// these keys.
1194    ///
1195    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1196    #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
1197    pub meta: Option<Meta>,
1198}
1199
1200impl TerminalExitStatus {
1201    #[must_use]
1202    pub fn new() -> Self {
1203        Self::default()
1204    }
1205
1206    /// The process exit code (may be null if terminated by signal).
1207    #[must_use]
1208    pub fn exit_code(mut self, exit_code: impl IntoOption<u32>) -> Self {
1209        self.exit_code = exit_code.into_option();
1210        self
1211    }
1212
1213    /// The signal that terminated the process (may be null if exited normally).
1214    #[must_use]
1215    pub fn signal(mut self, signal: impl IntoOption<String>) -> Self {
1216        self.signal = signal.into_option();
1217        self
1218    }
1219
1220    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1221    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1222    /// these keys.
1223    ///
1224    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1225    #[must_use]
1226    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1227        self.meta = meta.into_option();
1228        self
1229    }
1230}
1231
1232// Capabilities
1233
1234/// Capabilities supported by the client.
1235///
1236/// Advertised during initialization to inform the agent about
1237/// available features and methods.
1238///
1239/// See protocol docs: [Client Capabilities](https://agentclientprotocol.com/protocol/initialization#client-capabilities)
1240#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1241#[serde(rename_all = "camelCase")]
1242#[non_exhaustive]
1243pub struct ClientCapabilities {
1244    /// File system capabilities supported by the client.
1245    /// Determines which file operations the agent can request.
1246    #[serde(default)]
1247    pub fs: FileSystemCapability,
1248    /// Whether the Client support all `terminal/*` methods.
1249    #[serde(default)]
1250    pub terminal: bool,
1251    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1252    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1253    /// these keys.
1254    ///
1255    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1256    #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
1257    pub meta: Option<Meta>,
1258}
1259
1260impl ClientCapabilities {
1261    #[must_use]
1262    pub fn new() -> Self {
1263        Self::default()
1264    }
1265
1266    /// File system capabilities supported by the client.
1267    /// Determines which file operations the agent can request.
1268    #[must_use]
1269    pub fn fs(mut self, fs: FileSystemCapability) -> Self {
1270        self.fs = fs;
1271        self
1272    }
1273
1274    /// Whether the Client support all `terminal/*` methods.
1275    #[must_use]
1276    pub fn terminal(mut self, terminal: bool) -> Self {
1277        self.terminal = terminal;
1278        self
1279    }
1280
1281    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1282    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1283    /// these keys.
1284    ///
1285    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1286    #[must_use]
1287    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1288        self.meta = meta.into_option();
1289        self
1290    }
1291}
1292
1293/// Filesystem capabilities supported by the client.
1294/// File system capabilities that a client may support.
1295///
1296/// See protocol docs: [FileSystem](https://agentclientprotocol.com/protocol/initialization#filesystem)
1297#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1298#[serde(rename_all = "camelCase")]
1299#[non_exhaustive]
1300pub struct FileSystemCapability {
1301    /// Whether the Client supports `fs/read_text_file` requests.
1302    #[serde(default)]
1303    pub read_text_file: bool,
1304    /// Whether the Client supports `fs/write_text_file` requests.
1305    #[serde(default)]
1306    pub write_text_file: bool,
1307    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1308    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1309    /// these keys.
1310    ///
1311    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1312    #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
1313    pub meta: Option<Meta>,
1314}
1315
1316impl FileSystemCapability {
1317    #[must_use]
1318    pub fn new() -> Self {
1319        Self::default()
1320    }
1321
1322    /// Whether the Client supports `fs/read_text_file` requests.
1323    #[must_use]
1324    pub fn read_text_file(mut self, read_text_file: bool) -> Self {
1325        self.read_text_file = read_text_file;
1326        self
1327    }
1328
1329    /// Whether the Client supports `fs/write_text_file` requests.
1330    #[must_use]
1331    pub fn write_text_file(mut self, write_text_file: bool) -> Self {
1332        self.write_text_file = write_text_file;
1333        self
1334    }
1335
1336    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1337    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1338    /// these keys.
1339    ///
1340    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1341    #[must_use]
1342    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1343        self.meta = meta.into_option();
1344        self
1345    }
1346}
1347
1348// Method schema
1349
1350/// Names of all methods that clients handle.
1351///
1352/// Provides a centralized definition of method names used in the protocol.
1353#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
1354#[non_exhaustive]
1355pub struct ClientMethodNames {
1356    /// Method for requesting permission from the user.
1357    pub session_request_permission: &'static str,
1358    /// Notification for session updates.
1359    pub session_update: &'static str,
1360    /// Method for writing text files.
1361    pub fs_write_text_file: &'static str,
1362    /// Method for reading text files.
1363    pub fs_read_text_file: &'static str,
1364    /// Method for creating new terminals.
1365    pub terminal_create: &'static str,
1366    /// Method for getting terminals output.
1367    pub terminal_output: &'static str,
1368    /// Method for releasing a terminal.
1369    pub terminal_release: &'static str,
1370    /// Method for waiting for a terminal to finish.
1371    pub terminal_wait_for_exit: &'static str,
1372    /// Method for killing a terminal.
1373    pub terminal_kill: &'static str,
1374}
1375
1376/// Constant containing all client method names.
1377pub const CLIENT_METHOD_NAMES: ClientMethodNames = ClientMethodNames {
1378    session_update: SESSION_UPDATE_NOTIFICATION,
1379    session_request_permission: SESSION_REQUEST_PERMISSION_METHOD_NAME,
1380    fs_write_text_file: FS_WRITE_TEXT_FILE_METHOD_NAME,
1381    fs_read_text_file: FS_READ_TEXT_FILE_METHOD_NAME,
1382    terminal_create: TERMINAL_CREATE_METHOD_NAME,
1383    terminal_output: TERMINAL_OUTPUT_METHOD_NAME,
1384    terminal_release: TERMINAL_RELEASE_METHOD_NAME,
1385    terminal_wait_for_exit: TERMINAL_WAIT_FOR_EXIT_METHOD_NAME,
1386    terminal_kill: TERMINAL_KILL_METHOD_NAME,
1387};
1388
1389/// Notification name for session updates.
1390pub(crate) const SESSION_UPDATE_NOTIFICATION: &str = "session/update";
1391/// Method name for requesting user permission.
1392pub(crate) const SESSION_REQUEST_PERMISSION_METHOD_NAME: &str = "session/request_permission";
1393/// Method name for writing text files.
1394pub(crate) const FS_WRITE_TEXT_FILE_METHOD_NAME: &str = "fs/write_text_file";
1395/// Method name for reading text files.
1396pub(crate) const FS_READ_TEXT_FILE_METHOD_NAME: &str = "fs/read_text_file";
1397/// Method name for creating a new terminal.
1398pub(crate) const TERMINAL_CREATE_METHOD_NAME: &str = "terminal/create";
1399/// Method for getting terminals output.
1400pub(crate) const TERMINAL_OUTPUT_METHOD_NAME: &str = "terminal/output";
1401/// Method for releasing a terminal.
1402pub(crate) const TERMINAL_RELEASE_METHOD_NAME: &str = "terminal/release";
1403/// Method for waiting for a terminal to finish.
1404pub(crate) const TERMINAL_WAIT_FOR_EXIT_METHOD_NAME: &str = "terminal/wait_for_exit";
1405/// Method for killing a terminal.
1406pub(crate) const TERMINAL_KILL_METHOD_NAME: &str = "terminal/kill";
1407
1408/// All possible requests that an agent can send to a client.
1409///
1410/// This enum is used internally for routing RPC requests. You typically won't need
1411/// to use this directly - instead, use the methods on the [`Client`] trait.
1412///
1413/// This enum encompasses all method calls from agent to client.
1414#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
1415#[serde(untagged)]
1416#[schemars(inline)]
1417#[non_exhaustive]
1418pub enum AgentRequest {
1419    /// Writes content to a text file in the client's file system.
1420    ///
1421    /// Only available if the client advertises the `fs.writeTextFile` capability.
1422    /// Allows the agent to create or modify files within the client's environment.
1423    ///
1424    /// See protocol docs: [Client](https://agentclientprotocol.com/protocol/overview#client)
1425    WriteTextFileRequest(WriteTextFileRequest),
1426    /// Reads content from a text file in the client's file system.
1427    ///
1428    /// Only available if the client advertises the `fs.readTextFile` capability.
1429    /// Allows the agent to access file contents within the client's environment.
1430    ///
1431    /// See protocol docs: [Client](https://agentclientprotocol.com/protocol/overview#client)
1432    ReadTextFileRequest(ReadTextFileRequest),
1433    /// Requests permission from the user for a tool call operation.
1434    ///
1435    /// Called by the agent when it needs user authorization before executing
1436    /// a potentially sensitive operation. The client should present the options
1437    /// to the user and return their decision.
1438    ///
1439    /// If the client cancels the prompt turn via `session/cancel`, it MUST
1440    /// respond to this request with `RequestPermissionOutcome::Cancelled`.
1441    ///
1442    /// See protocol docs: [Requesting Permission](https://agentclientprotocol.com/protocol/tool-calls#requesting-permission)
1443    RequestPermissionRequest(RequestPermissionRequest),
1444    /// Executes a command in a new terminal
1445    ///
1446    /// Only available if the `terminal` Client capability is set to `true`.
1447    ///
1448    /// Returns a `TerminalId` that can be used with other terminal methods
1449    /// to get the current output, wait for exit, and kill the command.
1450    ///
1451    /// The `TerminalId` can also be used to embed the terminal in a tool call
1452    /// by using the `ToolCallContent::Terminal` variant.
1453    ///
1454    /// The Agent is responsible for releasing the terminal by using the `terminal/release`
1455    /// method.
1456    ///
1457    /// See protocol docs: [Terminals](https://agentclientprotocol.com/protocol/terminals)
1458    CreateTerminalRequest(CreateTerminalRequest),
1459    /// Gets the terminal output and exit status
1460    ///
1461    /// Returns the current content in the terminal without waiting for the command to exit.
1462    /// If the command has already exited, the exit status is included.
1463    ///
1464    /// See protocol docs: [Terminals](https://agentclientprotocol.com/protocol/terminals)
1465    TerminalOutputRequest(TerminalOutputRequest),
1466    /// Releases a terminal
1467    ///
1468    /// The command is killed if it hasn't exited yet. Use `terminal/wait_for_exit`
1469    /// to wait for the command to exit before releasing the terminal.
1470    ///
1471    /// After release, the `TerminalId` can no longer be used with other `terminal/*` methods,
1472    /// but tool calls that already contain it, continue to display its output.
1473    ///
1474    /// The `terminal/kill` method can be used to terminate the command without releasing
1475    /// the terminal, allowing the Agent to call `terminal/output` and other methods.
1476    ///
1477    /// See protocol docs: [Terminals](https://agentclientprotocol.com/protocol/terminals)
1478    ReleaseTerminalRequest(ReleaseTerminalRequest),
1479    /// Waits for the terminal command to exit and return its exit status
1480    ///
1481    /// See protocol docs: [Terminals](https://agentclientprotocol.com/protocol/terminals)
1482    WaitForTerminalExitRequest(WaitForTerminalExitRequest),
1483    /// Kills the terminal command without releasing the terminal
1484    ///
1485    /// While `terminal/release` will also kill the command, this method will keep
1486    /// the `TerminalId` valid so it can be used with other methods.
1487    ///
1488    /// This method can be helpful when implementing command timeouts which terminate
1489    /// the command as soon as elapsed, and then get the final output so it can be sent
1490    /// to the model.
1491    ///
1492    /// Note: `terminal/release` when `TerminalId` is no longer needed.
1493    ///
1494    /// See protocol docs: [Terminals](https://agentclientprotocol.com/protocol/terminals)
1495    KillTerminalCommandRequest(KillTerminalCommandRequest),
1496    /// Handles extension method requests from the agent.
1497    ///
1498    /// Allows the Agent to send an arbitrary request that is not part of the ACP spec.
1499    /// Extension methods provide a way to add custom functionality while maintaining
1500    /// protocol compatibility.
1501    ///
1502    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1503    ExtMethodRequest(ExtRequest),
1504}
1505
1506impl AgentRequest {
1507    /// Returns the corresponding method name of the request.
1508    #[must_use]
1509    pub fn method(&self) -> &str {
1510        match self {
1511            Self::WriteTextFileRequest(_) => CLIENT_METHOD_NAMES.fs_write_text_file,
1512            Self::ReadTextFileRequest(_) => CLIENT_METHOD_NAMES.fs_read_text_file,
1513            Self::RequestPermissionRequest(_) => CLIENT_METHOD_NAMES.session_request_permission,
1514            Self::CreateTerminalRequest(_) => CLIENT_METHOD_NAMES.terminal_create,
1515            Self::TerminalOutputRequest(_) => CLIENT_METHOD_NAMES.terminal_output,
1516            Self::ReleaseTerminalRequest(_) => CLIENT_METHOD_NAMES.terminal_release,
1517            Self::WaitForTerminalExitRequest(_) => CLIENT_METHOD_NAMES.terminal_wait_for_exit,
1518            Self::KillTerminalCommandRequest(_) => CLIENT_METHOD_NAMES.terminal_kill,
1519            Self::ExtMethodRequest(ext_request) => &ext_request.method,
1520        }
1521    }
1522}
1523
1524/// All possible responses that a client can send to an agent.
1525///
1526/// This enum is used internally for routing RPC responses. You typically won't need
1527/// to use this directly - the responses are handled automatically by the connection.
1528///
1529/// These are responses to the corresponding `AgentRequest` variants.
1530#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
1531#[serde(untagged)]
1532#[schemars(inline)]
1533#[non_exhaustive]
1534pub enum ClientResponse {
1535    WriteTextFileResponse(#[serde(default)] WriteTextFileResponse),
1536    ReadTextFileResponse(ReadTextFileResponse),
1537    RequestPermissionResponse(RequestPermissionResponse),
1538    CreateTerminalResponse(CreateTerminalResponse),
1539    TerminalOutputResponse(TerminalOutputResponse),
1540    ReleaseTerminalResponse(#[serde(default)] ReleaseTerminalResponse),
1541    WaitForTerminalExitResponse(WaitForTerminalExitResponse),
1542    KillTerminalResponse(#[serde(default)] KillTerminalCommandResponse),
1543    ExtMethodResponse(ExtResponse),
1544}
1545
1546/// All possible notifications that an agent can send to a client.
1547///
1548/// This enum is used internally for routing RPC notifications. You typically won't need
1549/// to use this directly - use the notification methods on the [`Client`] trait instead.
1550///
1551/// Notifications do not expect a response.
1552#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
1553#[serde(untagged)]
1554#[expect(clippy::large_enum_variant)]
1555#[schemars(inline)]
1556#[non_exhaustive]
1557pub enum AgentNotification {
1558    /// Handles session update notifications from the agent.
1559    ///
1560    /// This is a notification endpoint (no response expected) that receives
1561    /// real-time updates about session progress, including message chunks,
1562    /// tool calls, and execution plans.
1563    ///
1564    /// Note: Clients SHOULD continue accepting tool call updates even after
1565    /// sending a `session/cancel` notification, as the agent may send final
1566    /// updates before responding with the cancelled stop reason.
1567    ///
1568    /// See protocol docs: [Agent Reports Output](https://agentclientprotocol.com/protocol/prompt-turn#3-agent-reports-output)
1569    SessionNotification(SessionNotification),
1570    /// Handles extension notifications from the agent.
1571    ///
1572    /// Allows the Agent to send an arbitrary notification that is not part of the ACP spec.
1573    /// Extension notifications provide a way to send one-way messages for custom functionality
1574    /// while maintaining protocol compatibility.
1575    ///
1576    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1577    ExtNotification(ExtNotification),
1578}
1579
1580impl AgentNotification {
1581    /// Returns the corresponding method name of the notification.
1582    #[must_use]
1583    pub fn method(&self) -> &str {
1584        match self {
1585            Self::SessionNotification(_) => CLIENT_METHOD_NAMES.session_update,
1586            Self::ExtNotification(ext_notification) => &ext_notification.method,
1587        }
1588    }
1589}