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