Skip to main content

agent_client_protocol_schema/v2/
agent.rs

1//! Methods and notifications the agent handles/receives.
2//!
3//! This module defines the Agent trait and all associated types for implementing
4//! an AI coding agent that follows the Agent Client Protocol (ACP).
5
6use std::{collections::BTreeMap, path::PathBuf, sync::Arc};
7
8#[cfg(any(feature = "unstable_auth_methods", feature = "unstable_llm_providers"))]
9use std::collections::HashMap;
10
11use derive_more::{Display, From};
12use schemars::{JsonSchema, Schema};
13use serde::{Deserialize, Serialize};
14use serde_with::{DefaultOnError, VecSkipError, serde_as, skip_serializing_none};
15
16use super::{
17    ClientCapabilities, ContentBlock, ExtNotification, ExtRequest, ExtResponse, Meta, SessionId,
18};
19use crate::{IntoOption, ProtocolVersion, SkipListener};
20
21#[cfg(feature = "unstable_mcp_over_acp")]
22use super::mcp::{
23    MCP_MESSAGE_METHOD_NAME, MessageMcpNotification, MessageMcpRequest, MessageMcpResponse,
24};
25
26#[cfg(feature = "unstable_nes")]
27use super::{
28    AcceptNesNotification, CloseNesRequest, CloseNesResponse, DidChangeDocumentNotification,
29    DidCloseDocumentNotification, DidFocusDocumentNotification, DidOpenDocumentNotification,
30    DidSaveDocumentNotification, NesCapabilities, PositionEncodingKind, RejectNesNotification,
31    StartNesRequest, StartNesResponse, SuggestNesRequest, SuggestNesResponse,
32};
33
34#[cfg(feature = "unstable_nes")]
35use super::{
36    DOCUMENT_DID_CHANGE_METHOD_NAME, DOCUMENT_DID_CLOSE_METHOD_NAME,
37    DOCUMENT_DID_FOCUS_METHOD_NAME, DOCUMENT_DID_OPEN_METHOD_NAME, DOCUMENT_DID_SAVE_METHOD_NAME,
38    NES_ACCEPT_METHOD_NAME, NES_CLOSE_METHOD_NAME, NES_REJECT_METHOD_NAME, NES_START_METHOD_NAME,
39    NES_SUGGEST_METHOD_NAME,
40};
41
42// Initialize
43
44/// Request parameters for the initialize method.
45///
46/// Sent by the client to establish connection and negotiate capabilities.
47///
48/// See protocol docs: [Initialization](https://agentclientprotocol.com/protocol/initialization)
49#[serde_as]
50#[skip_serializing_none]
51#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
52#[schemars(extend("x-side" = "agent", "x-method" = INITIALIZE_METHOD_NAME))]
53#[serde(rename_all = "camelCase")]
54#[non_exhaustive]
55pub struct InitializeRequest {
56    /// The latest protocol version supported by the client.
57    pub protocol_version: ProtocolVersion,
58    /// Capabilities supported by the client.
59    #[serde(default)]
60    pub capabilities: ClientCapabilities,
61    /// Information about the Client name and version sent to the Agent.
62    ///
63    /// Note: in future versions of the protocol, this will be required.
64    #[serde_as(deserialize_as = "DefaultOnError")]
65    #[schemars(extend("x-deserialize-default-on-error" = true))]
66    #[serde(default)]
67    pub client_info: Option<Implementation>,
68    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
69    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
70    /// these keys.
71    ///
72    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
73    #[serde(rename = "_meta")]
74    pub meta: Option<Meta>,
75}
76
77impl InitializeRequest {
78    /// Builds [`InitializeRequest`] with the required request fields set; optional fields start unset or empty.
79    #[must_use]
80    pub fn new(protocol_version: ProtocolVersion) -> Self {
81        Self {
82            protocol_version,
83            capabilities: ClientCapabilities::default(),
84            client_info: None,
85            meta: None,
86        }
87    }
88
89    /// Capabilities supported by the client.
90    #[must_use]
91    pub fn capabilities(mut self, capabilities: ClientCapabilities) -> Self {
92        self.capabilities = capabilities;
93        self
94    }
95
96    /// Information about the Client name and version sent to the Agent.
97    #[must_use]
98    pub fn client_info(mut self, client_info: impl IntoOption<Implementation>) -> Self {
99        self.client_info = client_info.into_option();
100        self
101    }
102
103    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
104    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
105    /// these keys.
106    ///
107    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
108    #[must_use]
109    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
110        self.meta = meta.into_option();
111        self
112    }
113}
114
115/// Response to the `initialize` method.
116///
117/// Contains the negotiated protocol version and agent capabilities.
118///
119/// See protocol docs: [Initialization](https://agentclientprotocol.com/protocol/initialization)
120#[serde_as]
121#[skip_serializing_none]
122#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
123#[schemars(extend("x-side" = "agent", "x-method" = INITIALIZE_METHOD_NAME))]
124#[serde(rename_all = "camelCase")]
125#[non_exhaustive]
126pub struct InitializeResponse {
127    /// The protocol version the client specified if supported by the agent,
128    /// or the latest protocol version supported by the agent.
129    ///
130    /// The client should disconnect, if it doesn't support this version.
131    pub protocol_version: ProtocolVersion,
132    /// Capabilities supported by the agent.
133    #[serde(default)]
134    pub capabilities: AgentCapabilities,
135    /// Authentication methods supported by the agent.
136    #[serde_as(deserialize_as = "DefaultOnError<VecSkipError<_, SkipListener>>")]
137    #[schemars(extend("x-deserialize-default-on-error" = true, "x-deserialize-skip-invalid-items" = true))]
138    #[serde(default)]
139    pub auth_methods: Vec<AuthMethod>,
140    /// Information about the Agent name and version sent to the Client.
141    ///
142    /// Note: in future versions of the protocol, this will be required.
143    #[serde_as(deserialize_as = "DefaultOnError")]
144    #[schemars(extend("x-deserialize-default-on-error" = true))]
145    #[serde(default)]
146    pub agent_info: Option<Implementation>,
147    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
148    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
149    /// these keys.
150    ///
151    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
152    #[serde(rename = "_meta")]
153    pub meta: Option<Meta>,
154}
155
156impl InitializeResponse {
157    /// Builds [`InitializeResponse`] with the required response fields set; optional fields start unset or empty.
158    #[must_use]
159    pub fn new(protocol_version: ProtocolVersion) -> Self {
160        Self {
161            protocol_version,
162            capabilities: AgentCapabilities::default(),
163            auth_methods: vec![],
164            agent_info: None,
165            meta: None,
166        }
167    }
168
169    /// Capabilities supported by the agent.
170    #[must_use]
171    pub fn capabilities(mut self, capabilities: AgentCapabilities) -> Self {
172        self.capabilities = capabilities;
173        self
174    }
175
176    /// Authentication methods supported by the agent.
177    #[must_use]
178    pub fn auth_methods(mut self, auth_methods: Vec<AuthMethod>) -> Self {
179        self.auth_methods = auth_methods;
180        self
181    }
182
183    /// Information about the Agent name and version sent to the Client.
184    #[must_use]
185    pub fn agent_info(mut self, agent_info: impl IntoOption<Implementation>) -> Self {
186        self.agent_info = agent_info.into_option();
187        self
188    }
189
190    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
191    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
192    /// these keys.
193    ///
194    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
195    #[must_use]
196    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
197        self.meta = meta.into_option();
198        self
199    }
200}
201
202/// Metadata about the implementation of the client or agent.
203/// Describes the name and version of an MCP implementation, with an optional
204/// title for UI representation.
205#[skip_serializing_none]
206#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
207#[serde(rename_all = "camelCase")]
208#[non_exhaustive]
209pub struct Implementation {
210    /// Intended for programmatic or logical use, but can be used as a display
211    /// name fallback if title isn’t present.
212    pub name: String,
213    /// Intended for UI and end-user contexts — optimized to be human-readable
214    /// and easily understood.
215    ///
216    /// If not provided, the name should be used for display.
217    pub title: Option<String>,
218    /// Version of the implementation. Can be displayed to the user or used
219    /// for debugging or metrics purposes. (e.g. "1.0.0").
220    pub version: String,
221    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
222    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
223    /// these keys.
224    ///
225    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
226    #[serde(rename = "_meta")]
227    pub meta: Option<Meta>,
228}
229
230impl Implementation {
231    /// Builds [`Implementation`] with the required fields set; optional fields start unset or empty.
232    #[must_use]
233    pub fn new(name: impl Into<String>, version: impl Into<String>) -> Self {
234        Self {
235            name: name.into(),
236            title: None,
237            version: version.into(),
238            meta: None,
239        }
240    }
241
242    /// Intended for UI and end-user contexts — optimized to be human-readable
243    /// and easily understood.
244    ///
245    /// If not provided, the name should be used for display.
246    #[must_use]
247    pub fn title(mut self, title: impl IntoOption<String>) -> Self {
248        self.title = title.into_option();
249        self
250    }
251
252    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
253    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
254    /// these keys.
255    ///
256    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
257    #[must_use]
258    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
259        self.meta = meta.into_option();
260        self
261    }
262}
263
264// Authentication
265
266/// Request parameters for the authenticate method.
267///
268/// Specifies which authentication method to use.
269#[skip_serializing_none]
270#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
271#[schemars(extend("x-side" = "agent", "x-method" = AUTHENTICATE_METHOD_NAME))]
272#[serde(rename_all = "camelCase")]
273#[non_exhaustive]
274pub struct AuthenticateRequest {
275    /// The ID of the authentication method to use.
276    /// Must be one of the methods advertised in the initialize response.
277    pub method_id: AuthMethodId,
278    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
279    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
280    /// these keys.
281    ///
282    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
283    #[serde(rename = "_meta")]
284    pub meta: Option<Meta>,
285}
286
287impl AuthenticateRequest {
288    /// Builds [`AuthenticateRequest`] with the required request fields set; optional fields start unset or empty.
289    #[must_use]
290    pub fn new(method_id: impl Into<AuthMethodId>) -> Self {
291        Self {
292            method_id: method_id.into(),
293            meta: None,
294        }
295    }
296
297    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
298    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
299    /// these keys.
300    ///
301    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
302    #[must_use]
303    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
304        self.meta = meta.into_option();
305        self
306    }
307}
308
309/// Response to the `authenticate` method.
310#[skip_serializing_none]
311#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
312#[schemars(extend("x-side" = "agent", "x-method" = AUTHENTICATE_METHOD_NAME))]
313#[serde(rename_all = "camelCase")]
314#[non_exhaustive]
315pub struct AuthenticateResponse {
316    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
317    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
318    /// these keys.
319    ///
320    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
321    #[serde(rename = "_meta")]
322    pub meta: Option<Meta>,
323}
324
325impl AuthenticateResponse {
326    /// Builds [`AuthenticateResponse`] with the required response fields set; optional fields start unset or empty.
327    #[must_use]
328    pub fn new() -> Self {
329        Self::default()
330    }
331
332    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
333    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
334    /// these keys.
335    ///
336    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
337    #[must_use]
338    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
339        self.meta = meta.into_option();
340        self
341    }
342}
343
344// Logout
345
346/// Request parameters for the logout method.
347///
348/// Terminates the current authenticated session.
349#[skip_serializing_none]
350#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
351#[schemars(extend("x-side" = "agent", "x-method" = LOGOUT_METHOD_NAME))]
352#[serde(rename_all = "camelCase")]
353#[non_exhaustive]
354pub struct LogoutRequest {
355    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
356    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
357    /// these keys.
358    ///
359    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
360    #[serde(rename = "_meta")]
361    pub meta: Option<Meta>,
362}
363
364impl LogoutRequest {
365    /// Builds [`LogoutRequest`] with the required request fields set; optional fields start unset or empty.
366    #[must_use]
367    pub fn new() -> Self {
368        Self::default()
369    }
370
371    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
372    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
373    /// these keys.
374    ///
375    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
376    #[must_use]
377    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
378        self.meta = meta.into_option();
379        self
380    }
381}
382
383/// Response to the `logout` method.
384#[skip_serializing_none]
385#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
386#[schemars(extend("x-side" = "agent", "x-method" = LOGOUT_METHOD_NAME))]
387#[serde(rename_all = "camelCase")]
388#[non_exhaustive]
389pub struct LogoutResponse {
390    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
391    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
392    /// these keys.
393    ///
394    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
395    #[serde(rename = "_meta")]
396    pub meta: Option<Meta>,
397}
398
399impl LogoutResponse {
400    /// Builds [`LogoutResponse`] with the required response fields set; optional fields start unset or empty.
401    #[must_use]
402    pub fn new() -> Self {
403        Self::default()
404    }
405
406    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
407    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
408    /// these keys.
409    ///
410    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
411    #[must_use]
412    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
413        self.meta = meta.into_option();
414        self
415    }
416}
417
418/// Authentication-related capabilities supported by the agent.
419#[serde_as]
420#[skip_serializing_none]
421#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
422#[serde(rename_all = "camelCase")]
423#[non_exhaustive]
424pub struct AgentAuthCapabilities {
425    /// Whether the agent supports the logout method.
426    ///
427    /// By supplying `{}` it means that the agent supports the logout method.
428    #[serde_as(deserialize_as = "DefaultOnError")]
429    #[schemars(extend("x-deserialize-default-on-error" = true))]
430    #[serde(default)]
431    pub logout: Option<LogoutCapabilities>,
432    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
433    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
434    /// these keys.
435    ///
436    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
437    #[serde(rename = "_meta")]
438    pub meta: Option<Meta>,
439}
440
441impl AgentAuthCapabilities {
442    /// Builds an empty [`AgentAuthCapabilities`]; use builder methods to advertise supported sub-capabilities.
443    #[must_use]
444    pub fn new() -> Self {
445        Self::default()
446    }
447
448    /// Whether the agent supports the logout method.
449    #[must_use]
450    pub fn logout(mut self, logout: impl IntoOption<LogoutCapabilities>) -> Self {
451        self.logout = logout.into_option();
452        self
453    }
454
455    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
456    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
457    /// these keys.
458    ///
459    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
460    #[must_use]
461    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
462        self.meta = meta.into_option();
463        self
464    }
465}
466
467/// Logout capabilities supported by the agent.
468///
469/// By supplying `{}` it means that the agent supports the logout method.
470#[skip_serializing_none]
471#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
472#[non_exhaustive]
473pub struct LogoutCapabilities {
474    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
475    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
476    /// these keys.
477    ///
478    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
479    #[serde(rename = "_meta")]
480    pub meta: Option<Meta>,
481}
482
483impl LogoutCapabilities {
484    /// Builds an empty [`LogoutCapabilities`]; use builder methods to advertise supported sub-capabilities.
485    #[must_use]
486    pub fn new() -> Self {
487        Self::default()
488    }
489
490    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
491    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
492    /// these keys.
493    ///
494    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
495    #[must_use]
496    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
497        self.meta = meta.into_option();
498        self
499    }
500}
501
502/// Typed identifier used for auth method values on the wire.
503#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq, Hash, Display, From)]
504#[serde(transparent)]
505#[from(Arc<str>, String, &'static str)]
506#[non_exhaustive]
507pub struct AuthMethodId(pub Arc<str>);
508
509impl AuthMethodId {
510    /// Wraps a protocol string as a typed [`AuthMethodId`].
511    #[must_use]
512    pub fn new(id: impl Into<Arc<str>>) -> Self {
513        Self(id.into())
514    }
515}
516
517/// Describes an available authentication method.
518///
519/// The `type` field acts as the discriminator in the serialized JSON form.
520#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
521#[serde(tag = "type", rename_all = "snake_case")]
522#[non_exhaustive]
523pub enum AuthMethod {
524    /// **UNSTABLE**
525    ///
526    /// This capability is not part of the spec yet, and may be removed or changed at any point.
527    ///
528    /// User provides a key that the client passes to the agent as an environment variable.
529    #[cfg(feature = "unstable_auth_methods")]
530    EnvVar(AuthMethodEnvVar),
531    /// **UNSTABLE**
532    ///
533    /// This capability is not part of the spec yet, and may be removed or changed at any point.
534    ///
535    /// Client runs an interactive terminal for the user to authenticate via a TUI.
536    #[cfg(feature = "unstable_auth_methods")]
537    Terminal(AuthMethodTerminal),
538    /// Agent handles authentication itself.
539    ///
540    /// The `type` discriminator value is `agent`.
541    Agent(AuthMethodAgent),
542    /// Custom or future authentication method.
543    ///
544    /// Values beginning with `_` are reserved for implementation-specific
545    /// extensions. Unknown values that do not begin with `_` are reserved for
546    /// future ACP variants.
547    ///
548    /// Clients that do not understand this method type should preserve the raw
549    /// payload when storing, replaying, proxying, or forwarding initialization
550    /// data, and otherwise ignore the method or display it generically.
551    #[serde(untagged)]
552    Other(OtherAuthMethod),
553}
554
555impl AuthMethod {
556    /// The unique identifier for this authentication method.
557    #[must_use]
558    pub fn id(&self) -> &AuthMethodId {
559        match self {
560            Self::Agent(a) => &a.id,
561            Self::Other(a) => &a.id,
562            #[cfg(feature = "unstable_auth_methods")]
563            Self::EnvVar(e) => &e.id,
564            #[cfg(feature = "unstable_auth_methods")]
565            Self::Terminal(t) => &t.id,
566        }
567    }
568
569    /// The human-readable name of this authentication method.
570    #[must_use]
571    pub fn name(&self) -> &str {
572        match self {
573            Self::Agent(a) => &a.name,
574            Self::Other(a) => &a.name,
575            #[cfg(feature = "unstable_auth_methods")]
576            Self::EnvVar(e) => &e.name,
577            #[cfg(feature = "unstable_auth_methods")]
578            Self::Terminal(t) => &t.name,
579        }
580    }
581
582    /// Optional description providing more details about this authentication method.
583    #[must_use]
584    pub fn description(&self) -> Option<&str> {
585        match self {
586            Self::Agent(a) => a.description.as_deref(),
587            Self::Other(a) => a.description.as_deref(),
588            #[cfg(feature = "unstable_auth_methods")]
589            Self::EnvVar(e) => e.description.as_deref(),
590            #[cfg(feature = "unstable_auth_methods")]
591            Self::Terminal(t) => t.description.as_deref(),
592        }
593    }
594
595    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
596    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
597    /// these keys.
598    ///
599    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
600    #[must_use]
601    pub fn meta(&self) -> Option<&Meta> {
602        match self {
603            Self::Agent(a) => a.meta.as_ref(),
604            Self::Other(a) => a.meta.as_ref(),
605            #[cfg(feature = "unstable_auth_methods")]
606            Self::EnvVar(e) => e.meta.as_ref(),
607            #[cfg(feature = "unstable_auth_methods")]
608            Self::Terminal(t) => t.meta.as_ref(),
609        }
610    }
611}
612
613/// Custom or future authentication method payload.
614#[skip_serializing_none]
615#[derive(Debug, Clone, Serialize, JsonSchema, PartialEq, Eq)]
616#[schemars(inline)]
617#[schemars(transform = other_auth_method_schema)]
618#[serde(rename_all = "camelCase")]
619#[non_exhaustive]
620pub struct OtherAuthMethod {
621    /// Custom or future authentication method type.
622    ///
623    /// Values beginning with `_` are reserved for implementation-specific
624    /// extensions. Unknown values that do not begin with `_` are reserved for
625    /// future ACP variants.
626    #[serde(rename = "type")]
627    pub type_: String,
628    /// Unique identifier for this authentication method.
629    pub id: AuthMethodId,
630    /// Human-readable name of the authentication method.
631    pub name: String,
632    /// Optional description providing more details about this authentication method.
633    pub description: Option<String>,
634    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
635    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
636    /// these keys.
637    ///
638    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
639    #[serde(rename = "_meta")]
640    pub meta: Option<Meta>,
641    /// Additional fields from the unknown authentication method payload.
642    #[serde(flatten)]
643    pub fields: BTreeMap<String, serde_json::Value>,
644}
645
646impl OtherAuthMethod {
647    /// Builds [`OtherAuthMethod`] from an unknown discriminator and preserves the remaining extension fields.
648    #[must_use]
649    pub fn new(
650        type_: impl Into<String>,
651        id: impl Into<AuthMethodId>,
652        name: impl Into<String>,
653        mut fields: BTreeMap<String, serde_json::Value>,
654    ) -> Self {
655        fields.remove("type");
656        fields.remove("id");
657        fields.remove("name");
658        fields.remove("description");
659        fields.remove("_meta");
660        Self {
661            type_: type_.into(),
662            id: id.into(),
663            name: name.into(),
664            description: None,
665            meta: None,
666            fields,
667        }
668    }
669
670    /// Optional description providing more details about this authentication method.
671    #[must_use]
672    pub fn description(mut self, description: impl IntoOption<String>) -> Self {
673        self.description = description.into_option();
674        self
675    }
676
677    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
678    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
679    /// these keys.
680    ///
681    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
682    #[must_use]
683    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
684        self.meta = meta.into_option();
685        self
686    }
687}
688
689impl<'de> Deserialize<'de> for OtherAuthMethod {
690    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
691    where
692        D: serde::Deserializer<'de>,
693    {
694        #[derive(Deserialize)]
695        #[serde(rename_all = "camelCase")]
696        struct RawOtherAuthMethod {
697            #[serde(rename = "type")]
698            type_: String,
699            id: AuthMethodId,
700            name: String,
701            description: Option<String>,
702            #[serde(rename = "_meta")]
703            meta: Option<Meta>,
704            #[serde(flatten)]
705            fields: BTreeMap<String, serde_json::Value>,
706        }
707
708        let raw = RawOtherAuthMethod::deserialize(deserializer)?;
709        if is_known_auth_method_type(&raw.type_) {
710            return Err(serde::de::Error::custom(format!(
711                "known authentication method `{}` did not match its schema",
712                raw.type_
713            )));
714        }
715
716        Ok(Self {
717            type_: raw.type_,
718            id: raw.id,
719            name: raw.name,
720            description: raw.description,
721            meta: raw.meta,
722            fields: raw.fields,
723        })
724    }
725}
726
727fn is_known_auth_method_type(type_: &str) -> bool {
728    match type_ {
729        "agent" => true,
730        #[cfg(feature = "unstable_auth_methods")]
731        "env_var" | "terminal" => true,
732        _ => false,
733    }
734}
735
736fn other_auth_method_schema(schema: &mut Schema) {
737    super::schema_util::reject_known_string_discriminators(
738        schema,
739        "type",
740        &[
741            "agent",
742            #[cfg(feature = "unstable_auth_methods")]
743            "env_var",
744            #[cfg(feature = "unstable_auth_methods")]
745            "terminal",
746        ],
747    );
748}
749
750/// Agent handles authentication itself.
751///
752/// The `type` discriminator value is `agent`.
753#[skip_serializing_none]
754#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
755#[serde(rename_all = "camelCase")]
756#[non_exhaustive]
757pub struct AuthMethodAgent {
758    /// Unique identifier for this authentication method.
759    pub id: AuthMethodId,
760    /// Human-readable name of the authentication method.
761    pub name: String,
762    /// Optional description providing more details about this authentication method.
763    pub description: Option<String>,
764    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
765    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
766    /// these keys.
767    ///
768    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
769    #[serde(rename = "_meta")]
770    pub meta: Option<Meta>,
771}
772
773impl AuthMethodAgent {
774    /// Builds [`AuthMethodAgent`] with the required fields set; optional fields start unset or empty.
775    #[must_use]
776    pub fn new(id: impl Into<AuthMethodId>, name: impl Into<String>) -> Self {
777        Self {
778            id: id.into(),
779            name: name.into(),
780            description: None,
781            meta: None,
782        }
783    }
784
785    /// Optional description providing more details about this authentication method.
786    #[must_use]
787    pub fn description(mut self, description: impl IntoOption<String>) -> Self {
788        self.description = description.into_option();
789        self
790    }
791
792    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
793    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
794    /// these keys.
795    ///
796    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
797    #[must_use]
798    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
799        self.meta = meta.into_option();
800        self
801    }
802}
803
804/// **UNSTABLE**
805///
806/// This capability is not part of the spec yet, and may be removed or changed at any point.
807///
808/// Environment variable authentication method.
809///
810/// The user provides credentials that the client passes to the agent as environment variables.
811#[cfg(feature = "unstable_auth_methods")]
812#[skip_serializing_none]
813#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
814#[serde(rename_all = "camelCase")]
815#[non_exhaustive]
816pub struct AuthMethodEnvVar {
817    /// Unique identifier for this authentication method.
818    pub id: AuthMethodId,
819    /// Human-readable name of the authentication method.
820    pub name: String,
821    /// Optional description providing more details about this authentication method.
822    pub description: Option<String>,
823    /// The environment variables the client should set.
824    pub vars: Vec<AuthEnvVar>,
825    /// Optional link to a page where the user can obtain their credentials.
826    pub link: Option<String>,
827    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
828    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
829    /// these keys.
830    ///
831    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
832    #[serde(rename = "_meta")]
833    pub meta: Option<Meta>,
834}
835
836#[cfg(feature = "unstable_auth_methods")]
837impl AuthMethodEnvVar {
838    /// Builds [`AuthMethodEnvVar`] with the required fields set; optional fields start unset or empty.
839    #[must_use]
840    pub fn new(
841        id: impl Into<AuthMethodId>,
842        name: impl Into<String>,
843        vars: Vec<AuthEnvVar>,
844    ) -> Self {
845        Self {
846            id: id.into(),
847            name: name.into(),
848            description: None,
849            vars,
850            link: None,
851            meta: None,
852        }
853    }
854
855    /// Optional link to a page where the user can obtain their credentials.
856    #[must_use]
857    pub fn link(mut self, link: impl IntoOption<String>) -> Self {
858        self.link = link.into_option();
859        self
860    }
861
862    /// Optional description providing more details about this authentication method.
863    #[must_use]
864    pub fn description(mut self, description: impl IntoOption<String>) -> Self {
865        self.description = description.into_option();
866        self
867    }
868
869    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
870    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
871    /// these keys.
872    ///
873    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
874    #[must_use]
875    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
876        self.meta = meta.into_option();
877        self
878    }
879}
880
881/// **UNSTABLE**
882///
883/// This capability is not part of the spec yet, and may be removed or changed at any point.
884///
885/// Describes a single environment variable for an [`AuthMethodEnvVar`] authentication method.
886#[cfg(feature = "unstable_auth_methods")]
887#[skip_serializing_none]
888#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
889#[serde(rename_all = "camelCase")]
890#[non_exhaustive]
891pub struct AuthEnvVar {
892    /// The environment variable name (e.g. `"OPENAI_API_KEY"`).
893    pub name: String,
894    /// Human-readable label for this variable, displayed in client UI.
895    pub label: Option<String>,
896    /// Whether this value is a secret (e.g. API key, token).
897    /// Clients should use a password-style input for secret vars.
898    ///
899    /// Defaults to `true`.
900    #[serde(default = "default_true", skip_serializing_if = "is_true")]
901    #[schemars(extend("default" = true))]
902    pub secret: bool,
903    /// Whether this variable is optional.
904    ///
905    /// Defaults to `false`.
906    #[serde(default, skip_serializing_if = "is_false")]
907    #[schemars(extend("default" = false))]
908    pub optional: bool,
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    #[serde(rename = "_meta")]
915    pub meta: Option<Meta>,
916}
917
918#[cfg(feature = "unstable_auth_methods")]
919fn default_true() -> bool {
920    true
921}
922
923#[cfg(feature = "unstable_auth_methods")]
924#[expect(clippy::trivially_copy_pass_by_ref)]
925fn is_true(v: &bool) -> bool {
926    *v
927}
928
929#[cfg(feature = "unstable_auth_methods")]
930#[expect(clippy::trivially_copy_pass_by_ref)]
931fn is_false(v: &bool) -> bool {
932    !*v
933}
934
935#[cfg(feature = "unstable_auth_methods")]
936impl AuthEnvVar {
937    /// Creates an auth environment variable prompt with `secret` enabled and `optional` disabled.
938    #[must_use]
939    pub fn new(name: impl Into<String>) -> Self {
940        Self {
941            name: name.into(),
942            label: None,
943            secret: true,
944            optional: false,
945            meta: None,
946        }
947    }
948
949    /// Human-readable label for this variable, displayed in client UI.
950    #[must_use]
951    pub fn label(mut self, label: impl IntoOption<String>) -> Self {
952        self.label = label.into_option();
953        self
954    }
955
956    /// Whether this value is a secret (e.g. API key, token).
957    /// Clients should use a password-style input for secret vars.
958    #[must_use]
959    pub fn secret(mut self, secret: bool) -> Self {
960        self.secret = secret;
961        self
962    }
963
964    /// Whether this variable is optional.
965    #[must_use]
966    pub fn optional(mut self, optional: bool) -> Self {
967        self.optional = optional;
968        self
969    }
970
971    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
972    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
973    /// these keys.
974    ///
975    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
976    #[must_use]
977    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
978        self.meta = meta.into_option();
979        self
980    }
981}
982
983/// **UNSTABLE**
984///
985/// This capability is not part of the spec yet, and may be removed or changed at any point.
986///
987/// Terminal-based authentication method.
988///
989/// The client runs an interactive terminal for the user to authenticate via a TUI.
990#[cfg(feature = "unstable_auth_methods")]
991#[skip_serializing_none]
992#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
993#[serde(rename_all = "camelCase")]
994#[non_exhaustive]
995pub struct AuthMethodTerminal {
996    /// Unique identifier for this authentication method.
997    pub id: AuthMethodId,
998    /// Human-readable name of the authentication method.
999    pub name: String,
1000    /// Optional description providing more details about this authentication method.
1001    pub description: Option<String>,
1002    /// Additional arguments to pass when running the agent binary for terminal auth.
1003    #[serde(default, skip_serializing_if = "Vec::is_empty")]
1004    pub args: Vec<String>,
1005    /// Additional environment variables to set when running the agent binary for terminal auth.
1006    #[serde(default, skip_serializing_if = "HashMap::is_empty")]
1007    pub env: HashMap<String, String>,
1008    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1009    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1010    /// these keys.
1011    ///
1012    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1013    #[serde(rename = "_meta")]
1014    pub meta: Option<Meta>,
1015}
1016
1017#[cfg(feature = "unstable_auth_methods")]
1018impl AuthMethodTerminal {
1019    /// Builds [`AuthMethodTerminal`] with the required fields set; optional fields start unset or empty.
1020    #[must_use]
1021    pub fn new(id: impl Into<AuthMethodId>, name: impl Into<String>) -> Self {
1022        Self {
1023            id: id.into(),
1024            name: name.into(),
1025            description: None,
1026            args: Vec::new(),
1027            env: HashMap::new(),
1028            meta: None,
1029        }
1030    }
1031
1032    /// Additional arguments to pass when running the agent binary for terminal auth.
1033    #[must_use]
1034    pub fn args(mut self, args: Vec<String>) -> Self {
1035        self.args = args;
1036        self
1037    }
1038
1039    /// Additional environment variables to set when running the agent binary for terminal auth.
1040    #[must_use]
1041    pub fn env(mut self, env: HashMap<String, String>) -> Self {
1042        self.env = env;
1043        self
1044    }
1045
1046    /// Optional description providing more details about this authentication method.
1047    #[must_use]
1048    pub fn description(mut self, description: impl IntoOption<String>) -> Self {
1049        self.description = description.into_option();
1050        self
1051    }
1052
1053    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1054    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1055    /// these keys.
1056    ///
1057    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1058    #[must_use]
1059    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1060        self.meta = meta.into_option();
1061        self
1062    }
1063}
1064
1065// New session
1066
1067/// Request parameters for creating a new session.
1068///
1069/// See protocol docs: [Creating a Session](https://agentclientprotocol.com/protocol/session-setup#creating-a-session)
1070#[skip_serializing_none]
1071#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1072#[schemars(extend("x-side" = "agent", "x-method" = SESSION_NEW_METHOD_NAME))]
1073#[serde(rename_all = "camelCase")]
1074#[non_exhaustive]
1075pub struct NewSessionRequest {
1076    /// The working directory for this session. Must be an absolute path.
1077    pub cwd: PathBuf,
1078    /// Additional workspace roots for this session. Each path must be absolute.
1079    ///
1080    /// These expand the session's workspace scope without changing `cwd`, which
1081    /// remains the base for relative paths. When omitted or empty, no
1082    /// additional roots are activated for the new session.
1083    #[serde(default, skip_serializing_if = "Vec::is_empty")]
1084    pub additional_directories: Vec<PathBuf>,
1085    /// List of MCP (Model Context Protocol) servers the agent should connect to.
1086    pub mcp_servers: Vec<McpServer>,
1087    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1088    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1089    /// these keys.
1090    ///
1091    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1092    #[serde(rename = "_meta")]
1093    pub meta: Option<Meta>,
1094}
1095
1096impl NewSessionRequest {
1097    /// Builds [`NewSessionRequest`] with the required request fields set; optional fields start unset or empty.
1098    #[must_use]
1099    pub fn new(cwd: impl Into<PathBuf>) -> Self {
1100        Self {
1101            cwd: cwd.into(),
1102            additional_directories: vec![],
1103            mcp_servers: vec![],
1104            meta: None,
1105        }
1106    }
1107
1108    /// Additional workspace roots for this session. Each path must be absolute.
1109    #[must_use]
1110    pub fn additional_directories(mut self, additional_directories: Vec<PathBuf>) -> Self {
1111        self.additional_directories = additional_directories;
1112        self
1113    }
1114
1115    /// List of MCP (Model Context Protocol) servers the agent should connect to.
1116    #[must_use]
1117    pub fn mcp_servers(mut self, mcp_servers: Vec<McpServer>) -> Self {
1118        self.mcp_servers = mcp_servers;
1119        self
1120    }
1121
1122    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1123    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1124    /// these keys.
1125    ///
1126    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1127    #[must_use]
1128    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1129        self.meta = meta.into_option();
1130        self
1131    }
1132}
1133
1134/// Response from creating a new session.
1135///
1136/// See protocol docs: [Creating a Session](https://agentclientprotocol.com/protocol/session-setup#creating-a-session)
1137#[serde_as]
1138#[skip_serializing_none]
1139#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1140#[schemars(extend("x-side" = "agent", "x-method" = SESSION_NEW_METHOD_NAME))]
1141#[serde(rename_all = "camelCase")]
1142#[non_exhaustive]
1143pub struct NewSessionResponse {
1144    /// Unique identifier for the created session.
1145    ///
1146    /// Used in all subsequent requests for this conversation.
1147    pub session_id: SessionId,
1148    /// Initial session configuration options if supported by the Agent.
1149    #[serde_as(deserialize_as = "DefaultOnError<Option<VecSkipError<_, SkipListener>>>")]
1150    #[schemars(extend("x-deserialize-default-on-error" = true, "x-deserialize-skip-invalid-items" = true))]
1151    #[serde(default)]
1152    pub config_options: Option<Vec<SessionConfigOption>>,
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 NewSessionResponse {
1163    /// Builds [`NewSessionResponse`] with the required response fields set; optional fields start unset or empty.
1164    #[must_use]
1165    pub fn new(session_id: impl Into<SessionId>) -> Self {
1166        Self {
1167            session_id: session_id.into(),
1168            config_options: None,
1169            meta: None,
1170        }
1171    }
1172
1173    /// Initial session configuration options if supported by the Agent.
1174    #[must_use]
1175    pub fn config_options(
1176        mut self,
1177        config_options: impl IntoOption<Vec<SessionConfigOption>>,
1178    ) -> Self {
1179        self.config_options = config_options.into_option();
1180        self
1181    }
1182
1183    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1184    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1185    /// these keys.
1186    ///
1187    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1188    #[must_use]
1189    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1190        self.meta = meta.into_option();
1191        self
1192    }
1193}
1194
1195// Load session
1196
1197/// Request parameters for loading an existing session.
1198///
1199/// Only available if the Agent supports the `session.load` capability.
1200///
1201/// See protocol docs: [Loading Sessions](https://agentclientprotocol.com/protocol/session-setup#loading-sessions)
1202#[skip_serializing_none]
1203#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1204#[schemars(extend("x-side" = "agent", "x-method" = SESSION_LOAD_METHOD_NAME))]
1205#[serde(rename_all = "camelCase")]
1206#[non_exhaustive]
1207pub struct LoadSessionRequest {
1208    /// List of MCP servers to connect to for this session.
1209    pub mcp_servers: Vec<McpServer>,
1210    /// The working directory for this session.
1211    pub cwd: PathBuf,
1212    /// Additional workspace roots to activate for this session. Each path must be absolute.
1213    ///
1214    /// When omitted or empty, no additional roots are activated. When non-empty,
1215    /// this is the complete resulting additional-root list for the loaded
1216    /// session. It may differ from any previously used or reported list as long as
1217    /// the request `cwd` matches the session's `cwd`.
1218    #[serde(default, skip_serializing_if = "Vec::is_empty")]
1219    pub additional_directories: Vec<PathBuf>,
1220    /// The ID of the session to load.
1221    pub session_id: SessionId,
1222    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1223    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1224    /// these keys.
1225    ///
1226    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1227    #[serde(rename = "_meta")]
1228    pub meta: Option<Meta>,
1229}
1230
1231impl LoadSessionRequest {
1232    /// Builds [`LoadSessionRequest`] with the required request fields set; optional fields start unset or empty.
1233    #[must_use]
1234    pub fn new(session_id: impl Into<SessionId>, cwd: impl Into<PathBuf>) -> Self {
1235        Self {
1236            mcp_servers: vec![],
1237            cwd: cwd.into(),
1238            additional_directories: vec![],
1239            session_id: session_id.into(),
1240            meta: None,
1241        }
1242    }
1243
1244    /// Additional workspace roots to activate for this session. Each path must be absolute.
1245    #[must_use]
1246    pub fn additional_directories(mut self, additional_directories: Vec<PathBuf>) -> Self {
1247        self.additional_directories = additional_directories;
1248        self
1249    }
1250
1251    /// List of MCP servers to connect to for this session.
1252    #[must_use]
1253    pub fn mcp_servers(mut self, mcp_servers: Vec<McpServer>) -> Self {
1254        self.mcp_servers = mcp_servers;
1255        self
1256    }
1257
1258    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1259    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1260    /// these keys.
1261    ///
1262    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1263    #[must_use]
1264    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1265        self.meta = meta.into_option();
1266        self
1267    }
1268}
1269
1270/// Response from loading an existing session.
1271#[serde_as]
1272#[skip_serializing_none]
1273#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1274#[schemars(extend("x-side" = "agent", "x-method" = SESSION_LOAD_METHOD_NAME))]
1275#[serde(rename_all = "camelCase")]
1276#[non_exhaustive]
1277pub struct LoadSessionResponse {
1278    /// Initial session configuration options if supported by the Agent.
1279    #[serde_as(deserialize_as = "DefaultOnError<Option<VecSkipError<_, SkipListener>>>")]
1280    #[schemars(extend("x-deserialize-default-on-error" = true, "x-deserialize-skip-invalid-items" = true))]
1281    #[serde(default)]
1282    pub config_options: Option<Vec<SessionConfigOption>>,
1283    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1284    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1285    /// these keys.
1286    ///
1287    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1288    #[serde(rename = "_meta")]
1289    pub meta: Option<Meta>,
1290}
1291
1292impl LoadSessionResponse {
1293    /// Builds [`LoadSessionResponse`] with the required response fields set; optional fields start unset or empty.
1294    #[must_use]
1295    pub fn new() -> Self {
1296        Self::default()
1297    }
1298
1299    /// Initial session configuration options if supported by the Agent.
1300    #[must_use]
1301    pub fn config_options(
1302        mut self,
1303        config_options: impl IntoOption<Vec<SessionConfigOption>>,
1304    ) -> Self {
1305        self.config_options = config_options.into_option();
1306        self
1307    }
1308
1309    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1310    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1311    /// these keys.
1312    ///
1313    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1314    #[must_use]
1315    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1316        self.meta = meta.into_option();
1317        self
1318    }
1319}
1320
1321// Fork session
1322
1323/// **UNSTABLE**
1324///
1325/// This capability is not part of the spec yet, and may be removed or changed at any point.
1326///
1327/// Request parameters for forking an existing session.
1328///
1329/// Creates a new session based on the context of an existing one, allowing
1330/// operations like generating summaries without affecting the original session's history.
1331///
1332/// Only available if the Agent supports the `session.fork` capability.
1333#[cfg(feature = "unstable_session_fork")]
1334#[skip_serializing_none]
1335#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1336#[schemars(extend("x-side" = "agent", "x-method" = SESSION_FORK_METHOD_NAME))]
1337#[serde(rename_all = "camelCase")]
1338#[non_exhaustive]
1339pub struct ForkSessionRequest {
1340    /// The ID of the session to fork.
1341    pub session_id: SessionId,
1342    /// The working directory for this session.
1343    pub cwd: PathBuf,
1344    /// Additional workspace roots to activate for this session. Each path must be absolute.
1345    ///
1346    /// When omitted or empty, no additional roots are activated. When non-empty,
1347    /// this is the complete resulting additional-root list for the forked
1348    /// session.
1349    #[serde(default, skip_serializing_if = "Vec::is_empty")]
1350    pub additional_directories: Vec<PathBuf>,
1351    /// List of MCP servers to connect to for this session.
1352    #[serde(default, skip_serializing_if = "Vec::is_empty")]
1353    pub mcp_servers: Vec<McpServer>,
1354    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1355    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1356    /// these keys.
1357    ///
1358    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1359    #[serde(rename = "_meta")]
1360    pub meta: Option<Meta>,
1361}
1362
1363#[cfg(feature = "unstable_session_fork")]
1364impl ForkSessionRequest {
1365    /// Builds [`ForkSessionRequest`] with the required request fields set; optional fields start unset or empty.
1366    #[must_use]
1367    pub fn new(session_id: impl Into<SessionId>, cwd: impl Into<PathBuf>) -> Self {
1368        Self {
1369            session_id: session_id.into(),
1370            cwd: cwd.into(),
1371            additional_directories: vec![],
1372            mcp_servers: vec![],
1373            meta: None,
1374        }
1375    }
1376
1377    /// Additional workspace roots to activate for this session. Each path must be absolute.
1378    #[must_use]
1379    pub fn additional_directories(mut self, additional_directories: Vec<PathBuf>) -> Self {
1380        self.additional_directories = additional_directories;
1381        self
1382    }
1383
1384    /// List of MCP servers to connect to for this session.
1385    #[must_use]
1386    pub fn mcp_servers(mut self, mcp_servers: Vec<McpServer>) -> Self {
1387        self.mcp_servers = mcp_servers;
1388        self
1389    }
1390
1391    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1392    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1393    /// these keys.
1394    ///
1395    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1396    #[must_use]
1397    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1398        self.meta = meta.into_option();
1399        self
1400    }
1401}
1402
1403/// **UNSTABLE**
1404///
1405/// This capability is not part of the spec yet, and may be removed or changed at any point.
1406///
1407/// Response from forking an existing session.
1408#[cfg(feature = "unstable_session_fork")]
1409#[serde_as]
1410#[skip_serializing_none]
1411#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1412#[schemars(extend("x-side" = "agent", "x-method" = SESSION_FORK_METHOD_NAME))]
1413#[serde(rename_all = "camelCase")]
1414#[non_exhaustive]
1415pub struct ForkSessionResponse {
1416    /// Unique identifier for the newly created forked session.
1417    pub session_id: SessionId,
1418    /// Initial session configuration options if supported by the Agent.
1419    #[serde_as(deserialize_as = "DefaultOnError<Option<VecSkipError<_, SkipListener>>>")]
1420    #[schemars(extend("x-deserialize-default-on-error" = true, "x-deserialize-skip-invalid-items" = true))]
1421    #[serde(default)]
1422    pub config_options: Option<Vec<SessionConfigOption>>,
1423    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1424    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1425    /// these keys.
1426    ///
1427    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1428    #[serde(rename = "_meta")]
1429    pub meta: Option<Meta>,
1430}
1431
1432#[cfg(feature = "unstable_session_fork")]
1433impl ForkSessionResponse {
1434    /// Builds [`ForkSessionResponse`] with the required response fields set; optional fields start unset or empty.
1435    #[must_use]
1436    pub fn new(session_id: impl Into<SessionId>) -> Self {
1437        Self {
1438            session_id: session_id.into(),
1439            config_options: None,
1440            meta: None,
1441        }
1442    }
1443
1444    /// Initial session configuration options if supported by the Agent.
1445    #[must_use]
1446    pub fn config_options(
1447        mut self,
1448        config_options: impl IntoOption<Vec<SessionConfigOption>>,
1449    ) -> Self {
1450        self.config_options = config_options.into_option();
1451        self
1452    }
1453
1454    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1455    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1456    /// these keys.
1457    ///
1458    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1459    #[must_use]
1460    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1461        self.meta = meta.into_option();
1462        self
1463    }
1464}
1465
1466// Resume session
1467
1468/// Request parameters for resuming an existing session.
1469///
1470/// Resumes an existing session without returning previous messages (unlike `session/load`).
1471/// This is useful for agents that can resume sessions but don't implement full session loading.
1472///
1473/// Only available if the Agent supports the `session.resume` capability.
1474#[skip_serializing_none]
1475#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1476#[schemars(extend("x-side" = "agent", "x-method" = SESSION_RESUME_METHOD_NAME))]
1477#[serde(rename_all = "camelCase")]
1478#[non_exhaustive]
1479pub struct ResumeSessionRequest {
1480    /// The ID of the session to resume.
1481    pub session_id: SessionId,
1482    /// The working directory for this session.
1483    pub cwd: PathBuf,
1484    /// Additional workspace roots to activate for this session. Each path must be absolute.
1485    ///
1486    /// When omitted or empty, no additional roots are activated. When non-empty,
1487    /// this is the complete resulting additional-root list for the resumed
1488    /// session. It may differ from any previously used or reported list as long as
1489    /// the request `cwd` matches the session's `cwd`.
1490    #[serde(default, skip_serializing_if = "Vec::is_empty")]
1491    pub additional_directories: Vec<PathBuf>,
1492    /// List of MCP servers to connect to for this session.
1493    #[serde(default, skip_serializing_if = "Vec::is_empty")]
1494    pub mcp_servers: Vec<McpServer>,
1495    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1496    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1497    /// these keys.
1498    ///
1499    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1500    #[serde(rename = "_meta")]
1501    pub meta: Option<Meta>,
1502}
1503
1504impl ResumeSessionRequest {
1505    /// Builds [`ResumeSessionRequest`] with the required request fields set; optional fields start unset or empty.
1506    #[must_use]
1507    pub fn new(session_id: impl Into<SessionId>, cwd: impl Into<PathBuf>) -> Self {
1508        Self {
1509            session_id: session_id.into(),
1510            cwd: cwd.into(),
1511            additional_directories: vec![],
1512            mcp_servers: vec![],
1513            meta: None,
1514        }
1515    }
1516
1517    /// Additional workspace roots to activate for this session. Each path must be absolute.
1518    #[must_use]
1519    pub fn additional_directories(mut self, additional_directories: Vec<PathBuf>) -> Self {
1520        self.additional_directories = additional_directories;
1521        self
1522    }
1523
1524    /// List of MCP servers to connect to for this session.
1525    #[must_use]
1526    pub fn mcp_servers(mut self, mcp_servers: Vec<McpServer>) -> Self {
1527        self.mcp_servers = mcp_servers;
1528        self
1529    }
1530
1531    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1532    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1533    /// these keys.
1534    ///
1535    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1536    #[must_use]
1537    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1538        self.meta = meta.into_option();
1539        self
1540    }
1541}
1542
1543/// Response from resuming an existing session.
1544#[serde_as]
1545#[skip_serializing_none]
1546#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1547#[schemars(extend("x-side" = "agent", "x-method" = SESSION_RESUME_METHOD_NAME))]
1548#[serde(rename_all = "camelCase")]
1549#[non_exhaustive]
1550pub struct ResumeSessionResponse {
1551    /// Initial session configuration options if supported by the Agent.
1552    #[serde_as(deserialize_as = "DefaultOnError<Option<VecSkipError<_, SkipListener>>>")]
1553    #[schemars(extend("x-deserialize-default-on-error" = true, "x-deserialize-skip-invalid-items" = true))]
1554    #[serde(default)]
1555    pub config_options: Option<Vec<SessionConfigOption>>,
1556    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1557    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1558    /// these keys.
1559    ///
1560    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1561    #[serde(rename = "_meta")]
1562    pub meta: Option<Meta>,
1563}
1564
1565impl ResumeSessionResponse {
1566    /// Builds [`ResumeSessionResponse`] with the required response fields set; optional fields start unset or empty.
1567    #[must_use]
1568    pub fn new() -> Self {
1569        Self::default()
1570    }
1571
1572    /// Initial session configuration options if supported by the Agent.
1573    #[must_use]
1574    pub fn config_options(
1575        mut self,
1576        config_options: impl IntoOption<Vec<SessionConfigOption>>,
1577    ) -> Self {
1578        self.config_options = config_options.into_option();
1579        self
1580    }
1581
1582    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1583    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1584    /// these keys.
1585    ///
1586    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1587    #[must_use]
1588    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1589        self.meta = meta.into_option();
1590        self
1591    }
1592}
1593
1594// Close session
1595
1596/// Request parameters for closing an active session.
1597///
1598/// If supported, the agent **must** cancel any ongoing work related to the session
1599/// (treat it as if `session/cancel` was called) and then free up any resources
1600/// associated with the session.
1601///
1602/// Only available if the Agent supports the `session.close` capability.
1603#[skip_serializing_none]
1604#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1605#[schemars(extend("x-side" = "agent", "x-method" = SESSION_CLOSE_METHOD_NAME))]
1606#[serde(rename_all = "camelCase")]
1607#[non_exhaustive]
1608pub struct CloseSessionRequest {
1609    /// The ID of the session to close.
1610    pub session_id: SessionId,
1611    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1612    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1613    /// these keys.
1614    ///
1615    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1616    #[serde(rename = "_meta")]
1617    pub meta: Option<Meta>,
1618}
1619
1620impl CloseSessionRequest {
1621    /// Builds [`CloseSessionRequest`] with the required request fields set; optional fields start unset or empty.
1622    #[must_use]
1623    pub fn new(session_id: impl Into<SessionId>) -> Self {
1624        Self {
1625            session_id: session_id.into(),
1626            meta: None,
1627        }
1628    }
1629
1630    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1631    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1632    /// these keys.
1633    ///
1634    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1635    #[must_use]
1636    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1637        self.meta = meta.into_option();
1638        self
1639    }
1640}
1641
1642/// Response from closing a session.
1643#[skip_serializing_none]
1644#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1645#[schemars(extend("x-side" = "agent", "x-method" = SESSION_CLOSE_METHOD_NAME))]
1646#[serde(rename_all = "camelCase")]
1647#[non_exhaustive]
1648pub struct CloseSessionResponse {
1649    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1650    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1651    /// these keys.
1652    ///
1653    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1654    #[serde(rename = "_meta")]
1655    pub meta: Option<Meta>,
1656}
1657
1658impl CloseSessionResponse {
1659    /// Builds [`CloseSessionResponse`] with the required response fields set; optional fields start unset or empty.
1660    #[must_use]
1661    pub fn new() -> Self {
1662        Self::default()
1663    }
1664
1665    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1666    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1667    /// these keys.
1668    ///
1669    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1670    #[must_use]
1671    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1672        self.meta = meta.into_option();
1673        self
1674    }
1675}
1676
1677// List sessions
1678
1679/// Request parameters for listing existing sessions.
1680///
1681/// Only available if the Agent supports the `session.list` capability.
1682#[skip_serializing_none]
1683#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1684#[schemars(extend("x-side" = "agent", "x-method" = SESSION_LIST_METHOD_NAME))]
1685#[serde(rename_all = "camelCase")]
1686#[non_exhaustive]
1687pub struct ListSessionsRequest {
1688    /// Filter sessions by working directory. Must be an absolute path.
1689    pub cwd: Option<PathBuf>,
1690    /// Opaque cursor token from a previous response's nextCursor field for cursor-based pagination
1691    pub cursor: Option<String>,
1692    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1693    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1694    /// these keys.
1695    ///
1696    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1697    #[serde(rename = "_meta")]
1698    pub meta: Option<Meta>,
1699}
1700
1701impl ListSessionsRequest {
1702    /// Builds [`ListSessionsRequest`] with the required request fields set; optional fields start unset or empty.
1703    #[must_use]
1704    pub fn new() -> Self {
1705        Self::default()
1706    }
1707
1708    /// Filter sessions by working directory. Must be an absolute path.
1709    #[must_use]
1710    pub fn cwd(mut self, cwd: impl IntoOption<PathBuf>) -> Self {
1711        self.cwd = cwd.into_option();
1712        self
1713    }
1714
1715    /// Opaque cursor token from a previous response's nextCursor field for cursor-based pagination
1716    #[must_use]
1717    pub fn cursor(mut self, cursor: impl IntoOption<String>) -> Self {
1718        self.cursor = cursor.into_option();
1719        self
1720    }
1721
1722    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1723    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1724    /// these keys.
1725    ///
1726    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1727    #[must_use]
1728    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1729        self.meta = meta.into_option();
1730        self
1731    }
1732}
1733
1734/// Response from listing sessions.
1735#[serde_as]
1736#[skip_serializing_none]
1737#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1738#[schemars(extend("x-side" = "agent", "x-method" = SESSION_LIST_METHOD_NAME))]
1739#[serde(rename_all = "camelCase")]
1740#[non_exhaustive]
1741pub struct ListSessionsResponse {
1742    /// Array of session information objects
1743    #[serde_as(deserialize_as = "DefaultOnError<VecSkipError<_, SkipListener>>")]
1744    #[schemars(extend("x-deserialize-default-on-error" = true, "x-deserialize-skip-invalid-items" = true))]
1745    pub sessions: Vec<SessionInfo>,
1746    /// Opaque cursor token. If present, pass this in the next request's cursor parameter
1747    /// to fetch the next page. If absent, there are no more results.
1748    pub next_cursor: Option<String>,
1749    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1750    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1751    /// these keys.
1752    ///
1753    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1754    #[serde(rename = "_meta")]
1755    pub meta: Option<Meta>,
1756}
1757
1758impl ListSessionsResponse {
1759    /// Builds [`ListSessionsResponse`] with the required response fields set; optional fields start unset or empty.
1760    #[must_use]
1761    pub fn new(sessions: Vec<SessionInfo>) -> Self {
1762        Self {
1763            sessions,
1764            next_cursor: None,
1765            meta: None,
1766        }
1767    }
1768
1769    /// Sets or clears the optional `nextCursor` field.
1770    #[must_use]
1771    pub fn next_cursor(mut self, next_cursor: impl IntoOption<String>) -> Self {
1772        self.next_cursor = next_cursor.into_option();
1773        self
1774    }
1775
1776    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1777    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1778    /// these keys.
1779    ///
1780    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1781    #[must_use]
1782    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1783        self.meta = meta.into_option();
1784        self
1785    }
1786}
1787
1788// Delete session
1789
1790/// Request parameters for deleting an existing session from `session/list`.
1791///
1792/// Only available if the Agent supports the `session.delete` capability.
1793#[skip_serializing_none]
1794#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1795#[schemars(extend("x-side" = "agent", "x-method" = SESSION_DELETE_METHOD_NAME))]
1796#[serde(rename_all = "camelCase")]
1797#[non_exhaustive]
1798pub struct DeleteSessionRequest {
1799    /// The ID of the session to delete.
1800    pub session_id: SessionId,
1801    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1802    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1803    /// these keys.
1804    ///
1805    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1806    #[serde(rename = "_meta")]
1807    pub meta: Option<Meta>,
1808}
1809
1810impl DeleteSessionRequest {
1811    /// Builds [`DeleteSessionRequest`] with the required request fields set; optional fields start unset or empty.
1812    #[must_use]
1813    pub fn new(session_id: impl Into<SessionId>) -> Self {
1814        Self {
1815            session_id: session_id.into(),
1816            meta: None,
1817        }
1818    }
1819
1820    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1821    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1822    /// these keys.
1823    ///
1824    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1825    #[must_use]
1826    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1827        self.meta = meta.into_option();
1828        self
1829    }
1830}
1831
1832/// Response from deleting a session.
1833#[skip_serializing_none]
1834#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1835#[schemars(extend("x-side" = "agent", "x-method" = SESSION_DELETE_METHOD_NAME))]
1836#[serde(rename_all = "camelCase")]
1837#[non_exhaustive]
1838pub struct DeleteSessionResponse {
1839    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1840    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1841    /// these keys.
1842    ///
1843    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1844    #[serde(rename = "_meta")]
1845    pub meta: Option<Meta>,
1846}
1847
1848impl DeleteSessionResponse {
1849    /// Builds [`DeleteSessionResponse`] with the required response fields set; optional fields start unset or empty.
1850    #[must_use]
1851    pub fn new() -> Self {
1852        Self::default()
1853    }
1854
1855    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1856    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1857    /// these keys.
1858    ///
1859    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1860    #[must_use]
1861    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1862        self.meta = meta.into_option();
1863        self
1864    }
1865}
1866
1867/// Information about a session returned by session/list
1868#[serde_as]
1869#[skip_serializing_none]
1870#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1871#[serde(rename_all = "camelCase")]
1872#[non_exhaustive]
1873pub struct SessionInfo {
1874    /// Unique identifier for the session
1875    pub session_id: SessionId,
1876    /// The working directory for this session. Must be an absolute path.
1877    pub cwd: PathBuf,
1878    /// Additional workspace roots reported for this session. Each path must be absolute.
1879    ///
1880    /// When present, this is the complete ordered additional-root list reported
1881    /// by the Agent. Omitted and empty values are equivalent: the response
1882    /// reports no additional roots.
1883    #[serde(default, skip_serializing_if = "Vec::is_empty")]
1884    pub additional_directories: Vec<PathBuf>,
1885
1886    /// Human-readable title for the session
1887    #[serde_as(deserialize_as = "DefaultOnError")]
1888    #[schemars(extend("x-deserialize-default-on-error" = true))]
1889    #[serde(default)]
1890    pub title: Option<String>,
1891    /// ISO 8601 timestamp of last activity
1892    #[serde_as(deserialize_as = "DefaultOnError")]
1893    #[schemars(extend("x-deserialize-default-on-error" = true))]
1894    #[serde(default)]
1895    pub updated_at: Option<String>,
1896    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1897    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1898    /// these keys.
1899    ///
1900    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1901    #[serde(rename = "_meta")]
1902    pub meta: Option<Meta>,
1903}
1904
1905impl SessionInfo {
1906    /// Builds [`SessionInfo`] with the required fields set; optional fields start unset or empty.
1907    #[must_use]
1908    pub fn new(session_id: impl Into<SessionId>, cwd: impl Into<PathBuf>) -> Self {
1909        Self {
1910            session_id: session_id.into(),
1911            cwd: cwd.into(),
1912            additional_directories: vec![],
1913            title: None,
1914            updated_at: None,
1915            meta: None,
1916        }
1917    }
1918
1919    /// Additional workspace roots reported for this session. Each path must be absolute.
1920    #[must_use]
1921    pub fn additional_directories(mut self, additional_directories: Vec<PathBuf>) -> Self {
1922        self.additional_directories = additional_directories;
1923        self
1924    }
1925
1926    /// Human-readable title for the session
1927    #[must_use]
1928    pub fn title(mut self, title: impl IntoOption<String>) -> Self {
1929        self.title = title.into_option();
1930        self
1931    }
1932
1933    /// ISO 8601 timestamp of last activity
1934    #[must_use]
1935    pub fn updated_at(mut self, updated_at: impl IntoOption<String>) -> Self {
1936        self.updated_at = updated_at.into_option();
1937        self
1938    }
1939
1940    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1941    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1942    /// these keys.
1943    ///
1944    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1945    #[must_use]
1946    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1947        self.meta = meta.into_option();
1948        self
1949    }
1950}
1951
1952// Session config options
1953
1954/// Unique identifier for a session configuration option.
1955#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq, Hash, From, Display)]
1956#[serde(transparent)]
1957#[from(Arc<str>, String, &'static str)]
1958#[non_exhaustive]
1959pub struct SessionConfigId(pub Arc<str>);
1960
1961impl SessionConfigId {
1962    /// Wraps a protocol string as a typed [`SessionConfigId`].
1963    #[must_use]
1964    pub fn new(id: impl Into<Arc<str>>) -> Self {
1965        Self(id.into())
1966    }
1967}
1968
1969/// Unique identifier for a session configuration option value.
1970#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq, Hash, From, Display)]
1971#[serde(transparent)]
1972#[from(Arc<str>, String, &'static str)]
1973#[non_exhaustive]
1974pub struct SessionConfigValueId(pub Arc<str>);
1975
1976impl SessionConfigValueId {
1977    /// Wraps a protocol string as a typed [`SessionConfigValueId`].
1978    #[must_use]
1979    pub fn new(id: impl Into<Arc<str>>) -> Self {
1980        Self(id.into())
1981    }
1982}
1983
1984/// Unique identifier for a session configuration option value group.
1985#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq, Hash, From, Display)]
1986#[serde(transparent)]
1987#[from(Arc<str>, String, &'static str)]
1988#[non_exhaustive]
1989pub struct SessionConfigGroupId(pub Arc<str>);
1990
1991impl SessionConfigGroupId {
1992    /// Wraps a protocol string as a typed [`SessionConfigGroupId`].
1993    #[must_use]
1994    pub fn new(id: impl Into<Arc<str>>) -> Self {
1995        Self(id.into())
1996    }
1997}
1998
1999/// A possible value for a session configuration option.
2000#[skip_serializing_none]
2001#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2002#[serde(rename_all = "camelCase")]
2003#[non_exhaustive]
2004pub struct SessionConfigSelectOption {
2005    /// Unique identifier for this option value.
2006    pub value: SessionConfigValueId,
2007    /// Human-readable label for this option value.
2008    pub name: String,
2009    /// Optional description for this option value.
2010    #[serde(default)]
2011    pub description: Option<String>,
2012    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
2013    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
2014    /// these keys.
2015    ///
2016    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
2017    #[serde(rename = "_meta")]
2018    pub meta: Option<Meta>,
2019}
2020
2021impl SessionConfigSelectOption {
2022    /// Builds [`SessionConfigSelectOption`] with the required fields set; optional fields start unset or empty.
2023    #[must_use]
2024    pub fn new(value: impl Into<SessionConfigValueId>, name: impl Into<String>) -> Self {
2025        Self {
2026            value: value.into(),
2027            name: name.into(),
2028            description: None,
2029            meta: None,
2030        }
2031    }
2032
2033    /// Sets or clears the optional `description` field.
2034    #[must_use]
2035    pub fn description(mut self, description: impl IntoOption<String>) -> Self {
2036        self.description = description.into_option();
2037        self
2038    }
2039
2040    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
2041    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
2042    /// these keys.
2043    ///
2044    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
2045    #[must_use]
2046    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2047        self.meta = meta.into_option();
2048        self
2049    }
2050}
2051
2052/// A group of possible values for a session configuration option.
2053#[skip_serializing_none]
2054#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2055#[serde(rename_all = "camelCase")]
2056#[non_exhaustive]
2057pub struct SessionConfigSelectGroup {
2058    /// Unique identifier for this group.
2059    pub group: SessionConfigGroupId,
2060    /// Human-readable label for this group.
2061    pub name: String,
2062    /// The set of option values in this group.
2063    pub options: Vec<SessionConfigSelectOption>,
2064    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
2065    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
2066    /// these keys.
2067    ///
2068    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
2069    #[serde(rename = "_meta")]
2070    pub meta: Option<Meta>,
2071}
2072
2073impl SessionConfigSelectGroup {
2074    /// Builds [`SessionConfigSelectGroup`] with the required fields set; optional fields start unset or empty.
2075    #[must_use]
2076    pub fn new(
2077        group: impl Into<SessionConfigGroupId>,
2078        name: impl Into<String>,
2079        options: Vec<SessionConfigSelectOption>,
2080    ) -> Self {
2081        Self {
2082            group: group.into(),
2083            name: name.into(),
2084            options,
2085            meta: None,
2086        }
2087    }
2088
2089    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
2090    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
2091    /// these keys.
2092    ///
2093    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
2094    #[must_use]
2095    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2096        self.meta = meta.into_option();
2097        self
2098    }
2099}
2100
2101/// Possible values for a session configuration option.
2102#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2103#[serde(untagged)]
2104#[non_exhaustive]
2105pub enum SessionConfigSelectOptions {
2106    /// A flat list of options with no grouping.
2107    Ungrouped(Vec<SessionConfigSelectOption>),
2108    /// A list of options grouped under headers.
2109    Grouped(Vec<SessionConfigSelectGroup>),
2110}
2111
2112impl From<Vec<SessionConfigSelectOption>> for SessionConfigSelectOptions {
2113    fn from(options: Vec<SessionConfigSelectOption>) -> Self {
2114        SessionConfigSelectOptions::Ungrouped(options)
2115    }
2116}
2117
2118impl From<Vec<SessionConfigSelectGroup>> for SessionConfigSelectOptions {
2119    fn from(groups: Vec<SessionConfigSelectGroup>) -> Self {
2120        SessionConfigSelectOptions::Grouped(groups)
2121    }
2122}
2123
2124/// A single-value selector (dropdown) session configuration option payload.
2125#[skip_serializing_none]
2126#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2127#[serde(rename_all = "camelCase")]
2128#[non_exhaustive]
2129pub struct SessionConfigSelect {
2130    /// The currently selected value.
2131    pub current_value: SessionConfigValueId,
2132    /// The set of selectable options.
2133    pub options: SessionConfigSelectOptions,
2134}
2135
2136impl SessionConfigSelect {
2137    /// Builds [`SessionConfigSelect`] with the required fields set; optional fields start unset or empty.
2138    #[must_use]
2139    pub fn new(
2140        current_value: impl Into<SessionConfigValueId>,
2141        options: impl Into<SessionConfigSelectOptions>,
2142    ) -> Self {
2143        Self {
2144            current_value: current_value.into(),
2145            options: options.into(),
2146        }
2147    }
2148}
2149
2150/// **UNSTABLE**
2151///
2152/// This capability is not part of the spec yet, and may be removed or changed at any point.
2153///
2154/// A boolean on/off toggle session configuration option payload.
2155#[cfg(feature = "unstable_boolean_config")]
2156#[skip_serializing_none]
2157#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2158#[serde(rename_all = "camelCase")]
2159#[non_exhaustive]
2160pub struct SessionConfigBoolean {
2161    /// The current value of the boolean option.
2162    pub current_value: bool,
2163}
2164
2165#[cfg(feature = "unstable_boolean_config")]
2166impl SessionConfigBoolean {
2167    /// Builds [`SessionConfigBoolean`] with the required fields set; optional fields start unset or empty.
2168    #[must_use]
2169    pub fn new(current_value: bool) -> Self {
2170        Self { current_value }
2171    }
2172}
2173
2174/// Semantic category for a session configuration option.
2175///
2176/// This is intended to help Clients distinguish broadly common selectors (e.g. model selector vs
2177/// session mode selector vs thought/reasoning level) for UX purposes (keyboard shortcuts, icons,
2178/// placement). It MUST NOT be required for correctness. Clients MUST handle missing or unknown
2179/// categories gracefully.
2180///
2181/// Category names beginning with `_` are free for custom use, like other ACP extension methods.
2182/// Category names that do not begin with `_` are reserved for the ACP spec.
2183#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2184#[serde(rename_all = "snake_case")]
2185#[non_exhaustive]
2186pub enum SessionConfigOptionCategory {
2187    /// Session mode selector.
2188    Mode,
2189    /// Model selector.
2190    Model,
2191    /// **UNSTABLE**
2192    ///
2193    /// This capability is not part of the spec yet, and may be removed or changed at any point.
2194    ///
2195    /// Model-related configuration parameter.
2196    #[cfg(feature = "unstable_model_config_category")]
2197    ModelConfig,
2198    /// Thought/reasoning level selector.
2199    ThoughtLevel,
2200    /// Custom or future category.
2201    ///
2202    /// Values beginning with `_` are reserved for implementation-specific
2203    /// extensions. Unknown values that do not begin with `_` are reserved for
2204    /// future ACP variants.
2205    #[serde(untagged)]
2206    Other(String),
2207}
2208
2209/// Type-specific session configuration option payload.
2210#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2211#[serde(tag = "type", rename_all = "snake_case")]
2212#[schemars(extend("discriminator" = {"propertyName": "type"}))]
2213#[non_exhaustive]
2214pub enum SessionConfigKind {
2215    /// Single-value selector (dropdown).
2216    Select(SessionConfigSelect),
2217    /// **UNSTABLE**
2218    ///
2219    /// This capability is not part of the spec yet, and may be removed or changed at any point.
2220    ///
2221    /// Boolean on/off toggle.
2222    #[cfg(feature = "unstable_boolean_config")]
2223    Boolean(SessionConfigBoolean),
2224    /// Custom or future session configuration option payload.
2225    ///
2226    /// Values beginning with `_` are reserved for implementation-specific
2227    /// extensions. Unknown values that do not begin with `_` are reserved for
2228    /// future ACP variants.
2229    ///
2230    /// Clients that do not understand this option type should preserve the raw
2231    /// payload when storing, replaying, proxying, or forwarding configuration
2232    /// data, and otherwise ignore the option or display it generically.
2233    #[serde(untagged)]
2234    Other(OtherSessionConfigKind),
2235}
2236
2237/// Custom or future session configuration option payload.
2238#[derive(Debug, Clone, Serialize, JsonSchema, PartialEq, Eq)]
2239#[schemars(inline)]
2240#[schemars(transform = other_session_config_kind_schema)]
2241#[serde(rename_all = "camelCase")]
2242#[non_exhaustive]
2243pub struct OtherSessionConfigKind {
2244    /// Custom or future session configuration option type.
2245    ///
2246    /// Values beginning with `_` are reserved for implementation-specific
2247    /// extensions. Unknown values that do not begin with `_` are reserved for
2248    /// future ACP variants.
2249    #[serde(rename = "type")]
2250    pub type_: String,
2251    /// Additional fields from the unknown session configuration option payload.
2252    #[serde(flatten)]
2253    pub fields: BTreeMap<String, serde_json::Value>,
2254}
2255
2256impl OtherSessionConfigKind {
2257    /// Builds [`OtherSessionConfigKind`] from an unknown discriminator and preserves the remaining extension fields.
2258    #[must_use]
2259    pub fn new(type_: impl Into<String>, mut fields: BTreeMap<String, serde_json::Value>) -> Self {
2260        fields.remove("type");
2261        fields.remove("_meta");
2262        Self {
2263            type_: type_.into(),
2264            fields,
2265        }
2266    }
2267}
2268
2269impl<'de> Deserialize<'de> for OtherSessionConfigKind {
2270    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
2271    where
2272        D: serde::Deserializer<'de>,
2273    {
2274        let mut fields = BTreeMap::<String, serde_json::Value>::deserialize(deserializer)?;
2275        let type_ = fields
2276            .remove("type")
2277            .ok_or_else(|| serde::de::Error::missing_field("type"))?;
2278        let serde_json::Value::String(type_) = type_ else {
2279            return Err(serde::de::Error::custom("`type` must be a string"));
2280        };
2281
2282        if is_known_session_config_kind_type(&type_) {
2283            return Err(serde::de::Error::custom(format!(
2284                "known session configuration option `{type_}` did not match its schema"
2285            )));
2286        }
2287
2288        Ok(Self { type_, fields })
2289    }
2290}
2291
2292fn is_known_session_config_kind_type(type_: &str) -> bool {
2293    match type_ {
2294        "select" => true,
2295        #[cfg(feature = "unstable_boolean_config")]
2296        "boolean" => true,
2297        _ => false,
2298    }
2299}
2300
2301fn other_session_config_kind_schema(schema: &mut Schema) {
2302    super::schema_util::reject_known_string_discriminators(
2303        schema,
2304        "type",
2305        &[
2306            "select",
2307            #[cfg(feature = "unstable_boolean_config")]
2308            "boolean",
2309        ],
2310    );
2311}
2312
2313/// A session configuration option selector and its current state.
2314#[serde_as]
2315#[skip_serializing_none]
2316#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2317#[serde(rename_all = "camelCase")]
2318#[non_exhaustive]
2319pub struct SessionConfigOption {
2320    /// Unique identifier for the configuration option.
2321    pub id: SessionConfigId,
2322    /// Human-readable label for the option.
2323    pub name: String,
2324    /// Optional description for the Client to display to the user.
2325    #[serde(default)]
2326    pub description: Option<String>,
2327    /// Optional semantic category for this option (UX only).
2328    #[serde_as(deserialize_as = "DefaultOnError")]
2329    #[schemars(extend("x-deserialize-default-on-error" = true))]
2330    #[serde(default)]
2331    pub category: Option<SessionConfigOptionCategory>,
2332    /// Type-specific fields for this configuration option.
2333    #[serde(flatten)]
2334    pub kind: SessionConfigKind,
2335    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
2336    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
2337    /// these keys.
2338    ///
2339    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
2340    #[serde(rename = "_meta")]
2341    pub meta: Option<Meta>,
2342}
2343
2344impl SessionConfigOption {
2345    /// Builds [`SessionConfigOption`] with the required fields set; optional fields start unset or empty.
2346    #[must_use]
2347    pub fn new(
2348        id: impl Into<SessionConfigId>,
2349        name: impl Into<String>,
2350        kind: SessionConfigKind,
2351    ) -> Self {
2352        Self {
2353            id: id.into(),
2354            name: name.into(),
2355            description: None,
2356            category: None,
2357            kind,
2358            meta: None,
2359        }
2360    }
2361
2362    /// Builds a select-style session configuration option with its current value and choices.
2363    #[must_use]
2364    pub fn select(
2365        id: impl Into<SessionConfigId>,
2366        name: impl Into<String>,
2367        current_value: impl Into<SessionConfigValueId>,
2368        options: impl Into<SessionConfigSelectOptions>,
2369    ) -> Self {
2370        Self::new(
2371            id,
2372            name,
2373            SessionConfigKind::Select(SessionConfigSelect::new(current_value, options)),
2374        )
2375    }
2376
2377    /// **UNSTABLE**
2378    ///
2379    /// This capability is not part of the spec yet, and may be removed or changed at any point.
2380    #[cfg(feature = "unstable_boolean_config")]
2381    #[must_use]
2382    pub fn boolean(
2383        id: impl Into<SessionConfigId>,
2384        name: impl Into<String>,
2385        current_value: bool,
2386    ) -> Self {
2387        Self::new(
2388            id,
2389            name,
2390            SessionConfigKind::Boolean(SessionConfigBoolean::new(current_value)),
2391        )
2392    }
2393
2394    /// Sets or clears the optional `description` field.
2395    #[must_use]
2396    pub fn description(mut self, description: impl IntoOption<String>) -> Self {
2397        self.description = description.into_option();
2398        self
2399    }
2400
2401    /// Sets or clears the optional `category` field.
2402    #[must_use]
2403    pub fn category(mut self, category: impl IntoOption<SessionConfigOptionCategory>) -> Self {
2404        self.category = category.into_option();
2405        self
2406    }
2407
2408    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
2409    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
2410    /// these keys.
2411    ///
2412    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
2413    #[must_use]
2414    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2415        self.meta = meta.into_option();
2416        self
2417    }
2418}
2419
2420/// **UNSTABLE**
2421///
2422/// This capability is not part of the spec yet, and may be removed or changed at any point.
2423///
2424/// The value to set for a session configuration option.
2425///
2426/// The `type` field acts as the discriminator in the serialized JSON form.
2427/// When no `type` is present, the value is treated as a [`SessionConfigValueId`]
2428/// via the [`ValueId`](Self::ValueId) fallback variant.
2429///
2430/// The `type` discriminator describes the *shape* of the value, not the option
2431/// kind. For example every option kind that picks from a list of ids
2432/// (`select`, `radio`, …) would use [`ValueId`](Self::ValueId), while a
2433/// future freeform text option would get its own variant.
2434#[cfg(feature = "unstable_boolean_config")]
2435#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2436#[serde(tag = "type", rename_all = "snake_case")]
2437#[non_exhaustive]
2438pub enum SessionConfigOptionValue {
2439    /// A boolean value (`type: "boolean"`).
2440    Boolean {
2441        /// The boolean value.
2442        value: bool,
2443    },
2444    /// A [`SessionConfigValueId`] string value.
2445    ///
2446    /// This is the default when `type` is absent on the wire. Unknown `type`
2447    /// values with string payloads also gracefully deserialize into this
2448    /// variant.
2449    #[serde(untagged)]
2450    ValueId {
2451        /// The value ID.
2452        value: SessionConfigValueId,
2453    },
2454}
2455
2456#[cfg(feature = "unstable_boolean_config")]
2457impl SessionConfigOptionValue {
2458    /// Create a value-id option value (used by `select` and other id-based option types).
2459    #[must_use]
2460    pub fn value_id(id: impl Into<SessionConfigValueId>) -> Self {
2461        Self::ValueId { value: id.into() }
2462    }
2463
2464    /// Create a boolean option value.
2465    #[must_use]
2466    pub fn boolean(val: bool) -> Self {
2467        Self::Boolean { value: val }
2468    }
2469
2470    /// Return the inner [`SessionConfigValueId`] if this is a
2471    /// [`ValueId`](Self::ValueId) value.
2472    #[must_use]
2473    pub fn as_value_id(&self) -> Option<&SessionConfigValueId> {
2474        match self {
2475            Self::ValueId { value } => Some(value),
2476            _ => None,
2477        }
2478    }
2479
2480    /// Return the inner [`bool`] if this is a [`Boolean`](Self::Boolean) value.
2481    #[must_use]
2482    pub fn as_bool(&self) -> Option<bool> {
2483        match self {
2484            Self::Boolean { value } => Some(*value),
2485            _ => None,
2486        }
2487    }
2488}
2489
2490#[cfg(feature = "unstable_boolean_config")]
2491impl From<SessionConfigValueId> for SessionConfigOptionValue {
2492    fn from(value: SessionConfigValueId) -> Self {
2493        Self::ValueId { value }
2494    }
2495}
2496
2497#[cfg(feature = "unstable_boolean_config")]
2498impl From<bool> for SessionConfigOptionValue {
2499    fn from(value: bool) -> Self {
2500        Self::Boolean { value }
2501    }
2502}
2503
2504#[cfg(feature = "unstable_boolean_config")]
2505impl From<&str> for SessionConfigOptionValue {
2506    fn from(value: &str) -> Self {
2507        Self::ValueId {
2508            value: SessionConfigValueId::new(value),
2509        }
2510    }
2511}
2512
2513/// Request parameters for setting a session configuration option.
2514#[skip_serializing_none]
2515#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2516#[schemars(extend("x-side" = "agent", "x-method" = SESSION_SET_CONFIG_OPTION_METHOD_NAME))]
2517#[serde(rename_all = "camelCase")]
2518#[non_exhaustive]
2519pub struct SetSessionConfigOptionRequest {
2520    /// The ID of the session to set the configuration option for.
2521    pub session_id: SessionId,
2522    /// The ID of the configuration option to set.
2523    pub config_id: SessionConfigId,
2524    /// The value to set, including a `type` discriminator and the raw `value`.
2525    ///
2526    /// When `type` is absent on the wire, defaults to treating the value as a
2527    /// [`SessionConfigValueId`] for `select` options.
2528    #[cfg(feature = "unstable_boolean_config")]
2529    #[serde(flatten)]
2530    pub value: SessionConfigOptionValue,
2531    /// The ID of the configuration option value to set.
2532    #[cfg(not(feature = "unstable_boolean_config"))]
2533    pub value: SessionConfigValueId,
2534    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
2535    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
2536    /// these keys.
2537    ///
2538    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
2539    #[serde(rename = "_meta")]
2540    pub meta: Option<Meta>,
2541}
2542
2543impl SetSessionConfigOptionRequest {
2544    /// Builds [`SetSessionConfigOptionRequest`] with the required request fields set; optional fields start unset or empty.
2545    #[cfg(feature = "unstable_boolean_config")]
2546    #[must_use]
2547    pub fn new(
2548        session_id: impl Into<SessionId>,
2549        config_id: impl Into<SessionConfigId>,
2550        value: impl Into<SessionConfigOptionValue>,
2551    ) -> Self {
2552        Self {
2553            session_id: session_id.into(),
2554            config_id: config_id.into(),
2555            value: value.into(),
2556            meta: None,
2557        }
2558    }
2559
2560    /// Builds a select-value `session/set_config_option` request for crates built
2561    /// without boolean session configuration support.
2562    #[cfg(not(feature = "unstable_boolean_config"))]
2563    #[must_use]
2564    pub fn new(
2565        session_id: impl Into<SessionId>,
2566        config_id: impl Into<SessionConfigId>,
2567        value: impl Into<SessionConfigValueId>,
2568    ) -> Self {
2569        Self {
2570            session_id: session_id.into(),
2571            config_id: config_id.into(),
2572            value: value.into(),
2573            meta: None,
2574        }
2575    }
2576
2577    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
2578    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
2579    /// these keys.
2580    ///
2581    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
2582    #[must_use]
2583    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2584        self.meta = meta.into_option();
2585        self
2586    }
2587}
2588
2589/// Response to `session/set_config_option` method.
2590#[serde_as]
2591#[skip_serializing_none]
2592#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2593#[schemars(extend("x-side" = "agent", "x-method" = SESSION_SET_CONFIG_OPTION_METHOD_NAME))]
2594#[serde(rename_all = "camelCase")]
2595#[non_exhaustive]
2596pub struct SetSessionConfigOptionResponse {
2597    /// The full set of configuration options and their current values.
2598    #[serde_as(deserialize_as = "DefaultOnError<VecSkipError<_, SkipListener>>")]
2599    #[schemars(extend("x-deserialize-default-on-error" = true, "x-deserialize-skip-invalid-items" = true))]
2600    pub config_options: Vec<SessionConfigOption>,
2601    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
2602    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
2603    /// these keys.
2604    ///
2605    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
2606    #[serde(rename = "_meta")]
2607    pub meta: Option<Meta>,
2608}
2609
2610impl SetSessionConfigOptionResponse {
2611    /// Builds [`SetSessionConfigOptionResponse`] with the required response fields set; optional fields start unset or empty.
2612    #[must_use]
2613    pub fn new(config_options: Vec<SessionConfigOption>) -> Self {
2614        Self {
2615            config_options,
2616            meta: None,
2617        }
2618    }
2619
2620    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
2621    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
2622    /// these keys.
2623    ///
2624    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
2625    #[must_use]
2626    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2627        self.meta = meta.into_option();
2628        self
2629    }
2630}
2631
2632// MCP
2633
2634/// Configuration for connecting to an MCP (Model Context Protocol) server.
2635///
2636/// MCP servers provide tools and context that the agent can use when
2637/// processing prompts.
2638///
2639/// See protocol docs: [MCP Servers](https://agentclientprotocol.com/protocol/session-setup#mcp-servers)
2640#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2641#[serde(tag = "type", rename_all = "snake_case")]
2642#[schemars(extend("discriminator" = {"propertyName": "type"}))]
2643#[non_exhaustive]
2644pub enum McpServer {
2645    /// HTTP transport configuration
2646    ///
2647    /// Only available when the Agent capabilities include `session.mcp.http`.
2648    Http(McpServerHttp),
2649    /// **UNSTABLE**
2650    ///
2651    /// This capability is not part of the spec yet, and may be removed or changed at any point.
2652    ///
2653    /// ACP transport configuration
2654    ///
2655    /// Only available when the Agent capabilities include `session.mcp.acp`.
2656    /// The MCP server is provided by an ACP component and communicates over the ACP channel.
2657    #[cfg(feature = "unstable_mcp_over_acp")]
2658    Acp(McpServerAcp),
2659    /// Stdio transport configuration
2660    ///
2661    /// Only available when the Agent capabilities include `session.mcp.stdio`.
2662    Stdio(McpServerStdio),
2663    /// Custom or future MCP server transport configuration.
2664    ///
2665    /// Values beginning with `_` are reserved for implementation-specific
2666    /// extensions. Unknown values that do not begin with `_` are reserved for
2667    /// future ACP variants.
2668    ///
2669    /// Receivers that do not understand this transport should preserve the raw
2670    /// payload when storing, replaying, proxying, or forwarding session setup
2671    /// data, and otherwise ignore it or reject the server configuration.
2672    #[serde(untagged)]
2673    Other(OtherMcpServer),
2674}
2675
2676/// Custom or future MCP server transport payload.
2677#[derive(Debug, Clone, Serialize, JsonSchema, PartialEq, Eq)]
2678#[schemars(inline)]
2679#[schemars(transform = other_mcp_server_schema)]
2680#[serde(rename_all = "camelCase")]
2681#[non_exhaustive]
2682pub struct OtherMcpServer {
2683    /// Custom or future MCP server transport type.
2684    ///
2685    /// Values beginning with `_` are reserved for implementation-specific
2686    /// extensions. Unknown values that do not begin with `_` are reserved for
2687    /// future ACP variants.
2688    #[serde(rename = "type")]
2689    pub type_: String,
2690    /// Additional fields from the unknown MCP server transport payload.
2691    #[serde(flatten)]
2692    pub fields: BTreeMap<String, serde_json::Value>,
2693}
2694
2695impl OtherMcpServer {
2696    /// Builds [`OtherMcpServer`] from an unknown discriminator and preserves the remaining extension fields.
2697    #[must_use]
2698    pub fn new(type_: impl Into<String>, mut fields: BTreeMap<String, serde_json::Value>) -> Self {
2699        fields.remove("type");
2700        Self {
2701            type_: type_.into(),
2702            fields,
2703        }
2704    }
2705}
2706
2707impl<'de> Deserialize<'de> for OtherMcpServer {
2708    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
2709    where
2710        D: serde::Deserializer<'de>,
2711    {
2712        let mut fields = BTreeMap::<String, serde_json::Value>::deserialize(deserializer)?;
2713        let type_ = fields
2714            .remove("type")
2715            .ok_or_else(|| serde::de::Error::missing_field("type"))?;
2716        let serde_json::Value::String(type_) = type_ else {
2717            return Err(serde::de::Error::custom("`type` must be a string"));
2718        };
2719
2720        if is_known_mcp_server_type(&type_) {
2721            return Err(serde::de::Error::custom(format!(
2722                "known MCP server transport `{type_}` did not match its schema"
2723            )));
2724        }
2725
2726        Ok(Self { type_, fields })
2727    }
2728}
2729
2730fn is_known_mcp_server_type(type_: &str) -> bool {
2731    match type_ {
2732        "http" | "stdio" => true,
2733        #[cfg(feature = "unstable_mcp_over_acp")]
2734        "acp" => true,
2735        _ => false,
2736    }
2737}
2738
2739fn other_mcp_server_schema(schema: &mut Schema) {
2740    super::schema_util::reject_known_string_discriminators(
2741        schema,
2742        "type",
2743        &[
2744            "http",
2745            "stdio",
2746            #[cfg(feature = "unstable_mcp_over_acp")]
2747            "acp",
2748        ],
2749    );
2750}
2751
2752/// HTTP transport configuration for MCP.
2753#[skip_serializing_none]
2754#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2755#[serde(rename_all = "camelCase")]
2756#[non_exhaustive]
2757pub struct McpServerHttp {
2758    /// Human-readable name identifying this MCP server.
2759    pub name: String,
2760    /// URL to the MCP server.
2761    pub url: String,
2762    /// HTTP headers to set when making requests to the MCP server.
2763    pub headers: Vec<HttpHeader>,
2764    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
2765    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
2766    /// these keys.
2767    ///
2768    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
2769    #[serde(rename = "_meta")]
2770    pub meta: Option<Meta>,
2771}
2772
2773impl McpServerHttp {
2774    /// Builds [`McpServerHttp`] with the required fields set; optional fields start unset or empty.
2775    #[must_use]
2776    pub fn new(name: impl Into<String>, url: impl Into<String>) -> Self {
2777        Self {
2778            name: name.into(),
2779            url: url.into(),
2780            headers: Vec::new(),
2781            meta: None,
2782        }
2783    }
2784
2785    /// HTTP headers to set when making requests to the MCP server.
2786    #[must_use]
2787    pub fn headers(mut self, headers: Vec<HttpHeader>) -> Self {
2788        self.headers = headers;
2789        self
2790    }
2791
2792    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
2793    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
2794    /// these keys.
2795    ///
2796    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
2797    #[must_use]
2798    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2799        self.meta = meta.into_option();
2800        self
2801    }
2802}
2803
2804/// **UNSTABLE**
2805///
2806/// This capability is not part of the spec yet, and may be removed or changed at any point.
2807///
2808/// Unique identifier for an MCP server using the ACP transport.
2809///
2810/// The value is opaque and generated by the ACP component providing the MCP server. It is
2811/// used by `mcp/connect` to route connection requests back to the component that declared the
2812/// server.
2813#[cfg(feature = "unstable_mcp_over_acp")]
2814#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq, Hash, Display, From)]
2815#[serde(transparent)]
2816#[from(Arc<str>, String, &'static str)]
2817#[non_exhaustive]
2818pub struct McpServerAcpId(pub Arc<str>);
2819
2820#[cfg(feature = "unstable_mcp_over_acp")]
2821impl McpServerAcpId {
2822    /// Wraps a protocol string as a typed [`McpServerAcpId`].
2823    #[must_use]
2824    pub fn new(id: impl Into<Arc<str>>) -> Self {
2825        Self(id.into())
2826    }
2827}
2828
2829/// **UNSTABLE**
2830///
2831/// This capability is not part of the spec yet, and may be removed or changed at any point.
2832///
2833/// ACP transport configuration for MCP.
2834///
2835/// The MCP server is provided by an ACP component and communicates over the ACP channel
2836/// using `mcp/connect`, `mcp/message`, and `mcp/disconnect`.
2837#[skip_serializing_none]
2838#[cfg(feature = "unstable_mcp_over_acp")]
2839#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2840#[serde(rename_all = "camelCase")]
2841#[non_exhaustive]
2842pub struct McpServerAcp {
2843    /// Human-readable name identifying this MCP server.
2844    pub name: String,
2845    /// Unique identifier for this MCP server, generated by the component providing it.
2846    ///
2847    /// Providers MUST NOT reuse an ID for multiple ACP-transport MCP servers that are visible
2848    /// on the same ACP connection.
2849    pub id: McpServerAcpId,
2850    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
2851    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
2852    /// these keys.
2853    ///
2854    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
2855    #[serde(rename = "_meta")]
2856    pub meta: Option<Meta>,
2857}
2858
2859#[cfg(feature = "unstable_mcp_over_acp")]
2860impl McpServerAcp {
2861    /// Builds [`McpServerAcp`] with the required fields set; optional fields start unset or empty.
2862    #[must_use]
2863    pub fn new(name: impl Into<String>, id: impl Into<McpServerAcpId>) -> Self {
2864        Self {
2865            name: name.into(),
2866            id: id.into(),
2867            meta: None,
2868        }
2869    }
2870
2871    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
2872    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
2873    /// these keys.
2874    ///
2875    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
2876    #[must_use]
2877    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2878        self.meta = meta.into_option();
2879        self
2880    }
2881}
2882
2883/// Stdio transport configuration for MCP.
2884#[skip_serializing_none]
2885#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2886#[serde(rename_all = "camelCase")]
2887#[non_exhaustive]
2888pub struct McpServerStdio {
2889    /// Human-readable name identifying this MCP server.
2890    pub name: String,
2891    /// Path to the MCP server executable.
2892    pub command: PathBuf,
2893    /// Command-line arguments to pass to the MCP server.
2894    pub args: Vec<String>,
2895    /// Environment variables to set when launching the MCP server.
2896    pub env: Vec<EnvVariable>,
2897    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
2898    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
2899    /// these keys.
2900    ///
2901    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
2902    #[serde(rename = "_meta")]
2903    pub meta: Option<Meta>,
2904}
2905
2906impl McpServerStdio {
2907    /// Builds [`McpServerStdio`] with the required fields set; optional fields start unset or empty.
2908    #[must_use]
2909    pub fn new(name: impl Into<String>, command: impl Into<PathBuf>) -> Self {
2910        Self {
2911            name: name.into(),
2912            command: command.into(),
2913            args: Vec::new(),
2914            env: Vec::new(),
2915            meta: None,
2916        }
2917    }
2918
2919    /// Command-line arguments to pass to the MCP server.
2920    #[must_use]
2921    pub fn args(mut self, args: Vec<String>) -> Self {
2922        self.args = args;
2923        self
2924    }
2925
2926    /// Environment variables to set when launching the MCP server.
2927    #[must_use]
2928    pub fn env(mut self, env: Vec<EnvVariable>) -> Self {
2929        self.env = env;
2930        self
2931    }
2932
2933    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
2934    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
2935    /// these keys.
2936    ///
2937    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
2938    #[must_use]
2939    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2940        self.meta = meta.into_option();
2941        self
2942    }
2943}
2944
2945/// An environment variable to set when launching an MCP server.
2946#[skip_serializing_none]
2947#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2948#[serde(rename_all = "camelCase")]
2949#[non_exhaustive]
2950pub struct EnvVariable {
2951    /// The name of the environment variable.
2952    pub name: String,
2953    /// The value to set for the environment variable.
2954    pub value: String,
2955    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
2956    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
2957    /// these keys.
2958    ///
2959    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
2960    #[serde(rename = "_meta")]
2961    pub meta: Option<Meta>,
2962}
2963
2964impl EnvVariable {
2965    /// Builds [`EnvVariable`] with the required fields set; optional fields start unset or empty.
2966    #[must_use]
2967    pub fn new(name: impl Into<String>, value: impl Into<String>) -> Self {
2968        Self {
2969            name: name.into(),
2970            value: value.into(),
2971            meta: None,
2972        }
2973    }
2974
2975    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
2976    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
2977    /// these keys.
2978    ///
2979    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
2980    #[must_use]
2981    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2982        self.meta = meta.into_option();
2983        self
2984    }
2985}
2986
2987/// An HTTP header to set when making requests to the MCP server.
2988#[skip_serializing_none]
2989#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2990#[serde(rename_all = "camelCase")]
2991#[non_exhaustive]
2992pub struct HttpHeader {
2993    /// The name of the HTTP header.
2994    pub name: String,
2995    /// The value to set for the HTTP header.
2996    pub value: String,
2997    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
2998    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
2999    /// these keys.
3000    ///
3001    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
3002    #[serde(rename = "_meta")]
3003    pub meta: Option<Meta>,
3004}
3005
3006impl HttpHeader {
3007    /// Builds [`HttpHeader`] with the required fields set; optional fields start unset or empty.
3008    #[must_use]
3009    pub fn new(name: impl Into<String>, value: impl Into<String>) -> Self {
3010        Self {
3011            name: name.into(),
3012            value: value.into(),
3013            meta: None,
3014        }
3015    }
3016
3017    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
3018    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
3019    /// these keys.
3020    ///
3021    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
3022    #[must_use]
3023    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3024        self.meta = meta.into_option();
3025        self
3026    }
3027}
3028
3029// Prompt
3030
3031/// Request parameters for sending a user prompt to the agent.
3032///
3033/// Contains the user's message and any additional context.
3034///
3035/// See protocol docs: [User Message](https://agentclientprotocol.com/protocol/prompt-lifecycle#1-user-message)
3036#[skip_serializing_none]
3037#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq)]
3038#[schemars(extend("x-side" = "agent", "x-method" = SESSION_PROMPT_METHOD_NAME))]
3039#[serde(rename_all = "camelCase")]
3040#[non_exhaustive]
3041pub struct PromptRequest {
3042    /// The ID of the session to send this user message to
3043    pub session_id: SessionId,
3044    /// The blocks of content that compose the user's message.
3045    ///
3046    /// As a baseline, the Agent MUST support [`ContentBlock::Text`] and [`ContentBlock::ResourceLink`],
3047    /// while other variants are optionally enabled via [`PromptCapabilities`].
3048    ///
3049    /// The Client MUST adapt its interface according to [`PromptCapabilities`].
3050    ///
3051    /// The client MAY include referenced pieces of context as either
3052    /// [`ContentBlock::Resource`] or [`ContentBlock::ResourceLink`].
3053    ///
3054    /// When available, [`ContentBlock::Resource`] is preferred
3055    /// as it avoids extra round-trips and allows the message to include
3056    /// pieces of context from sources the agent may not have access to.
3057    pub prompt: Vec<ContentBlock>,
3058    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
3059    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
3060    /// these keys.
3061    ///
3062    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
3063    #[serde(rename = "_meta")]
3064    pub meta: Option<Meta>,
3065}
3066
3067impl PromptRequest {
3068    /// Builds [`PromptRequest`] with the required request fields set; optional fields start unset or empty.
3069    #[must_use]
3070    pub fn new(session_id: impl Into<SessionId>, prompt: Vec<ContentBlock>) -> Self {
3071        Self {
3072            session_id: session_id.into(),
3073            prompt,
3074            meta: None,
3075        }
3076    }
3077
3078    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
3079    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
3080    /// these keys.
3081    ///
3082    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
3083    #[must_use]
3084    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3085        self.meta = meta.into_option();
3086        self
3087    }
3088}
3089
3090/// Response acknowledging that a user prompt was accepted.
3091///
3092/// This response does not indicate that the agent has finished processing.
3093/// Agents report session state through `state_update` session updates.
3094///
3095/// See protocol docs: [Prompt Accepted](https://agentclientprotocol.com/protocol/prompt-lifecycle#2-prompt-accepted)
3096#[skip_serializing_none]
3097#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3098#[schemars(extend("x-side" = "agent", "x-method" = SESSION_PROMPT_METHOD_NAME))]
3099#[serde(rename_all = "camelCase")]
3100#[non_exhaustive]
3101pub struct PromptResponse {
3102    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
3103    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
3104    /// these keys.
3105    ///
3106    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
3107    #[serde(rename = "_meta")]
3108    pub meta: Option<Meta>,
3109}
3110
3111impl PromptResponse {
3112    /// Builds [`PromptResponse`] with the required response fields set; optional fields start unset or empty.
3113    #[must_use]
3114    pub fn new() -> Self {
3115        Self::default()
3116    }
3117
3118    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
3119    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
3120    /// these keys.
3121    ///
3122    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
3123    #[must_use]
3124    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3125        self.meta = meta.into_option();
3126        self
3127    }
3128}
3129
3130/// Reasons why an agent stops active session work.
3131///
3132/// See protocol docs: [Stop Reasons](https://agentclientprotocol.com/protocol/prompt-lifecycle#stop-reasons)
3133#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize, JsonSchema)]
3134#[serde(rename_all = "snake_case")]
3135#[non_exhaustive]
3136pub enum StopReason {
3137    /// The active work ended successfully.
3138    EndTurn,
3139    /// The active work ended because the agent reached the maximum number of tokens.
3140    MaxTokens,
3141    /// The active work ended because the agent reached the maximum number of
3142    /// allowed agent requests before returning idle.
3143    MaxTurnRequests,
3144    /// The active work ended because the agent refused to continue. The user
3145    /// prompt and everything that comes after it won't be included in the next
3146    /// prompt, so this should be reflected in the UI.
3147    Refusal,
3148    /// Active session work was cancelled by the client via `session/cancel`.
3149    ///
3150    /// Agents should report this stop reason on an idle `state_update` session update
3151    /// when cancellation succeeds, even if cancellation causes exceptions in
3152    /// underlying operations.
3153    Cancelled,
3154    /// Custom or future stop reason.
3155    ///
3156    /// Values beginning with `_` are reserved for implementation-specific
3157    /// extensions. Unknown values that do not begin with `_` are reserved for
3158    /// future ACP variants.
3159    #[serde(untagged)]
3160    Other(String),
3161}
3162
3163/// **UNSTABLE**
3164///
3165/// This capability is not part of the spec yet, and may be removed or changed at any point.
3166///
3167/// Token usage information for completed session work.
3168#[cfg(feature = "unstable_end_turn_token_usage")]
3169#[skip_serializing_none]
3170#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3171#[serde(rename_all = "camelCase")]
3172#[non_exhaustive]
3173pub struct Usage {
3174    /// Sum of all token types across session.
3175    pub total_tokens: u64,
3176    /// Total input tokens.
3177    pub input_tokens: u64,
3178    /// Total output tokens.
3179    pub output_tokens: u64,
3180    /// Total thought/reasoning tokens
3181    pub thought_tokens: Option<u64>,
3182    /// Total cache read tokens.
3183    pub cached_read_tokens: Option<u64>,
3184    /// Total cache write tokens.
3185    pub cached_write_tokens: Option<u64>,
3186    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
3187    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
3188    /// these keys.
3189    ///
3190    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
3191    #[serde(rename = "_meta")]
3192    pub meta: Option<Meta>,
3193}
3194
3195#[cfg(feature = "unstable_end_turn_token_usage")]
3196impl Usage {
3197    /// Builds [`Usage`] with the required fields set; optional fields start unset or empty.
3198    #[must_use]
3199    pub fn new(total_tokens: u64, input_tokens: u64, output_tokens: u64) -> Self {
3200        Self {
3201            total_tokens,
3202            input_tokens,
3203            output_tokens,
3204            thought_tokens: None,
3205            cached_read_tokens: None,
3206            cached_write_tokens: None,
3207            meta: None,
3208        }
3209    }
3210
3211    /// Total thought/reasoning tokens
3212    #[must_use]
3213    pub fn thought_tokens(mut self, thought_tokens: impl IntoOption<u64>) -> Self {
3214        self.thought_tokens = thought_tokens.into_option();
3215        self
3216    }
3217
3218    /// Total cache read tokens.
3219    #[must_use]
3220    pub fn cached_read_tokens(mut self, cached_read_tokens: impl IntoOption<u64>) -> Self {
3221        self.cached_read_tokens = cached_read_tokens.into_option();
3222        self
3223    }
3224
3225    /// Total cache write tokens.
3226    #[must_use]
3227    pub fn cached_write_tokens(mut self, cached_write_tokens: impl IntoOption<u64>) -> Self {
3228        self.cached_write_tokens = cached_write_tokens.into_option();
3229        self
3230    }
3231
3232    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
3233    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
3234    /// these keys.
3235    ///
3236    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
3237    #[must_use]
3238    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3239        self.meta = meta.into_option();
3240        self
3241    }
3242}
3243
3244// Providers
3245
3246/// **UNSTABLE**
3247///
3248/// This capability is not part of the spec yet, and may be removed or changed at any point.
3249///
3250/// Well-known API protocol identifiers for LLM providers.
3251///
3252/// Agents and clients MUST handle unknown protocol identifiers gracefully.
3253///
3254/// Protocol names beginning with `_` are free for custom use, like other ACP extension methods.
3255/// Protocol names that do not begin with `_` are reserved for the ACP spec.
3256#[cfg(feature = "unstable_llm_providers")]
3257#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3258#[serde(rename_all = "snake_case")]
3259#[non_exhaustive]
3260#[expect(clippy::doc_markdown)]
3261pub enum LlmProtocol {
3262    /// Anthropic API protocol.
3263    Anthropic,
3264    /// OpenAI API protocol.
3265    #[serde(rename = "openai")]
3266    OpenAi,
3267    /// Azure OpenAI API protocol.
3268    Azure,
3269    /// Google Vertex AI API protocol.
3270    Vertex,
3271    /// AWS Bedrock API protocol.
3272    Bedrock,
3273    /// Custom or future protocol.
3274    ///
3275    /// Values beginning with `_` are reserved for implementation-specific
3276    /// extensions. Unknown values that do not begin with `_` are reserved for
3277    /// future ACP variants.
3278    #[serde(untagged)]
3279    Other(String),
3280}
3281
3282/// **UNSTABLE**
3283///
3284/// This capability is not part of the spec yet, and may be removed or changed at any point.
3285///
3286/// Current effective non-secret routing configuration for a provider.
3287#[cfg(feature = "unstable_llm_providers")]
3288#[skip_serializing_none]
3289#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3290#[serde(rename_all = "camelCase")]
3291#[non_exhaustive]
3292pub struct ProviderCurrentConfig {
3293    /// Protocol currently used by this provider.
3294    pub api_type: LlmProtocol,
3295    /// Base URL currently used by this provider.
3296    pub base_url: String,
3297    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
3298    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
3299    /// these keys.
3300    ///
3301    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
3302    #[serde(rename = "_meta")]
3303    pub meta: Option<Meta>,
3304}
3305
3306#[cfg(feature = "unstable_llm_providers")]
3307impl ProviderCurrentConfig {
3308    /// Builds [`ProviderCurrentConfig`] with the required fields set; optional fields start unset or empty.
3309    #[must_use]
3310    pub fn new(api_type: LlmProtocol, base_url: impl Into<String>) -> Self {
3311        Self {
3312            api_type,
3313            base_url: base_url.into(),
3314            meta: None,
3315        }
3316    }
3317
3318    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
3319    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
3320    /// these keys.
3321    ///
3322    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
3323    #[must_use]
3324    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3325        self.meta = meta.into_option();
3326        self
3327    }
3328}
3329
3330/// **UNSTABLE**
3331///
3332/// This capability is not part of the spec yet, and may be removed or changed at any point.
3333///
3334/// Information about a configurable LLM provider.
3335#[cfg(feature = "unstable_llm_providers")]
3336#[serde_as]
3337#[skip_serializing_none]
3338#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3339#[serde(rename_all = "camelCase")]
3340#[non_exhaustive]
3341pub struct ProviderInfo {
3342    /// Provider identifier, for example "main" or "openai".
3343    pub id: String,
3344    /// Supported protocol types for this provider.
3345    #[serde_as(deserialize_as = "DefaultOnError<VecSkipError<_, SkipListener>>")]
3346    #[schemars(extend("x-deserialize-default-on-error" = true, "x-deserialize-skip-invalid-items" = true))]
3347    pub supported: Vec<LlmProtocol>,
3348    /// Whether this provider is mandatory and cannot be disabled via `providers/disable`.
3349    /// If true, clients must not call `providers/disable` for this id.
3350    pub required: bool,
3351    /// Current effective non-secret routing config.
3352    /// Null or omitted means provider is disabled.
3353    pub current: Option<ProviderCurrentConfig>,
3354    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
3355    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
3356    /// these keys.
3357    ///
3358    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
3359    #[serde(rename = "_meta")]
3360    pub meta: Option<Meta>,
3361}
3362
3363#[cfg(feature = "unstable_llm_providers")]
3364impl ProviderInfo {
3365    /// Builds [`ProviderInfo`] with the required fields set; optional fields start unset or empty.
3366    #[must_use]
3367    pub fn new(
3368        id: impl Into<String>,
3369        supported: Vec<LlmProtocol>,
3370        required: bool,
3371        current: impl IntoOption<ProviderCurrentConfig>,
3372    ) -> Self {
3373        Self {
3374            id: id.into(),
3375            supported,
3376            required,
3377            current: current.into_option(),
3378            meta: None,
3379        }
3380    }
3381
3382    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
3383    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
3384    /// these keys.
3385    ///
3386    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
3387    #[must_use]
3388    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3389        self.meta = meta.into_option();
3390        self
3391    }
3392}
3393
3394/// **UNSTABLE**
3395///
3396/// This capability is not part of the spec yet, and may be removed or changed at any point.
3397///
3398/// Request parameters for `providers/list`.
3399#[cfg(feature = "unstable_llm_providers")]
3400#[skip_serializing_none]
3401#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3402#[schemars(extend("x-side" = "agent", "x-method" = PROVIDERS_LIST_METHOD_NAME))]
3403#[serde(rename_all = "camelCase")]
3404#[non_exhaustive]
3405pub struct ListProvidersRequest {
3406    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
3407    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
3408    /// these keys.
3409    ///
3410    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
3411    #[serde(rename = "_meta")]
3412    pub meta: Option<Meta>,
3413}
3414
3415#[cfg(feature = "unstable_llm_providers")]
3416impl ListProvidersRequest {
3417    /// Builds [`ListProvidersRequest`] with the required request fields set; optional fields start unset or empty.
3418    #[must_use]
3419    pub fn new() -> Self {
3420        Self::default()
3421    }
3422
3423    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
3424    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
3425    /// these keys.
3426    ///
3427    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
3428    #[must_use]
3429    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3430        self.meta = meta.into_option();
3431        self
3432    }
3433}
3434
3435/// **UNSTABLE**
3436///
3437/// This capability is not part of the spec yet, and may be removed or changed at any point.
3438///
3439/// Response to `providers/list`.
3440#[cfg(feature = "unstable_llm_providers")]
3441#[serde_as]
3442#[skip_serializing_none]
3443#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3444#[schemars(extend("x-side" = "agent", "x-method" = PROVIDERS_LIST_METHOD_NAME))]
3445#[serde(rename_all = "camelCase")]
3446#[non_exhaustive]
3447pub struct ListProvidersResponse {
3448    /// Configurable providers with current routing info suitable for UI display.
3449    #[serde_as(deserialize_as = "DefaultOnError<VecSkipError<_, SkipListener>>")]
3450    #[schemars(extend("x-deserialize-default-on-error" = true, "x-deserialize-skip-invalid-items" = true))]
3451    pub providers: Vec<ProviderInfo>,
3452    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
3453    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
3454    /// these keys.
3455    ///
3456    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
3457    #[serde(rename = "_meta")]
3458    pub meta: Option<Meta>,
3459}
3460
3461#[cfg(feature = "unstable_llm_providers")]
3462impl ListProvidersResponse {
3463    /// Builds [`ListProvidersResponse`] with the required response fields set; optional fields start unset or empty.
3464    #[must_use]
3465    pub fn new(providers: Vec<ProviderInfo>) -> Self {
3466        Self {
3467            providers,
3468            meta: None,
3469        }
3470    }
3471
3472    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
3473    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
3474    /// these keys.
3475    ///
3476    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
3477    #[must_use]
3478    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3479        self.meta = meta.into_option();
3480        self
3481    }
3482}
3483
3484/// **UNSTABLE**
3485///
3486/// This capability is not part of the spec yet, and may be removed or changed at any point.
3487///
3488/// Request parameters for `providers/set`.
3489///
3490/// Replaces the full configuration for one provider id.
3491#[cfg(feature = "unstable_llm_providers")]
3492#[skip_serializing_none]
3493#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3494#[schemars(extend("x-side" = "agent", "x-method" = PROVIDERS_SET_METHOD_NAME))]
3495#[serde(rename_all = "camelCase")]
3496#[non_exhaustive]
3497pub struct SetProviderRequest {
3498    /// Provider id to configure.
3499    pub id: String,
3500    /// Protocol type for this provider.
3501    pub api_type: LlmProtocol,
3502    /// Base URL for requests sent through this provider.
3503    pub base_url: String,
3504    /// Full headers map for this provider.
3505    /// May include authorization, routing, or other integration-specific headers.
3506    #[serde(default, skip_serializing_if = "HashMap::is_empty")]
3507    pub headers: HashMap<String, String>,
3508    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
3509    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
3510    /// these keys.
3511    ///
3512    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
3513    #[serde(rename = "_meta")]
3514    pub meta: Option<Meta>,
3515}
3516
3517#[cfg(feature = "unstable_llm_providers")]
3518impl SetProviderRequest {
3519    /// Builds [`SetProviderRequest`] with the required request fields set; optional fields start unset or empty.
3520    #[must_use]
3521    pub fn new(id: impl Into<String>, api_type: LlmProtocol, base_url: impl Into<String>) -> Self {
3522        Self {
3523            id: id.into(),
3524            api_type,
3525            base_url: base_url.into(),
3526            headers: HashMap::new(),
3527            meta: None,
3528        }
3529    }
3530
3531    /// Full headers map for this provider.
3532    /// May include authorization, routing, or other integration-specific headers.
3533    #[must_use]
3534    pub fn headers(mut self, headers: HashMap<String, String>) -> Self {
3535        self.headers = headers;
3536        self
3537    }
3538
3539    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
3540    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
3541    /// these keys.
3542    ///
3543    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
3544    #[must_use]
3545    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3546        self.meta = meta.into_option();
3547        self
3548    }
3549}
3550
3551/// **UNSTABLE**
3552///
3553/// This capability is not part of the spec yet, and may be removed or changed at any point.
3554///
3555/// Response to `providers/set`.
3556#[cfg(feature = "unstable_llm_providers")]
3557#[skip_serializing_none]
3558#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3559#[schemars(extend("x-side" = "agent", "x-method" = PROVIDERS_SET_METHOD_NAME))]
3560#[serde(rename_all = "camelCase")]
3561#[non_exhaustive]
3562pub struct SetProviderResponse {
3563    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
3564    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
3565    /// these keys.
3566    ///
3567    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
3568    #[serde(rename = "_meta")]
3569    pub meta: Option<Meta>,
3570}
3571
3572#[cfg(feature = "unstable_llm_providers")]
3573impl SetProviderResponse {
3574    /// Builds [`SetProviderResponse`] with the required response fields set; optional fields start unset or empty.
3575    #[must_use]
3576    pub fn new() -> Self {
3577        Self::default()
3578    }
3579
3580    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
3581    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
3582    /// these keys.
3583    ///
3584    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
3585    #[must_use]
3586    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3587        self.meta = meta.into_option();
3588        self
3589    }
3590}
3591
3592/// **UNSTABLE**
3593///
3594/// This capability is not part of the spec yet, and may be removed or changed at any point.
3595///
3596/// Request parameters for `providers/disable`.
3597#[cfg(feature = "unstable_llm_providers")]
3598#[skip_serializing_none]
3599#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3600#[schemars(extend("x-side" = "agent", "x-method" = PROVIDERS_DISABLE_METHOD_NAME))]
3601#[serde(rename_all = "camelCase")]
3602#[non_exhaustive]
3603pub struct DisableProviderRequest {
3604    /// Provider id to disable.
3605    pub id: String,
3606    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
3607    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
3608    /// these keys.
3609    ///
3610    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
3611    #[serde(rename = "_meta")]
3612    pub meta: Option<Meta>,
3613}
3614
3615#[cfg(feature = "unstable_llm_providers")]
3616impl DisableProviderRequest {
3617    /// Builds [`DisableProviderRequest`] with the required request fields set; optional fields start unset or empty.
3618    #[must_use]
3619    pub fn new(id: impl Into<String>) -> Self {
3620        Self {
3621            id: id.into(),
3622            meta: None,
3623        }
3624    }
3625
3626    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
3627    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
3628    /// these keys.
3629    ///
3630    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
3631    #[must_use]
3632    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3633        self.meta = meta.into_option();
3634        self
3635    }
3636}
3637
3638/// **UNSTABLE**
3639///
3640/// This capability is not part of the spec yet, and may be removed or changed at any point.
3641///
3642/// Response to `providers/disable`.
3643#[cfg(feature = "unstable_llm_providers")]
3644#[skip_serializing_none]
3645#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3646#[schemars(extend("x-side" = "agent", "x-method" = PROVIDERS_DISABLE_METHOD_NAME))]
3647#[serde(rename_all = "camelCase")]
3648#[non_exhaustive]
3649pub struct DisableProviderResponse {
3650    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
3651    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
3652    /// these keys.
3653    ///
3654    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
3655    #[serde(rename = "_meta")]
3656    pub meta: Option<Meta>,
3657}
3658
3659#[cfg(feature = "unstable_llm_providers")]
3660impl DisableProviderResponse {
3661    /// Builds [`DisableProviderResponse`] with the required response fields set; optional fields start unset or empty.
3662    #[must_use]
3663    pub fn new() -> Self {
3664        Self::default()
3665    }
3666
3667    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
3668    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
3669    /// these keys.
3670    ///
3671    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
3672    #[must_use]
3673    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3674        self.meta = meta.into_option();
3675        self
3676    }
3677}
3678
3679// Capabilities
3680
3681/// Capabilities supported by the agent.
3682///
3683/// Advertised during initialization to inform the client about
3684/// available features and content types.
3685///
3686/// See protocol docs: [Agent Capabilities](https://agentclientprotocol.com/protocol/initialization#agent-capabilities)
3687#[serde_as]
3688#[skip_serializing_none]
3689#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3690#[serde(rename_all = "camelCase")]
3691#[non_exhaustive]
3692pub struct AgentCapabilities {
3693    /// Session capabilities supported by the agent.
3694    ///
3695    /// Optional. Omitted or `null` both mean the agent does not support the
3696    /// `session/*` method surface. Supplying `{}` means the agent supports the
3697    /// baseline session methods: `session/new`, `session/prompt`,
3698    /// `session/cancel`, and `session/update`.
3699    #[serde_as(deserialize_as = "DefaultOnError")]
3700    #[schemars(extend("x-deserialize-default-on-error" = true))]
3701    #[serde(default)]
3702    pub session: Option<SessionCapabilities>,
3703    /// Authentication-related capabilities supported by the agent.
3704    #[serde(default)]
3705    pub auth: AgentAuthCapabilities,
3706    /// **UNSTABLE**
3707    ///
3708    /// This capability is not part of the spec yet, and may be removed or changed at any point.
3709    ///
3710    /// Provider configuration capabilities supported by the agent.
3711    ///
3712    /// By supplying `{}` it means that the agent supports provider configuration methods.
3713    #[cfg(feature = "unstable_llm_providers")]
3714    #[serde_as(deserialize_as = "DefaultOnError")]
3715    #[schemars(extend("x-deserialize-default-on-error" = true))]
3716    #[serde(default)]
3717    pub providers: Option<ProvidersCapabilities>,
3718    /// **UNSTABLE**
3719    ///
3720    /// This capability is not part of the spec yet, and may be removed or changed at any point.
3721    ///
3722    /// NES (Next Edit Suggestions) capabilities supported by the agent.
3723    #[cfg(feature = "unstable_nes")]
3724    #[serde_as(deserialize_as = "DefaultOnError")]
3725    #[schemars(extend("x-deserialize-default-on-error" = true))]
3726    #[serde(default)]
3727    pub nes: Option<NesCapabilities>,
3728    /// **UNSTABLE**
3729    ///
3730    /// This capability is not part of the spec yet, and may be removed or changed at any point.
3731    ///
3732    /// The position encoding selected by the agent from the client's supported encodings.
3733    #[cfg(feature = "unstable_nes")]
3734    #[serde_as(deserialize_as = "DefaultOnError")]
3735    #[schemars(extend("x-deserialize-default-on-error" = true))]
3736    #[serde(default)]
3737    pub position_encoding: Option<PositionEncodingKind>,
3738    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
3739    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
3740    /// these keys.
3741    ///
3742    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
3743    #[serde(rename = "_meta")]
3744    pub meta: Option<Meta>,
3745}
3746
3747impl AgentCapabilities {
3748    /// Builds an empty [`AgentCapabilities`]; use builder methods to advertise supported sub-capabilities.
3749    #[must_use]
3750    pub fn new() -> Self {
3751        Self::default()
3752    }
3753
3754    /// Session capabilities supported by the agent.
3755    ///
3756    /// Omitted or `null` both mean the agent does not support the `session/*`
3757    /// method surface. Supplying `{}` means the agent supports the baseline
3758    /// session methods: `session/new`, `session/prompt`, `session/cancel`, and
3759    /// `session/update`.
3760    #[must_use]
3761    pub fn session(mut self, session: impl IntoOption<SessionCapabilities>) -> Self {
3762        self.session = session.into_option();
3763        self
3764    }
3765
3766    /// Authentication-related capabilities supported by the agent.
3767    #[must_use]
3768    pub fn auth(mut self, auth: AgentAuthCapabilities) -> Self {
3769        self.auth = auth;
3770        self
3771    }
3772
3773    /// **UNSTABLE**
3774    ///
3775    /// This capability is not part of the spec yet, and may be removed or changed at any point.
3776    ///
3777    /// Provider configuration capabilities supported by the agent.
3778    #[cfg(feature = "unstable_llm_providers")]
3779    #[must_use]
3780    pub fn providers(mut self, providers: impl IntoOption<ProvidersCapabilities>) -> Self {
3781        self.providers = providers.into_option();
3782        self
3783    }
3784
3785    /// **UNSTABLE**
3786    ///
3787    /// This capability is not part of the spec yet, and may be removed or changed at any point.
3788    ///
3789    /// NES (Next Edit Suggestions) capabilities supported by the agent.
3790    #[cfg(feature = "unstable_nes")]
3791    #[must_use]
3792    pub fn nes(mut self, nes: impl IntoOption<NesCapabilities>) -> Self {
3793        self.nes = nes.into_option();
3794        self
3795    }
3796
3797    /// **UNSTABLE**
3798    ///
3799    /// The position encoding selected by the agent from the client's supported encodings.
3800    #[cfg(feature = "unstable_nes")]
3801    #[must_use]
3802    pub fn position_encoding(
3803        mut self,
3804        position_encoding: impl IntoOption<PositionEncodingKind>,
3805    ) -> Self {
3806        self.position_encoding = position_encoding.into_option();
3807        self
3808    }
3809
3810    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
3811    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
3812    /// these keys.
3813    ///
3814    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
3815    #[must_use]
3816    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3817        self.meta = meta.into_option();
3818        self
3819    }
3820}
3821
3822/// **UNSTABLE**
3823///
3824/// This capability is not part of the spec yet, and may be removed or changed at any point.
3825///
3826/// Provider configuration capabilities supported by the agent.
3827///
3828/// By supplying `{}` it means that the agent supports provider configuration methods.
3829#[cfg(feature = "unstable_llm_providers")]
3830#[skip_serializing_none]
3831#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3832#[non_exhaustive]
3833pub struct ProvidersCapabilities {
3834    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
3835    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
3836    /// these keys.
3837    ///
3838    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
3839    #[serde(rename = "_meta")]
3840    pub meta: Option<Meta>,
3841}
3842
3843#[cfg(feature = "unstable_llm_providers")]
3844impl ProvidersCapabilities {
3845    /// Builds an empty [`ProvidersCapabilities`]; use builder methods to advertise supported sub-capabilities.
3846    #[must_use]
3847    pub fn new() -> Self {
3848        Self::default()
3849    }
3850
3851    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
3852    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
3853    /// these keys.
3854    ///
3855    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
3856    #[must_use]
3857    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3858        self.meta = meta.into_option();
3859        self
3860    }
3861}
3862
3863/// Session capabilities supported by the agent.
3864///
3865/// Supplying `{}` means the agent supports the baseline session methods:
3866/// `session/new`, `session/prompt`, `session/cancel`, and `session/update`.
3867///
3868/// Agents that support sessions **MAY** support additional session methods,
3869/// prompt content types, and MCP transports by specifying additional
3870/// capabilities.
3871///
3872/// See protocol docs: [Session Capabilities](https://agentclientprotocol.com/protocol/initialization#session-capabilities)
3873#[serde_as]
3874#[skip_serializing_none]
3875#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3876#[serde(rename_all = "camelCase")]
3877#[non_exhaustive]
3878pub struct SessionCapabilities {
3879    /// Prompt capabilities supported by the agent in `session/prompt` requests.
3880    ///
3881    /// Optional. Omitted or `null` both mean the agent does not advertise any
3882    /// prompt extensions beyond the baseline text and resource-link content
3883    /// required by `session/prompt`.
3884    #[serde_as(deserialize_as = "DefaultOnError")]
3885    #[schemars(extend("x-deserialize-default-on-error" = true))]
3886    #[serde(default)]
3887    pub prompt: Option<PromptCapabilities>,
3888    /// MCP capabilities supported by the agent for session lifecycle requests.
3889    ///
3890    /// Optional. Omitted or `null` both mean the agent does not advertise MCP
3891    /// server transport support for sessions.
3892    #[serde_as(deserialize_as = "DefaultOnError")]
3893    #[schemars(extend("x-deserialize-default-on-error" = true))]
3894    #[serde(default)]
3895    pub mcp: Option<McpCapabilities>,
3896    /// Whether the agent supports `session/load`.
3897    ///
3898    /// Optional. Omitted or `null` both mean the agent does not advertise support.
3899    /// Supplying `{}` means the agent supports loading sessions.
3900    #[serde_as(deserialize_as = "DefaultOnError")]
3901    #[schemars(extend("x-deserialize-default-on-error" = true))]
3902    #[serde(default)]
3903    pub load: Option<SessionLoadCapabilities>,
3904    /// Whether the agent supports `session/list`.
3905    #[serde_as(deserialize_as = "DefaultOnError")]
3906    #[schemars(extend("x-deserialize-default-on-error" = true))]
3907    #[serde(default)]
3908    pub list: Option<SessionListCapabilities>,
3909    /// Whether the agent supports `session/delete`.
3910    ///
3911    /// Optional. Omitted or `null` both mean the agent does not advertise support.
3912    /// Supplying `{}` means the agent supports deleting sessions from `session/list`.
3913    #[serde_as(deserialize_as = "DefaultOnError")]
3914    #[schemars(extend("x-deserialize-default-on-error" = true))]
3915    #[serde(default)]
3916    pub delete: Option<SessionDeleteCapabilities>,
3917    /// Whether the agent supports `additionalDirectories` on supported session lifecycle requests.
3918    ///
3919    /// Agents that also support `session/list` may return
3920    /// `SessionInfo.additionalDirectories` to report the complete ordered
3921    /// additional-root list associated with a listed session.
3922    #[serde_as(deserialize_as = "DefaultOnError")]
3923    #[schemars(extend("x-deserialize-default-on-error" = true))]
3924    #[serde(default)]
3925    pub additional_directories: Option<SessionAdditionalDirectoriesCapabilities>,
3926    /// **UNSTABLE**
3927    ///
3928    /// This capability is not part of the spec yet, and may be removed or changed at any point.
3929    ///
3930    /// Whether the agent supports `session/fork`.
3931    #[cfg(feature = "unstable_session_fork")]
3932    #[serde_as(deserialize_as = "DefaultOnError")]
3933    #[schemars(extend("x-deserialize-default-on-error" = true))]
3934    #[serde(default)]
3935    pub fork: Option<SessionForkCapabilities>,
3936    /// Whether the agent supports `session/resume`.
3937    #[serde_as(deserialize_as = "DefaultOnError")]
3938    #[schemars(extend("x-deserialize-default-on-error" = true))]
3939    #[serde(default)]
3940    pub resume: Option<SessionResumeCapabilities>,
3941    /// Whether the agent supports `session/close`.
3942    #[serde_as(deserialize_as = "DefaultOnError")]
3943    #[schemars(extend("x-deserialize-default-on-error" = true))]
3944    #[serde(default)]
3945    pub close: Option<SessionCloseCapabilities>,
3946    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
3947    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
3948    /// these keys.
3949    ///
3950    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
3951    #[serde(rename = "_meta")]
3952    pub meta: Option<Meta>,
3953}
3954
3955impl SessionCapabilities {
3956    /// Builds an empty [`SessionCapabilities`]; use builder methods to advertise supported sub-capabilities.
3957    #[must_use]
3958    pub fn new() -> Self {
3959        Self::default()
3960    }
3961
3962    /// Prompt capabilities supported by the agent in `session/prompt` requests.
3963    ///
3964    /// Omitted or `null` both mean the agent does not advertise any prompt
3965    /// extensions beyond the baseline text and resource-link content required by
3966    /// `session/prompt`.
3967    #[must_use]
3968    pub fn prompt(mut self, prompt: impl IntoOption<PromptCapabilities>) -> Self {
3969        self.prompt = prompt.into_option();
3970        self
3971    }
3972
3973    /// MCP capabilities supported by the agent for session lifecycle requests.
3974    ///
3975    /// Omitted or `null` both mean the agent does not advertise MCP server
3976    /// transport support for sessions.
3977    #[must_use]
3978    pub fn mcp(mut self, mcp: impl IntoOption<McpCapabilities>) -> Self {
3979        self.mcp = mcp.into_option();
3980        self
3981    }
3982
3983    /// Whether the agent supports `session/load`.
3984    ///
3985    /// Omitted or `null` both mean the agent does not advertise support.
3986    /// Supplying `{}` means the agent supports loading sessions.
3987    #[must_use]
3988    pub fn load(mut self, load: impl IntoOption<SessionLoadCapabilities>) -> Self {
3989        self.load = load.into_option();
3990        self
3991    }
3992
3993    /// Whether the agent supports `session/list`.
3994    #[must_use]
3995    pub fn list(mut self, list: impl IntoOption<SessionListCapabilities>) -> Self {
3996        self.list = list.into_option();
3997        self
3998    }
3999
4000    /// Whether the agent supports `session/delete`.
4001    ///
4002    /// Omitted or `null` both mean the agent does not advertise support.
4003    /// Supplying `{}` means the agent supports deleting sessions from `session/list`.
4004    #[must_use]
4005    pub fn delete(mut self, delete: impl IntoOption<SessionDeleteCapabilities>) -> Self {
4006        self.delete = delete.into_option();
4007        self
4008    }
4009
4010    /// Whether the agent supports `additionalDirectories` on supported session lifecycle requests.
4011    ///
4012    /// Agents that also support `session/list` may return
4013    /// `SessionInfo.additionalDirectories` to report the complete ordered
4014    /// additional-root list associated with a listed session.
4015    #[must_use]
4016    pub fn additional_directories(
4017        mut self,
4018        additional_directories: impl IntoOption<SessionAdditionalDirectoriesCapabilities>,
4019    ) -> Self {
4020        self.additional_directories = additional_directories.into_option();
4021        self
4022    }
4023
4024    #[cfg(feature = "unstable_session_fork")]
4025    /// Whether the agent supports `session/fork`.
4026    #[must_use]
4027    pub fn fork(mut self, fork: impl IntoOption<SessionForkCapabilities>) -> Self {
4028        self.fork = fork.into_option();
4029        self
4030    }
4031
4032    /// Whether the agent supports `session/resume`.
4033    #[must_use]
4034    pub fn resume(mut self, resume: impl IntoOption<SessionResumeCapabilities>) -> Self {
4035        self.resume = resume.into_option();
4036        self
4037    }
4038
4039    /// Whether the agent supports `session/close`.
4040    #[must_use]
4041    pub fn close(mut self, close: impl IntoOption<SessionCloseCapabilities>) -> Self {
4042        self.close = close.into_option();
4043        self
4044    }
4045
4046    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
4047    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
4048    /// these keys.
4049    ///
4050    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
4051    #[must_use]
4052    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4053        self.meta = meta.into_option();
4054        self
4055    }
4056}
4057
4058/// Capabilities for the `session/load` method.
4059///
4060/// Supplying `{}` means the agent supports loading sessions.
4061#[skip_serializing_none]
4062#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
4063#[non_exhaustive]
4064pub struct SessionLoadCapabilities {
4065    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
4066    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
4067    /// these keys.
4068    ///
4069    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
4070    #[serde(rename = "_meta")]
4071    pub meta: Option<Meta>,
4072}
4073
4074impl SessionLoadCapabilities {
4075    /// Builds an empty [`SessionLoadCapabilities`]; use builder methods to advertise supported sub-capabilities.
4076    #[must_use]
4077    pub fn new() -> Self {
4078        Self::default()
4079    }
4080
4081    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
4082    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
4083    /// these keys.
4084    ///
4085    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
4086    #[must_use]
4087    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4088        self.meta = meta.into_option();
4089        self
4090    }
4091}
4092
4093/// Capabilities for the `session/list` method.
4094///
4095/// By supplying `{}` it means that the agent supports listing of sessions.
4096#[skip_serializing_none]
4097#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
4098#[non_exhaustive]
4099pub struct SessionListCapabilities {
4100    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
4101    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
4102    /// these keys.
4103    ///
4104    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
4105    #[serde(rename = "_meta")]
4106    pub meta: Option<Meta>,
4107}
4108
4109impl SessionListCapabilities {
4110    /// Builds an empty [`SessionListCapabilities`]; use builder methods to advertise supported sub-capabilities.
4111    #[must_use]
4112    pub fn new() -> Self {
4113        Self::default()
4114    }
4115
4116    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
4117    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
4118    /// these keys.
4119    ///
4120    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
4121    #[must_use]
4122    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4123        self.meta = meta.into_option();
4124        self
4125    }
4126}
4127
4128/// Capabilities for the `session/delete` method.
4129///
4130/// Supplying `{}` means the agent supports deleting sessions from `session/list`.
4131#[skip_serializing_none]
4132#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
4133#[non_exhaustive]
4134pub struct SessionDeleteCapabilities {
4135    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
4136    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
4137    /// these keys.
4138    ///
4139    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
4140    #[serde(rename = "_meta")]
4141    pub meta: Option<Meta>,
4142}
4143
4144impl SessionDeleteCapabilities {
4145    /// Builds an empty [`SessionDeleteCapabilities`]; use builder methods to advertise supported sub-capabilities.
4146    #[must_use]
4147    pub fn new() -> Self {
4148        Self::default()
4149    }
4150
4151    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
4152    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
4153    /// these keys.
4154    ///
4155    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
4156    #[must_use]
4157    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4158        self.meta = meta.into_option();
4159        self
4160    }
4161}
4162
4163/// Capabilities for additional session directories support.
4164///
4165/// By supplying `{}` it means that the agent supports the `additionalDirectories`
4166/// field on supported session lifecycle requests. Agents that also support
4167/// `session/list` may return `SessionInfo.additionalDirectories` to report the
4168/// complete ordered additional-root list associated with a listed session.
4169#[skip_serializing_none]
4170#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
4171#[non_exhaustive]
4172pub struct SessionAdditionalDirectoriesCapabilities {
4173    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
4174    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
4175    /// these keys.
4176    ///
4177    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
4178    #[serde(rename = "_meta")]
4179    pub meta: Option<Meta>,
4180}
4181
4182impl SessionAdditionalDirectoriesCapabilities {
4183    /// Builds an empty [`SessionAdditionalDirectoriesCapabilities`]; use builder methods to advertise supported sub-capabilities.
4184    #[must_use]
4185    pub fn new() -> Self {
4186        Self::default()
4187    }
4188
4189    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
4190    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
4191    /// these keys.
4192    ///
4193    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
4194    #[must_use]
4195    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4196        self.meta = meta.into_option();
4197        self
4198    }
4199}
4200
4201/// **UNSTABLE**
4202///
4203/// This capability is not part of the spec yet, and may be removed or changed at any point.
4204///
4205/// Capabilities for the `session/fork` method.
4206///
4207/// By supplying `{}` it means that the agent supports forking of sessions.
4208#[cfg(feature = "unstable_session_fork")]
4209#[skip_serializing_none]
4210#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
4211#[non_exhaustive]
4212pub struct SessionForkCapabilities {
4213    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
4214    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
4215    /// these keys.
4216    ///
4217    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
4218    #[serde(rename = "_meta")]
4219    pub meta: Option<Meta>,
4220}
4221
4222#[cfg(feature = "unstable_session_fork")]
4223impl SessionForkCapabilities {
4224    /// Builds an empty [`SessionForkCapabilities`]; use builder methods to advertise supported sub-capabilities.
4225    #[must_use]
4226    pub fn new() -> Self {
4227        Self::default()
4228    }
4229
4230    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
4231    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
4232    /// these keys.
4233    ///
4234    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
4235    #[must_use]
4236    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4237        self.meta = meta.into_option();
4238        self
4239    }
4240}
4241
4242/// Capabilities for the `session/resume` method.
4243///
4244/// By supplying `{}` it means that the agent supports resuming of sessions.
4245#[skip_serializing_none]
4246#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
4247#[non_exhaustive]
4248pub struct SessionResumeCapabilities {
4249    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
4250    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
4251    /// these keys.
4252    ///
4253    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
4254    #[serde(rename = "_meta")]
4255    pub meta: Option<Meta>,
4256}
4257
4258impl SessionResumeCapabilities {
4259    /// Builds an empty [`SessionResumeCapabilities`]; use builder methods to advertise supported sub-capabilities.
4260    #[must_use]
4261    pub fn new() -> Self {
4262        Self::default()
4263    }
4264
4265    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
4266    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
4267    /// these keys.
4268    ///
4269    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
4270    #[must_use]
4271    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4272        self.meta = meta.into_option();
4273        self
4274    }
4275}
4276
4277/// Capabilities for the `session/close` method.
4278///
4279/// By supplying `{}` it means that the agent supports closing of sessions.
4280#[skip_serializing_none]
4281#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
4282#[non_exhaustive]
4283pub struct SessionCloseCapabilities {
4284    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
4285    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
4286    /// these keys.
4287    ///
4288    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
4289    #[serde(rename = "_meta")]
4290    pub meta: Option<Meta>,
4291}
4292
4293impl SessionCloseCapabilities {
4294    /// Builds an empty [`SessionCloseCapabilities`]; use builder methods to advertise supported sub-capabilities.
4295    #[must_use]
4296    pub fn new() -> Self {
4297        Self::default()
4298    }
4299
4300    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
4301    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
4302    /// these keys.
4303    ///
4304    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
4305    #[must_use]
4306    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4307        self.meta = meta.into_option();
4308        self
4309    }
4310}
4311
4312/// Prompt capabilities supported by the agent in `session/prompt` requests.
4313///
4314/// Baseline agent functionality requires support for [`ContentBlock::Text`]
4315/// and [`ContentBlock::ResourceLink`] in prompt requests.
4316///
4317/// Other variants must be explicitly opted in to.
4318/// Capabilities for different types of content in prompt requests.
4319///
4320/// Indicates which content types beyond the baseline (text and resource links)
4321/// the agent can process.
4322///
4323/// See protocol docs: [Prompt Capabilities](https://agentclientprotocol.com/protocol/initialization#prompt-capabilities)
4324#[serde_as]
4325#[skip_serializing_none]
4326#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
4327#[serde(rename_all = "camelCase")]
4328#[non_exhaustive]
4329pub struct PromptCapabilities {
4330    /// Agent supports [`ContentBlock::Image`].
4331    ///
4332    /// Optional. Omitted or `null` both mean the agent does not advertise support.
4333    /// Supplying `{}` means the agent supports image content in prompts.
4334    #[serde_as(deserialize_as = "DefaultOnError")]
4335    #[schemars(extend("x-deserialize-default-on-error" = true))]
4336    #[serde(default)]
4337    pub image: Option<PromptImageCapabilities>,
4338    /// Agent supports [`ContentBlock::Audio`].
4339    ///
4340    /// Optional. Omitted or `null` both mean the agent does not advertise support.
4341    /// Supplying `{}` means the agent supports audio content in prompts.
4342    #[serde_as(deserialize_as = "DefaultOnError")]
4343    #[schemars(extend("x-deserialize-default-on-error" = true))]
4344    #[serde(default)]
4345    pub audio: Option<PromptAudioCapabilities>,
4346    /// Agent supports embedded context in `session/prompt` requests.
4347    ///
4348    /// When enabled, the Client is allowed to include [`ContentBlock::Resource`]
4349    /// in prompt requests for pieces of context that are referenced in the message.
4350    ///
4351    /// Optional. Omitted or `null` both mean the agent does not advertise support.
4352    /// Supplying `{}` means the agent supports embedded context in prompts.
4353    #[serde_as(deserialize_as = "DefaultOnError")]
4354    #[schemars(extend("x-deserialize-default-on-error" = true))]
4355    #[serde(default)]
4356    pub embedded_context: Option<PromptEmbeddedContextCapabilities>,
4357    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
4358    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
4359    /// these keys.
4360    ///
4361    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
4362    #[serde(rename = "_meta")]
4363    pub meta: Option<Meta>,
4364}
4365
4366impl PromptCapabilities {
4367    /// Builds an empty [`PromptCapabilities`]; use builder methods to advertise supported sub-capabilities.
4368    #[must_use]
4369    pub fn new() -> Self {
4370        Self::default()
4371    }
4372
4373    /// Agent supports [`ContentBlock::Image`].
4374    ///
4375    /// Omitted or `null` both mean the agent does not advertise support.
4376    /// Supplying `{}` means the agent supports image content in prompts.
4377    #[must_use]
4378    pub fn image(mut self, image: impl IntoOption<PromptImageCapabilities>) -> Self {
4379        self.image = image.into_option();
4380        self
4381    }
4382
4383    /// Agent supports [`ContentBlock::Audio`].
4384    ///
4385    /// Omitted or `null` both mean the agent does not advertise support.
4386    /// Supplying `{}` means the agent supports audio content in prompts.
4387    #[must_use]
4388    pub fn audio(mut self, audio: impl IntoOption<PromptAudioCapabilities>) -> Self {
4389        self.audio = audio.into_option();
4390        self
4391    }
4392
4393    /// Agent supports embedded context in `session/prompt` requests.
4394    ///
4395    /// When enabled, the Client is allowed to include [`ContentBlock::Resource`]
4396    /// in prompt requests for pieces of context that are referenced in the message.
4397    ///
4398    /// Omitted or `null` both mean the agent does not advertise support.
4399    /// Supplying `{}` means the agent supports embedded context in prompts.
4400    #[must_use]
4401    pub fn embedded_context(
4402        mut self,
4403        embedded_context: impl IntoOption<PromptEmbeddedContextCapabilities>,
4404    ) -> Self {
4405        self.embedded_context = embedded_context.into_option();
4406        self
4407    }
4408
4409    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
4410    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
4411    /// these keys.
4412    ///
4413    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
4414    #[must_use]
4415    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4416        self.meta = meta.into_option();
4417        self
4418    }
4419}
4420
4421/// Capabilities for image content in prompt requests.
4422///
4423/// Supplying `{}` means the agent supports image content in prompts.
4424#[skip_serializing_none]
4425#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
4426#[non_exhaustive]
4427pub struct PromptImageCapabilities {
4428    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
4429    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
4430    /// these keys.
4431    ///
4432    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
4433    #[serde(rename = "_meta")]
4434    pub meta: Option<Meta>,
4435}
4436
4437impl PromptImageCapabilities {
4438    /// Builds an empty [`PromptImageCapabilities`]; use builder methods to advertise supported sub-capabilities.
4439    #[must_use]
4440    pub fn new() -> Self {
4441        Self::default()
4442    }
4443
4444    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
4445    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
4446    /// these keys.
4447    ///
4448    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
4449    #[must_use]
4450    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4451        self.meta = meta.into_option();
4452        self
4453    }
4454}
4455
4456/// Capabilities for audio content in prompt requests.
4457///
4458/// Supplying `{}` means the agent supports audio content in prompts.
4459#[skip_serializing_none]
4460#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
4461#[non_exhaustive]
4462pub struct PromptAudioCapabilities {
4463    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
4464    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
4465    /// these keys.
4466    ///
4467    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
4468    #[serde(rename = "_meta")]
4469    pub meta: Option<Meta>,
4470}
4471
4472impl PromptAudioCapabilities {
4473    /// Builds an empty [`PromptAudioCapabilities`]; use builder methods to advertise supported sub-capabilities.
4474    #[must_use]
4475    pub fn new() -> Self {
4476        Self::default()
4477    }
4478
4479    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
4480    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
4481    /// these keys.
4482    ///
4483    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
4484    #[must_use]
4485    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4486        self.meta = meta.into_option();
4487        self
4488    }
4489}
4490
4491/// Capabilities for embedded context in prompt requests.
4492///
4493/// Supplying `{}` means the agent supports embedded context in prompts.
4494#[skip_serializing_none]
4495#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
4496#[non_exhaustive]
4497pub struct PromptEmbeddedContextCapabilities {
4498    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
4499    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
4500    /// these keys.
4501    ///
4502    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
4503    #[serde(rename = "_meta")]
4504    pub meta: Option<Meta>,
4505}
4506
4507impl PromptEmbeddedContextCapabilities {
4508    /// Builds an empty [`PromptEmbeddedContextCapabilities`]; use builder methods to advertise supported sub-capabilities.
4509    #[must_use]
4510    pub fn new() -> Self {
4511        Self::default()
4512    }
4513
4514    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
4515    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
4516    /// these keys.
4517    ///
4518    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
4519    #[must_use]
4520    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4521        self.meta = meta.into_option();
4522        self
4523    }
4524}
4525
4526/// MCP capabilities supported by the agent for session lifecycle requests.
4527#[serde_as]
4528#[skip_serializing_none]
4529#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
4530#[serde(rename_all = "camelCase")]
4531#[non_exhaustive]
4532pub struct McpCapabilities {
4533    /// Agent supports [`McpServer::Stdio`].
4534    ///
4535    /// Optional. Omitted or `null` both mean the agent does not advertise support.
4536    /// Supplying `{}` means the agent supports stdio MCP server transports.
4537    #[serde_as(deserialize_as = "DefaultOnError")]
4538    #[schemars(extend("x-deserialize-default-on-error" = true))]
4539    #[serde(default)]
4540    pub stdio: Option<McpStdioCapabilities>,
4541    /// Agent supports [`McpServer::Http`].
4542    ///
4543    /// Optional. Omitted or `null` both mean the agent does not advertise support.
4544    /// Supplying `{}` means the agent supports HTTP MCP server transports.
4545    #[serde_as(deserialize_as = "DefaultOnError")]
4546    #[schemars(extend("x-deserialize-default-on-error" = true))]
4547    #[serde(default)]
4548    pub http: Option<McpHttpCapabilities>,
4549    /// **UNSTABLE**
4550    ///
4551    /// This capability is not part of the spec yet, and may be removed or changed at any point.
4552    ///
4553    /// Agent supports [`McpServer::Acp`].
4554    #[cfg(feature = "unstable_mcp_over_acp")]
4555    ///
4556    /// Optional. Omitted or `null` both mean the agent does not advertise support.
4557    /// Supplying `{}` means the agent supports ACP MCP server transports.
4558    #[serde_as(deserialize_as = "DefaultOnError")]
4559    #[schemars(extend("x-deserialize-default-on-error" = true))]
4560    #[serde(default)]
4561    pub acp: Option<McpAcpCapabilities>,
4562    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
4563    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
4564    /// these keys.
4565    ///
4566    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
4567    #[serde(rename = "_meta")]
4568    pub meta: Option<Meta>,
4569}
4570
4571impl McpCapabilities {
4572    /// Builds an empty [`McpCapabilities`]; use builder methods to advertise supported sub-capabilities.
4573    #[must_use]
4574    pub fn new() -> Self {
4575        Self::default()
4576    }
4577
4578    /// Agent supports [`McpServer::Stdio`].
4579    ///
4580    /// Omitted or `null` both mean the agent does not advertise support.
4581    /// Supplying `{}` means the agent supports stdio MCP server transports.
4582    #[must_use]
4583    pub fn stdio(mut self, stdio: impl IntoOption<McpStdioCapabilities>) -> Self {
4584        self.stdio = stdio.into_option();
4585        self
4586    }
4587
4588    /// Agent supports [`McpServer::Http`].
4589    ///
4590    /// Omitted or `null` both mean the agent does not advertise support.
4591    /// Supplying `{}` means the agent supports HTTP MCP server transports.
4592    #[must_use]
4593    pub fn http(mut self, http: impl IntoOption<McpHttpCapabilities>) -> Self {
4594        self.http = http.into_option();
4595        self
4596    }
4597
4598    /// **UNSTABLE**
4599    ///
4600    /// This capability is not part of the spec yet, and may be removed or changed at any point.
4601    ///
4602    /// Agent supports [`McpServer::Acp`].
4603    #[cfg(feature = "unstable_mcp_over_acp")]
4604    ///
4605    /// Omitted or `null` both mean the agent does not advertise support.
4606    /// Supplying `{}` means the agent supports ACP MCP server transports.
4607    #[must_use]
4608    pub fn acp(mut self, acp: impl IntoOption<McpAcpCapabilities>) -> Self {
4609        self.acp = acp.into_option();
4610        self
4611    }
4612
4613    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
4614    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
4615    /// these keys.
4616    ///
4617    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
4618    #[must_use]
4619    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4620        self.meta = meta.into_option();
4621        self
4622    }
4623}
4624
4625/// Capabilities for stdio MCP server transports.
4626///
4627/// Supplying `{}` means the agent supports stdio MCP server transports.
4628#[skip_serializing_none]
4629#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
4630#[non_exhaustive]
4631pub struct McpStdioCapabilities {
4632    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
4633    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
4634    /// these keys.
4635    ///
4636    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
4637    #[serde(rename = "_meta")]
4638    pub meta: Option<Meta>,
4639}
4640
4641impl McpStdioCapabilities {
4642    /// Builds an empty [`McpStdioCapabilities`]; use builder methods to advertise supported sub-capabilities.
4643    #[must_use]
4644    pub fn new() -> Self {
4645        Self::default()
4646    }
4647
4648    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
4649    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
4650    /// these keys.
4651    ///
4652    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
4653    #[must_use]
4654    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4655        self.meta = meta.into_option();
4656        self
4657    }
4658}
4659
4660/// Capabilities for HTTP MCP server transports.
4661///
4662/// Supplying `{}` means the agent supports HTTP MCP server transports.
4663#[skip_serializing_none]
4664#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
4665#[non_exhaustive]
4666pub struct McpHttpCapabilities {
4667    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
4668    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
4669    /// these keys.
4670    ///
4671    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
4672    #[serde(rename = "_meta")]
4673    pub meta: Option<Meta>,
4674}
4675
4676impl McpHttpCapabilities {
4677    /// Builds an empty [`McpHttpCapabilities`]; use builder methods to advertise supported sub-capabilities.
4678    #[must_use]
4679    pub fn new() -> Self {
4680        Self::default()
4681    }
4682
4683    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
4684    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
4685    /// these keys.
4686    ///
4687    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
4688    #[must_use]
4689    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4690        self.meta = meta.into_option();
4691        self
4692    }
4693}
4694
4695/// **UNSTABLE**
4696///
4697/// This capability is not part of the spec yet, and may be removed or changed at any point.
4698///
4699/// Capabilities for ACP MCP server transports.
4700///
4701/// Supplying `{}` means the agent supports ACP MCP server transports.
4702#[cfg(feature = "unstable_mcp_over_acp")]
4703#[skip_serializing_none]
4704#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
4705#[non_exhaustive]
4706pub struct McpAcpCapabilities {
4707    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
4708    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
4709    /// these keys.
4710    ///
4711    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
4712    #[serde(rename = "_meta")]
4713    pub meta: Option<Meta>,
4714}
4715
4716#[cfg(feature = "unstable_mcp_over_acp")]
4717impl McpAcpCapabilities {
4718    /// Builds an empty [`McpAcpCapabilities`]; use builder methods to advertise supported sub-capabilities.
4719    #[must_use]
4720    pub fn new() -> Self {
4721        Self::default()
4722    }
4723
4724    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
4725    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
4726    /// these keys.
4727    ///
4728    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
4729    #[must_use]
4730    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4731        self.meta = meta.into_option();
4732        self
4733    }
4734}
4735
4736// Method schema
4737
4738/// Names of all methods that agents handle.
4739///
4740/// Provides a centralized definition of method names used in the protocol.
4741#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
4742#[non_exhaustive]
4743pub struct AgentMethodNames {
4744    /// Method for initializing the connection.
4745    pub initialize: &'static str,
4746    /// Method for authenticating with the agent.
4747    pub authenticate: &'static str,
4748    /// Method for listing configurable providers.
4749    #[cfg(feature = "unstable_llm_providers")]
4750    pub providers_list: &'static str,
4751    /// Method for setting provider configuration.
4752    #[cfg(feature = "unstable_llm_providers")]
4753    pub providers_set: &'static str,
4754    /// Method for disabling a provider.
4755    #[cfg(feature = "unstable_llm_providers")]
4756    pub providers_disable: &'static str,
4757    /// Method for creating a new session.
4758    pub session_new: &'static str,
4759    /// Method for loading an existing session.
4760    pub session_load: &'static str,
4761    /// Method for setting a configuration option for a session.
4762    pub session_set_config_option: &'static str,
4763    /// Method for sending a prompt to the agent.
4764    pub session_prompt: &'static str,
4765    /// Notification for cancelling operations.
4766    pub session_cancel: &'static str,
4767    /// Method for exchanging MCP-over-ACP messages.
4768    #[cfg(feature = "unstable_mcp_over_acp")]
4769    pub mcp_message: &'static str,
4770    /// Method for listing existing sessions.
4771    pub session_list: &'static str,
4772    /// Method for deleting an existing session.
4773    pub session_delete: &'static str,
4774    /// Method for forking an existing session.
4775    #[cfg(feature = "unstable_session_fork")]
4776    pub session_fork: &'static str,
4777    /// Method for resuming an existing session.
4778    pub session_resume: &'static str,
4779    /// Method for closing an active session.
4780    pub session_close: &'static str,
4781    /// Method for logging out of an authenticated session.
4782    pub logout: &'static str,
4783    /// Method for starting an NES session.
4784    #[cfg(feature = "unstable_nes")]
4785    pub nes_start: &'static str,
4786    /// Method for requesting a suggestion.
4787    #[cfg(feature = "unstable_nes")]
4788    pub nes_suggest: &'static str,
4789    /// Notification for accepting a suggestion.
4790    #[cfg(feature = "unstable_nes")]
4791    pub nes_accept: &'static str,
4792    /// Notification for rejecting a suggestion.
4793    #[cfg(feature = "unstable_nes")]
4794    pub nes_reject: &'static str,
4795    /// Method for closing an NES session.
4796    #[cfg(feature = "unstable_nes")]
4797    pub nes_close: &'static str,
4798    /// Notification for document open events.
4799    #[cfg(feature = "unstable_nes")]
4800    pub document_did_open: &'static str,
4801    /// Notification for document change events.
4802    #[cfg(feature = "unstable_nes")]
4803    pub document_did_change: &'static str,
4804    /// Notification for document close events.
4805    #[cfg(feature = "unstable_nes")]
4806    pub document_did_close: &'static str,
4807    /// Notification for document save events.
4808    #[cfg(feature = "unstable_nes")]
4809    pub document_did_save: &'static str,
4810    /// Notification for document focus events.
4811    #[cfg(feature = "unstable_nes")]
4812    pub document_did_focus: &'static str,
4813}
4814
4815/// Constant containing all agent method names.
4816pub const AGENT_METHOD_NAMES: AgentMethodNames = AgentMethodNames {
4817    initialize: INITIALIZE_METHOD_NAME,
4818    authenticate: AUTHENTICATE_METHOD_NAME,
4819    #[cfg(feature = "unstable_llm_providers")]
4820    providers_list: PROVIDERS_LIST_METHOD_NAME,
4821    #[cfg(feature = "unstable_llm_providers")]
4822    providers_set: PROVIDERS_SET_METHOD_NAME,
4823    #[cfg(feature = "unstable_llm_providers")]
4824    providers_disable: PROVIDERS_DISABLE_METHOD_NAME,
4825    session_new: SESSION_NEW_METHOD_NAME,
4826    session_load: SESSION_LOAD_METHOD_NAME,
4827    session_set_config_option: SESSION_SET_CONFIG_OPTION_METHOD_NAME,
4828    session_prompt: SESSION_PROMPT_METHOD_NAME,
4829    session_cancel: SESSION_CANCEL_METHOD_NAME,
4830    #[cfg(feature = "unstable_mcp_over_acp")]
4831    mcp_message: MCP_MESSAGE_METHOD_NAME,
4832    session_list: SESSION_LIST_METHOD_NAME,
4833    session_delete: SESSION_DELETE_METHOD_NAME,
4834    #[cfg(feature = "unstable_session_fork")]
4835    session_fork: SESSION_FORK_METHOD_NAME,
4836    session_resume: SESSION_RESUME_METHOD_NAME,
4837    session_close: SESSION_CLOSE_METHOD_NAME,
4838    logout: LOGOUT_METHOD_NAME,
4839    #[cfg(feature = "unstable_nes")]
4840    nes_start: NES_START_METHOD_NAME,
4841    #[cfg(feature = "unstable_nes")]
4842    nes_suggest: NES_SUGGEST_METHOD_NAME,
4843    #[cfg(feature = "unstable_nes")]
4844    nes_accept: NES_ACCEPT_METHOD_NAME,
4845    #[cfg(feature = "unstable_nes")]
4846    nes_reject: NES_REJECT_METHOD_NAME,
4847    #[cfg(feature = "unstable_nes")]
4848    nes_close: NES_CLOSE_METHOD_NAME,
4849    #[cfg(feature = "unstable_nes")]
4850    document_did_open: DOCUMENT_DID_OPEN_METHOD_NAME,
4851    #[cfg(feature = "unstable_nes")]
4852    document_did_change: DOCUMENT_DID_CHANGE_METHOD_NAME,
4853    #[cfg(feature = "unstable_nes")]
4854    document_did_close: DOCUMENT_DID_CLOSE_METHOD_NAME,
4855    #[cfg(feature = "unstable_nes")]
4856    document_did_save: DOCUMENT_DID_SAVE_METHOD_NAME,
4857    #[cfg(feature = "unstable_nes")]
4858    document_did_focus: DOCUMENT_DID_FOCUS_METHOD_NAME,
4859};
4860
4861/// Method name for the initialize request.
4862pub(crate) const INITIALIZE_METHOD_NAME: &str = "initialize";
4863/// Method name for the authenticate request.
4864pub(crate) const AUTHENTICATE_METHOD_NAME: &str = "authenticate";
4865/// Method name for listing configurable providers.
4866#[cfg(feature = "unstable_llm_providers")]
4867pub(crate) const PROVIDERS_LIST_METHOD_NAME: &str = "providers/list";
4868/// Method name for setting provider configuration.
4869#[cfg(feature = "unstable_llm_providers")]
4870pub(crate) const PROVIDERS_SET_METHOD_NAME: &str = "providers/set";
4871/// Method name for disabling a provider.
4872#[cfg(feature = "unstable_llm_providers")]
4873pub(crate) const PROVIDERS_DISABLE_METHOD_NAME: &str = "providers/disable";
4874/// Method name for creating a new session.
4875pub(crate) const SESSION_NEW_METHOD_NAME: &str = "session/new";
4876/// Method name for loading an existing session.
4877pub(crate) const SESSION_LOAD_METHOD_NAME: &str = "session/load";
4878/// Method name for setting a configuration option for a session.
4879pub(crate) const SESSION_SET_CONFIG_OPTION_METHOD_NAME: &str = "session/set_config_option";
4880/// Method name for sending a prompt.
4881pub(crate) const SESSION_PROMPT_METHOD_NAME: &str = "session/prompt";
4882/// Method name for the cancel notification.
4883pub(crate) const SESSION_CANCEL_METHOD_NAME: &str = "session/cancel";
4884/// Method name for listing existing sessions.
4885pub(crate) const SESSION_LIST_METHOD_NAME: &str = "session/list";
4886/// Method name for deleting an existing session.
4887pub(crate) const SESSION_DELETE_METHOD_NAME: &str = "session/delete";
4888/// Method name for forking an existing session.
4889#[cfg(feature = "unstable_session_fork")]
4890pub(crate) const SESSION_FORK_METHOD_NAME: &str = "session/fork";
4891/// Method name for resuming an existing session.
4892pub(crate) const SESSION_RESUME_METHOD_NAME: &str = "session/resume";
4893/// Method name for closing an active session.
4894pub(crate) const SESSION_CLOSE_METHOD_NAME: &str = "session/close";
4895/// Method name for logging out of an authenticated session.
4896pub(crate) const LOGOUT_METHOD_NAME: &str = "logout";
4897
4898/// All possible requests that a client can send to an agent.
4899///
4900/// This enum is used internally for routing RPC requests. You typically won't need
4901/// to use this directly.
4902///
4903/// This enum encompasses all method calls from client to agent.
4904#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
4905#[serde(untagged)]
4906#[schemars(inline)]
4907#[non_exhaustive]
4908pub enum ClientRequest {
4909    /// Establishes the connection with a client and negotiates protocol capabilities.
4910    ///
4911    /// This method is called once at the beginning of the connection to:
4912    /// - Negotiate the protocol version to use
4913    /// - Exchange capability information between client and agent
4914    /// - Determine available authentication methods
4915    ///
4916    /// The agent should respond with its supported protocol version and capabilities.
4917    ///
4918    /// See protocol docs: [Initialization](https://agentclientprotocol.com/protocol/initialization)
4919    InitializeRequest(Box<InitializeRequest>),
4920    /// Authenticates the client using the specified authentication method.
4921    ///
4922    /// Called when the agent requires authentication before allowing session creation.
4923    /// The client provides the authentication method ID that was advertised during initialization.
4924    ///
4925    /// After successful authentication, the client can proceed to create sessions with
4926    /// `new_session` without receiving an `auth_required` error.
4927    ///
4928    /// See protocol docs: [Initialization](https://agentclientprotocol.com/protocol/initialization)
4929    AuthenticateRequest(AuthenticateRequest),
4930    /// **UNSTABLE**
4931    ///
4932    /// This capability is not part of the spec yet, and may be removed or changed at any point.
4933    ///
4934    /// Lists providers that can be configured by the client.
4935    #[cfg(feature = "unstable_llm_providers")]
4936    ListProvidersRequest(ListProvidersRequest),
4937    /// **UNSTABLE**
4938    ///
4939    /// This capability is not part of the spec yet, and may be removed or changed at any point.
4940    ///
4941    /// Replaces the configuration for a provider.
4942    #[cfg(feature = "unstable_llm_providers")]
4943    SetProviderRequest(Box<SetProviderRequest>),
4944    /// **UNSTABLE**
4945    ///
4946    /// This capability is not part of the spec yet, and may be removed or changed at any point.
4947    ///
4948    /// Disables a provider.
4949    #[cfg(feature = "unstable_llm_providers")]
4950    DisableProviderRequest(DisableProviderRequest),
4951    /// Logs out of the current authenticated state.
4952    ///
4953    /// After a successful logout, all new sessions will require authentication.
4954    /// There is no guarantee about the behavior of already running sessions.
4955    LogoutRequest(LogoutRequest),
4956    /// Creates a new conversation session with the agent.
4957    ///
4958    /// Sessions represent independent conversation contexts with their own history and state.
4959    ///
4960    /// The agent should:
4961    /// - Create a new session context
4962    /// - Connect to any specified MCP servers
4963    /// - Return a unique session ID for future requests
4964    ///
4965    /// May return an `auth_required` error if the agent requires authentication.
4966    ///
4967    /// See protocol docs: [Session Setup](https://agentclientprotocol.com/protocol/session-setup)
4968    NewSessionRequest(NewSessionRequest),
4969    /// Loads an existing session to resume a previous conversation.
4970    ///
4971    /// This method is only available if the agent advertises the `session.load` capability.
4972    ///
4973    /// The agent should:
4974    /// - Restore the session context and conversation history
4975    /// - Connect to the specified MCP servers
4976    /// - Stream the entire conversation history back to the client via notifications
4977    ///
4978    /// See protocol docs: [Loading Sessions](https://agentclientprotocol.com/protocol/session-setup#loading-sessions)
4979    LoadSessionRequest(LoadSessionRequest),
4980    /// Lists existing sessions known to the agent.
4981    ///
4982    /// This method is only available if the agent advertises the `session.list` capability.
4983    ///
4984    /// The agent should return metadata about sessions with optional filtering and pagination support.
4985    ListSessionsRequest(ListSessionsRequest),
4986    /// Deletes an existing session from `session/list`.
4987    ///
4988    /// This method is only available if the agent advertises the `session.delete` capability.
4989    DeleteSessionRequest(DeleteSessionRequest),
4990    #[cfg(feature = "unstable_session_fork")]
4991    /// **UNSTABLE**
4992    ///
4993    /// This capability is not part of the spec yet, and may be removed or changed at any point.
4994    ///
4995    /// Forks an existing session to create a new independent session.
4996    ///
4997    /// This method is only available if the agent advertises the `session.fork` capability.
4998    ///
4999    /// The agent should create a new session with the same conversation context as the
5000    /// original, allowing operations like generating summaries without affecting the
5001    /// original session's history.
5002    ForkSessionRequest(ForkSessionRequest),
5003    /// Resumes an existing session without returning previous messages.
5004    ///
5005    /// This method is only available if the agent advertises the `session.resume` capability.
5006    ///
5007    /// The agent should resume the session context, allowing the conversation to continue
5008    /// without replaying the message history (unlike `session/load`).
5009    ResumeSessionRequest(ResumeSessionRequest),
5010    /// Closes an active session and frees up any resources associated with it.
5011    ///
5012    /// This method is only available if the agent advertises the `session.close` capability.
5013    ///
5014    /// The agent must cancel any ongoing work (as if `session/cancel` was called)
5015    /// and then free up any resources associated with the session.
5016    CloseSessionRequest(CloseSessionRequest),
5017    /// Sets the current value for a session configuration option.
5018    SetSessionConfigOptionRequest(SetSessionConfigOptionRequest),
5019    /// Processes a user prompt within a session.
5020    ///
5021    /// This request accepts the prompt:
5022    /// - Receives user messages with optional context (files, images, etc.)
5023    /// - Returns once the prompt is accepted
5024    ///
5025    /// After acceptance, the Agent reports the accepted user message,
5026    /// processing state, output, tool calls, and completion through
5027    /// `session/update` notifications.
5028    ///
5029    /// See protocol docs: [Prompt Lifecycle](https://agentclientprotocol.com/protocol/prompt-lifecycle)
5030    PromptRequest(PromptRequest),
5031    #[cfg(feature = "unstable_nes")]
5032    /// **UNSTABLE**
5033    ///
5034    /// This capability is not part of the spec yet, and may be removed or changed at any point.
5035    ///
5036    /// Starts an NES session.
5037    StartNesRequest(Box<StartNesRequest>),
5038    #[cfg(feature = "unstable_nes")]
5039    /// **UNSTABLE**
5040    ///
5041    /// This capability is not part of the spec yet, and may be removed or changed at any point.
5042    ///
5043    /// Requests a code suggestion.
5044    SuggestNesRequest(Box<SuggestNesRequest>),
5045    #[cfg(feature = "unstable_nes")]
5046    /// **UNSTABLE**
5047    ///
5048    /// This capability is not part of the spec yet, and may be removed or changed at any point.
5049    ///
5050    /// Closes an active NES session and frees up any resources associated with it.
5051    ///
5052    /// The agent must cancel any ongoing work and then free up any resources
5053    /// associated with the NES session.
5054    CloseNesRequest(CloseNesRequest),
5055    /// **UNSTABLE**
5056    ///
5057    /// This capability is not part of the spec yet, and may be removed or changed at any point.
5058    ///
5059    /// Exchanges an MCP-over-ACP message.
5060    #[cfg(feature = "unstable_mcp_over_acp")]
5061    MessageMcpRequest(MessageMcpRequest),
5062    /// Handles extension method requests from the client.
5063    ///
5064    /// Extension methods provide a way to add custom functionality while maintaining
5065    /// protocol compatibility.
5066    ///
5067    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
5068    ExtMethodRequest(ExtRequest),
5069}
5070
5071impl ClientRequest {
5072    /// Returns the corresponding method name of the request.
5073    #[must_use]
5074    pub fn method(&self) -> &str {
5075        match self {
5076            Self::InitializeRequest(_) => AGENT_METHOD_NAMES.initialize,
5077            Self::AuthenticateRequest(_) => AGENT_METHOD_NAMES.authenticate,
5078            #[cfg(feature = "unstable_llm_providers")]
5079            Self::ListProvidersRequest(_) => AGENT_METHOD_NAMES.providers_list,
5080            #[cfg(feature = "unstable_llm_providers")]
5081            Self::SetProviderRequest(_) => AGENT_METHOD_NAMES.providers_set,
5082            #[cfg(feature = "unstable_llm_providers")]
5083            Self::DisableProviderRequest(_) => AGENT_METHOD_NAMES.providers_disable,
5084            Self::LogoutRequest(_) => AGENT_METHOD_NAMES.logout,
5085            Self::NewSessionRequest(_) => AGENT_METHOD_NAMES.session_new,
5086            Self::LoadSessionRequest(_) => AGENT_METHOD_NAMES.session_load,
5087            Self::ListSessionsRequest(_) => AGENT_METHOD_NAMES.session_list,
5088            Self::DeleteSessionRequest(_) => AGENT_METHOD_NAMES.session_delete,
5089            #[cfg(feature = "unstable_session_fork")]
5090            Self::ForkSessionRequest(_) => AGENT_METHOD_NAMES.session_fork,
5091            Self::ResumeSessionRequest(_) => AGENT_METHOD_NAMES.session_resume,
5092            Self::CloseSessionRequest(_) => AGENT_METHOD_NAMES.session_close,
5093            Self::SetSessionConfigOptionRequest(_) => AGENT_METHOD_NAMES.session_set_config_option,
5094            Self::PromptRequest(_) => AGENT_METHOD_NAMES.session_prompt,
5095            #[cfg(feature = "unstable_nes")]
5096            Self::StartNesRequest(_) => AGENT_METHOD_NAMES.nes_start,
5097            #[cfg(feature = "unstable_nes")]
5098            Self::SuggestNesRequest(_) => AGENT_METHOD_NAMES.nes_suggest,
5099            #[cfg(feature = "unstable_nes")]
5100            Self::CloseNesRequest(_) => AGENT_METHOD_NAMES.nes_close,
5101            #[cfg(feature = "unstable_mcp_over_acp")]
5102            Self::MessageMcpRequest(_) => AGENT_METHOD_NAMES.mcp_message,
5103            Self::ExtMethodRequest(ext_request) => &ext_request.method,
5104        }
5105    }
5106}
5107
5108/// All possible responses that an agent can send to a client.
5109///
5110/// This enum is used internally for routing RPC responses. You typically won't need
5111/// to use this directly - the responses are handled automatically by the connection.
5112///
5113/// These are responses to the corresponding `ClientRequest` variants.
5114#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
5115#[serde(untagged)]
5116#[schemars(inline)]
5117#[non_exhaustive]
5118pub enum AgentResponse {
5119    /// Successful result returned for a `initialize` request.
5120    InitializeResponse(Box<InitializeResponse>),
5121    /// Successful result returned for a `authenticate` request.
5122    AuthenticateResponse(#[serde(default)] AuthenticateResponse),
5123    /// Successful result returned for a `providers/list` request.
5124    #[cfg(feature = "unstable_llm_providers")]
5125    ListProvidersResponse(ListProvidersResponse),
5126    /// Successful result returned for a `providers/set` request.
5127    #[cfg(feature = "unstable_llm_providers")]
5128    SetProviderResponse(#[serde(default)] SetProviderResponse),
5129    /// Successful result returned for a `providers/disable` request.
5130    #[cfg(feature = "unstable_llm_providers")]
5131    DisableProviderResponse(#[serde(default)] DisableProviderResponse),
5132    /// Successful result returned for a `logout` request.
5133    LogoutResponse(#[serde(default)] LogoutResponse),
5134    /// Successful result returned for a `session/new` request.
5135    NewSessionResponse(NewSessionResponse),
5136    /// Successful result returned for a `session/load` request.
5137    LoadSessionResponse(#[serde(default)] LoadSessionResponse),
5138    /// Successful result returned for a `session/list` request.
5139    ListSessionsResponse(ListSessionsResponse),
5140    /// Successful result returned for a `session/delete` request.
5141    DeleteSessionResponse(#[serde(default)] DeleteSessionResponse),
5142    /// Successful result returned for a `session/fork` request.
5143    #[cfg(feature = "unstable_session_fork")]
5144    ForkSessionResponse(ForkSessionResponse),
5145    /// Successful result returned for a `session/resume` request.
5146    ResumeSessionResponse(#[serde(default)] ResumeSessionResponse),
5147    /// Successful result returned for a `session/close` request.
5148    CloseSessionResponse(#[serde(default)] CloseSessionResponse),
5149    /// Successful result returned for a `session/set_config_option` request.
5150    SetSessionConfigOptionResponse(SetSessionConfigOptionResponse),
5151    /// Successful result returned for a `session/prompt` request.
5152    PromptResponse(PromptResponse),
5153    /// Successful result returned for a `nes/start` request.
5154    #[cfg(feature = "unstable_nes")]
5155    StartNesResponse(StartNesResponse),
5156    /// Successful result returned for a `nes/suggest` request.
5157    #[cfg(feature = "unstable_nes")]
5158    SuggestNesResponse(SuggestNesResponse),
5159    /// Successful result returned for a `nes/close` request.
5160    #[cfg(feature = "unstable_nes")]
5161    CloseNesResponse(#[serde(default)] CloseNesResponse),
5162    /// Successful result returned by an extension method outside the core ACP method set.
5163    ExtMethodResponse(ExtResponse),
5164    /// Successful result returned by an MCP-over-ACP `mcp/message` request.
5165    #[cfg(feature = "unstable_mcp_over_acp")]
5166    MessageMcpResponse(MessageMcpResponse),
5167}
5168
5169/// All possible notifications that a client can send to an agent.
5170///
5171/// This enum is used internally for routing RPC notifications. You typically won't need
5172/// to use this directly.
5173///
5174/// Notifications do not expect a response.
5175#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
5176#[serde(untagged)]
5177#[schemars(inline)]
5178#[non_exhaustive]
5179pub enum ClientNotification {
5180    /// Cancels ongoing operations for a session.
5181    ///
5182    /// This is a notification sent by the client to cancel active work in a
5183    /// session.
5184    ///
5185    /// Upon receiving this notification, the Agent SHOULD:
5186    /// - Stop all language model requests as soon as possible
5187    /// - Abort all tool call invocations in progress
5188    /// - Send any pending `session/update` notifications
5189    /// - Report an idle `state_update` with `StopReason::Cancelled` after
5190    ///   cancellation succeeds
5191    ///
5192    /// See protocol docs: [Cancellation](https://agentclientprotocol.com/protocol/prompt-lifecycle#cancellation)
5193    CancelNotification(CancelNotification),
5194    #[cfg(feature = "unstable_nes")]
5195    /// **UNSTABLE**
5196    ///
5197    /// Notification sent when a file is opened in the editor.
5198    DidOpenDocumentNotification(DidOpenDocumentNotification),
5199    #[cfg(feature = "unstable_nes")]
5200    /// **UNSTABLE**
5201    ///
5202    /// Notification sent when a file is edited.
5203    DidChangeDocumentNotification(DidChangeDocumentNotification),
5204    #[cfg(feature = "unstable_nes")]
5205    /// **UNSTABLE**
5206    ///
5207    /// Notification sent when a file is closed.
5208    DidCloseDocumentNotification(DidCloseDocumentNotification),
5209    #[cfg(feature = "unstable_nes")]
5210    /// **UNSTABLE**
5211    ///
5212    /// Notification sent when a file is saved.
5213    DidSaveDocumentNotification(DidSaveDocumentNotification),
5214    #[cfg(feature = "unstable_nes")]
5215    /// **UNSTABLE**
5216    ///
5217    /// Notification sent when a file becomes the active editor tab.
5218    DidFocusDocumentNotification(Box<DidFocusDocumentNotification>),
5219    #[cfg(feature = "unstable_nes")]
5220    /// **UNSTABLE**
5221    ///
5222    /// Notification sent when a suggestion is accepted.
5223    AcceptNesNotification(AcceptNesNotification),
5224    #[cfg(feature = "unstable_nes")]
5225    /// **UNSTABLE**
5226    ///
5227    /// Notification sent when a suggestion is rejected.
5228    RejectNesNotification(RejectNesNotification),
5229    /// **UNSTABLE**
5230    ///
5231    /// This capability is not part of the spec yet, and may be removed or changed at any point.
5232    ///
5233    /// Sends an MCP-over-ACP notification.
5234    #[cfg(feature = "unstable_mcp_over_acp")]
5235    MessageMcpNotification(MessageMcpNotification),
5236    /// Handles extension notifications from the client.
5237    ///
5238    /// Extension notifications provide a way to send one-way messages for custom functionality
5239    /// while maintaining protocol compatibility.
5240    ///
5241    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
5242    ExtNotification(ExtNotification),
5243}
5244
5245impl ClientNotification {
5246    /// Returns the corresponding method name of the notification.
5247    #[must_use]
5248    pub fn method(&self) -> &str {
5249        match self {
5250            Self::CancelNotification(_) => AGENT_METHOD_NAMES.session_cancel,
5251            #[cfg(feature = "unstable_nes")]
5252            Self::DidOpenDocumentNotification(_) => AGENT_METHOD_NAMES.document_did_open,
5253            #[cfg(feature = "unstable_nes")]
5254            Self::DidChangeDocumentNotification(_) => AGENT_METHOD_NAMES.document_did_change,
5255            #[cfg(feature = "unstable_nes")]
5256            Self::DidCloseDocumentNotification(_) => AGENT_METHOD_NAMES.document_did_close,
5257            #[cfg(feature = "unstable_nes")]
5258            Self::DidSaveDocumentNotification(_) => AGENT_METHOD_NAMES.document_did_save,
5259            #[cfg(feature = "unstable_nes")]
5260            Self::DidFocusDocumentNotification(_) => AGENT_METHOD_NAMES.document_did_focus,
5261            #[cfg(feature = "unstable_nes")]
5262            Self::AcceptNesNotification(_) => AGENT_METHOD_NAMES.nes_accept,
5263            #[cfg(feature = "unstable_nes")]
5264            Self::RejectNesNotification(_) => AGENT_METHOD_NAMES.nes_reject,
5265            #[cfg(feature = "unstable_mcp_over_acp")]
5266            Self::MessageMcpNotification(_) => AGENT_METHOD_NAMES.mcp_message,
5267            Self::ExtNotification(ext_notification) => &ext_notification.method,
5268        }
5269    }
5270}
5271
5272/// Notification to cancel ongoing operations for a session.
5273///
5274/// See protocol docs: [Cancellation](https://agentclientprotocol.com/protocol/prompt-lifecycle#cancellation)
5275#[skip_serializing_none]
5276#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
5277#[schemars(extend("x-side" = "agent", "x-method" = SESSION_CANCEL_METHOD_NAME))]
5278#[serde(rename_all = "camelCase")]
5279#[non_exhaustive]
5280pub struct CancelNotification {
5281    /// The ID of the session to cancel operations for.
5282    pub session_id: SessionId,
5283    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
5284    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
5285    /// these keys.
5286    ///
5287    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
5288    #[serde(rename = "_meta")]
5289    pub meta: Option<Meta>,
5290}
5291
5292impl CancelNotification {
5293    /// Builds [`CancelNotification`] with the required notification fields set; optional fields start unset or empty.
5294    #[must_use]
5295    pub fn new(session_id: impl Into<SessionId>) -> Self {
5296        Self {
5297            session_id: session_id.into(),
5298            meta: None,
5299        }
5300    }
5301
5302    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
5303    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
5304    /// these keys.
5305    ///
5306    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
5307    #[must_use]
5308    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
5309        self.meta = meta.into_option();
5310        self
5311    }
5312}
5313
5314#[cfg(test)]
5315mod test_serialization {
5316    use super::*;
5317    use serde_json::json;
5318
5319    fn test_meta() -> Meta {
5320        json!({ "source": "test" }).as_object().unwrap().clone()
5321    }
5322
5323    fn serialized_meta_key_count(value: &impl serde::Serialize) -> usize {
5324        serde_json::to_string(value)
5325            .unwrap()
5326            .matches("\"_meta\"")
5327            .count()
5328    }
5329
5330    #[test]
5331    fn test_mcp_server_stdio_serialization() {
5332        let server = McpServer::Stdio(
5333            McpServerStdio::new("test-server", "/usr/bin/server")
5334                .args(vec!["--port".to_string(), "3000".to_string()])
5335                .env(vec![EnvVariable::new("API_KEY", "secret123")]),
5336        );
5337
5338        let json = serde_json::to_value(&server).unwrap();
5339        assert_eq!(
5340            json,
5341            json!({
5342                "type": "stdio",
5343                "name": "test-server",
5344                "command": "/usr/bin/server",
5345                "args": ["--port", "3000"],
5346                "env": [
5347                    {
5348                        "name": "API_KEY",
5349                        "value": "secret123"
5350                    }
5351                ]
5352            })
5353        );
5354
5355        let deserialized: McpServer = serde_json::from_value(json).unwrap();
5356        match deserialized {
5357            McpServer::Stdio(McpServerStdio {
5358                name,
5359                command,
5360                args,
5361                env,
5362                meta: _,
5363            }) => {
5364                assert_eq!(name, "test-server");
5365                assert_eq!(command, PathBuf::from("/usr/bin/server"));
5366                assert_eq!(args, vec!["--port", "3000"]);
5367                assert_eq!(env.len(), 1);
5368                assert_eq!(env[0].name, "API_KEY");
5369                assert_eq!(env[0].value, "secret123");
5370            }
5371            _ => panic!("Expected Stdio variant"),
5372        }
5373    }
5374
5375    #[test]
5376    fn test_mcp_server_unknown_transport_serialization() {
5377        let json = json!({
5378            "type": "websocket",
5379            "name": "future-server",
5380            "url": "wss://example.com/mcp",
5381            "protocolVersion": "2026-01-01"
5382        });
5383
5384        let deserialized: McpServer = serde_json::from_value(json.clone()).unwrap();
5385        let McpServer::Other(OtherMcpServer { type_, fields }) = &deserialized else {
5386            panic!("Expected Other variant");
5387        };
5388
5389        assert_eq!(type_, "websocket");
5390        assert_eq!(fields["name"], "future-server");
5391        assert_eq!(fields["url"], "wss://example.com/mcp");
5392        assert_eq!(fields["protocolVersion"], "2026-01-01");
5393        assert_eq!(serde_json::to_value(&deserialized).unwrap(), json);
5394    }
5395
5396    #[test]
5397    fn test_mcp_server_stdio_requires_type() {
5398        let result = serde_json::from_value::<McpServer>(json!({
5399            "name": "test-server",
5400            "command": "/usr/bin/server",
5401            "args": [],
5402            "env": []
5403        }));
5404
5405        assert!(result.is_err());
5406    }
5407
5408    #[test]
5409    fn test_mcp_server_unknown_does_not_hide_malformed_known_transport() {
5410        let result = serde_json::from_value::<McpServer>(json!({
5411            "type": "stdio",
5412            "name": "test-server",
5413            "args": [],
5414            "env": []
5415        }));
5416
5417        assert!(result.is_err());
5418    }
5419
5420    #[test]
5421    fn test_mcp_server_http_serialization() {
5422        let server = McpServer::Http(
5423            McpServerHttp::new("http-server", "https://api.example.com").headers(vec![
5424                HttpHeader::new("Authorization", "Bearer token123"),
5425                HttpHeader::new("Content-Type", "application/json"),
5426            ]),
5427        );
5428
5429        let json = serde_json::to_value(&server).unwrap();
5430        assert_eq!(
5431            json,
5432            json!({
5433                "type": "http",
5434                "name": "http-server",
5435                "url": "https://api.example.com",
5436                "headers": [
5437                    {
5438                        "name": "Authorization",
5439                        "value": "Bearer token123"
5440                    },
5441                    {
5442                        "name": "Content-Type",
5443                        "value": "application/json"
5444                    }
5445                ]
5446            })
5447        );
5448
5449        let deserialized: McpServer = serde_json::from_value(json).unwrap();
5450        match deserialized {
5451            McpServer::Http(McpServerHttp {
5452                name,
5453                url,
5454                headers,
5455                meta: _,
5456            }) => {
5457                assert_eq!(name, "http-server");
5458                assert_eq!(url, "https://api.example.com");
5459                assert_eq!(headers.len(), 2);
5460                assert_eq!(headers[0].name, "Authorization");
5461                assert_eq!(headers[0].value, "Bearer token123");
5462                assert_eq!(headers[1].name, "Content-Type");
5463                assert_eq!(headers[1].value, "application/json");
5464            }
5465            _ => panic!("Expected Http variant"),
5466        }
5467    }
5468
5469    #[cfg(feature = "unstable_mcp_over_acp")]
5470    #[test]
5471    fn test_client_mcp_message_method_names() {
5472        assert_eq!(AGENT_METHOD_NAMES.mcp_message, "mcp/message");
5473
5474        assert_eq!(
5475            ClientRequest::MessageMcpRequest(MessageMcpRequest::new("conn-1", "tools/list"))
5476                .method(),
5477            "mcp/message"
5478        );
5479        assert_eq!(
5480            ClientNotification::MessageMcpNotification(MessageMcpNotification::new(
5481                "conn-1",
5482                "notifications/progress"
5483            ))
5484            .method(),
5485            "mcp/message"
5486        );
5487    }
5488
5489    #[test]
5490    fn test_session_config_option_category_known_variants() {
5491        // Test serialization of known variants
5492        assert_eq!(
5493            serde_json::to_value(&SessionConfigOptionCategory::Mode).unwrap(),
5494            json!("mode")
5495        );
5496        assert_eq!(
5497            serde_json::to_value(&SessionConfigOptionCategory::Model).unwrap(),
5498            json!("model")
5499        );
5500        #[cfg(feature = "unstable_model_config_category")]
5501        assert_eq!(
5502            serde_json::to_value(&SessionConfigOptionCategory::ModelConfig).unwrap(),
5503            json!("model_config")
5504        );
5505        assert_eq!(
5506            serde_json::to_value(&SessionConfigOptionCategory::ThoughtLevel).unwrap(),
5507            json!("thought_level")
5508        );
5509
5510        // Test deserialization of known variants
5511        assert_eq!(
5512            serde_json::from_str::<SessionConfigOptionCategory>("\"mode\"").unwrap(),
5513            SessionConfigOptionCategory::Mode
5514        );
5515        assert_eq!(
5516            serde_json::from_str::<SessionConfigOptionCategory>("\"model\"").unwrap(),
5517            SessionConfigOptionCategory::Model
5518        );
5519        #[cfg(feature = "unstable_model_config_category")]
5520        assert_eq!(
5521            serde_json::from_str::<SessionConfigOptionCategory>("\"model_config\"").unwrap(),
5522            SessionConfigOptionCategory::ModelConfig
5523        );
5524        assert_eq!(
5525            serde_json::from_str::<SessionConfigOptionCategory>("\"thought_level\"").unwrap(),
5526            SessionConfigOptionCategory::ThoughtLevel
5527        );
5528    }
5529
5530    #[test]
5531    fn test_session_config_option_category_unknown_variants() {
5532        // Test that unknown strings are captured in Other variant
5533        let unknown: SessionConfigOptionCategory =
5534            serde_json::from_str("\"some_future_category\"").unwrap();
5535        assert_eq!(
5536            unknown,
5537            SessionConfigOptionCategory::Other("some_future_category".to_string())
5538        );
5539
5540        // Test round-trip of unknown category
5541        let json = serde_json::to_value(&unknown).unwrap();
5542        assert_eq!(json, json!("some_future_category"));
5543    }
5544
5545    #[cfg(not(feature = "unstable_model_config_category"))]
5546    #[test]
5547    fn test_session_config_option_model_config_is_unknown_without_feature() {
5548        let unknown: SessionConfigOptionCategory =
5549            serde_json::from_str("\"model_config\"").unwrap();
5550        assert_eq!(
5551            unknown,
5552            SessionConfigOptionCategory::Other("model_config".to_string())
5553        );
5554    }
5555
5556    #[test]
5557    fn test_session_config_option_category_custom_categories() {
5558        // Category names beginning with `_` are free for custom use
5559        let custom: SessionConfigOptionCategory =
5560            serde_json::from_str("\"_my_custom_category\"").unwrap();
5561        assert_eq!(
5562            custom,
5563            SessionConfigOptionCategory::Other("_my_custom_category".to_string())
5564        );
5565
5566        // Test round-trip preserves the custom category name
5567        let json = serde_json::to_value(&custom).unwrap();
5568        assert_eq!(json, json!("_my_custom_category"));
5569
5570        // Deserialize back and verify
5571        let deserialized: SessionConfigOptionCategory = serde_json::from_value(json).unwrap();
5572        assert_eq!(
5573            deserialized,
5574            SessionConfigOptionCategory::Other("_my_custom_category".to_string()),
5575        );
5576    }
5577
5578    #[test]
5579    fn test_auth_method_agent_serialization() {
5580        let method = AuthMethod::Agent(AuthMethodAgent::new("default-auth", "Default Auth"));
5581
5582        let json = serde_json::to_value(&method).unwrap();
5583        assert_eq!(
5584            json,
5585            json!({
5586                "id": "default-auth",
5587                "name": "Default Auth",
5588                "type": "agent"
5589            })
5590        );
5591        // description should be omitted when None
5592        assert!(!json.as_object().unwrap().contains_key("description"));
5593
5594        let deserialized: AuthMethod = serde_json::from_value(json).unwrap();
5595        match deserialized {
5596            AuthMethod::Agent(AuthMethodAgent { id, name, .. }) => {
5597                assert_eq!(id.0.as_ref(), "default-auth");
5598                assert_eq!(name, "Default Auth");
5599            }
5600            _ => panic!("Expected Agent variant"),
5601        }
5602    }
5603
5604    #[test]
5605    fn test_auth_method_agent_deserialization() {
5606        let json = json!({
5607            "id": "agent-auth",
5608            "name": "Agent Auth",
5609            "type": "agent"
5610        });
5611
5612        let deserialized: AuthMethod = serde_json::from_value(json).unwrap();
5613        assert!(matches!(deserialized, AuthMethod::Agent(_)));
5614    }
5615
5616    #[test]
5617    fn test_auth_method_agent_requires_type() {
5618        assert!(
5619            serde_json::from_value::<AuthMethod>(json!({
5620                "id": "agent-auth",
5621                "name": "Agent Auth"
5622            }))
5623            .is_err()
5624        );
5625    }
5626
5627    #[test]
5628    fn test_auth_method_agent_rejects_null_type() {
5629        assert!(
5630            serde_json::from_value::<AuthMethod>(json!({
5631                "id": "agent-auth",
5632                "name": "Agent Auth",
5633                "type": null
5634            }))
5635            .is_err()
5636        );
5637    }
5638
5639    #[test]
5640    fn test_auth_method_unknown_does_not_hide_malformed_agent() {
5641        assert!(
5642            serde_json::from_value::<AuthMethod>(json!({
5643                "id": "agent-auth",
5644                "type": "agent"
5645            }))
5646            .is_err()
5647        );
5648    }
5649
5650    #[test]
5651    fn test_auth_method_unknown_variant_roundtrip() {
5652        let method: AuthMethod = serde_json::from_value(json!({
5653            "id": "oauth",
5654            "name": "OAuth",
5655            "type": "_oauth",
5656            "authorizationUrl": "https://example.com/auth"
5657        }))
5658        .unwrap();
5659
5660        assert_eq!(method.id().0.as_ref(), "oauth");
5661        assert_eq!(method.name(), "OAuth");
5662        let AuthMethod::Other(unknown) = method else {
5663            panic!("expected unknown auth method");
5664        };
5665        assert_eq!(unknown.type_, "_oauth");
5666        assert_eq!(
5667            unknown.fields.get("authorizationUrl"),
5668            Some(&json!("https://example.com/auth"))
5669        );
5670
5671        assert_eq!(
5672            serde_json::to_value(AuthMethod::Other(unknown)).unwrap(),
5673            json!({
5674                "id": "oauth",
5675                "name": "OAuth",
5676                "type": "_oauth",
5677                "authorizationUrl": "https://example.com/auth"
5678            })
5679        );
5680    }
5681
5682    #[cfg(feature = "unstable_auth_methods")]
5683    #[test]
5684    fn test_auth_method_unknown_does_not_hide_malformed_known_variant() {
5685        assert!(
5686            serde_json::from_value::<AuthMethod>(json!({
5687                "id": "api-key",
5688                "name": "API Key",
5689                "type": "env_var"
5690            }))
5691            .is_err()
5692        );
5693    }
5694
5695    #[test]
5696    fn test_session_delete_serialization() {
5697        assert_eq!(AGENT_METHOD_NAMES.session_delete, "session/delete");
5698        assert_eq!(
5699            ClientRequest::DeleteSessionRequest(DeleteSessionRequest::new("sess_abc123")).method(),
5700            "session/delete"
5701        );
5702        assert_eq!(
5703            serde_json::to_value(DeleteSessionRequest::new("sess_abc123")).unwrap(),
5704            json!({
5705                "sessionId": "sess_abc123"
5706            })
5707        );
5708        assert_eq!(
5709            serde_json::to_value(DeleteSessionResponse::new()).unwrap(),
5710            json!({})
5711        );
5712        assert_eq!(
5713            serde_json::to_value(
5714                SessionCapabilities::new().delete(SessionDeleteCapabilities::new())
5715            )
5716            .unwrap(),
5717            json!({
5718                "delete": {}
5719            })
5720        );
5721    }
5722    #[test]
5723    fn test_session_additional_directories_serialization() {
5724        assert_eq!(
5725            serde_json::to_value(NewSessionRequest::new("/home/user/project")).unwrap(),
5726            json!({
5727                "cwd": "/home/user/project",
5728                "mcpServers": []
5729            })
5730        );
5731        assert_eq!(
5732            serde_json::to_value(
5733                NewSessionRequest::new("/home/user/project").additional_directories(vec![
5734                    PathBuf::from("/home/user/shared-lib"),
5735                    PathBuf::from("/home/user/product-docs"),
5736                ])
5737            )
5738            .unwrap(),
5739            json!({
5740                "cwd": "/home/user/project",
5741                "additionalDirectories": [
5742                    "/home/user/shared-lib",
5743                    "/home/user/product-docs"
5744                ],
5745                "mcpServers": []
5746            })
5747        );
5748        assert_eq!(
5749            serde_json::to_value(SessionInfo::new("sess_abc123", "/home/user/project")).unwrap(),
5750            json!({
5751                "sessionId": "sess_abc123",
5752                "cwd": "/home/user/project"
5753            })
5754        );
5755        assert_eq!(
5756            serde_json::to_value(
5757                SessionInfo::new("sess_abc123", "/home/user/project").additional_directories(vec![
5758                    PathBuf::from("/home/user/shared-lib"),
5759                    PathBuf::from("/home/user/product-docs"),
5760                ])
5761            )
5762            .unwrap(),
5763            json!({
5764                "sessionId": "sess_abc123",
5765                "cwd": "/home/user/project",
5766                "additionalDirectories": [
5767                    "/home/user/shared-lib",
5768                    "/home/user/product-docs"
5769                ]
5770            })
5771        );
5772        assert_eq!(
5773            serde_json::from_value::<SessionInfo>(json!({
5774                "sessionId": "sess_abc123",
5775                "cwd": "/home/user/project"
5776            }))
5777            .unwrap()
5778            .additional_directories,
5779            Vec::<PathBuf>::new()
5780        );
5781    }
5782    #[test]
5783    fn test_session_load_capabilities_serialization() {
5784        assert_eq!(
5785            serde_json::to_value(SessionCapabilities::new().load(SessionLoadCapabilities::new()))
5786                .unwrap(),
5787            json!({
5788                "load": {}
5789            })
5790        );
5791    }
5792
5793    #[test]
5794    fn test_session_additional_directories_capabilities_serialization() {
5795        assert_eq!(
5796            serde_json::to_value(
5797                SessionCapabilities::new()
5798                    .additional_directories(SessionAdditionalDirectoriesCapabilities::new())
5799            )
5800            .unwrap(),
5801            json!({
5802                "additionalDirectories": {}
5803            })
5804        );
5805    }
5806
5807    #[cfg(feature = "unstable_auth_methods")]
5808    #[test]
5809    fn test_auth_method_env_var_serialization() {
5810        let method = AuthMethod::EnvVar(AuthMethodEnvVar::new(
5811            "api-key",
5812            "API Key",
5813            vec![AuthEnvVar::new("API_KEY")],
5814        ));
5815
5816        let json = serde_json::to_value(&method).unwrap();
5817        assert_eq!(
5818            json,
5819            json!({
5820                "id": "api-key",
5821                "name": "API Key",
5822                "type": "env_var",
5823                "vars": [{"name": "API_KEY"}]
5824            })
5825        );
5826        // secret defaults to true and should be omitted; optional defaults to false and should be omitted
5827        assert!(!json["vars"][0].as_object().unwrap().contains_key("secret"));
5828        assert!(
5829            !json["vars"][0]
5830                .as_object()
5831                .unwrap()
5832                .contains_key("optional")
5833        );
5834
5835        let deserialized: AuthMethod = serde_json::from_value(json).unwrap();
5836        match deserialized {
5837            AuthMethod::EnvVar(AuthMethodEnvVar {
5838                id,
5839                name: method_name,
5840                vars,
5841                link,
5842                ..
5843            }) => {
5844                assert_eq!(id.0.as_ref(), "api-key");
5845                assert_eq!(method_name, "API Key");
5846                assert_eq!(vars.len(), 1);
5847                assert_eq!(vars[0].name, "API_KEY");
5848                assert!(vars[0].secret);
5849                assert!(!vars[0].optional);
5850                assert!(link.is_none());
5851            }
5852            _ => panic!("Expected EnvVar variant"),
5853        }
5854    }
5855
5856    #[cfg(feature = "unstable_auth_methods")]
5857    #[test]
5858    fn test_auth_method_env_var_with_link_serialization() {
5859        let method = AuthMethod::EnvVar(
5860            AuthMethodEnvVar::new("api-key", "API Key", vec![AuthEnvVar::new("API_KEY")])
5861                .link("https://example.com/keys"),
5862        );
5863
5864        let json = serde_json::to_value(&method).unwrap();
5865        assert_eq!(
5866            json,
5867            json!({
5868                "id": "api-key",
5869                "name": "API Key",
5870                "type": "env_var",
5871                "vars": [{"name": "API_KEY"}],
5872                "link": "https://example.com/keys"
5873            })
5874        );
5875
5876        let deserialized: AuthMethod = serde_json::from_value(json).unwrap();
5877        match deserialized {
5878            AuthMethod::EnvVar(AuthMethodEnvVar { link, .. }) => {
5879                assert_eq!(link.as_deref(), Some("https://example.com/keys"));
5880            }
5881            _ => panic!("Expected EnvVar variant"),
5882        }
5883    }
5884
5885    #[cfg(feature = "unstable_auth_methods")]
5886    #[test]
5887    fn test_auth_method_env_var_multiple_vars() {
5888        let method = AuthMethod::EnvVar(AuthMethodEnvVar::new(
5889            "azure-openai",
5890            "Azure OpenAI",
5891            vec![
5892                AuthEnvVar::new("AZURE_OPENAI_API_KEY").label("API Key"),
5893                AuthEnvVar::new("AZURE_OPENAI_ENDPOINT")
5894                    .label("Endpoint URL")
5895                    .secret(false),
5896                AuthEnvVar::new("AZURE_OPENAI_API_VERSION")
5897                    .label("API Version")
5898                    .secret(false)
5899                    .optional(true),
5900            ],
5901        ));
5902
5903        let json = serde_json::to_value(&method).unwrap();
5904        assert_eq!(
5905            json,
5906            json!({
5907                "id": "azure-openai",
5908                "name": "Azure OpenAI",
5909                "type": "env_var",
5910                "vars": [
5911                    {"name": "AZURE_OPENAI_API_KEY", "label": "API Key"},
5912                    {"name": "AZURE_OPENAI_ENDPOINT", "label": "Endpoint URL", "secret": false},
5913                    {"name": "AZURE_OPENAI_API_VERSION", "label": "API Version", "secret": false, "optional": true}
5914                ]
5915            })
5916        );
5917
5918        let deserialized: AuthMethod = serde_json::from_value(json).unwrap();
5919        match deserialized {
5920            AuthMethod::EnvVar(AuthMethodEnvVar { vars, .. }) => {
5921                assert_eq!(vars.len(), 3);
5922                // First var: secret (default true), not optional (default false)
5923                assert_eq!(vars[0].name, "AZURE_OPENAI_API_KEY");
5924                assert_eq!(vars[0].label.as_deref(), Some("API Key"));
5925                assert!(vars[0].secret);
5926                assert!(!vars[0].optional);
5927                // Second var: not a secret, not optional
5928                assert_eq!(vars[1].name, "AZURE_OPENAI_ENDPOINT");
5929                assert!(!vars[1].secret);
5930                assert!(!vars[1].optional);
5931                // Third var: not a secret, optional
5932                assert_eq!(vars[2].name, "AZURE_OPENAI_API_VERSION");
5933                assert!(!vars[2].secret);
5934                assert!(vars[2].optional);
5935            }
5936            _ => panic!("Expected EnvVar variant"),
5937        }
5938    }
5939
5940    #[cfg(feature = "unstable_auth_methods")]
5941    #[test]
5942    fn test_auth_method_terminal_serialization() {
5943        let method = AuthMethod::Terminal(AuthMethodTerminal::new("tui-auth", "Terminal Auth"));
5944
5945        let json = serde_json::to_value(&method).unwrap();
5946        assert_eq!(
5947            json,
5948            json!({
5949                "id": "tui-auth",
5950                "name": "Terminal Auth",
5951                "type": "terminal"
5952            })
5953        );
5954        // args and env should be omitted when empty
5955        assert!(!json.as_object().unwrap().contains_key("args"));
5956        assert!(!json.as_object().unwrap().contains_key("env"));
5957
5958        let deserialized: AuthMethod = serde_json::from_value(json).unwrap();
5959        match deserialized {
5960            AuthMethod::Terminal(AuthMethodTerminal { args, env, .. }) => {
5961                assert!(args.is_empty());
5962                assert!(env.is_empty());
5963            }
5964            _ => panic!("Expected Terminal variant"),
5965        }
5966    }
5967
5968    #[cfg(feature = "unstable_auth_methods")]
5969    #[test]
5970    fn test_auth_method_terminal_with_args_and_env_serialization() {
5971        use std::collections::HashMap;
5972
5973        let mut env = HashMap::new();
5974        env.insert("TERM".to_string(), "xterm-256color".to_string());
5975
5976        let method = AuthMethod::Terminal(
5977            AuthMethodTerminal::new("tui-auth", "Terminal Auth")
5978                .args(vec!["--interactive".to_string(), "--color".to_string()])
5979                .env(env),
5980        );
5981
5982        let json = serde_json::to_value(&method).unwrap();
5983        assert_eq!(
5984            json,
5985            json!({
5986                "id": "tui-auth",
5987                "name": "Terminal Auth",
5988                "type": "terminal",
5989                "args": ["--interactive", "--color"],
5990                "env": {
5991                    "TERM": "xterm-256color"
5992                }
5993            })
5994        );
5995
5996        let deserialized: AuthMethod = serde_json::from_value(json).unwrap();
5997        match deserialized {
5998            AuthMethod::Terminal(AuthMethodTerminal { args, env, .. }) => {
5999                assert_eq!(args, vec!["--interactive", "--color"]);
6000                assert_eq!(env.len(), 1);
6001                assert_eq!(env.get("TERM").unwrap(), "xterm-256color");
6002            }
6003            _ => panic!("Expected Terminal variant"),
6004        }
6005    }
6006
6007    #[cfg(feature = "unstable_boolean_config")]
6008    #[test]
6009    fn test_session_config_option_value_id_serialize() {
6010        let val = SessionConfigOptionValue::value_id("model-1");
6011        let json = serde_json::to_value(&val).unwrap();
6012        // ValueId omits the "type" field (it's the default)
6013        assert_eq!(json, json!({ "value": "model-1" }));
6014        assert!(!json.as_object().unwrap().contains_key("type"));
6015    }
6016
6017    #[cfg(feature = "unstable_boolean_config")]
6018    #[test]
6019    fn test_session_config_option_value_boolean_serialize() {
6020        let val = SessionConfigOptionValue::boolean(true);
6021        let json = serde_json::to_value(&val).unwrap();
6022        assert_eq!(json, json!({ "type": "boolean", "value": true }));
6023    }
6024
6025    #[cfg(feature = "unstable_boolean_config")]
6026    #[test]
6027    fn test_session_config_option_value_deserialize_no_type() {
6028        // Missing "type" should default to ValueId
6029        let json = json!({ "value": "model-1" });
6030        let val: SessionConfigOptionValue = serde_json::from_value(json).unwrap();
6031        assert_eq!(val, SessionConfigOptionValue::value_id("model-1"));
6032        assert_eq!(val.as_value_id().unwrap().to_string(), "model-1");
6033    }
6034
6035    #[cfg(feature = "unstable_boolean_config")]
6036    #[test]
6037    fn test_session_config_option_value_deserialize_boolean() {
6038        let json = json!({ "type": "boolean", "value": true });
6039        let val: SessionConfigOptionValue = serde_json::from_value(json).unwrap();
6040        assert_eq!(val, SessionConfigOptionValue::boolean(true));
6041        assert_eq!(val.as_bool(), Some(true));
6042    }
6043
6044    #[cfg(feature = "unstable_boolean_config")]
6045    #[test]
6046    fn test_session_config_option_value_deserialize_boolean_false() {
6047        let json = json!({ "type": "boolean", "value": false });
6048        let val: SessionConfigOptionValue = serde_json::from_value(json).unwrap();
6049        assert_eq!(val, SessionConfigOptionValue::boolean(false));
6050        assert_eq!(val.as_bool(), Some(false));
6051    }
6052
6053    #[cfg(feature = "unstable_boolean_config")]
6054    #[test]
6055    fn test_session_config_option_value_deserialize_unknown_type_with_string_value() {
6056        // Unknown type with a string value gracefully falls back to ValueId
6057        let json = json!({ "type": "text", "value": "freeform input" });
6058        let val: SessionConfigOptionValue = serde_json::from_value(json).unwrap();
6059        assert_eq!(val.as_value_id().unwrap().to_string(), "freeform input");
6060    }
6061
6062    #[cfg(feature = "unstable_boolean_config")]
6063    #[test]
6064    fn test_session_config_option_value_roundtrip_value_id() {
6065        let original = SessionConfigOptionValue::value_id("option-a");
6066        let json = serde_json::to_value(&original).unwrap();
6067        let roundtripped: SessionConfigOptionValue = serde_json::from_value(json).unwrap();
6068        assert_eq!(original, roundtripped);
6069    }
6070
6071    #[cfg(feature = "unstable_boolean_config")]
6072    #[test]
6073    fn test_session_config_option_value_roundtrip_boolean() {
6074        let original = SessionConfigOptionValue::boolean(false);
6075        let json = serde_json::to_value(&original).unwrap();
6076        let roundtripped: SessionConfigOptionValue = serde_json::from_value(json).unwrap();
6077        assert_eq!(original, roundtripped);
6078    }
6079
6080    #[cfg(feature = "unstable_boolean_config")]
6081    #[test]
6082    fn test_session_config_option_value_type_mismatch_boolean_with_string() {
6083        // type says "boolean" but value is a string — falls to untagged ValueId
6084        let json = json!({ "type": "boolean", "value": "not a bool" });
6085        let result = serde_json::from_value::<SessionConfigOptionValue>(json);
6086        // serde tries Boolean first (fails), then falls to untagged ValueId (succeeds)
6087        assert!(result.is_ok());
6088        assert_eq!(
6089            result.unwrap().as_value_id().unwrap().to_string(),
6090            "not a bool"
6091        );
6092    }
6093
6094    #[cfg(feature = "unstable_boolean_config")]
6095    #[test]
6096    fn test_session_config_option_value_from_impls() {
6097        let from_str: SessionConfigOptionValue = "model-1".into();
6098        assert_eq!(from_str.as_value_id().unwrap().to_string(), "model-1");
6099
6100        let from_id: SessionConfigOptionValue = SessionConfigValueId::new("model-2").into();
6101        assert_eq!(from_id.as_value_id().unwrap().to_string(), "model-2");
6102
6103        let from_bool: SessionConfigOptionValue = true.into();
6104        assert_eq!(from_bool.as_bool(), Some(true));
6105    }
6106
6107    #[cfg(feature = "unstable_boolean_config")]
6108    #[test]
6109    fn test_set_session_config_option_request_value_id() {
6110        let req = SetSessionConfigOptionRequest::new("sess_1", "model", "model-1");
6111        let json = serde_json::to_value(&req).unwrap();
6112        assert_eq!(
6113            json,
6114            json!({
6115                "sessionId": "sess_1",
6116                "configId": "model",
6117                "value": "model-1"
6118            })
6119        );
6120        // No "type" field for value_id
6121        assert!(!json.as_object().unwrap().contains_key("type"));
6122    }
6123
6124    #[cfg(feature = "unstable_boolean_config")]
6125    #[test]
6126    fn test_set_session_config_option_request_boolean() {
6127        let req = SetSessionConfigOptionRequest::new("sess_1", "brave_mode", true);
6128        let json = serde_json::to_value(&req).unwrap();
6129        assert_eq!(
6130            json,
6131            json!({
6132                "sessionId": "sess_1",
6133                "configId": "brave_mode",
6134                "type": "boolean",
6135                "value": true
6136            })
6137        );
6138    }
6139
6140    #[cfg(feature = "unstable_boolean_config")]
6141    #[test]
6142    fn test_set_session_config_option_request_deserialize_no_type() {
6143        // Backwards-compatible: no "type" field → value_id
6144        let json = json!({
6145            "sessionId": "sess_1",
6146            "configId": "model",
6147            "value": "model-1"
6148        });
6149        let req: SetSessionConfigOptionRequest = serde_json::from_value(json).unwrap();
6150        assert_eq!(req.session_id.to_string(), "sess_1");
6151        assert_eq!(req.config_id.to_string(), "model");
6152        assert_eq!(req.value.as_value_id().unwrap().to_string(), "model-1");
6153    }
6154
6155    #[cfg(feature = "unstable_boolean_config")]
6156    #[test]
6157    fn test_set_session_config_option_request_deserialize_boolean() {
6158        let json = json!({
6159            "sessionId": "sess_1",
6160            "configId": "brave_mode",
6161            "type": "boolean",
6162            "value": true
6163        });
6164        let req: SetSessionConfigOptionRequest = serde_json::from_value(json).unwrap();
6165        assert_eq!(req.value.as_bool(), Some(true));
6166    }
6167
6168    #[cfg(feature = "unstable_boolean_config")]
6169    #[test]
6170    fn test_set_session_config_option_request_roundtrip_value_id() {
6171        let original = SetSessionConfigOptionRequest::new("s", "c", "v");
6172        let json = serde_json::to_value(&original).unwrap();
6173        let roundtripped: SetSessionConfigOptionRequest = serde_json::from_value(json).unwrap();
6174        assert_eq!(original, roundtripped);
6175    }
6176
6177    #[cfg(feature = "unstable_boolean_config")]
6178    #[test]
6179    fn test_set_session_config_option_request_roundtrip_boolean() {
6180        let original = SetSessionConfigOptionRequest::new("s", "c", false);
6181        let json = serde_json::to_value(&original).unwrap();
6182        let roundtripped: SetSessionConfigOptionRequest = serde_json::from_value(json).unwrap();
6183        assert_eq!(original, roundtripped);
6184    }
6185
6186    #[cfg(feature = "unstable_boolean_config")]
6187    #[test]
6188    fn test_session_config_boolean_serialization() {
6189        let cfg = SessionConfigBoolean::new(true);
6190        let json = serde_json::to_value(&cfg).unwrap();
6191        assert_eq!(json, json!({ "currentValue": true }));
6192
6193        let deserialized: SessionConfigBoolean = serde_json::from_value(json).unwrap();
6194        assert!(deserialized.current_value);
6195    }
6196
6197    #[cfg(feature = "unstable_boolean_config")]
6198    #[test]
6199    fn test_session_config_option_boolean_variant() {
6200        let opt = SessionConfigOption::boolean("brave_mode", "Brave Mode", false)
6201            .description("Skip confirmation prompts")
6202            .meta(test_meta());
6203        assert_eq!(serialized_meta_key_count(&opt), 1);
6204
6205        let json = serde_json::to_value(&opt).unwrap();
6206        assert_eq!(
6207            json,
6208            json!({
6209                "id": "brave_mode",
6210                "name": "Brave Mode",
6211                "description": "Skip confirmation prompts",
6212                "type": "boolean",
6213                "currentValue": false,
6214                "_meta": {
6215                    "source": "test"
6216                }
6217            })
6218        );
6219
6220        let deserialized: SessionConfigOption = serde_json::from_value(json).unwrap();
6221        assert_eq!(deserialized.id.to_string(), "brave_mode");
6222        assert_eq!(deserialized.name, "Brave Mode");
6223        match deserialized.kind {
6224            SessionConfigKind::Boolean(ref b) => assert!(!b.current_value),
6225            _ => panic!("Expected Boolean kind"),
6226        }
6227    }
6228
6229    #[cfg(feature = "unstable_boolean_config")]
6230    #[test]
6231    fn test_session_config_option_select_still_works() {
6232        // Make sure existing select options are unaffected
6233        let opt = SessionConfigOption::select(
6234            "model",
6235            "Model",
6236            "model-1",
6237            vec![
6238                SessionConfigSelectOption::new("model-1", "Model 1"),
6239                SessionConfigSelectOption::new("model-2", "Model 2"),
6240            ],
6241        )
6242        .meta(test_meta());
6243        assert_eq!(serialized_meta_key_count(&opt), 1);
6244
6245        let json = serde_json::to_value(&opt).unwrap();
6246        assert_eq!(json["type"], "select");
6247        assert_eq!(json["currentValue"], "model-1");
6248        assert_eq!(json["options"].as_array().unwrap().len(), 2);
6249        assert_eq!(json["_meta"]["source"], "test");
6250
6251        let deserialized: SessionConfigOption = serde_json::from_value(json).unwrap();
6252        match deserialized.kind {
6253            SessionConfigKind::Select(ref s) => {
6254                assert_eq!(s.current_value.to_string(), "model-1");
6255            }
6256            _ => panic!("Expected Select kind"),
6257        }
6258    }
6259
6260    #[test]
6261    fn test_session_config_option_unknown_kind_roundtrip() {
6262        let option: SessionConfigOption = serde_json::from_value(json!({
6263            "id": "verbosity",
6264            "name": "Verbosity",
6265            "type": "_slider",
6266            "currentValue": 3,
6267            "min": 0,
6268            "max": 5,
6269            "_meta": {
6270                "source": "test"
6271            }
6272        }))
6273        .unwrap();
6274
6275        assert_eq!(option.id.to_string(), "verbosity");
6276        assert_eq!(option.meta.as_ref().unwrap()["source"], "test");
6277        let SessionConfigKind::Other(unknown) = &option.kind else {
6278            panic!("expected unknown config kind");
6279        };
6280        assert_eq!(unknown.type_, "_slider");
6281        assert_eq!(unknown.fields.get("currentValue"), Some(&json!(3)));
6282        assert!(!unknown.fields.contains_key("_meta"));
6283        assert_eq!(serialized_meta_key_count(&option), 1);
6284
6285        let json = serde_json::to_value(&option).unwrap();
6286        assert_eq!(json["type"], "_slider");
6287        assert_eq!(json["currentValue"], 3);
6288        assert_eq!(json["min"], 0);
6289        assert_eq!(json["max"], 5);
6290        assert_eq!(json["_meta"]["source"], "test");
6291    }
6292
6293    #[test]
6294    fn test_session_config_option_unknown_kind_does_not_duplicate_flattened_meta() {
6295        let mut fields = std::collections::BTreeMap::new();
6296        fields.insert("currentValue".to_string(), json!(3));
6297        fields.insert("_meta".to_string(), json!({ "inner": "ignored" }));
6298
6299        let option = SessionConfigOption::new(
6300            "verbosity",
6301            "Verbosity",
6302            SessionConfigKind::Other(OtherSessionConfigKind::new("_slider", fields)),
6303        )
6304        .meta(test_meta());
6305
6306        let SessionConfigKind::Other(unknown) = &option.kind else {
6307            panic!("expected unknown config kind");
6308        };
6309        assert!(!unknown.fields.contains_key("_meta"));
6310        assert_eq!(serialized_meta_key_count(&option), 1);
6311
6312        let json = serde_json::to_value(&option).unwrap();
6313        assert_eq!(json["type"], "_slider");
6314        assert_eq!(json["currentValue"], 3);
6315        assert_eq!(json["_meta"]["source"], "test");
6316    }
6317
6318    #[test]
6319    fn test_session_config_option_unknown_does_not_hide_malformed_known_kind() {
6320        assert!(
6321            serde_json::from_value::<SessionConfigOption>(json!({
6322                "id": "model",
6323                "name": "Model",
6324                "type": "select"
6325            }))
6326            .is_err()
6327        );
6328    }
6329
6330    #[cfg(feature = "unstable_llm_providers")]
6331    #[test]
6332    fn test_llm_protocol_known_variants() {
6333        assert_eq!(
6334            serde_json::to_value(&LlmProtocol::Anthropic).unwrap(),
6335            json!("anthropic")
6336        );
6337        assert_eq!(
6338            serde_json::to_value(&LlmProtocol::OpenAi).unwrap(),
6339            json!("openai")
6340        );
6341        assert_eq!(
6342            serde_json::to_value(&LlmProtocol::Azure).unwrap(),
6343            json!("azure")
6344        );
6345        assert_eq!(
6346            serde_json::to_value(&LlmProtocol::Vertex).unwrap(),
6347            json!("vertex")
6348        );
6349        assert_eq!(
6350            serde_json::to_value(&LlmProtocol::Bedrock).unwrap(),
6351            json!("bedrock")
6352        );
6353
6354        assert_eq!(
6355            serde_json::from_str::<LlmProtocol>("\"anthropic\"").unwrap(),
6356            LlmProtocol::Anthropic
6357        );
6358        assert_eq!(
6359            serde_json::from_str::<LlmProtocol>("\"openai\"").unwrap(),
6360            LlmProtocol::OpenAi
6361        );
6362        assert_eq!(
6363            serde_json::from_str::<LlmProtocol>("\"azure\"").unwrap(),
6364            LlmProtocol::Azure
6365        );
6366        assert_eq!(
6367            serde_json::from_str::<LlmProtocol>("\"vertex\"").unwrap(),
6368            LlmProtocol::Vertex
6369        );
6370        assert_eq!(
6371            serde_json::from_str::<LlmProtocol>("\"bedrock\"").unwrap(),
6372            LlmProtocol::Bedrock
6373        );
6374    }
6375
6376    #[cfg(feature = "unstable_llm_providers")]
6377    #[test]
6378    fn test_llm_protocol_unknown_variant() {
6379        let unknown: LlmProtocol = serde_json::from_str("\"cohere\"").unwrap();
6380        assert_eq!(unknown, LlmProtocol::Other("cohere".to_string()));
6381
6382        let json = serde_json::to_value(&unknown).unwrap();
6383        assert_eq!(json, json!("cohere"));
6384    }
6385
6386    #[cfg(feature = "unstable_llm_providers")]
6387    #[test]
6388    fn test_provider_current_config_serialization() {
6389        let config =
6390            ProviderCurrentConfig::new(LlmProtocol::Anthropic, "https://api.anthropic.com");
6391
6392        let json = serde_json::to_value(&config).unwrap();
6393        assert_eq!(
6394            json,
6395            json!({
6396                "apiType": "anthropic",
6397                "baseUrl": "https://api.anthropic.com"
6398            })
6399        );
6400
6401        let deserialized: ProviderCurrentConfig = serde_json::from_value(json).unwrap();
6402        assert_eq!(deserialized.api_type, LlmProtocol::Anthropic);
6403        assert_eq!(deserialized.base_url, "https://api.anthropic.com");
6404    }
6405
6406    #[cfg(feature = "unstable_llm_providers")]
6407    #[test]
6408    fn test_provider_info_with_current_config() {
6409        let info = ProviderInfo::new(
6410            "main",
6411            vec![LlmProtocol::Anthropic, LlmProtocol::OpenAi],
6412            true,
6413            Some(ProviderCurrentConfig::new(
6414                LlmProtocol::Anthropic,
6415                "https://api.anthropic.com",
6416            )),
6417        );
6418
6419        let json = serde_json::to_value(&info).unwrap();
6420        assert_eq!(
6421            json,
6422            json!({
6423                "id": "main",
6424                "supported": ["anthropic", "openai"],
6425                "required": true,
6426                "current": {
6427                    "apiType": "anthropic",
6428                    "baseUrl": "https://api.anthropic.com"
6429                }
6430            })
6431        );
6432
6433        let deserialized: ProviderInfo = serde_json::from_value(json).unwrap();
6434        assert_eq!(deserialized.id, "main");
6435        assert_eq!(deserialized.supported.len(), 2);
6436        assert!(deserialized.required);
6437        assert!(deserialized.current.is_some());
6438        assert_eq!(
6439            deserialized.current.as_ref().unwrap().api_type,
6440            LlmProtocol::Anthropic
6441        );
6442    }
6443
6444    #[cfg(feature = "unstable_llm_providers")]
6445    #[test]
6446    fn test_provider_info_disabled() {
6447        let info = ProviderInfo::new(
6448            "secondary",
6449            vec![LlmProtocol::OpenAi],
6450            false,
6451            None::<ProviderCurrentConfig>,
6452        );
6453
6454        let json = serde_json::to_value(&info).unwrap();
6455        assert_eq!(
6456            json,
6457            json!({
6458                "id": "secondary",
6459                "supported": ["openai"],
6460                "required": false
6461            })
6462        );
6463
6464        let deserialized: ProviderInfo = serde_json::from_value(json).unwrap();
6465        assert_eq!(deserialized.id, "secondary");
6466        assert!(!deserialized.required);
6467        assert!(deserialized.current.is_none());
6468    }
6469
6470    #[cfg(feature = "unstable_llm_providers")]
6471    #[test]
6472    fn test_provider_info_missing_current_defaults_to_none() {
6473        // current is optional; omitting it should decode as None
6474        let json = json!({
6475            "id": "main",
6476            "supported": ["anthropic"],
6477            "required": true
6478        });
6479        let deserialized: ProviderInfo = serde_json::from_value(json).unwrap();
6480        assert!(deserialized.current.is_none());
6481    }
6482
6483    #[cfg(feature = "unstable_llm_providers")]
6484    #[test]
6485    fn test_provider_info_explicit_null_current_decodes_to_none() {
6486        // current: null and an omitted current are equivalent on the wire;
6487        // both must deserialize into None so the disabled state is preserved
6488        // regardless of which form the peer chose to send.
6489        let json = json!({
6490            "id": "main",
6491            "supported": ["anthropic"],
6492            "required": true,
6493            "current": null
6494        });
6495        let deserialized: ProviderInfo = serde_json::from_value(json).unwrap();
6496        assert!(deserialized.current.is_none());
6497    }
6498
6499    #[cfg(feature = "unstable_llm_providers")]
6500    #[test]
6501    fn test_list_providers_response_serialization() {
6502        let response = ListProvidersResponse::new(vec![ProviderInfo::new(
6503            "main",
6504            vec![LlmProtocol::Anthropic],
6505            true,
6506            Some(ProviderCurrentConfig::new(
6507                LlmProtocol::Anthropic,
6508                "https://api.anthropic.com",
6509            )),
6510        )]);
6511
6512        let json = serde_json::to_value(&response).unwrap();
6513        assert_eq!(json["providers"].as_array().unwrap().len(), 1);
6514        assert_eq!(json["providers"][0]["id"], "main");
6515
6516        let deserialized: ListProvidersResponse = serde_json::from_value(json).unwrap();
6517        assert_eq!(deserialized.providers.len(), 1);
6518    }
6519
6520    #[cfg(feature = "unstable_llm_providers")]
6521    #[test]
6522    fn test_set_provider_request_serialization() {
6523        use std::collections::HashMap;
6524
6525        let mut headers = HashMap::new();
6526        headers.insert("Authorization".to_string(), "Bearer sk-test".to_string());
6527
6528        let request =
6529            SetProviderRequest::new("main", LlmProtocol::OpenAi, "https://api.openai.com/v1")
6530                .headers(headers);
6531
6532        let json = serde_json::to_value(&request).unwrap();
6533        assert_eq!(
6534            json,
6535            json!({
6536                "id": "main",
6537                "apiType": "openai",
6538                "baseUrl": "https://api.openai.com/v1",
6539                "headers": {
6540                    "Authorization": "Bearer sk-test"
6541                }
6542            })
6543        );
6544
6545        let deserialized: SetProviderRequest = serde_json::from_value(json).unwrap();
6546        assert_eq!(deserialized.id, "main");
6547        assert_eq!(deserialized.api_type, LlmProtocol::OpenAi);
6548        assert_eq!(deserialized.base_url, "https://api.openai.com/v1");
6549        assert_eq!(deserialized.headers.len(), 1);
6550        assert_eq!(
6551            deserialized.headers.get("Authorization").unwrap(),
6552            "Bearer sk-test"
6553        );
6554    }
6555
6556    #[cfg(feature = "unstable_llm_providers")]
6557    #[test]
6558    fn test_set_provider_request_omits_empty_headers() {
6559        let request =
6560            SetProviderRequest::new("main", LlmProtocol::Anthropic, "https://api.anthropic.com");
6561
6562        let json = serde_json::to_value(&request).unwrap();
6563        // headers should be omitted when empty
6564        assert!(!json.as_object().unwrap().contains_key("headers"));
6565    }
6566
6567    #[cfg(feature = "unstable_llm_providers")]
6568    #[test]
6569    fn test_disable_provider_request_serialization() {
6570        let request = DisableProviderRequest::new("secondary");
6571
6572        let json = serde_json::to_value(&request).unwrap();
6573        assert_eq!(json, json!({ "id": "secondary" }));
6574
6575        let deserialized: DisableProviderRequest = serde_json::from_value(json).unwrap();
6576        assert_eq!(deserialized.id, "secondary");
6577    }
6578
6579    #[cfg(feature = "unstable_llm_providers")]
6580    #[test]
6581    fn test_providers_capabilities_serialization() {
6582        let caps = ProvidersCapabilities::new();
6583
6584        let json = serde_json::to_value(&caps).unwrap();
6585        assert_eq!(json, json!({}));
6586
6587        let deserialized: ProvidersCapabilities = serde_json::from_value(json).unwrap();
6588        assert!(deserialized.meta.is_none());
6589    }
6590
6591    #[cfg(feature = "unstable_llm_providers")]
6592    #[test]
6593    fn test_agent_capabilities_with_providers() {
6594        let caps = AgentCapabilities::new().providers(ProvidersCapabilities::new());
6595
6596        let json = serde_json::to_value(&caps).unwrap();
6597        assert_eq!(json["providers"], json!({}));
6598
6599        let deserialized: AgentCapabilities = serde_json::from_value(json).unwrap();
6600        assert!(deserialized.providers.is_some());
6601    }
6602
6603    #[test]
6604    fn test_agent_capabilities_session_is_explicit() {
6605        let json = serde_json::to_value(AgentCapabilities::new()).unwrap();
6606        assert!(json.get("session").is_none());
6607
6608        let caps = AgentCapabilities::new().session(
6609            SessionCapabilities::new()
6610                .prompt(PromptCapabilities::new().image(PromptImageCapabilities::new()))
6611                .mcp(McpCapabilities::new().stdio(McpStdioCapabilities::new()))
6612                .load(SessionLoadCapabilities::new()),
6613        );
6614
6615        assert_eq!(
6616            serde_json::to_value(&caps).unwrap(),
6617            json!({
6618                "auth": {},
6619                "session": {
6620                    "prompt": {
6621                        "image": {}
6622                    },
6623                    "mcp": {
6624                        "stdio": {}
6625                    },
6626                    "load": {}
6627                }
6628            })
6629        );
6630
6631        let deserialized: AgentCapabilities = serde_json::from_value(json!({
6632            "session": false
6633        }))
6634        .unwrap();
6635        assert!(deserialized.session.is_none());
6636    }
6637
6638    #[test]
6639    fn test_prompt_capabilities_serialize_supported_content_as_objects() {
6640        let caps = PromptCapabilities::new()
6641            .image(PromptImageCapabilities::new())
6642            .audio(PromptAudioCapabilities::new())
6643            .embedded_context(PromptEmbeddedContextCapabilities::new());
6644
6645        assert_eq!(
6646            serde_json::to_value(&caps).unwrap(),
6647            json!({
6648                "image": {},
6649                "audio": {},
6650                "embeddedContext": {}
6651            })
6652        );
6653
6654        let deserialized: PromptCapabilities = serde_json::from_value(json!({
6655            "image": null,
6656            "audio": false,
6657            "embeddedContext": {}
6658        }))
6659        .unwrap();
6660        assert!(deserialized.image.is_none());
6661        assert!(deserialized.audio.is_none());
6662        assert!(deserialized.embedded_context.is_some());
6663    }
6664
6665    #[test]
6666    fn test_mcp_capabilities_serialize_supported_transports_as_objects() {
6667        let caps = McpCapabilities::new()
6668            .stdio(McpStdioCapabilities::new())
6669            .http(McpHttpCapabilities::new());
6670
6671        assert_eq!(
6672            serde_json::to_value(&caps).unwrap(),
6673            json!({
6674                "stdio": {},
6675                "http": {}
6676            })
6677        );
6678
6679        let deserialized: McpCapabilities = serde_json::from_value(json!({
6680            "stdio": null,
6681            "http": false
6682        }))
6683        .unwrap();
6684        assert!(deserialized.stdio.is_none());
6685        assert!(deserialized.http.is_none());
6686    }
6687
6688    #[cfg(feature = "unstable_mcp_over_acp")]
6689    #[test]
6690    fn test_mcp_capabilities_serialize_acp_support_as_object() {
6691        let caps = McpCapabilities::new().acp(McpAcpCapabilities::new());
6692
6693        assert_eq!(
6694            serde_json::to_value(&caps).unwrap(),
6695            json!({
6696                "acp": {}
6697            })
6698        );
6699    }
6700}