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    /// Model-related configuration parameter.
2192    ModelConfig,
2193    /// Thought/reasoning level selector.
2194    ThoughtLevel,
2195    /// Custom or future category.
2196    ///
2197    /// Values beginning with `_` are reserved for implementation-specific
2198    /// extensions. Unknown values that do not begin with `_` are reserved for
2199    /// future ACP variants.
2200    #[serde(untagged)]
2201    Other(String),
2202}
2203
2204/// Type-specific session configuration option payload.
2205#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2206#[serde(tag = "type", rename_all = "snake_case")]
2207#[schemars(extend("discriminator" = {"propertyName": "type"}))]
2208#[non_exhaustive]
2209pub enum SessionConfigKind {
2210    /// Single-value selector (dropdown).
2211    Select(SessionConfigSelect),
2212    /// **UNSTABLE**
2213    ///
2214    /// This capability is not part of the spec yet, and may be removed or changed at any point.
2215    ///
2216    /// Boolean on/off toggle.
2217    #[cfg(feature = "unstable_boolean_config")]
2218    Boolean(SessionConfigBoolean),
2219    /// Custom or future session configuration option payload.
2220    ///
2221    /// Values beginning with `_` are reserved for implementation-specific
2222    /// extensions. Unknown values that do not begin with `_` are reserved for
2223    /// future ACP variants.
2224    ///
2225    /// Clients that do not understand this option type should preserve the raw
2226    /// payload when storing, replaying, proxying, or forwarding configuration
2227    /// data, and otherwise ignore the option or display it generically.
2228    #[serde(untagged)]
2229    Other(OtherSessionConfigKind),
2230}
2231
2232/// Custom or future session configuration option payload.
2233#[derive(Debug, Clone, Serialize, JsonSchema, PartialEq, Eq)]
2234#[schemars(inline)]
2235#[schemars(transform = other_session_config_kind_schema)]
2236#[serde(rename_all = "camelCase")]
2237#[non_exhaustive]
2238pub struct OtherSessionConfigKind {
2239    /// Custom or future session configuration option type.
2240    ///
2241    /// Values beginning with `_` are reserved for implementation-specific
2242    /// extensions. Unknown values that do not begin with `_` are reserved for
2243    /// future ACP variants.
2244    #[serde(rename = "type")]
2245    pub type_: String,
2246    /// Additional fields from the unknown session configuration option payload.
2247    #[serde(flatten)]
2248    pub fields: BTreeMap<String, serde_json::Value>,
2249}
2250
2251impl OtherSessionConfigKind {
2252    /// Builds [`OtherSessionConfigKind`] from an unknown discriminator and preserves the remaining extension fields.
2253    #[must_use]
2254    pub fn new(type_: impl Into<String>, mut fields: BTreeMap<String, serde_json::Value>) -> Self {
2255        fields.remove("type");
2256        fields.remove("_meta");
2257        Self {
2258            type_: type_.into(),
2259            fields,
2260        }
2261    }
2262}
2263
2264impl<'de> Deserialize<'de> for OtherSessionConfigKind {
2265    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
2266    where
2267        D: serde::Deserializer<'de>,
2268    {
2269        let mut fields = BTreeMap::<String, serde_json::Value>::deserialize(deserializer)?;
2270        let type_ = fields
2271            .remove("type")
2272            .ok_or_else(|| serde::de::Error::missing_field("type"))?;
2273        let serde_json::Value::String(type_) = type_ else {
2274            return Err(serde::de::Error::custom("`type` must be a string"));
2275        };
2276
2277        if is_known_session_config_kind_type(&type_) {
2278            return Err(serde::de::Error::custom(format!(
2279                "known session configuration option `{type_}` did not match its schema"
2280            )));
2281        }
2282
2283        Ok(Self { type_, fields })
2284    }
2285}
2286
2287fn is_known_session_config_kind_type(type_: &str) -> bool {
2288    match type_ {
2289        "select" => true,
2290        #[cfg(feature = "unstable_boolean_config")]
2291        "boolean" => true,
2292        _ => false,
2293    }
2294}
2295
2296fn other_session_config_kind_schema(schema: &mut Schema) {
2297    super::schema_util::reject_known_string_discriminators(
2298        schema,
2299        "type",
2300        &[
2301            "select",
2302            #[cfg(feature = "unstable_boolean_config")]
2303            "boolean",
2304        ],
2305    );
2306}
2307
2308/// A session configuration option selector and its current state.
2309#[serde_as]
2310#[skip_serializing_none]
2311#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2312#[serde(rename_all = "camelCase")]
2313#[non_exhaustive]
2314pub struct SessionConfigOption {
2315    /// Unique identifier for the configuration option.
2316    pub id: SessionConfigId,
2317    /// Human-readable label for the option.
2318    pub name: String,
2319    /// Optional description for the Client to display to the user.
2320    #[serde(default)]
2321    pub description: Option<String>,
2322    /// Optional semantic category for this option (UX only).
2323    #[serde_as(deserialize_as = "DefaultOnError")]
2324    #[schemars(extend("x-deserialize-default-on-error" = true))]
2325    #[serde(default)]
2326    pub category: Option<SessionConfigOptionCategory>,
2327    /// Type-specific fields for this configuration option.
2328    #[serde(flatten)]
2329    pub kind: SessionConfigKind,
2330    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
2331    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
2332    /// these keys.
2333    ///
2334    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
2335    #[serde(rename = "_meta")]
2336    pub meta: Option<Meta>,
2337}
2338
2339impl SessionConfigOption {
2340    /// Builds [`SessionConfigOption`] with the required fields set; optional fields start unset or empty.
2341    #[must_use]
2342    pub fn new(
2343        id: impl Into<SessionConfigId>,
2344        name: impl Into<String>,
2345        kind: SessionConfigKind,
2346    ) -> Self {
2347        Self {
2348            id: id.into(),
2349            name: name.into(),
2350            description: None,
2351            category: None,
2352            kind,
2353            meta: None,
2354        }
2355    }
2356
2357    /// Builds a select-style session configuration option with its current value and choices.
2358    #[must_use]
2359    pub fn select(
2360        id: impl Into<SessionConfigId>,
2361        name: impl Into<String>,
2362        current_value: impl Into<SessionConfigValueId>,
2363        options: impl Into<SessionConfigSelectOptions>,
2364    ) -> Self {
2365        Self::new(
2366            id,
2367            name,
2368            SessionConfigKind::Select(SessionConfigSelect::new(current_value, options)),
2369        )
2370    }
2371
2372    /// **UNSTABLE**
2373    ///
2374    /// This capability is not part of the spec yet, and may be removed or changed at any point.
2375    #[cfg(feature = "unstable_boolean_config")]
2376    #[must_use]
2377    pub fn boolean(
2378        id: impl Into<SessionConfigId>,
2379        name: impl Into<String>,
2380        current_value: bool,
2381    ) -> Self {
2382        Self::new(
2383            id,
2384            name,
2385            SessionConfigKind::Boolean(SessionConfigBoolean::new(current_value)),
2386        )
2387    }
2388
2389    /// Sets or clears the optional `description` field.
2390    #[must_use]
2391    pub fn description(mut self, description: impl IntoOption<String>) -> Self {
2392        self.description = description.into_option();
2393        self
2394    }
2395
2396    /// Sets or clears the optional `category` field.
2397    #[must_use]
2398    pub fn category(mut self, category: impl IntoOption<SessionConfigOptionCategory>) -> Self {
2399        self.category = category.into_option();
2400        self
2401    }
2402
2403    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
2404    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
2405    /// these keys.
2406    ///
2407    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
2408    #[must_use]
2409    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2410        self.meta = meta.into_option();
2411        self
2412    }
2413}
2414
2415/// **UNSTABLE**
2416///
2417/// This capability is not part of the spec yet, and may be removed or changed at any point.
2418///
2419/// The value to set for a session configuration option.
2420///
2421/// The `type` field acts as the discriminator in the serialized JSON form.
2422/// When no `type` is present, the value is treated as a [`SessionConfigValueId`]
2423/// via the [`ValueId`](Self::ValueId) fallback variant.
2424///
2425/// The `type` discriminator describes the *shape* of the value, not the option
2426/// kind. For example every option kind that picks from a list of ids
2427/// (`select`, `radio`, …) would use [`ValueId`](Self::ValueId), while a
2428/// future freeform text option would get its own variant.
2429#[cfg(feature = "unstable_boolean_config")]
2430#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2431#[serde(tag = "type", rename_all = "snake_case")]
2432#[non_exhaustive]
2433pub enum SessionConfigOptionValue {
2434    /// A boolean value (`type: "boolean"`).
2435    Boolean {
2436        /// The boolean value.
2437        value: bool,
2438    },
2439    /// A [`SessionConfigValueId`] string value.
2440    ///
2441    /// This is the default when `type` is absent on the wire. Unknown `type`
2442    /// values with string payloads also gracefully deserialize into this
2443    /// variant.
2444    #[serde(untagged)]
2445    ValueId {
2446        /// The value ID.
2447        value: SessionConfigValueId,
2448    },
2449}
2450
2451#[cfg(feature = "unstable_boolean_config")]
2452impl SessionConfigOptionValue {
2453    /// Create a value-id option value (used by `select` and other id-based option types).
2454    #[must_use]
2455    pub fn value_id(id: impl Into<SessionConfigValueId>) -> Self {
2456        Self::ValueId { value: id.into() }
2457    }
2458
2459    /// Create a boolean option value.
2460    #[must_use]
2461    pub fn boolean(val: bool) -> Self {
2462        Self::Boolean { value: val }
2463    }
2464
2465    /// Return the inner [`SessionConfigValueId`] if this is a
2466    /// [`ValueId`](Self::ValueId) value.
2467    #[must_use]
2468    pub fn as_value_id(&self) -> Option<&SessionConfigValueId> {
2469        match self {
2470            Self::ValueId { value } => Some(value),
2471            _ => None,
2472        }
2473    }
2474
2475    /// Return the inner [`bool`] if this is a [`Boolean`](Self::Boolean) value.
2476    #[must_use]
2477    pub fn as_bool(&self) -> Option<bool> {
2478        match self {
2479            Self::Boolean { value } => Some(*value),
2480            _ => None,
2481        }
2482    }
2483}
2484
2485#[cfg(feature = "unstable_boolean_config")]
2486impl From<SessionConfigValueId> for SessionConfigOptionValue {
2487    fn from(value: SessionConfigValueId) -> Self {
2488        Self::ValueId { value }
2489    }
2490}
2491
2492#[cfg(feature = "unstable_boolean_config")]
2493impl From<bool> for SessionConfigOptionValue {
2494    fn from(value: bool) -> Self {
2495        Self::Boolean { value }
2496    }
2497}
2498
2499#[cfg(feature = "unstable_boolean_config")]
2500impl From<&str> for SessionConfigOptionValue {
2501    fn from(value: &str) -> Self {
2502        Self::ValueId {
2503            value: SessionConfigValueId::new(value),
2504        }
2505    }
2506}
2507
2508/// Request parameters for setting a session configuration option.
2509#[skip_serializing_none]
2510#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2511#[schemars(extend("x-side" = "agent", "x-method" = SESSION_SET_CONFIG_OPTION_METHOD_NAME))]
2512#[serde(rename_all = "camelCase")]
2513#[non_exhaustive]
2514pub struct SetSessionConfigOptionRequest {
2515    /// The ID of the session to set the configuration option for.
2516    pub session_id: SessionId,
2517    /// The ID of the configuration option to set.
2518    pub config_id: SessionConfigId,
2519    /// The value to set, including a `type` discriminator and the raw `value`.
2520    ///
2521    /// When `type` is absent on the wire, defaults to treating the value as a
2522    /// [`SessionConfigValueId`] for `select` options.
2523    #[cfg(feature = "unstable_boolean_config")]
2524    #[serde(flatten)]
2525    pub value: SessionConfigOptionValue,
2526    /// The ID of the configuration option value to set.
2527    #[cfg(not(feature = "unstable_boolean_config"))]
2528    pub value: SessionConfigValueId,
2529    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
2530    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
2531    /// these keys.
2532    ///
2533    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
2534    #[serde(rename = "_meta")]
2535    pub meta: Option<Meta>,
2536}
2537
2538impl SetSessionConfigOptionRequest {
2539    /// Builds [`SetSessionConfigOptionRequest`] with the required request fields set; optional fields start unset or empty.
2540    #[cfg(feature = "unstable_boolean_config")]
2541    #[must_use]
2542    pub fn new(
2543        session_id: impl Into<SessionId>,
2544        config_id: impl Into<SessionConfigId>,
2545        value: impl Into<SessionConfigOptionValue>,
2546    ) -> Self {
2547        Self {
2548            session_id: session_id.into(),
2549            config_id: config_id.into(),
2550            value: value.into(),
2551            meta: None,
2552        }
2553    }
2554
2555    /// Builds a select-value `session/set_config_option` request for crates built
2556    /// without boolean session configuration support.
2557    #[cfg(not(feature = "unstable_boolean_config"))]
2558    #[must_use]
2559    pub fn new(
2560        session_id: impl Into<SessionId>,
2561        config_id: impl Into<SessionConfigId>,
2562        value: impl Into<SessionConfigValueId>,
2563    ) -> Self {
2564        Self {
2565            session_id: session_id.into(),
2566            config_id: config_id.into(),
2567            value: value.into(),
2568            meta: None,
2569        }
2570    }
2571
2572    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
2573    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
2574    /// these keys.
2575    ///
2576    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
2577    #[must_use]
2578    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2579        self.meta = meta.into_option();
2580        self
2581    }
2582}
2583
2584/// Response to `session/set_config_option` method.
2585#[serde_as]
2586#[skip_serializing_none]
2587#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2588#[schemars(extend("x-side" = "agent", "x-method" = SESSION_SET_CONFIG_OPTION_METHOD_NAME))]
2589#[serde(rename_all = "camelCase")]
2590#[non_exhaustive]
2591pub struct SetSessionConfigOptionResponse {
2592    /// The full set of configuration options and their current values.
2593    #[serde_as(deserialize_as = "DefaultOnError<VecSkipError<_, SkipListener>>")]
2594    #[schemars(extend("x-deserialize-default-on-error" = true, "x-deserialize-skip-invalid-items" = true))]
2595    pub config_options: Vec<SessionConfigOption>,
2596    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
2597    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
2598    /// these keys.
2599    ///
2600    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
2601    #[serde(rename = "_meta")]
2602    pub meta: Option<Meta>,
2603}
2604
2605impl SetSessionConfigOptionResponse {
2606    /// Builds [`SetSessionConfigOptionResponse`] with the required response fields set; optional fields start unset or empty.
2607    #[must_use]
2608    pub fn new(config_options: Vec<SessionConfigOption>) -> Self {
2609        Self {
2610            config_options,
2611            meta: None,
2612        }
2613    }
2614
2615    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
2616    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
2617    /// these keys.
2618    ///
2619    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
2620    #[must_use]
2621    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2622        self.meta = meta.into_option();
2623        self
2624    }
2625}
2626
2627// MCP
2628
2629/// Configuration for connecting to an MCP (Model Context Protocol) server.
2630///
2631/// MCP servers provide tools and context that the agent can use when
2632/// processing prompts.
2633///
2634/// See protocol docs: [MCP Servers](https://agentclientprotocol.com/protocol/session-setup#mcp-servers)
2635#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2636#[serde(tag = "type", rename_all = "snake_case")]
2637#[schemars(extend("discriminator" = {"propertyName": "type"}))]
2638#[non_exhaustive]
2639pub enum McpServer {
2640    /// HTTP transport configuration
2641    ///
2642    /// Only available when the Agent capabilities include `session.mcp.http`.
2643    Http(McpServerHttp),
2644    /// **UNSTABLE**
2645    ///
2646    /// This capability is not part of the spec yet, and may be removed or changed at any point.
2647    ///
2648    /// ACP transport configuration
2649    ///
2650    /// Only available when the Agent capabilities include `session.mcp.acp`.
2651    /// The MCP server is provided by an ACP component and communicates over the ACP channel.
2652    #[cfg(feature = "unstable_mcp_over_acp")]
2653    Acp(McpServerAcp),
2654    /// Stdio transport configuration
2655    ///
2656    /// Only available when the Agent capabilities include `session.mcp.stdio`.
2657    Stdio(McpServerStdio),
2658    /// Custom or future MCP server transport configuration.
2659    ///
2660    /// Values beginning with `_` are reserved for implementation-specific
2661    /// extensions. Unknown values that do not begin with `_` are reserved for
2662    /// future ACP variants.
2663    ///
2664    /// Receivers that do not understand this transport should preserve the raw
2665    /// payload when storing, replaying, proxying, or forwarding session setup
2666    /// data, and otherwise ignore it or reject the server configuration.
2667    #[serde(untagged)]
2668    Other(OtherMcpServer),
2669}
2670
2671/// Custom or future MCP server transport payload.
2672#[derive(Debug, Clone, Serialize, JsonSchema, PartialEq, Eq)]
2673#[schemars(inline)]
2674#[schemars(transform = other_mcp_server_schema)]
2675#[serde(rename_all = "camelCase")]
2676#[non_exhaustive]
2677pub struct OtherMcpServer {
2678    /// Custom or future MCP server transport type.
2679    ///
2680    /// Values beginning with `_` are reserved for implementation-specific
2681    /// extensions. Unknown values that do not begin with `_` are reserved for
2682    /// future ACP variants.
2683    #[serde(rename = "type")]
2684    pub type_: String,
2685    /// Additional fields from the unknown MCP server transport payload.
2686    #[serde(flatten)]
2687    pub fields: BTreeMap<String, serde_json::Value>,
2688}
2689
2690impl OtherMcpServer {
2691    /// Builds [`OtherMcpServer`] from an unknown discriminator and preserves the remaining extension fields.
2692    #[must_use]
2693    pub fn new(type_: impl Into<String>, mut fields: BTreeMap<String, serde_json::Value>) -> Self {
2694        fields.remove("type");
2695        Self {
2696            type_: type_.into(),
2697            fields,
2698        }
2699    }
2700}
2701
2702impl<'de> Deserialize<'de> for OtherMcpServer {
2703    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
2704    where
2705        D: serde::Deserializer<'de>,
2706    {
2707        let mut fields = BTreeMap::<String, serde_json::Value>::deserialize(deserializer)?;
2708        let type_ = fields
2709            .remove("type")
2710            .ok_or_else(|| serde::de::Error::missing_field("type"))?;
2711        let serde_json::Value::String(type_) = type_ else {
2712            return Err(serde::de::Error::custom("`type` must be a string"));
2713        };
2714
2715        if is_known_mcp_server_type(&type_) {
2716            return Err(serde::de::Error::custom(format!(
2717                "known MCP server transport `{type_}` did not match its schema"
2718            )));
2719        }
2720
2721        Ok(Self { type_, fields })
2722    }
2723}
2724
2725fn is_known_mcp_server_type(type_: &str) -> bool {
2726    match type_ {
2727        "http" | "stdio" => true,
2728        #[cfg(feature = "unstable_mcp_over_acp")]
2729        "acp" => true,
2730        _ => false,
2731    }
2732}
2733
2734fn other_mcp_server_schema(schema: &mut Schema) {
2735    super::schema_util::reject_known_string_discriminators(
2736        schema,
2737        "type",
2738        &[
2739            "http",
2740            "stdio",
2741            #[cfg(feature = "unstable_mcp_over_acp")]
2742            "acp",
2743        ],
2744    );
2745}
2746
2747/// HTTP transport configuration for MCP.
2748#[skip_serializing_none]
2749#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2750#[serde(rename_all = "camelCase")]
2751#[non_exhaustive]
2752pub struct McpServerHttp {
2753    /// Human-readable name identifying this MCP server.
2754    pub name: String,
2755    /// URL to the MCP server.
2756    pub url: String,
2757    /// HTTP headers to set when making requests to the MCP server.
2758    pub headers: Vec<HttpHeader>,
2759    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
2760    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
2761    /// these keys.
2762    ///
2763    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
2764    #[serde(rename = "_meta")]
2765    pub meta: Option<Meta>,
2766}
2767
2768impl McpServerHttp {
2769    /// Builds [`McpServerHttp`] with the required fields set; optional fields start unset or empty.
2770    #[must_use]
2771    pub fn new(name: impl Into<String>, url: impl Into<String>) -> Self {
2772        Self {
2773            name: name.into(),
2774            url: url.into(),
2775            headers: Vec::new(),
2776            meta: None,
2777        }
2778    }
2779
2780    /// HTTP headers to set when making requests to the MCP server.
2781    #[must_use]
2782    pub fn headers(mut self, headers: Vec<HttpHeader>) -> Self {
2783        self.headers = headers;
2784        self
2785    }
2786
2787    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
2788    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
2789    /// these keys.
2790    ///
2791    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
2792    #[must_use]
2793    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2794        self.meta = meta.into_option();
2795        self
2796    }
2797}
2798
2799/// **UNSTABLE**
2800///
2801/// This capability is not part of the spec yet, and may be removed or changed at any point.
2802///
2803/// Unique identifier for an MCP server using the ACP transport.
2804///
2805/// The value is opaque and generated by the ACP component providing the MCP server. It is
2806/// used by `mcp/connect` to route connection requests back to the component that declared the
2807/// server.
2808#[cfg(feature = "unstable_mcp_over_acp")]
2809#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq, Hash, Display, From)]
2810#[serde(transparent)]
2811#[from(Arc<str>, String, &'static str)]
2812#[non_exhaustive]
2813pub struct McpServerAcpId(pub Arc<str>);
2814
2815#[cfg(feature = "unstable_mcp_over_acp")]
2816impl McpServerAcpId {
2817    /// Wraps a protocol string as a typed [`McpServerAcpId`].
2818    #[must_use]
2819    pub fn new(id: impl Into<Arc<str>>) -> Self {
2820        Self(id.into())
2821    }
2822}
2823
2824/// **UNSTABLE**
2825///
2826/// This capability is not part of the spec yet, and may be removed or changed at any point.
2827///
2828/// ACP transport configuration for MCP.
2829///
2830/// The MCP server is provided by an ACP component and communicates over the ACP channel
2831/// using `mcp/connect`, `mcp/message`, and `mcp/disconnect`.
2832#[skip_serializing_none]
2833#[cfg(feature = "unstable_mcp_over_acp")]
2834#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2835#[serde(rename_all = "camelCase")]
2836#[non_exhaustive]
2837pub struct McpServerAcp {
2838    /// Human-readable name identifying this MCP server.
2839    pub name: String,
2840    /// Unique identifier for this MCP server, generated by the component providing it.
2841    ///
2842    /// Providers MUST NOT reuse an ID for multiple ACP-transport MCP servers that are visible
2843    /// on the same ACP connection.
2844    pub id: McpServerAcpId,
2845    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
2846    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
2847    /// these keys.
2848    ///
2849    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
2850    #[serde(rename = "_meta")]
2851    pub meta: Option<Meta>,
2852}
2853
2854#[cfg(feature = "unstable_mcp_over_acp")]
2855impl McpServerAcp {
2856    /// Builds [`McpServerAcp`] with the required fields set; optional fields start unset or empty.
2857    #[must_use]
2858    pub fn new(name: impl Into<String>, id: impl Into<McpServerAcpId>) -> Self {
2859        Self {
2860            name: name.into(),
2861            id: id.into(),
2862            meta: None,
2863        }
2864    }
2865
2866    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
2867    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
2868    /// these keys.
2869    ///
2870    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
2871    #[must_use]
2872    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2873        self.meta = meta.into_option();
2874        self
2875    }
2876}
2877
2878/// Stdio transport configuration for MCP.
2879#[skip_serializing_none]
2880#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2881#[serde(rename_all = "camelCase")]
2882#[non_exhaustive]
2883pub struct McpServerStdio {
2884    /// Human-readable name identifying this MCP server.
2885    pub name: String,
2886    /// Path to the MCP server executable.
2887    pub command: PathBuf,
2888    /// Command-line arguments to pass to the MCP server.
2889    pub args: Vec<String>,
2890    /// Environment variables to set when launching the MCP server.
2891    pub env: Vec<EnvVariable>,
2892    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
2893    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
2894    /// these keys.
2895    ///
2896    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
2897    #[serde(rename = "_meta")]
2898    pub meta: Option<Meta>,
2899}
2900
2901impl McpServerStdio {
2902    /// Builds [`McpServerStdio`] with the required fields set; optional fields start unset or empty.
2903    #[must_use]
2904    pub fn new(name: impl Into<String>, command: impl Into<PathBuf>) -> Self {
2905        Self {
2906            name: name.into(),
2907            command: command.into(),
2908            args: Vec::new(),
2909            env: Vec::new(),
2910            meta: None,
2911        }
2912    }
2913
2914    /// Command-line arguments to pass to the MCP server.
2915    #[must_use]
2916    pub fn args(mut self, args: Vec<String>) -> Self {
2917        self.args = args;
2918        self
2919    }
2920
2921    /// Environment variables to set when launching the MCP server.
2922    #[must_use]
2923    pub fn env(mut self, env: Vec<EnvVariable>) -> Self {
2924        self.env = env;
2925        self
2926    }
2927
2928    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
2929    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
2930    /// these keys.
2931    ///
2932    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
2933    #[must_use]
2934    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2935        self.meta = meta.into_option();
2936        self
2937    }
2938}
2939
2940/// An environment variable to set when launching an MCP server.
2941#[skip_serializing_none]
2942#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2943#[serde(rename_all = "camelCase")]
2944#[non_exhaustive]
2945pub struct EnvVariable {
2946    /// The name of the environment variable.
2947    pub name: String,
2948    /// The value to set for the environment variable.
2949    pub value: String,
2950    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
2951    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
2952    /// these keys.
2953    ///
2954    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
2955    #[serde(rename = "_meta")]
2956    pub meta: Option<Meta>,
2957}
2958
2959impl EnvVariable {
2960    /// Builds [`EnvVariable`] with the required fields set; optional fields start unset or empty.
2961    #[must_use]
2962    pub fn new(name: impl Into<String>, value: impl Into<String>) -> Self {
2963        Self {
2964            name: name.into(),
2965            value: value.into(),
2966            meta: None,
2967        }
2968    }
2969
2970    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
2971    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
2972    /// these keys.
2973    ///
2974    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
2975    #[must_use]
2976    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2977        self.meta = meta.into_option();
2978        self
2979    }
2980}
2981
2982/// An HTTP header to set when making requests to the MCP server.
2983#[skip_serializing_none]
2984#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2985#[serde(rename_all = "camelCase")]
2986#[non_exhaustive]
2987pub struct HttpHeader {
2988    /// The name of the HTTP header.
2989    pub name: String,
2990    /// The value to set for the HTTP header.
2991    pub value: String,
2992    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
2993    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
2994    /// these keys.
2995    ///
2996    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
2997    #[serde(rename = "_meta")]
2998    pub meta: Option<Meta>,
2999}
3000
3001impl HttpHeader {
3002    /// Builds [`HttpHeader`] with the required fields set; optional fields start unset or empty.
3003    #[must_use]
3004    pub fn new(name: impl Into<String>, value: impl Into<String>) -> Self {
3005        Self {
3006            name: name.into(),
3007            value: value.into(),
3008            meta: None,
3009        }
3010    }
3011
3012    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
3013    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
3014    /// these keys.
3015    ///
3016    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
3017    #[must_use]
3018    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3019        self.meta = meta.into_option();
3020        self
3021    }
3022}
3023
3024// Prompt
3025
3026/// Request parameters for sending a user prompt to the agent.
3027///
3028/// Contains the user's message and any additional context.
3029///
3030/// See protocol docs: [User Message](https://agentclientprotocol.com/protocol/prompt-lifecycle#1-user-message)
3031#[skip_serializing_none]
3032#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq)]
3033#[schemars(extend("x-side" = "agent", "x-method" = SESSION_PROMPT_METHOD_NAME))]
3034#[serde(rename_all = "camelCase")]
3035#[non_exhaustive]
3036pub struct PromptRequest {
3037    /// The ID of the session to send this user message to
3038    pub session_id: SessionId,
3039    /// The blocks of content that compose the user's message.
3040    ///
3041    /// As a baseline, the Agent MUST support [`ContentBlock::Text`] and [`ContentBlock::ResourceLink`],
3042    /// while other variants are optionally enabled via [`PromptCapabilities`].
3043    ///
3044    /// The Client MUST adapt its interface according to [`PromptCapabilities`].
3045    ///
3046    /// The client MAY include referenced pieces of context as either
3047    /// [`ContentBlock::Resource`] or [`ContentBlock::ResourceLink`].
3048    ///
3049    /// When available, [`ContentBlock::Resource`] is preferred
3050    /// as it avoids extra round-trips and allows the message to include
3051    /// pieces of context from sources the agent may not have access to.
3052    pub prompt: Vec<ContentBlock>,
3053    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
3054    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
3055    /// these keys.
3056    ///
3057    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
3058    #[serde(rename = "_meta")]
3059    pub meta: Option<Meta>,
3060}
3061
3062impl PromptRequest {
3063    /// Builds [`PromptRequest`] with the required request fields set; optional fields start unset or empty.
3064    #[must_use]
3065    pub fn new(session_id: impl Into<SessionId>, prompt: Vec<ContentBlock>) -> Self {
3066        Self {
3067            session_id: session_id.into(),
3068            prompt,
3069            meta: None,
3070        }
3071    }
3072
3073    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
3074    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
3075    /// these keys.
3076    ///
3077    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
3078    #[must_use]
3079    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3080        self.meta = meta.into_option();
3081        self
3082    }
3083}
3084
3085/// Response acknowledging that a user prompt was accepted.
3086///
3087/// This response does not indicate that the agent has finished processing.
3088/// Agents report session state through `state_update` session updates.
3089///
3090/// See protocol docs: [Prompt Accepted](https://agentclientprotocol.com/protocol/prompt-lifecycle#2-prompt-accepted)
3091#[skip_serializing_none]
3092#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3093#[schemars(extend("x-side" = "agent", "x-method" = SESSION_PROMPT_METHOD_NAME))]
3094#[serde(rename_all = "camelCase")]
3095#[non_exhaustive]
3096pub struct PromptResponse {
3097    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
3098    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
3099    /// these keys.
3100    ///
3101    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
3102    #[serde(rename = "_meta")]
3103    pub meta: Option<Meta>,
3104}
3105
3106impl PromptResponse {
3107    /// Builds [`PromptResponse`] with the required response fields set; optional fields start unset or empty.
3108    #[must_use]
3109    pub fn new() -> Self {
3110        Self::default()
3111    }
3112
3113    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
3114    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
3115    /// these keys.
3116    ///
3117    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
3118    #[must_use]
3119    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3120        self.meta = meta.into_option();
3121        self
3122    }
3123}
3124
3125/// Reasons why an agent stops active session work.
3126///
3127/// See protocol docs: [Stop Reasons](https://agentclientprotocol.com/protocol/prompt-lifecycle#stop-reasons)
3128#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize, JsonSchema)]
3129#[serde(rename_all = "snake_case")]
3130#[non_exhaustive]
3131pub enum StopReason {
3132    /// The active work ended successfully.
3133    EndTurn,
3134    /// The active work ended because the agent reached the maximum number of tokens.
3135    MaxTokens,
3136    /// The active work ended because the agent reached the maximum number of
3137    /// allowed agent requests before returning idle.
3138    MaxTurnRequests,
3139    /// The active work ended because the agent refused to continue. The user
3140    /// prompt and everything that comes after it won't be included in the next
3141    /// prompt, so this should be reflected in the UI.
3142    Refusal,
3143    /// Active session work was cancelled by the client via `session/cancel`.
3144    ///
3145    /// Agents should report this stop reason on an idle `state_update` session update
3146    /// when cancellation succeeds, even if cancellation causes exceptions in
3147    /// underlying operations.
3148    Cancelled,
3149    /// Custom or future stop reason.
3150    ///
3151    /// Values beginning with `_` are reserved for implementation-specific
3152    /// extensions. Unknown values that do not begin with `_` are reserved for
3153    /// future ACP variants.
3154    #[serde(untagged)]
3155    Other(String),
3156}
3157
3158/// **UNSTABLE**
3159///
3160/// This capability is not part of the spec yet, and may be removed or changed at any point.
3161///
3162/// Token usage information for completed session work.
3163#[cfg(feature = "unstable_end_turn_token_usage")]
3164#[skip_serializing_none]
3165#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3166#[serde(rename_all = "camelCase")]
3167#[non_exhaustive]
3168pub struct Usage {
3169    /// Sum of all token types across session.
3170    pub total_tokens: u64,
3171    /// Total input tokens.
3172    pub input_tokens: u64,
3173    /// Total output tokens.
3174    pub output_tokens: u64,
3175    /// Total thought/reasoning tokens
3176    pub thought_tokens: Option<u64>,
3177    /// Total cache read tokens.
3178    pub cached_read_tokens: Option<u64>,
3179    /// Total cache write tokens.
3180    pub cached_write_tokens: Option<u64>,
3181    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
3182    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
3183    /// these keys.
3184    ///
3185    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
3186    #[serde(rename = "_meta")]
3187    pub meta: Option<Meta>,
3188}
3189
3190#[cfg(feature = "unstable_end_turn_token_usage")]
3191impl Usage {
3192    /// Builds [`Usage`] with the required fields set; optional fields start unset or empty.
3193    #[must_use]
3194    pub fn new(total_tokens: u64, input_tokens: u64, output_tokens: u64) -> Self {
3195        Self {
3196            total_tokens,
3197            input_tokens,
3198            output_tokens,
3199            thought_tokens: None,
3200            cached_read_tokens: None,
3201            cached_write_tokens: None,
3202            meta: None,
3203        }
3204    }
3205
3206    /// Total thought/reasoning tokens
3207    #[must_use]
3208    pub fn thought_tokens(mut self, thought_tokens: impl IntoOption<u64>) -> Self {
3209        self.thought_tokens = thought_tokens.into_option();
3210        self
3211    }
3212
3213    /// Total cache read tokens.
3214    #[must_use]
3215    pub fn cached_read_tokens(mut self, cached_read_tokens: impl IntoOption<u64>) -> Self {
3216        self.cached_read_tokens = cached_read_tokens.into_option();
3217        self
3218    }
3219
3220    /// Total cache write tokens.
3221    #[must_use]
3222    pub fn cached_write_tokens(mut self, cached_write_tokens: impl IntoOption<u64>) -> Self {
3223        self.cached_write_tokens = cached_write_tokens.into_option();
3224        self
3225    }
3226
3227    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
3228    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
3229    /// these keys.
3230    ///
3231    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
3232    #[must_use]
3233    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3234        self.meta = meta.into_option();
3235        self
3236    }
3237}
3238
3239// Providers
3240
3241/// **UNSTABLE**
3242///
3243/// This capability is not part of the spec yet, and may be removed or changed at any point.
3244///
3245/// Well-known API protocol identifiers for LLM providers.
3246///
3247/// Agents and clients MUST handle unknown protocol identifiers gracefully.
3248///
3249/// Protocol names beginning with `_` are free for custom use, like other ACP extension methods.
3250/// Protocol names that do not begin with `_` are reserved for the ACP spec.
3251#[cfg(feature = "unstable_llm_providers")]
3252#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3253#[serde(rename_all = "snake_case")]
3254#[non_exhaustive]
3255#[expect(clippy::doc_markdown)]
3256pub enum LlmProtocol {
3257    /// Anthropic API protocol.
3258    Anthropic,
3259    /// OpenAI API protocol.
3260    #[serde(rename = "openai")]
3261    OpenAi,
3262    /// Azure OpenAI API protocol.
3263    Azure,
3264    /// Google Vertex AI API protocol.
3265    Vertex,
3266    /// AWS Bedrock API protocol.
3267    Bedrock,
3268    /// Custom or future protocol.
3269    ///
3270    /// Values beginning with `_` are reserved for implementation-specific
3271    /// extensions. Unknown values that do not begin with `_` are reserved for
3272    /// future ACP variants.
3273    #[serde(untagged)]
3274    Other(String),
3275}
3276
3277/// **UNSTABLE**
3278///
3279/// This capability is not part of the spec yet, and may be removed or changed at any point.
3280///
3281/// Current effective non-secret routing configuration for a provider.
3282#[cfg(feature = "unstable_llm_providers")]
3283#[skip_serializing_none]
3284#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3285#[serde(rename_all = "camelCase")]
3286#[non_exhaustive]
3287pub struct ProviderCurrentConfig {
3288    /// Protocol currently used by this provider.
3289    pub api_type: LlmProtocol,
3290    /// Base URL currently used by this provider.
3291    pub base_url: String,
3292    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
3293    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
3294    /// these keys.
3295    ///
3296    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
3297    #[serde(rename = "_meta")]
3298    pub meta: Option<Meta>,
3299}
3300
3301#[cfg(feature = "unstable_llm_providers")]
3302impl ProviderCurrentConfig {
3303    /// Builds [`ProviderCurrentConfig`] with the required fields set; optional fields start unset or empty.
3304    #[must_use]
3305    pub fn new(api_type: LlmProtocol, base_url: impl Into<String>) -> Self {
3306        Self {
3307            api_type,
3308            base_url: base_url.into(),
3309            meta: None,
3310        }
3311    }
3312
3313    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
3314    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
3315    /// these keys.
3316    ///
3317    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
3318    #[must_use]
3319    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3320        self.meta = meta.into_option();
3321        self
3322    }
3323}
3324
3325/// **UNSTABLE**
3326///
3327/// This capability is not part of the spec yet, and may be removed or changed at any point.
3328///
3329/// Information about a configurable LLM provider.
3330#[cfg(feature = "unstable_llm_providers")]
3331#[serde_as]
3332#[skip_serializing_none]
3333#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3334#[serde(rename_all = "camelCase")]
3335#[non_exhaustive]
3336pub struct ProviderInfo {
3337    /// Provider identifier, for example "main" or "openai".
3338    pub id: String,
3339    /// Supported protocol types for this provider.
3340    #[serde_as(deserialize_as = "DefaultOnError<VecSkipError<_, SkipListener>>")]
3341    #[schemars(extend("x-deserialize-default-on-error" = true, "x-deserialize-skip-invalid-items" = true))]
3342    pub supported: Vec<LlmProtocol>,
3343    /// Whether this provider is mandatory and cannot be disabled via `providers/disable`.
3344    /// If true, clients must not call `providers/disable` for this id.
3345    pub required: bool,
3346    /// Current effective non-secret routing config.
3347    /// Null or omitted means provider is disabled.
3348    pub current: Option<ProviderCurrentConfig>,
3349    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
3350    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
3351    /// these keys.
3352    ///
3353    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
3354    #[serde(rename = "_meta")]
3355    pub meta: Option<Meta>,
3356}
3357
3358#[cfg(feature = "unstable_llm_providers")]
3359impl ProviderInfo {
3360    /// Builds [`ProviderInfo`] with the required fields set; optional fields start unset or empty.
3361    #[must_use]
3362    pub fn new(
3363        id: impl Into<String>,
3364        supported: Vec<LlmProtocol>,
3365        required: bool,
3366        current: impl IntoOption<ProviderCurrentConfig>,
3367    ) -> Self {
3368        Self {
3369            id: id.into(),
3370            supported,
3371            required,
3372            current: current.into_option(),
3373            meta: None,
3374        }
3375    }
3376
3377    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
3378    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
3379    /// these keys.
3380    ///
3381    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
3382    #[must_use]
3383    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3384        self.meta = meta.into_option();
3385        self
3386    }
3387}
3388
3389/// **UNSTABLE**
3390///
3391/// This capability is not part of the spec yet, and may be removed or changed at any point.
3392///
3393/// Request parameters for `providers/list`.
3394#[cfg(feature = "unstable_llm_providers")]
3395#[skip_serializing_none]
3396#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3397#[schemars(extend("x-side" = "agent", "x-method" = PROVIDERS_LIST_METHOD_NAME))]
3398#[serde(rename_all = "camelCase")]
3399#[non_exhaustive]
3400pub struct ListProvidersRequest {
3401    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
3402    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
3403    /// these keys.
3404    ///
3405    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
3406    #[serde(rename = "_meta")]
3407    pub meta: Option<Meta>,
3408}
3409
3410#[cfg(feature = "unstable_llm_providers")]
3411impl ListProvidersRequest {
3412    /// Builds [`ListProvidersRequest`] with the required request fields set; optional fields start unset or empty.
3413    #[must_use]
3414    pub fn new() -> Self {
3415        Self::default()
3416    }
3417
3418    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
3419    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
3420    /// these keys.
3421    ///
3422    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
3423    #[must_use]
3424    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3425        self.meta = meta.into_option();
3426        self
3427    }
3428}
3429
3430/// **UNSTABLE**
3431///
3432/// This capability is not part of the spec yet, and may be removed or changed at any point.
3433///
3434/// Response to `providers/list`.
3435#[cfg(feature = "unstable_llm_providers")]
3436#[serde_as]
3437#[skip_serializing_none]
3438#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3439#[schemars(extend("x-side" = "agent", "x-method" = PROVIDERS_LIST_METHOD_NAME))]
3440#[serde(rename_all = "camelCase")]
3441#[non_exhaustive]
3442pub struct ListProvidersResponse {
3443    /// Configurable providers with current routing info suitable for UI display.
3444    #[serde_as(deserialize_as = "DefaultOnError<VecSkipError<_, SkipListener>>")]
3445    #[schemars(extend("x-deserialize-default-on-error" = true, "x-deserialize-skip-invalid-items" = true))]
3446    pub providers: Vec<ProviderInfo>,
3447    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
3448    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
3449    /// these keys.
3450    ///
3451    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
3452    #[serde(rename = "_meta")]
3453    pub meta: Option<Meta>,
3454}
3455
3456#[cfg(feature = "unstable_llm_providers")]
3457impl ListProvidersResponse {
3458    /// Builds [`ListProvidersResponse`] with the required response fields set; optional fields start unset or empty.
3459    #[must_use]
3460    pub fn new(providers: Vec<ProviderInfo>) -> Self {
3461        Self {
3462            providers,
3463            meta: None,
3464        }
3465    }
3466
3467    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
3468    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
3469    /// these keys.
3470    ///
3471    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
3472    #[must_use]
3473    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3474        self.meta = meta.into_option();
3475        self
3476    }
3477}
3478
3479/// **UNSTABLE**
3480///
3481/// This capability is not part of the spec yet, and may be removed or changed at any point.
3482///
3483/// Request parameters for `providers/set`.
3484///
3485/// Replaces the full configuration for one provider id.
3486#[cfg(feature = "unstable_llm_providers")]
3487#[skip_serializing_none]
3488#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3489#[schemars(extend("x-side" = "agent", "x-method" = PROVIDERS_SET_METHOD_NAME))]
3490#[serde(rename_all = "camelCase")]
3491#[non_exhaustive]
3492pub struct SetProviderRequest {
3493    /// Provider id to configure.
3494    pub id: String,
3495    /// Protocol type for this provider.
3496    pub api_type: LlmProtocol,
3497    /// Base URL for requests sent through this provider.
3498    pub base_url: String,
3499    /// Full headers map for this provider.
3500    /// May include authorization, routing, or other integration-specific headers.
3501    #[serde(default, skip_serializing_if = "HashMap::is_empty")]
3502    pub headers: HashMap<String, String>,
3503    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
3504    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
3505    /// these keys.
3506    ///
3507    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
3508    #[serde(rename = "_meta")]
3509    pub meta: Option<Meta>,
3510}
3511
3512#[cfg(feature = "unstable_llm_providers")]
3513impl SetProviderRequest {
3514    /// Builds [`SetProviderRequest`] with the required request fields set; optional fields start unset or empty.
3515    #[must_use]
3516    pub fn new(id: impl Into<String>, api_type: LlmProtocol, base_url: impl Into<String>) -> Self {
3517        Self {
3518            id: id.into(),
3519            api_type,
3520            base_url: base_url.into(),
3521            headers: HashMap::new(),
3522            meta: None,
3523        }
3524    }
3525
3526    /// Full headers map for this provider.
3527    /// May include authorization, routing, or other integration-specific headers.
3528    #[must_use]
3529    pub fn headers(mut self, headers: HashMap<String, String>) -> Self {
3530        self.headers = headers;
3531        self
3532    }
3533
3534    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
3535    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
3536    /// these keys.
3537    ///
3538    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
3539    #[must_use]
3540    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3541        self.meta = meta.into_option();
3542        self
3543    }
3544}
3545
3546/// **UNSTABLE**
3547///
3548/// This capability is not part of the spec yet, and may be removed or changed at any point.
3549///
3550/// Response to `providers/set`.
3551#[cfg(feature = "unstable_llm_providers")]
3552#[skip_serializing_none]
3553#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3554#[schemars(extend("x-side" = "agent", "x-method" = PROVIDERS_SET_METHOD_NAME))]
3555#[serde(rename_all = "camelCase")]
3556#[non_exhaustive]
3557pub struct SetProviderResponse {
3558    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
3559    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
3560    /// these keys.
3561    ///
3562    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
3563    #[serde(rename = "_meta")]
3564    pub meta: Option<Meta>,
3565}
3566
3567#[cfg(feature = "unstable_llm_providers")]
3568impl SetProviderResponse {
3569    /// Builds [`SetProviderResponse`] with the required response fields set; optional fields start unset or empty.
3570    #[must_use]
3571    pub fn new() -> Self {
3572        Self::default()
3573    }
3574
3575    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
3576    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
3577    /// these keys.
3578    ///
3579    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
3580    #[must_use]
3581    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3582        self.meta = meta.into_option();
3583        self
3584    }
3585}
3586
3587/// **UNSTABLE**
3588///
3589/// This capability is not part of the spec yet, and may be removed or changed at any point.
3590///
3591/// Request parameters for `providers/disable`.
3592#[cfg(feature = "unstable_llm_providers")]
3593#[skip_serializing_none]
3594#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3595#[schemars(extend("x-side" = "agent", "x-method" = PROVIDERS_DISABLE_METHOD_NAME))]
3596#[serde(rename_all = "camelCase")]
3597#[non_exhaustive]
3598pub struct DisableProviderRequest {
3599    /// Provider id to disable.
3600    pub id: String,
3601    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
3602    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
3603    /// these keys.
3604    ///
3605    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
3606    #[serde(rename = "_meta")]
3607    pub meta: Option<Meta>,
3608}
3609
3610#[cfg(feature = "unstable_llm_providers")]
3611impl DisableProviderRequest {
3612    /// Builds [`DisableProviderRequest`] with the required request fields set; optional fields start unset or empty.
3613    #[must_use]
3614    pub fn new(id: impl Into<String>) -> Self {
3615        Self {
3616            id: id.into(),
3617            meta: None,
3618        }
3619    }
3620
3621    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
3622    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
3623    /// these keys.
3624    ///
3625    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
3626    #[must_use]
3627    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3628        self.meta = meta.into_option();
3629        self
3630    }
3631}
3632
3633/// **UNSTABLE**
3634///
3635/// This capability is not part of the spec yet, and may be removed or changed at any point.
3636///
3637/// Response to `providers/disable`.
3638#[cfg(feature = "unstable_llm_providers")]
3639#[skip_serializing_none]
3640#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3641#[schemars(extend("x-side" = "agent", "x-method" = PROVIDERS_DISABLE_METHOD_NAME))]
3642#[serde(rename_all = "camelCase")]
3643#[non_exhaustive]
3644pub struct DisableProviderResponse {
3645    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
3646    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
3647    /// these keys.
3648    ///
3649    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
3650    #[serde(rename = "_meta")]
3651    pub meta: Option<Meta>,
3652}
3653
3654#[cfg(feature = "unstable_llm_providers")]
3655impl DisableProviderResponse {
3656    /// Builds [`DisableProviderResponse`] with the required response fields set; optional fields start unset or empty.
3657    #[must_use]
3658    pub fn new() -> Self {
3659        Self::default()
3660    }
3661
3662    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
3663    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
3664    /// these keys.
3665    ///
3666    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
3667    #[must_use]
3668    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3669        self.meta = meta.into_option();
3670        self
3671    }
3672}
3673
3674// Capabilities
3675
3676/// Capabilities supported by the agent.
3677///
3678/// Advertised during initialization to inform the client about
3679/// available features and content types.
3680///
3681/// See protocol docs: [Agent Capabilities](https://agentclientprotocol.com/protocol/initialization#agent-capabilities)
3682#[serde_as]
3683#[skip_serializing_none]
3684#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3685#[serde(rename_all = "camelCase")]
3686#[non_exhaustive]
3687pub struct AgentCapabilities {
3688    /// Session capabilities supported by the agent.
3689    ///
3690    /// Optional. Omitted or `null` both mean the agent does not support the
3691    /// `session/*` method surface. Supplying `{}` means the agent supports the
3692    /// baseline session methods: `session/new`, `session/prompt`,
3693    /// `session/cancel`, and `session/update`.
3694    #[serde_as(deserialize_as = "DefaultOnError")]
3695    #[schemars(extend("x-deserialize-default-on-error" = true))]
3696    #[serde(default)]
3697    pub session: Option<SessionCapabilities>,
3698    /// Authentication-related capabilities supported by the agent.
3699    #[serde(default)]
3700    pub auth: AgentAuthCapabilities,
3701    /// **UNSTABLE**
3702    ///
3703    /// This capability is not part of the spec yet, and may be removed or changed at any point.
3704    ///
3705    /// Provider configuration capabilities supported by the agent.
3706    ///
3707    /// By supplying `{}` it means that the agent supports provider configuration methods.
3708    #[cfg(feature = "unstable_llm_providers")]
3709    #[serde_as(deserialize_as = "DefaultOnError")]
3710    #[schemars(extend("x-deserialize-default-on-error" = true))]
3711    #[serde(default)]
3712    pub providers: Option<ProvidersCapabilities>,
3713    /// **UNSTABLE**
3714    ///
3715    /// This capability is not part of the spec yet, and may be removed or changed at any point.
3716    ///
3717    /// NES (Next Edit Suggestions) capabilities supported by the agent.
3718    #[cfg(feature = "unstable_nes")]
3719    #[serde_as(deserialize_as = "DefaultOnError")]
3720    #[schemars(extend("x-deserialize-default-on-error" = true))]
3721    #[serde(default)]
3722    pub nes: Option<NesCapabilities>,
3723    /// **UNSTABLE**
3724    ///
3725    /// This capability is not part of the spec yet, and may be removed or changed at any point.
3726    ///
3727    /// The position encoding selected by the agent from the client's supported encodings.
3728    #[cfg(feature = "unstable_nes")]
3729    #[serde_as(deserialize_as = "DefaultOnError")]
3730    #[schemars(extend("x-deserialize-default-on-error" = true))]
3731    #[serde(default)]
3732    pub position_encoding: Option<PositionEncodingKind>,
3733    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
3734    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
3735    /// these keys.
3736    ///
3737    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
3738    #[serde(rename = "_meta")]
3739    pub meta: Option<Meta>,
3740}
3741
3742impl AgentCapabilities {
3743    /// Builds an empty [`AgentCapabilities`]; use builder methods to advertise supported sub-capabilities.
3744    #[must_use]
3745    pub fn new() -> Self {
3746        Self::default()
3747    }
3748
3749    /// Session capabilities supported by the agent.
3750    ///
3751    /// Omitted or `null` both mean the agent does not support the `session/*`
3752    /// method surface. Supplying `{}` means the agent supports the baseline
3753    /// session methods: `session/new`, `session/prompt`, `session/cancel`, and
3754    /// `session/update`.
3755    #[must_use]
3756    pub fn session(mut self, session: impl IntoOption<SessionCapabilities>) -> Self {
3757        self.session = session.into_option();
3758        self
3759    }
3760
3761    /// Authentication-related capabilities supported by the agent.
3762    #[must_use]
3763    pub fn auth(mut self, auth: AgentAuthCapabilities) -> Self {
3764        self.auth = auth;
3765        self
3766    }
3767
3768    /// **UNSTABLE**
3769    ///
3770    /// This capability is not part of the spec yet, and may be removed or changed at any point.
3771    ///
3772    /// Provider configuration capabilities supported by the agent.
3773    #[cfg(feature = "unstable_llm_providers")]
3774    #[must_use]
3775    pub fn providers(mut self, providers: impl IntoOption<ProvidersCapabilities>) -> Self {
3776        self.providers = providers.into_option();
3777        self
3778    }
3779
3780    /// **UNSTABLE**
3781    ///
3782    /// This capability is not part of the spec yet, and may be removed or changed at any point.
3783    ///
3784    /// NES (Next Edit Suggestions) capabilities supported by the agent.
3785    #[cfg(feature = "unstable_nes")]
3786    #[must_use]
3787    pub fn nes(mut self, nes: impl IntoOption<NesCapabilities>) -> Self {
3788        self.nes = nes.into_option();
3789        self
3790    }
3791
3792    /// **UNSTABLE**
3793    ///
3794    /// The position encoding selected by the agent from the client's supported encodings.
3795    #[cfg(feature = "unstable_nes")]
3796    #[must_use]
3797    pub fn position_encoding(
3798        mut self,
3799        position_encoding: impl IntoOption<PositionEncodingKind>,
3800    ) -> Self {
3801        self.position_encoding = position_encoding.into_option();
3802        self
3803    }
3804
3805    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
3806    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
3807    /// these keys.
3808    ///
3809    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
3810    #[must_use]
3811    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3812        self.meta = meta.into_option();
3813        self
3814    }
3815}
3816
3817/// **UNSTABLE**
3818///
3819/// This capability is not part of the spec yet, and may be removed or changed at any point.
3820///
3821/// Provider configuration capabilities supported by the agent.
3822///
3823/// By supplying `{}` it means that the agent supports provider configuration methods.
3824#[cfg(feature = "unstable_llm_providers")]
3825#[skip_serializing_none]
3826#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3827#[non_exhaustive]
3828pub struct ProvidersCapabilities {
3829    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
3830    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
3831    /// these keys.
3832    ///
3833    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
3834    #[serde(rename = "_meta")]
3835    pub meta: Option<Meta>,
3836}
3837
3838#[cfg(feature = "unstable_llm_providers")]
3839impl ProvidersCapabilities {
3840    /// Builds an empty [`ProvidersCapabilities`]; use builder methods to advertise supported sub-capabilities.
3841    #[must_use]
3842    pub fn new() -> Self {
3843        Self::default()
3844    }
3845
3846    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
3847    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
3848    /// these keys.
3849    ///
3850    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
3851    #[must_use]
3852    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3853        self.meta = meta.into_option();
3854        self
3855    }
3856}
3857
3858/// Session capabilities supported by the agent.
3859///
3860/// Supplying `{}` means the agent supports the baseline session methods:
3861/// `session/new`, `session/prompt`, `session/cancel`, and `session/update`.
3862///
3863/// Agents that support sessions **MAY** support additional session methods,
3864/// prompt content types, and MCP transports by specifying additional
3865/// capabilities.
3866///
3867/// See protocol docs: [Session Capabilities](https://agentclientprotocol.com/protocol/initialization#session-capabilities)
3868#[serde_as]
3869#[skip_serializing_none]
3870#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3871#[serde(rename_all = "camelCase")]
3872#[non_exhaustive]
3873pub struct SessionCapabilities {
3874    /// Prompt capabilities supported by the agent in `session/prompt` requests.
3875    ///
3876    /// Optional. Omitted or `null` both mean the agent does not advertise any
3877    /// prompt extensions beyond the baseline text and resource-link content
3878    /// required by `session/prompt`.
3879    #[serde_as(deserialize_as = "DefaultOnError")]
3880    #[schemars(extend("x-deserialize-default-on-error" = true))]
3881    #[serde(default)]
3882    pub prompt: Option<PromptCapabilities>,
3883    /// MCP capabilities supported by the agent for session lifecycle requests.
3884    ///
3885    /// Optional. Omitted or `null` both mean the agent does not advertise MCP
3886    /// server transport support for sessions.
3887    #[serde_as(deserialize_as = "DefaultOnError")]
3888    #[schemars(extend("x-deserialize-default-on-error" = true))]
3889    #[serde(default)]
3890    pub mcp: Option<McpCapabilities>,
3891    /// Whether the agent supports `session/load`.
3892    ///
3893    /// Optional. Omitted or `null` both mean the agent does not advertise support.
3894    /// Supplying `{}` means the agent supports loading sessions.
3895    #[serde_as(deserialize_as = "DefaultOnError")]
3896    #[schemars(extend("x-deserialize-default-on-error" = true))]
3897    #[serde(default)]
3898    pub load: Option<SessionLoadCapabilities>,
3899    /// Whether the agent supports `session/list`.
3900    #[serde_as(deserialize_as = "DefaultOnError")]
3901    #[schemars(extend("x-deserialize-default-on-error" = true))]
3902    #[serde(default)]
3903    pub list: Option<SessionListCapabilities>,
3904    /// Whether the agent supports `session/delete`.
3905    ///
3906    /// Optional. Omitted or `null` both mean the agent does not advertise support.
3907    /// Supplying `{}` means the agent supports deleting sessions from `session/list`.
3908    #[serde_as(deserialize_as = "DefaultOnError")]
3909    #[schemars(extend("x-deserialize-default-on-error" = true))]
3910    #[serde(default)]
3911    pub delete: Option<SessionDeleteCapabilities>,
3912    /// Whether the agent supports `additionalDirectories` on supported session lifecycle requests.
3913    ///
3914    /// Agents that also support `session/list` may return
3915    /// `SessionInfo.additionalDirectories` to report the complete ordered
3916    /// additional-root list associated with a listed session.
3917    #[serde_as(deserialize_as = "DefaultOnError")]
3918    #[schemars(extend("x-deserialize-default-on-error" = true))]
3919    #[serde(default)]
3920    pub additional_directories: Option<SessionAdditionalDirectoriesCapabilities>,
3921    /// **UNSTABLE**
3922    ///
3923    /// This capability is not part of the spec yet, and may be removed or changed at any point.
3924    ///
3925    /// Whether the agent supports `session/fork`.
3926    #[cfg(feature = "unstable_session_fork")]
3927    #[serde_as(deserialize_as = "DefaultOnError")]
3928    #[schemars(extend("x-deserialize-default-on-error" = true))]
3929    #[serde(default)]
3930    pub fork: Option<SessionForkCapabilities>,
3931    /// Whether the agent supports `session/resume`.
3932    #[serde_as(deserialize_as = "DefaultOnError")]
3933    #[schemars(extend("x-deserialize-default-on-error" = true))]
3934    #[serde(default)]
3935    pub resume: Option<SessionResumeCapabilities>,
3936    /// Whether the agent supports `session/close`.
3937    #[serde_as(deserialize_as = "DefaultOnError")]
3938    #[schemars(extend("x-deserialize-default-on-error" = true))]
3939    #[serde(default)]
3940    pub close: Option<SessionCloseCapabilities>,
3941    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
3942    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
3943    /// these keys.
3944    ///
3945    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
3946    #[serde(rename = "_meta")]
3947    pub meta: Option<Meta>,
3948}
3949
3950impl SessionCapabilities {
3951    /// Builds an empty [`SessionCapabilities`]; use builder methods to advertise supported sub-capabilities.
3952    #[must_use]
3953    pub fn new() -> Self {
3954        Self::default()
3955    }
3956
3957    /// Prompt capabilities supported by the agent in `session/prompt` requests.
3958    ///
3959    /// Omitted or `null` both mean the agent does not advertise any prompt
3960    /// extensions beyond the baseline text and resource-link content required by
3961    /// `session/prompt`.
3962    #[must_use]
3963    pub fn prompt(mut self, prompt: impl IntoOption<PromptCapabilities>) -> Self {
3964        self.prompt = prompt.into_option();
3965        self
3966    }
3967
3968    /// MCP capabilities supported by the agent for session lifecycle requests.
3969    ///
3970    /// Omitted or `null` both mean the agent does not advertise MCP server
3971    /// transport support for sessions.
3972    #[must_use]
3973    pub fn mcp(mut self, mcp: impl IntoOption<McpCapabilities>) -> Self {
3974        self.mcp = mcp.into_option();
3975        self
3976    }
3977
3978    /// Whether the agent supports `session/load`.
3979    ///
3980    /// Omitted or `null` both mean the agent does not advertise support.
3981    /// Supplying `{}` means the agent supports loading sessions.
3982    #[must_use]
3983    pub fn load(mut self, load: impl IntoOption<SessionLoadCapabilities>) -> Self {
3984        self.load = load.into_option();
3985        self
3986    }
3987
3988    /// Whether the agent supports `session/list`.
3989    #[must_use]
3990    pub fn list(mut self, list: impl IntoOption<SessionListCapabilities>) -> Self {
3991        self.list = list.into_option();
3992        self
3993    }
3994
3995    /// Whether the agent supports `session/delete`.
3996    ///
3997    /// Omitted or `null` both mean the agent does not advertise support.
3998    /// Supplying `{}` means the agent supports deleting sessions from `session/list`.
3999    #[must_use]
4000    pub fn delete(mut self, delete: impl IntoOption<SessionDeleteCapabilities>) -> Self {
4001        self.delete = delete.into_option();
4002        self
4003    }
4004
4005    /// Whether the agent supports `additionalDirectories` on supported session lifecycle requests.
4006    ///
4007    /// Agents that also support `session/list` may return
4008    /// `SessionInfo.additionalDirectories` to report the complete ordered
4009    /// additional-root list associated with a listed session.
4010    #[must_use]
4011    pub fn additional_directories(
4012        mut self,
4013        additional_directories: impl IntoOption<SessionAdditionalDirectoriesCapabilities>,
4014    ) -> Self {
4015        self.additional_directories = additional_directories.into_option();
4016        self
4017    }
4018
4019    #[cfg(feature = "unstable_session_fork")]
4020    /// Whether the agent supports `session/fork`.
4021    #[must_use]
4022    pub fn fork(mut self, fork: impl IntoOption<SessionForkCapabilities>) -> Self {
4023        self.fork = fork.into_option();
4024        self
4025    }
4026
4027    /// Whether the agent supports `session/resume`.
4028    #[must_use]
4029    pub fn resume(mut self, resume: impl IntoOption<SessionResumeCapabilities>) -> Self {
4030        self.resume = resume.into_option();
4031        self
4032    }
4033
4034    /// Whether the agent supports `session/close`.
4035    #[must_use]
4036    pub fn close(mut self, close: impl IntoOption<SessionCloseCapabilities>) -> Self {
4037        self.close = close.into_option();
4038        self
4039    }
4040
4041    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
4042    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
4043    /// these keys.
4044    ///
4045    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
4046    #[must_use]
4047    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4048        self.meta = meta.into_option();
4049        self
4050    }
4051}
4052
4053/// Capabilities for the `session/load` method.
4054///
4055/// Supplying `{}` means the agent supports loading sessions.
4056#[skip_serializing_none]
4057#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
4058#[non_exhaustive]
4059pub struct SessionLoadCapabilities {
4060    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
4061    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
4062    /// these keys.
4063    ///
4064    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
4065    #[serde(rename = "_meta")]
4066    pub meta: Option<Meta>,
4067}
4068
4069impl SessionLoadCapabilities {
4070    /// Builds an empty [`SessionLoadCapabilities`]; use builder methods to advertise supported sub-capabilities.
4071    #[must_use]
4072    pub fn new() -> Self {
4073        Self::default()
4074    }
4075
4076    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
4077    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
4078    /// these keys.
4079    ///
4080    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
4081    #[must_use]
4082    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4083        self.meta = meta.into_option();
4084        self
4085    }
4086}
4087
4088/// Capabilities for the `session/list` method.
4089///
4090/// By supplying `{}` it means that the agent supports listing of sessions.
4091#[skip_serializing_none]
4092#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
4093#[non_exhaustive]
4094pub struct SessionListCapabilities {
4095    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
4096    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
4097    /// these keys.
4098    ///
4099    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
4100    #[serde(rename = "_meta")]
4101    pub meta: Option<Meta>,
4102}
4103
4104impl SessionListCapabilities {
4105    /// Builds an empty [`SessionListCapabilities`]; use builder methods to advertise supported sub-capabilities.
4106    #[must_use]
4107    pub fn new() -> Self {
4108        Self::default()
4109    }
4110
4111    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
4112    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
4113    /// these keys.
4114    ///
4115    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
4116    #[must_use]
4117    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4118        self.meta = meta.into_option();
4119        self
4120    }
4121}
4122
4123/// Capabilities for the `session/delete` method.
4124///
4125/// Supplying `{}` means the agent supports deleting sessions from `session/list`.
4126#[skip_serializing_none]
4127#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
4128#[non_exhaustive]
4129pub struct SessionDeleteCapabilities {
4130    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
4131    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
4132    /// these keys.
4133    ///
4134    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
4135    #[serde(rename = "_meta")]
4136    pub meta: Option<Meta>,
4137}
4138
4139impl SessionDeleteCapabilities {
4140    /// Builds an empty [`SessionDeleteCapabilities`]; use builder methods to advertise supported sub-capabilities.
4141    #[must_use]
4142    pub fn new() -> Self {
4143        Self::default()
4144    }
4145
4146    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
4147    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
4148    /// these keys.
4149    ///
4150    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
4151    #[must_use]
4152    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4153        self.meta = meta.into_option();
4154        self
4155    }
4156}
4157
4158/// Capabilities for additional session directories support.
4159///
4160/// By supplying `{}` it means that the agent supports the `additionalDirectories`
4161/// field on supported session lifecycle requests. Agents that also support
4162/// `session/list` may return `SessionInfo.additionalDirectories` to report the
4163/// complete ordered additional-root list associated with a listed session.
4164#[skip_serializing_none]
4165#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
4166#[non_exhaustive]
4167pub struct SessionAdditionalDirectoriesCapabilities {
4168    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
4169    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
4170    /// these keys.
4171    ///
4172    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
4173    #[serde(rename = "_meta")]
4174    pub meta: Option<Meta>,
4175}
4176
4177impl SessionAdditionalDirectoriesCapabilities {
4178    /// Builds an empty [`SessionAdditionalDirectoriesCapabilities`]; use builder methods to advertise supported sub-capabilities.
4179    #[must_use]
4180    pub fn new() -> Self {
4181        Self::default()
4182    }
4183
4184    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
4185    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
4186    /// these keys.
4187    ///
4188    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
4189    #[must_use]
4190    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4191        self.meta = meta.into_option();
4192        self
4193    }
4194}
4195
4196/// **UNSTABLE**
4197///
4198/// This capability is not part of the spec yet, and may be removed or changed at any point.
4199///
4200/// Capabilities for the `session/fork` method.
4201///
4202/// By supplying `{}` it means that the agent supports forking of sessions.
4203#[cfg(feature = "unstable_session_fork")]
4204#[skip_serializing_none]
4205#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
4206#[non_exhaustive]
4207pub struct SessionForkCapabilities {
4208    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
4209    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
4210    /// these keys.
4211    ///
4212    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
4213    #[serde(rename = "_meta")]
4214    pub meta: Option<Meta>,
4215}
4216
4217#[cfg(feature = "unstable_session_fork")]
4218impl SessionForkCapabilities {
4219    /// Builds an empty [`SessionForkCapabilities`]; use builder methods to advertise supported sub-capabilities.
4220    #[must_use]
4221    pub fn new() -> Self {
4222        Self::default()
4223    }
4224
4225    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
4226    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
4227    /// these keys.
4228    ///
4229    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
4230    #[must_use]
4231    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4232        self.meta = meta.into_option();
4233        self
4234    }
4235}
4236
4237/// Capabilities for the `session/resume` method.
4238///
4239/// By supplying `{}` it means that the agent supports resuming of sessions.
4240#[skip_serializing_none]
4241#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
4242#[non_exhaustive]
4243pub struct SessionResumeCapabilities {
4244    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
4245    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
4246    /// these keys.
4247    ///
4248    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
4249    #[serde(rename = "_meta")]
4250    pub meta: Option<Meta>,
4251}
4252
4253impl SessionResumeCapabilities {
4254    /// Builds an empty [`SessionResumeCapabilities`]; use builder methods to advertise supported sub-capabilities.
4255    #[must_use]
4256    pub fn new() -> Self {
4257        Self::default()
4258    }
4259
4260    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
4261    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
4262    /// these keys.
4263    ///
4264    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
4265    #[must_use]
4266    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4267        self.meta = meta.into_option();
4268        self
4269    }
4270}
4271
4272/// Capabilities for the `session/close` method.
4273///
4274/// By supplying `{}` it means that the agent supports closing of sessions.
4275#[skip_serializing_none]
4276#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
4277#[non_exhaustive]
4278pub struct SessionCloseCapabilities {
4279    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
4280    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
4281    /// these keys.
4282    ///
4283    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
4284    #[serde(rename = "_meta")]
4285    pub meta: Option<Meta>,
4286}
4287
4288impl SessionCloseCapabilities {
4289    /// Builds an empty [`SessionCloseCapabilities`]; use builder methods to advertise supported sub-capabilities.
4290    #[must_use]
4291    pub fn new() -> Self {
4292        Self::default()
4293    }
4294
4295    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
4296    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
4297    /// these keys.
4298    ///
4299    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
4300    #[must_use]
4301    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4302        self.meta = meta.into_option();
4303        self
4304    }
4305}
4306
4307/// Prompt capabilities supported by the agent in `session/prompt` requests.
4308///
4309/// Baseline agent functionality requires support for [`ContentBlock::Text`]
4310/// and [`ContentBlock::ResourceLink`] in prompt requests.
4311///
4312/// Other variants must be explicitly opted in to.
4313/// Capabilities for different types of content in prompt requests.
4314///
4315/// Indicates which content types beyond the baseline (text and resource links)
4316/// the agent can process.
4317///
4318/// See protocol docs: [Prompt Capabilities](https://agentclientprotocol.com/protocol/initialization#prompt-capabilities)
4319#[serde_as]
4320#[skip_serializing_none]
4321#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
4322#[serde(rename_all = "camelCase")]
4323#[non_exhaustive]
4324pub struct PromptCapabilities {
4325    /// Agent supports [`ContentBlock::Image`].
4326    ///
4327    /// Optional. Omitted or `null` both mean the agent does not advertise support.
4328    /// Supplying `{}` means the agent supports image content in prompts.
4329    #[serde_as(deserialize_as = "DefaultOnError")]
4330    #[schemars(extend("x-deserialize-default-on-error" = true))]
4331    #[serde(default)]
4332    pub image: Option<PromptImageCapabilities>,
4333    /// Agent supports [`ContentBlock::Audio`].
4334    ///
4335    /// Optional. Omitted or `null` both mean the agent does not advertise support.
4336    /// Supplying `{}` means the agent supports audio content in prompts.
4337    #[serde_as(deserialize_as = "DefaultOnError")]
4338    #[schemars(extend("x-deserialize-default-on-error" = true))]
4339    #[serde(default)]
4340    pub audio: Option<PromptAudioCapabilities>,
4341    /// Agent supports embedded context in `session/prompt` requests.
4342    ///
4343    /// When enabled, the Client is allowed to include [`ContentBlock::Resource`]
4344    /// in prompt requests for pieces of context that are referenced in the message.
4345    ///
4346    /// Optional. Omitted or `null` both mean the agent does not advertise support.
4347    /// Supplying `{}` means the agent supports embedded context in prompts.
4348    #[serde_as(deserialize_as = "DefaultOnError")]
4349    #[schemars(extend("x-deserialize-default-on-error" = true))]
4350    #[serde(default)]
4351    pub embedded_context: Option<PromptEmbeddedContextCapabilities>,
4352    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
4353    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
4354    /// these keys.
4355    ///
4356    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
4357    #[serde(rename = "_meta")]
4358    pub meta: Option<Meta>,
4359}
4360
4361impl PromptCapabilities {
4362    /// Builds an empty [`PromptCapabilities`]; use builder methods to advertise supported sub-capabilities.
4363    #[must_use]
4364    pub fn new() -> Self {
4365        Self::default()
4366    }
4367
4368    /// Agent supports [`ContentBlock::Image`].
4369    ///
4370    /// Omitted or `null` both mean the agent does not advertise support.
4371    /// Supplying `{}` means the agent supports image content in prompts.
4372    #[must_use]
4373    pub fn image(mut self, image: impl IntoOption<PromptImageCapabilities>) -> Self {
4374        self.image = image.into_option();
4375        self
4376    }
4377
4378    /// Agent supports [`ContentBlock::Audio`].
4379    ///
4380    /// Omitted or `null` both mean the agent does not advertise support.
4381    /// Supplying `{}` means the agent supports audio content in prompts.
4382    #[must_use]
4383    pub fn audio(mut self, audio: impl IntoOption<PromptAudioCapabilities>) -> Self {
4384        self.audio = audio.into_option();
4385        self
4386    }
4387
4388    /// Agent supports embedded context in `session/prompt` requests.
4389    ///
4390    /// When enabled, the Client is allowed to include [`ContentBlock::Resource`]
4391    /// in prompt requests for pieces of context that are referenced in the message.
4392    ///
4393    /// Omitted or `null` both mean the agent does not advertise support.
4394    /// Supplying `{}` means the agent supports embedded context in prompts.
4395    #[must_use]
4396    pub fn embedded_context(
4397        mut self,
4398        embedded_context: impl IntoOption<PromptEmbeddedContextCapabilities>,
4399    ) -> Self {
4400        self.embedded_context = embedded_context.into_option();
4401        self
4402    }
4403
4404    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
4405    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
4406    /// these keys.
4407    ///
4408    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
4409    #[must_use]
4410    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4411        self.meta = meta.into_option();
4412        self
4413    }
4414}
4415
4416/// Capabilities for image content in prompt requests.
4417///
4418/// Supplying `{}` means the agent supports image content in prompts.
4419#[skip_serializing_none]
4420#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
4421#[non_exhaustive]
4422pub struct PromptImageCapabilities {
4423    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
4424    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
4425    /// these keys.
4426    ///
4427    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
4428    #[serde(rename = "_meta")]
4429    pub meta: Option<Meta>,
4430}
4431
4432impl PromptImageCapabilities {
4433    /// Builds an empty [`PromptImageCapabilities`]; use builder methods to advertise supported sub-capabilities.
4434    #[must_use]
4435    pub fn new() -> Self {
4436        Self::default()
4437    }
4438
4439    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
4440    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
4441    /// these keys.
4442    ///
4443    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
4444    #[must_use]
4445    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4446        self.meta = meta.into_option();
4447        self
4448    }
4449}
4450
4451/// Capabilities for audio content in prompt requests.
4452///
4453/// Supplying `{}` means the agent supports audio content in prompts.
4454#[skip_serializing_none]
4455#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
4456#[non_exhaustive]
4457pub struct PromptAudioCapabilities {
4458    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
4459    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
4460    /// these keys.
4461    ///
4462    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
4463    #[serde(rename = "_meta")]
4464    pub meta: Option<Meta>,
4465}
4466
4467impl PromptAudioCapabilities {
4468    /// Builds an empty [`PromptAudioCapabilities`]; use builder methods to advertise supported sub-capabilities.
4469    #[must_use]
4470    pub fn new() -> Self {
4471        Self::default()
4472    }
4473
4474    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
4475    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
4476    /// these keys.
4477    ///
4478    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
4479    #[must_use]
4480    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4481        self.meta = meta.into_option();
4482        self
4483    }
4484}
4485
4486/// Capabilities for embedded context in prompt requests.
4487///
4488/// Supplying `{}` means the agent supports embedded context in prompts.
4489#[skip_serializing_none]
4490#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
4491#[non_exhaustive]
4492pub struct PromptEmbeddedContextCapabilities {
4493    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
4494    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
4495    /// these keys.
4496    ///
4497    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
4498    #[serde(rename = "_meta")]
4499    pub meta: Option<Meta>,
4500}
4501
4502impl PromptEmbeddedContextCapabilities {
4503    /// Builds an empty [`PromptEmbeddedContextCapabilities`]; use builder methods to advertise supported sub-capabilities.
4504    #[must_use]
4505    pub fn new() -> Self {
4506        Self::default()
4507    }
4508
4509    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
4510    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
4511    /// these keys.
4512    ///
4513    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
4514    #[must_use]
4515    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4516        self.meta = meta.into_option();
4517        self
4518    }
4519}
4520
4521/// MCP capabilities supported by the agent for session lifecycle requests.
4522#[serde_as]
4523#[skip_serializing_none]
4524#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
4525#[serde(rename_all = "camelCase")]
4526#[non_exhaustive]
4527pub struct McpCapabilities {
4528    /// Agent supports [`McpServer::Stdio`].
4529    ///
4530    /// Optional. Omitted or `null` both mean the agent does not advertise support.
4531    /// Supplying `{}` means the agent supports stdio MCP server transports.
4532    #[serde_as(deserialize_as = "DefaultOnError")]
4533    #[schemars(extend("x-deserialize-default-on-error" = true))]
4534    #[serde(default)]
4535    pub stdio: Option<McpStdioCapabilities>,
4536    /// Agent supports [`McpServer::Http`].
4537    ///
4538    /// Optional. Omitted or `null` both mean the agent does not advertise support.
4539    /// Supplying `{}` means the agent supports HTTP MCP server transports.
4540    #[serde_as(deserialize_as = "DefaultOnError")]
4541    #[schemars(extend("x-deserialize-default-on-error" = true))]
4542    #[serde(default)]
4543    pub http: Option<McpHttpCapabilities>,
4544    /// **UNSTABLE**
4545    ///
4546    /// This capability is not part of the spec yet, and may be removed or changed at any point.
4547    ///
4548    /// Agent supports [`McpServer::Acp`].
4549    #[cfg(feature = "unstable_mcp_over_acp")]
4550    ///
4551    /// Optional. Omitted or `null` both mean the agent does not advertise support.
4552    /// Supplying `{}` means the agent supports ACP MCP server transports.
4553    #[serde_as(deserialize_as = "DefaultOnError")]
4554    #[schemars(extend("x-deserialize-default-on-error" = true))]
4555    #[serde(default)]
4556    pub acp: Option<McpAcpCapabilities>,
4557    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
4558    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
4559    /// these keys.
4560    ///
4561    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
4562    #[serde(rename = "_meta")]
4563    pub meta: Option<Meta>,
4564}
4565
4566impl McpCapabilities {
4567    /// Builds an empty [`McpCapabilities`]; use builder methods to advertise supported sub-capabilities.
4568    #[must_use]
4569    pub fn new() -> Self {
4570        Self::default()
4571    }
4572
4573    /// Agent supports [`McpServer::Stdio`].
4574    ///
4575    /// Omitted or `null` both mean the agent does not advertise support.
4576    /// Supplying `{}` means the agent supports stdio MCP server transports.
4577    #[must_use]
4578    pub fn stdio(mut self, stdio: impl IntoOption<McpStdioCapabilities>) -> Self {
4579        self.stdio = stdio.into_option();
4580        self
4581    }
4582
4583    /// Agent supports [`McpServer::Http`].
4584    ///
4585    /// Omitted or `null` both mean the agent does not advertise support.
4586    /// Supplying `{}` means the agent supports HTTP MCP server transports.
4587    #[must_use]
4588    pub fn http(mut self, http: impl IntoOption<McpHttpCapabilities>) -> Self {
4589        self.http = http.into_option();
4590        self
4591    }
4592
4593    /// **UNSTABLE**
4594    ///
4595    /// This capability is not part of the spec yet, and may be removed or changed at any point.
4596    ///
4597    /// Agent supports [`McpServer::Acp`].
4598    #[cfg(feature = "unstable_mcp_over_acp")]
4599    ///
4600    /// Omitted or `null` both mean the agent does not advertise support.
4601    /// Supplying `{}` means the agent supports ACP MCP server transports.
4602    #[must_use]
4603    pub fn acp(mut self, acp: impl IntoOption<McpAcpCapabilities>) -> Self {
4604        self.acp = acp.into_option();
4605        self
4606    }
4607
4608    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
4609    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
4610    /// these keys.
4611    ///
4612    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
4613    #[must_use]
4614    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4615        self.meta = meta.into_option();
4616        self
4617    }
4618}
4619
4620/// Capabilities for stdio MCP server transports.
4621///
4622/// Supplying `{}` means the agent supports stdio MCP server transports.
4623#[skip_serializing_none]
4624#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
4625#[non_exhaustive]
4626pub struct McpStdioCapabilities {
4627    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
4628    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
4629    /// these keys.
4630    ///
4631    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
4632    #[serde(rename = "_meta")]
4633    pub meta: Option<Meta>,
4634}
4635
4636impl McpStdioCapabilities {
4637    /// Builds an empty [`McpStdioCapabilities`]; use builder methods to advertise supported sub-capabilities.
4638    #[must_use]
4639    pub fn new() -> Self {
4640        Self::default()
4641    }
4642
4643    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
4644    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
4645    /// these keys.
4646    ///
4647    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
4648    #[must_use]
4649    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4650        self.meta = meta.into_option();
4651        self
4652    }
4653}
4654
4655/// Capabilities for HTTP MCP server transports.
4656///
4657/// Supplying `{}` means the agent supports HTTP MCP server transports.
4658#[skip_serializing_none]
4659#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
4660#[non_exhaustive]
4661pub struct McpHttpCapabilities {
4662    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
4663    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
4664    /// these keys.
4665    ///
4666    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
4667    #[serde(rename = "_meta")]
4668    pub meta: Option<Meta>,
4669}
4670
4671impl McpHttpCapabilities {
4672    /// Builds an empty [`McpHttpCapabilities`]; use builder methods to advertise supported sub-capabilities.
4673    #[must_use]
4674    pub fn new() -> Self {
4675        Self::default()
4676    }
4677
4678    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
4679    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
4680    /// these keys.
4681    ///
4682    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
4683    #[must_use]
4684    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4685        self.meta = meta.into_option();
4686        self
4687    }
4688}
4689
4690/// **UNSTABLE**
4691///
4692/// This capability is not part of the spec yet, and may be removed or changed at any point.
4693///
4694/// Capabilities for ACP MCP server transports.
4695///
4696/// Supplying `{}` means the agent supports ACP MCP server transports.
4697#[cfg(feature = "unstable_mcp_over_acp")]
4698#[skip_serializing_none]
4699#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
4700#[non_exhaustive]
4701pub struct McpAcpCapabilities {
4702    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
4703    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
4704    /// these keys.
4705    ///
4706    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
4707    #[serde(rename = "_meta")]
4708    pub meta: Option<Meta>,
4709}
4710
4711#[cfg(feature = "unstable_mcp_over_acp")]
4712impl McpAcpCapabilities {
4713    /// Builds an empty [`McpAcpCapabilities`]; use builder methods to advertise supported sub-capabilities.
4714    #[must_use]
4715    pub fn new() -> Self {
4716        Self::default()
4717    }
4718
4719    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
4720    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
4721    /// these keys.
4722    ///
4723    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
4724    #[must_use]
4725    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4726        self.meta = meta.into_option();
4727        self
4728    }
4729}
4730
4731// Method schema
4732
4733/// Names of all methods that agents handle.
4734///
4735/// Provides a centralized definition of method names used in the protocol.
4736#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
4737#[non_exhaustive]
4738pub struct AgentMethodNames {
4739    /// Method for initializing the connection.
4740    pub initialize: &'static str,
4741    /// Method for authenticating with the agent.
4742    pub authenticate: &'static str,
4743    /// Method for listing configurable providers.
4744    #[cfg(feature = "unstable_llm_providers")]
4745    pub providers_list: &'static str,
4746    /// Method for setting provider configuration.
4747    #[cfg(feature = "unstable_llm_providers")]
4748    pub providers_set: &'static str,
4749    /// Method for disabling a provider.
4750    #[cfg(feature = "unstable_llm_providers")]
4751    pub providers_disable: &'static str,
4752    /// Method for creating a new session.
4753    pub session_new: &'static str,
4754    /// Method for loading an existing session.
4755    pub session_load: &'static str,
4756    /// Method for setting a configuration option for a session.
4757    pub session_set_config_option: &'static str,
4758    /// Method for sending a prompt to the agent.
4759    pub session_prompt: &'static str,
4760    /// Notification for cancelling operations.
4761    pub session_cancel: &'static str,
4762    /// Method for exchanging MCP-over-ACP messages.
4763    #[cfg(feature = "unstable_mcp_over_acp")]
4764    pub mcp_message: &'static str,
4765    /// Method for listing existing sessions.
4766    pub session_list: &'static str,
4767    /// Method for deleting an existing session.
4768    pub session_delete: &'static str,
4769    /// Method for forking an existing session.
4770    #[cfg(feature = "unstable_session_fork")]
4771    pub session_fork: &'static str,
4772    /// Method for resuming an existing session.
4773    pub session_resume: &'static str,
4774    /// Method for closing an active session.
4775    pub session_close: &'static str,
4776    /// Method for logging out of an authenticated session.
4777    pub logout: &'static str,
4778    /// Method for starting an NES session.
4779    #[cfg(feature = "unstable_nes")]
4780    pub nes_start: &'static str,
4781    /// Method for requesting a suggestion.
4782    #[cfg(feature = "unstable_nes")]
4783    pub nes_suggest: &'static str,
4784    /// Notification for accepting a suggestion.
4785    #[cfg(feature = "unstable_nes")]
4786    pub nes_accept: &'static str,
4787    /// Notification for rejecting a suggestion.
4788    #[cfg(feature = "unstable_nes")]
4789    pub nes_reject: &'static str,
4790    /// Method for closing an NES session.
4791    #[cfg(feature = "unstable_nes")]
4792    pub nes_close: &'static str,
4793    /// Notification for document open events.
4794    #[cfg(feature = "unstable_nes")]
4795    pub document_did_open: &'static str,
4796    /// Notification for document change events.
4797    #[cfg(feature = "unstable_nes")]
4798    pub document_did_change: &'static str,
4799    /// Notification for document close events.
4800    #[cfg(feature = "unstable_nes")]
4801    pub document_did_close: &'static str,
4802    /// Notification for document save events.
4803    #[cfg(feature = "unstable_nes")]
4804    pub document_did_save: &'static str,
4805    /// Notification for document focus events.
4806    #[cfg(feature = "unstable_nes")]
4807    pub document_did_focus: &'static str,
4808}
4809
4810/// Constant containing all agent method names.
4811pub const AGENT_METHOD_NAMES: AgentMethodNames = AgentMethodNames {
4812    initialize: INITIALIZE_METHOD_NAME,
4813    authenticate: AUTHENTICATE_METHOD_NAME,
4814    #[cfg(feature = "unstable_llm_providers")]
4815    providers_list: PROVIDERS_LIST_METHOD_NAME,
4816    #[cfg(feature = "unstable_llm_providers")]
4817    providers_set: PROVIDERS_SET_METHOD_NAME,
4818    #[cfg(feature = "unstable_llm_providers")]
4819    providers_disable: PROVIDERS_DISABLE_METHOD_NAME,
4820    session_new: SESSION_NEW_METHOD_NAME,
4821    session_load: SESSION_LOAD_METHOD_NAME,
4822    session_set_config_option: SESSION_SET_CONFIG_OPTION_METHOD_NAME,
4823    session_prompt: SESSION_PROMPT_METHOD_NAME,
4824    session_cancel: SESSION_CANCEL_METHOD_NAME,
4825    #[cfg(feature = "unstable_mcp_over_acp")]
4826    mcp_message: MCP_MESSAGE_METHOD_NAME,
4827    session_list: SESSION_LIST_METHOD_NAME,
4828    session_delete: SESSION_DELETE_METHOD_NAME,
4829    #[cfg(feature = "unstable_session_fork")]
4830    session_fork: SESSION_FORK_METHOD_NAME,
4831    session_resume: SESSION_RESUME_METHOD_NAME,
4832    session_close: SESSION_CLOSE_METHOD_NAME,
4833    logout: LOGOUT_METHOD_NAME,
4834    #[cfg(feature = "unstable_nes")]
4835    nes_start: NES_START_METHOD_NAME,
4836    #[cfg(feature = "unstable_nes")]
4837    nes_suggest: NES_SUGGEST_METHOD_NAME,
4838    #[cfg(feature = "unstable_nes")]
4839    nes_accept: NES_ACCEPT_METHOD_NAME,
4840    #[cfg(feature = "unstable_nes")]
4841    nes_reject: NES_REJECT_METHOD_NAME,
4842    #[cfg(feature = "unstable_nes")]
4843    nes_close: NES_CLOSE_METHOD_NAME,
4844    #[cfg(feature = "unstable_nes")]
4845    document_did_open: DOCUMENT_DID_OPEN_METHOD_NAME,
4846    #[cfg(feature = "unstable_nes")]
4847    document_did_change: DOCUMENT_DID_CHANGE_METHOD_NAME,
4848    #[cfg(feature = "unstable_nes")]
4849    document_did_close: DOCUMENT_DID_CLOSE_METHOD_NAME,
4850    #[cfg(feature = "unstable_nes")]
4851    document_did_save: DOCUMENT_DID_SAVE_METHOD_NAME,
4852    #[cfg(feature = "unstable_nes")]
4853    document_did_focus: DOCUMENT_DID_FOCUS_METHOD_NAME,
4854};
4855
4856/// Method name for the initialize request.
4857pub(crate) const INITIALIZE_METHOD_NAME: &str = "initialize";
4858/// Method name for the authenticate request.
4859pub(crate) const AUTHENTICATE_METHOD_NAME: &str = "authenticate";
4860/// Method name for listing configurable providers.
4861#[cfg(feature = "unstable_llm_providers")]
4862pub(crate) const PROVIDERS_LIST_METHOD_NAME: &str = "providers/list";
4863/// Method name for setting provider configuration.
4864#[cfg(feature = "unstable_llm_providers")]
4865pub(crate) const PROVIDERS_SET_METHOD_NAME: &str = "providers/set";
4866/// Method name for disabling a provider.
4867#[cfg(feature = "unstable_llm_providers")]
4868pub(crate) const PROVIDERS_DISABLE_METHOD_NAME: &str = "providers/disable";
4869/// Method name for creating a new session.
4870pub(crate) const SESSION_NEW_METHOD_NAME: &str = "session/new";
4871/// Method name for loading an existing session.
4872pub(crate) const SESSION_LOAD_METHOD_NAME: &str = "session/load";
4873/// Method name for setting a configuration option for a session.
4874pub(crate) const SESSION_SET_CONFIG_OPTION_METHOD_NAME: &str = "session/set_config_option";
4875/// Method name for sending a prompt.
4876pub(crate) const SESSION_PROMPT_METHOD_NAME: &str = "session/prompt";
4877/// Method name for the cancel notification.
4878pub(crate) const SESSION_CANCEL_METHOD_NAME: &str = "session/cancel";
4879/// Method name for listing existing sessions.
4880pub(crate) const SESSION_LIST_METHOD_NAME: &str = "session/list";
4881/// Method name for deleting an existing session.
4882pub(crate) const SESSION_DELETE_METHOD_NAME: &str = "session/delete";
4883/// Method name for forking an existing session.
4884#[cfg(feature = "unstable_session_fork")]
4885pub(crate) const SESSION_FORK_METHOD_NAME: &str = "session/fork";
4886/// Method name for resuming an existing session.
4887pub(crate) const SESSION_RESUME_METHOD_NAME: &str = "session/resume";
4888/// Method name for closing an active session.
4889pub(crate) const SESSION_CLOSE_METHOD_NAME: &str = "session/close";
4890/// Method name for logging out of an authenticated session.
4891pub(crate) const LOGOUT_METHOD_NAME: &str = "logout";
4892
4893/// All possible requests that a client can send to an agent.
4894///
4895/// This enum is used internally for routing RPC requests. You typically won't need
4896/// to use this directly.
4897///
4898/// This enum encompasses all method calls from client to agent.
4899#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
4900#[serde(untagged)]
4901#[schemars(inline)]
4902#[non_exhaustive]
4903pub enum ClientRequest {
4904    /// Establishes the connection with a client and negotiates protocol capabilities.
4905    ///
4906    /// This method is called once at the beginning of the connection to:
4907    /// - Negotiate the protocol version to use
4908    /// - Exchange capability information between client and agent
4909    /// - Determine available authentication methods
4910    ///
4911    /// The agent should respond with its supported protocol version and capabilities.
4912    ///
4913    /// See protocol docs: [Initialization](https://agentclientprotocol.com/protocol/initialization)
4914    InitializeRequest(Box<InitializeRequest>),
4915    /// Authenticates the client using the specified authentication method.
4916    ///
4917    /// Called when the agent requires authentication before allowing session creation.
4918    /// The client provides the authentication method ID that was advertised during initialization.
4919    ///
4920    /// After successful authentication, the client can proceed to create sessions with
4921    /// `new_session` without receiving an `auth_required` error.
4922    ///
4923    /// See protocol docs: [Initialization](https://agentclientprotocol.com/protocol/initialization)
4924    AuthenticateRequest(AuthenticateRequest),
4925    /// **UNSTABLE**
4926    ///
4927    /// This capability is not part of the spec yet, and may be removed or changed at any point.
4928    ///
4929    /// Lists providers that can be configured by the client.
4930    #[cfg(feature = "unstable_llm_providers")]
4931    ListProvidersRequest(ListProvidersRequest),
4932    /// **UNSTABLE**
4933    ///
4934    /// This capability is not part of the spec yet, and may be removed or changed at any point.
4935    ///
4936    /// Replaces the configuration for a provider.
4937    #[cfg(feature = "unstable_llm_providers")]
4938    SetProviderRequest(Box<SetProviderRequest>),
4939    /// **UNSTABLE**
4940    ///
4941    /// This capability is not part of the spec yet, and may be removed or changed at any point.
4942    ///
4943    /// Disables a provider.
4944    #[cfg(feature = "unstable_llm_providers")]
4945    DisableProviderRequest(DisableProviderRequest),
4946    /// Logs out of the current authenticated state.
4947    ///
4948    /// After a successful logout, all new sessions will require authentication.
4949    /// There is no guarantee about the behavior of already running sessions.
4950    LogoutRequest(LogoutRequest),
4951    /// Creates a new conversation session with the agent.
4952    ///
4953    /// Sessions represent independent conversation contexts with their own history and state.
4954    ///
4955    /// The agent should:
4956    /// - Create a new session context
4957    /// - Connect to any specified MCP servers
4958    /// - Return a unique session ID for future requests
4959    ///
4960    /// May return an `auth_required` error if the agent requires authentication.
4961    ///
4962    /// See protocol docs: [Session Setup](https://agentclientprotocol.com/protocol/session-setup)
4963    NewSessionRequest(NewSessionRequest),
4964    /// Loads an existing session to resume a previous conversation.
4965    ///
4966    /// This method is only available if the agent advertises the `session.load` capability.
4967    ///
4968    /// The agent should:
4969    /// - Restore the session context and conversation history
4970    /// - Connect to the specified MCP servers
4971    /// - Stream the entire conversation history back to the client via notifications
4972    ///
4973    /// See protocol docs: [Loading Sessions](https://agentclientprotocol.com/protocol/session-setup#loading-sessions)
4974    LoadSessionRequest(LoadSessionRequest),
4975    /// Lists existing sessions known to the agent.
4976    ///
4977    /// This method is only available if the agent advertises the `session.list` capability.
4978    ///
4979    /// The agent should return metadata about sessions with optional filtering and pagination support.
4980    ListSessionsRequest(ListSessionsRequest),
4981    /// Deletes an existing session from `session/list`.
4982    ///
4983    /// This method is only available if the agent advertises the `session.delete` capability.
4984    DeleteSessionRequest(DeleteSessionRequest),
4985    #[cfg(feature = "unstable_session_fork")]
4986    /// **UNSTABLE**
4987    ///
4988    /// This capability is not part of the spec yet, and may be removed or changed at any point.
4989    ///
4990    /// Forks an existing session to create a new independent session.
4991    ///
4992    /// This method is only available if the agent advertises the `session.fork` capability.
4993    ///
4994    /// The agent should create a new session with the same conversation context as the
4995    /// original, allowing operations like generating summaries without affecting the
4996    /// original session's history.
4997    ForkSessionRequest(ForkSessionRequest),
4998    /// Resumes an existing session without returning previous messages.
4999    ///
5000    /// This method is only available if the agent advertises the `session.resume` capability.
5001    ///
5002    /// The agent should resume the session context, allowing the conversation to continue
5003    /// without replaying the message history (unlike `session/load`).
5004    ResumeSessionRequest(ResumeSessionRequest),
5005    /// Closes an active session and frees up any resources associated with it.
5006    ///
5007    /// This method is only available if the agent advertises the `session.close` capability.
5008    ///
5009    /// The agent must cancel any ongoing work (as if `session/cancel` was called)
5010    /// and then free up any resources associated with the session.
5011    CloseSessionRequest(CloseSessionRequest),
5012    /// Sets the current value for a session configuration option.
5013    SetSessionConfigOptionRequest(SetSessionConfigOptionRequest),
5014    /// Processes a user prompt within a session.
5015    ///
5016    /// This request accepts the prompt:
5017    /// - Receives user messages with optional context (files, images, etc.)
5018    /// - Returns once the prompt is accepted
5019    ///
5020    /// After acceptance, the Agent reports the accepted user message,
5021    /// processing state, output, tool calls, and completion through
5022    /// `session/update` notifications.
5023    ///
5024    /// See protocol docs: [Prompt Lifecycle](https://agentclientprotocol.com/protocol/prompt-lifecycle)
5025    PromptRequest(PromptRequest),
5026    #[cfg(feature = "unstable_nes")]
5027    /// **UNSTABLE**
5028    ///
5029    /// This capability is not part of the spec yet, and may be removed or changed at any point.
5030    ///
5031    /// Starts an NES session.
5032    StartNesRequest(Box<StartNesRequest>),
5033    #[cfg(feature = "unstable_nes")]
5034    /// **UNSTABLE**
5035    ///
5036    /// This capability is not part of the spec yet, and may be removed or changed at any point.
5037    ///
5038    /// Requests a code suggestion.
5039    SuggestNesRequest(Box<SuggestNesRequest>),
5040    #[cfg(feature = "unstable_nes")]
5041    /// **UNSTABLE**
5042    ///
5043    /// This capability is not part of the spec yet, and may be removed or changed at any point.
5044    ///
5045    /// Closes an active NES session and frees up any resources associated with it.
5046    ///
5047    /// The agent must cancel any ongoing work and then free up any resources
5048    /// associated with the NES session.
5049    CloseNesRequest(CloseNesRequest),
5050    /// **UNSTABLE**
5051    ///
5052    /// This capability is not part of the spec yet, and may be removed or changed at any point.
5053    ///
5054    /// Exchanges an MCP-over-ACP message.
5055    #[cfg(feature = "unstable_mcp_over_acp")]
5056    MessageMcpRequest(MessageMcpRequest),
5057    /// Handles extension method requests from the client.
5058    ///
5059    /// Extension methods provide a way to add custom functionality while maintaining
5060    /// protocol compatibility.
5061    ///
5062    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
5063    ExtMethodRequest(ExtRequest),
5064}
5065
5066impl ClientRequest {
5067    /// Returns the corresponding method name of the request.
5068    #[must_use]
5069    pub fn method(&self) -> &str {
5070        match self {
5071            Self::InitializeRequest(_) => AGENT_METHOD_NAMES.initialize,
5072            Self::AuthenticateRequest(_) => AGENT_METHOD_NAMES.authenticate,
5073            #[cfg(feature = "unstable_llm_providers")]
5074            Self::ListProvidersRequest(_) => AGENT_METHOD_NAMES.providers_list,
5075            #[cfg(feature = "unstable_llm_providers")]
5076            Self::SetProviderRequest(_) => AGENT_METHOD_NAMES.providers_set,
5077            #[cfg(feature = "unstable_llm_providers")]
5078            Self::DisableProviderRequest(_) => AGENT_METHOD_NAMES.providers_disable,
5079            Self::LogoutRequest(_) => AGENT_METHOD_NAMES.logout,
5080            Self::NewSessionRequest(_) => AGENT_METHOD_NAMES.session_new,
5081            Self::LoadSessionRequest(_) => AGENT_METHOD_NAMES.session_load,
5082            Self::ListSessionsRequest(_) => AGENT_METHOD_NAMES.session_list,
5083            Self::DeleteSessionRequest(_) => AGENT_METHOD_NAMES.session_delete,
5084            #[cfg(feature = "unstable_session_fork")]
5085            Self::ForkSessionRequest(_) => AGENT_METHOD_NAMES.session_fork,
5086            Self::ResumeSessionRequest(_) => AGENT_METHOD_NAMES.session_resume,
5087            Self::CloseSessionRequest(_) => AGENT_METHOD_NAMES.session_close,
5088            Self::SetSessionConfigOptionRequest(_) => AGENT_METHOD_NAMES.session_set_config_option,
5089            Self::PromptRequest(_) => AGENT_METHOD_NAMES.session_prompt,
5090            #[cfg(feature = "unstable_nes")]
5091            Self::StartNesRequest(_) => AGENT_METHOD_NAMES.nes_start,
5092            #[cfg(feature = "unstable_nes")]
5093            Self::SuggestNesRequest(_) => AGENT_METHOD_NAMES.nes_suggest,
5094            #[cfg(feature = "unstable_nes")]
5095            Self::CloseNesRequest(_) => AGENT_METHOD_NAMES.nes_close,
5096            #[cfg(feature = "unstable_mcp_over_acp")]
5097            Self::MessageMcpRequest(_) => AGENT_METHOD_NAMES.mcp_message,
5098            Self::ExtMethodRequest(ext_request) => &ext_request.method,
5099        }
5100    }
5101}
5102
5103/// All possible responses that an agent can send to a client.
5104///
5105/// This enum is used internally for routing RPC responses. You typically won't need
5106/// to use this directly - the responses are handled automatically by the connection.
5107///
5108/// These are responses to the corresponding `ClientRequest` variants.
5109#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
5110#[serde(untagged)]
5111#[schemars(inline)]
5112#[non_exhaustive]
5113pub enum AgentResponse {
5114    /// Successful result returned for a `initialize` request.
5115    InitializeResponse(Box<InitializeResponse>),
5116    /// Successful result returned for a `authenticate` request.
5117    AuthenticateResponse(#[serde(default)] AuthenticateResponse),
5118    /// Successful result returned for a `providers/list` request.
5119    #[cfg(feature = "unstable_llm_providers")]
5120    ListProvidersResponse(ListProvidersResponse),
5121    /// Successful result returned for a `providers/set` request.
5122    #[cfg(feature = "unstable_llm_providers")]
5123    SetProviderResponse(#[serde(default)] SetProviderResponse),
5124    /// Successful result returned for a `providers/disable` request.
5125    #[cfg(feature = "unstable_llm_providers")]
5126    DisableProviderResponse(#[serde(default)] DisableProviderResponse),
5127    /// Successful result returned for a `logout` request.
5128    LogoutResponse(#[serde(default)] LogoutResponse),
5129    /// Successful result returned for a `session/new` request.
5130    NewSessionResponse(NewSessionResponse),
5131    /// Successful result returned for a `session/load` request.
5132    LoadSessionResponse(#[serde(default)] LoadSessionResponse),
5133    /// Successful result returned for a `session/list` request.
5134    ListSessionsResponse(ListSessionsResponse),
5135    /// Successful result returned for a `session/delete` request.
5136    DeleteSessionResponse(#[serde(default)] DeleteSessionResponse),
5137    /// Successful result returned for a `session/fork` request.
5138    #[cfg(feature = "unstable_session_fork")]
5139    ForkSessionResponse(ForkSessionResponse),
5140    /// Successful result returned for a `session/resume` request.
5141    ResumeSessionResponse(#[serde(default)] ResumeSessionResponse),
5142    /// Successful result returned for a `session/close` request.
5143    CloseSessionResponse(#[serde(default)] CloseSessionResponse),
5144    /// Successful result returned for a `session/set_config_option` request.
5145    SetSessionConfigOptionResponse(SetSessionConfigOptionResponse),
5146    /// Successful result returned for a `session/prompt` request.
5147    PromptResponse(PromptResponse),
5148    /// Successful result returned for a `nes/start` request.
5149    #[cfg(feature = "unstable_nes")]
5150    StartNesResponse(StartNesResponse),
5151    /// Successful result returned for a `nes/suggest` request.
5152    #[cfg(feature = "unstable_nes")]
5153    SuggestNesResponse(SuggestNesResponse),
5154    /// Successful result returned for a `nes/close` request.
5155    #[cfg(feature = "unstable_nes")]
5156    CloseNesResponse(#[serde(default)] CloseNesResponse),
5157    /// Successful result returned by an extension method outside the core ACP method set.
5158    ExtMethodResponse(ExtResponse),
5159    /// Successful result returned by an MCP-over-ACP `mcp/message` request.
5160    #[cfg(feature = "unstable_mcp_over_acp")]
5161    MessageMcpResponse(MessageMcpResponse),
5162}
5163
5164/// All possible notifications that a client can send to an agent.
5165///
5166/// This enum is used internally for routing RPC notifications. You typically won't need
5167/// to use this directly.
5168///
5169/// Notifications do not expect a response.
5170#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
5171#[serde(untagged)]
5172#[schemars(inline)]
5173#[non_exhaustive]
5174pub enum ClientNotification {
5175    /// Cancels ongoing operations for a session.
5176    ///
5177    /// This is a notification sent by the client to cancel active work in a
5178    /// session.
5179    ///
5180    /// Upon receiving this notification, the Agent SHOULD:
5181    /// - Stop all language model requests as soon as possible
5182    /// - Abort all tool call invocations in progress
5183    /// - Send any pending `session/update` notifications
5184    /// - Report an idle `state_update` with `StopReason::Cancelled` after
5185    ///   cancellation succeeds
5186    ///
5187    /// See protocol docs: [Cancellation](https://agentclientprotocol.com/protocol/prompt-lifecycle#cancellation)
5188    CancelNotification(CancelNotification),
5189    #[cfg(feature = "unstable_nes")]
5190    /// **UNSTABLE**
5191    ///
5192    /// Notification sent when a file is opened in the editor.
5193    DidOpenDocumentNotification(DidOpenDocumentNotification),
5194    #[cfg(feature = "unstable_nes")]
5195    /// **UNSTABLE**
5196    ///
5197    /// Notification sent when a file is edited.
5198    DidChangeDocumentNotification(DidChangeDocumentNotification),
5199    #[cfg(feature = "unstable_nes")]
5200    /// **UNSTABLE**
5201    ///
5202    /// Notification sent when a file is closed.
5203    DidCloseDocumentNotification(DidCloseDocumentNotification),
5204    #[cfg(feature = "unstable_nes")]
5205    /// **UNSTABLE**
5206    ///
5207    /// Notification sent when a file is saved.
5208    DidSaveDocumentNotification(DidSaveDocumentNotification),
5209    #[cfg(feature = "unstable_nes")]
5210    /// **UNSTABLE**
5211    ///
5212    /// Notification sent when a file becomes the active editor tab.
5213    DidFocusDocumentNotification(Box<DidFocusDocumentNotification>),
5214    #[cfg(feature = "unstable_nes")]
5215    /// **UNSTABLE**
5216    ///
5217    /// Notification sent when a suggestion is accepted.
5218    AcceptNesNotification(AcceptNesNotification),
5219    #[cfg(feature = "unstable_nes")]
5220    /// **UNSTABLE**
5221    ///
5222    /// Notification sent when a suggestion is rejected.
5223    RejectNesNotification(RejectNesNotification),
5224    /// **UNSTABLE**
5225    ///
5226    /// This capability is not part of the spec yet, and may be removed or changed at any point.
5227    ///
5228    /// Sends an MCP-over-ACP notification.
5229    #[cfg(feature = "unstable_mcp_over_acp")]
5230    MessageMcpNotification(MessageMcpNotification),
5231    /// Handles extension notifications from the client.
5232    ///
5233    /// Extension notifications provide a way to send one-way messages for custom functionality
5234    /// while maintaining protocol compatibility.
5235    ///
5236    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
5237    ExtNotification(ExtNotification),
5238}
5239
5240impl ClientNotification {
5241    /// Returns the corresponding method name of the notification.
5242    #[must_use]
5243    pub fn method(&self) -> &str {
5244        match self {
5245            Self::CancelNotification(_) => AGENT_METHOD_NAMES.session_cancel,
5246            #[cfg(feature = "unstable_nes")]
5247            Self::DidOpenDocumentNotification(_) => AGENT_METHOD_NAMES.document_did_open,
5248            #[cfg(feature = "unstable_nes")]
5249            Self::DidChangeDocumentNotification(_) => AGENT_METHOD_NAMES.document_did_change,
5250            #[cfg(feature = "unstable_nes")]
5251            Self::DidCloseDocumentNotification(_) => AGENT_METHOD_NAMES.document_did_close,
5252            #[cfg(feature = "unstable_nes")]
5253            Self::DidSaveDocumentNotification(_) => AGENT_METHOD_NAMES.document_did_save,
5254            #[cfg(feature = "unstable_nes")]
5255            Self::DidFocusDocumentNotification(_) => AGENT_METHOD_NAMES.document_did_focus,
5256            #[cfg(feature = "unstable_nes")]
5257            Self::AcceptNesNotification(_) => AGENT_METHOD_NAMES.nes_accept,
5258            #[cfg(feature = "unstable_nes")]
5259            Self::RejectNesNotification(_) => AGENT_METHOD_NAMES.nes_reject,
5260            #[cfg(feature = "unstable_mcp_over_acp")]
5261            Self::MessageMcpNotification(_) => AGENT_METHOD_NAMES.mcp_message,
5262            Self::ExtNotification(ext_notification) => &ext_notification.method,
5263        }
5264    }
5265}
5266
5267/// Notification to cancel ongoing operations for a session.
5268///
5269/// See protocol docs: [Cancellation](https://agentclientprotocol.com/protocol/prompt-lifecycle#cancellation)
5270#[skip_serializing_none]
5271#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
5272#[schemars(extend("x-side" = "agent", "x-method" = SESSION_CANCEL_METHOD_NAME))]
5273#[serde(rename_all = "camelCase")]
5274#[non_exhaustive]
5275pub struct CancelNotification {
5276    /// The ID of the session to cancel operations for.
5277    pub session_id: SessionId,
5278    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
5279    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
5280    /// these keys.
5281    ///
5282    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
5283    #[serde(rename = "_meta")]
5284    pub meta: Option<Meta>,
5285}
5286
5287impl CancelNotification {
5288    /// Builds [`CancelNotification`] with the required notification fields set; optional fields start unset or empty.
5289    #[must_use]
5290    pub fn new(session_id: impl Into<SessionId>) -> Self {
5291        Self {
5292            session_id: session_id.into(),
5293            meta: None,
5294        }
5295    }
5296
5297    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
5298    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
5299    /// these keys.
5300    ///
5301    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
5302    #[must_use]
5303    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
5304        self.meta = meta.into_option();
5305        self
5306    }
5307}
5308
5309#[cfg(test)]
5310mod test_serialization {
5311    use super::*;
5312    use serde_json::json;
5313
5314    fn test_meta() -> Meta {
5315        json!({ "source": "test" }).as_object().unwrap().clone()
5316    }
5317
5318    fn serialized_meta_key_count(value: &impl serde::Serialize) -> usize {
5319        serde_json::to_string(value)
5320            .unwrap()
5321            .matches("\"_meta\"")
5322            .count()
5323    }
5324
5325    #[test]
5326    fn test_mcp_server_stdio_serialization() {
5327        let server = McpServer::Stdio(
5328            McpServerStdio::new("test-server", "/usr/bin/server")
5329                .args(vec!["--port".to_string(), "3000".to_string()])
5330                .env(vec![EnvVariable::new("API_KEY", "secret123")]),
5331        );
5332
5333        let json = serde_json::to_value(&server).unwrap();
5334        assert_eq!(
5335            json,
5336            json!({
5337                "type": "stdio",
5338                "name": "test-server",
5339                "command": "/usr/bin/server",
5340                "args": ["--port", "3000"],
5341                "env": [
5342                    {
5343                        "name": "API_KEY",
5344                        "value": "secret123"
5345                    }
5346                ]
5347            })
5348        );
5349
5350        let deserialized: McpServer = serde_json::from_value(json).unwrap();
5351        match deserialized {
5352            McpServer::Stdio(McpServerStdio {
5353                name,
5354                command,
5355                args,
5356                env,
5357                meta: _,
5358            }) => {
5359                assert_eq!(name, "test-server");
5360                assert_eq!(command, PathBuf::from("/usr/bin/server"));
5361                assert_eq!(args, vec!["--port", "3000"]);
5362                assert_eq!(env.len(), 1);
5363                assert_eq!(env[0].name, "API_KEY");
5364                assert_eq!(env[0].value, "secret123");
5365            }
5366            _ => panic!("Expected Stdio variant"),
5367        }
5368    }
5369
5370    #[test]
5371    fn test_mcp_server_unknown_transport_serialization() {
5372        let json = json!({
5373            "type": "websocket",
5374            "name": "future-server",
5375            "url": "wss://example.com/mcp",
5376            "protocolVersion": "2026-01-01"
5377        });
5378
5379        let deserialized: McpServer = serde_json::from_value(json.clone()).unwrap();
5380        let McpServer::Other(OtherMcpServer { type_, fields }) = &deserialized else {
5381            panic!("Expected Other variant");
5382        };
5383
5384        assert_eq!(type_, "websocket");
5385        assert_eq!(fields["name"], "future-server");
5386        assert_eq!(fields["url"], "wss://example.com/mcp");
5387        assert_eq!(fields["protocolVersion"], "2026-01-01");
5388        assert_eq!(serde_json::to_value(&deserialized).unwrap(), json);
5389    }
5390
5391    #[test]
5392    fn test_mcp_server_stdio_requires_type() {
5393        let result = serde_json::from_value::<McpServer>(json!({
5394            "name": "test-server",
5395            "command": "/usr/bin/server",
5396            "args": [],
5397            "env": []
5398        }));
5399
5400        assert!(result.is_err());
5401    }
5402
5403    #[test]
5404    fn test_mcp_server_unknown_does_not_hide_malformed_known_transport() {
5405        let result = serde_json::from_value::<McpServer>(json!({
5406            "type": "stdio",
5407            "name": "test-server",
5408            "args": [],
5409            "env": []
5410        }));
5411
5412        assert!(result.is_err());
5413    }
5414
5415    #[test]
5416    fn test_mcp_server_http_serialization() {
5417        let server = McpServer::Http(
5418            McpServerHttp::new("http-server", "https://api.example.com").headers(vec![
5419                HttpHeader::new("Authorization", "Bearer token123"),
5420                HttpHeader::new("Content-Type", "application/json"),
5421            ]),
5422        );
5423
5424        let json = serde_json::to_value(&server).unwrap();
5425        assert_eq!(
5426            json,
5427            json!({
5428                "type": "http",
5429                "name": "http-server",
5430                "url": "https://api.example.com",
5431                "headers": [
5432                    {
5433                        "name": "Authorization",
5434                        "value": "Bearer token123"
5435                    },
5436                    {
5437                        "name": "Content-Type",
5438                        "value": "application/json"
5439                    }
5440                ]
5441            })
5442        );
5443
5444        let deserialized: McpServer = serde_json::from_value(json).unwrap();
5445        match deserialized {
5446            McpServer::Http(McpServerHttp {
5447                name,
5448                url,
5449                headers,
5450                meta: _,
5451            }) => {
5452                assert_eq!(name, "http-server");
5453                assert_eq!(url, "https://api.example.com");
5454                assert_eq!(headers.len(), 2);
5455                assert_eq!(headers[0].name, "Authorization");
5456                assert_eq!(headers[0].value, "Bearer token123");
5457                assert_eq!(headers[1].name, "Content-Type");
5458                assert_eq!(headers[1].value, "application/json");
5459            }
5460            _ => panic!("Expected Http variant"),
5461        }
5462    }
5463
5464    #[cfg(feature = "unstable_mcp_over_acp")]
5465    #[test]
5466    fn test_client_mcp_message_method_names() {
5467        assert_eq!(AGENT_METHOD_NAMES.mcp_message, "mcp/message");
5468
5469        assert_eq!(
5470            ClientRequest::MessageMcpRequest(MessageMcpRequest::new("conn-1", "tools/list"))
5471                .method(),
5472            "mcp/message"
5473        );
5474        assert_eq!(
5475            ClientNotification::MessageMcpNotification(MessageMcpNotification::new(
5476                "conn-1",
5477                "notifications/progress"
5478            ))
5479            .method(),
5480            "mcp/message"
5481        );
5482    }
5483
5484    #[test]
5485    fn test_session_config_option_category_known_variants() {
5486        // Test serialization of known variants
5487        assert_eq!(
5488            serde_json::to_value(&SessionConfigOptionCategory::Mode).unwrap(),
5489            json!("mode")
5490        );
5491        assert_eq!(
5492            serde_json::to_value(&SessionConfigOptionCategory::Model).unwrap(),
5493            json!("model")
5494        );
5495        assert_eq!(
5496            serde_json::to_value(&SessionConfigOptionCategory::ModelConfig).unwrap(),
5497            json!("model_config")
5498        );
5499        assert_eq!(
5500            serde_json::to_value(&SessionConfigOptionCategory::ThoughtLevel).unwrap(),
5501            json!("thought_level")
5502        );
5503
5504        // Test deserialization of known variants
5505        assert_eq!(
5506            serde_json::from_str::<SessionConfigOptionCategory>("\"mode\"").unwrap(),
5507            SessionConfigOptionCategory::Mode
5508        );
5509        assert_eq!(
5510            serde_json::from_str::<SessionConfigOptionCategory>("\"model\"").unwrap(),
5511            SessionConfigOptionCategory::Model
5512        );
5513        assert_eq!(
5514            serde_json::from_str::<SessionConfigOptionCategory>("\"model_config\"").unwrap(),
5515            SessionConfigOptionCategory::ModelConfig
5516        );
5517        assert_eq!(
5518            serde_json::from_str::<SessionConfigOptionCategory>("\"thought_level\"").unwrap(),
5519            SessionConfigOptionCategory::ThoughtLevel
5520        );
5521    }
5522
5523    #[test]
5524    fn test_session_config_option_category_unknown_variants() {
5525        // Test that unknown strings are captured in Other variant
5526        let unknown: SessionConfigOptionCategory =
5527            serde_json::from_str("\"some_future_category\"").unwrap();
5528        assert_eq!(
5529            unknown,
5530            SessionConfigOptionCategory::Other("some_future_category".to_string())
5531        );
5532
5533        // Test round-trip of unknown category
5534        let json = serde_json::to_value(&unknown).unwrap();
5535        assert_eq!(json, json!("some_future_category"));
5536    }
5537
5538    #[test]
5539    fn test_session_config_option_category_custom_categories() {
5540        // Category names beginning with `_` are free for custom use
5541        let custom: SessionConfigOptionCategory =
5542            serde_json::from_str("\"_my_custom_category\"").unwrap();
5543        assert_eq!(
5544            custom,
5545            SessionConfigOptionCategory::Other("_my_custom_category".to_string())
5546        );
5547
5548        // Test round-trip preserves the custom category name
5549        let json = serde_json::to_value(&custom).unwrap();
5550        assert_eq!(json, json!("_my_custom_category"));
5551
5552        // Deserialize back and verify
5553        let deserialized: SessionConfigOptionCategory = serde_json::from_value(json).unwrap();
5554        assert_eq!(
5555            deserialized,
5556            SessionConfigOptionCategory::Other("_my_custom_category".to_string()),
5557        );
5558    }
5559
5560    #[test]
5561    fn test_auth_method_agent_serialization() {
5562        let method = AuthMethod::Agent(AuthMethodAgent::new("default-auth", "Default Auth"));
5563
5564        let json = serde_json::to_value(&method).unwrap();
5565        assert_eq!(
5566            json,
5567            json!({
5568                "id": "default-auth",
5569                "name": "Default Auth",
5570                "type": "agent"
5571            })
5572        );
5573        // description should be omitted when None
5574        assert!(!json.as_object().unwrap().contains_key("description"));
5575
5576        let deserialized: AuthMethod = serde_json::from_value(json).unwrap();
5577        match deserialized {
5578            AuthMethod::Agent(AuthMethodAgent { id, name, .. }) => {
5579                assert_eq!(id.0.as_ref(), "default-auth");
5580                assert_eq!(name, "Default Auth");
5581            }
5582            _ => panic!("Expected Agent variant"),
5583        }
5584    }
5585
5586    #[test]
5587    fn test_auth_method_agent_deserialization() {
5588        let json = json!({
5589            "id": "agent-auth",
5590            "name": "Agent Auth",
5591            "type": "agent"
5592        });
5593
5594        let deserialized: AuthMethod = serde_json::from_value(json).unwrap();
5595        assert!(matches!(deserialized, AuthMethod::Agent(_)));
5596    }
5597
5598    #[test]
5599    fn test_auth_method_agent_requires_type() {
5600        assert!(
5601            serde_json::from_value::<AuthMethod>(json!({
5602                "id": "agent-auth",
5603                "name": "Agent Auth"
5604            }))
5605            .is_err()
5606        );
5607    }
5608
5609    #[test]
5610    fn test_auth_method_agent_rejects_null_type() {
5611        assert!(
5612            serde_json::from_value::<AuthMethod>(json!({
5613                "id": "agent-auth",
5614                "name": "Agent Auth",
5615                "type": null
5616            }))
5617            .is_err()
5618        );
5619    }
5620
5621    #[test]
5622    fn test_auth_method_unknown_does_not_hide_malformed_agent() {
5623        assert!(
5624            serde_json::from_value::<AuthMethod>(json!({
5625                "id": "agent-auth",
5626                "type": "agent"
5627            }))
5628            .is_err()
5629        );
5630    }
5631
5632    #[test]
5633    fn test_auth_method_unknown_variant_roundtrip() {
5634        let method: AuthMethod = serde_json::from_value(json!({
5635            "id": "oauth",
5636            "name": "OAuth",
5637            "type": "_oauth",
5638            "authorizationUrl": "https://example.com/auth"
5639        }))
5640        .unwrap();
5641
5642        assert_eq!(method.id().0.as_ref(), "oauth");
5643        assert_eq!(method.name(), "OAuth");
5644        let AuthMethod::Other(unknown) = method else {
5645            panic!("expected unknown auth method");
5646        };
5647        assert_eq!(unknown.type_, "_oauth");
5648        assert_eq!(
5649            unknown.fields.get("authorizationUrl"),
5650            Some(&json!("https://example.com/auth"))
5651        );
5652
5653        assert_eq!(
5654            serde_json::to_value(AuthMethod::Other(unknown)).unwrap(),
5655            json!({
5656                "id": "oauth",
5657                "name": "OAuth",
5658                "type": "_oauth",
5659                "authorizationUrl": "https://example.com/auth"
5660            })
5661        );
5662    }
5663
5664    #[cfg(feature = "unstable_auth_methods")]
5665    #[test]
5666    fn test_auth_method_unknown_does_not_hide_malformed_known_variant() {
5667        assert!(
5668            serde_json::from_value::<AuthMethod>(json!({
5669                "id": "api-key",
5670                "name": "API Key",
5671                "type": "env_var"
5672            }))
5673            .is_err()
5674        );
5675    }
5676
5677    #[test]
5678    fn test_session_delete_serialization() {
5679        assert_eq!(AGENT_METHOD_NAMES.session_delete, "session/delete");
5680        assert_eq!(
5681            ClientRequest::DeleteSessionRequest(DeleteSessionRequest::new("sess_abc123")).method(),
5682            "session/delete"
5683        );
5684        assert_eq!(
5685            serde_json::to_value(DeleteSessionRequest::new("sess_abc123")).unwrap(),
5686            json!({
5687                "sessionId": "sess_abc123"
5688            })
5689        );
5690        assert_eq!(
5691            serde_json::to_value(DeleteSessionResponse::new()).unwrap(),
5692            json!({})
5693        );
5694        assert_eq!(
5695            serde_json::to_value(
5696                SessionCapabilities::new().delete(SessionDeleteCapabilities::new())
5697            )
5698            .unwrap(),
5699            json!({
5700                "delete": {}
5701            })
5702        );
5703    }
5704    #[test]
5705    fn test_session_additional_directories_serialization() {
5706        assert_eq!(
5707            serde_json::to_value(NewSessionRequest::new("/home/user/project")).unwrap(),
5708            json!({
5709                "cwd": "/home/user/project",
5710                "mcpServers": []
5711            })
5712        );
5713        assert_eq!(
5714            serde_json::to_value(
5715                NewSessionRequest::new("/home/user/project").additional_directories(vec![
5716                    PathBuf::from("/home/user/shared-lib"),
5717                    PathBuf::from("/home/user/product-docs"),
5718                ])
5719            )
5720            .unwrap(),
5721            json!({
5722                "cwd": "/home/user/project",
5723                "additionalDirectories": [
5724                    "/home/user/shared-lib",
5725                    "/home/user/product-docs"
5726                ],
5727                "mcpServers": []
5728            })
5729        );
5730        assert_eq!(
5731            serde_json::to_value(SessionInfo::new("sess_abc123", "/home/user/project")).unwrap(),
5732            json!({
5733                "sessionId": "sess_abc123",
5734                "cwd": "/home/user/project"
5735            })
5736        );
5737        assert_eq!(
5738            serde_json::to_value(
5739                SessionInfo::new("sess_abc123", "/home/user/project").additional_directories(vec![
5740                    PathBuf::from("/home/user/shared-lib"),
5741                    PathBuf::from("/home/user/product-docs"),
5742                ])
5743            )
5744            .unwrap(),
5745            json!({
5746                "sessionId": "sess_abc123",
5747                "cwd": "/home/user/project",
5748                "additionalDirectories": [
5749                    "/home/user/shared-lib",
5750                    "/home/user/product-docs"
5751                ]
5752            })
5753        );
5754        assert_eq!(
5755            serde_json::from_value::<SessionInfo>(json!({
5756                "sessionId": "sess_abc123",
5757                "cwd": "/home/user/project"
5758            }))
5759            .unwrap()
5760            .additional_directories,
5761            Vec::<PathBuf>::new()
5762        );
5763    }
5764    #[test]
5765    fn test_session_load_capabilities_serialization() {
5766        assert_eq!(
5767            serde_json::to_value(SessionCapabilities::new().load(SessionLoadCapabilities::new()))
5768                .unwrap(),
5769            json!({
5770                "load": {}
5771            })
5772        );
5773    }
5774
5775    #[test]
5776    fn test_session_additional_directories_capabilities_serialization() {
5777        assert_eq!(
5778            serde_json::to_value(
5779                SessionCapabilities::new()
5780                    .additional_directories(SessionAdditionalDirectoriesCapabilities::new())
5781            )
5782            .unwrap(),
5783            json!({
5784                "additionalDirectories": {}
5785            })
5786        );
5787    }
5788
5789    #[cfg(feature = "unstable_auth_methods")]
5790    #[test]
5791    fn test_auth_method_env_var_serialization() {
5792        let method = AuthMethod::EnvVar(AuthMethodEnvVar::new(
5793            "api-key",
5794            "API Key",
5795            vec![AuthEnvVar::new("API_KEY")],
5796        ));
5797
5798        let json = serde_json::to_value(&method).unwrap();
5799        assert_eq!(
5800            json,
5801            json!({
5802                "id": "api-key",
5803                "name": "API Key",
5804                "type": "env_var",
5805                "vars": [{"name": "API_KEY"}]
5806            })
5807        );
5808        // secret defaults to true and should be omitted; optional defaults to false and should be omitted
5809        assert!(!json["vars"][0].as_object().unwrap().contains_key("secret"));
5810        assert!(
5811            !json["vars"][0]
5812                .as_object()
5813                .unwrap()
5814                .contains_key("optional")
5815        );
5816
5817        let deserialized: AuthMethod = serde_json::from_value(json).unwrap();
5818        match deserialized {
5819            AuthMethod::EnvVar(AuthMethodEnvVar {
5820                id,
5821                name: method_name,
5822                vars,
5823                link,
5824                ..
5825            }) => {
5826                assert_eq!(id.0.as_ref(), "api-key");
5827                assert_eq!(method_name, "API Key");
5828                assert_eq!(vars.len(), 1);
5829                assert_eq!(vars[0].name, "API_KEY");
5830                assert!(vars[0].secret);
5831                assert!(!vars[0].optional);
5832                assert!(link.is_none());
5833            }
5834            _ => panic!("Expected EnvVar variant"),
5835        }
5836    }
5837
5838    #[cfg(feature = "unstable_auth_methods")]
5839    #[test]
5840    fn test_auth_method_env_var_with_link_serialization() {
5841        let method = AuthMethod::EnvVar(
5842            AuthMethodEnvVar::new("api-key", "API Key", vec![AuthEnvVar::new("API_KEY")])
5843                .link("https://example.com/keys"),
5844        );
5845
5846        let json = serde_json::to_value(&method).unwrap();
5847        assert_eq!(
5848            json,
5849            json!({
5850                "id": "api-key",
5851                "name": "API Key",
5852                "type": "env_var",
5853                "vars": [{"name": "API_KEY"}],
5854                "link": "https://example.com/keys"
5855            })
5856        );
5857
5858        let deserialized: AuthMethod = serde_json::from_value(json).unwrap();
5859        match deserialized {
5860            AuthMethod::EnvVar(AuthMethodEnvVar { link, .. }) => {
5861                assert_eq!(link.as_deref(), Some("https://example.com/keys"));
5862            }
5863            _ => panic!("Expected EnvVar variant"),
5864        }
5865    }
5866
5867    #[cfg(feature = "unstable_auth_methods")]
5868    #[test]
5869    fn test_auth_method_env_var_multiple_vars() {
5870        let method = AuthMethod::EnvVar(AuthMethodEnvVar::new(
5871            "azure-openai",
5872            "Azure OpenAI",
5873            vec![
5874                AuthEnvVar::new("AZURE_OPENAI_API_KEY").label("API Key"),
5875                AuthEnvVar::new("AZURE_OPENAI_ENDPOINT")
5876                    .label("Endpoint URL")
5877                    .secret(false),
5878                AuthEnvVar::new("AZURE_OPENAI_API_VERSION")
5879                    .label("API Version")
5880                    .secret(false)
5881                    .optional(true),
5882            ],
5883        ));
5884
5885        let json = serde_json::to_value(&method).unwrap();
5886        assert_eq!(
5887            json,
5888            json!({
5889                "id": "azure-openai",
5890                "name": "Azure OpenAI",
5891                "type": "env_var",
5892                "vars": [
5893                    {"name": "AZURE_OPENAI_API_KEY", "label": "API Key"},
5894                    {"name": "AZURE_OPENAI_ENDPOINT", "label": "Endpoint URL", "secret": false},
5895                    {"name": "AZURE_OPENAI_API_VERSION", "label": "API Version", "secret": false, "optional": true}
5896                ]
5897            })
5898        );
5899
5900        let deserialized: AuthMethod = serde_json::from_value(json).unwrap();
5901        match deserialized {
5902            AuthMethod::EnvVar(AuthMethodEnvVar { vars, .. }) => {
5903                assert_eq!(vars.len(), 3);
5904                // First var: secret (default true), not optional (default false)
5905                assert_eq!(vars[0].name, "AZURE_OPENAI_API_KEY");
5906                assert_eq!(vars[0].label.as_deref(), Some("API Key"));
5907                assert!(vars[0].secret);
5908                assert!(!vars[0].optional);
5909                // Second var: not a secret, not optional
5910                assert_eq!(vars[1].name, "AZURE_OPENAI_ENDPOINT");
5911                assert!(!vars[1].secret);
5912                assert!(!vars[1].optional);
5913                // Third var: not a secret, optional
5914                assert_eq!(vars[2].name, "AZURE_OPENAI_API_VERSION");
5915                assert!(!vars[2].secret);
5916                assert!(vars[2].optional);
5917            }
5918            _ => panic!("Expected EnvVar variant"),
5919        }
5920    }
5921
5922    #[cfg(feature = "unstable_auth_methods")]
5923    #[test]
5924    fn test_auth_method_terminal_serialization() {
5925        let method = AuthMethod::Terminal(AuthMethodTerminal::new("tui-auth", "Terminal Auth"));
5926
5927        let json = serde_json::to_value(&method).unwrap();
5928        assert_eq!(
5929            json,
5930            json!({
5931                "id": "tui-auth",
5932                "name": "Terminal Auth",
5933                "type": "terminal"
5934            })
5935        );
5936        // args and env should be omitted when empty
5937        assert!(!json.as_object().unwrap().contains_key("args"));
5938        assert!(!json.as_object().unwrap().contains_key("env"));
5939
5940        let deserialized: AuthMethod = serde_json::from_value(json).unwrap();
5941        match deserialized {
5942            AuthMethod::Terminal(AuthMethodTerminal { args, env, .. }) => {
5943                assert!(args.is_empty());
5944                assert!(env.is_empty());
5945            }
5946            _ => panic!("Expected Terminal variant"),
5947        }
5948    }
5949
5950    #[cfg(feature = "unstable_auth_methods")]
5951    #[test]
5952    fn test_auth_method_terminal_with_args_and_env_serialization() {
5953        use std::collections::HashMap;
5954
5955        let mut env = HashMap::new();
5956        env.insert("TERM".to_string(), "xterm-256color".to_string());
5957
5958        let method = AuthMethod::Terminal(
5959            AuthMethodTerminal::new("tui-auth", "Terminal Auth")
5960                .args(vec!["--interactive".to_string(), "--color".to_string()])
5961                .env(env),
5962        );
5963
5964        let json = serde_json::to_value(&method).unwrap();
5965        assert_eq!(
5966            json,
5967            json!({
5968                "id": "tui-auth",
5969                "name": "Terminal Auth",
5970                "type": "terminal",
5971                "args": ["--interactive", "--color"],
5972                "env": {
5973                    "TERM": "xterm-256color"
5974                }
5975            })
5976        );
5977
5978        let deserialized: AuthMethod = serde_json::from_value(json).unwrap();
5979        match deserialized {
5980            AuthMethod::Terminal(AuthMethodTerminal { args, env, .. }) => {
5981                assert_eq!(args, vec!["--interactive", "--color"]);
5982                assert_eq!(env.len(), 1);
5983                assert_eq!(env.get("TERM").unwrap(), "xterm-256color");
5984            }
5985            _ => panic!("Expected Terminal variant"),
5986        }
5987    }
5988
5989    #[cfg(feature = "unstable_boolean_config")]
5990    #[test]
5991    fn test_session_config_option_value_id_serialize() {
5992        let val = SessionConfigOptionValue::value_id("model-1");
5993        let json = serde_json::to_value(&val).unwrap();
5994        // ValueId omits the "type" field (it's the default)
5995        assert_eq!(json, json!({ "value": "model-1" }));
5996        assert!(!json.as_object().unwrap().contains_key("type"));
5997    }
5998
5999    #[cfg(feature = "unstable_boolean_config")]
6000    #[test]
6001    fn test_session_config_option_value_boolean_serialize() {
6002        let val = SessionConfigOptionValue::boolean(true);
6003        let json = serde_json::to_value(&val).unwrap();
6004        assert_eq!(json, json!({ "type": "boolean", "value": true }));
6005    }
6006
6007    #[cfg(feature = "unstable_boolean_config")]
6008    #[test]
6009    fn test_session_config_option_value_deserialize_no_type() {
6010        // Missing "type" should default to ValueId
6011        let json = json!({ "value": "model-1" });
6012        let val: SessionConfigOptionValue = serde_json::from_value(json).unwrap();
6013        assert_eq!(val, SessionConfigOptionValue::value_id("model-1"));
6014        assert_eq!(val.as_value_id().unwrap().to_string(), "model-1");
6015    }
6016
6017    #[cfg(feature = "unstable_boolean_config")]
6018    #[test]
6019    fn test_session_config_option_value_deserialize_boolean() {
6020        let json = json!({ "type": "boolean", "value": true });
6021        let val: SessionConfigOptionValue = serde_json::from_value(json).unwrap();
6022        assert_eq!(val, SessionConfigOptionValue::boolean(true));
6023        assert_eq!(val.as_bool(), Some(true));
6024    }
6025
6026    #[cfg(feature = "unstable_boolean_config")]
6027    #[test]
6028    fn test_session_config_option_value_deserialize_boolean_false() {
6029        let json = json!({ "type": "boolean", "value": false });
6030        let val: SessionConfigOptionValue = serde_json::from_value(json).unwrap();
6031        assert_eq!(val, SessionConfigOptionValue::boolean(false));
6032        assert_eq!(val.as_bool(), Some(false));
6033    }
6034
6035    #[cfg(feature = "unstable_boolean_config")]
6036    #[test]
6037    fn test_session_config_option_value_deserialize_unknown_type_with_string_value() {
6038        // Unknown type with a string value gracefully falls back to ValueId
6039        let json = json!({ "type": "text", "value": "freeform input" });
6040        let val: SessionConfigOptionValue = serde_json::from_value(json).unwrap();
6041        assert_eq!(val.as_value_id().unwrap().to_string(), "freeform input");
6042    }
6043
6044    #[cfg(feature = "unstable_boolean_config")]
6045    #[test]
6046    fn test_session_config_option_value_roundtrip_value_id() {
6047        let original = SessionConfigOptionValue::value_id("option-a");
6048        let json = serde_json::to_value(&original).unwrap();
6049        let roundtripped: SessionConfigOptionValue = serde_json::from_value(json).unwrap();
6050        assert_eq!(original, roundtripped);
6051    }
6052
6053    #[cfg(feature = "unstable_boolean_config")]
6054    #[test]
6055    fn test_session_config_option_value_roundtrip_boolean() {
6056        let original = SessionConfigOptionValue::boolean(false);
6057        let json = serde_json::to_value(&original).unwrap();
6058        let roundtripped: SessionConfigOptionValue = serde_json::from_value(json).unwrap();
6059        assert_eq!(original, roundtripped);
6060    }
6061
6062    #[cfg(feature = "unstable_boolean_config")]
6063    #[test]
6064    fn test_session_config_option_value_type_mismatch_boolean_with_string() {
6065        // type says "boolean" but value is a string — falls to untagged ValueId
6066        let json = json!({ "type": "boolean", "value": "not a bool" });
6067        let result = serde_json::from_value::<SessionConfigOptionValue>(json);
6068        // serde tries Boolean first (fails), then falls to untagged ValueId (succeeds)
6069        assert!(result.is_ok());
6070        assert_eq!(
6071            result.unwrap().as_value_id().unwrap().to_string(),
6072            "not a bool"
6073        );
6074    }
6075
6076    #[cfg(feature = "unstable_boolean_config")]
6077    #[test]
6078    fn test_session_config_option_value_from_impls() {
6079        let from_str: SessionConfigOptionValue = "model-1".into();
6080        assert_eq!(from_str.as_value_id().unwrap().to_string(), "model-1");
6081
6082        let from_id: SessionConfigOptionValue = SessionConfigValueId::new("model-2").into();
6083        assert_eq!(from_id.as_value_id().unwrap().to_string(), "model-2");
6084
6085        let from_bool: SessionConfigOptionValue = true.into();
6086        assert_eq!(from_bool.as_bool(), Some(true));
6087    }
6088
6089    #[cfg(feature = "unstable_boolean_config")]
6090    #[test]
6091    fn test_set_session_config_option_request_value_id() {
6092        let req = SetSessionConfigOptionRequest::new("sess_1", "model", "model-1");
6093        let json = serde_json::to_value(&req).unwrap();
6094        assert_eq!(
6095            json,
6096            json!({
6097                "sessionId": "sess_1",
6098                "configId": "model",
6099                "value": "model-1"
6100            })
6101        );
6102        // No "type" field for value_id
6103        assert!(!json.as_object().unwrap().contains_key("type"));
6104    }
6105
6106    #[cfg(feature = "unstable_boolean_config")]
6107    #[test]
6108    fn test_set_session_config_option_request_boolean() {
6109        let req = SetSessionConfigOptionRequest::new("sess_1", "brave_mode", true);
6110        let json = serde_json::to_value(&req).unwrap();
6111        assert_eq!(
6112            json,
6113            json!({
6114                "sessionId": "sess_1",
6115                "configId": "brave_mode",
6116                "type": "boolean",
6117                "value": true
6118            })
6119        );
6120    }
6121
6122    #[cfg(feature = "unstable_boolean_config")]
6123    #[test]
6124    fn test_set_session_config_option_request_deserialize_no_type() {
6125        // Backwards-compatible: no "type" field → value_id
6126        let json = json!({
6127            "sessionId": "sess_1",
6128            "configId": "model",
6129            "value": "model-1"
6130        });
6131        let req: SetSessionConfigOptionRequest = serde_json::from_value(json).unwrap();
6132        assert_eq!(req.session_id.to_string(), "sess_1");
6133        assert_eq!(req.config_id.to_string(), "model");
6134        assert_eq!(req.value.as_value_id().unwrap().to_string(), "model-1");
6135    }
6136
6137    #[cfg(feature = "unstable_boolean_config")]
6138    #[test]
6139    fn test_set_session_config_option_request_deserialize_boolean() {
6140        let json = json!({
6141            "sessionId": "sess_1",
6142            "configId": "brave_mode",
6143            "type": "boolean",
6144            "value": true
6145        });
6146        let req: SetSessionConfigOptionRequest = serde_json::from_value(json).unwrap();
6147        assert_eq!(req.value.as_bool(), Some(true));
6148    }
6149
6150    #[cfg(feature = "unstable_boolean_config")]
6151    #[test]
6152    fn test_set_session_config_option_request_roundtrip_value_id() {
6153        let original = SetSessionConfigOptionRequest::new("s", "c", "v");
6154        let json = serde_json::to_value(&original).unwrap();
6155        let roundtripped: SetSessionConfigOptionRequest = serde_json::from_value(json).unwrap();
6156        assert_eq!(original, roundtripped);
6157    }
6158
6159    #[cfg(feature = "unstable_boolean_config")]
6160    #[test]
6161    fn test_set_session_config_option_request_roundtrip_boolean() {
6162        let original = SetSessionConfigOptionRequest::new("s", "c", false);
6163        let json = serde_json::to_value(&original).unwrap();
6164        let roundtripped: SetSessionConfigOptionRequest = serde_json::from_value(json).unwrap();
6165        assert_eq!(original, roundtripped);
6166    }
6167
6168    #[cfg(feature = "unstable_boolean_config")]
6169    #[test]
6170    fn test_session_config_boolean_serialization() {
6171        let cfg = SessionConfigBoolean::new(true);
6172        let json = serde_json::to_value(&cfg).unwrap();
6173        assert_eq!(json, json!({ "currentValue": true }));
6174
6175        let deserialized: SessionConfigBoolean = serde_json::from_value(json).unwrap();
6176        assert!(deserialized.current_value);
6177    }
6178
6179    #[cfg(feature = "unstable_boolean_config")]
6180    #[test]
6181    fn test_session_config_option_boolean_variant() {
6182        let opt = SessionConfigOption::boolean("brave_mode", "Brave Mode", false)
6183            .description("Skip confirmation prompts")
6184            .meta(test_meta());
6185        assert_eq!(serialized_meta_key_count(&opt), 1);
6186
6187        let json = serde_json::to_value(&opt).unwrap();
6188        assert_eq!(
6189            json,
6190            json!({
6191                "id": "brave_mode",
6192                "name": "Brave Mode",
6193                "description": "Skip confirmation prompts",
6194                "type": "boolean",
6195                "currentValue": false,
6196                "_meta": {
6197                    "source": "test"
6198                }
6199            })
6200        );
6201
6202        let deserialized: SessionConfigOption = serde_json::from_value(json).unwrap();
6203        assert_eq!(deserialized.id.to_string(), "brave_mode");
6204        assert_eq!(deserialized.name, "Brave Mode");
6205        match deserialized.kind {
6206            SessionConfigKind::Boolean(ref b) => assert!(!b.current_value),
6207            _ => panic!("Expected Boolean kind"),
6208        }
6209    }
6210
6211    #[cfg(feature = "unstable_boolean_config")]
6212    #[test]
6213    fn test_session_config_option_select_still_works() {
6214        // Make sure existing select options are unaffected
6215        let opt = SessionConfigOption::select(
6216            "model",
6217            "Model",
6218            "model-1",
6219            vec![
6220                SessionConfigSelectOption::new("model-1", "Model 1"),
6221                SessionConfigSelectOption::new("model-2", "Model 2"),
6222            ],
6223        )
6224        .meta(test_meta());
6225        assert_eq!(serialized_meta_key_count(&opt), 1);
6226
6227        let json = serde_json::to_value(&opt).unwrap();
6228        assert_eq!(json["type"], "select");
6229        assert_eq!(json["currentValue"], "model-1");
6230        assert_eq!(json["options"].as_array().unwrap().len(), 2);
6231        assert_eq!(json["_meta"]["source"], "test");
6232
6233        let deserialized: SessionConfigOption = serde_json::from_value(json).unwrap();
6234        match deserialized.kind {
6235            SessionConfigKind::Select(ref s) => {
6236                assert_eq!(s.current_value.to_string(), "model-1");
6237            }
6238            _ => panic!("Expected Select kind"),
6239        }
6240    }
6241
6242    #[test]
6243    fn test_session_config_option_unknown_kind_roundtrip() {
6244        let option: SessionConfigOption = serde_json::from_value(json!({
6245            "id": "verbosity",
6246            "name": "Verbosity",
6247            "type": "_slider",
6248            "currentValue": 3,
6249            "min": 0,
6250            "max": 5,
6251            "_meta": {
6252                "source": "test"
6253            }
6254        }))
6255        .unwrap();
6256
6257        assert_eq!(option.id.to_string(), "verbosity");
6258        assert_eq!(option.meta.as_ref().unwrap()["source"], "test");
6259        let SessionConfigKind::Other(unknown) = &option.kind else {
6260            panic!("expected unknown config kind");
6261        };
6262        assert_eq!(unknown.type_, "_slider");
6263        assert_eq!(unknown.fields.get("currentValue"), Some(&json!(3)));
6264        assert!(!unknown.fields.contains_key("_meta"));
6265        assert_eq!(serialized_meta_key_count(&option), 1);
6266
6267        let json = serde_json::to_value(&option).unwrap();
6268        assert_eq!(json["type"], "_slider");
6269        assert_eq!(json["currentValue"], 3);
6270        assert_eq!(json["min"], 0);
6271        assert_eq!(json["max"], 5);
6272        assert_eq!(json["_meta"]["source"], "test");
6273    }
6274
6275    #[test]
6276    fn test_session_config_option_unknown_kind_does_not_duplicate_flattened_meta() {
6277        let mut fields = std::collections::BTreeMap::new();
6278        fields.insert("currentValue".to_string(), json!(3));
6279        fields.insert("_meta".to_string(), json!({ "inner": "ignored" }));
6280
6281        let option = SessionConfigOption::new(
6282            "verbosity",
6283            "Verbosity",
6284            SessionConfigKind::Other(OtherSessionConfigKind::new("_slider", fields)),
6285        )
6286        .meta(test_meta());
6287
6288        let SessionConfigKind::Other(unknown) = &option.kind else {
6289            panic!("expected unknown config kind");
6290        };
6291        assert!(!unknown.fields.contains_key("_meta"));
6292        assert_eq!(serialized_meta_key_count(&option), 1);
6293
6294        let json = serde_json::to_value(&option).unwrap();
6295        assert_eq!(json["type"], "_slider");
6296        assert_eq!(json["currentValue"], 3);
6297        assert_eq!(json["_meta"]["source"], "test");
6298    }
6299
6300    #[test]
6301    fn test_session_config_option_unknown_does_not_hide_malformed_known_kind() {
6302        assert!(
6303            serde_json::from_value::<SessionConfigOption>(json!({
6304                "id": "model",
6305                "name": "Model",
6306                "type": "select"
6307            }))
6308            .is_err()
6309        );
6310    }
6311
6312    #[cfg(feature = "unstable_llm_providers")]
6313    #[test]
6314    fn test_llm_protocol_known_variants() {
6315        assert_eq!(
6316            serde_json::to_value(&LlmProtocol::Anthropic).unwrap(),
6317            json!("anthropic")
6318        );
6319        assert_eq!(
6320            serde_json::to_value(&LlmProtocol::OpenAi).unwrap(),
6321            json!("openai")
6322        );
6323        assert_eq!(
6324            serde_json::to_value(&LlmProtocol::Azure).unwrap(),
6325            json!("azure")
6326        );
6327        assert_eq!(
6328            serde_json::to_value(&LlmProtocol::Vertex).unwrap(),
6329            json!("vertex")
6330        );
6331        assert_eq!(
6332            serde_json::to_value(&LlmProtocol::Bedrock).unwrap(),
6333            json!("bedrock")
6334        );
6335
6336        assert_eq!(
6337            serde_json::from_str::<LlmProtocol>("\"anthropic\"").unwrap(),
6338            LlmProtocol::Anthropic
6339        );
6340        assert_eq!(
6341            serde_json::from_str::<LlmProtocol>("\"openai\"").unwrap(),
6342            LlmProtocol::OpenAi
6343        );
6344        assert_eq!(
6345            serde_json::from_str::<LlmProtocol>("\"azure\"").unwrap(),
6346            LlmProtocol::Azure
6347        );
6348        assert_eq!(
6349            serde_json::from_str::<LlmProtocol>("\"vertex\"").unwrap(),
6350            LlmProtocol::Vertex
6351        );
6352        assert_eq!(
6353            serde_json::from_str::<LlmProtocol>("\"bedrock\"").unwrap(),
6354            LlmProtocol::Bedrock
6355        );
6356    }
6357
6358    #[cfg(feature = "unstable_llm_providers")]
6359    #[test]
6360    fn test_llm_protocol_unknown_variant() {
6361        let unknown: LlmProtocol = serde_json::from_str("\"cohere\"").unwrap();
6362        assert_eq!(unknown, LlmProtocol::Other("cohere".to_string()));
6363
6364        let json = serde_json::to_value(&unknown).unwrap();
6365        assert_eq!(json, json!("cohere"));
6366    }
6367
6368    #[cfg(feature = "unstable_llm_providers")]
6369    #[test]
6370    fn test_provider_current_config_serialization() {
6371        let config =
6372            ProviderCurrentConfig::new(LlmProtocol::Anthropic, "https://api.anthropic.com");
6373
6374        let json = serde_json::to_value(&config).unwrap();
6375        assert_eq!(
6376            json,
6377            json!({
6378                "apiType": "anthropic",
6379                "baseUrl": "https://api.anthropic.com"
6380            })
6381        );
6382
6383        let deserialized: ProviderCurrentConfig = serde_json::from_value(json).unwrap();
6384        assert_eq!(deserialized.api_type, LlmProtocol::Anthropic);
6385        assert_eq!(deserialized.base_url, "https://api.anthropic.com");
6386    }
6387
6388    #[cfg(feature = "unstable_llm_providers")]
6389    #[test]
6390    fn test_provider_info_with_current_config() {
6391        let info = ProviderInfo::new(
6392            "main",
6393            vec![LlmProtocol::Anthropic, LlmProtocol::OpenAi],
6394            true,
6395            Some(ProviderCurrentConfig::new(
6396                LlmProtocol::Anthropic,
6397                "https://api.anthropic.com",
6398            )),
6399        );
6400
6401        let json = serde_json::to_value(&info).unwrap();
6402        assert_eq!(
6403            json,
6404            json!({
6405                "id": "main",
6406                "supported": ["anthropic", "openai"],
6407                "required": true,
6408                "current": {
6409                    "apiType": "anthropic",
6410                    "baseUrl": "https://api.anthropic.com"
6411                }
6412            })
6413        );
6414
6415        let deserialized: ProviderInfo = serde_json::from_value(json).unwrap();
6416        assert_eq!(deserialized.id, "main");
6417        assert_eq!(deserialized.supported.len(), 2);
6418        assert!(deserialized.required);
6419        assert!(deserialized.current.is_some());
6420        assert_eq!(
6421            deserialized.current.as_ref().unwrap().api_type,
6422            LlmProtocol::Anthropic
6423        );
6424    }
6425
6426    #[cfg(feature = "unstable_llm_providers")]
6427    #[test]
6428    fn test_provider_info_disabled() {
6429        let info = ProviderInfo::new(
6430            "secondary",
6431            vec![LlmProtocol::OpenAi],
6432            false,
6433            None::<ProviderCurrentConfig>,
6434        );
6435
6436        let json = serde_json::to_value(&info).unwrap();
6437        assert_eq!(
6438            json,
6439            json!({
6440                "id": "secondary",
6441                "supported": ["openai"],
6442                "required": false
6443            })
6444        );
6445
6446        let deserialized: ProviderInfo = serde_json::from_value(json).unwrap();
6447        assert_eq!(deserialized.id, "secondary");
6448        assert!(!deserialized.required);
6449        assert!(deserialized.current.is_none());
6450    }
6451
6452    #[cfg(feature = "unstable_llm_providers")]
6453    #[test]
6454    fn test_provider_info_missing_current_defaults_to_none() {
6455        // current is optional; omitting it should decode as None
6456        let json = json!({
6457            "id": "main",
6458            "supported": ["anthropic"],
6459            "required": true
6460        });
6461        let deserialized: ProviderInfo = serde_json::from_value(json).unwrap();
6462        assert!(deserialized.current.is_none());
6463    }
6464
6465    #[cfg(feature = "unstable_llm_providers")]
6466    #[test]
6467    fn test_provider_info_explicit_null_current_decodes_to_none() {
6468        // current: null and an omitted current are equivalent on the wire;
6469        // both must deserialize into None so the disabled state is preserved
6470        // regardless of which form the peer chose to send.
6471        let json = json!({
6472            "id": "main",
6473            "supported": ["anthropic"],
6474            "required": true,
6475            "current": null
6476        });
6477        let deserialized: ProviderInfo = serde_json::from_value(json).unwrap();
6478        assert!(deserialized.current.is_none());
6479    }
6480
6481    #[cfg(feature = "unstable_llm_providers")]
6482    #[test]
6483    fn test_list_providers_response_serialization() {
6484        let response = ListProvidersResponse::new(vec![ProviderInfo::new(
6485            "main",
6486            vec![LlmProtocol::Anthropic],
6487            true,
6488            Some(ProviderCurrentConfig::new(
6489                LlmProtocol::Anthropic,
6490                "https://api.anthropic.com",
6491            )),
6492        )]);
6493
6494        let json = serde_json::to_value(&response).unwrap();
6495        assert_eq!(json["providers"].as_array().unwrap().len(), 1);
6496        assert_eq!(json["providers"][0]["id"], "main");
6497
6498        let deserialized: ListProvidersResponse = serde_json::from_value(json).unwrap();
6499        assert_eq!(deserialized.providers.len(), 1);
6500    }
6501
6502    #[cfg(feature = "unstable_llm_providers")]
6503    #[test]
6504    fn test_set_provider_request_serialization() {
6505        use std::collections::HashMap;
6506
6507        let mut headers = HashMap::new();
6508        headers.insert("Authorization".to_string(), "Bearer sk-test".to_string());
6509
6510        let request =
6511            SetProviderRequest::new("main", LlmProtocol::OpenAi, "https://api.openai.com/v1")
6512                .headers(headers);
6513
6514        let json = serde_json::to_value(&request).unwrap();
6515        assert_eq!(
6516            json,
6517            json!({
6518                "id": "main",
6519                "apiType": "openai",
6520                "baseUrl": "https://api.openai.com/v1",
6521                "headers": {
6522                    "Authorization": "Bearer sk-test"
6523                }
6524            })
6525        );
6526
6527        let deserialized: SetProviderRequest = serde_json::from_value(json).unwrap();
6528        assert_eq!(deserialized.id, "main");
6529        assert_eq!(deserialized.api_type, LlmProtocol::OpenAi);
6530        assert_eq!(deserialized.base_url, "https://api.openai.com/v1");
6531        assert_eq!(deserialized.headers.len(), 1);
6532        assert_eq!(
6533            deserialized.headers.get("Authorization").unwrap(),
6534            "Bearer sk-test"
6535        );
6536    }
6537
6538    #[cfg(feature = "unstable_llm_providers")]
6539    #[test]
6540    fn test_set_provider_request_omits_empty_headers() {
6541        let request =
6542            SetProviderRequest::new("main", LlmProtocol::Anthropic, "https://api.anthropic.com");
6543
6544        let json = serde_json::to_value(&request).unwrap();
6545        // headers should be omitted when empty
6546        assert!(!json.as_object().unwrap().contains_key("headers"));
6547    }
6548
6549    #[cfg(feature = "unstable_llm_providers")]
6550    #[test]
6551    fn test_disable_provider_request_serialization() {
6552        let request = DisableProviderRequest::new("secondary");
6553
6554        let json = serde_json::to_value(&request).unwrap();
6555        assert_eq!(json, json!({ "id": "secondary" }));
6556
6557        let deserialized: DisableProviderRequest = serde_json::from_value(json).unwrap();
6558        assert_eq!(deserialized.id, "secondary");
6559    }
6560
6561    #[cfg(feature = "unstable_llm_providers")]
6562    #[test]
6563    fn test_providers_capabilities_serialization() {
6564        let caps = ProvidersCapabilities::new();
6565
6566        let json = serde_json::to_value(&caps).unwrap();
6567        assert_eq!(json, json!({}));
6568
6569        let deserialized: ProvidersCapabilities = serde_json::from_value(json).unwrap();
6570        assert!(deserialized.meta.is_none());
6571    }
6572
6573    #[cfg(feature = "unstable_llm_providers")]
6574    #[test]
6575    fn test_agent_capabilities_with_providers() {
6576        let caps = AgentCapabilities::new().providers(ProvidersCapabilities::new());
6577
6578        let json = serde_json::to_value(&caps).unwrap();
6579        assert_eq!(json["providers"], json!({}));
6580
6581        let deserialized: AgentCapabilities = serde_json::from_value(json).unwrap();
6582        assert!(deserialized.providers.is_some());
6583    }
6584
6585    #[test]
6586    fn test_agent_capabilities_session_is_explicit() {
6587        let json = serde_json::to_value(AgentCapabilities::new()).unwrap();
6588        assert!(json.get("session").is_none());
6589
6590        let caps = AgentCapabilities::new().session(
6591            SessionCapabilities::new()
6592                .prompt(PromptCapabilities::new().image(PromptImageCapabilities::new()))
6593                .mcp(McpCapabilities::new().stdio(McpStdioCapabilities::new()))
6594                .load(SessionLoadCapabilities::new()),
6595        );
6596
6597        assert_eq!(
6598            serde_json::to_value(&caps).unwrap(),
6599            json!({
6600                "auth": {},
6601                "session": {
6602                    "prompt": {
6603                        "image": {}
6604                    },
6605                    "mcp": {
6606                        "stdio": {}
6607                    },
6608                    "load": {}
6609                }
6610            })
6611        );
6612
6613        let deserialized: AgentCapabilities = serde_json::from_value(json!({
6614            "session": false
6615        }))
6616        .unwrap();
6617        assert!(deserialized.session.is_none());
6618    }
6619
6620    #[test]
6621    fn test_prompt_capabilities_serialize_supported_content_as_objects() {
6622        let caps = PromptCapabilities::new()
6623            .image(PromptImageCapabilities::new())
6624            .audio(PromptAudioCapabilities::new())
6625            .embedded_context(PromptEmbeddedContextCapabilities::new());
6626
6627        assert_eq!(
6628            serde_json::to_value(&caps).unwrap(),
6629            json!({
6630                "image": {},
6631                "audio": {},
6632                "embeddedContext": {}
6633            })
6634        );
6635
6636        let deserialized: PromptCapabilities = serde_json::from_value(json!({
6637            "image": null,
6638            "audio": false,
6639            "embeddedContext": {}
6640        }))
6641        .unwrap();
6642        assert!(deserialized.image.is_none());
6643        assert!(deserialized.audio.is_none());
6644        assert!(deserialized.embedded_context.is_some());
6645    }
6646
6647    #[test]
6648    fn test_mcp_capabilities_serialize_supported_transports_as_objects() {
6649        let caps = McpCapabilities::new()
6650            .stdio(McpStdioCapabilities::new())
6651            .http(McpHttpCapabilities::new());
6652
6653        assert_eq!(
6654            serde_json::to_value(&caps).unwrap(),
6655            json!({
6656                "stdio": {},
6657                "http": {}
6658            })
6659        );
6660
6661        let deserialized: McpCapabilities = serde_json::from_value(json!({
6662            "stdio": null,
6663            "http": false
6664        }))
6665        .unwrap();
6666        assert!(deserialized.stdio.is_none());
6667        assert!(deserialized.http.is_none());
6668    }
6669
6670    #[cfg(feature = "unstable_mcp_over_acp")]
6671    #[test]
6672    fn test_mcp_capabilities_serialize_acp_support_as_object() {
6673        let caps = McpCapabilities::new().acp(McpAcpCapabilities::new());
6674
6675        assert_eq!(
6676            serde_json::to_value(&caps).unwrap(),
6677            json!({
6678                "acp": {}
6679            })
6680        );
6681    }
6682}