Skip to main content

agent_client_protocol_schema/v1/
client.rs

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