Skip to main content

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