Skip to main content

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