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