Skip to main content

agent_client_protocol_schema/v1/
client.rs

1//! Methods and notifications the client handles/receives.
2//!
3//! This module defines the Client trait and all associated types for implementing
4//! a client that interacts with AI coding agents via the Agent Client Protocol (ACP).
5
6use std::{path::PathBuf, sync::Arc};
7
8use derive_more::{Display, From};
9use schemars::JsonSchema;
10use serde::{Deserialize, Serialize};
11use serde_with::{DefaultOnError, VecSkipError, serde_as, skip_serializing_none};
12
13#[cfg(feature = "unstable_elicitation")]
14use crate::{
15    CompleteElicitationNotification, CreateElicitationRequest, CreateElicitationResponse,
16    ElicitationCapabilities,
17};
18use crate::{
19    ContentBlock, EnvVariable, ExtNotification, ExtRequest, ExtResponse, IntoMaybeUndefined,
20    IntoOption, MaybeUndefined, Meta, Plan, SessionConfigOption, SessionId, SessionModeId,
21    SkipListener, ToolCall, ToolCallUpdate,
22};
23#[cfg(feature = "unstable_plan_operations")]
24use crate::{PlanCapabilities, PlanRemoved, PlanUpdate};
25
26#[cfg(feature = "unstable_mcp_over_acp")]
27use super::mcp::{
28    ConnectMcpRequest, ConnectMcpResponse, DisconnectMcpRequest, DisconnectMcpResponse,
29    MCP_CONNECT_METHOD_NAME, MCP_DISCONNECT_METHOD_NAME, MCP_MESSAGE_METHOD_NAME,
30    MessageMcpNotification, MessageMcpRequest, MessageMcpResponse,
31};
32
33#[cfg(feature = "unstable_nes")]
34use crate::{ClientNesCapabilities, PositionEncodingKind};
35
36// Session updates
37
38/// Notification containing a session update from the agent.
39///
40/// Used to stream real-time progress and results during prompt processing.
41///
42/// See protocol docs: [Agent Reports Output](https://agentclientprotocol.com/protocol/prompt-turn#3-agent-reports-output)
43#[skip_serializing_none]
44#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq)]
45#[schemars(extend("x-side" = "client", "x-method" = SESSION_UPDATE_NOTIFICATION))]
46#[serde(rename_all = "camelCase")]
47#[non_exhaustive]
48pub struct SessionNotification {
49    /// The ID of the session this update pertains to.
50    pub session_id: SessionId,
51    /// The actual update content.
52    pub update: SessionUpdate,
53    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
54    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
55    /// these keys.
56    ///
57    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
58    #[serde(rename = "_meta")]
59    pub meta: Option<Meta>,
60}
61
62impl SessionNotification {
63    #[must_use]
64    pub fn new(session_id: impl Into<SessionId>, update: SessionUpdate) -> Self {
65        Self {
66            session_id: session_id.into(),
67            update,
68            meta: None,
69        }
70    }
71
72    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
73    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
74    /// these keys.
75    ///
76    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
77    #[must_use]
78    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
79        self.meta = meta.into_option();
80        self
81    }
82}
83
84/// Different types of updates that can be sent during session processing.
85///
86/// These updates provide real-time feedback about the agent's progress.
87///
88/// See protocol docs: [Agent Reports Output](https://agentclientprotocol.com/protocol/prompt-turn#3-agent-reports-output)
89#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq)]
90#[serde(tag = "sessionUpdate", rename_all = "snake_case")]
91#[schemars(extend("discriminator" = {"propertyName": "sessionUpdate"}))]
92#[non_exhaustive]
93pub enum SessionUpdate {
94    /// A chunk of the user's message being streamed.
95    UserMessageChunk(ContentChunk),
96    /// A chunk of the agent's response being streamed.
97    AgentMessageChunk(ContentChunk),
98    /// A chunk of the agent's internal reasoning being streamed.
99    AgentThoughtChunk(ContentChunk),
100    /// Notification that a new tool call has been initiated.
101    ToolCall(ToolCall),
102    /// Update on the status or results of a tool call.
103    ToolCallUpdate(ToolCallUpdate),
104    /// The agent's execution plan for complex tasks.
105    /// See protocol docs: [Agent Plan](https://agentclientprotocol.com/protocol/agent-plan)
106    Plan(Plan),
107    /// **UNSTABLE**
108    ///
109    /// This capability is not part of the spec yet, and may be removed or changed at any point.
110    ///
111    /// A content update for a plan identified by ID.
112    #[cfg(feature = "unstable_plan_operations")]
113    PlanUpdate(PlanUpdate),
114    /// **UNSTABLE**
115    ///
116    /// This capability is not part of the spec yet, and may be removed or changed at any point.
117    ///
118    /// Removal notice for a plan identified by ID.
119    #[cfg(feature = "unstable_plan_operations")]
120    PlanRemoved(PlanRemoved),
121    /// Available commands are ready or have changed
122    AvailableCommandsUpdate(AvailableCommandsUpdate),
123    /// The current mode of the session has changed
124    ///
125    /// See protocol docs: [Session Modes](https://agentclientprotocol.com/protocol/session-modes)
126    CurrentModeUpdate(CurrentModeUpdate),
127    /// Session configuration options have been updated.
128    ConfigOptionUpdate(ConfigOptionUpdate),
129    /// Session metadata has been updated (title, timestamps, custom metadata)
130    SessionInfoUpdate(SessionInfoUpdate),
131    /// **UNSTABLE**
132    ///
133    /// This capability is not part of the spec yet, and may be removed or changed at any point.
134    ///
135    /// Context window and cost update for the session.
136    #[cfg(feature = "unstable_session_usage")]
137    UsageUpdate(UsageUpdate),
138}
139
140/// The current mode of the session has changed
141///
142/// See protocol docs: [Session Modes](https://agentclientprotocol.com/protocol/session-modes)
143#[skip_serializing_none]
144#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
145#[serde(rename_all = "camelCase")]
146#[non_exhaustive]
147pub struct CurrentModeUpdate {
148    /// The ID of the current mode
149    pub current_mode_id: SessionModeId,
150    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
151    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
152    /// these keys.
153    ///
154    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
155    #[serde(rename = "_meta")]
156    pub meta: Option<Meta>,
157}
158
159impl CurrentModeUpdate {
160    #[must_use]
161    pub fn new(current_mode_id: impl Into<SessionModeId>) -> Self {
162        Self {
163            current_mode_id: current_mode_id.into(),
164            meta: None,
165        }
166    }
167
168    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
169    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
170    /// these keys.
171    ///
172    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
173    #[must_use]
174    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
175        self.meta = meta.into_option();
176        self
177    }
178}
179
180/// Session configuration options have been updated.
181#[serde_as]
182#[skip_serializing_none]
183#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
184#[serde(rename_all = "camelCase")]
185#[non_exhaustive]
186pub struct ConfigOptionUpdate {
187    /// The full set of configuration options and their current values.
188    #[serde_as(deserialize_as = "DefaultOnError<VecSkipError<_, SkipListener>>")]
189    pub config_options: Vec<SessionConfigOption>,
190    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
191    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
192    /// these keys.
193    ///
194    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
195    #[serde(rename = "_meta")]
196    pub meta: Option<Meta>,
197}
198
199impl ConfigOptionUpdate {
200    #[must_use]
201    pub fn new(config_options: Vec<SessionConfigOption>) -> Self {
202        Self {
203            config_options,
204            meta: None,
205        }
206    }
207
208    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
209    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
210    /// these keys.
211    ///
212    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
213    #[must_use]
214    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
215        self.meta = meta.into_option();
216        self
217    }
218}
219
220/// Update to session metadata. All fields are optional to support partial updates.
221///
222/// Agents send this notification to update session information like title or custom metadata.
223/// This allows clients to display dynamic session names and track session state changes.
224#[skip_serializing_none]
225#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
226#[serde(rename_all = "camelCase")]
227#[non_exhaustive]
228pub struct SessionInfoUpdate {
229    /// Human-readable title for the session. Set to null to clear.
230    #[serde(default, skip_serializing_if = "MaybeUndefined::is_undefined")]
231    pub title: MaybeUndefined<String>,
232    /// ISO 8601 timestamp of last activity. Set to null to clear.
233    #[serde(default, skip_serializing_if = "MaybeUndefined::is_undefined")]
234    pub updated_at: MaybeUndefined<String>,
235    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
236    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
237    /// these keys.
238    ///
239    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
240    #[serde(rename = "_meta")]
241    pub meta: Option<Meta>,
242}
243
244impl SessionInfoUpdate {
245    #[must_use]
246    pub fn new() -> Self {
247        Self::default()
248    }
249
250    /// Human-readable title for the session. Set to null to clear.
251    #[must_use]
252    pub fn title(mut self, title: impl IntoMaybeUndefined<String>) -> Self {
253        self.title = title.into_maybe_undefined();
254        self
255    }
256
257    /// ISO 8601 timestamp of last activity. Set to null to clear.
258    #[must_use]
259    pub fn updated_at(mut self, updated_at: impl IntoMaybeUndefined<String>) -> Self {
260        self.updated_at = updated_at.into_maybe_undefined();
261        self
262    }
263
264    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
265    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
266    /// these keys.
267    ///
268    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
269    #[must_use]
270    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
271        self.meta = meta.into_option();
272        self
273    }
274}
275
276/// **UNSTABLE**
277///
278/// This capability is not part of the spec yet, and may be removed or changed at any point.
279///
280/// Context window and cost update for a session.
281#[cfg(feature = "unstable_session_usage")]
282#[serde_as]
283#[skip_serializing_none]
284#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq)]
285#[serde(rename_all = "camelCase")]
286#[non_exhaustive]
287pub struct UsageUpdate {
288    /// Tokens currently in context.
289    pub used: u64,
290    /// Total context window size in tokens.
291    pub size: u64,
292    /// Cumulative session cost (optional).
293    #[serde_as(deserialize_as = "DefaultOnError")]
294    #[serde(default)]
295    pub cost: Option<Cost>,
296    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
297    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
298    /// these keys.
299    ///
300    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
301    #[serde(rename = "_meta")]
302    pub meta: Option<Meta>,
303}
304
305#[cfg(feature = "unstable_session_usage")]
306impl UsageUpdate {
307    #[must_use]
308    pub fn new(used: u64, size: u64) -> Self {
309        Self {
310            used,
311            size,
312            cost: None,
313            meta: None,
314        }
315    }
316
317    /// Cumulative session cost (optional).
318    #[must_use]
319    pub fn cost(mut self, cost: impl IntoOption<Cost>) -> Self {
320        self.cost = cost.into_option();
321        self
322    }
323
324    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
325    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
326    /// these keys.
327    ///
328    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
329    #[must_use]
330    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
331        self.meta = meta.into_option();
332        self
333    }
334}
335
336/// **UNSTABLE**
337///
338/// This capability is not part of the spec yet, and may be removed or changed at any point.
339///
340/// Cost information for a session.
341#[cfg(feature = "unstable_session_usage")]
342#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq)]
343#[serde(rename_all = "camelCase")]
344#[non_exhaustive]
345pub struct Cost {
346    /// Total cumulative cost for session.
347    pub amount: f64,
348    /// ISO 4217 currency code (e.g., "USD", "EUR").
349    pub currency: String,
350}
351
352#[cfg(feature = "unstable_session_usage")]
353impl Cost {
354    #[must_use]
355    pub fn new(amount: f64, currency: impl Into<String>) -> Self {
356        Self {
357            amount,
358            currency: currency.into(),
359        }
360    }
361}
362
363/// A streamed item of content
364#[skip_serializing_none]
365#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq)]
366#[serde(rename_all = "camelCase")]
367#[non_exhaustive]
368pub struct ContentChunk {
369    /// A single item of content
370    pub content: ContentBlock,
371    /// **UNSTABLE**
372    ///
373    /// This capability is not part of the spec yet, and may be removed or changed at any point.
374    ///
375    /// A unique identifier for the message this chunk belongs to.
376    ///
377    /// All chunks belonging to the same message share the same `messageId`.
378    /// A change in `messageId` indicates a new message has started.
379    /// Both clients and agents MUST use UUID format for message IDs.
380    #[cfg(feature = "unstable_message_id")]
381    pub message_id: Option<String>,
382    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
383    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
384    /// these keys.
385    ///
386    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
387    #[serde(rename = "_meta")]
388    pub meta: Option<Meta>,
389}
390
391impl ContentChunk {
392    #[must_use]
393    pub fn new(content: ContentBlock) -> Self {
394        Self {
395            content,
396            #[cfg(feature = "unstable_message_id")]
397            message_id: None,
398            meta: None,
399        }
400    }
401
402    /// **UNSTABLE**
403    ///
404    /// This capability is not part of the spec yet, and may be removed or changed at any point.
405    ///
406    /// A unique identifier for the message this chunk belongs to.
407    ///
408    /// All chunks belonging to the same message share the same `messageId`.
409    /// A change in `messageId` indicates a new message has started.
410    /// Both clients and agents MUST use UUID format for message IDs.
411    #[cfg(feature = "unstable_message_id")]
412    #[must_use]
413    pub fn message_id(mut self, message_id: impl IntoOption<String>) -> Self {
414        self.message_id = message_id.into_option();
415        self
416    }
417
418    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
419    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
420    /// these keys.
421    ///
422    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
423    #[must_use]
424    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
425        self.meta = meta.into_option();
426        self
427    }
428}
429
430/// Available commands are ready or have changed
431#[serde_as]
432#[skip_serializing_none]
433#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
434#[serde(rename_all = "camelCase")]
435#[non_exhaustive]
436pub struct AvailableCommandsUpdate {
437    /// Commands the agent can execute
438    #[serde_as(deserialize_as = "DefaultOnError<VecSkipError<_, SkipListener>>")]
439    pub available_commands: Vec<AvailableCommand>,
440    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
441    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
442    /// these keys.
443    ///
444    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
445    #[serde(rename = "_meta")]
446    pub meta: Option<Meta>,
447}
448
449impl AvailableCommandsUpdate {
450    #[must_use]
451    pub fn new(available_commands: Vec<AvailableCommand>) -> Self {
452        Self {
453            available_commands,
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/// Information about a command.
471#[serde_as]
472#[skip_serializing_none]
473#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
474#[serde(rename_all = "camelCase")]
475#[non_exhaustive]
476pub struct AvailableCommand {
477    /// Command name (e.g., `create_plan`, `research_codebase`).
478    pub name: String,
479    /// Human-readable description of what the command does.
480    pub description: String,
481    /// Input for the command if required
482    #[serde_as(deserialize_as = "DefaultOnError")]
483    #[serde(default)]
484    pub input: Option<AvailableCommandInput>,
485    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
486    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
487    /// these keys.
488    ///
489    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
490    #[serde(rename = "_meta")]
491    pub meta: Option<Meta>,
492}
493
494impl AvailableCommand {
495    #[must_use]
496    pub fn new(name: impl Into<String>, description: impl Into<String>) -> Self {
497        Self {
498            name: name.into(),
499            description: description.into(),
500            input: None,
501            meta: None,
502        }
503    }
504
505    /// Input for the command if required
506    #[must_use]
507    pub fn input(mut self, input: impl IntoOption<AvailableCommandInput>) -> Self {
508        self.input = input.into_option();
509        self
510    }
511
512    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
513    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
514    /// these keys.
515    ///
516    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
517    #[must_use]
518    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
519        self.meta = meta.into_option();
520        self
521    }
522}
523
524/// The input specification for a command.
525#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
526#[serde(untagged, rename_all = "camelCase")]
527#[non_exhaustive]
528pub enum AvailableCommandInput {
529    /// All text that was typed after the command name is provided as input.
530    Unstructured(UnstructuredCommandInput),
531}
532
533/// All text that was typed after the command name is provided as input.
534#[skip_serializing_none]
535#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
536#[serde(rename_all = "camelCase")]
537#[non_exhaustive]
538pub struct UnstructuredCommandInput {
539    /// A hint to display when the input hasn't been provided yet
540    pub hint: String,
541    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
542    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
543    /// these keys.
544    ///
545    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
546    #[serde(rename = "_meta")]
547    pub meta: Option<Meta>,
548}
549
550impl UnstructuredCommandInput {
551    #[must_use]
552    pub fn new(hint: impl Into<String>) -> Self {
553        Self {
554            hint: hint.into(),
555            meta: None,
556        }
557    }
558
559    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
560    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
561    /// these keys.
562    ///
563    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
564    #[must_use]
565    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
566        self.meta = meta.into_option();
567        self
568    }
569}
570
571// Permission
572
573/// Request for user permission to execute a tool call.
574///
575/// Sent when the agent needs authorization before performing a sensitive operation.
576///
577/// See protocol docs: [Requesting Permission](https://agentclientprotocol.com/protocol/tool-calls#requesting-permission)
578#[skip_serializing_none]
579#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq)]
580#[schemars(extend("x-side" = "client", "x-method" = SESSION_REQUEST_PERMISSION_METHOD_NAME))]
581#[serde(rename_all = "camelCase")]
582#[non_exhaustive]
583pub struct RequestPermissionRequest {
584    /// The session ID for this request.
585    pub session_id: SessionId,
586    /// Details about the tool call requiring permission.
587    pub tool_call: ToolCallUpdate,
588    /// Available permission options for the user to choose from.
589    pub options: Vec<PermissionOption>,
590    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
591    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
592    /// these keys.
593    ///
594    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
595    #[serde(rename = "_meta")]
596    pub meta: Option<Meta>,
597}
598
599impl RequestPermissionRequest {
600    #[must_use]
601    pub fn new(
602        session_id: impl Into<SessionId>,
603        tool_call: ToolCallUpdate,
604        options: Vec<PermissionOption>,
605    ) -> Self {
606        Self {
607            session_id: session_id.into(),
608            tool_call,
609            options,
610            meta: None,
611        }
612    }
613
614    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
615    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
616    /// these keys.
617    ///
618    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
619    #[must_use]
620    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
621        self.meta = meta.into_option();
622        self
623    }
624}
625
626/// An option presented to the user when requesting permission.
627#[skip_serializing_none]
628#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
629#[serde(rename_all = "camelCase")]
630#[non_exhaustive]
631pub struct PermissionOption {
632    /// Unique identifier for this permission option.
633    pub option_id: PermissionOptionId,
634    /// Human-readable label to display to the user.
635    pub name: String,
636    /// Hint about the nature of this permission option.
637    pub kind: PermissionOptionKind,
638    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
639    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
640    /// these keys.
641    ///
642    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
643    #[serde(rename = "_meta")]
644    pub meta: Option<Meta>,
645}
646
647impl PermissionOption {
648    #[must_use]
649    pub fn new(
650        option_id: impl Into<PermissionOptionId>,
651        name: impl Into<String>,
652        kind: PermissionOptionKind,
653    ) -> Self {
654        Self {
655            option_id: option_id.into(),
656            name: name.into(),
657            kind,
658            meta: None,
659        }
660    }
661
662    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
663    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
664    /// these keys.
665    ///
666    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
667    #[must_use]
668    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
669        self.meta = meta.into_option();
670        self
671    }
672}
673
674/// Unique identifier for a permission option.
675#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq, Hash, Display, From)]
676#[serde(transparent)]
677#[from(Arc<str>, String, &'static str)]
678#[non_exhaustive]
679pub struct PermissionOptionId(pub Arc<str>);
680
681impl PermissionOptionId {
682    #[must_use]
683    pub fn new(id: impl Into<Arc<str>>) -> Self {
684        Self(id.into())
685    }
686}
687
688/// The type of permission option being presented to the user.
689///
690/// Helps clients choose appropriate icons and UI treatment.
691#[derive(Debug, Clone, Copy, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
692#[serde(rename_all = "snake_case")]
693#[non_exhaustive]
694pub enum PermissionOptionKind {
695    /// Allow this operation only this time.
696    AllowOnce,
697    /// Allow this operation and remember the choice.
698    AllowAlways,
699    /// Reject this operation only this time.
700    RejectOnce,
701    /// Reject this operation and remember the choice.
702    RejectAlways,
703}
704
705/// Response to a permission request.
706#[skip_serializing_none]
707#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
708#[schemars(extend("x-side" = "client", "x-method" = SESSION_REQUEST_PERMISSION_METHOD_NAME))]
709#[serde(rename_all = "camelCase")]
710#[non_exhaustive]
711pub struct RequestPermissionResponse {
712    /// The user's decision on the permission request.
713    // This extra-level is unfortunately needed because the output must be an object
714    pub outcome: RequestPermissionOutcome,
715    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
716    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
717    /// these keys.
718    ///
719    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
720    #[serde(rename = "_meta")]
721    pub meta: Option<Meta>,
722}
723
724impl RequestPermissionResponse {
725    #[must_use]
726    pub fn new(outcome: RequestPermissionOutcome) -> Self {
727        Self {
728            outcome,
729            meta: None,
730        }
731    }
732
733    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
734    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
735    /// these keys.
736    ///
737    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
738    #[must_use]
739    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
740        self.meta = meta.into_option();
741        self
742    }
743}
744
745/// The outcome of a permission request.
746#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
747#[serde(tag = "outcome", rename_all = "snake_case")]
748#[schemars(extend("discriminator" = {"propertyName": "outcome"}))]
749#[non_exhaustive]
750pub enum RequestPermissionOutcome {
751    /// The prompt turn was cancelled before the user responded.
752    ///
753    /// When a client sends a `session/cancel` notification to cancel an ongoing
754    /// prompt turn, it MUST respond to all pending `session/request_permission`
755    /// requests with this `Cancelled` outcome.
756    ///
757    /// See protocol docs: [Cancellation](https://agentclientprotocol.com/protocol/prompt-turn#cancellation)
758    Cancelled,
759    /// The user selected one of the provided options.
760    #[serde(rename_all = "camelCase")]
761    Selected(SelectedPermissionOutcome),
762}
763
764/// The user selected one of the provided options.
765#[skip_serializing_none]
766#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
767#[serde(rename_all = "camelCase")]
768#[non_exhaustive]
769pub struct SelectedPermissionOutcome {
770    /// The ID of the option the user selected.
771    pub option_id: PermissionOptionId,
772    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
773    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
774    /// these keys.
775    ///
776    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
777    #[serde(rename = "_meta")]
778    pub meta: Option<Meta>,
779}
780
781impl SelectedPermissionOutcome {
782    #[must_use]
783    pub fn new(option_id: impl Into<PermissionOptionId>) -> Self {
784        Self {
785            option_id: option_id.into(),
786            meta: None,
787        }
788    }
789
790    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
791    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
792    /// these keys.
793    ///
794    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
795    #[must_use]
796    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
797        self.meta = meta.into_option();
798        self
799    }
800}
801
802// Write text file
803
804/// Request to write content to a text file.
805///
806/// Only available if the client supports the `fs.writeTextFile` capability.
807#[skip_serializing_none]
808#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
809#[schemars(extend("x-side" = "client", "x-method" = FS_WRITE_TEXT_FILE_METHOD_NAME))]
810#[serde(rename_all = "camelCase")]
811#[non_exhaustive]
812pub struct WriteTextFileRequest {
813    /// The session ID for this request.
814    pub session_id: SessionId,
815    /// Absolute path to the file to write.
816    pub path: PathBuf,
817    /// The text content to write to the file.
818    pub content: String,
819    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
820    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
821    /// these keys.
822    ///
823    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
824    #[serde(rename = "_meta")]
825    pub meta: Option<Meta>,
826}
827
828impl WriteTextFileRequest {
829    #[must_use]
830    pub fn new(
831        session_id: impl Into<SessionId>,
832        path: impl Into<PathBuf>,
833        content: impl Into<String>,
834    ) -> Self {
835        Self {
836            session_id: session_id.into(),
837            path: path.into(),
838            content: content.into(),
839            meta: None,
840        }
841    }
842
843    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
844    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
845    /// these keys.
846    ///
847    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
848    #[must_use]
849    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
850        self.meta = meta.into_option();
851        self
852    }
853}
854
855/// Response to `fs/write_text_file`
856#[skip_serializing_none]
857#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
858#[serde(rename_all = "camelCase")]
859#[schemars(extend("x-side" = "client", "x-method" = FS_WRITE_TEXT_FILE_METHOD_NAME))]
860#[non_exhaustive]
861pub struct WriteTextFileResponse {
862    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
863    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
864    /// these keys.
865    ///
866    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
867    #[serde(rename = "_meta")]
868    pub meta: Option<Meta>,
869}
870
871impl WriteTextFileResponse {
872    #[must_use]
873    pub fn new() -> Self {
874        Self::default()
875    }
876
877    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
878    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
879    /// these keys.
880    ///
881    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
882    #[must_use]
883    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
884        self.meta = meta.into_option();
885        self
886    }
887}
888
889// Read text file
890
891/// Request to read content from a text file.
892///
893/// Only available if the client supports the `fs.readTextFile` capability.
894#[skip_serializing_none]
895#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
896#[schemars(extend("x-side" = "client", "x-method" = FS_READ_TEXT_FILE_METHOD_NAME))]
897#[serde(rename_all = "camelCase")]
898#[non_exhaustive]
899pub struct ReadTextFileRequest {
900    /// The session ID for this request.
901    pub session_id: SessionId,
902    /// Absolute path to the file to read.
903    pub path: PathBuf,
904    /// Line number to start reading from (1-based).
905    pub line: Option<u32>,
906    /// Maximum number of lines to read.
907    pub limit: Option<u32>,
908    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
909    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
910    /// these keys.
911    ///
912    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
913    #[serde(rename = "_meta")]
914    pub meta: Option<Meta>,
915}
916
917impl ReadTextFileRequest {
918    #[must_use]
919    pub fn new(session_id: impl Into<SessionId>, path: impl Into<PathBuf>) -> Self {
920        Self {
921            session_id: session_id.into(),
922            path: path.into(),
923            line: None,
924            limit: None,
925            meta: None,
926        }
927    }
928
929    /// Line number to start reading from (1-based).
930    #[must_use]
931    pub fn line(mut self, line: impl IntoOption<u32>) -> Self {
932        self.line = line.into_option();
933        self
934    }
935
936    /// Maximum number of lines to read.
937    #[must_use]
938    pub fn limit(mut self, limit: impl IntoOption<u32>) -> Self {
939        self.limit = limit.into_option();
940        self
941    }
942
943    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
944    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
945    /// these keys.
946    ///
947    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
948    #[must_use]
949    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
950        self.meta = meta.into_option();
951        self
952    }
953}
954
955/// Response containing the contents of a text file.
956#[skip_serializing_none]
957#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
958#[schemars(extend("x-side" = "client", "x-method" = FS_READ_TEXT_FILE_METHOD_NAME))]
959#[serde(rename_all = "camelCase")]
960#[non_exhaustive]
961pub struct ReadTextFileResponse {
962    pub content: String,
963    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
964    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
965    /// these keys.
966    ///
967    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
968    #[serde(rename = "_meta")]
969    pub meta: Option<Meta>,
970}
971
972impl ReadTextFileResponse {
973    #[must_use]
974    pub fn new(content: impl Into<String>) -> Self {
975        Self {
976            content: content.into(),
977            meta: None,
978        }
979    }
980
981    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
982    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
983    /// these keys.
984    ///
985    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
986    #[must_use]
987    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
988        self.meta = meta.into_option();
989        self
990    }
991}
992
993// Terminals
994
995#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq, Hash, Display, From)]
996#[serde(transparent)]
997#[from(Arc<str>, String, &'static str)]
998#[non_exhaustive]
999pub struct TerminalId(pub Arc<str>);
1000
1001impl TerminalId {
1002    #[must_use]
1003    pub fn new(id: impl Into<Arc<str>>) -> Self {
1004        Self(id.into())
1005    }
1006}
1007
1008/// Request to create a new terminal and execute a command.
1009#[skip_serializing_none]
1010#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1011#[serde(rename_all = "camelCase")]
1012#[schemars(extend("x-side" = "client", "x-method" = TERMINAL_CREATE_METHOD_NAME))]
1013#[non_exhaustive]
1014pub struct CreateTerminalRequest {
1015    /// The session ID for this request.
1016    pub session_id: SessionId,
1017    /// The command to execute.
1018    pub command: String,
1019    /// Array of command arguments.
1020    #[serde(default, skip_serializing_if = "Vec::is_empty")]
1021    pub args: Vec<String>,
1022    /// Environment variables for the command.
1023    #[serde(default, skip_serializing_if = "Vec::is_empty")]
1024    pub env: Vec<EnvVariable>,
1025    /// Working directory for the command (absolute path).
1026    pub cwd: Option<PathBuf>,
1027    /// Maximum number of output bytes to retain.
1028    ///
1029    /// When the limit is exceeded, the Client truncates from the beginning of the output
1030    /// to stay within the limit.
1031    ///
1032    /// The Client MUST ensure truncation happens at a character boundary to maintain valid
1033    /// string output, even if this means the retained output is slightly less than the
1034    /// specified limit.
1035    pub output_byte_limit: Option<u64>,
1036    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1037    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1038    /// these keys.
1039    ///
1040    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1041    #[serde(rename = "_meta")]
1042    pub meta: Option<Meta>,
1043}
1044
1045impl CreateTerminalRequest {
1046    #[must_use]
1047    pub fn new(session_id: impl Into<SessionId>, command: impl Into<String>) -> Self {
1048        Self {
1049            session_id: session_id.into(),
1050            command: command.into(),
1051            args: Vec::new(),
1052            env: Vec::new(),
1053            cwd: None,
1054            output_byte_limit: None,
1055            meta: None,
1056        }
1057    }
1058
1059    /// Array of command arguments.
1060    #[must_use]
1061    pub fn args(mut self, args: Vec<String>) -> Self {
1062        self.args = args;
1063        self
1064    }
1065
1066    /// Environment variables for the command.
1067    #[must_use]
1068    pub fn env(mut self, env: Vec<EnvVariable>) -> Self {
1069        self.env = env;
1070        self
1071    }
1072
1073    /// Working directory for the command (absolute path).
1074    #[must_use]
1075    pub fn cwd(mut self, cwd: impl IntoOption<PathBuf>) -> Self {
1076        self.cwd = cwd.into_option();
1077        self
1078    }
1079
1080    /// Maximum number of output bytes to retain.
1081    ///
1082    /// When the limit is exceeded, the Client truncates from the beginning of the output
1083    /// to stay within the limit.
1084    ///
1085    /// The Client MUST ensure truncation happens at a character boundary to maintain valid
1086    /// string output, even if this means the retained output is slightly less than the
1087    /// specified limit.
1088    #[must_use]
1089    pub fn output_byte_limit(mut self, output_byte_limit: impl IntoOption<u64>) -> Self {
1090        self.output_byte_limit = output_byte_limit.into_option();
1091        self
1092    }
1093
1094    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1095    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1096    /// these keys.
1097    ///
1098    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1099    #[must_use]
1100    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1101        self.meta = meta.into_option();
1102        self
1103    }
1104}
1105
1106/// Response containing the ID of the created terminal.
1107#[skip_serializing_none]
1108#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1109#[serde(rename_all = "camelCase")]
1110#[schemars(extend("x-side" = "client", "x-method" = TERMINAL_CREATE_METHOD_NAME))]
1111#[non_exhaustive]
1112pub struct CreateTerminalResponse {
1113    /// The unique identifier for the created terminal.
1114    pub terminal_id: TerminalId,
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(rename = "_meta")]
1121    pub meta: Option<Meta>,
1122}
1123
1124impl CreateTerminalResponse {
1125    #[must_use]
1126    pub fn new(terminal_id: impl Into<TerminalId>) -> Self {
1127        Self {
1128            terminal_id: terminal_id.into(),
1129            meta: None,
1130        }
1131    }
1132
1133    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1134    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1135    /// these keys.
1136    ///
1137    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1138    #[must_use]
1139    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1140        self.meta = meta.into_option();
1141        self
1142    }
1143}
1144
1145/// Request to get the current output and status of a terminal.
1146#[skip_serializing_none]
1147#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1148#[serde(rename_all = "camelCase")]
1149#[schemars(extend("x-side" = "client", "x-method" = TERMINAL_OUTPUT_METHOD_NAME))]
1150#[non_exhaustive]
1151pub struct TerminalOutputRequest {
1152    /// The session ID for this request.
1153    pub session_id: SessionId,
1154    /// The ID of the terminal to get output from.
1155    pub terminal_id: TerminalId,
1156    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1157    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1158    /// these keys.
1159    ///
1160    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1161    #[serde(rename = "_meta")]
1162    pub meta: Option<Meta>,
1163}
1164
1165impl TerminalOutputRequest {
1166    #[must_use]
1167    pub fn new(session_id: impl Into<SessionId>, terminal_id: impl Into<TerminalId>) -> Self {
1168        Self {
1169            session_id: session_id.into(),
1170            terminal_id: terminal_id.into(),
1171            meta: None,
1172        }
1173    }
1174
1175    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1176    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1177    /// these keys.
1178    ///
1179    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1180    #[must_use]
1181    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1182        self.meta = meta.into_option();
1183        self
1184    }
1185}
1186
1187/// Response containing the terminal output and exit status.
1188#[skip_serializing_none]
1189#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1190#[serde(rename_all = "camelCase")]
1191#[schemars(extend("x-side" = "client", "x-method" = TERMINAL_OUTPUT_METHOD_NAME))]
1192#[non_exhaustive]
1193pub struct TerminalOutputResponse {
1194    /// The terminal output captured so far.
1195    pub output: String,
1196    /// Whether the output was truncated due to byte limits.
1197    pub truncated: bool,
1198    /// Exit status if the command has completed.
1199    pub exit_status: Option<TerminalExitStatus>,
1200    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1201    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1202    /// these keys.
1203    ///
1204    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1205    #[serde(rename = "_meta")]
1206    pub meta: Option<Meta>,
1207}
1208
1209impl TerminalOutputResponse {
1210    #[must_use]
1211    pub fn new(output: impl Into<String>, truncated: bool) -> Self {
1212        Self {
1213            output: output.into(),
1214            truncated,
1215            exit_status: None,
1216            meta: None,
1217        }
1218    }
1219
1220    /// Exit status if the command has completed.
1221    #[must_use]
1222    pub fn exit_status(mut self, exit_status: impl IntoOption<TerminalExitStatus>) -> Self {
1223        self.exit_status = exit_status.into_option();
1224        self
1225    }
1226
1227    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1228    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1229    /// these keys.
1230    ///
1231    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1232    #[must_use]
1233    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1234        self.meta = meta.into_option();
1235        self
1236    }
1237}
1238
1239/// Request to release a terminal and free its resources.
1240#[skip_serializing_none]
1241#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1242#[serde(rename_all = "camelCase")]
1243#[schemars(extend("x-side" = "client", "x-method" = TERMINAL_RELEASE_METHOD_NAME))]
1244#[non_exhaustive]
1245pub struct ReleaseTerminalRequest {
1246    /// The session ID for this request.
1247    pub session_id: SessionId,
1248    /// The ID of the terminal to release.
1249    pub terminal_id: TerminalId,
1250    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1251    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1252    /// these keys.
1253    ///
1254    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1255    #[serde(rename = "_meta")]
1256    pub meta: Option<Meta>,
1257}
1258
1259impl ReleaseTerminalRequest {
1260    #[must_use]
1261    pub fn new(session_id: impl Into<SessionId>, terminal_id: impl Into<TerminalId>) -> Self {
1262        Self {
1263            session_id: session_id.into(),
1264            terminal_id: terminal_id.into(),
1265            meta: None,
1266        }
1267    }
1268
1269    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1270    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1271    /// these keys.
1272    ///
1273    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1274    #[must_use]
1275    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1276        self.meta = meta.into_option();
1277        self
1278    }
1279}
1280
1281/// Response to terminal/release method
1282#[skip_serializing_none]
1283#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1284#[serde(rename_all = "camelCase")]
1285#[schemars(extend("x-side" = "client", "x-method" = TERMINAL_RELEASE_METHOD_NAME))]
1286#[non_exhaustive]
1287pub struct ReleaseTerminalResponse {
1288    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1289    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1290    /// these keys.
1291    ///
1292    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1293    #[serde(rename = "_meta")]
1294    pub meta: Option<Meta>,
1295}
1296
1297impl ReleaseTerminalResponse {
1298    #[must_use]
1299    pub fn new() -> Self {
1300        Self::default()
1301    }
1302
1303    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1304    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1305    /// these keys.
1306    ///
1307    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1308    #[must_use]
1309    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1310        self.meta = meta.into_option();
1311        self
1312    }
1313}
1314
1315/// Request to kill a terminal without releasing it.
1316#[skip_serializing_none]
1317#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1318#[serde(rename_all = "camelCase")]
1319#[schemars(extend("x-side" = "client", "x-method" = TERMINAL_KILL_METHOD_NAME))]
1320#[non_exhaustive]
1321pub struct KillTerminalRequest {
1322    /// The session ID for this request.
1323    pub session_id: SessionId,
1324    /// The ID of the terminal to kill.
1325    pub terminal_id: TerminalId,
1326    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1327    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1328    /// these keys.
1329    ///
1330    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1331    #[serde(rename = "_meta")]
1332    pub meta: Option<Meta>,
1333}
1334
1335impl KillTerminalRequest {
1336    #[must_use]
1337    pub fn new(session_id: impl Into<SessionId>, terminal_id: impl Into<TerminalId>) -> Self {
1338        Self {
1339            session_id: session_id.into(),
1340            terminal_id: terminal_id.into(),
1341            meta: None,
1342        }
1343    }
1344
1345    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1346    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1347    /// these keys.
1348    ///
1349    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1350    #[must_use]
1351    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1352        self.meta = meta.into_option();
1353        self
1354    }
1355}
1356
1357/// Response to `terminal/kill` method
1358#[skip_serializing_none]
1359#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1360#[serde(rename_all = "camelCase")]
1361#[schemars(extend("x-side" = "client", "x-method" = TERMINAL_KILL_METHOD_NAME))]
1362#[non_exhaustive]
1363pub struct KillTerminalResponse {
1364    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1365    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1366    /// these keys.
1367    ///
1368    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1369    #[serde(rename = "_meta")]
1370    pub meta: Option<Meta>,
1371}
1372
1373impl KillTerminalResponse {
1374    #[must_use]
1375    pub fn new() -> Self {
1376        Self::default()
1377    }
1378
1379    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1380    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1381    /// these keys.
1382    ///
1383    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1384    #[must_use]
1385    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1386        self.meta = meta.into_option();
1387        self
1388    }
1389}
1390
1391/// Request to wait for a terminal command to exit.
1392#[skip_serializing_none]
1393#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1394#[serde(rename_all = "camelCase")]
1395#[schemars(extend("x-side" = "client", "x-method" = TERMINAL_WAIT_FOR_EXIT_METHOD_NAME))]
1396#[non_exhaustive]
1397pub struct WaitForTerminalExitRequest {
1398    /// The session ID for this request.
1399    pub session_id: SessionId,
1400    /// The ID of the terminal to wait for.
1401    pub terminal_id: TerminalId,
1402    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1403    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1404    /// these keys.
1405    ///
1406    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1407    #[serde(rename = "_meta")]
1408    pub meta: Option<Meta>,
1409}
1410
1411impl WaitForTerminalExitRequest {
1412    #[must_use]
1413    pub fn new(session_id: impl Into<SessionId>, terminal_id: impl Into<TerminalId>) -> Self {
1414        Self {
1415            session_id: session_id.into(),
1416            terminal_id: terminal_id.into(),
1417            meta: None,
1418        }
1419    }
1420
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    #[must_use]
1427    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1428        self.meta = meta.into_option();
1429        self
1430    }
1431}
1432
1433/// Response containing the exit status of a terminal command.
1434#[skip_serializing_none]
1435#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1436#[serde(rename_all = "camelCase")]
1437#[schemars(extend("x-side" = "client", "x-method" = TERMINAL_WAIT_FOR_EXIT_METHOD_NAME))]
1438#[non_exhaustive]
1439pub struct WaitForTerminalExitResponse {
1440    /// The exit status of the terminal command.
1441    #[serde(flatten)]
1442    pub exit_status: TerminalExitStatus,
1443    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1444    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1445    /// these keys.
1446    ///
1447    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1448    #[serde(rename = "_meta")]
1449    pub meta: Option<Meta>,
1450}
1451
1452impl WaitForTerminalExitResponse {
1453    #[must_use]
1454    pub fn new(exit_status: TerminalExitStatus) -> Self {
1455        Self {
1456            exit_status,
1457            meta: None,
1458        }
1459    }
1460
1461    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1462    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1463    /// these keys.
1464    ///
1465    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1466    #[must_use]
1467    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1468        self.meta = meta.into_option();
1469        self
1470    }
1471}
1472
1473/// Exit status of a terminal command.
1474#[skip_serializing_none]
1475#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1476#[serde(rename_all = "camelCase")]
1477#[non_exhaustive]
1478pub struct TerminalExitStatus {
1479    /// The process exit code (may be null if terminated by signal).
1480    pub exit_code: Option<u32>,
1481    /// The signal that terminated the process (may be null if exited normally).
1482    pub signal: Option<String>,
1483    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1484    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1485    /// these keys.
1486    ///
1487    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1488    #[serde(rename = "_meta")]
1489    pub meta: Option<Meta>,
1490}
1491
1492impl TerminalExitStatus {
1493    #[must_use]
1494    pub fn new() -> Self {
1495        Self::default()
1496    }
1497
1498    /// The process exit code (may be null if terminated by signal).
1499    #[must_use]
1500    pub fn exit_code(mut self, exit_code: impl IntoOption<u32>) -> Self {
1501        self.exit_code = exit_code.into_option();
1502        self
1503    }
1504
1505    /// The signal that terminated the process (may be null if exited normally).
1506    #[must_use]
1507    pub fn signal(mut self, signal: impl IntoOption<String>) -> Self {
1508        self.signal = signal.into_option();
1509        self
1510    }
1511
1512    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1513    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1514    /// these keys.
1515    ///
1516    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1517    #[must_use]
1518    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1519        self.meta = meta.into_option();
1520        self
1521    }
1522}
1523
1524// Capabilities
1525
1526/// Capabilities supported by the client.
1527///
1528/// Advertised during initialization to inform the agent about
1529/// available features and methods.
1530///
1531/// See protocol docs: [Client Capabilities](https://agentclientprotocol.com/protocol/initialization#client-capabilities)
1532#[serde_as]
1533#[skip_serializing_none]
1534#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1535#[serde(rename_all = "camelCase")]
1536#[non_exhaustive]
1537pub struct ClientCapabilities {
1538    /// File system capabilities supported by the client.
1539    /// Determines which file operations the agent can request.
1540    #[serde(default)]
1541    pub fs: FileSystemCapabilities,
1542    /// Whether the Client support all `terminal/*` methods.
1543    #[serde(default)]
1544    pub terminal: bool,
1545    /// **UNSTABLE**
1546    ///
1547    /// This capability is not part of the spec yet, and may be removed or changed at any point.
1548    ///
1549    /// Whether the client supports `plan_update` and `plan_removed` session updates.
1550    ///
1551    /// Optional. Omitted means the client does not advertise support.
1552    /// Supplying `{}` means the client can receive both update types.
1553    #[cfg(feature = "unstable_plan_operations")]
1554    #[serde_as(deserialize_as = "DefaultOnError")]
1555    #[serde(default)]
1556    pub plan_capabilities: Option<PlanCapabilities>,
1557    /// **UNSTABLE**
1558    ///
1559    /// This capability is not part of the spec yet, and may be removed or changed at any point.
1560    ///
1561    /// Authentication capabilities supported by the client.
1562    /// Determines which authentication method types the agent may include
1563    /// in its `InitializeResponse`.
1564    #[cfg(feature = "unstable_auth_methods")]
1565    #[serde(default)]
1566    pub auth: AuthCapabilities,
1567    /// **UNSTABLE**
1568    ///
1569    /// This capability is not part of the spec yet, and may be removed or changed at any point.
1570    ///
1571    /// Elicitation capabilities supported by the client.
1572    /// Determines which elicitation modes the agent may use.
1573    #[cfg(feature = "unstable_elicitation")]
1574    #[serde_as(deserialize_as = "DefaultOnError")]
1575    #[serde(default)]
1576    pub elicitation: Option<ElicitationCapabilities>,
1577    /// **UNSTABLE**
1578    ///
1579    /// This capability is not part of the spec yet, and may be removed or changed at any point.
1580    ///
1581    /// NES (Next Edit Suggestions) capabilities supported by the client.
1582    #[cfg(feature = "unstable_nes")]
1583    #[serde_as(deserialize_as = "DefaultOnError")]
1584    #[serde(default)]
1585    pub nes: Option<ClientNesCapabilities>,
1586    /// **UNSTABLE**
1587    ///
1588    /// This capability is not part of the spec yet, and may be removed or changed at any point.
1589    ///
1590    /// The position encodings supported by the client, in order of preference.
1591    #[cfg(feature = "unstable_nes")]
1592    #[serde_as(deserialize_as = "DefaultOnError<VecSkipError<_, SkipListener>>")]
1593    #[serde(default, skip_serializing_if = "Vec::is_empty")]
1594    pub position_encodings: Vec<PositionEncodingKind>,
1595
1596    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1597    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1598    /// these keys.
1599    ///
1600    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1601    #[serde(rename = "_meta")]
1602    pub meta: Option<Meta>,
1603}
1604
1605impl ClientCapabilities {
1606    #[must_use]
1607    pub fn new() -> Self {
1608        Self::default()
1609    }
1610
1611    /// File system capabilities supported by the client.
1612    /// Determines which file operations the agent can request.
1613    #[must_use]
1614    pub fn fs(mut self, fs: FileSystemCapabilities) -> Self {
1615        self.fs = fs;
1616        self
1617    }
1618
1619    /// Whether the Client support all `terminal/*` methods.
1620    #[must_use]
1621    pub fn terminal(mut self, terminal: bool) -> Self {
1622        self.terminal = terminal;
1623        self
1624    }
1625
1626    /// **UNSTABLE**
1627    ///
1628    /// This capability is not part of the spec yet, and may be removed or changed at any point.
1629    ///
1630    /// Whether the client supports `plan_update` and `plan_removed` session updates.
1631    ///
1632    /// Omitted means the client does not advertise support.
1633    /// Supplying `{}` means the client can receive both update types.
1634    #[cfg(feature = "unstable_plan_operations")]
1635    #[must_use]
1636    pub fn plan_capabilities(
1637        mut self,
1638        plan_capabilities: impl IntoOption<PlanCapabilities>,
1639    ) -> Self {
1640        self.plan_capabilities = plan_capabilities.into_option();
1641        self
1642    }
1643
1644    /// **UNSTABLE**
1645    ///
1646    /// This capability is not part of the spec yet, and may be removed or changed at any point.
1647    ///
1648    /// Authentication capabilities supported by the client.
1649    /// Determines which authentication method types the agent may include
1650    /// in its `InitializeResponse`.
1651    #[cfg(feature = "unstable_auth_methods")]
1652    #[must_use]
1653    pub fn auth(mut self, auth: AuthCapabilities) -> Self {
1654        self.auth = auth;
1655        self
1656    }
1657
1658    /// **UNSTABLE**
1659    ///
1660    /// This capability is not part of the spec yet, and may be removed or changed at any point.
1661    ///
1662    /// Elicitation capabilities supported by the client.
1663    /// Determines which elicitation modes the agent may use.
1664    #[cfg(feature = "unstable_elicitation")]
1665    #[must_use]
1666    pub fn elicitation(mut self, elicitation: impl IntoOption<ElicitationCapabilities>) -> Self {
1667        self.elicitation = elicitation.into_option();
1668        self
1669    }
1670
1671    /// **UNSTABLE**
1672    ///
1673    /// NES (Next Edit Suggestions) capabilities supported by the client.
1674    #[cfg(feature = "unstable_nes")]
1675    #[must_use]
1676    pub fn nes(mut self, nes: impl IntoOption<ClientNesCapabilities>) -> Self {
1677        self.nes = nes.into_option();
1678        self
1679    }
1680
1681    /// **UNSTABLE**
1682    ///
1683    /// The position encodings supported by the client, in order of preference.
1684    #[cfg(feature = "unstable_nes")]
1685    #[must_use]
1686    pub fn position_encodings(mut self, position_encodings: Vec<PositionEncodingKind>) -> Self {
1687        self.position_encodings = position_encodings;
1688        self
1689    }
1690
1691    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1692    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1693    /// these keys.
1694    ///
1695    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1696    #[must_use]
1697    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1698        self.meta = meta.into_option();
1699        self
1700    }
1701}
1702
1703/// **UNSTABLE**
1704///
1705/// This capability is not part of the spec yet, and may be removed or changed at any point.
1706///
1707/// Authentication capabilities supported by the client.
1708///
1709/// Advertised during initialization to inform the agent which authentication
1710/// method types the client can handle. This governs opt-in types that require
1711/// additional client-side support.
1712#[cfg(feature = "unstable_auth_methods")]
1713#[skip_serializing_none]
1714#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1715#[serde(rename_all = "camelCase")]
1716#[non_exhaustive]
1717pub struct AuthCapabilities {
1718    /// Whether the client supports `terminal` authentication methods.
1719    ///
1720    /// When `true`, the agent may include `terminal` entries in its authentication methods.
1721    #[serde(default)]
1722    pub terminal: bool,
1723    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1724    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1725    /// these keys.
1726    ///
1727    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1728    #[serde(rename = "_meta")]
1729    pub meta: Option<Meta>,
1730}
1731
1732#[cfg(feature = "unstable_auth_methods")]
1733impl AuthCapabilities {
1734    #[must_use]
1735    pub fn new() -> Self {
1736        Self::default()
1737    }
1738
1739    /// Whether the client supports `terminal` authentication methods.
1740    ///
1741    /// When `true`, the agent may include `AuthMethod::Terminal`
1742    /// entries in its authentication methods.
1743    #[must_use]
1744    pub fn terminal(mut self, terminal: bool) -> Self {
1745        self.terminal = terminal;
1746        self
1747    }
1748
1749    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1750    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1751    /// these keys.
1752    ///
1753    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1754    #[must_use]
1755    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1756        self.meta = meta.into_option();
1757        self
1758    }
1759}
1760
1761/// File system capabilities that a client may support.
1762///
1763/// See protocol docs: [FileSystem](https://agentclientprotocol.com/protocol/initialization#filesystem)
1764#[skip_serializing_none]
1765#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1766#[serde(rename_all = "camelCase")]
1767#[non_exhaustive]
1768pub struct FileSystemCapabilities {
1769    /// Whether the Client supports `fs/read_text_file` requests.
1770    #[serde(default)]
1771    pub read_text_file: bool,
1772    /// Whether the Client supports `fs/write_text_file` requests.
1773    #[serde(default)]
1774    pub write_text_file: bool,
1775    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1776    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1777    /// these keys.
1778    ///
1779    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1780    #[serde(rename = "_meta")]
1781    pub meta: Option<Meta>,
1782}
1783
1784impl FileSystemCapabilities {
1785    #[must_use]
1786    pub fn new() -> Self {
1787        Self::default()
1788    }
1789
1790    /// Whether the Client supports `fs/read_text_file` requests.
1791    #[must_use]
1792    pub fn read_text_file(mut self, read_text_file: bool) -> Self {
1793        self.read_text_file = read_text_file;
1794        self
1795    }
1796
1797    /// Whether the Client supports `fs/write_text_file` requests.
1798    #[must_use]
1799    pub fn write_text_file(mut self, write_text_file: bool) -> Self {
1800        self.write_text_file = write_text_file;
1801        self
1802    }
1803
1804    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1805    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1806    /// these keys.
1807    ///
1808    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1809    #[must_use]
1810    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1811        self.meta = meta.into_option();
1812        self
1813    }
1814}
1815
1816// Method schema
1817
1818/// Names of all methods that clients handle.
1819///
1820/// Provides a centralized definition of method names used in the protocol.
1821#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
1822#[non_exhaustive]
1823pub struct ClientMethodNames {
1824    /// Method for requesting permission from the user.
1825    pub session_request_permission: &'static str,
1826    /// Notification for session updates.
1827    pub session_update: &'static str,
1828    /// Method for writing text files.
1829    pub fs_write_text_file: &'static str,
1830    /// Method for reading text files.
1831    pub fs_read_text_file: &'static str,
1832    /// Method for creating new terminals.
1833    pub terminal_create: &'static str,
1834    /// Method for getting terminals output.
1835    pub terminal_output: &'static str,
1836    /// Method for releasing a terminal.
1837    pub terminal_release: &'static str,
1838    /// Method for waiting for a terminal to finish.
1839    pub terminal_wait_for_exit: &'static str,
1840    /// Method for killing a terminal.
1841    pub terminal_kill: &'static str,
1842    /// Method for opening an MCP-over-ACP connection.
1843    #[cfg(feature = "unstable_mcp_over_acp")]
1844    pub mcp_connect: &'static str,
1845    /// Method for exchanging MCP-over-ACP messages.
1846    #[cfg(feature = "unstable_mcp_over_acp")]
1847    pub mcp_message: &'static str,
1848    /// Method for closing an MCP-over-ACP connection.
1849    #[cfg(feature = "unstable_mcp_over_acp")]
1850    pub mcp_disconnect: &'static str,
1851    /// Method for elicitation.
1852    #[cfg(feature = "unstable_elicitation")]
1853    pub elicitation_create: &'static str,
1854    /// Notification for elicitation completion.
1855    #[cfg(feature = "unstable_elicitation")]
1856    pub elicitation_complete: &'static str,
1857}
1858
1859/// Constant containing all client method names.
1860pub const CLIENT_METHOD_NAMES: ClientMethodNames = ClientMethodNames {
1861    session_update: SESSION_UPDATE_NOTIFICATION,
1862    session_request_permission: SESSION_REQUEST_PERMISSION_METHOD_NAME,
1863    fs_write_text_file: FS_WRITE_TEXT_FILE_METHOD_NAME,
1864    fs_read_text_file: FS_READ_TEXT_FILE_METHOD_NAME,
1865    terminal_create: TERMINAL_CREATE_METHOD_NAME,
1866    terminal_output: TERMINAL_OUTPUT_METHOD_NAME,
1867    terminal_release: TERMINAL_RELEASE_METHOD_NAME,
1868    terminal_wait_for_exit: TERMINAL_WAIT_FOR_EXIT_METHOD_NAME,
1869    terminal_kill: TERMINAL_KILL_METHOD_NAME,
1870    #[cfg(feature = "unstable_mcp_over_acp")]
1871    mcp_connect: MCP_CONNECT_METHOD_NAME,
1872    #[cfg(feature = "unstable_mcp_over_acp")]
1873    mcp_message: MCP_MESSAGE_METHOD_NAME,
1874    #[cfg(feature = "unstable_mcp_over_acp")]
1875    mcp_disconnect: MCP_DISCONNECT_METHOD_NAME,
1876    #[cfg(feature = "unstable_elicitation")]
1877    elicitation_create: ELICITATION_CREATE_METHOD_NAME,
1878    #[cfg(feature = "unstable_elicitation")]
1879    elicitation_complete: ELICITATION_COMPLETE_NOTIFICATION,
1880};
1881
1882/// Notification name for session updates.
1883pub(crate) const SESSION_UPDATE_NOTIFICATION: &str = "session/update";
1884/// Method name for requesting user permission.
1885pub(crate) const SESSION_REQUEST_PERMISSION_METHOD_NAME: &str = "session/request_permission";
1886/// Method name for writing text files.
1887pub(crate) const FS_WRITE_TEXT_FILE_METHOD_NAME: &str = "fs/write_text_file";
1888/// Method name for reading text files.
1889pub(crate) const FS_READ_TEXT_FILE_METHOD_NAME: &str = "fs/read_text_file";
1890/// Method name for creating a new terminal.
1891pub(crate) const TERMINAL_CREATE_METHOD_NAME: &str = "terminal/create";
1892/// Method for getting terminals output.
1893pub(crate) const TERMINAL_OUTPUT_METHOD_NAME: &str = "terminal/output";
1894/// Method for releasing a terminal.
1895pub(crate) const TERMINAL_RELEASE_METHOD_NAME: &str = "terminal/release";
1896/// Method for waiting for a terminal to finish.
1897pub(crate) const TERMINAL_WAIT_FOR_EXIT_METHOD_NAME: &str = "terminal/wait_for_exit";
1898/// Method for killing a terminal.
1899pub(crate) const TERMINAL_KILL_METHOD_NAME: &str = "terminal/kill";
1900/// Method name for elicitation.
1901#[cfg(feature = "unstable_elicitation")]
1902pub(crate) const ELICITATION_CREATE_METHOD_NAME: &str = "elicitation/create";
1903/// Notification name for elicitation completion.
1904#[cfg(feature = "unstable_elicitation")]
1905pub(crate) const ELICITATION_COMPLETE_NOTIFICATION: &str = "elicitation/complete";
1906
1907/// All possible requests that an agent can send to a client.
1908///
1909/// This enum is used internally for routing RPC requests. You typically won't need
1910/// to use this directly.
1911///
1912/// This enum encompasses all method calls from agent to client.
1913#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
1914#[serde(untagged)]
1915#[schemars(inline)]
1916#[non_exhaustive]
1917pub enum AgentRequest {
1918    /// Writes content to a text file in the client's file system.
1919    ///
1920    /// Only available if the client advertises the `fs.writeTextFile` capability.
1921    /// Allows the agent to create or modify files within the client's environment.
1922    ///
1923    /// See protocol docs: [Client](https://agentclientprotocol.com/protocol/overview#client)
1924    WriteTextFileRequest(WriteTextFileRequest),
1925    /// Reads content from a text file in the client's file system.
1926    ///
1927    /// Only available if the client advertises the `fs.readTextFile` capability.
1928    /// Allows the agent to access file contents within the client's environment.
1929    ///
1930    /// See protocol docs: [Client](https://agentclientprotocol.com/protocol/overview#client)
1931    ReadTextFileRequest(ReadTextFileRequest),
1932    /// Requests permission from the user for a tool call operation.
1933    ///
1934    /// Called by the agent when it needs user authorization before executing
1935    /// a potentially sensitive operation. The client should present the options
1936    /// to the user and return their decision.
1937    ///
1938    /// If the client cancels the prompt turn via `session/cancel`, it MUST
1939    /// respond to this request with `RequestPermissionOutcome::Cancelled`.
1940    ///
1941    /// See protocol docs: [Requesting Permission](https://agentclientprotocol.com/protocol/tool-calls#requesting-permission)
1942    RequestPermissionRequest(RequestPermissionRequest),
1943    /// Executes a command in a new terminal
1944    ///
1945    /// Only available if the `terminal` Client capability is set to `true`.
1946    ///
1947    /// Returns a `TerminalId` that can be used with other terminal methods
1948    /// to get the current output, wait for exit, and kill the command.
1949    ///
1950    /// The `TerminalId` can also be used to embed the terminal in a tool call
1951    /// by using the `ToolCallContent::Terminal` variant.
1952    ///
1953    /// The Agent is responsible for releasing the terminal by using the `terminal/release`
1954    /// method.
1955    ///
1956    /// See protocol docs: [Terminals](https://agentclientprotocol.com/protocol/terminals)
1957    CreateTerminalRequest(CreateTerminalRequest),
1958    /// Gets the terminal output and exit status
1959    ///
1960    /// Returns the current content in the terminal without waiting for the command to exit.
1961    /// If the command has already exited, the exit status is included.
1962    ///
1963    /// See protocol docs: [Terminals](https://agentclientprotocol.com/protocol/terminals)
1964    TerminalOutputRequest(TerminalOutputRequest),
1965    /// Releases a terminal
1966    ///
1967    /// The command is killed if it hasn't exited yet. Use `terminal/wait_for_exit`
1968    /// to wait for the command to exit before releasing the terminal.
1969    ///
1970    /// After release, the `TerminalId` can no longer be used with other `terminal/*` methods,
1971    /// but tool calls that already contain it, continue to display its output.
1972    ///
1973    /// The `terminal/kill` method can be used to terminate the command without releasing
1974    /// the terminal, allowing the Agent to call `terminal/output` and other methods.
1975    ///
1976    /// See protocol docs: [Terminals](https://agentclientprotocol.com/protocol/terminals)
1977    ReleaseTerminalRequest(ReleaseTerminalRequest),
1978    /// Waits for the terminal command to exit and return its exit status
1979    ///
1980    /// See protocol docs: [Terminals](https://agentclientprotocol.com/protocol/terminals)
1981    WaitForTerminalExitRequest(WaitForTerminalExitRequest),
1982    /// Kills the terminal command without releasing the terminal
1983    ///
1984    /// While `terminal/release` will also kill the command, this method will keep
1985    /// the `TerminalId` valid so it can be used with other methods.
1986    ///
1987    /// This method can be helpful when implementing command timeouts which terminate
1988    /// the command as soon as elapsed, and then get the final output so it can be sent
1989    /// to the model.
1990    ///
1991    /// Note: Call `terminal/release` when `TerminalId` is no longer needed.
1992    ///
1993    /// See protocol docs: [Terminals](https://agentclientprotocol.com/protocol/terminals)
1994    KillTerminalRequest(KillTerminalRequest),
1995    /// **UNSTABLE**
1996    ///
1997    /// This capability is not part of the spec yet, and may be removed or changed at any point.
1998    ///
1999    /// Requests structured user input via a form or URL.
2000    #[cfg(feature = "unstable_elicitation")]
2001    CreateElicitationRequest(CreateElicitationRequest),
2002    /// **UNSTABLE**
2003    ///
2004    /// This capability is not part of the spec yet, and may be removed or changed at any point.
2005    ///
2006    /// Opens an MCP-over-ACP connection.
2007    #[cfg(feature = "unstable_mcp_over_acp")]
2008    ConnectMcpRequest(ConnectMcpRequest),
2009    /// **UNSTABLE**
2010    ///
2011    /// This capability is not part of the spec yet, and may be removed or changed at any point.
2012    ///
2013    /// Exchanges an MCP-over-ACP message.
2014    #[cfg(feature = "unstable_mcp_over_acp")]
2015    MessageMcpRequest(MessageMcpRequest),
2016    /// **UNSTABLE**
2017    ///
2018    /// This capability is not part of the spec yet, and may be removed or changed at any point.
2019    ///
2020    /// Closes an MCP-over-ACP connection.
2021    #[cfg(feature = "unstable_mcp_over_acp")]
2022    DisconnectMcpRequest(DisconnectMcpRequest),
2023    /// Handles extension method requests from the agent.
2024    ///
2025    /// Allows the Agent to send an arbitrary request that is not part of the ACP spec.
2026    /// Extension methods provide a way to add custom functionality while maintaining
2027    /// protocol compatibility.
2028    ///
2029    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
2030    ExtMethodRequest(ExtRequest),
2031}
2032
2033impl AgentRequest {
2034    /// Returns the corresponding method name of the request.
2035    #[must_use]
2036    pub fn method(&self) -> &str {
2037        match self {
2038            Self::WriteTextFileRequest(_) => CLIENT_METHOD_NAMES.fs_write_text_file,
2039            Self::ReadTextFileRequest(_) => CLIENT_METHOD_NAMES.fs_read_text_file,
2040            Self::RequestPermissionRequest(_) => CLIENT_METHOD_NAMES.session_request_permission,
2041            Self::CreateTerminalRequest(_) => CLIENT_METHOD_NAMES.terminal_create,
2042            Self::TerminalOutputRequest(_) => CLIENT_METHOD_NAMES.terminal_output,
2043            Self::ReleaseTerminalRequest(_) => CLIENT_METHOD_NAMES.terminal_release,
2044            Self::WaitForTerminalExitRequest(_) => CLIENT_METHOD_NAMES.terminal_wait_for_exit,
2045            Self::KillTerminalRequest(_) => CLIENT_METHOD_NAMES.terminal_kill,
2046            #[cfg(feature = "unstable_elicitation")]
2047            Self::CreateElicitationRequest(_) => CLIENT_METHOD_NAMES.elicitation_create,
2048            #[cfg(feature = "unstable_mcp_over_acp")]
2049            Self::ConnectMcpRequest(_) => CLIENT_METHOD_NAMES.mcp_connect,
2050            #[cfg(feature = "unstable_mcp_over_acp")]
2051            Self::MessageMcpRequest(_) => CLIENT_METHOD_NAMES.mcp_message,
2052            #[cfg(feature = "unstable_mcp_over_acp")]
2053            Self::DisconnectMcpRequest(_) => CLIENT_METHOD_NAMES.mcp_disconnect,
2054            Self::ExtMethodRequest(ext_request) => &ext_request.method,
2055        }
2056    }
2057}
2058
2059/// All possible responses that a client can send to an agent.
2060///
2061/// This enum is used internally for routing RPC responses. You typically won't need
2062/// to use this directly - the responses are handled automatically by the connection.
2063///
2064/// These are responses to the corresponding `AgentRequest` variants.
2065#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
2066#[serde(untagged)]
2067#[schemars(inline)]
2068#[non_exhaustive]
2069pub enum ClientResponse {
2070    WriteTextFileResponse(#[serde(default)] WriteTextFileResponse),
2071    ReadTextFileResponse(ReadTextFileResponse),
2072    RequestPermissionResponse(RequestPermissionResponse),
2073    CreateTerminalResponse(CreateTerminalResponse),
2074    TerminalOutputResponse(TerminalOutputResponse),
2075    ReleaseTerminalResponse(#[serde(default)] ReleaseTerminalResponse),
2076    WaitForTerminalExitResponse(WaitForTerminalExitResponse),
2077    KillTerminalResponse(#[serde(default)] KillTerminalResponse),
2078    #[cfg(feature = "unstable_elicitation")]
2079    CreateElicitationResponse(CreateElicitationResponse),
2080    #[cfg(feature = "unstable_mcp_over_acp")]
2081    ConnectMcpResponse(ConnectMcpResponse),
2082    #[cfg(feature = "unstable_mcp_over_acp")]
2083    DisconnectMcpResponse(#[serde(default)] DisconnectMcpResponse),
2084    ExtMethodResponse(ExtResponse),
2085    #[cfg(feature = "unstable_mcp_over_acp")]
2086    MessageMcpResponse(MessageMcpResponse),
2087}
2088
2089/// All possible notifications that an agent can send to a client.
2090///
2091/// This enum is used internally for routing RPC notifications. You typically won't need
2092/// to use this directly.
2093///
2094/// Notifications do not expect a response.
2095#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
2096#[serde(untagged)]
2097#[expect(clippy::large_enum_variant)]
2098#[schemars(inline)]
2099#[non_exhaustive]
2100pub enum AgentNotification {
2101    /// Handles session update notifications from the agent.
2102    ///
2103    /// This is a notification endpoint (no response expected) that receives
2104    /// real-time updates about session progress, including message chunks,
2105    /// tool calls, and execution plans.
2106    ///
2107    /// Note: Clients SHOULD continue accepting tool call updates even after
2108    /// sending a `session/cancel` notification, as the agent may send final
2109    /// updates before responding with the cancelled stop reason.
2110    ///
2111    /// See protocol docs: [Agent Reports Output](https://agentclientprotocol.com/protocol/prompt-turn#3-agent-reports-output)
2112    SessionNotification(SessionNotification),
2113    /// **UNSTABLE**
2114    ///
2115    /// This capability is not part of the spec yet, and may be removed or changed at any point.
2116    ///
2117    /// Notification that a URL-based elicitation has completed.
2118    #[cfg(feature = "unstable_elicitation")]
2119    CompleteElicitationNotification(CompleteElicitationNotification),
2120    /// **UNSTABLE**
2121    ///
2122    /// This capability is not part of the spec yet, and may be removed or changed at any point.
2123    ///
2124    /// Receives an MCP-over-ACP notification.
2125    #[cfg(feature = "unstable_mcp_over_acp")]
2126    MessageMcpNotification(MessageMcpNotification),
2127    /// Handles extension notifications from the agent.
2128    ///
2129    /// Allows the Agent to send an arbitrary notification that is not part of the ACP spec.
2130    /// Extension notifications provide a way to send one-way messages for custom functionality
2131    /// while maintaining protocol compatibility.
2132    ///
2133    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
2134    ExtNotification(ExtNotification),
2135}
2136
2137impl AgentNotification {
2138    /// Returns the corresponding method name of the notification.
2139    #[must_use]
2140    pub fn method(&self) -> &str {
2141        match self {
2142            Self::SessionNotification(_) => CLIENT_METHOD_NAMES.session_update,
2143            #[cfg(feature = "unstable_elicitation")]
2144            Self::CompleteElicitationNotification(_) => CLIENT_METHOD_NAMES.elicitation_complete,
2145            #[cfg(feature = "unstable_mcp_over_acp")]
2146            Self::MessageMcpNotification(_) => CLIENT_METHOD_NAMES.mcp_message,
2147            Self::ExtNotification(ext_notification) => &ext_notification.method,
2148        }
2149    }
2150}
2151
2152#[cfg(test)]
2153mod tests {
2154    use super::*;
2155
2156    #[test]
2157    fn test_serialization_behavior() {
2158        use serde_json::json;
2159
2160        assert_eq!(
2161            serde_json::from_value::<SessionInfoUpdate>(json!({})).unwrap(),
2162            SessionInfoUpdate {
2163                title: MaybeUndefined::Undefined,
2164                updated_at: MaybeUndefined::Undefined,
2165                meta: None
2166            }
2167        );
2168        assert_eq!(
2169            serde_json::from_value::<SessionInfoUpdate>(json!({"title": null, "updatedAt": null}))
2170                .unwrap(),
2171            SessionInfoUpdate {
2172                title: MaybeUndefined::Null,
2173                updated_at: MaybeUndefined::Null,
2174                meta: None
2175            }
2176        );
2177        assert_eq!(
2178            serde_json::from_value::<SessionInfoUpdate>(
2179                json!({"title": "title", "updatedAt": "timestamp"})
2180            )
2181            .unwrap(),
2182            SessionInfoUpdate {
2183                title: MaybeUndefined::Value("title".to_string()),
2184                updated_at: MaybeUndefined::Value("timestamp".to_string()),
2185                meta: None
2186            }
2187        );
2188
2189        assert_eq!(
2190            serde_json::to_value(SessionInfoUpdate::new()).unwrap(),
2191            json!({})
2192        );
2193        assert_eq!(
2194            serde_json::to_value(SessionInfoUpdate::new().title("title")).unwrap(),
2195            json!({"title": "title"})
2196        );
2197        assert_eq!(
2198            serde_json::to_value(SessionInfoUpdate::new().title(None)).unwrap(),
2199            json!({"title": null})
2200        );
2201        assert_eq!(
2202            serde_json::to_value(
2203                SessionInfoUpdate::new()
2204                    .title("title")
2205                    .title(MaybeUndefined::Undefined)
2206            )
2207            .unwrap(),
2208            json!({})
2209        );
2210    }
2211
2212    #[cfg(feature = "unstable_nes")]
2213    #[test]
2214    fn test_client_capabilities_position_encodings_serialization() {
2215        use serde_json::json;
2216
2217        let capabilities = ClientCapabilities::new().position_encodings(vec![
2218            PositionEncodingKind::Utf32,
2219            PositionEncodingKind::Utf16,
2220        ]);
2221        let json = serde_json::to_value(&capabilities).unwrap();
2222
2223        assert_eq!(json["positionEncodings"], json!(["utf-32", "utf-16"]));
2224    }
2225
2226    #[cfg(feature = "unstable_plan_operations")]
2227    #[test]
2228    fn test_plan_operations_serialization() {
2229        use serde_json::json;
2230
2231        let plan_update =
2232            SessionUpdate::PlanUpdate(PlanUpdate::new(crate::PlanUpdateContent::items(
2233                "plan-1",
2234                vec![crate::PlanEntry::new(
2235                    "Step 1",
2236                    crate::PlanEntryPriority::High,
2237                    crate::PlanEntryStatus::Pending,
2238                )],
2239            )));
2240
2241        assert_eq!(
2242            serde_json::to_value(plan_update).unwrap(),
2243            json!({
2244                "sessionUpdate": "plan_update",
2245                "plan": {
2246                    "type": "items",
2247                    "id": "plan-1",
2248                    "entries": [
2249                        {
2250                            "content": "Step 1",
2251                            "priority": "high",
2252                            "status": "pending"
2253                        }
2254                    ]
2255                }
2256            })
2257        );
2258
2259        assert_eq!(
2260            serde_json::to_value(SessionUpdate::PlanRemoved(PlanRemoved::new("plan-1"))).unwrap(),
2261            json!({
2262                "sessionUpdate": "plan_removed",
2263                "id": "plan-1"
2264            })
2265        );
2266
2267        let capabilities = ClientCapabilities::new().plan_capabilities(PlanCapabilities::new());
2268        let json = serde_json::to_value(&capabilities).unwrap();
2269        assert_eq!(json["planCapabilities"], json!({}));
2270
2271        assert_eq!(
2272            serde_json::from_value::<ClientCapabilities>(json!({ "planCapabilities": null }))
2273                .unwrap()
2274                .plan_capabilities,
2275            None
2276        );
2277    }
2278
2279    #[cfg(feature = "unstable_mcp_over_acp")]
2280    #[test]
2281    fn test_agent_mcp_request_method_names() {
2282        use serde_json::json;
2283
2284        let params: serde_json::Map<String, serde_json::Value> =
2285            [("cursor".to_string(), json!("abc"))].into_iter().collect();
2286
2287        assert_eq!(CLIENT_METHOD_NAMES.mcp_connect, "mcp/connect");
2288        assert_eq!(CLIENT_METHOD_NAMES.mcp_message, "mcp/message");
2289        assert_eq!(CLIENT_METHOD_NAMES.mcp_disconnect, "mcp/disconnect");
2290
2291        assert_eq!(
2292            AgentRequest::ConnectMcpRequest(ConnectMcpRequest::new("server-1")).method(),
2293            "mcp/connect"
2294        );
2295        assert_eq!(
2296            AgentRequest::MessageMcpRequest(MessageMcpRequest::new("conn-1", "tools/list"))
2297                .method(),
2298            "mcp/message"
2299        );
2300        assert_eq!(
2301            AgentRequest::DisconnectMcpRequest(DisconnectMcpRequest::new("conn-1")).method(),
2302            "mcp/disconnect"
2303        );
2304        assert_eq!(
2305            AgentNotification::MessageMcpNotification(MessageMcpNotification::new(
2306                "conn-1",
2307                "notifications/progress"
2308            ))
2309            .method(),
2310            "mcp/message"
2311        );
2312
2313        assert_eq!(
2314            serde_json::to_value(ConnectMcpRequest::new("server-1")).unwrap(),
2315            json!({ "acpId": "server-1" })
2316        );
2317        assert_eq!(
2318            serde_json::to_value(ConnectMcpResponse::new("conn-1")).unwrap(),
2319            json!({ "connectionId": "conn-1" })
2320        );
2321        assert_eq!(
2322            serde_json::to_value(MessageMcpRequest::new("conn-1", "tools/list").params(params))
2323                .unwrap(),
2324            json!({
2325                "connectionId": "conn-1",
2326                "method": "tools/list",
2327                "params": { "cursor": "abc" }
2328            })
2329        );
2330        assert_eq!(
2331            serde_json::to_value(DisconnectMcpRequest::new("conn-1")).unwrap(),
2332            json!({ "connectionId": "conn-1" })
2333        );
2334        assert_eq!(
2335            serde_json::to_value(MessageMcpNotification::new(
2336                "conn-1",
2337                "notifications/progress"
2338            ))
2339            .unwrap(),
2340            json!({
2341                "connectionId": "conn-1",
2342                "method": "notifications/progress"
2343            })
2344        );
2345
2346        let request_with_null_params: MessageMcpRequest = serde_json::from_value(json!({
2347            "connectionId": "conn-1",
2348            "method": "tools/list",
2349            "params": null
2350        }))
2351        .unwrap();
2352        assert_eq!(request_with_null_params.params, None);
2353    }
2354}