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