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    #[serde_as(deserialize_as = "DefaultOnError<VecSkipError<_, SkipListener>>")]
660    #[schemars(extend("x-deserialize-default-on-error" = true, "x-deserialize-skip-invalid-items" = true))]
661    pub options: Vec<PermissionOption>,
662    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
663    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
664    /// these keys.
665    ///
666    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
667    #[serde_as(deserialize_as = "DefaultOnError")]
668    #[schemars(extend("x-deserialize-default-on-error" = true))]
669    #[serde(default)]
670    #[serde(rename = "_meta")]
671    pub meta: Option<Meta>,
672}
673
674impl RequestPermissionRequest {
675    /// Builds [`RequestPermissionRequest`] with the required request fields set; optional fields start unset or empty.
676    #[must_use]
677    pub fn new(
678        session_id: impl Into<SessionId>,
679        tool_call: ToolCallUpdate,
680        options: Vec<PermissionOption>,
681    ) -> Self {
682        Self {
683            session_id: session_id.into(),
684            tool_call,
685            options,
686            meta: None,
687        }
688    }
689
690    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
691    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
692    /// these keys.
693    ///
694    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
695    #[must_use]
696    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
697        self.meta = meta.into_option();
698        self
699    }
700}
701
702/// An option presented to the user when requesting permission.
703#[serde_as]
704#[skip_serializing_none]
705#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
706#[serde(rename_all = "camelCase")]
707#[non_exhaustive]
708pub struct PermissionOption {
709    /// Unique identifier for this permission option.
710    pub option_id: PermissionOptionId,
711    /// Human-readable label to display to the user.
712    pub name: String,
713    /// Hint about the nature of this permission option.
714    pub kind: PermissionOptionKind,
715    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
716    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
717    /// these keys.
718    ///
719    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
720    #[serde_as(deserialize_as = "DefaultOnError")]
721    #[schemars(extend("x-deserialize-default-on-error" = true))]
722    #[serde(default)]
723    #[serde(rename = "_meta")]
724    pub meta: Option<Meta>,
725}
726
727impl PermissionOption {
728    /// Builds [`PermissionOption`] with the required fields set; optional fields start unset or empty.
729    #[must_use]
730    pub fn new(
731        option_id: impl Into<PermissionOptionId>,
732        name: impl Into<String>,
733        kind: PermissionOptionKind,
734    ) -> Self {
735        Self {
736            option_id: option_id.into(),
737            name: name.into(),
738            kind,
739            meta: None,
740        }
741    }
742
743    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
744    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
745    /// these keys.
746    ///
747    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
748    #[must_use]
749    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
750        self.meta = meta.into_option();
751        self
752    }
753}
754
755/// Unique identifier for a permission option.
756#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq, Hash, Display, From)]
757#[serde(transparent)]
758#[from(Arc<str>, String, &'static str)]
759#[non_exhaustive]
760pub struct PermissionOptionId(pub Arc<str>);
761
762impl PermissionOptionId {
763    /// Wraps a protocol string as a typed [`PermissionOptionId`].
764    #[must_use]
765    pub fn new(id: impl Into<Arc<str>>) -> Self {
766        Self(id.into())
767    }
768}
769
770/// The type of permission option being presented to the user.
771///
772/// Helps clients choose appropriate icons and UI treatment.
773#[derive(Debug, Clone, Copy, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
774#[serde(rename_all = "snake_case")]
775#[non_exhaustive]
776pub enum PermissionOptionKind {
777    /// Allow this operation only this time.
778    AllowOnce,
779    /// Allow this operation and remember the choice.
780    AllowAlways,
781    /// Reject this operation only this time.
782    RejectOnce,
783    /// Reject this operation and remember the choice.
784    RejectAlways,
785}
786
787/// Response to a permission request.
788#[serde_as]
789#[skip_serializing_none]
790#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
791#[schemars(extend("x-side" = "client", "x-method" = SESSION_REQUEST_PERMISSION_METHOD_NAME))]
792#[serde(rename_all = "camelCase")]
793#[non_exhaustive]
794pub struct RequestPermissionResponse {
795    /// The user's decision on the permission request.
796    // This extra-level is unfortunately needed because the output must be an object
797    pub outcome: RequestPermissionOutcome,
798    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
799    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
800    /// these keys.
801    ///
802    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
803    #[serde_as(deserialize_as = "DefaultOnError")]
804    #[schemars(extend("x-deserialize-default-on-error" = true))]
805    #[serde(default)]
806    #[serde(rename = "_meta")]
807    pub meta: Option<Meta>,
808}
809
810impl RequestPermissionResponse {
811    /// Builds [`RequestPermissionResponse`] with the required response fields set; optional fields start unset or empty.
812    #[must_use]
813    pub fn new(outcome: RequestPermissionOutcome) -> Self {
814        Self {
815            outcome,
816            meta: None,
817        }
818    }
819
820    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
821    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
822    /// these keys.
823    ///
824    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
825    #[must_use]
826    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
827        self.meta = meta.into_option();
828        self
829    }
830}
831
832/// The outcome of a permission request.
833#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
834#[serde(tag = "outcome", rename_all = "snake_case")]
835#[schemars(extend("discriminator" = {"propertyName": "outcome"}))]
836#[non_exhaustive]
837pub enum RequestPermissionOutcome {
838    /// The prompt turn was cancelled before the user responded.
839    ///
840    /// When a client sends a `session/cancel` notification to cancel an ongoing
841    /// prompt turn, it MUST respond to all pending `session/request_permission`
842    /// requests with this `Cancelled` outcome.
843    ///
844    /// See protocol docs: [Cancellation](https://agentclientprotocol.com/protocol/prompt-turn#cancellation)
845    Cancelled,
846    /// The user selected one of the provided options.
847    #[serde(rename_all = "camelCase")]
848    Selected(SelectedPermissionOutcome),
849}
850
851/// The user selected one of the provided options.
852#[serde_as]
853#[skip_serializing_none]
854#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
855#[serde(rename_all = "camelCase")]
856#[non_exhaustive]
857pub struct SelectedPermissionOutcome {
858    /// The ID of the option the user selected.
859    pub option_id: PermissionOptionId,
860    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
861    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
862    /// these keys.
863    ///
864    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
865    #[serde_as(deserialize_as = "DefaultOnError")]
866    #[schemars(extend("x-deserialize-default-on-error" = true))]
867    #[serde(default)]
868    #[serde(rename = "_meta")]
869    pub meta: Option<Meta>,
870}
871
872impl SelectedPermissionOutcome {
873    /// Builds [`SelectedPermissionOutcome`] with the required fields set; optional fields start unset or empty.
874    #[must_use]
875    pub fn new(option_id: impl Into<PermissionOptionId>) -> Self {
876        Self {
877            option_id: option_id.into(),
878            meta: None,
879        }
880    }
881
882    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
883    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
884    /// these keys.
885    ///
886    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
887    #[must_use]
888    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
889        self.meta = meta.into_option();
890        self
891    }
892}
893
894// Write text file
895
896/// Request to write content to a text file.
897///
898/// Only available if the client supports the `fs.writeTextFile` capability.
899#[serde_as]
900#[skip_serializing_none]
901#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
902#[schemars(extend("x-side" = "client", "x-method" = FS_WRITE_TEXT_FILE_METHOD_NAME))]
903#[serde(rename_all = "camelCase")]
904#[non_exhaustive]
905pub struct WriteTextFileRequest {
906    /// The session ID for this request.
907    pub session_id: SessionId,
908    /// Absolute path to the file to write.
909    pub path: PathBuf,
910    /// The text content to write to the file.
911    pub content: String,
912    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
913    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
914    /// these keys.
915    ///
916    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
917    #[serde_as(deserialize_as = "DefaultOnError")]
918    #[schemars(extend("x-deserialize-default-on-error" = true))]
919    #[serde(default)]
920    #[serde(rename = "_meta")]
921    pub meta: Option<Meta>,
922}
923
924impl WriteTextFileRequest {
925    /// Builds [`WriteTextFileRequest`] with the required request fields set; optional fields start unset or empty.
926    #[must_use]
927    pub fn new(
928        session_id: impl Into<SessionId>,
929        path: impl Into<PathBuf>,
930        content: impl Into<String>,
931    ) -> Self {
932        Self {
933            session_id: session_id.into(),
934            path: path.into(),
935            content: content.into(),
936            meta: None,
937        }
938    }
939
940    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
941    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
942    /// these keys.
943    ///
944    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
945    #[must_use]
946    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
947        self.meta = meta.into_option();
948        self
949    }
950}
951
952/// Response to `fs/write_text_file`
953#[serde_as]
954#[skip_serializing_none]
955#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
956#[serde(rename_all = "camelCase")]
957#[schemars(extend("x-side" = "client", "x-method" = FS_WRITE_TEXT_FILE_METHOD_NAME))]
958#[non_exhaustive]
959pub struct WriteTextFileResponse {
960    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
961    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
962    /// these keys.
963    ///
964    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
965    #[serde_as(deserialize_as = "DefaultOnError")]
966    #[schemars(extend("x-deserialize-default-on-error" = true))]
967    #[serde(default)]
968    #[serde(rename = "_meta")]
969    pub meta: Option<Meta>,
970}
971
972impl WriteTextFileResponse {
973    /// Builds [`WriteTextFileResponse`] with the required response fields set; optional fields start unset or empty.
974    #[must_use]
975    pub fn new() -> Self {
976        Self::default()
977    }
978
979    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
980    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
981    /// these keys.
982    ///
983    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
984    #[must_use]
985    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
986        self.meta = meta.into_option();
987        self
988    }
989}
990
991// Read text file
992
993/// Request to read content from a text file.
994///
995/// Only available if the client supports the `fs.readTextFile` capability.
996#[serde_as]
997#[skip_serializing_none]
998#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
999#[schemars(extend("x-side" = "client", "x-method" = FS_READ_TEXT_FILE_METHOD_NAME))]
1000#[serde(rename_all = "camelCase")]
1001#[non_exhaustive]
1002pub struct ReadTextFileRequest {
1003    /// The session ID for this request.
1004    pub session_id: SessionId,
1005    /// Absolute path to the file to read.
1006    pub path: PathBuf,
1007    /// Line number to start reading from (1-based).
1008    #[serde_as(deserialize_as = "DefaultOnError")]
1009    #[schemars(extend("x-deserialize-default-on-error" = true))]
1010    #[serde(default)]
1011    pub line: Option<u32>,
1012    /// Maximum number of lines to read.
1013    #[serde_as(deserialize_as = "DefaultOnError")]
1014    #[schemars(extend("x-deserialize-default-on-error" = true))]
1015    #[serde(default)]
1016    pub limit: Option<u32>,
1017    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1018    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1019    /// these keys.
1020    ///
1021    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1022    #[serde_as(deserialize_as = "DefaultOnError")]
1023    #[schemars(extend("x-deserialize-default-on-error" = true))]
1024    #[serde(default)]
1025    #[serde(rename = "_meta")]
1026    pub meta: Option<Meta>,
1027}
1028
1029impl ReadTextFileRequest {
1030    /// Builds [`ReadTextFileRequest`] with the required request fields set; optional fields start unset or empty.
1031    #[must_use]
1032    pub fn new(session_id: impl Into<SessionId>, path: impl Into<PathBuf>) -> Self {
1033        Self {
1034            session_id: session_id.into(),
1035            path: path.into(),
1036            line: None,
1037            limit: None,
1038            meta: None,
1039        }
1040    }
1041
1042    /// Line number to start reading from (1-based).
1043    #[must_use]
1044    pub fn line(mut self, line: impl IntoOption<u32>) -> Self {
1045        self.line = line.into_option();
1046        self
1047    }
1048
1049    /// Maximum number of lines to read.
1050    #[must_use]
1051    pub fn limit(mut self, limit: impl IntoOption<u32>) -> Self {
1052        self.limit = limit.into_option();
1053        self
1054    }
1055
1056    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1057    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1058    /// these keys.
1059    ///
1060    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1061    #[must_use]
1062    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1063        self.meta = meta.into_option();
1064        self
1065    }
1066}
1067
1068/// Response containing the contents of a text file.
1069#[serde_as]
1070#[skip_serializing_none]
1071#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1072#[schemars(extend("x-side" = "client", "x-method" = FS_READ_TEXT_FILE_METHOD_NAME))]
1073#[serde(rename_all = "camelCase")]
1074#[non_exhaustive]
1075pub struct ReadTextFileResponse {
1076    /// Content payload returned by this response.
1077    pub content: String,
1078    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1079    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1080    /// these keys.
1081    ///
1082    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1083    #[serde_as(deserialize_as = "DefaultOnError")]
1084    #[schemars(extend("x-deserialize-default-on-error" = true))]
1085    #[serde(default)]
1086    #[serde(rename = "_meta")]
1087    pub meta: Option<Meta>,
1088}
1089
1090impl ReadTextFileResponse {
1091    /// Builds [`ReadTextFileResponse`] with the required response fields set; optional fields start unset or empty.
1092    #[must_use]
1093    pub fn new(content: impl Into<String>) -> Self {
1094        Self {
1095            content: content.into(),
1096            meta: None,
1097        }
1098    }
1099
1100    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1101    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1102    /// these keys.
1103    ///
1104    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1105    #[must_use]
1106    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1107        self.meta = meta.into_option();
1108        self
1109    }
1110}
1111
1112// Terminals
1113
1114/// Typed identifier used for terminal values on the wire.
1115#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq, Hash, Display, From)]
1116#[serde(transparent)]
1117#[from(Arc<str>, String, &'static str)]
1118#[non_exhaustive]
1119pub struct TerminalId(pub Arc<str>);
1120
1121impl TerminalId {
1122    /// Wraps a protocol string as a typed [`TerminalId`].
1123    #[must_use]
1124    pub fn new(id: impl Into<Arc<str>>) -> Self {
1125        Self(id.into())
1126    }
1127}
1128
1129/// Request to create a new terminal and execute a command.
1130#[serde_as]
1131#[skip_serializing_none]
1132#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1133#[serde(rename_all = "camelCase")]
1134#[schemars(extend("x-side" = "client", "x-method" = TERMINAL_CREATE_METHOD_NAME))]
1135#[non_exhaustive]
1136pub struct CreateTerminalRequest {
1137    /// The session ID for this request.
1138    pub session_id: SessionId,
1139    /// The command to execute.
1140    pub command: String,
1141    /// Array of command arguments.
1142    #[serde_as(deserialize_as = "DefaultOnError<VecSkipError<_, SkipListener>>")]
1143    #[schemars(extend("x-deserialize-default-on-error" = true, "x-deserialize-skip-invalid-items" = true))]
1144    #[serde(default, skip_serializing_if = "Vec::is_empty")]
1145    pub args: Vec<String>,
1146    /// Environment variables for the command.
1147    #[serde_as(deserialize_as = "DefaultOnError<VecSkipError<_, SkipListener>>")]
1148    #[schemars(extend("x-deserialize-default-on-error" = true, "x-deserialize-skip-invalid-items" = true))]
1149    #[serde(default, skip_serializing_if = "Vec::is_empty")]
1150    pub env: Vec<EnvVariable>,
1151    /// Working directory for the command (absolute path).
1152    #[serde_as(deserialize_as = "DefaultOnError")]
1153    #[schemars(extend("x-deserialize-default-on-error" = true))]
1154    #[serde(default)]
1155    pub cwd: Option<PathBuf>,
1156    /// Maximum number of output bytes to retain.
1157    ///
1158    /// When the limit is exceeded, the Client truncates from the beginning of the output
1159    /// to stay within the limit.
1160    ///
1161    /// The Client MUST ensure truncation happens at a character boundary to maintain valid
1162    /// string output, even if this means the retained output is slightly less than the
1163    /// specified limit.
1164    #[serde_as(deserialize_as = "DefaultOnError")]
1165    #[schemars(extend("x-deserialize-default-on-error" = true))]
1166    #[serde(default)]
1167    pub output_byte_limit: Option<u64>,
1168    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1169    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1170    /// these keys.
1171    ///
1172    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1173    #[serde_as(deserialize_as = "DefaultOnError")]
1174    #[schemars(extend("x-deserialize-default-on-error" = true))]
1175    #[serde(default)]
1176    #[serde(rename = "_meta")]
1177    pub meta: Option<Meta>,
1178}
1179
1180impl CreateTerminalRequest {
1181    /// Builds [`CreateTerminalRequest`] with the required request fields set; optional fields start unset or empty.
1182    #[must_use]
1183    pub fn new(session_id: impl Into<SessionId>, command: impl Into<String>) -> Self {
1184        Self {
1185            session_id: session_id.into(),
1186            command: command.into(),
1187            args: Vec::new(),
1188            env: Vec::new(),
1189            cwd: None,
1190            output_byte_limit: None,
1191            meta: None,
1192        }
1193    }
1194
1195    /// Array of command arguments.
1196    #[must_use]
1197    pub fn args(mut self, args: Vec<String>) -> Self {
1198        self.args = args;
1199        self
1200    }
1201
1202    /// Environment variables for the command.
1203    #[must_use]
1204    pub fn env(mut self, env: Vec<EnvVariable>) -> Self {
1205        self.env = env;
1206        self
1207    }
1208
1209    /// Working directory for the command (absolute path).
1210    #[must_use]
1211    pub fn cwd(mut self, cwd: impl IntoOption<PathBuf>) -> Self {
1212        self.cwd = cwd.into_option();
1213        self
1214    }
1215
1216    /// Maximum number of output bytes to retain.
1217    ///
1218    /// When the limit is exceeded, the Client truncates from the beginning of the output
1219    /// to stay within the limit.
1220    ///
1221    /// The Client MUST ensure truncation happens at a character boundary to maintain valid
1222    /// string output, even if this means the retained output is slightly less than the
1223    /// specified limit.
1224    #[must_use]
1225    pub fn output_byte_limit(mut self, output_byte_limit: impl IntoOption<u64>) -> Self {
1226        self.output_byte_limit = output_byte_limit.into_option();
1227        self
1228    }
1229
1230    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1231    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1232    /// these keys.
1233    ///
1234    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1235    #[must_use]
1236    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1237        self.meta = meta.into_option();
1238        self
1239    }
1240}
1241
1242/// Response containing the ID of the created terminal.
1243#[serde_as]
1244#[skip_serializing_none]
1245#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1246#[serde(rename_all = "camelCase")]
1247#[schemars(extend("x-side" = "client", "x-method" = TERMINAL_CREATE_METHOD_NAME))]
1248#[non_exhaustive]
1249pub struct CreateTerminalResponse {
1250    /// The unique identifier for the created terminal.
1251    pub terminal_id: TerminalId,
1252    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1253    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1254    /// these keys.
1255    ///
1256    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1257    #[serde_as(deserialize_as = "DefaultOnError")]
1258    #[schemars(extend("x-deserialize-default-on-error" = true))]
1259    #[serde(default)]
1260    #[serde(rename = "_meta")]
1261    pub meta: Option<Meta>,
1262}
1263
1264impl CreateTerminalResponse {
1265    /// Builds [`CreateTerminalResponse`] with the required response fields set; optional fields start unset or empty.
1266    #[must_use]
1267    pub fn new(terminal_id: impl Into<TerminalId>) -> Self {
1268        Self {
1269            terminal_id: terminal_id.into(),
1270            meta: None,
1271        }
1272    }
1273
1274    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1275    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1276    /// these keys.
1277    ///
1278    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1279    #[must_use]
1280    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1281        self.meta = meta.into_option();
1282        self
1283    }
1284}
1285
1286/// Request to get the current output and status of a terminal.
1287#[serde_as]
1288#[skip_serializing_none]
1289#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1290#[serde(rename_all = "camelCase")]
1291#[schemars(extend("x-side" = "client", "x-method" = TERMINAL_OUTPUT_METHOD_NAME))]
1292#[non_exhaustive]
1293pub struct TerminalOutputRequest {
1294    /// The session ID for this request.
1295    pub session_id: SessionId,
1296    /// The ID of the terminal to get output from.
1297    pub terminal_id: TerminalId,
1298    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1299    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1300    /// these keys.
1301    ///
1302    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1303    #[serde_as(deserialize_as = "DefaultOnError")]
1304    #[schemars(extend("x-deserialize-default-on-error" = true))]
1305    #[serde(default)]
1306    #[serde(rename = "_meta")]
1307    pub meta: Option<Meta>,
1308}
1309
1310impl TerminalOutputRequest {
1311    /// Builds [`TerminalOutputRequest`] with the required request fields set; optional fields start unset or empty.
1312    #[must_use]
1313    pub fn new(session_id: impl Into<SessionId>, terminal_id: impl Into<TerminalId>) -> Self {
1314        Self {
1315            session_id: session_id.into(),
1316            terminal_id: terminal_id.into(),
1317            meta: None,
1318        }
1319    }
1320
1321    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1322    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1323    /// these keys.
1324    ///
1325    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1326    #[must_use]
1327    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1328        self.meta = meta.into_option();
1329        self
1330    }
1331}
1332
1333/// Response containing the terminal output and exit status.
1334#[serde_as]
1335#[skip_serializing_none]
1336#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1337#[serde(rename_all = "camelCase")]
1338#[schemars(extend("x-side" = "client", "x-method" = TERMINAL_OUTPUT_METHOD_NAME))]
1339#[non_exhaustive]
1340pub struct TerminalOutputResponse {
1341    /// The terminal output captured so far.
1342    pub output: String,
1343    /// Whether the output was truncated due to byte limits.
1344    pub truncated: bool,
1345    /// Exit status if the command has completed.
1346    #[serde_as(deserialize_as = "DefaultOnError")]
1347    #[schemars(extend("x-deserialize-default-on-error" = true))]
1348    #[serde(default)]
1349    pub exit_status: Option<TerminalExitStatus>,
1350    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1351    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1352    /// these keys.
1353    ///
1354    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1355    #[serde_as(deserialize_as = "DefaultOnError")]
1356    #[schemars(extend("x-deserialize-default-on-error" = true))]
1357    #[serde(default)]
1358    #[serde(rename = "_meta")]
1359    pub meta: Option<Meta>,
1360}
1361
1362impl TerminalOutputResponse {
1363    /// Builds [`TerminalOutputResponse`] with the required response fields set; optional fields start unset or empty.
1364    #[must_use]
1365    pub fn new(output: impl Into<String>, truncated: bool) -> Self {
1366        Self {
1367            output: output.into(),
1368            truncated,
1369            exit_status: None,
1370            meta: None,
1371        }
1372    }
1373
1374    /// Exit status if the command has completed.
1375    #[must_use]
1376    pub fn exit_status(mut self, exit_status: impl IntoOption<TerminalExitStatus>) -> Self {
1377        self.exit_status = exit_status.into_option();
1378        self
1379    }
1380
1381    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1382    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1383    /// these keys.
1384    ///
1385    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1386    #[must_use]
1387    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1388        self.meta = meta.into_option();
1389        self
1390    }
1391}
1392
1393/// Request to release a terminal and free its resources.
1394#[serde_as]
1395#[skip_serializing_none]
1396#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1397#[serde(rename_all = "camelCase")]
1398#[schemars(extend("x-side" = "client", "x-method" = TERMINAL_RELEASE_METHOD_NAME))]
1399#[non_exhaustive]
1400pub struct ReleaseTerminalRequest {
1401    /// The session ID for this request.
1402    pub session_id: SessionId,
1403    /// The ID of the terminal to release.
1404    pub terminal_id: TerminalId,
1405    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1406    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1407    /// these keys.
1408    ///
1409    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1410    #[serde_as(deserialize_as = "DefaultOnError")]
1411    #[schemars(extend("x-deserialize-default-on-error" = true))]
1412    #[serde(default)]
1413    #[serde(rename = "_meta")]
1414    pub meta: Option<Meta>,
1415}
1416
1417impl ReleaseTerminalRequest {
1418    /// Builds [`ReleaseTerminalRequest`] with the required request fields set; optional fields start unset or empty.
1419    #[must_use]
1420    pub fn new(session_id: impl Into<SessionId>, terminal_id: impl Into<TerminalId>) -> Self {
1421        Self {
1422            session_id: session_id.into(),
1423            terminal_id: terminal_id.into(),
1424            meta: None,
1425        }
1426    }
1427
1428    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1429    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1430    /// these keys.
1431    ///
1432    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1433    #[must_use]
1434    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1435        self.meta = meta.into_option();
1436        self
1437    }
1438}
1439
1440/// Response to terminal/release method
1441#[serde_as]
1442#[skip_serializing_none]
1443#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1444#[serde(rename_all = "camelCase")]
1445#[schemars(extend("x-side" = "client", "x-method" = TERMINAL_RELEASE_METHOD_NAME))]
1446#[non_exhaustive]
1447pub struct ReleaseTerminalResponse {
1448    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1449    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1450    /// these keys.
1451    ///
1452    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1453    #[serde_as(deserialize_as = "DefaultOnError")]
1454    #[schemars(extend("x-deserialize-default-on-error" = true))]
1455    #[serde(default)]
1456    #[serde(rename = "_meta")]
1457    pub meta: Option<Meta>,
1458}
1459
1460impl ReleaseTerminalResponse {
1461    /// Builds [`ReleaseTerminalResponse`] with the required response fields set; optional fields start unset or empty.
1462    #[must_use]
1463    pub fn new() -> Self {
1464        Self::default()
1465    }
1466
1467    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1468    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1469    /// these keys.
1470    ///
1471    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1472    #[must_use]
1473    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1474        self.meta = meta.into_option();
1475        self
1476    }
1477}
1478
1479/// Request to kill a terminal without releasing it.
1480#[serde_as]
1481#[skip_serializing_none]
1482#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1483#[serde(rename_all = "camelCase")]
1484#[schemars(extend("x-side" = "client", "x-method" = TERMINAL_KILL_METHOD_NAME))]
1485#[non_exhaustive]
1486pub struct KillTerminalRequest {
1487    /// The session ID for this request.
1488    pub session_id: SessionId,
1489    /// The ID of the terminal to kill.
1490    pub terminal_id: TerminalId,
1491    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1492    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1493    /// these keys.
1494    ///
1495    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1496    #[serde_as(deserialize_as = "DefaultOnError")]
1497    #[schemars(extend("x-deserialize-default-on-error" = true))]
1498    #[serde(default)]
1499    #[serde(rename = "_meta")]
1500    pub meta: Option<Meta>,
1501}
1502
1503impl KillTerminalRequest {
1504    /// Builds [`KillTerminalRequest`] with the required request fields set; optional fields start unset or empty.
1505    #[must_use]
1506    pub fn new(session_id: impl Into<SessionId>, terminal_id: impl Into<TerminalId>) -> Self {
1507        Self {
1508            session_id: session_id.into(),
1509            terminal_id: terminal_id.into(),
1510            meta: None,
1511        }
1512    }
1513
1514    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1515    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1516    /// these keys.
1517    ///
1518    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1519    #[must_use]
1520    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1521        self.meta = meta.into_option();
1522        self
1523    }
1524}
1525
1526/// Response to `terminal/kill` method
1527#[serde_as]
1528#[skip_serializing_none]
1529#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1530#[serde(rename_all = "camelCase")]
1531#[schemars(extend("x-side" = "client", "x-method" = TERMINAL_KILL_METHOD_NAME))]
1532#[non_exhaustive]
1533pub struct KillTerminalResponse {
1534    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1535    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1536    /// these keys.
1537    ///
1538    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1539    #[serde_as(deserialize_as = "DefaultOnError")]
1540    #[schemars(extend("x-deserialize-default-on-error" = true))]
1541    #[serde(default)]
1542    #[serde(rename = "_meta")]
1543    pub meta: Option<Meta>,
1544}
1545
1546impl KillTerminalResponse {
1547    /// Builds [`KillTerminalResponse`] with the required response fields set; optional fields start unset or empty.
1548    #[must_use]
1549    pub fn new() -> Self {
1550        Self::default()
1551    }
1552
1553    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1554    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1555    /// these keys.
1556    ///
1557    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1558    #[must_use]
1559    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1560        self.meta = meta.into_option();
1561        self
1562    }
1563}
1564
1565/// Request to wait for a terminal command to exit.
1566#[serde_as]
1567#[skip_serializing_none]
1568#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1569#[serde(rename_all = "camelCase")]
1570#[schemars(extend("x-side" = "client", "x-method" = TERMINAL_WAIT_FOR_EXIT_METHOD_NAME))]
1571#[non_exhaustive]
1572pub struct WaitForTerminalExitRequest {
1573    /// The session ID for this request.
1574    pub session_id: SessionId,
1575    /// The ID of the terminal to wait for.
1576    pub terminal_id: TerminalId,
1577    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1578    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1579    /// these keys.
1580    ///
1581    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1582    #[serde_as(deserialize_as = "DefaultOnError")]
1583    #[schemars(extend("x-deserialize-default-on-error" = true))]
1584    #[serde(default)]
1585    #[serde(rename = "_meta")]
1586    pub meta: Option<Meta>,
1587}
1588
1589impl WaitForTerminalExitRequest {
1590    /// Builds [`WaitForTerminalExitRequest`] with the required request fields set; optional fields start unset or empty.
1591    #[must_use]
1592    pub fn new(session_id: impl Into<SessionId>, terminal_id: impl Into<TerminalId>) -> Self {
1593        Self {
1594            session_id: session_id.into(),
1595            terminal_id: terminal_id.into(),
1596            meta: None,
1597        }
1598    }
1599
1600    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1601    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1602    /// these keys.
1603    ///
1604    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1605    #[must_use]
1606    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1607        self.meta = meta.into_option();
1608        self
1609    }
1610}
1611
1612/// Response containing the exit status of a terminal command.
1613#[serde_as]
1614#[skip_serializing_none]
1615#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1616#[serde(rename_all = "camelCase")]
1617#[schemars(extend("x-side" = "client", "x-method" = TERMINAL_WAIT_FOR_EXIT_METHOD_NAME))]
1618#[non_exhaustive]
1619pub struct WaitForTerminalExitResponse {
1620    /// The exit status of the terminal command.
1621    #[serde(flatten)]
1622    pub exit_status: TerminalExitStatus,
1623    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1624    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1625    /// these keys.
1626    ///
1627    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1628    #[serde_as(deserialize_as = "DefaultOnError")]
1629    #[schemars(extend("x-deserialize-default-on-error" = true))]
1630    #[serde(default)]
1631    #[serde(rename = "_meta")]
1632    pub meta: Option<Meta>,
1633}
1634
1635impl WaitForTerminalExitResponse {
1636    /// Builds [`WaitForTerminalExitResponse`] with the required response fields set; optional fields start unset or empty.
1637    #[must_use]
1638    pub fn new(exit_status: TerminalExitStatus) -> Self {
1639        Self {
1640            exit_status,
1641            meta: None,
1642        }
1643    }
1644
1645    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1646    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1647    /// these keys.
1648    ///
1649    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1650    #[must_use]
1651    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1652        self.meta = meta.into_option();
1653        self
1654    }
1655}
1656
1657/// Exit status of a terminal command.
1658#[serde_as]
1659#[skip_serializing_none]
1660#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1661#[serde(rename_all = "camelCase")]
1662#[non_exhaustive]
1663pub struct TerminalExitStatus {
1664    /// The process exit code (may be null if terminated by signal).
1665    #[serde_as(deserialize_as = "DefaultOnError")]
1666    #[schemars(extend("x-deserialize-default-on-error" = true))]
1667    #[serde(default)]
1668    pub exit_code: Option<u32>,
1669    /// The signal that terminated the process (may be null if exited normally).
1670    #[serde_as(deserialize_as = "DefaultOnError")]
1671    #[schemars(extend("x-deserialize-default-on-error" = true))]
1672    #[serde(default)]
1673    pub signal: Option<String>,
1674    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1675    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1676    /// these keys.
1677    ///
1678    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1679    #[serde_as(deserialize_as = "DefaultOnError")]
1680    #[schemars(extend("x-deserialize-default-on-error" = true))]
1681    #[serde(default)]
1682    #[serde(rename = "_meta")]
1683    pub meta: Option<Meta>,
1684}
1685
1686impl TerminalExitStatus {
1687    /// Builds [`TerminalExitStatus`] with the required fields set; optional fields start unset or empty.
1688    #[must_use]
1689    pub fn new() -> Self {
1690        Self::default()
1691    }
1692
1693    /// The process exit code (may be null if terminated by signal).
1694    #[must_use]
1695    pub fn exit_code(mut self, exit_code: impl IntoOption<u32>) -> Self {
1696        self.exit_code = exit_code.into_option();
1697        self
1698    }
1699
1700    /// The signal that terminated the process (may be null if exited normally).
1701    #[must_use]
1702    pub fn signal(mut self, signal: impl IntoOption<String>) -> Self {
1703        self.signal = signal.into_option();
1704        self
1705    }
1706
1707    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1708    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1709    /// these keys.
1710    ///
1711    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1712    #[must_use]
1713    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1714        self.meta = meta.into_option();
1715        self
1716    }
1717}
1718
1719// Capabilities
1720
1721/// Capabilities supported by the client.
1722///
1723/// Advertised during initialization to inform the agent about
1724/// available features and methods.
1725///
1726/// See protocol docs: [Client Capabilities](https://agentclientprotocol.com/protocol/initialization#client-capabilities)
1727#[serde_as]
1728#[skip_serializing_none]
1729#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1730#[serde(rename_all = "camelCase")]
1731#[non_exhaustive]
1732pub struct ClientCapabilities {
1733    /// File system capabilities supported by the client.
1734    /// Determines which file operations the agent can request.
1735    #[serde_as(deserialize_as = "DefaultOnError")]
1736    #[schemars(extend("x-deserialize-default-on-error" = true))]
1737    #[serde(default)]
1738    pub fs: FileSystemCapabilities,
1739    /// Whether the Client support all `terminal/*` methods.
1740    #[serde_as(deserialize_as = "DefaultOnError")]
1741    #[schemars(extend("x-deserialize-default-on-error" = true))]
1742    #[serde(default)]
1743    pub terminal: bool,
1744    /// **UNSTABLE**
1745    ///
1746    /// This capability is not part of the spec yet, and may be removed or changed at any point.
1747    ///
1748    /// Session-related capabilities supported by the client.
1749    #[cfg(feature = "unstable_boolean_config")]
1750    #[serde_as(deserialize_as = "DefaultOnError")]
1751    #[schemars(extend("x-deserialize-default-on-error" = true))]
1752    #[serde(default)]
1753    pub session: Option<ClientSessionCapabilities>,
1754    /// **UNSTABLE**
1755    ///
1756    /// This capability is not part of the spec yet, and may be removed or changed at any point.
1757    ///
1758    /// Whether the client supports `plan_update` and `plan_removed` session updates.
1759    ///
1760    /// Optional. Omitted means the client does not advertise support.
1761    /// Supplying `{}` means the client can receive both update types.
1762    #[cfg(feature = "unstable_plan_operations")]
1763    #[serde_as(deserialize_as = "DefaultOnError")]
1764    #[schemars(extend("x-deserialize-default-on-error" = true))]
1765    #[serde(default)]
1766    pub plan: Option<PlanCapabilities>,
1767    /// **UNSTABLE**
1768    ///
1769    /// This capability is not part of the spec yet, and may be removed or changed at any point.
1770    ///
1771    /// Authentication capabilities supported by the client.
1772    /// Determines which authentication method types the agent may include
1773    /// in its `InitializeResponse`.
1774    #[cfg(feature = "unstable_auth_methods")]
1775    #[serde_as(deserialize_as = "DefaultOnError")]
1776    #[schemars(extend("x-deserialize-default-on-error" = true))]
1777    #[serde(default)]
1778    pub auth: AuthCapabilities,
1779    /// **UNSTABLE**
1780    ///
1781    /// This capability is not part of the spec yet, and may be removed or changed at any point.
1782    ///
1783    /// Elicitation capabilities supported by the client.
1784    /// Determines which elicitation modes the agent may use.
1785    #[cfg(feature = "unstable_elicitation")]
1786    #[serde_as(deserialize_as = "DefaultOnError")]
1787    #[schemars(extend("x-deserialize-default-on-error" = true))]
1788    #[serde(default)]
1789    pub elicitation: Option<ElicitationCapabilities>,
1790    /// **UNSTABLE**
1791    ///
1792    /// This capability is not part of the spec yet, and may be removed or changed at any point.
1793    ///
1794    /// NES (Next Edit Suggestions) capabilities supported by the client.
1795    #[cfg(feature = "unstable_nes")]
1796    #[serde_as(deserialize_as = "DefaultOnError")]
1797    #[schemars(extend("x-deserialize-default-on-error" = true))]
1798    #[serde(default)]
1799    pub nes: Option<ClientNesCapabilities>,
1800    /// **UNSTABLE**
1801    ///
1802    /// This capability is not part of the spec yet, and may be removed or changed at any point.
1803    ///
1804    /// The position encodings supported by the client, in order of preference.
1805    #[cfg(feature = "unstable_nes")]
1806    #[serde_as(deserialize_as = "DefaultOnError<VecSkipError<_, SkipListener>>")]
1807    #[schemars(extend("x-deserialize-default-on-error" = true, "x-deserialize-skip-invalid-items" = true))]
1808    #[serde(default, skip_serializing_if = "Vec::is_empty")]
1809    pub position_encodings: Vec<PositionEncodingKind>,
1810
1811    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1812    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1813    /// these keys.
1814    ///
1815    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1816    #[serde_as(deserialize_as = "DefaultOnError")]
1817    #[schemars(extend("x-deserialize-default-on-error" = true))]
1818    #[serde(default)]
1819    #[serde(rename = "_meta")]
1820    pub meta: Option<Meta>,
1821}
1822
1823impl ClientCapabilities {
1824    /// Builds an empty [`ClientCapabilities`]; use builder methods to advertise supported sub-capabilities.
1825    #[must_use]
1826    pub fn new() -> Self {
1827        Self::default()
1828    }
1829
1830    /// File system capabilities supported by the client.
1831    /// Determines which file operations the agent can request.
1832    #[must_use]
1833    pub fn fs(mut self, fs: FileSystemCapabilities) -> Self {
1834        self.fs = fs;
1835        self
1836    }
1837
1838    /// Whether the Client support all `terminal/*` methods.
1839    #[must_use]
1840    pub fn terminal(mut self, terminal: bool) -> Self {
1841        self.terminal = terminal;
1842        self
1843    }
1844
1845    /// **UNSTABLE**
1846    ///
1847    /// This capability is not part of the spec yet, and may be removed or changed at any point.
1848    ///
1849    /// Session-related capabilities supported by the client.
1850    #[cfg(feature = "unstable_boolean_config")]
1851    #[must_use]
1852    pub fn session(mut self, session: impl IntoOption<ClientSessionCapabilities>) -> Self {
1853        self.session = session.into_option();
1854        self
1855    }
1856
1857    /// **UNSTABLE**
1858    ///
1859    /// This capability is not part of the spec yet, and may be removed or changed at any point.
1860    ///
1861    /// Whether the client supports `plan_update` and `plan_removed` session updates.
1862    ///
1863    /// Omitted means the client does not advertise support.
1864    /// Supplying `{}` means the client can receive both update types.
1865    #[cfg(feature = "unstable_plan_operations")]
1866    #[must_use]
1867    pub fn plan(mut self, plan: impl IntoOption<PlanCapabilities>) -> Self {
1868        self.plan = plan.into_option();
1869        self
1870    }
1871
1872    /// **UNSTABLE**
1873    ///
1874    /// This capability is not part of the spec yet, and may be removed or changed at any point.
1875    ///
1876    /// Authentication capabilities supported by the client.
1877    /// Determines which authentication method types the agent may include
1878    /// in its `InitializeResponse`.
1879    #[cfg(feature = "unstable_auth_methods")]
1880    #[must_use]
1881    pub fn auth(mut self, auth: AuthCapabilities) -> Self {
1882        self.auth = auth;
1883        self
1884    }
1885
1886    /// **UNSTABLE**
1887    ///
1888    /// This capability is not part of the spec yet, and may be removed or changed at any point.
1889    ///
1890    /// Elicitation capabilities supported by the client.
1891    /// Determines which elicitation modes the agent may use.
1892    #[cfg(feature = "unstable_elicitation")]
1893    #[must_use]
1894    pub fn elicitation(mut self, elicitation: impl IntoOption<ElicitationCapabilities>) -> Self {
1895        self.elicitation = elicitation.into_option();
1896        self
1897    }
1898
1899    /// **UNSTABLE**
1900    ///
1901    /// NES (Next Edit Suggestions) capabilities supported by the client.
1902    #[cfg(feature = "unstable_nes")]
1903    #[must_use]
1904    pub fn nes(mut self, nes: impl IntoOption<ClientNesCapabilities>) -> Self {
1905        self.nes = nes.into_option();
1906        self
1907    }
1908
1909    /// **UNSTABLE**
1910    ///
1911    /// The position encodings supported by the client, in order of preference.
1912    #[cfg(feature = "unstable_nes")]
1913    #[must_use]
1914    pub fn position_encodings(mut self, position_encodings: Vec<PositionEncodingKind>) -> Self {
1915        self.position_encodings = position_encodings;
1916        self
1917    }
1918
1919    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1920    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1921    /// these keys.
1922    ///
1923    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1924    #[must_use]
1925    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1926        self.meta = meta.into_option();
1927        self
1928    }
1929}
1930
1931/// **UNSTABLE**
1932///
1933/// This capability is not part of the spec yet, and may be removed or changed at any point.
1934///
1935/// Session-related capabilities supported by the client.
1936#[cfg(feature = "unstable_boolean_config")]
1937#[serde_as]
1938#[skip_serializing_none]
1939#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1940#[serde(rename_all = "camelCase")]
1941#[non_exhaustive]
1942pub struct ClientSessionCapabilities {
1943    /// Config option capabilities supported by the client.
1944    ///
1945    /// Omitted or `null` means the client does not advertise support for any
1946    /// config option extensions.
1947    #[serde_as(deserialize_as = "DefaultOnError")]
1948    #[schemars(extend("x-deserialize-default-on-error" = true))]
1949    #[serde(default)]
1950    pub config_options: Option<SessionConfigOptionsCapabilities>,
1951    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1952    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1953    /// these keys.
1954    ///
1955    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1956    #[serde_as(deserialize_as = "DefaultOnError")]
1957    #[schemars(extend("x-deserialize-default-on-error" = true))]
1958    #[serde(default)]
1959    #[serde(rename = "_meta")]
1960    pub meta: Option<Meta>,
1961}
1962
1963#[cfg(feature = "unstable_boolean_config")]
1964impl ClientSessionCapabilities {
1965    /// Builds an empty [`ClientSessionCapabilities`]; use builder methods to advertise supported sub-capabilities.
1966    #[must_use]
1967    pub fn new() -> Self {
1968        Self::default()
1969    }
1970
1971    /// Config option capabilities supported by the client.
1972    ///
1973    /// Omitted or `null` means the client does not advertise support for any
1974    /// config option extensions.
1975    #[must_use]
1976    pub fn config_options(
1977        mut self,
1978        config_options: impl IntoOption<SessionConfigOptionsCapabilities>,
1979    ) -> Self {
1980        self.config_options = config_options.into_option();
1981        self
1982    }
1983
1984    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1985    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1986    /// these keys.
1987    ///
1988    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1989    #[must_use]
1990    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1991        self.meta = meta.into_option();
1992        self
1993    }
1994}
1995
1996/// **UNSTABLE**
1997///
1998/// This capability is not part of the spec yet, and may be removed or changed at any point.
1999///
2000/// Session configuration option capabilities supported by the client.
2001#[cfg(feature = "unstable_boolean_config")]
2002#[serde_as]
2003#[skip_serializing_none]
2004#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2005#[serde(rename_all = "camelCase")]
2006#[non_exhaustive]
2007pub struct SessionConfigOptionsCapabilities {
2008    /// Whether the client supports boolean session configuration options.
2009    ///
2010    /// Omitted or `null` means the client does not advertise support.
2011    /// Supplying `{}` means agents may include `type: "boolean"` entries in
2012    /// `configOptions`, and the client may send `session/set_config_option`
2013    /// requests with `type: "boolean"` and a boolean `value`.
2014    #[serde_as(deserialize_as = "DefaultOnError")]
2015    #[schemars(extend("x-deserialize-default-on-error" = true))]
2016    #[serde(default)]
2017    pub boolean: Option<BooleanConfigOptionCapabilities>,
2018    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
2019    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
2020    /// these keys.
2021    ///
2022    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
2023    #[serde_as(deserialize_as = "DefaultOnError")]
2024    #[schemars(extend("x-deserialize-default-on-error" = true))]
2025    #[serde(default)]
2026    #[serde(rename = "_meta")]
2027    pub meta: Option<Meta>,
2028}
2029
2030#[cfg(feature = "unstable_boolean_config")]
2031impl SessionConfigOptionsCapabilities {
2032    /// Builds an empty [`SessionConfigOptionsCapabilities`]; use builder methods to advertise supported sub-capabilities.
2033    #[must_use]
2034    pub fn new() -> Self {
2035        Self::default()
2036    }
2037
2038    /// Whether the client supports boolean session configuration options.
2039    ///
2040    /// Omitted or `null` means the client does not advertise support.
2041    /// Supplying `{}` means agents may include `type: "boolean"` entries in
2042    /// `configOptions`, and the client may send `session/set_config_option`
2043    /// requests with `type: "boolean"` and a boolean `value`.
2044    #[must_use]
2045    pub fn boolean(mut self, boolean: impl IntoOption<BooleanConfigOptionCapabilities>) -> Self {
2046        self.boolean = boolean.into_option();
2047        self
2048    }
2049
2050    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
2051    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
2052    /// these keys.
2053    ///
2054    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
2055    #[must_use]
2056    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2057        self.meta = meta.into_option();
2058        self
2059    }
2060}
2061
2062/// **UNSTABLE**
2063///
2064/// This capability is not part of the spec yet, and may be removed or changed at any point.
2065///
2066/// Capabilities for boolean session configuration options.
2067///
2068/// Supplying `{}` means the client supports boolean session configuration options.
2069#[cfg(feature = "unstable_boolean_config")]
2070#[serde_as]
2071#[skip_serializing_none]
2072#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2073#[non_exhaustive]
2074pub struct BooleanConfigOptionCapabilities {
2075    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
2076    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
2077    /// these keys.
2078    ///
2079    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
2080    #[serde_as(deserialize_as = "DefaultOnError")]
2081    #[schemars(extend("x-deserialize-default-on-error" = true))]
2082    #[serde(default)]
2083    #[serde(rename = "_meta")]
2084    pub meta: Option<Meta>,
2085}
2086
2087#[cfg(feature = "unstable_boolean_config")]
2088impl BooleanConfigOptionCapabilities {
2089    /// Builds an empty [`BooleanConfigOptionCapabilities`]; use builder methods to advertise supported sub-capabilities.
2090    #[must_use]
2091    pub fn new() -> Self {
2092        Self::default()
2093    }
2094
2095    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
2096    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
2097    /// these keys.
2098    ///
2099    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
2100    #[must_use]
2101    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2102        self.meta = meta.into_option();
2103        self
2104    }
2105}
2106
2107/// **UNSTABLE**
2108///
2109/// This capability is not part of the spec yet, and may be removed or changed at any point.
2110///
2111/// Authentication capabilities supported by the client.
2112///
2113/// Advertised during initialization to inform the agent which authentication
2114/// method types the client can handle. This governs opt-in types that require
2115/// additional client-side support.
2116#[cfg(feature = "unstable_auth_methods")]
2117#[serde_as]
2118#[skip_serializing_none]
2119#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2120#[serde(rename_all = "camelCase")]
2121#[non_exhaustive]
2122pub struct AuthCapabilities {
2123    /// Whether the client supports `terminal` authentication methods.
2124    ///
2125    /// When `true`, the agent may include `terminal` entries in its authentication methods.
2126    #[serde_as(deserialize_as = "DefaultOnError")]
2127    #[schemars(extend("x-deserialize-default-on-error" = true))]
2128    #[serde(default)]
2129    pub terminal: bool,
2130    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
2131    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
2132    /// these keys.
2133    ///
2134    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
2135    #[serde_as(deserialize_as = "DefaultOnError")]
2136    #[schemars(extend("x-deserialize-default-on-error" = true))]
2137    #[serde(default)]
2138    #[serde(rename = "_meta")]
2139    pub meta: Option<Meta>,
2140}
2141
2142#[cfg(feature = "unstable_auth_methods")]
2143impl AuthCapabilities {
2144    /// Builds an empty [`AuthCapabilities`]; use builder methods to advertise supported sub-capabilities.
2145    #[must_use]
2146    pub fn new() -> Self {
2147        Self::default()
2148    }
2149
2150    /// Whether the client supports `terminal` authentication methods.
2151    ///
2152    /// When `true`, the agent may include `AuthMethod::Terminal`
2153    /// entries in its authentication methods.
2154    #[must_use]
2155    pub fn terminal(mut self, terminal: bool) -> Self {
2156        self.terminal = terminal;
2157        self
2158    }
2159
2160    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
2161    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
2162    /// these keys.
2163    ///
2164    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
2165    #[must_use]
2166    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2167        self.meta = meta.into_option();
2168        self
2169    }
2170}
2171
2172/// File system capabilities that a client may support.
2173///
2174/// See protocol docs: [FileSystem](https://agentclientprotocol.com/protocol/initialization#filesystem)
2175#[serde_as]
2176#[skip_serializing_none]
2177#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2178#[serde(rename_all = "camelCase")]
2179#[non_exhaustive]
2180pub struct FileSystemCapabilities {
2181    /// Whether the Client supports `fs/read_text_file` requests.
2182    #[serde_as(deserialize_as = "DefaultOnError")]
2183    #[schemars(extend("x-deserialize-default-on-error" = true))]
2184    #[serde(default)]
2185    pub read_text_file: bool,
2186    /// Whether the Client supports `fs/write_text_file` requests.
2187    #[serde_as(deserialize_as = "DefaultOnError")]
2188    #[schemars(extend("x-deserialize-default-on-error" = true))]
2189    #[serde(default)]
2190    pub write_text_file: bool,
2191    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
2192    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
2193    /// these keys.
2194    ///
2195    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
2196    #[serde_as(deserialize_as = "DefaultOnError")]
2197    #[schemars(extend("x-deserialize-default-on-error" = true))]
2198    #[serde(default)]
2199    #[serde(rename = "_meta")]
2200    pub meta: Option<Meta>,
2201}
2202
2203impl FileSystemCapabilities {
2204    /// Builds an empty [`FileSystemCapabilities`]; use builder methods to advertise supported sub-capabilities.
2205    #[must_use]
2206    pub fn new() -> Self {
2207        Self::default()
2208    }
2209
2210    /// Whether the Client supports `fs/read_text_file` requests.
2211    #[must_use]
2212    pub fn read_text_file(mut self, read_text_file: bool) -> Self {
2213        self.read_text_file = read_text_file;
2214        self
2215    }
2216
2217    /// Whether the Client supports `fs/write_text_file` requests.
2218    #[must_use]
2219    pub fn write_text_file(mut self, write_text_file: bool) -> Self {
2220        self.write_text_file = write_text_file;
2221        self
2222    }
2223
2224    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
2225    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
2226    /// these keys.
2227    ///
2228    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
2229    #[must_use]
2230    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2231        self.meta = meta.into_option();
2232        self
2233    }
2234}
2235
2236// Method schema
2237
2238/// Names of all methods that clients handle.
2239///
2240/// Provides a centralized definition of method names used in the protocol.
2241#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
2242#[non_exhaustive]
2243pub struct ClientMethodNames {
2244    /// Method for requesting permission from the user.
2245    pub session_request_permission: &'static str,
2246    /// Notification for session updates.
2247    pub session_update: &'static str,
2248    /// Method for writing text files.
2249    pub fs_write_text_file: &'static str,
2250    /// Method for reading text files.
2251    pub fs_read_text_file: &'static str,
2252    /// Method for creating new terminals.
2253    pub terminal_create: &'static str,
2254    /// Method for getting terminals output.
2255    pub terminal_output: &'static str,
2256    /// Method for releasing a terminal.
2257    pub terminal_release: &'static str,
2258    /// Method for waiting for a terminal to finish.
2259    pub terminal_wait_for_exit: &'static str,
2260    /// Method for killing a terminal.
2261    pub terminal_kill: &'static str,
2262    /// Method for opening an MCP-over-ACP connection.
2263    #[cfg(feature = "unstable_mcp_over_acp")]
2264    pub mcp_connect: &'static str,
2265    /// Method for exchanging MCP-over-ACP messages.
2266    #[cfg(feature = "unstable_mcp_over_acp")]
2267    pub mcp_message: &'static str,
2268    /// Method for closing an MCP-over-ACP connection.
2269    #[cfg(feature = "unstable_mcp_over_acp")]
2270    pub mcp_disconnect: &'static str,
2271    /// Method for elicitation.
2272    #[cfg(feature = "unstable_elicitation")]
2273    pub elicitation_create: &'static str,
2274    /// Notification for elicitation completion.
2275    #[cfg(feature = "unstable_elicitation")]
2276    pub elicitation_complete: &'static str,
2277}
2278
2279/// Constant containing all client method names.
2280pub const CLIENT_METHOD_NAMES: ClientMethodNames = ClientMethodNames {
2281    session_update: SESSION_UPDATE_NOTIFICATION,
2282    session_request_permission: SESSION_REQUEST_PERMISSION_METHOD_NAME,
2283    fs_write_text_file: FS_WRITE_TEXT_FILE_METHOD_NAME,
2284    fs_read_text_file: FS_READ_TEXT_FILE_METHOD_NAME,
2285    terminal_create: TERMINAL_CREATE_METHOD_NAME,
2286    terminal_output: TERMINAL_OUTPUT_METHOD_NAME,
2287    terminal_release: TERMINAL_RELEASE_METHOD_NAME,
2288    terminal_wait_for_exit: TERMINAL_WAIT_FOR_EXIT_METHOD_NAME,
2289    terminal_kill: TERMINAL_KILL_METHOD_NAME,
2290    #[cfg(feature = "unstable_mcp_over_acp")]
2291    mcp_connect: MCP_CONNECT_METHOD_NAME,
2292    #[cfg(feature = "unstable_mcp_over_acp")]
2293    mcp_message: MCP_MESSAGE_METHOD_NAME,
2294    #[cfg(feature = "unstable_mcp_over_acp")]
2295    mcp_disconnect: MCP_DISCONNECT_METHOD_NAME,
2296    #[cfg(feature = "unstable_elicitation")]
2297    elicitation_create: ELICITATION_CREATE_METHOD_NAME,
2298    #[cfg(feature = "unstable_elicitation")]
2299    elicitation_complete: ELICITATION_COMPLETE_NOTIFICATION,
2300};
2301
2302/// Notification name for session updates.
2303pub(crate) const SESSION_UPDATE_NOTIFICATION: &str = "session/update";
2304/// Method name for requesting user permission.
2305pub(crate) const SESSION_REQUEST_PERMISSION_METHOD_NAME: &str = "session/request_permission";
2306/// Method name for writing text files.
2307pub(crate) const FS_WRITE_TEXT_FILE_METHOD_NAME: &str = "fs/write_text_file";
2308/// Method name for reading text files.
2309pub(crate) const FS_READ_TEXT_FILE_METHOD_NAME: &str = "fs/read_text_file";
2310/// Method name for creating a new terminal.
2311pub(crate) const TERMINAL_CREATE_METHOD_NAME: &str = "terminal/create";
2312/// Method for getting terminals output.
2313pub(crate) const TERMINAL_OUTPUT_METHOD_NAME: &str = "terminal/output";
2314/// Method for releasing a terminal.
2315pub(crate) const TERMINAL_RELEASE_METHOD_NAME: &str = "terminal/release";
2316/// Method for waiting for a terminal to finish.
2317pub(crate) const TERMINAL_WAIT_FOR_EXIT_METHOD_NAME: &str = "terminal/wait_for_exit";
2318/// Method for killing a terminal.
2319pub(crate) const TERMINAL_KILL_METHOD_NAME: &str = "terminal/kill";
2320/// Method name for elicitation.
2321#[cfg(feature = "unstable_elicitation")]
2322pub(crate) const ELICITATION_CREATE_METHOD_NAME: &str = "elicitation/create";
2323/// Notification name for elicitation completion.
2324#[cfg(feature = "unstable_elicitation")]
2325pub(crate) const ELICITATION_COMPLETE_NOTIFICATION: &str = "elicitation/complete";
2326
2327/// All possible requests that an agent can send to a client.
2328///
2329/// This enum is used internally for routing RPC requests. You typically won't need
2330/// to use this directly.
2331///
2332/// This enum encompasses all method calls from agent to client.
2333#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
2334#[serde(untagged)]
2335#[schemars(inline)]
2336#[non_exhaustive]
2337#[allow(clippy::large_enum_variant)]
2338pub enum AgentRequest {
2339    /// Writes content to a text file in the client's file system.
2340    ///
2341    /// Only available if the client advertises the `fs.writeTextFile` capability.
2342    /// Allows the agent to create or modify files within the client's environment.
2343    ///
2344    /// See protocol docs: [Client](https://agentclientprotocol.com/protocol/overview#client)
2345    WriteTextFileRequest(WriteTextFileRequest),
2346    /// Reads content from a text file in the client's file system.
2347    ///
2348    /// Only available if the client advertises the `fs.readTextFile` capability.
2349    /// Allows the agent to access file contents within the client's environment.
2350    ///
2351    /// See protocol docs: [Client](https://agentclientprotocol.com/protocol/overview#client)
2352    ReadTextFileRequest(ReadTextFileRequest),
2353    /// Requests permission from the user for a tool call operation.
2354    ///
2355    /// Called by the agent when it needs user authorization before executing
2356    /// a potentially sensitive operation. The client should present the options
2357    /// to the user and return their decision.
2358    ///
2359    /// If the client cancels the prompt turn via `session/cancel`, it MUST
2360    /// respond to this request with `RequestPermissionOutcome::Cancelled`.
2361    ///
2362    /// See protocol docs: [Requesting Permission](https://agentclientprotocol.com/protocol/tool-calls#requesting-permission)
2363    RequestPermissionRequest(RequestPermissionRequest),
2364    /// Executes a command in a new terminal
2365    ///
2366    /// Only available if the `terminal` Client capability is set to `true`.
2367    ///
2368    /// Returns a `TerminalId` that can be used with other terminal methods
2369    /// to get the current output, wait for exit, and kill the command.
2370    ///
2371    /// The `TerminalId` can also be used to embed the terminal in a tool call
2372    /// by using the `ToolCallContent::Terminal` variant.
2373    ///
2374    /// The Agent is responsible for releasing the terminal by using the `terminal/release`
2375    /// method.
2376    ///
2377    /// See protocol docs: [Terminals](https://agentclientprotocol.com/protocol/terminals)
2378    CreateTerminalRequest(CreateTerminalRequest),
2379    /// Gets the terminal output and exit status
2380    ///
2381    /// Returns the current content in the terminal without waiting for the command to exit.
2382    /// If the command has already exited, the exit status is included.
2383    ///
2384    /// See protocol docs: [Terminals](https://agentclientprotocol.com/protocol/terminals)
2385    TerminalOutputRequest(TerminalOutputRequest),
2386    /// Releases a terminal
2387    ///
2388    /// The command is killed if it hasn't exited yet. Use `terminal/wait_for_exit`
2389    /// to wait for the command to exit before releasing the terminal.
2390    ///
2391    /// After release, the `TerminalId` can no longer be used with other `terminal/*` methods,
2392    /// but tool calls that already contain it, continue to display its output.
2393    ///
2394    /// The `terminal/kill` method can be used to terminate the command without releasing
2395    /// the terminal, allowing the Agent to call `terminal/output` and other methods.
2396    ///
2397    /// See protocol docs: [Terminals](https://agentclientprotocol.com/protocol/terminals)
2398    ReleaseTerminalRequest(ReleaseTerminalRequest),
2399    /// Waits for the terminal command to exit and return its exit status
2400    ///
2401    /// See protocol docs: [Terminals](https://agentclientprotocol.com/protocol/terminals)
2402    WaitForTerminalExitRequest(WaitForTerminalExitRequest),
2403    /// Kills the terminal command without releasing the terminal
2404    ///
2405    /// While `terminal/release` will also kill the command, this method will keep
2406    /// the `TerminalId` valid so it can be used with other methods.
2407    ///
2408    /// This method can be helpful when implementing command timeouts which terminate
2409    /// the command as soon as elapsed, and then get the final output so it can be sent
2410    /// to the model.
2411    ///
2412    /// Note: Call `terminal/release` when `TerminalId` is no longer needed.
2413    ///
2414    /// See protocol docs: [Terminals](https://agentclientprotocol.com/protocol/terminals)
2415    KillTerminalRequest(KillTerminalRequest),
2416    /// **UNSTABLE**
2417    ///
2418    /// This capability is not part of the spec yet, and may be removed or changed at any point.
2419    ///
2420    /// Requests structured user input via a form or URL.
2421    #[cfg(feature = "unstable_elicitation")]
2422    CreateElicitationRequest(CreateElicitationRequest),
2423    /// **UNSTABLE**
2424    ///
2425    /// This capability is not part of the spec yet, and may be removed or changed at any point.
2426    ///
2427    /// Opens an MCP-over-ACP connection.
2428    #[cfg(feature = "unstable_mcp_over_acp")]
2429    ConnectMcpRequest(ConnectMcpRequest),
2430    /// **UNSTABLE**
2431    ///
2432    /// This capability is not part of the spec yet, and may be removed or changed at any point.
2433    ///
2434    /// Exchanges an MCP-over-ACP message.
2435    #[cfg(feature = "unstable_mcp_over_acp")]
2436    MessageMcpRequest(MessageMcpRequest),
2437    /// **UNSTABLE**
2438    ///
2439    /// This capability is not part of the spec yet, and may be removed or changed at any point.
2440    ///
2441    /// Closes an MCP-over-ACP connection.
2442    #[cfg(feature = "unstable_mcp_over_acp")]
2443    DisconnectMcpRequest(DisconnectMcpRequest),
2444    /// Handles extension method requests from the agent.
2445    ///
2446    /// Allows the Agent to send an arbitrary request that is not part of the ACP spec.
2447    /// Extension methods provide a way to add custom functionality while maintaining
2448    /// protocol compatibility.
2449    ///
2450    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
2451    ExtMethodRequest(ExtRequest),
2452}
2453
2454impl AgentRequest {
2455    /// Returns the corresponding method name of the request.
2456    #[must_use]
2457    pub fn method(&self) -> &str {
2458        match self {
2459            Self::WriteTextFileRequest(_) => CLIENT_METHOD_NAMES.fs_write_text_file,
2460            Self::ReadTextFileRequest(_) => CLIENT_METHOD_NAMES.fs_read_text_file,
2461            Self::RequestPermissionRequest(_) => CLIENT_METHOD_NAMES.session_request_permission,
2462            Self::CreateTerminalRequest(_) => CLIENT_METHOD_NAMES.terminal_create,
2463            Self::TerminalOutputRequest(_) => CLIENT_METHOD_NAMES.terminal_output,
2464            Self::ReleaseTerminalRequest(_) => CLIENT_METHOD_NAMES.terminal_release,
2465            Self::WaitForTerminalExitRequest(_) => CLIENT_METHOD_NAMES.terminal_wait_for_exit,
2466            Self::KillTerminalRequest(_) => CLIENT_METHOD_NAMES.terminal_kill,
2467            #[cfg(feature = "unstable_elicitation")]
2468            Self::CreateElicitationRequest(_) => CLIENT_METHOD_NAMES.elicitation_create,
2469            #[cfg(feature = "unstable_mcp_over_acp")]
2470            Self::ConnectMcpRequest(_) => CLIENT_METHOD_NAMES.mcp_connect,
2471            #[cfg(feature = "unstable_mcp_over_acp")]
2472            Self::MessageMcpRequest(_) => CLIENT_METHOD_NAMES.mcp_message,
2473            #[cfg(feature = "unstable_mcp_over_acp")]
2474            Self::DisconnectMcpRequest(_) => CLIENT_METHOD_NAMES.mcp_disconnect,
2475            Self::ExtMethodRequest(ext_request) => &ext_request.method,
2476        }
2477    }
2478}
2479
2480/// All possible responses that a client can send to an agent.
2481///
2482/// This enum is used internally for routing RPC responses. You typically won't need
2483/// to use this directly - the responses are handled automatically by the connection.
2484///
2485/// These are responses to the corresponding `AgentRequest` variants.
2486#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
2487#[serde(untagged)]
2488#[schemars(inline)]
2489#[non_exhaustive]
2490pub enum ClientResponse {
2491    /// Successful result returned for a `fs/write_text_file` request.
2492    WriteTextFileResponse(#[serde(default)] WriteTextFileResponse),
2493    /// Successful result returned for a `fs/read_text_file` request.
2494    ReadTextFileResponse(ReadTextFileResponse),
2495    /// Successful result returned for a `session/request_permission` request.
2496    RequestPermissionResponse(RequestPermissionResponse),
2497    /// Successful result returned for a `terminal/create` request.
2498    CreateTerminalResponse(CreateTerminalResponse),
2499    /// Successful result returned for a `terminal/output` request.
2500    TerminalOutputResponse(TerminalOutputResponse),
2501    /// Successful result returned for a `terminal/release` request.
2502    ReleaseTerminalResponse(#[serde(default)] ReleaseTerminalResponse),
2503    /// Successful result returned for a `terminal/wait_for_exit` request.
2504    WaitForTerminalExitResponse(WaitForTerminalExitResponse),
2505    /// Successful result returned for a `terminal/kill` request.
2506    KillTerminalResponse(#[serde(default)] KillTerminalResponse),
2507    /// Successful result returned for a `elicitation/create` request.
2508    #[cfg(feature = "unstable_elicitation")]
2509    CreateElicitationResponse(CreateElicitationResponse),
2510    /// Successful result returned for a `mcp/connect` request.
2511    #[cfg(feature = "unstable_mcp_over_acp")]
2512    ConnectMcpResponse(ConnectMcpResponse),
2513    /// Successful result returned for a `mcp/disconnect` request.
2514    #[cfg(feature = "unstable_mcp_over_acp")]
2515    DisconnectMcpResponse(#[serde(default)] DisconnectMcpResponse),
2516    /// Successful result returned by an MCP-over-ACP `mcp/message` request.
2517    #[cfg(feature = "unstable_mcp_over_acp")]
2518    MessageMcpResponse(MessageMcpResponse),
2519    /// Successful result returned by an extension method outside the core ACP method set.
2520    ExtMethodResponse(ExtResponse),
2521}
2522
2523/// All possible notifications that an agent can send to a client.
2524///
2525/// This enum is used internally for routing RPC notifications. You typically won't need
2526/// to use this directly.
2527///
2528/// Notifications do not expect a response.
2529#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
2530#[serde(untagged)]
2531#[expect(clippy::large_enum_variant)]
2532#[schemars(inline)]
2533#[non_exhaustive]
2534pub enum AgentNotification {
2535    /// Handles session update notifications from the agent.
2536    ///
2537    /// This is a notification endpoint (no response expected) that receives
2538    /// real-time updates about session progress, including message chunks,
2539    /// tool calls, and execution plans.
2540    ///
2541    /// Note: Clients SHOULD continue accepting tool call updates even after
2542    /// sending a `session/cancel` notification, as the agent may send final
2543    /// updates before responding with the cancelled stop reason.
2544    ///
2545    /// See protocol docs: [Agent Reports Output](https://agentclientprotocol.com/protocol/prompt-turn#3-agent-reports-output)
2546    SessionNotification(SessionNotification),
2547    /// **UNSTABLE**
2548    ///
2549    /// This capability is not part of the spec yet, and may be removed or changed at any point.
2550    ///
2551    /// Notification that a URL-based elicitation has completed.
2552    #[cfg(feature = "unstable_elicitation")]
2553    CompleteElicitationNotification(CompleteElicitationNotification),
2554    /// **UNSTABLE**
2555    ///
2556    /// This capability is not part of the spec yet, and may be removed or changed at any point.
2557    ///
2558    /// Receives an MCP-over-ACP notification.
2559    #[cfg(feature = "unstable_mcp_over_acp")]
2560    MessageMcpNotification(MessageMcpNotification),
2561    /// Handles extension notifications from the agent.
2562    ///
2563    /// Allows the Agent to send an arbitrary notification that is not part of the ACP spec.
2564    /// Extension notifications provide a way to send one-way messages for custom functionality
2565    /// while maintaining protocol compatibility.
2566    ///
2567    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
2568    ExtNotification(ExtNotification),
2569}
2570
2571impl AgentNotification {
2572    /// Returns the corresponding method name of the notification.
2573    #[must_use]
2574    pub fn method(&self) -> &str {
2575        match self {
2576            Self::SessionNotification(_) => CLIENT_METHOD_NAMES.session_update,
2577            #[cfg(feature = "unstable_elicitation")]
2578            Self::CompleteElicitationNotification(_) => CLIENT_METHOD_NAMES.elicitation_complete,
2579            #[cfg(feature = "unstable_mcp_over_acp")]
2580            Self::MessageMcpNotification(_) => CLIENT_METHOD_NAMES.mcp_message,
2581            Self::ExtNotification(ext_notification) => &ext_notification.method,
2582        }
2583    }
2584}
2585
2586#[cfg(test)]
2587mod tests {
2588    use super::*;
2589
2590    #[test]
2591    fn test_client_capabilities_default_on_malformed_values() {
2592        use serde_json::json;
2593
2594        let capabilities: ClientCapabilities = serde_json::from_value(json!({
2595            "fs": {
2596                "readTextFile": "yes",
2597                "writeTextFile": true
2598            },
2599            "terminal": {}
2600        }))
2601        .unwrap();
2602
2603        assert!(!capabilities.fs.read_text_file);
2604        assert!(capabilities.fs.write_text_file);
2605        assert!(!capabilities.terminal);
2606
2607        let capabilities: ClientCapabilities = serde_json::from_value(json!({
2608            "fs": false
2609        }))
2610        .unwrap();
2611        assert_eq!(capabilities.fs, FileSystemCapabilities::default());
2612
2613        #[cfg(feature = "unstable_auth_methods")]
2614        {
2615            let capabilities: ClientCapabilities = serde_json::from_value(json!({
2616                "auth": false
2617            }))
2618            .unwrap();
2619            assert_eq!(capabilities.auth, AuthCapabilities::default());
2620
2621            let capabilities: AuthCapabilities = serde_json::from_value(json!({
2622                "terminal": {}
2623            }))
2624            .unwrap();
2625            assert!(!capabilities.terminal);
2626        }
2627    }
2628
2629    #[test]
2630    fn test_serialization_behavior() {
2631        use serde_json::json;
2632
2633        assert_eq!(
2634            serde_json::from_value::<SessionInfoUpdate>(json!({})).unwrap(),
2635            SessionInfoUpdate {
2636                title: MaybeUndefined::Undefined,
2637                updated_at: MaybeUndefined::Undefined,
2638                meta: None
2639            }
2640        );
2641        assert_eq!(
2642            serde_json::from_value::<SessionInfoUpdate>(json!({"title": null, "updatedAt": null}))
2643                .unwrap(),
2644            SessionInfoUpdate {
2645                title: MaybeUndefined::Null,
2646                updated_at: MaybeUndefined::Null,
2647                meta: None
2648            }
2649        );
2650        assert_eq!(
2651            serde_json::from_value::<SessionInfoUpdate>(
2652                json!({"title": "title", "updatedAt": "timestamp"})
2653            )
2654            .unwrap(),
2655            SessionInfoUpdate {
2656                title: MaybeUndefined::Value("title".to_string()),
2657                updated_at: MaybeUndefined::Value("timestamp".to_string()),
2658                meta: None
2659            }
2660        );
2661
2662        assert_eq!(
2663            serde_json::to_value(SessionInfoUpdate::new()).unwrap(),
2664            json!({})
2665        );
2666        assert_eq!(
2667            serde_json::to_value(SessionInfoUpdate::new().title("title")).unwrap(),
2668            json!({"title": "title"})
2669        );
2670        assert_eq!(
2671            serde_json::to_value(SessionInfoUpdate::new().title(None)).unwrap(),
2672            json!({"title": null})
2673        );
2674        assert_eq!(
2675            serde_json::to_value(
2676                SessionInfoUpdate::new()
2677                    .title("title")
2678                    .title(MaybeUndefined::Undefined)
2679            )
2680            .unwrap(),
2681            json!({})
2682        );
2683    }
2684
2685    #[test]
2686    fn test_content_chunk_message_id_serialization() {
2687        use serde_json::json;
2688
2689        assert_eq!(
2690            serde_json::to_value(SessionUpdate::AgentMessageChunk(ContentChunk::new(
2691                ContentBlock::Text(crate::v1::TextContent::new("Hello"))
2692            )))
2693            .unwrap(),
2694            json!({
2695                "sessionUpdate": "agent_message_chunk",
2696                "content": {
2697                    "type": "text",
2698                    "text": "Hello"
2699                }
2700            })
2701        );
2702
2703        assert_eq!(
2704            serde_json::to_value(SessionUpdate::AgentMessageChunk(
2705                ContentChunk::new(ContentBlock::Text(crate::v1::TextContent::new("Hello")))
2706                    .message_id("msg_agent_c42b9")
2707            ))
2708            .unwrap(),
2709            json!({
2710                "sessionUpdate": "agent_message_chunk",
2711                "messageId": "msg_agent_c42b9",
2712                "content": {
2713                    "type": "text",
2714                    "text": "Hello"
2715                }
2716            })
2717        );
2718
2719        let SessionUpdate::AgentMessageChunk(chunk) = serde_json::from_value(json!({
2720            "sessionUpdate": "agent_message_chunk",
2721            "messageId": null,
2722            "content": {
2723                "type": "text",
2724                "text": "Hello"
2725            }
2726        }))
2727        .unwrap() else {
2728            panic!("expected agent message chunk");
2729        };
2730
2731        assert_eq!(chunk.message_id, None);
2732    }
2733
2734    #[test]
2735    fn test_usage_update_serialization() {
2736        use serde_json::json;
2737
2738        assert_eq!(
2739            serde_json::to_value(SessionUpdate::UsageUpdate(UsageUpdate::new(
2740                53_000, 200_000
2741            )))
2742            .unwrap(),
2743            json!({
2744                "sessionUpdate": "usage_update",
2745                "used": 53000,
2746                "size": 200_000
2747            })
2748        );
2749
2750        assert_eq!(
2751            serde_json::to_value(SessionUpdate::UsageUpdate(
2752                UsageUpdate::new(53_000, 200_000).cost(Cost::new(0.045, "USD"))
2753            ))
2754            .unwrap(),
2755            json!({
2756                "sessionUpdate": "usage_update",
2757                "used": 53000,
2758                "size": 200_000,
2759                "cost": {
2760                    "amount": 0.045,
2761                    "currency": "USD"
2762                }
2763            })
2764        );
2765
2766        let SessionUpdate::UsageUpdate(update) = serde_json::from_value(json!({
2767            "sessionUpdate": "usage_update",
2768            "used": 53000,
2769            "size": 200_000,
2770            "cost": null
2771        }))
2772        .unwrap() else {
2773            panic!("expected usage update");
2774        };
2775
2776        assert_eq!(update.cost, None);
2777    }
2778
2779    #[cfg(feature = "unstable_nes")]
2780    #[test]
2781    fn test_client_capabilities_position_encodings_serialization() {
2782        use serde_json::json;
2783
2784        let capabilities = ClientCapabilities::new().position_encodings(vec![
2785            PositionEncodingKind::Utf32,
2786            PositionEncodingKind::Utf16,
2787        ]);
2788        let json = serde_json::to_value(&capabilities).unwrap();
2789
2790        assert_eq!(json["positionEncodings"], json!(["utf-32", "utf-16"]));
2791    }
2792
2793    #[cfg(feature = "unstable_boolean_config")]
2794    #[test]
2795    fn test_client_capabilities_boolean_config_options_serialization() {
2796        use serde_json::json;
2797
2798        let capabilities = ClientCapabilities::new().session(
2799            ClientSessionCapabilities::new().config_options(
2800                SessionConfigOptionsCapabilities::new()
2801                    .boolean(BooleanConfigOptionCapabilities::new()),
2802            ),
2803        );
2804        let json = serde_json::to_value(&capabilities).unwrap();
2805
2806        assert_eq!(json["session"]["configOptions"]["boolean"], json!({}));
2807
2808        let omitted: ClientCapabilities = serde_json::from_value(json!({})).unwrap();
2809        assert!(omitted.session.is_none());
2810
2811        let null_session: ClientCapabilities = serde_json::from_value(json!({
2812            "session": null
2813        }))
2814        .unwrap();
2815        assert!(null_session.session.is_none());
2816
2817        let null_config_options: ClientCapabilities = serde_json::from_value(json!({
2818            "session": {
2819                "configOptions": null
2820            }
2821        }))
2822        .unwrap();
2823        assert!(
2824            null_config_options
2825                .session
2826                .and_then(|session| session.config_options)
2827                .is_none()
2828        );
2829
2830        let null_boolean: ClientCapabilities = serde_json::from_value(json!({
2831            "session": {
2832                "configOptions": {
2833                    "boolean": null
2834                }
2835            }
2836        }))
2837        .unwrap();
2838        assert!(
2839            null_boolean
2840                .session
2841                .and_then(|session| session.config_options)
2842                .and_then(|config_options| config_options.boolean)
2843                .is_none()
2844        );
2845    }
2846
2847    #[cfg(feature = "unstable_plan_operations")]
2848    #[test]
2849    fn test_plan_operations_serialization() {
2850        use serde_json::json;
2851
2852        use crate::v1::{PlanEntry, PlanEntryPriority, PlanEntryStatus, PlanUpdateContent};
2853
2854        let plan_update = SessionUpdate::PlanUpdate(PlanUpdate::new(PlanUpdateContent::items(
2855            "plan-1",
2856            vec![PlanEntry::new(
2857                "Step 1",
2858                PlanEntryPriority::High,
2859                PlanEntryStatus::Pending,
2860            )],
2861        )));
2862
2863        assert_eq!(
2864            serde_json::to_value(plan_update).unwrap(),
2865            json!({
2866                "sessionUpdate": "plan_update",
2867                "plan": {
2868                    "type": "items",
2869                    "id": "plan-1",
2870                    "entries": [
2871                        {
2872                            "content": "Step 1",
2873                            "priority": "high",
2874                            "status": "pending"
2875                        }
2876                    ]
2877                }
2878            })
2879        );
2880
2881        assert_eq!(
2882            serde_json::to_value(SessionUpdate::PlanRemoved(PlanRemoved::new("plan-1"))).unwrap(),
2883            json!({
2884                "sessionUpdate": "plan_removed",
2885                "id": "plan-1"
2886            })
2887        );
2888
2889        let capabilities = ClientCapabilities::new().plan(PlanCapabilities::new());
2890        let json = serde_json::to_value(&capabilities).unwrap();
2891        assert_eq!(json["plan"], json!({}));
2892
2893        assert_eq!(
2894            serde_json::from_value::<ClientCapabilities>(json!({ "plan": null }))
2895                .unwrap()
2896                .plan,
2897            None
2898        );
2899    }
2900
2901    #[cfg(feature = "unstable_mcp_over_acp")]
2902    #[test]
2903    fn test_agent_mcp_request_method_names() {
2904        use serde_json::json;
2905
2906        let params: serde_json::Map<String, serde_json::Value> =
2907            [("cursor".to_string(), json!("abc"))].into_iter().collect();
2908
2909        assert_eq!(CLIENT_METHOD_NAMES.mcp_connect, "mcp/connect");
2910        assert_eq!(CLIENT_METHOD_NAMES.mcp_message, "mcp/message");
2911        assert_eq!(CLIENT_METHOD_NAMES.mcp_disconnect, "mcp/disconnect");
2912
2913        assert_eq!(
2914            AgentRequest::ConnectMcpRequest(ConnectMcpRequest::new("server-1")).method(),
2915            "mcp/connect"
2916        );
2917        assert_eq!(
2918            AgentRequest::MessageMcpRequest(MessageMcpRequest::new("conn-1", "tools/list"))
2919                .method(),
2920            "mcp/message"
2921        );
2922        assert_eq!(
2923            AgentRequest::DisconnectMcpRequest(DisconnectMcpRequest::new("conn-1")).method(),
2924            "mcp/disconnect"
2925        );
2926        assert_eq!(
2927            AgentNotification::MessageMcpNotification(MessageMcpNotification::new(
2928                "conn-1",
2929                "notifications/progress"
2930            ))
2931            .method(),
2932            "mcp/message"
2933        );
2934
2935        assert_eq!(
2936            serde_json::to_value(ConnectMcpRequest::new("server-1")).unwrap(),
2937            json!({ "acpId": "server-1" })
2938        );
2939        assert_eq!(
2940            serde_json::to_value(ConnectMcpResponse::new("conn-1")).unwrap(),
2941            json!({ "connectionId": "conn-1" })
2942        );
2943        assert_eq!(
2944            serde_json::to_value(MessageMcpRequest::new("conn-1", "tools/list").params(params))
2945                .unwrap(),
2946            json!({
2947                "connectionId": "conn-1",
2948                "method": "tools/list",
2949                "params": { "cursor": "abc" }
2950            })
2951        );
2952        assert_eq!(
2953            serde_json::to_value(DisconnectMcpRequest::new("conn-1")).unwrap(),
2954            json!({ "connectionId": "conn-1" })
2955        );
2956        assert_eq!(
2957            serde_json::to_value(MessageMcpNotification::new(
2958                "conn-1",
2959                "notifications/progress"
2960            ))
2961            .unwrap(),
2962            json!({
2963                "connectionId": "conn-1",
2964                "method": "notifications/progress"
2965            })
2966        );
2967
2968        let request_with_null_params: MessageMcpRequest = serde_json::from_value(json!({
2969            "connectionId": "conn-1",
2970            "method": "tools/list",
2971            "params": null
2972        }))
2973        .unwrap();
2974        assert_eq!(request_with_null_params.params, None);
2975    }
2976}