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