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 super::{
15    CompleteElicitationNotification, CreateElicitationRequest, CreateElicitationResponse,
16    ElicitationCapabilities,
17};
18use crate::{IntoMaybeUndefined, IntoOption, MaybeUndefined, SkipListener};
19
20use super::{
21    ContentBlock, EnvVariable, ExtNotification, ExtRequest, ExtResponse, Meta, Plan,
22    SessionConfigOption, SessionId, SessionModeId, ToolCall, ToolCallUpdate,
23};
24#[cfg(feature = "unstable_plan_operations")]
25use super::{PlanCapabilities, PlanRemoved, PlanUpdate};
26
27#[cfg(feature = "unstable_mcp_over_acp")]
28use super::mcp::{
29    ConnectMcpRequest, ConnectMcpResponse, DisconnectMcpRequest, DisconnectMcpResponse,
30    MCP_CONNECT_METHOD_NAME, MCP_DISCONNECT_METHOD_NAME, MCP_MESSAGE_METHOD_NAME,
31    MessageMcpNotification, MessageMcpRequest, MessageMcpResponse,
32};
33
34#[cfg(feature = "unstable_nes")]
35use super::{ClientNesCapabilities, PositionEncodingKind};
36
37// Session updates
38
39/// Notification containing a session update from the agent.
40///
41/// Used to stream real-time progress and results during prompt processing.
42///
43/// See protocol docs: [Agent Reports Output](https://agentclientprotocol.com/protocol/prompt-turn#3-agent-reports-output)
44#[serde_as]
45#[skip_serializing_none]
46#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq)]
47#[schemars(extend("x-side" = "client", "x-method" = SESSION_UPDATE_NOTIFICATION))]
48#[serde(rename_all = "camelCase")]
49#[non_exhaustive]
50pub struct SessionNotification {
51    /// The ID of the session this update pertains to.
52    pub session_id: SessionId,
53    /// The actual update content.
54    pub update: SessionUpdate,
55    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
56    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
57    /// these keys.
58    ///
59    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
60    #[serde_as(deserialize_as = "DefaultOnError")]
61    #[schemars(extend("x-deserialize-default-on-error" = true))]
62    #[serde(default)]
63    #[serde(rename = "_meta")]
64    pub meta: Option<Meta>,
65}
66
67impl SessionNotification {
68    /// Builds [`SessionNotification`] with the required notification fields set; optional fields start unset or empty.
69    #[must_use]
70    pub fn new(session_id: impl Into<SessionId>, update: SessionUpdate) -> Self {
71        Self {
72            session_id: session_id.into(),
73            update,
74            meta: None,
75        }
76    }
77
78    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
79    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
80    /// these keys.
81    ///
82    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
83    #[must_use]
84    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
85        self.meta = meta.into_option();
86        self
87    }
88}
89
90/// Different types of updates that can be sent during session processing.
91///
92/// These updates provide real-time feedback about the agent's progress.
93///
94/// See protocol docs: [Agent Reports Output](https://agentclientprotocol.com/protocol/prompt-turn#3-agent-reports-output)
95#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq)]
96#[serde(tag = "sessionUpdate", rename_all = "snake_case")]
97#[schemars(extend("discriminator" = {"propertyName": "sessionUpdate"}))]
98#[non_exhaustive]
99pub enum SessionUpdate {
100    /// A chunk of the user's message being streamed.
101    UserMessageChunk(ContentChunk),
102    /// A chunk of the agent's response being streamed.
103    AgentMessageChunk(ContentChunk),
104    /// A chunk of the agent's internal reasoning being streamed.
105    AgentThoughtChunk(ContentChunk),
106    /// Notification that a new tool call has been initiated.
107    ToolCall(ToolCall),
108    /// Update on the status or results of a tool call.
109    ToolCallUpdate(ToolCallUpdate),
110    /// The agent's execution plan for complex tasks.
111    /// See protocol docs: [Agent Plan](https://agentclientprotocol.com/protocol/agent-plan)
112    Plan(Plan),
113    /// **UNSTABLE**
114    ///
115    /// This capability is not part of the spec yet, and may be removed or changed at any point.
116    ///
117    /// A content update for a plan identified by ID.
118    #[cfg(feature = "unstable_plan_operations")]
119    PlanUpdate(PlanUpdate),
120    /// **UNSTABLE**
121    ///
122    /// This capability is not part of the spec yet, and may be removed or changed at any point.
123    ///
124    /// Removal notice for a plan identified by ID.
125    #[cfg(feature = "unstable_plan_operations")]
126    PlanRemoved(PlanRemoved),
127    /// Available commands are ready or have changed
128    AvailableCommandsUpdate(AvailableCommandsUpdate),
129    /// The current mode of the session has changed
130    ///
131    /// See protocol docs: [Session Modes](https://agentclientprotocol.com/protocol/session-modes)
132    CurrentModeUpdate(CurrentModeUpdate),
133    /// Session configuration options have been updated.
134    ConfigOptionUpdate(ConfigOptionUpdate),
135    /// Session metadata has been updated (title, timestamps, custom metadata)
136    SessionInfoUpdate(SessionInfoUpdate),
137    /// Context window and cost update for the session.
138    UsageUpdate(UsageUpdate),
139}
140
141/// The current mode of the session has changed
142///
143/// See protocol docs: [Session Modes](https://agentclientprotocol.com/protocol/session-modes)
144#[serde_as]
145#[skip_serializing_none]
146#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
147#[serde(rename_all = "camelCase")]
148#[non_exhaustive]
149pub struct CurrentModeUpdate {
150    /// The ID of the current mode
151    pub current_mode_id: SessionModeId,
152    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
153    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
154    /// these keys.
155    ///
156    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
157    #[serde_as(deserialize_as = "DefaultOnError")]
158    #[schemars(extend("x-deserialize-default-on-error" = true))]
159    #[serde(default)]
160    #[serde(rename = "_meta")]
161    pub meta: Option<Meta>,
162}
163
164impl CurrentModeUpdate {
165    /// Builds [`CurrentModeUpdate`] with the required fields set; optional fields start unset or empty.
166    #[must_use]
167    pub fn new(current_mode_id: impl Into<SessionModeId>) -> Self {
168        Self {
169            current_mode_id: current_mode_id.into(),
170            meta: None,
171        }
172    }
173
174    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
175    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
176    /// these keys.
177    ///
178    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
179    #[must_use]
180    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
181        self.meta = meta.into_option();
182        self
183    }
184}
185
186/// Session configuration options have been updated.
187#[serde_as]
188#[skip_serializing_none]
189#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
190#[serde(rename_all = "camelCase")]
191#[non_exhaustive]
192pub struct ConfigOptionUpdate {
193    /// The full set of configuration options and their current values.
194    #[serde_as(deserialize_as = "DefaultOnError<VecSkipError<_, SkipListener>>")]
195    #[schemars(extend("x-deserialize-default-on-error" = true, "x-deserialize-skip-invalid-items" = true))]
196    pub config_options: Vec<SessionConfigOption>,
197    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
198    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
199    /// these keys.
200    ///
201    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
202    #[serde_as(deserialize_as = "DefaultOnError")]
203    #[schemars(extend("x-deserialize-default-on-error" = true))]
204    #[serde(default)]
205    #[serde(rename = "_meta")]
206    pub meta: Option<Meta>,
207}
208
209impl ConfigOptionUpdate {
210    /// Builds [`ConfigOptionUpdate`] with the required fields set; optional fields start unset or empty.
211    #[must_use]
212    pub fn new(config_options: Vec<SessionConfigOption>) -> Self {
213        Self {
214            config_options,
215            meta: None,
216        }
217    }
218
219    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
220    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
221    /// these keys.
222    ///
223    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
224    #[must_use]
225    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
226        self.meta = meta.into_option();
227        self
228    }
229}
230
231/// Update to session metadata. All fields are optional to support partial updates.
232///
233/// Agents send this notification to update session information like title or custom metadata.
234/// This allows clients to display dynamic session names and track session state changes.
235#[serde_as]
236#[skip_serializing_none]
237#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
238#[serde(rename_all = "camelCase")]
239#[non_exhaustive]
240pub struct SessionInfoUpdate {
241    /// Human-readable title for the session. Set to null to clear.
242    #[serde_as(deserialize_as = "DefaultOnError")]
243    #[schemars(extend("x-deserialize-default-on-error" = true))]
244    #[serde(default, skip_serializing_if = "MaybeUndefined::is_undefined")]
245    pub title: MaybeUndefined<String>,
246    /// ISO 8601 timestamp of last activity. Set to null to clear.
247    #[serde_as(deserialize_as = "DefaultOnError")]
248    #[schemars(extend("x-deserialize-default-on-error" = true))]
249    #[serde(default, skip_serializing_if = "MaybeUndefined::is_undefined")]
250    pub updated_at: MaybeUndefined<String>,
251    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
252    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
253    /// these keys.
254    ///
255    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
256    #[serde_as(deserialize_as = "DefaultOnError")]
257    #[schemars(extend("x-deserialize-default-on-error" = true))]
258    #[serde(default)]
259    #[serde(rename = "_meta")]
260    pub meta: Option<Meta>,
261}
262
263impl SessionInfoUpdate {
264    /// Builds [`SessionInfoUpdate`] with the required fields set; optional fields start unset or empty.
265    #[must_use]
266    pub fn new() -> Self {
267        Self::default()
268    }
269
270    /// Human-readable title for the session. Set to null to clear.
271    #[must_use]
272    pub fn title(mut self, title: impl IntoMaybeUndefined<String>) -> Self {
273        self.title = title.into_maybe_undefined();
274        self
275    }
276
277    /// ISO 8601 timestamp of last activity. Set to null to clear.
278    #[must_use]
279    pub fn updated_at(mut self, updated_at: impl IntoMaybeUndefined<String>) -> Self {
280        self.updated_at = updated_at.into_maybe_undefined();
281        self
282    }
283
284    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
285    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
286    /// these keys.
287    ///
288    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
289    #[must_use]
290    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
291        self.meta = meta.into_option();
292        self
293    }
294}
295
296/// Context window and cost update for a session.
297#[serde_as]
298#[skip_serializing_none]
299#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq)]
300#[serde(rename_all = "camelCase")]
301#[non_exhaustive]
302pub struct UsageUpdate {
303    /// Tokens currently in context.
304    pub used: u64,
305    /// Total context window size in tokens.
306    pub size: u64,
307    /// Cumulative session cost (optional).
308    #[serde_as(deserialize_as = "DefaultOnError")]
309    #[schemars(extend("x-deserialize-default-on-error" = true))]
310    #[serde(default)]
311    pub cost: Option<Cost>,
312    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
313    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
314    /// these keys.
315    ///
316    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
317    #[serde_as(deserialize_as = "DefaultOnError")]
318    #[schemars(extend("x-deserialize-default-on-error" = true))]
319    #[serde(default)]
320    #[serde(rename = "_meta")]
321    pub meta: Option<Meta>,
322}
323
324impl UsageUpdate {
325    /// Builds [`UsageUpdate`] with the required fields set; optional fields start unset or empty.
326    #[must_use]
327    pub fn new(used: u64, size: u64) -> Self {
328        Self {
329            used,
330            size,
331            cost: None,
332            meta: None,
333        }
334    }
335
336    /// Cumulative session cost (optional).
337    #[must_use]
338    pub fn cost(mut self, cost: impl IntoOption<Cost>) -> Self {
339        self.cost = cost.into_option();
340        self
341    }
342
343    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
344    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
345    /// these keys.
346    ///
347    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
348    #[must_use]
349    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
350        self.meta = meta.into_option();
351        self
352    }
353}
354
355/// Cost information for a session.
356#[serde_as]
357#[skip_serializing_none]
358#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq)]
359#[serde(rename_all = "camelCase")]
360#[non_exhaustive]
361pub struct Cost {
362    /// Total cumulative cost for session.
363    pub amount: f64,
364    /// ISO 4217 currency code (e.g., "USD", "EUR").
365    pub currency: String,
366    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
367    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
368    /// these keys.
369    ///
370    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
371    #[serde_as(deserialize_as = "DefaultOnError")]
372    #[schemars(extend("x-deserialize-default-on-error" = true))]
373    #[serde(default)]
374    #[serde(rename = "_meta")]
375    pub meta: Option<Meta>,
376}
377
378impl Cost {
379    /// Builds [`Cost`] with the required fields set; optional fields start unset or empty.
380    #[must_use]
381    pub fn new(amount: f64, currency: impl Into<String>) -> Self {
382        Self {
383            amount,
384            currency: currency.into(),
385            meta: None,
386        }
387    }
388
389    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
390    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
391    /// these keys.
392    ///
393    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
394    #[must_use]
395    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
396        self.meta = meta.into_option();
397        self
398    }
399}
400
401/// A streamed item of content
402#[serde_as]
403#[skip_serializing_none]
404#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq)]
405#[serde(rename_all = "camelCase")]
406#[non_exhaustive]
407pub struct ContentChunk {
408    /// A single item of content
409    pub content: ContentBlock,
410    /// A unique identifier for the message this chunk belongs to.
411    ///
412    /// All chunks belonging to the same message share the same `messageId`.
413    /// A change in `messageId` indicates a new message has started.
414    #[serde_as(deserialize_as = "DefaultOnError")]
415    #[schemars(extend("x-deserialize-default-on-error" = true))]
416    #[serde(default)]
417    pub message_id: Option<MessageId>,
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    #[serde_as(deserialize_as = "DefaultOnError")]
424    #[schemars(extend("x-deserialize-default-on-error" = true))]
425    #[serde(default)]
426    #[serde(rename = "_meta")]
427    pub meta: Option<Meta>,
428}
429
430impl ContentChunk {
431    /// Builds [`ContentChunk`] with the required fields set; optional fields start unset or empty.
432    #[must_use]
433    pub fn new(content: ContentBlock) -> Self {
434        Self {
435            content,
436            message_id: None,
437            meta: None,
438        }
439    }
440
441    /// A unique identifier for the message this chunk belongs to.
442    ///
443    /// All chunks belonging to the same message share the same `messageId`.
444    /// A change in `messageId` indicates a new message has started.
445    #[must_use]
446    pub fn message_id(mut self, message_id: impl IntoOption<MessageId>) -> Self {
447        self.message_id = message_id.into_option();
448        self
449    }
450
451    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
452    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
453    /// these keys.
454    ///
455    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
456    #[must_use]
457    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
458        self.meta = meta.into_option();
459        self
460    }
461}
462
463/// Unique identifier for a message within a session.
464#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq, Hash, Display, From)]
465#[serde(transparent)]
466#[from(Arc<str>, String, &'static str)]
467#[non_exhaustive]
468pub struct MessageId(pub Arc<str>);
469
470impl MessageId {
471    /// Wraps a protocol string as a typed [`MessageId`].
472    #[must_use]
473    pub fn new(id: impl Into<Arc<str>>) -> Self {
474        Self(id.into())
475    }
476}
477
478impl IntoOption<MessageId> for &str {
479    fn into_option(self) -> Option<MessageId> {
480        Some(MessageId::new(self))
481    }
482}
483
484/// Available commands are ready or have changed
485#[serde_as]
486#[skip_serializing_none]
487#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
488#[serde(rename_all = "camelCase")]
489#[non_exhaustive]
490pub struct AvailableCommandsUpdate {
491    /// Commands the agent can execute
492    #[serde_as(deserialize_as = "DefaultOnError<VecSkipError<_, SkipListener>>")]
493    #[schemars(extend("x-deserialize-default-on-error" = true, "x-deserialize-skip-invalid-items" = true))]
494    pub available_commands: Vec<AvailableCommand>,
495    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
496    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
497    /// these keys.
498    ///
499    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
500    #[serde_as(deserialize_as = "DefaultOnError")]
501    #[schemars(extend("x-deserialize-default-on-error" = true))]
502    #[serde(default)]
503    #[serde(rename = "_meta")]
504    pub meta: Option<Meta>,
505}
506
507impl AvailableCommandsUpdate {
508    /// Builds [`AvailableCommandsUpdate`] with the required fields set; optional fields start unset or empty.
509    #[must_use]
510    pub fn new(available_commands: Vec<AvailableCommand>) -> Self {
511        Self {
512            available_commands,
513            meta: None,
514        }
515    }
516
517    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
518    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
519    /// these keys.
520    ///
521    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
522    #[must_use]
523    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
524        self.meta = meta.into_option();
525        self
526    }
527}
528
529/// Information about a command.
530#[serde_as]
531#[skip_serializing_none]
532#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
533#[serde(rename_all = "camelCase")]
534#[non_exhaustive]
535pub struct AvailableCommand {
536    /// Command name (e.g., `create_plan`, `research_codebase`).
537    pub name: String,
538    /// Human-readable description of what the command does.
539    pub description: String,
540    /// Input for the command if required
541    #[serde_as(deserialize_as = "DefaultOnError")]
542    #[schemars(extend("x-deserialize-default-on-error" = true))]
543    #[serde(default)]
544    pub input: Option<AvailableCommandInput>,
545    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
546    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
547    /// these keys.
548    ///
549    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
550    #[serde_as(deserialize_as = "DefaultOnError")]
551    #[schemars(extend("x-deserialize-default-on-error" = true))]
552    #[serde(default)]
553    #[serde(rename = "_meta")]
554    pub meta: Option<Meta>,
555}
556
557impl AvailableCommand {
558    /// Builds [`AvailableCommand`] with the required fields set; optional fields start unset or empty.
559    #[must_use]
560    pub fn new(name: impl Into<String>, description: impl Into<String>) -> Self {
561        Self {
562            name: name.into(),
563            description: description.into(),
564            input: None,
565            meta: None,
566        }
567    }
568
569    /// Input for the command if required
570    #[must_use]
571    pub fn input(mut self, input: impl IntoOption<AvailableCommandInput>) -> Self {
572        self.input = input.into_option();
573        self
574    }
575
576    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
577    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
578    /// these keys.
579    ///
580    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
581    #[must_use]
582    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
583        self.meta = meta.into_option();
584        self
585    }
586}
587
588/// The input specification for a command.
589#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
590#[serde(untagged, rename_all = "camelCase")]
591#[non_exhaustive]
592pub enum AvailableCommandInput {
593    /// All text that was typed after the command name is provided as input.
594    Unstructured(UnstructuredCommandInput),
595}
596
597/// All text that was typed after the command name is provided as input.
598#[serde_as]
599#[skip_serializing_none]
600#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
601#[serde(rename_all = "camelCase")]
602#[non_exhaustive]
603pub struct UnstructuredCommandInput {
604    /// A hint to display when the input hasn't been provided yet
605    pub hint: String,
606    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
607    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
608    /// these keys.
609    ///
610    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
611    #[serde_as(deserialize_as = "DefaultOnError")]
612    #[schemars(extend("x-deserialize-default-on-error" = true))]
613    #[serde(default)]
614    #[serde(rename = "_meta")]
615    pub meta: Option<Meta>,
616}
617
618impl UnstructuredCommandInput {
619    /// Builds [`UnstructuredCommandInput`] with the required fields set; optional fields start unset or empty.
620    #[must_use]
621    pub fn new(hint: impl Into<String>) -> Self {
622        Self {
623            hint: hint.into(),
624            meta: None,
625        }
626    }
627
628    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
629    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
630    /// these keys.
631    ///
632    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
633    #[must_use]
634    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
635        self.meta = meta.into_option();
636        self
637    }
638}
639
640// Permission
641
642/// Request for user permission to execute a tool call.
643///
644/// Sent when the agent needs authorization before performing a sensitive operation.
645///
646/// See protocol docs: [Requesting Permission](https://agentclientprotocol.com/protocol/tool-calls#requesting-permission)
647#[serde_as]
648#[skip_serializing_none]
649#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq)]
650#[schemars(extend("x-side" = "client", "x-method" = SESSION_REQUEST_PERMISSION_METHOD_NAME))]
651#[serde(rename_all = "camelCase")]
652#[non_exhaustive]
653pub struct RequestPermissionRequest {
654    /// The session ID for this request.
655    pub session_id: SessionId,
656    /// Details about the tool call requiring permission.
657    pub tool_call: ToolCallUpdate,
658    /// Available permission options for the user to choose from.
659    pub options: Vec<PermissionOption>,
660    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
661    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
662    /// these keys.
663    ///
664    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
665    #[serde_as(deserialize_as = "DefaultOnError")]
666    #[schemars(extend("x-deserialize-default-on-error" = true))]
667    #[serde(default)]
668    #[serde(rename = "_meta")]
669    pub meta: Option<Meta>,
670}
671
672impl RequestPermissionRequest {
673    /// Builds [`RequestPermissionRequest`] with the required request fields set; optional fields start unset or empty.
674    #[must_use]
675    pub fn new(
676        session_id: impl Into<SessionId>,
677        tool_call: ToolCallUpdate,
678        options: Vec<PermissionOption>,
679    ) -> Self {
680        Self {
681            session_id: session_id.into(),
682            tool_call,
683            options,
684            meta: None,
685        }
686    }
687
688    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
689    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
690    /// these keys.
691    ///
692    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
693    #[must_use]
694    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
695        self.meta = meta.into_option();
696        self
697    }
698}
699
700/// An option presented to the user when requesting permission.
701#[serde_as]
702#[skip_serializing_none]
703#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
704#[serde(rename_all = "camelCase")]
705#[non_exhaustive]
706pub struct PermissionOption {
707    /// Unique identifier for this permission option.
708    pub option_id: PermissionOptionId,
709    /// Human-readable label to display to the user.
710    pub name: String,
711    /// Hint about the nature of this permission option.
712    pub kind: PermissionOptionKind,
713    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
714    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
715    /// these keys.
716    ///
717    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
718    #[serde_as(deserialize_as = "DefaultOnError")]
719    #[schemars(extend("x-deserialize-default-on-error" = true))]
720    #[serde(default)]
721    #[serde(rename = "_meta")]
722    pub meta: Option<Meta>,
723}
724
725impl PermissionOption {
726    /// Builds [`PermissionOption`] with the required fields set; optional fields start unset or empty.
727    #[must_use]
728    pub fn new(
729        option_id: impl Into<PermissionOptionId>,
730        name: impl Into<String>,
731        kind: PermissionOptionKind,
732    ) -> Self {
733        Self {
734            option_id: option_id.into(),
735            name: name.into(),
736            kind,
737            meta: None,
738        }
739    }
740
741    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
742    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
743    /// these keys.
744    ///
745    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
746    #[must_use]
747    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
748        self.meta = meta.into_option();
749        self
750    }
751}
752
753/// Unique identifier for a permission option.
754#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq, Hash, Display, From)]
755#[serde(transparent)]
756#[from(Arc<str>, String, &'static str)]
757#[non_exhaustive]
758pub struct PermissionOptionId(pub Arc<str>);
759
760impl PermissionOptionId {
761    /// Wraps a protocol string as a typed [`PermissionOptionId`].
762    #[must_use]
763    pub fn new(id: impl Into<Arc<str>>) -> Self {
764        Self(id.into())
765    }
766}
767
768/// The type of permission option being presented to the user.
769///
770/// Helps clients choose appropriate icons and UI treatment.
771#[derive(Debug, Clone, Copy, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
772#[serde(rename_all = "snake_case")]
773#[non_exhaustive]
774pub enum PermissionOptionKind {
775    /// Allow this operation only this time.
776    AllowOnce,
777    /// Allow this operation and remember the choice.
778    AllowAlways,
779    /// Reject this operation only this time.
780    RejectOnce,
781    /// Reject this operation and remember the choice.
782    RejectAlways,
783}
784
785/// Response to a permission request.
786#[serde_as]
787#[skip_serializing_none]
788#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
789#[schemars(extend("x-side" = "client", "x-method" = SESSION_REQUEST_PERMISSION_METHOD_NAME))]
790#[serde(rename_all = "camelCase")]
791#[non_exhaustive]
792pub struct RequestPermissionResponse {
793    /// The user's decision on the permission request.
794    // This extra-level is unfortunately needed because the output must be an object
795    pub outcome: RequestPermissionOutcome,
796    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
797    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
798    /// these keys.
799    ///
800    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
801    #[serde_as(deserialize_as = "DefaultOnError")]
802    #[schemars(extend("x-deserialize-default-on-error" = true))]
803    #[serde(default)]
804    #[serde(rename = "_meta")]
805    pub meta: Option<Meta>,
806}
807
808impl RequestPermissionResponse {
809    /// Builds [`RequestPermissionResponse`] with the required response fields set; optional fields start unset or empty.
810    #[must_use]
811    pub fn new(outcome: RequestPermissionOutcome) -> Self {
812        Self {
813            outcome,
814            meta: None,
815        }
816    }
817
818    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
819    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
820    /// these keys.
821    ///
822    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
823    #[must_use]
824    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
825        self.meta = meta.into_option();
826        self
827    }
828}
829
830/// The outcome of a permission request.
831#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
832#[serde(tag = "outcome", rename_all = "snake_case")]
833#[schemars(extend("discriminator" = {"propertyName": "outcome"}))]
834#[non_exhaustive]
835pub enum RequestPermissionOutcome {
836    /// The prompt turn was cancelled before the user responded.
837    ///
838    /// When a client sends a `session/cancel` notification to cancel an ongoing
839    /// prompt turn, it MUST respond to all pending `session/request_permission`
840    /// requests with this `Cancelled` outcome.
841    ///
842    /// See protocol docs: [Cancellation](https://agentclientprotocol.com/protocol/prompt-turn#cancellation)
843    Cancelled,
844    /// The user selected one of the provided options.
845    #[serde(rename_all = "camelCase")]
846    Selected(SelectedPermissionOutcome),
847}
848
849/// The user selected one of the provided options.
850#[serde_as]
851#[skip_serializing_none]
852#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
853#[serde(rename_all = "camelCase")]
854#[non_exhaustive]
855pub struct SelectedPermissionOutcome {
856    /// The ID of the option the user selected.
857    pub option_id: PermissionOptionId,
858    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
859    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
860    /// these keys.
861    ///
862    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
863    #[serde_as(deserialize_as = "DefaultOnError")]
864    #[schemars(extend("x-deserialize-default-on-error" = true))]
865    #[serde(default)]
866    #[serde(rename = "_meta")]
867    pub meta: Option<Meta>,
868}
869
870impl SelectedPermissionOutcome {
871    /// Builds [`SelectedPermissionOutcome`] with the required fields set; optional fields start unset or empty.
872    #[must_use]
873    pub fn new(option_id: impl Into<PermissionOptionId>) -> Self {
874        Self {
875            option_id: option_id.into(),
876            meta: None,
877        }
878    }
879
880    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
881    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
882    /// these keys.
883    ///
884    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
885    #[must_use]
886    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
887        self.meta = meta.into_option();
888        self
889    }
890}
891
892// Write text file
893
894/// Request to write content to a text file.
895///
896/// Only available if the client supports the `fs.writeTextFile` capability.
897#[serde_as]
898#[skip_serializing_none]
899#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
900#[schemars(extend("x-side" = "client", "x-method" = FS_WRITE_TEXT_FILE_METHOD_NAME))]
901#[serde(rename_all = "camelCase")]
902#[non_exhaustive]
903pub struct WriteTextFileRequest {
904    /// The session ID for this request.
905    pub session_id: SessionId,
906    /// Absolute path to the file to write.
907    pub path: PathBuf,
908    /// The text content to write to the file.
909    pub content: String,
910    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
911    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
912    /// these keys.
913    ///
914    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
915    #[serde_as(deserialize_as = "DefaultOnError")]
916    #[schemars(extend("x-deserialize-default-on-error" = true))]
917    #[serde(default)]
918    #[serde(rename = "_meta")]
919    pub meta: Option<Meta>,
920}
921
922impl WriteTextFileRequest {
923    /// Builds [`WriteTextFileRequest`] with the required request fields set; optional fields start unset or empty.
924    #[must_use]
925    pub fn new(
926        session_id: impl Into<SessionId>,
927        path: impl Into<PathBuf>,
928        content: impl Into<String>,
929    ) -> Self {
930        Self {
931            session_id: session_id.into(),
932            path: path.into(),
933            content: content.into(),
934            meta: None,
935        }
936    }
937
938    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
939    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
940    /// these keys.
941    ///
942    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
943    #[must_use]
944    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
945        self.meta = meta.into_option();
946        self
947    }
948}
949
950/// Response to `fs/write_text_file`
951#[serde_as]
952#[skip_serializing_none]
953#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
954#[serde(rename_all = "camelCase")]
955#[schemars(extend("x-side" = "client", "x-method" = FS_WRITE_TEXT_FILE_METHOD_NAME))]
956#[non_exhaustive]
957pub struct WriteTextFileResponse {
958    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
959    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
960    /// these keys.
961    ///
962    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
963    #[serde_as(deserialize_as = "DefaultOnError")]
964    #[schemars(extend("x-deserialize-default-on-error" = true))]
965    #[serde(default)]
966    #[serde(rename = "_meta")]
967    pub meta: Option<Meta>,
968}
969
970impl WriteTextFileResponse {
971    /// Builds [`WriteTextFileResponse`] with the required response fields set; optional fields start unset or empty.
972    #[must_use]
973    pub fn new() -> Self {
974        Self::default()
975    }
976
977    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
978    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
979    /// these keys.
980    ///
981    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
982    #[must_use]
983    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
984        self.meta = meta.into_option();
985        self
986    }
987}
988
989// Read text file
990
991/// Request to read content from a text file.
992///
993/// Only available if the client supports the `fs.readTextFile` capability.
994#[serde_as]
995#[skip_serializing_none]
996#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
997#[schemars(extend("x-side" = "client", "x-method" = FS_READ_TEXT_FILE_METHOD_NAME))]
998#[serde(rename_all = "camelCase")]
999#[non_exhaustive]
1000pub struct ReadTextFileRequest {
1001    /// The session ID for this request.
1002    pub session_id: SessionId,
1003    /// Absolute path to the file to read.
1004    pub path: PathBuf,
1005    /// Line number to start reading from (1-based).
1006    #[serde_as(deserialize_as = "DefaultOnError")]
1007    #[schemars(extend("x-deserialize-default-on-error" = true))]
1008    #[serde(default)]
1009    pub line: Option<u32>,
1010    /// Maximum number of lines to read.
1011    #[serde_as(deserialize_as = "DefaultOnError")]
1012    #[schemars(extend("x-deserialize-default-on-error" = true))]
1013    #[serde(default)]
1014    pub limit: Option<u32>,
1015    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1016    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1017    /// these keys.
1018    ///
1019    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1020    #[serde_as(deserialize_as = "DefaultOnError")]
1021    #[schemars(extend("x-deserialize-default-on-error" = true))]
1022    #[serde(default)]
1023    #[serde(rename = "_meta")]
1024    pub meta: Option<Meta>,
1025}
1026
1027impl ReadTextFileRequest {
1028    /// Builds [`ReadTextFileRequest`] with the required request fields set; optional fields start unset or empty.
1029    #[must_use]
1030    pub fn new(session_id: impl Into<SessionId>, path: impl Into<PathBuf>) -> Self {
1031        Self {
1032            session_id: session_id.into(),
1033            path: path.into(),
1034            line: None,
1035            limit: None,
1036            meta: None,
1037        }
1038    }
1039
1040    /// Line number to start reading from (1-based).
1041    #[must_use]
1042    pub fn line(mut self, line: impl IntoOption<u32>) -> Self {
1043        self.line = line.into_option();
1044        self
1045    }
1046
1047    /// Maximum number of lines to read.
1048    #[must_use]
1049    pub fn limit(mut self, limit: impl IntoOption<u32>) -> Self {
1050        self.limit = limit.into_option();
1051        self
1052    }
1053
1054    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1055    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1056    /// these keys.
1057    ///
1058    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1059    #[must_use]
1060    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1061        self.meta = meta.into_option();
1062        self
1063    }
1064}
1065
1066/// Response containing the contents of a text file.
1067#[serde_as]
1068#[skip_serializing_none]
1069#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1070#[schemars(extend("x-side" = "client", "x-method" = FS_READ_TEXT_FILE_METHOD_NAME))]
1071#[serde(rename_all = "camelCase")]
1072#[non_exhaustive]
1073pub struct ReadTextFileResponse {
1074    /// Content payload returned by this response.
1075    pub content: String,
1076    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1077    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1078    /// these keys.
1079    ///
1080    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1081    #[serde_as(deserialize_as = "DefaultOnError")]
1082    #[schemars(extend("x-deserialize-default-on-error" = true))]
1083    #[serde(default)]
1084    #[serde(rename = "_meta")]
1085    pub meta: Option<Meta>,
1086}
1087
1088impl ReadTextFileResponse {
1089    /// Builds [`ReadTextFileResponse`] with the required response fields set; optional fields start unset or empty.
1090    #[must_use]
1091    pub fn new(content: impl Into<String>) -> Self {
1092        Self {
1093            content: content.into(),
1094            meta: None,
1095        }
1096    }
1097
1098    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1099    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1100    /// these keys.
1101    ///
1102    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1103    #[must_use]
1104    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1105        self.meta = meta.into_option();
1106        self
1107    }
1108}
1109
1110// Terminals
1111
1112/// Typed identifier used for terminal values on the wire.
1113#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq, Hash, Display, From)]
1114#[serde(transparent)]
1115#[from(Arc<str>, String, &'static str)]
1116#[non_exhaustive]
1117pub struct TerminalId(pub Arc<str>);
1118
1119impl TerminalId {
1120    /// Wraps a protocol string as a typed [`TerminalId`].
1121    #[must_use]
1122    pub fn new(id: impl Into<Arc<str>>) -> Self {
1123        Self(id.into())
1124    }
1125}
1126
1127/// Request to create a new terminal and execute a command.
1128#[serde_as]
1129#[skip_serializing_none]
1130#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1131#[serde(rename_all = "camelCase")]
1132#[schemars(extend("x-side" = "client", "x-method" = TERMINAL_CREATE_METHOD_NAME))]
1133#[non_exhaustive]
1134pub struct CreateTerminalRequest {
1135    /// The session ID for this request.
1136    pub session_id: SessionId,
1137    /// The command to execute.
1138    pub command: String,
1139    /// Array of command arguments.
1140    #[serde_as(deserialize_as = "DefaultOnError<VecSkipError<_, SkipListener>>")]
1141    #[schemars(extend("x-deserialize-default-on-error" = true, "x-deserialize-skip-invalid-items" = true))]
1142    #[serde(default, skip_serializing_if = "Vec::is_empty")]
1143    pub args: Vec<String>,
1144    /// Environment variables for the command.
1145    #[serde_as(deserialize_as = "DefaultOnError<VecSkipError<_, SkipListener>>")]
1146    #[schemars(extend("x-deserialize-default-on-error" = true, "x-deserialize-skip-invalid-items" = true))]
1147    #[serde(default, skip_serializing_if = "Vec::is_empty")]
1148    pub env: Vec<EnvVariable>,
1149    /// Working directory for the command. Must be an absolute path.
1150    #[serde_as(deserialize_as = "DefaultOnError")]
1151    #[schemars(extend("x-deserialize-default-on-error" = true))]
1152    #[serde(default)]
1153    pub cwd: Option<PathBuf>,
1154    /// Maximum number of output bytes to retain.
1155    ///
1156    /// When the limit is exceeded, the Client truncates from the beginning of the output
1157    /// to stay within the limit.
1158    ///
1159    /// The Client MUST ensure truncation happens at a character boundary to maintain valid
1160    /// string output, even if this means the retained output is slightly less than the
1161    /// specified limit.
1162    #[serde_as(deserialize_as = "DefaultOnError")]
1163    #[schemars(extend("x-deserialize-default-on-error" = true))]
1164    #[serde(default)]
1165    pub output_byte_limit: Option<u64>,
1166    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1167    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1168    /// these keys.
1169    ///
1170    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1171    #[serde_as(deserialize_as = "DefaultOnError")]
1172    #[schemars(extend("x-deserialize-default-on-error" = true))]
1173    #[serde(default)]
1174    #[serde(rename = "_meta")]
1175    pub meta: Option<Meta>,
1176}
1177
1178impl CreateTerminalRequest {
1179    /// Builds [`CreateTerminalRequest`] with the required request fields set; optional fields start unset or empty.
1180    #[must_use]
1181    pub fn new(session_id: impl Into<SessionId>, command: impl Into<String>) -> Self {
1182        Self {
1183            session_id: session_id.into(),
1184            command: command.into(),
1185            args: Vec::new(),
1186            env: Vec::new(),
1187            cwd: None,
1188            output_byte_limit: None,
1189            meta: None,
1190        }
1191    }
1192
1193    /// Array of command arguments.
1194    #[must_use]
1195    pub fn args(mut self, args: Vec<String>) -> Self {
1196        self.args = args;
1197        self
1198    }
1199
1200    /// Environment variables for the command.
1201    #[must_use]
1202    pub fn env(mut self, env: Vec<EnvVariable>) -> Self {
1203        self.env = env;
1204        self
1205    }
1206
1207    /// Working directory for the command. Must be an absolute path.
1208    #[must_use]
1209    pub fn cwd(mut self, cwd: impl IntoOption<PathBuf>) -> Self {
1210        self.cwd = cwd.into_option();
1211        self
1212    }
1213
1214    /// Maximum number of output bytes to retain.
1215    ///
1216    /// When the limit is exceeded, the Client truncates from the beginning of the output
1217    /// to stay within the limit.
1218    ///
1219    /// The Client MUST ensure truncation happens at a character boundary to maintain valid
1220    /// string output, even if this means the retained output is slightly less than the
1221    /// specified limit.
1222    #[must_use]
1223    pub fn output_byte_limit(mut self, output_byte_limit: impl IntoOption<u64>) -> Self {
1224        self.output_byte_limit = output_byte_limit.into_option();
1225        self
1226    }
1227
1228    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1229    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1230    /// these keys.
1231    ///
1232    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1233    #[must_use]
1234    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1235        self.meta = meta.into_option();
1236        self
1237    }
1238}
1239
1240/// Response containing the ID of the created terminal.
1241#[serde_as]
1242#[skip_serializing_none]
1243#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1244#[serde(rename_all = "camelCase")]
1245#[schemars(extend("x-side" = "client", "x-method" = TERMINAL_CREATE_METHOD_NAME))]
1246#[non_exhaustive]
1247pub struct CreateTerminalResponse {
1248    /// The unique identifier for the created terminal.
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_as(deserialize_as = "DefaultOnError")]
1256    #[schemars(extend("x-deserialize-default-on-error" = true))]
1257    #[serde(default)]
1258    #[serde(rename = "_meta")]
1259    pub meta: Option<Meta>,
1260}
1261
1262impl CreateTerminalResponse {
1263    /// Builds [`CreateTerminalResponse`] with the required response fields set; optional fields start unset or empty.
1264    #[must_use]
1265    pub fn new(terminal_id: impl Into<TerminalId>) -> Self {
1266        Self {
1267            terminal_id: terminal_id.into(),
1268            meta: None,
1269        }
1270    }
1271
1272    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1273    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1274    /// these keys.
1275    ///
1276    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1277    #[must_use]
1278    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1279        self.meta = meta.into_option();
1280        self
1281    }
1282}
1283
1284/// Request to get the current output and status of a terminal.
1285#[serde_as]
1286#[skip_serializing_none]
1287#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1288#[serde(rename_all = "camelCase")]
1289#[schemars(extend("x-side" = "client", "x-method" = TERMINAL_OUTPUT_METHOD_NAME))]
1290#[non_exhaustive]
1291pub struct TerminalOutputRequest {
1292    /// The session ID for this request.
1293    pub session_id: SessionId,
1294    /// The ID of the terminal to get output from.
1295    pub terminal_id: TerminalId,
1296    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1297    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1298    /// these keys.
1299    ///
1300    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1301    #[serde_as(deserialize_as = "DefaultOnError")]
1302    #[schemars(extend("x-deserialize-default-on-error" = true))]
1303    #[serde(default)]
1304    #[serde(rename = "_meta")]
1305    pub meta: Option<Meta>,
1306}
1307
1308impl TerminalOutputRequest {
1309    /// Builds [`TerminalOutputRequest`] with the required request fields set; optional fields start unset or empty.
1310    #[must_use]
1311    pub fn new(session_id: impl Into<SessionId>, terminal_id: impl Into<TerminalId>) -> Self {
1312        Self {
1313            session_id: session_id.into(),
1314            terminal_id: terminal_id.into(),
1315            meta: None,
1316        }
1317    }
1318
1319    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1320    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1321    /// these keys.
1322    ///
1323    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1324    #[must_use]
1325    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1326        self.meta = meta.into_option();
1327        self
1328    }
1329}
1330
1331/// Response containing the terminal output and exit status.
1332#[serde_as]
1333#[skip_serializing_none]
1334#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1335#[serde(rename_all = "camelCase")]
1336#[schemars(extend("x-side" = "client", "x-method" = TERMINAL_OUTPUT_METHOD_NAME))]
1337#[non_exhaustive]
1338pub struct TerminalOutputResponse {
1339    /// The terminal output captured so far.
1340    pub output: String,
1341    /// Whether the output was truncated due to byte limits.
1342    pub truncated: bool,
1343    /// Exit status if the command has completed.
1344    #[serde_as(deserialize_as = "DefaultOnError")]
1345    #[schemars(extend("x-deserialize-default-on-error" = true))]
1346    #[serde(default)]
1347    pub exit_status: Option<TerminalExitStatus>,
1348    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1349    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1350    /// these keys.
1351    ///
1352    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1353    #[serde_as(deserialize_as = "DefaultOnError")]
1354    #[schemars(extend("x-deserialize-default-on-error" = true))]
1355    #[serde(default)]
1356    #[serde(rename = "_meta")]
1357    pub meta: Option<Meta>,
1358}
1359
1360impl TerminalOutputResponse {
1361    /// Builds [`TerminalOutputResponse`] with the required response fields set; optional fields start unset or empty.
1362    #[must_use]
1363    pub fn new(output: impl Into<String>, truncated: bool) -> Self {
1364        Self {
1365            output: output.into(),
1366            truncated,
1367            exit_status: None,
1368            meta: None,
1369        }
1370    }
1371
1372    /// Exit status if the command has completed.
1373    #[must_use]
1374    pub fn exit_status(mut self, exit_status: impl IntoOption<TerminalExitStatus>) -> Self {
1375        self.exit_status = exit_status.into_option();
1376        self
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 release a terminal and free its resources.
1392#[serde_as]
1393#[skip_serializing_none]
1394#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1395#[serde(rename_all = "camelCase")]
1396#[schemars(extend("x-side" = "client", "x-method" = TERMINAL_RELEASE_METHOD_NAME))]
1397#[non_exhaustive]
1398pub struct ReleaseTerminalRequest {
1399    /// The session ID for this request.
1400    pub session_id: SessionId,
1401    /// The ID of the terminal to release.
1402    pub terminal_id: TerminalId,
1403    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1404    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1405    /// these keys.
1406    ///
1407    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1408    #[serde_as(deserialize_as = "DefaultOnError")]
1409    #[schemars(extend("x-deserialize-default-on-error" = true))]
1410    #[serde(default)]
1411    #[serde(rename = "_meta")]
1412    pub meta: Option<Meta>,
1413}
1414
1415impl ReleaseTerminalRequest {
1416    /// Builds [`ReleaseTerminalRequest`] with the required request fields set; optional fields start unset or empty.
1417    #[must_use]
1418    pub fn new(session_id: impl Into<SessionId>, terminal_id: impl Into<TerminalId>) -> Self {
1419        Self {
1420            session_id: session_id.into(),
1421            terminal_id: terminal_id.into(),
1422            meta: None,
1423        }
1424    }
1425
1426    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1427    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1428    /// these keys.
1429    ///
1430    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1431    #[must_use]
1432    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1433        self.meta = meta.into_option();
1434        self
1435    }
1436}
1437
1438/// Response to terminal/release method
1439#[serde_as]
1440#[skip_serializing_none]
1441#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1442#[serde(rename_all = "camelCase")]
1443#[schemars(extend("x-side" = "client", "x-method" = TERMINAL_RELEASE_METHOD_NAME))]
1444#[non_exhaustive]
1445pub struct ReleaseTerminalResponse {
1446    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1447    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1448    /// these keys.
1449    ///
1450    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1451    #[serde_as(deserialize_as = "DefaultOnError")]
1452    #[schemars(extend("x-deserialize-default-on-error" = true))]
1453    #[serde(default)]
1454    #[serde(rename = "_meta")]
1455    pub meta: Option<Meta>,
1456}
1457
1458impl ReleaseTerminalResponse {
1459    /// Builds [`ReleaseTerminalResponse`] with the required response fields set; optional fields start unset or empty.
1460    #[must_use]
1461    pub fn new() -> Self {
1462        Self::default()
1463    }
1464
1465    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1466    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1467    /// these keys.
1468    ///
1469    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1470    #[must_use]
1471    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1472        self.meta = meta.into_option();
1473        self
1474    }
1475}
1476
1477/// Request to kill a terminal without releasing it.
1478#[serde_as]
1479#[skip_serializing_none]
1480#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1481#[serde(rename_all = "camelCase")]
1482#[schemars(extend("x-side" = "client", "x-method" = TERMINAL_KILL_METHOD_NAME))]
1483#[non_exhaustive]
1484pub struct KillTerminalRequest {
1485    /// The session ID for this request.
1486    pub session_id: SessionId,
1487    /// The ID of the terminal to kill.
1488    pub terminal_id: TerminalId,
1489    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1490    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1491    /// these keys.
1492    ///
1493    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1494    #[serde_as(deserialize_as = "DefaultOnError")]
1495    #[schemars(extend("x-deserialize-default-on-error" = true))]
1496    #[serde(default)]
1497    #[serde(rename = "_meta")]
1498    pub meta: Option<Meta>,
1499}
1500
1501impl KillTerminalRequest {
1502    /// Builds [`KillTerminalRequest`] with the required request fields set; optional fields start unset or empty.
1503    #[must_use]
1504    pub fn new(session_id: impl Into<SessionId>, terminal_id: impl Into<TerminalId>) -> Self {
1505        Self {
1506            session_id: session_id.into(),
1507            terminal_id: terminal_id.into(),
1508            meta: None,
1509        }
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/// Response to `terminal/kill` method
1525#[serde_as]
1526#[skip_serializing_none]
1527#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1528#[serde(rename_all = "camelCase")]
1529#[schemars(extend("x-side" = "client", "x-method" = TERMINAL_KILL_METHOD_NAME))]
1530#[non_exhaustive]
1531pub struct KillTerminalResponse {
1532    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1533    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1534    /// these keys.
1535    ///
1536    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1537    #[serde_as(deserialize_as = "DefaultOnError")]
1538    #[schemars(extend("x-deserialize-default-on-error" = true))]
1539    #[serde(default)]
1540    #[serde(rename = "_meta")]
1541    pub meta: Option<Meta>,
1542}
1543
1544impl KillTerminalResponse {
1545    /// Builds [`KillTerminalResponse`] with the required response fields set; optional fields start unset or empty.
1546    #[must_use]
1547    pub fn new() -> Self {
1548        Self::default()
1549    }
1550
1551    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1552    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1553    /// these keys.
1554    ///
1555    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1556    #[must_use]
1557    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1558        self.meta = meta.into_option();
1559        self
1560    }
1561}
1562
1563/// Request to wait for a terminal command to exit.
1564#[serde_as]
1565#[skip_serializing_none]
1566#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1567#[serde(rename_all = "camelCase")]
1568#[schemars(extend("x-side" = "client", "x-method" = TERMINAL_WAIT_FOR_EXIT_METHOD_NAME))]
1569#[non_exhaustive]
1570pub struct WaitForTerminalExitRequest {
1571    /// The session ID for this request.
1572    pub session_id: SessionId,
1573    /// The ID of the terminal to wait for.
1574    pub terminal_id: TerminalId,
1575    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1576    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1577    /// these keys.
1578    ///
1579    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1580    #[serde_as(deserialize_as = "DefaultOnError")]
1581    #[schemars(extend("x-deserialize-default-on-error" = true))]
1582    #[serde(default)]
1583    #[serde(rename = "_meta")]
1584    pub meta: Option<Meta>,
1585}
1586
1587impl WaitForTerminalExitRequest {
1588    /// Builds [`WaitForTerminalExitRequest`] with the required request fields set; optional fields start unset or empty.
1589    #[must_use]
1590    pub fn new(session_id: impl Into<SessionId>, terminal_id: impl Into<TerminalId>) -> Self {
1591        Self {
1592            session_id: session_id.into(),
1593            terminal_id: terminal_id.into(),
1594            meta: None,
1595        }
1596    }
1597
1598    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1599    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1600    /// these keys.
1601    ///
1602    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1603    #[must_use]
1604    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1605        self.meta = meta.into_option();
1606        self
1607    }
1608}
1609
1610/// Response containing the exit status of a terminal command.
1611#[serde_as]
1612#[skip_serializing_none]
1613#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1614#[serde(rename_all = "camelCase")]
1615#[schemars(extend("x-side" = "client", "x-method" = TERMINAL_WAIT_FOR_EXIT_METHOD_NAME))]
1616#[non_exhaustive]
1617pub struct WaitForTerminalExitResponse {
1618    /// The exit status of the terminal command.
1619    #[serde(flatten)]
1620    pub exit_status: TerminalExitStatus,
1621    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1622    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1623    /// these keys.
1624    ///
1625    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1626    #[serde_as(deserialize_as = "DefaultOnError")]
1627    #[schemars(extend("x-deserialize-default-on-error" = true))]
1628    #[serde(default)]
1629    #[serde(rename = "_meta")]
1630    pub meta: Option<Meta>,
1631}
1632
1633impl WaitForTerminalExitResponse {
1634    /// Builds [`WaitForTerminalExitResponse`] with the required response fields set; optional fields start unset or empty.
1635    #[must_use]
1636    pub fn new(exit_status: TerminalExitStatus) -> Self {
1637        Self {
1638            exit_status,
1639            meta: None,
1640        }
1641    }
1642
1643    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1644    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1645    /// these keys.
1646    ///
1647    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1648    #[must_use]
1649    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1650        self.meta = meta.into_option();
1651        self
1652    }
1653}
1654
1655/// Exit status of a terminal command.
1656#[serde_as]
1657#[skip_serializing_none]
1658#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1659#[serde(rename_all = "camelCase")]
1660#[non_exhaustive]
1661pub struct TerminalExitStatus {
1662    /// The process exit code (may be null if terminated by signal).
1663    #[serde_as(deserialize_as = "DefaultOnError")]
1664    #[schemars(extend("x-deserialize-default-on-error" = true))]
1665    #[serde(default)]
1666    pub exit_code: Option<u32>,
1667    /// The signal that terminated the process (may be null if exited normally).
1668    #[serde_as(deserialize_as = "DefaultOnError")]
1669    #[schemars(extend("x-deserialize-default-on-error" = true))]
1670    #[serde(default)]
1671    pub signal: Option<String>,
1672    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1673    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1674    /// these keys.
1675    ///
1676    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1677    #[serde_as(deserialize_as = "DefaultOnError")]
1678    #[schemars(extend("x-deserialize-default-on-error" = true))]
1679    #[serde(default)]
1680    #[serde(rename = "_meta")]
1681    pub meta: Option<Meta>,
1682}
1683
1684impl TerminalExitStatus {
1685    /// Builds [`TerminalExitStatus`] with the required fields set; optional fields start unset or empty.
1686    #[must_use]
1687    pub fn new() -> Self {
1688        Self::default()
1689    }
1690
1691    /// The process exit code (may be null if terminated by signal).
1692    #[must_use]
1693    pub fn exit_code(mut self, exit_code: impl IntoOption<u32>) -> Self {
1694        self.exit_code = exit_code.into_option();
1695        self
1696    }
1697
1698    /// The signal that terminated the process (may be null if exited normally).
1699    #[must_use]
1700    pub fn signal(mut self, signal: impl IntoOption<String>) -> Self {
1701        self.signal = signal.into_option();
1702        self
1703    }
1704
1705    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1706    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1707    /// these keys.
1708    ///
1709    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1710    #[must_use]
1711    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1712        self.meta = meta.into_option();
1713        self
1714    }
1715}
1716
1717// Capabilities
1718
1719/// Capabilities supported by the client.
1720///
1721/// Advertised during initialization to inform the agent about
1722/// available features and methods.
1723///
1724/// See protocol docs: [Client Capabilities](https://agentclientprotocol.com/protocol/initialization#client-capabilities)
1725#[serde_as]
1726#[skip_serializing_none]
1727#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1728#[serde(rename_all = "camelCase")]
1729#[non_exhaustive]
1730pub struct ClientCapabilities {
1731    /// File system capabilities supported by the client.
1732    /// Determines which file operations the agent can request.
1733    #[serde_as(deserialize_as = "DefaultOnError")]
1734    #[schemars(extend("x-deserialize-default-on-error" = true))]
1735    #[serde(default)]
1736    pub fs: FileSystemCapabilities,
1737    /// Whether the Client support all `terminal/*` methods.
1738    #[serde_as(deserialize_as = "DefaultOnError")]
1739    #[schemars(extend("x-deserialize-default-on-error" = true))]
1740    #[serde(default)]
1741    pub terminal: bool,
1742    /// Session-related capabilities supported by the client.
1743    ///
1744    /// Optional. Omitted or `null` both mean the client does not advertise any
1745    /// session-related extensions.
1746    #[serde_as(deserialize_as = "DefaultOnError")]
1747    #[schemars(extend("x-deserialize-default-on-error" = true))]
1748    #[serde(default)]
1749    pub session: Option<ClientSessionCapabilities>,
1750    /// **UNSTABLE**
1751    ///
1752    /// This capability is not part of the spec yet, and may be removed or changed at any point.
1753    ///
1754    /// Whether the client supports `plan_update` and `plan_removed` session updates.
1755    ///
1756    /// Optional. Omitted or `null` both mean the client does not advertise support.
1757    /// Supplying `{}` means the client can receive both update types.
1758    #[cfg(feature = "unstable_plan_operations")]
1759    #[serde_as(deserialize_as = "DefaultOnError")]
1760    #[schemars(extend("x-deserialize-default-on-error" = true))]
1761    #[serde(default)]
1762    pub plan: Option<PlanCapabilities>,
1763    /// **UNSTABLE**
1764    ///
1765    /// This capability is not part of the spec yet, and may be removed or changed at any point.
1766    ///
1767    /// Authentication capabilities supported by the client.
1768    /// Determines which authentication method types the agent may include
1769    /// in its `InitializeResponse`.
1770    #[cfg(feature = "unstable_auth_methods")]
1771    #[serde_as(deserialize_as = "DefaultOnError")]
1772    #[schemars(extend("x-deserialize-default-on-error" = true))]
1773    #[serde(default)]
1774    pub auth: AuthCapabilities,
1775    /// **UNSTABLE**
1776    ///
1777    /// This capability is not part of the spec yet, and may be removed or changed at any point.
1778    ///
1779    /// Elicitation capabilities supported by the client.
1780    /// Determines which elicitation modes the agent may use.
1781    ///
1782    /// Optional. Omitted or `null` both mean the client does not advertise
1783    /// elicitation support.
1784    #[cfg(feature = "unstable_elicitation")]
1785    #[serde_as(deserialize_as = "DefaultOnError")]
1786    #[schemars(extend("x-deserialize-default-on-error" = true))]
1787    #[serde(default)]
1788    pub elicitation: Option<ElicitationCapabilities>,
1789    /// **UNSTABLE**
1790    ///
1791    /// This capability is not part of the spec yet, and may be removed or changed at any point.
1792    ///
1793    /// NES (Next Edit Suggestions) capabilities supported by the client.
1794    ///
1795    /// Optional. Omitted or `null` both mean the client does not advertise any
1796    /// NES suggestion-kind extensions.
1797    #[cfg(feature = "unstable_nes")]
1798    #[serde_as(deserialize_as = "DefaultOnError")]
1799    #[schemars(extend("x-deserialize-default-on-error" = true))]
1800    #[serde(default)]
1801    pub nes: Option<ClientNesCapabilities>,
1802    /// **UNSTABLE**
1803    ///
1804    /// This capability is not part of the spec yet, and may be removed or changed at any point.
1805    ///
1806    /// The position encodings supported by the client, in order of preference.
1807    #[cfg(feature = "unstable_nes")]
1808    #[serde_as(deserialize_as = "DefaultOnError<VecSkipError<_, SkipListener>>")]
1809    #[schemars(extend("x-deserialize-default-on-error" = true, "x-deserialize-skip-invalid-items" = true))]
1810    #[serde(default, skip_serializing_if = "Vec::is_empty")]
1811    pub position_encodings: Vec<PositionEncodingKind>,
1812
1813    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1814    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1815    /// these keys.
1816    ///
1817    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1818    #[serde_as(deserialize_as = "DefaultOnError")]
1819    #[schemars(extend("x-deserialize-default-on-error" = true))]
1820    #[serde(default)]
1821    #[serde(rename = "_meta")]
1822    pub meta: Option<Meta>,
1823}
1824
1825impl ClientCapabilities {
1826    /// Builds an empty [`ClientCapabilities`]; use builder methods to advertise supported sub-capabilities.
1827    #[must_use]
1828    pub fn new() -> Self {
1829        Self::default()
1830    }
1831
1832    /// File system capabilities supported by the client.
1833    /// Determines which file operations the agent can request.
1834    #[must_use]
1835    pub fn fs(mut self, fs: FileSystemCapabilities) -> Self {
1836        self.fs = fs;
1837        self
1838    }
1839
1840    /// Whether the Client support all `terminal/*` methods.
1841    #[must_use]
1842    pub fn terminal(mut self, terminal: bool) -> Self {
1843        self.terminal = terminal;
1844        self
1845    }
1846
1847    /// Session-related capabilities supported by the client.
1848    #[must_use]
1849    pub fn session(mut self, session: impl IntoOption<ClientSessionCapabilities>) -> Self {
1850        self.session = session.into_option();
1851        self
1852    }
1853
1854    /// **UNSTABLE**
1855    ///
1856    /// This capability is not part of the spec yet, and may be removed or changed at any point.
1857    ///
1858    /// Whether the client supports `plan_update` and `plan_removed` session updates.
1859    ///
1860    /// Omitted or `null` both mean the client does not advertise support.
1861    /// Supplying `{}` means the client can receive both update types.
1862    #[cfg(feature = "unstable_plan_operations")]
1863    #[must_use]
1864    pub fn plan(mut self, plan: impl IntoOption<PlanCapabilities>) -> Self {
1865        self.plan = plan.into_option();
1866        self
1867    }
1868
1869    /// **UNSTABLE**
1870    ///
1871    /// This capability is not part of the spec yet, and may be removed or changed at any point.
1872    ///
1873    /// Authentication capabilities supported by the client.
1874    /// Determines which authentication method types the agent may include
1875    /// in its `InitializeResponse`.
1876    #[cfg(feature = "unstable_auth_methods")]
1877    #[must_use]
1878    pub fn auth(mut self, auth: AuthCapabilities) -> Self {
1879        self.auth = auth;
1880        self
1881    }
1882
1883    /// **UNSTABLE**
1884    ///
1885    /// This capability is not part of the spec yet, and may be removed or changed at any point.
1886    ///
1887    /// Elicitation capabilities supported by the client.
1888    /// Determines which elicitation modes the agent may use.
1889    #[cfg(feature = "unstable_elicitation")]
1890    #[must_use]
1891    pub fn elicitation(mut self, elicitation: impl IntoOption<ElicitationCapabilities>) -> Self {
1892        self.elicitation = elicitation.into_option();
1893        self
1894    }
1895
1896    /// **UNSTABLE**
1897    ///
1898    /// NES (Next Edit Suggestions) capabilities supported by the client.
1899    #[cfg(feature = "unstable_nes")]
1900    #[must_use]
1901    pub fn nes(mut self, nes: impl IntoOption<ClientNesCapabilities>) -> Self {
1902        self.nes = nes.into_option();
1903        self
1904    }
1905
1906    /// **UNSTABLE**
1907    ///
1908    /// The position encodings supported by the client, in order of preference.
1909    #[cfg(feature = "unstable_nes")]
1910    #[must_use]
1911    pub fn position_encodings(mut self, position_encodings: Vec<PositionEncodingKind>) -> Self {
1912        self.position_encodings = position_encodings;
1913        self
1914    }
1915
1916    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1917    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1918    /// these keys.
1919    ///
1920    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1921    #[must_use]
1922    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1923        self.meta = meta.into_option();
1924        self
1925    }
1926}
1927
1928/// Session-related capabilities supported by the client.
1929#[serde_as]
1930#[skip_serializing_none]
1931#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1932#[serde(rename_all = "camelCase")]
1933#[non_exhaustive]
1934pub struct ClientSessionCapabilities {
1935    /// Config option capabilities supported by the client.
1936    ///
1937    /// Omitted or `null` both mean the client does not advertise support for any
1938    /// config option extensions.
1939    #[serde_as(deserialize_as = "DefaultOnError")]
1940    #[schemars(extend("x-deserialize-default-on-error" = true))]
1941    #[serde(default)]
1942    pub config_options: Option<SessionConfigOptionsCapabilities>,
1943    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1944    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1945    /// these keys.
1946    ///
1947    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1948    #[serde_as(deserialize_as = "DefaultOnError")]
1949    #[schemars(extend("x-deserialize-default-on-error" = true))]
1950    #[serde(default)]
1951    #[serde(rename = "_meta")]
1952    pub meta: Option<Meta>,
1953}
1954
1955impl ClientSessionCapabilities {
1956    /// Builds an empty [`ClientSessionCapabilities`]; use builder methods to advertise supported sub-capabilities.
1957    #[must_use]
1958    pub fn new() -> Self {
1959        Self::default()
1960    }
1961
1962    /// Config option capabilities supported by the client.
1963    ///
1964    /// Omitted or `null` both mean the client does not advertise support for any
1965    /// config option extensions.
1966    #[must_use]
1967    pub fn config_options(
1968        mut self,
1969        config_options: impl IntoOption<SessionConfigOptionsCapabilities>,
1970    ) -> Self {
1971        self.config_options = config_options.into_option();
1972        self
1973    }
1974
1975    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1976    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1977    /// these keys.
1978    ///
1979    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1980    #[must_use]
1981    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1982        self.meta = meta.into_option();
1983        self
1984    }
1985}
1986
1987/// Session configuration option capabilities supported by the client.
1988#[serde_as]
1989#[skip_serializing_none]
1990#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1991#[serde(rename_all = "camelCase")]
1992#[non_exhaustive]
1993pub struct SessionConfigOptionsCapabilities {
1994    /// Whether the client supports boolean session configuration options.
1995    ///
1996    /// Optional. Omitted or `null` both mean the client does not advertise support.
1997    /// Supplying `{}` means agents may include `type: "boolean"` entries in
1998    /// `configOptions`, and the client may send `session/set_config_option`
1999    /// requests with `type: "boolean"` and a boolean `value`.
2000    #[serde_as(deserialize_as = "DefaultOnError")]
2001    #[schemars(extend("x-deserialize-default-on-error" = true))]
2002    #[serde(default)]
2003    pub boolean: Option<BooleanConfigOptionCapabilities>,
2004    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
2005    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
2006    /// these keys.
2007    ///
2008    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
2009    #[serde_as(deserialize_as = "DefaultOnError")]
2010    #[schemars(extend("x-deserialize-default-on-error" = true))]
2011    #[serde(default)]
2012    #[serde(rename = "_meta")]
2013    pub meta: Option<Meta>,
2014}
2015
2016impl SessionConfigOptionsCapabilities {
2017    /// Builds an empty [`SessionConfigOptionsCapabilities`]; use builder methods to advertise supported sub-capabilities.
2018    #[must_use]
2019    pub fn new() -> Self {
2020        Self::default()
2021    }
2022
2023    /// Whether the client supports boolean session configuration options.
2024    ///
2025    /// Omitted or `null` both mean the client does not advertise support.
2026    /// Supplying `{}` means agents may include `type: "boolean"` entries in
2027    /// `configOptions`, and the client may send `session/set_config_option`
2028    /// requests with `type: "boolean"` and a boolean `value`.
2029    #[must_use]
2030    pub fn boolean(mut self, boolean: impl IntoOption<BooleanConfigOptionCapabilities>) -> Self {
2031        self.boolean = boolean.into_option();
2032        self
2033    }
2034
2035    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
2036    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
2037    /// these keys.
2038    ///
2039    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
2040    #[must_use]
2041    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2042        self.meta = meta.into_option();
2043        self
2044    }
2045}
2046
2047/// Capabilities for boolean session configuration options.
2048///
2049/// Supplying `{}` means the client supports boolean session configuration options.
2050#[serde_as]
2051#[skip_serializing_none]
2052#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2053#[non_exhaustive]
2054pub struct BooleanConfigOptionCapabilities {
2055    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
2056    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
2057    /// these keys.
2058    ///
2059    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
2060    #[serde_as(deserialize_as = "DefaultOnError")]
2061    #[schemars(extend("x-deserialize-default-on-error" = true))]
2062    #[serde(default)]
2063    #[serde(rename = "_meta")]
2064    pub meta: Option<Meta>,
2065}
2066
2067impl BooleanConfigOptionCapabilities {
2068    /// Builds an empty [`BooleanConfigOptionCapabilities`]; use builder methods to advertise supported sub-capabilities.
2069    #[must_use]
2070    pub fn new() -> Self {
2071        Self::default()
2072    }
2073
2074    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
2075    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
2076    /// these keys.
2077    ///
2078    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
2079    #[must_use]
2080    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2081        self.meta = meta.into_option();
2082        self
2083    }
2084}
2085
2086/// **UNSTABLE**
2087///
2088/// This capability is not part of the spec yet, and may be removed or changed at any point.
2089///
2090/// Authentication capabilities supported by the client.
2091///
2092/// Advertised during initialization to inform the agent which authentication
2093/// method types the client can handle. This governs opt-in types that require
2094/// additional client-side support.
2095#[cfg(feature = "unstable_auth_methods")]
2096#[serde_as]
2097#[skip_serializing_none]
2098#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2099#[serde(rename_all = "camelCase")]
2100#[non_exhaustive]
2101pub struct AuthCapabilities {
2102    /// Whether the client supports `terminal` authentication methods.
2103    ///
2104    /// When `true`, the agent may include `terminal` entries in its authentication methods.
2105    #[serde_as(deserialize_as = "DefaultOnError")]
2106    #[schemars(extend("x-deserialize-default-on-error" = true))]
2107    #[serde(default)]
2108    pub terminal: bool,
2109    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
2110    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
2111    /// these keys.
2112    ///
2113    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
2114    #[serde_as(deserialize_as = "DefaultOnError")]
2115    #[schemars(extend("x-deserialize-default-on-error" = true))]
2116    #[serde(default)]
2117    #[serde(rename = "_meta")]
2118    pub meta: Option<Meta>,
2119}
2120
2121#[cfg(feature = "unstable_auth_methods")]
2122impl AuthCapabilities {
2123    /// Builds an empty [`AuthCapabilities`]; use builder methods to advertise supported sub-capabilities.
2124    #[must_use]
2125    pub fn new() -> Self {
2126        Self::default()
2127    }
2128
2129    /// Whether the client supports `terminal` authentication methods.
2130    ///
2131    /// When `true`, the agent may include `AuthMethod::Terminal`
2132    /// entries in its authentication methods.
2133    #[must_use]
2134    pub fn terminal(mut self, terminal: bool) -> Self {
2135        self.terminal = terminal;
2136        self
2137    }
2138
2139    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
2140    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
2141    /// these keys.
2142    ///
2143    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
2144    #[must_use]
2145    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2146        self.meta = meta.into_option();
2147        self
2148    }
2149}
2150
2151/// File system capabilities that a client may support.
2152///
2153/// See protocol docs: [FileSystem](https://agentclientprotocol.com/protocol/initialization#filesystem)
2154#[serde_as]
2155#[skip_serializing_none]
2156#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2157#[serde(rename_all = "camelCase")]
2158#[non_exhaustive]
2159pub struct FileSystemCapabilities {
2160    /// Whether the Client supports `fs/read_text_file` requests.
2161    #[serde_as(deserialize_as = "DefaultOnError")]
2162    #[schemars(extend("x-deserialize-default-on-error" = true))]
2163    #[serde(default)]
2164    pub read_text_file: bool,
2165    /// Whether the Client supports `fs/write_text_file` requests.
2166    #[serde_as(deserialize_as = "DefaultOnError")]
2167    #[schemars(extend("x-deserialize-default-on-error" = true))]
2168    #[serde(default)]
2169    pub write_text_file: bool,
2170    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
2171    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
2172    /// these keys.
2173    ///
2174    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
2175    #[serde_as(deserialize_as = "DefaultOnError")]
2176    #[schemars(extend("x-deserialize-default-on-error" = true))]
2177    #[serde(default)]
2178    #[serde(rename = "_meta")]
2179    pub meta: Option<Meta>,
2180}
2181
2182impl FileSystemCapabilities {
2183    /// Builds an empty [`FileSystemCapabilities`]; use builder methods to advertise supported sub-capabilities.
2184    #[must_use]
2185    pub fn new() -> Self {
2186        Self::default()
2187    }
2188
2189    /// Whether the Client supports `fs/read_text_file` requests.
2190    #[must_use]
2191    pub fn read_text_file(mut self, read_text_file: bool) -> Self {
2192        self.read_text_file = read_text_file;
2193        self
2194    }
2195
2196    /// Whether the Client supports `fs/write_text_file` requests.
2197    #[must_use]
2198    pub fn write_text_file(mut self, write_text_file: bool) -> Self {
2199        self.write_text_file = write_text_file;
2200        self
2201    }
2202
2203    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
2204    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
2205    /// these keys.
2206    ///
2207    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
2208    #[must_use]
2209    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2210        self.meta = meta.into_option();
2211        self
2212    }
2213}
2214
2215// Method schema
2216
2217/// Names of all methods that clients handle.
2218///
2219/// Provides a centralized definition of method names used in the protocol.
2220#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
2221#[non_exhaustive]
2222pub struct ClientMethodNames {
2223    /// Method for requesting permission from the user.
2224    pub session_request_permission: &'static str,
2225    /// Notification for session updates.
2226    pub session_update: &'static str,
2227    /// Method for writing text files.
2228    pub fs_write_text_file: &'static str,
2229    /// Method for reading text files.
2230    pub fs_read_text_file: &'static str,
2231    /// Method for creating new terminals.
2232    pub terminal_create: &'static str,
2233    /// Method for getting terminals output.
2234    pub terminal_output: &'static str,
2235    /// Method for releasing a terminal.
2236    pub terminal_release: &'static str,
2237    /// Method for waiting for a terminal to finish.
2238    pub terminal_wait_for_exit: &'static str,
2239    /// Method for killing a terminal.
2240    pub terminal_kill: &'static str,
2241    /// Method for opening an MCP-over-ACP connection.
2242    #[cfg(feature = "unstable_mcp_over_acp")]
2243    pub mcp_connect: &'static str,
2244    /// Method for exchanging MCP-over-ACP messages.
2245    #[cfg(feature = "unstable_mcp_over_acp")]
2246    pub mcp_message: &'static str,
2247    /// Method for closing an MCP-over-ACP connection.
2248    #[cfg(feature = "unstable_mcp_over_acp")]
2249    pub mcp_disconnect: &'static str,
2250    /// Method for elicitation.
2251    #[cfg(feature = "unstable_elicitation")]
2252    pub elicitation_create: &'static str,
2253    /// Notification for elicitation completion.
2254    #[cfg(feature = "unstable_elicitation")]
2255    pub elicitation_complete: &'static str,
2256}
2257
2258/// Constant containing all client method names.
2259pub const CLIENT_METHOD_NAMES: ClientMethodNames = ClientMethodNames {
2260    session_update: SESSION_UPDATE_NOTIFICATION,
2261    session_request_permission: SESSION_REQUEST_PERMISSION_METHOD_NAME,
2262    fs_write_text_file: FS_WRITE_TEXT_FILE_METHOD_NAME,
2263    fs_read_text_file: FS_READ_TEXT_FILE_METHOD_NAME,
2264    terminal_create: TERMINAL_CREATE_METHOD_NAME,
2265    terminal_output: TERMINAL_OUTPUT_METHOD_NAME,
2266    terminal_release: TERMINAL_RELEASE_METHOD_NAME,
2267    terminal_wait_for_exit: TERMINAL_WAIT_FOR_EXIT_METHOD_NAME,
2268    terminal_kill: TERMINAL_KILL_METHOD_NAME,
2269    #[cfg(feature = "unstable_mcp_over_acp")]
2270    mcp_connect: MCP_CONNECT_METHOD_NAME,
2271    #[cfg(feature = "unstable_mcp_over_acp")]
2272    mcp_message: MCP_MESSAGE_METHOD_NAME,
2273    #[cfg(feature = "unstable_mcp_over_acp")]
2274    mcp_disconnect: MCP_DISCONNECT_METHOD_NAME,
2275    #[cfg(feature = "unstable_elicitation")]
2276    elicitation_create: ELICITATION_CREATE_METHOD_NAME,
2277    #[cfg(feature = "unstable_elicitation")]
2278    elicitation_complete: ELICITATION_COMPLETE_NOTIFICATION,
2279};
2280
2281/// Notification name for session updates.
2282pub(crate) const SESSION_UPDATE_NOTIFICATION: &str = "session/update";
2283/// Method name for requesting user permission.
2284pub(crate) const SESSION_REQUEST_PERMISSION_METHOD_NAME: &str = "session/request_permission";
2285/// Method name for writing text files.
2286pub(crate) const FS_WRITE_TEXT_FILE_METHOD_NAME: &str = "fs/write_text_file";
2287/// Method name for reading text files.
2288pub(crate) const FS_READ_TEXT_FILE_METHOD_NAME: &str = "fs/read_text_file";
2289/// Method name for creating a new terminal.
2290pub(crate) const TERMINAL_CREATE_METHOD_NAME: &str = "terminal/create";
2291/// Method for getting terminals output.
2292pub(crate) const TERMINAL_OUTPUT_METHOD_NAME: &str = "terminal/output";
2293/// Method for releasing a terminal.
2294pub(crate) const TERMINAL_RELEASE_METHOD_NAME: &str = "terminal/release";
2295/// Method for waiting for a terminal to finish.
2296pub(crate) const TERMINAL_WAIT_FOR_EXIT_METHOD_NAME: &str = "terminal/wait_for_exit";
2297/// Method for killing a terminal.
2298pub(crate) const TERMINAL_KILL_METHOD_NAME: &str = "terminal/kill";
2299/// Method name for elicitation.
2300#[cfg(feature = "unstable_elicitation")]
2301pub(crate) const ELICITATION_CREATE_METHOD_NAME: &str = "elicitation/create";
2302/// Notification name for elicitation completion.
2303#[cfg(feature = "unstable_elicitation")]
2304pub(crate) const ELICITATION_COMPLETE_NOTIFICATION: &str = "elicitation/complete";
2305
2306/// All possible requests that an agent can send to a client.
2307///
2308/// This enum is used internally for routing RPC requests. You typically won't need
2309/// to use this directly.
2310///
2311/// This enum encompasses all method calls from agent to client.
2312#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
2313#[serde(untagged)]
2314#[schemars(inline)]
2315#[non_exhaustive]
2316#[allow(clippy::large_enum_variant)]
2317pub enum AgentRequest {
2318    /// Writes content to a text file in the client's file system.
2319    ///
2320    /// Only available if the client advertises the `fs.writeTextFile` capability.
2321    /// Allows the agent to create or modify files within the client's environment.
2322    ///
2323    /// See protocol docs: [Client](https://agentclientprotocol.com/protocol/overview#client)
2324    WriteTextFileRequest(WriteTextFileRequest),
2325    /// Reads content from a text file in the client's file system.
2326    ///
2327    /// Only available if the client advertises the `fs.readTextFile` capability.
2328    /// Allows the agent to access file contents within the client's environment.
2329    ///
2330    /// See protocol docs: [Client](https://agentclientprotocol.com/protocol/overview#client)
2331    ReadTextFileRequest(ReadTextFileRequest),
2332    /// Requests permission from the user for a tool call operation.
2333    ///
2334    /// Called by the agent when it needs user authorization before executing
2335    /// a potentially sensitive operation. The client should present the options
2336    /// to the user and return their decision.
2337    ///
2338    /// If the client cancels the prompt turn via `session/cancel`, it MUST
2339    /// respond to this request with `RequestPermissionOutcome::Cancelled`.
2340    ///
2341    /// See protocol docs: [Requesting Permission](https://agentclientprotocol.com/protocol/tool-calls#requesting-permission)
2342    RequestPermissionRequest(RequestPermissionRequest),
2343    /// Executes a command in a new terminal
2344    ///
2345    /// Only available if the `terminal` Client capability is set to `true`.
2346    ///
2347    /// Returns a `TerminalId` that can be used with other terminal methods
2348    /// to get the current output, wait for exit, and kill the command.
2349    ///
2350    /// The `TerminalId` can also be used to embed the terminal in a tool call
2351    /// by using the `ToolCallContent::Terminal` variant.
2352    ///
2353    /// The Agent is responsible for releasing the terminal by using the `terminal/release`
2354    /// method.
2355    ///
2356    /// See protocol docs: [Terminals](https://agentclientprotocol.com/protocol/terminals)
2357    CreateTerminalRequest(CreateTerminalRequest),
2358    /// Gets the terminal output and exit status
2359    ///
2360    /// Returns the current content in the terminal without waiting for the command to exit.
2361    /// If the command has already exited, the exit status is included.
2362    ///
2363    /// See protocol docs: [Terminals](https://agentclientprotocol.com/protocol/terminals)
2364    TerminalOutputRequest(TerminalOutputRequest),
2365    /// Releases a terminal
2366    ///
2367    /// The command is killed if it hasn't exited yet. Use `terminal/wait_for_exit`
2368    /// to wait for the command to exit before releasing the terminal.
2369    ///
2370    /// After release, the `TerminalId` can no longer be used with other `terminal/*` methods,
2371    /// but tool calls that already contain it, continue to display its output.
2372    ///
2373    /// The `terminal/kill` method can be used to terminate the command without releasing
2374    /// the terminal, allowing the Agent to call `terminal/output` and other methods.
2375    ///
2376    /// See protocol docs: [Terminals](https://agentclientprotocol.com/protocol/terminals)
2377    ReleaseTerminalRequest(ReleaseTerminalRequest),
2378    /// Waits for the terminal command to exit and return its exit status
2379    ///
2380    /// See protocol docs: [Terminals](https://agentclientprotocol.com/protocol/terminals)
2381    WaitForTerminalExitRequest(WaitForTerminalExitRequest),
2382    /// Kills the terminal command without releasing the terminal
2383    ///
2384    /// While `terminal/release` will also kill the command, this method will keep
2385    /// the `TerminalId` valid so it can be used with other methods.
2386    ///
2387    /// This method can be helpful when implementing command timeouts which terminate
2388    /// the command as soon as elapsed, and then get the final output so it can be sent
2389    /// to the model.
2390    ///
2391    /// Note: Call `terminal/release` when `TerminalId` is no longer needed.
2392    ///
2393    /// See protocol docs: [Terminals](https://agentclientprotocol.com/protocol/terminals)
2394    KillTerminalRequest(KillTerminalRequest),
2395    /// **UNSTABLE**
2396    ///
2397    /// This capability is not part of the spec yet, and may be removed or changed at any point.
2398    ///
2399    /// Requests structured user input via a form or URL.
2400    #[cfg(feature = "unstable_elicitation")]
2401    CreateElicitationRequest(CreateElicitationRequest),
2402    /// **UNSTABLE**
2403    ///
2404    /// This capability is not part of the spec yet, and may be removed or changed at any point.
2405    ///
2406    /// Opens an MCP-over-ACP connection.
2407    #[cfg(feature = "unstable_mcp_over_acp")]
2408    ConnectMcpRequest(ConnectMcpRequest),
2409    /// **UNSTABLE**
2410    ///
2411    /// This capability is not part of the spec yet, and may be removed or changed at any point.
2412    ///
2413    /// Exchanges an MCP-over-ACP message.
2414    #[cfg(feature = "unstable_mcp_over_acp")]
2415    MessageMcpRequest(MessageMcpRequest),
2416    /// **UNSTABLE**
2417    ///
2418    /// This capability is not part of the spec yet, and may be removed or changed at any point.
2419    ///
2420    /// Closes an MCP-over-ACP connection.
2421    #[cfg(feature = "unstable_mcp_over_acp")]
2422    DisconnectMcpRequest(DisconnectMcpRequest),
2423    /// Handles extension method requests from the agent.
2424    ///
2425    /// Allows the Agent to send an arbitrary request that is not part of the ACP spec.
2426    /// Extension methods provide a way to add custom functionality while maintaining
2427    /// protocol compatibility.
2428    ///
2429    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
2430    ExtMethodRequest(ExtRequest),
2431}
2432
2433impl AgentRequest {
2434    /// Returns the corresponding method name of the request.
2435    #[must_use]
2436    pub fn method(&self) -> &str {
2437        match self {
2438            Self::WriteTextFileRequest(_) => CLIENT_METHOD_NAMES.fs_write_text_file,
2439            Self::ReadTextFileRequest(_) => CLIENT_METHOD_NAMES.fs_read_text_file,
2440            Self::RequestPermissionRequest(_) => CLIENT_METHOD_NAMES.session_request_permission,
2441            Self::CreateTerminalRequest(_) => CLIENT_METHOD_NAMES.terminal_create,
2442            Self::TerminalOutputRequest(_) => CLIENT_METHOD_NAMES.terminal_output,
2443            Self::ReleaseTerminalRequest(_) => CLIENT_METHOD_NAMES.terminal_release,
2444            Self::WaitForTerminalExitRequest(_) => CLIENT_METHOD_NAMES.terminal_wait_for_exit,
2445            Self::KillTerminalRequest(_) => CLIENT_METHOD_NAMES.terminal_kill,
2446            #[cfg(feature = "unstable_elicitation")]
2447            Self::CreateElicitationRequest(_) => CLIENT_METHOD_NAMES.elicitation_create,
2448            #[cfg(feature = "unstable_mcp_over_acp")]
2449            Self::ConnectMcpRequest(_) => CLIENT_METHOD_NAMES.mcp_connect,
2450            #[cfg(feature = "unstable_mcp_over_acp")]
2451            Self::MessageMcpRequest(_) => CLIENT_METHOD_NAMES.mcp_message,
2452            #[cfg(feature = "unstable_mcp_over_acp")]
2453            Self::DisconnectMcpRequest(_) => CLIENT_METHOD_NAMES.mcp_disconnect,
2454            Self::ExtMethodRequest(ext_request) => &ext_request.method,
2455        }
2456    }
2457}
2458
2459/// All possible responses that a client can send to an agent.
2460///
2461/// This enum is used internally for routing RPC responses. You typically won't need
2462/// to use this directly - the responses are handled automatically by the connection.
2463///
2464/// These are responses to the corresponding `AgentRequest` variants.
2465#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
2466#[serde(untagged)]
2467#[schemars(inline)]
2468#[non_exhaustive]
2469pub enum ClientResponse {
2470    /// Successful result returned for a `fs/write_text_file` request.
2471    WriteTextFileResponse(#[serde(default)] WriteTextFileResponse),
2472    /// Successful result returned for a `fs/read_text_file` request.
2473    ReadTextFileResponse(ReadTextFileResponse),
2474    /// Successful result returned for a `session/request_permission` request.
2475    RequestPermissionResponse(RequestPermissionResponse),
2476    /// Successful result returned for a `terminal/create` request.
2477    CreateTerminalResponse(CreateTerminalResponse),
2478    /// Successful result returned for a `terminal/output` request.
2479    TerminalOutputResponse(TerminalOutputResponse),
2480    /// Successful result returned for a `terminal/release` request.
2481    ReleaseTerminalResponse(#[serde(default)] ReleaseTerminalResponse),
2482    /// Successful result returned for a `terminal/wait_for_exit` request.
2483    WaitForTerminalExitResponse(WaitForTerminalExitResponse),
2484    /// Successful result returned for a `terminal/kill` request.
2485    KillTerminalResponse(#[serde(default)] KillTerminalResponse),
2486    /// Successful result returned for a `elicitation/create` request.
2487    #[cfg(feature = "unstable_elicitation")]
2488    CreateElicitationResponse(CreateElicitationResponse),
2489    /// Successful result returned for a `mcp/connect` request.
2490    #[cfg(feature = "unstable_mcp_over_acp")]
2491    ConnectMcpResponse(ConnectMcpResponse),
2492    /// Successful result returned for a `mcp/disconnect` request.
2493    #[cfg(feature = "unstable_mcp_over_acp")]
2494    DisconnectMcpResponse(#[serde(default)] DisconnectMcpResponse),
2495    /// Successful result returned by an MCP-over-ACP `mcp/message` request.
2496    #[cfg(feature = "unstable_mcp_over_acp")]
2497    MessageMcpResponse(MessageMcpResponse),
2498    /// Successful result returned by an extension method outside the core ACP method set.
2499    ExtMethodResponse(ExtResponse),
2500}
2501
2502/// All possible notifications that an agent can send to a client.
2503///
2504/// This enum is used internally for routing RPC notifications. You typically won't need
2505/// to use this directly.
2506///
2507/// Notifications do not expect a response.
2508#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
2509#[serde(untagged)]
2510#[expect(clippy::large_enum_variant)]
2511#[schemars(inline)]
2512#[non_exhaustive]
2513pub enum AgentNotification {
2514    /// Handles session update notifications from the agent.
2515    ///
2516    /// This is a notification endpoint (no response expected) that receives
2517    /// real-time updates about session progress, including message chunks,
2518    /// tool calls, and execution plans.
2519    ///
2520    /// Note: Clients SHOULD continue accepting tool call updates even after
2521    /// sending a `session/cancel` notification, as the agent may send final
2522    /// updates before responding with the cancelled stop reason.
2523    ///
2524    /// See protocol docs: [Agent Reports Output](https://agentclientprotocol.com/protocol/prompt-turn#3-agent-reports-output)
2525    SessionNotification(SessionNotification),
2526    /// **UNSTABLE**
2527    ///
2528    /// This capability is not part of the spec yet, and may be removed or changed at any point.
2529    ///
2530    /// Notification that a URL-based elicitation has completed.
2531    #[cfg(feature = "unstable_elicitation")]
2532    CompleteElicitationNotification(CompleteElicitationNotification),
2533    /// **UNSTABLE**
2534    ///
2535    /// This capability is not part of the spec yet, and may be removed or changed at any point.
2536    ///
2537    /// Receives an MCP-over-ACP notification.
2538    #[cfg(feature = "unstable_mcp_over_acp")]
2539    MessageMcpNotification(MessageMcpNotification),
2540    /// Handles extension notifications from the agent.
2541    ///
2542    /// Allows the Agent to send an arbitrary notification that is not part of the ACP spec.
2543    /// Extension notifications provide a way to send one-way messages for custom functionality
2544    /// while maintaining protocol compatibility.
2545    ///
2546    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
2547    ExtNotification(ExtNotification),
2548}
2549
2550impl AgentNotification {
2551    /// Returns the corresponding method name of the notification.
2552    #[must_use]
2553    pub fn method(&self) -> &str {
2554        match self {
2555            Self::SessionNotification(_) => CLIENT_METHOD_NAMES.session_update,
2556            #[cfg(feature = "unstable_elicitation")]
2557            Self::CompleteElicitationNotification(_) => CLIENT_METHOD_NAMES.elicitation_complete,
2558            #[cfg(feature = "unstable_mcp_over_acp")]
2559            Self::MessageMcpNotification(_) => CLIENT_METHOD_NAMES.mcp_message,
2560            Self::ExtNotification(ext_notification) => &ext_notification.method,
2561        }
2562    }
2563}
2564
2565#[cfg(test)]
2566mod tests {
2567    use super::*;
2568
2569    #[test]
2570    fn test_client_capabilities_default_on_malformed_values() {
2571        use serde_json::json;
2572
2573        let capabilities: ClientCapabilities = serde_json::from_value(json!({
2574            "fs": {
2575                "readTextFile": "yes",
2576                "writeTextFile": true
2577            },
2578            "terminal": {}
2579        }))
2580        .unwrap();
2581
2582        assert!(!capabilities.fs.read_text_file);
2583        assert!(capabilities.fs.write_text_file);
2584        assert!(!capabilities.terminal);
2585
2586        let capabilities: ClientCapabilities = serde_json::from_value(json!({
2587            "fs": false
2588        }))
2589        .unwrap();
2590        assert_eq!(capabilities.fs, FileSystemCapabilities::default());
2591
2592        #[cfg(feature = "unstable_auth_methods")]
2593        {
2594            let capabilities: ClientCapabilities = serde_json::from_value(json!({
2595                "auth": false
2596            }))
2597            .unwrap();
2598            assert_eq!(capabilities.auth, AuthCapabilities::default());
2599
2600            let capabilities: AuthCapabilities = serde_json::from_value(json!({
2601                "terminal": {}
2602            }))
2603            .unwrap();
2604            assert!(!capabilities.terminal);
2605        }
2606    }
2607
2608    #[test]
2609    fn test_serialization_behavior() {
2610        use serde_json::json;
2611
2612        assert_eq!(
2613            serde_json::from_value::<SessionInfoUpdate>(json!({})).unwrap(),
2614            SessionInfoUpdate {
2615                title: MaybeUndefined::Undefined,
2616                updated_at: MaybeUndefined::Undefined,
2617                meta: None
2618            }
2619        );
2620        assert_eq!(
2621            serde_json::from_value::<SessionInfoUpdate>(json!({"title": null, "updatedAt": null}))
2622                .unwrap(),
2623            SessionInfoUpdate {
2624                title: MaybeUndefined::Null,
2625                updated_at: MaybeUndefined::Null,
2626                meta: None
2627            }
2628        );
2629        assert_eq!(
2630            serde_json::from_value::<SessionInfoUpdate>(
2631                json!({"title": "title", "updatedAt": "timestamp"})
2632            )
2633            .unwrap(),
2634            SessionInfoUpdate {
2635                title: MaybeUndefined::Value("title".to_string()),
2636                updated_at: MaybeUndefined::Value("timestamp".to_string()),
2637                meta: None
2638            }
2639        );
2640
2641        assert_eq!(
2642            serde_json::to_value(SessionInfoUpdate::new()).unwrap(),
2643            json!({})
2644        );
2645        assert_eq!(
2646            serde_json::to_value(SessionInfoUpdate::new().title("title")).unwrap(),
2647            json!({"title": "title"})
2648        );
2649        assert_eq!(
2650            serde_json::to_value(SessionInfoUpdate::new().title(None)).unwrap(),
2651            json!({"title": null})
2652        );
2653        assert_eq!(
2654            serde_json::to_value(
2655                SessionInfoUpdate::new()
2656                    .title("title")
2657                    .title(MaybeUndefined::Undefined)
2658            )
2659            .unwrap(),
2660            json!({})
2661        );
2662    }
2663
2664    #[test]
2665    fn test_content_chunk_message_id_serialization() {
2666        use serde_json::json;
2667
2668        assert_eq!(
2669            serde_json::to_value(SessionUpdate::AgentMessageChunk(ContentChunk::new(
2670                ContentBlock::Text(crate::v1::TextContent::new("Hello"))
2671            )))
2672            .unwrap(),
2673            json!({
2674                "sessionUpdate": "agent_message_chunk",
2675                "content": {
2676                    "type": "text",
2677                    "text": "Hello"
2678                }
2679            })
2680        );
2681
2682        assert_eq!(
2683            serde_json::to_value(SessionUpdate::AgentMessageChunk(
2684                ContentChunk::new(ContentBlock::Text(crate::v1::TextContent::new("Hello")))
2685                    .message_id("msg_agent_c42b9")
2686            ))
2687            .unwrap(),
2688            json!({
2689                "sessionUpdate": "agent_message_chunk",
2690                "messageId": "msg_agent_c42b9",
2691                "content": {
2692                    "type": "text",
2693                    "text": "Hello"
2694                }
2695            })
2696        );
2697
2698        let SessionUpdate::AgentMessageChunk(chunk) = serde_json::from_value(json!({
2699            "sessionUpdate": "agent_message_chunk",
2700            "messageId": null,
2701            "content": {
2702                "type": "text",
2703                "text": "Hello"
2704            }
2705        }))
2706        .unwrap() else {
2707            panic!("expected agent message chunk");
2708        };
2709
2710        assert_eq!(chunk.message_id, None);
2711    }
2712
2713    #[test]
2714    fn test_usage_update_serialization() {
2715        use serde_json::json;
2716
2717        assert_eq!(
2718            serde_json::to_value(SessionUpdate::UsageUpdate(UsageUpdate::new(
2719                53_000, 200_000
2720            )))
2721            .unwrap(),
2722            json!({
2723                "sessionUpdate": "usage_update",
2724                "used": 53000,
2725                "size": 200_000
2726            })
2727        );
2728
2729        assert_eq!(
2730            serde_json::to_value(SessionUpdate::UsageUpdate(
2731                UsageUpdate::new(53_000, 200_000).cost(Cost::new(0.045, "USD"))
2732            ))
2733            .unwrap(),
2734            json!({
2735                "sessionUpdate": "usage_update",
2736                "used": 53000,
2737                "size": 200_000,
2738                "cost": {
2739                    "amount": 0.045,
2740                    "currency": "USD"
2741                }
2742            })
2743        );
2744
2745        let SessionUpdate::UsageUpdate(update) = serde_json::from_value(json!({
2746            "sessionUpdate": "usage_update",
2747            "used": 53000,
2748            "size": 200_000,
2749            "cost": null
2750        }))
2751        .unwrap() else {
2752            panic!("expected usage update");
2753        };
2754
2755        assert_eq!(update.cost, None);
2756    }
2757
2758    #[cfg(feature = "unstable_nes")]
2759    #[test]
2760    fn test_client_capabilities_position_encodings_serialization() {
2761        use serde_json::json;
2762
2763        let capabilities = ClientCapabilities::new().position_encodings(vec![
2764            PositionEncodingKind::Utf32,
2765            PositionEncodingKind::Utf16,
2766        ]);
2767        let json = serde_json::to_value(&capabilities).unwrap();
2768
2769        assert_eq!(json["positionEncodings"], json!(["utf-32", "utf-16"]));
2770    }
2771
2772    #[test]
2773    fn test_client_capabilities_boolean_config_options_serialization() {
2774        use serde_json::json;
2775
2776        let capabilities = ClientCapabilities::new().session(
2777            ClientSessionCapabilities::new().config_options(
2778                SessionConfigOptionsCapabilities::new()
2779                    .boolean(BooleanConfigOptionCapabilities::new()),
2780            ),
2781        );
2782        let json = serde_json::to_value(&capabilities).unwrap();
2783
2784        assert_eq!(json["session"]["configOptions"]["boolean"], json!({}));
2785
2786        let omitted: ClientCapabilities = serde_json::from_value(json!({})).unwrap();
2787        assert!(omitted.session.is_none());
2788
2789        let null_session: ClientCapabilities = serde_json::from_value(json!({
2790            "session": null
2791        }))
2792        .unwrap();
2793        assert!(null_session.session.is_none());
2794
2795        let null_config_options: ClientCapabilities = serde_json::from_value(json!({
2796            "session": {
2797                "configOptions": null
2798            }
2799        }))
2800        .unwrap();
2801        assert!(
2802            null_config_options
2803                .session
2804                .and_then(|session| session.config_options)
2805                .is_none()
2806        );
2807
2808        let null_boolean: ClientCapabilities = serde_json::from_value(json!({
2809            "session": {
2810                "configOptions": {
2811                    "boolean": null
2812                }
2813            }
2814        }))
2815        .unwrap();
2816        assert!(
2817            null_boolean
2818                .session
2819                .and_then(|session| session.config_options)
2820                .and_then(|config_options| config_options.boolean)
2821                .is_none()
2822        );
2823    }
2824
2825    #[cfg(feature = "unstable_plan_operations")]
2826    #[test]
2827    fn test_plan_operations_serialization() {
2828        use serde_json::json;
2829
2830        use crate::v1::{PlanEntry, PlanEntryPriority, PlanEntryStatus, PlanUpdateContent};
2831
2832        let plan_update = SessionUpdate::PlanUpdate(PlanUpdate::new(PlanUpdateContent::items(
2833            "plan-1",
2834            vec![PlanEntry::new(
2835                "Step 1",
2836                PlanEntryPriority::High,
2837                PlanEntryStatus::Pending,
2838            )],
2839        )));
2840
2841        assert_eq!(
2842            serde_json::to_value(plan_update).unwrap(),
2843            json!({
2844                "sessionUpdate": "plan_update",
2845                "plan": {
2846                    "type": "items",
2847                    "planId": "plan-1",
2848                    "entries": [
2849                        {
2850                            "content": "Step 1",
2851                            "priority": "high",
2852                            "status": "pending"
2853                        }
2854                    ]
2855                }
2856            })
2857        );
2858
2859        assert_eq!(
2860            serde_json::to_value(SessionUpdate::PlanRemoved(PlanRemoved::new("plan-1"))).unwrap(),
2861            json!({
2862                "sessionUpdate": "plan_removed",
2863                "planId": "plan-1"
2864            })
2865        );
2866
2867        let capabilities = ClientCapabilities::new().plan(PlanCapabilities::new());
2868        let json = serde_json::to_value(&capabilities).unwrap();
2869        assert_eq!(json["plan"], json!({}));
2870
2871        assert_eq!(
2872            serde_json::from_value::<ClientCapabilities>(json!({ "plan": null }))
2873                .unwrap()
2874                .plan,
2875            None
2876        );
2877    }
2878
2879    #[cfg(feature = "unstable_mcp_over_acp")]
2880    #[test]
2881    fn test_agent_mcp_request_method_names() {
2882        use serde_json::json;
2883
2884        let params: serde_json::Map<String, serde_json::Value> =
2885            [("cursor".to_string(), json!("abc"))].into_iter().collect();
2886
2887        assert_eq!(CLIENT_METHOD_NAMES.mcp_connect, "mcp/connect");
2888        assert_eq!(CLIENT_METHOD_NAMES.mcp_message, "mcp/message");
2889        assert_eq!(CLIENT_METHOD_NAMES.mcp_disconnect, "mcp/disconnect");
2890
2891        assert_eq!(
2892            AgentRequest::ConnectMcpRequest(ConnectMcpRequest::new("server-1")).method(),
2893            "mcp/connect"
2894        );
2895        assert_eq!(
2896            AgentRequest::MessageMcpRequest(MessageMcpRequest::new("conn-1", "tools/list"))
2897                .method(),
2898            "mcp/message"
2899        );
2900        assert_eq!(
2901            AgentRequest::DisconnectMcpRequest(DisconnectMcpRequest::new("conn-1")).method(),
2902            "mcp/disconnect"
2903        );
2904        assert_eq!(
2905            AgentNotification::MessageMcpNotification(MessageMcpNotification::new(
2906                "conn-1",
2907                "notifications/progress"
2908            ))
2909            .method(),
2910            "mcp/message"
2911        );
2912
2913        assert_eq!(
2914            serde_json::to_value(ConnectMcpRequest::new("server-1")).unwrap(),
2915            json!({ "serverId": "server-1" })
2916        );
2917        assert_eq!(
2918            serde_json::to_value(ConnectMcpResponse::new("conn-1")).unwrap(),
2919            json!({ "connectionId": "conn-1" })
2920        );
2921        assert_eq!(
2922            serde_json::to_value(MessageMcpRequest::new("conn-1", "tools/list").params(params))
2923                .unwrap(),
2924            json!({
2925                "connectionId": "conn-1",
2926                "method": "tools/list",
2927                "params": { "cursor": "abc" }
2928            })
2929        );
2930        assert_eq!(
2931            serde_json::to_value(DisconnectMcpRequest::new("conn-1")).unwrap(),
2932            json!({ "connectionId": "conn-1" })
2933        );
2934        assert_eq!(
2935            serde_json::to_value(MessageMcpNotification::new(
2936                "conn-1",
2937                "notifications/progress"
2938            ))
2939            .unwrap(),
2940            json!({
2941                "connectionId": "conn-1",
2942                "method": "notifications/progress"
2943            })
2944        );
2945
2946        let request_with_null_params: MessageMcpRequest = serde_json::from_value(json!({
2947            "connectionId": "conn-1",
2948            "method": "tools/list",
2949            "params": null
2950        }))
2951        .unwrap();
2952        assert_eq!(request_with_null_params.params, None);
2953    }
2954
2955    #[test]
2956    fn request_permission_request_rejects_malformed_options() {
2957        use serde_json::json;
2958
2959        assert!(
2960            serde_json::from_value::<RequestPermissionRequest>(json!({
2961                "sessionId": "sess-1",
2962                "toolCall": {"toolCallId": "tc-1"},
2963                "options": "not-an-array"
2964            }))
2965            .is_err()
2966        );
2967        assert!(
2968            serde_json::from_value::<RequestPermissionRequest>(json!({
2969                "sessionId": "sess-1",
2970                "toolCall": {"toolCallId": "tc-1"},
2971                "options": [{"optionId": "allow"}]
2972            }))
2973            .is_err()
2974        );
2975    }
2976}