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