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    /// **UNSTABLE**
2303    ///
2304    /// This capability is not part of the spec yet, and may be removed or changed at any point.
2305    ///
2306    /// Model-related configuration parameter.
2307    #[cfg(feature = "unstable_model_config_category")]
2308    ModelConfig,
2309    /// Thought/reasoning level selector.
2310    ThoughtLevel,
2311    /// Unknown / uncategorized selector.
2312    #[serde(untagged)]
2313    Other(String),
2314}
2315
2316/// Type-specific session configuration option payload.
2317#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2318#[serde(tag = "type", rename_all = "snake_case")]
2319#[schemars(extend("discriminator" = {"propertyName": "type"}))]
2320#[non_exhaustive]
2321pub enum SessionConfigKind {
2322    /// Single-value selector (dropdown).
2323    Select(SessionConfigSelect),
2324    /// **UNSTABLE**
2325    ///
2326    /// This capability is not part of the spec yet, and may be removed or changed at any point.
2327    ///
2328    /// Boolean on/off toggle.
2329    #[cfg(feature = "unstable_boolean_config")]
2330    Boolean(SessionConfigBoolean),
2331}
2332
2333/// A session configuration option selector and its current state.
2334#[serde_as]
2335#[skip_serializing_none]
2336#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2337#[serde(rename_all = "camelCase")]
2338#[non_exhaustive]
2339pub struct SessionConfigOption {
2340    /// Unique identifier for the configuration option.
2341    pub id: SessionConfigId,
2342    /// Human-readable label for the option.
2343    pub name: String,
2344    /// Optional description for the Client to display to the user.
2345    #[serde(default)]
2346    pub description: Option<String>,
2347    /// Optional semantic category for this option (UX only).
2348    #[serde_as(deserialize_as = "DefaultOnError")]
2349    #[schemars(extend("x-deserialize-default-on-error" = true))]
2350    #[serde(default)]
2351    pub category: Option<SessionConfigOptionCategory>,
2352    /// Type-specific fields for this configuration option.
2353    #[serde(flatten)]
2354    pub kind: SessionConfigKind,
2355    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
2356    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
2357    /// these keys.
2358    ///
2359    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
2360    #[serde(rename = "_meta")]
2361    pub meta: Option<Meta>,
2362}
2363
2364impl SessionConfigOption {
2365    /// Builds [`SessionConfigOption`] with the required fields set; optional fields start unset or empty.
2366    #[must_use]
2367    pub fn new(
2368        id: impl Into<SessionConfigId>,
2369        name: impl Into<String>,
2370        kind: SessionConfigKind,
2371    ) -> Self {
2372        Self {
2373            id: id.into(),
2374            name: name.into(),
2375            description: None,
2376            category: None,
2377            kind,
2378            meta: None,
2379        }
2380    }
2381
2382    /// Builds a select-style session configuration option with its current value and choices.
2383    #[must_use]
2384    pub fn select(
2385        id: impl Into<SessionConfigId>,
2386        name: impl Into<String>,
2387        current_value: impl Into<SessionConfigValueId>,
2388        options: impl Into<SessionConfigSelectOptions>,
2389    ) -> Self {
2390        Self::new(
2391            id,
2392            name,
2393            SessionConfigKind::Select(SessionConfigSelect::new(current_value, options)),
2394        )
2395    }
2396
2397    /// **UNSTABLE**
2398    ///
2399    /// This capability is not part of the spec yet, and may be removed or changed at any point.
2400    #[cfg(feature = "unstable_boolean_config")]
2401    #[must_use]
2402    pub fn boolean(
2403        id: impl Into<SessionConfigId>,
2404        name: impl Into<String>,
2405        current_value: bool,
2406    ) -> Self {
2407        Self::new(
2408            id,
2409            name,
2410            SessionConfigKind::Boolean(SessionConfigBoolean::new(current_value)),
2411        )
2412    }
2413
2414    /// Sets or clears the optional `description` field.
2415    #[must_use]
2416    pub fn description(mut self, description: impl IntoOption<String>) -> Self {
2417        self.description = description.into_option();
2418        self
2419    }
2420
2421    /// Sets or clears the optional `category` field.
2422    #[must_use]
2423    pub fn category(mut self, category: impl IntoOption<SessionConfigOptionCategory>) -> Self {
2424        self.category = category.into_option();
2425        self
2426    }
2427
2428    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
2429    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
2430    /// these keys.
2431    ///
2432    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
2433    #[must_use]
2434    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2435        self.meta = meta.into_option();
2436        self
2437    }
2438}
2439
2440/// **UNSTABLE**
2441///
2442/// This capability is not part of the spec yet, and may be removed or changed at any point.
2443///
2444/// The value to set for a session configuration option.
2445///
2446/// The `type` field acts as the discriminator in the serialized JSON form.
2447/// When no `type` is present, the value is treated as a [`SessionConfigValueId`]
2448/// via the [`ValueId`](Self::ValueId) fallback variant.
2449///
2450/// The `type` discriminator describes the *shape* of the value, not the option
2451/// kind. For example every option kind that picks from a list of ids
2452/// (`select`, `radio`, …) would use [`ValueId`](Self::ValueId), while a
2453/// future freeform text option would get its own variant.
2454#[cfg(feature = "unstable_boolean_config")]
2455#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2456#[serde(tag = "type", rename_all = "snake_case")]
2457#[non_exhaustive]
2458pub enum SessionConfigOptionValue {
2459    /// A boolean value (`type: "boolean"`).
2460    Boolean {
2461        /// The boolean value.
2462        value: bool,
2463    },
2464    /// A [`SessionConfigValueId`] string value.
2465    ///
2466    /// This is the default when `type` is absent on the wire. Unknown `type`
2467    /// values with string payloads also gracefully deserialize into this
2468    /// variant.
2469    #[serde(untagged)]
2470    ValueId {
2471        /// The value ID.
2472        value: SessionConfigValueId,
2473    },
2474}
2475
2476#[cfg(feature = "unstable_boolean_config")]
2477impl SessionConfigOptionValue {
2478    /// Create a value-id option value (used by `select` and other id-based option types).
2479    #[must_use]
2480    pub fn value_id(id: impl Into<SessionConfigValueId>) -> Self {
2481        Self::ValueId { value: id.into() }
2482    }
2483
2484    /// Create a boolean option value.
2485    #[must_use]
2486    pub fn boolean(val: bool) -> Self {
2487        Self::Boolean { value: val }
2488    }
2489
2490    /// Return the inner [`SessionConfigValueId`] if this is a
2491    /// [`ValueId`](Self::ValueId) value.
2492    #[must_use]
2493    pub fn as_value_id(&self) -> Option<&SessionConfigValueId> {
2494        match self {
2495            Self::ValueId { value } => Some(value),
2496            _ => None,
2497        }
2498    }
2499
2500    /// Return the inner [`bool`] if this is a [`Boolean`](Self::Boolean) value.
2501    #[must_use]
2502    pub fn as_bool(&self) -> Option<bool> {
2503        match self {
2504            Self::Boolean { value } => Some(*value),
2505            _ => None,
2506        }
2507    }
2508}
2509
2510#[cfg(feature = "unstable_boolean_config")]
2511impl From<SessionConfigValueId> for SessionConfigOptionValue {
2512    fn from(value: SessionConfigValueId) -> Self {
2513        Self::ValueId { value }
2514    }
2515}
2516
2517#[cfg(feature = "unstable_boolean_config")]
2518impl From<bool> for SessionConfigOptionValue {
2519    fn from(value: bool) -> Self {
2520        Self::Boolean { value }
2521    }
2522}
2523
2524#[cfg(feature = "unstable_boolean_config")]
2525impl From<&str> for SessionConfigOptionValue {
2526    fn from(value: &str) -> Self {
2527        Self::ValueId {
2528            value: SessionConfigValueId::new(value),
2529        }
2530    }
2531}
2532
2533/// Request parameters for setting a session configuration option.
2534#[skip_serializing_none]
2535#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2536#[schemars(extend("x-side" = "agent", "x-method" = SESSION_SET_CONFIG_OPTION_METHOD_NAME))]
2537#[serde(rename_all = "camelCase")]
2538#[non_exhaustive]
2539pub struct SetSessionConfigOptionRequest {
2540    /// The ID of the session to set the configuration option for.
2541    pub session_id: SessionId,
2542    /// The ID of the configuration option to set.
2543    pub config_id: SessionConfigId,
2544    /// The value to set, including a `type` discriminator and the raw `value`.
2545    ///
2546    /// When `type` is absent on the wire, defaults to treating the value as a
2547    /// [`SessionConfigValueId`] for `select` options.
2548    #[cfg(feature = "unstable_boolean_config")]
2549    #[serde(flatten)]
2550    pub value: SessionConfigOptionValue,
2551    /// The ID of the configuration option value to set.
2552    #[cfg(not(feature = "unstable_boolean_config"))]
2553    pub value: SessionConfigValueId,
2554    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
2555    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
2556    /// these keys.
2557    ///
2558    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
2559    #[serde(rename = "_meta")]
2560    pub meta: Option<Meta>,
2561}
2562
2563impl SetSessionConfigOptionRequest {
2564    /// Builds [`SetSessionConfigOptionRequest`] with the required request fields set; optional fields start unset or empty.
2565    #[cfg(feature = "unstable_boolean_config")]
2566    #[must_use]
2567    pub fn new(
2568        session_id: impl Into<SessionId>,
2569        config_id: impl Into<SessionConfigId>,
2570        value: impl Into<SessionConfigOptionValue>,
2571    ) -> Self {
2572        Self {
2573            session_id: session_id.into(),
2574            config_id: config_id.into(),
2575            value: value.into(),
2576            meta: None,
2577        }
2578    }
2579
2580    /// Builds a select-value `session/set_config_option` request for crates built
2581    /// without boolean session configuration support.
2582    #[cfg(not(feature = "unstable_boolean_config"))]
2583    #[must_use]
2584    pub fn new(
2585        session_id: impl Into<SessionId>,
2586        config_id: impl Into<SessionConfigId>,
2587        value: impl Into<SessionConfigValueId>,
2588    ) -> Self {
2589        Self {
2590            session_id: session_id.into(),
2591            config_id: config_id.into(),
2592            value: value.into(),
2593            meta: None,
2594        }
2595    }
2596
2597    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
2598    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
2599    /// these keys.
2600    ///
2601    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
2602    #[must_use]
2603    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2604        self.meta = meta.into_option();
2605        self
2606    }
2607}
2608
2609/// Response to `session/set_config_option` method.
2610#[serde_as]
2611#[skip_serializing_none]
2612#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2613#[schemars(extend("x-side" = "agent", "x-method" = SESSION_SET_CONFIG_OPTION_METHOD_NAME))]
2614#[serde(rename_all = "camelCase")]
2615#[non_exhaustive]
2616pub struct SetSessionConfigOptionResponse {
2617    /// The full set of configuration options and their current values.
2618    #[serde_as(deserialize_as = "DefaultOnError<VecSkipError<_, SkipListener>>")]
2619    #[schemars(extend("x-deserialize-default-on-error" = true, "x-deserialize-skip-invalid-items" = true))]
2620    pub config_options: Vec<SessionConfigOption>,
2621    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
2622    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
2623    /// these keys.
2624    ///
2625    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
2626    #[serde(rename = "_meta")]
2627    pub meta: Option<Meta>,
2628}
2629
2630impl SetSessionConfigOptionResponse {
2631    /// Builds [`SetSessionConfigOptionResponse`] with the required response fields set; optional fields start unset or empty.
2632    #[must_use]
2633    pub fn new(config_options: Vec<SessionConfigOption>) -> Self {
2634        Self {
2635            config_options,
2636            meta: None,
2637        }
2638    }
2639
2640    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
2641    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
2642    /// these keys.
2643    ///
2644    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
2645    #[must_use]
2646    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2647        self.meta = meta.into_option();
2648        self
2649    }
2650}
2651
2652// MCP
2653
2654/// Configuration for connecting to an MCP (Model Context Protocol) server.
2655///
2656/// MCP servers provide tools and context that the agent can use when
2657/// processing prompts.
2658///
2659/// See protocol docs: [MCP Servers](https://agentclientprotocol.com/protocol/session-setup#mcp-servers)
2660#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2661#[serde(tag = "type", rename_all = "snake_case")]
2662#[non_exhaustive]
2663pub enum McpServer {
2664    /// HTTP transport configuration
2665    ///
2666    /// Only available when the Agent capabilities indicate `mcp_capabilities.http` is `true`.
2667    Http(McpServerHttp),
2668    /// SSE transport configuration
2669    ///
2670    /// Only available when the Agent capabilities indicate `mcp_capabilities.sse` is `true`.
2671    Sse(McpServerSse),
2672    /// **UNSTABLE**
2673    ///
2674    /// This capability is not part of the spec yet, and may be removed or changed at any point.
2675    ///
2676    /// ACP transport configuration
2677    ///
2678    /// Only available when the Agent capabilities indicate `mcp_capabilities.acp` is `true`.
2679    /// The MCP server is provided by an ACP component and communicates over the ACP channel.
2680    #[cfg(feature = "unstable_mcp_over_acp")]
2681    Acp(McpServerAcp),
2682    /// Stdio transport configuration
2683    ///
2684    /// All Agents MUST support this transport.
2685    #[serde(untagged)]
2686    Stdio(McpServerStdio),
2687}
2688
2689/// HTTP transport configuration for MCP.
2690#[skip_serializing_none]
2691#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2692#[serde(rename_all = "camelCase")]
2693#[non_exhaustive]
2694pub struct McpServerHttp {
2695    /// Human-readable name identifying this MCP server.
2696    pub name: String,
2697    /// URL to the MCP server.
2698    pub url: String,
2699    /// HTTP headers to set when making requests to the MCP server.
2700    pub headers: Vec<HttpHeader>,
2701    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
2702    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
2703    /// these keys.
2704    ///
2705    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
2706    #[serde(rename = "_meta")]
2707    pub meta: Option<Meta>,
2708}
2709
2710impl McpServerHttp {
2711    /// Builds [`McpServerHttp`] with the required fields set; optional fields start unset or empty.
2712    #[must_use]
2713    pub fn new(name: impl Into<String>, url: impl Into<String>) -> Self {
2714        Self {
2715            name: name.into(),
2716            url: url.into(),
2717            headers: Vec::new(),
2718            meta: None,
2719        }
2720    }
2721
2722    /// HTTP headers to set when making requests to the MCP server.
2723    #[must_use]
2724    pub fn headers(mut self, headers: Vec<HttpHeader>) -> Self {
2725        self.headers = headers;
2726        self
2727    }
2728
2729    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
2730    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
2731    /// these keys.
2732    ///
2733    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
2734    #[must_use]
2735    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2736        self.meta = meta.into_option();
2737        self
2738    }
2739}
2740
2741/// SSE transport configuration for MCP.
2742#[skip_serializing_none]
2743#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2744#[serde(rename_all = "camelCase")]
2745#[non_exhaustive]
2746pub struct McpServerSse {
2747    /// Human-readable name identifying this MCP server.
2748    pub name: String,
2749    /// URL to the MCP server.
2750    pub url: String,
2751    /// HTTP headers to set when making requests to the MCP server.
2752    pub headers: Vec<HttpHeader>,
2753    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
2754    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
2755    /// these keys.
2756    ///
2757    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
2758    #[serde(rename = "_meta")]
2759    pub meta: Option<Meta>,
2760}
2761
2762impl McpServerSse {
2763    /// Builds [`McpServerSse`] with the required fields set; optional fields start unset or empty.
2764    #[must_use]
2765    pub fn new(name: impl Into<String>, url: impl Into<String>) -> Self {
2766        Self {
2767            name: name.into(),
2768            url: url.into(),
2769            headers: Vec::new(),
2770            meta: None,
2771        }
2772    }
2773
2774    /// HTTP headers to set when making requests to the MCP server.
2775    #[must_use]
2776    pub fn headers(mut self, headers: Vec<HttpHeader>) -> Self {
2777        self.headers = headers;
2778        self
2779    }
2780
2781    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
2782    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
2783    /// these keys.
2784    ///
2785    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
2786    #[must_use]
2787    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2788        self.meta = meta.into_option();
2789        self
2790    }
2791}
2792
2793/// **UNSTABLE**
2794///
2795/// This capability is not part of the spec yet, and may be removed or changed at any point.
2796///
2797/// Unique identifier for an MCP server using the ACP transport.
2798///
2799/// The value is opaque and generated by the ACP component providing the MCP server. It is
2800/// used by `mcp/connect` to route connection requests back to the component that declared the
2801/// server.
2802#[cfg(feature = "unstable_mcp_over_acp")]
2803#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq, Hash, Display, From)]
2804#[serde(transparent)]
2805#[from(Arc<str>, String, &'static str)]
2806#[non_exhaustive]
2807pub struct McpServerAcpId(pub Arc<str>);
2808
2809#[cfg(feature = "unstable_mcp_over_acp")]
2810impl McpServerAcpId {
2811    /// Wraps a protocol string as a typed [`McpServerAcpId`].
2812    #[must_use]
2813    pub fn new(id: impl Into<Arc<str>>) -> Self {
2814        Self(id.into())
2815    }
2816}
2817
2818/// **UNSTABLE**
2819///
2820/// This capability is not part of the spec yet, and may be removed or changed at any point.
2821///
2822/// ACP transport configuration for MCP.
2823///
2824/// The MCP server is provided by an ACP component and communicates over the ACP channel
2825/// using `mcp/connect`, `mcp/message`, and `mcp/disconnect`.
2826#[skip_serializing_none]
2827#[cfg(feature = "unstable_mcp_over_acp")]
2828#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2829#[serde(rename_all = "camelCase")]
2830#[non_exhaustive]
2831pub struct McpServerAcp {
2832    /// Human-readable name identifying this MCP server.
2833    pub name: String,
2834    /// Unique identifier for this MCP server, generated by the component providing it.
2835    ///
2836    /// Providers MUST NOT reuse an ID for multiple ACP-transport MCP servers that are visible
2837    /// on the same ACP connection.
2838    pub id: McpServerAcpId,
2839    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
2840    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
2841    /// these keys.
2842    ///
2843    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
2844    #[serde(rename = "_meta")]
2845    pub meta: Option<Meta>,
2846}
2847
2848#[cfg(feature = "unstable_mcp_over_acp")]
2849impl McpServerAcp {
2850    /// Builds [`McpServerAcp`] with the required fields set; optional fields start unset or empty.
2851    #[must_use]
2852    pub fn new(name: impl Into<String>, id: impl Into<McpServerAcpId>) -> Self {
2853        Self {
2854            name: name.into(),
2855            id: id.into(),
2856            meta: None,
2857        }
2858    }
2859
2860    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
2861    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
2862    /// these keys.
2863    ///
2864    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
2865    #[must_use]
2866    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2867        self.meta = meta.into_option();
2868        self
2869    }
2870}
2871
2872/// Stdio transport configuration for MCP.
2873#[skip_serializing_none]
2874#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2875#[serde(rename_all = "camelCase")]
2876#[non_exhaustive]
2877pub struct McpServerStdio {
2878    /// Human-readable name identifying this MCP server.
2879    pub name: String,
2880    /// Path to the MCP server executable.
2881    pub command: PathBuf,
2882    /// Command-line arguments to pass to the MCP server.
2883    pub args: Vec<String>,
2884    /// Environment variables to set when launching the MCP server.
2885    pub env: Vec<EnvVariable>,
2886    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
2887    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
2888    /// these keys.
2889    ///
2890    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
2891    #[serde(rename = "_meta")]
2892    pub meta: Option<Meta>,
2893}
2894
2895impl McpServerStdio {
2896    /// Builds [`McpServerStdio`] with the required fields set; optional fields start unset or empty.
2897    #[must_use]
2898    pub fn new(name: impl Into<String>, command: impl Into<PathBuf>) -> Self {
2899        Self {
2900            name: name.into(),
2901            command: command.into(),
2902            args: Vec::new(),
2903            env: Vec::new(),
2904            meta: None,
2905        }
2906    }
2907
2908    /// Command-line arguments to pass to the MCP server.
2909    #[must_use]
2910    pub fn args(mut self, args: Vec<String>) -> Self {
2911        self.args = args;
2912        self
2913    }
2914
2915    /// Environment variables to set when launching the MCP server.
2916    #[must_use]
2917    pub fn env(mut self, env: Vec<EnvVariable>) -> Self {
2918        self.env = env;
2919        self
2920    }
2921
2922    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
2923    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
2924    /// these keys.
2925    ///
2926    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
2927    #[must_use]
2928    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2929        self.meta = meta.into_option();
2930        self
2931    }
2932}
2933
2934/// An environment variable to set when launching an MCP server.
2935#[skip_serializing_none]
2936#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2937#[serde(rename_all = "camelCase")]
2938#[non_exhaustive]
2939pub struct EnvVariable {
2940    /// The name of the environment variable.
2941    pub name: String,
2942    /// The value to set for the environment variable.
2943    pub value: String,
2944    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
2945    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
2946    /// these keys.
2947    ///
2948    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
2949    #[serde(rename = "_meta")]
2950    pub meta: Option<Meta>,
2951}
2952
2953impl EnvVariable {
2954    /// Builds [`EnvVariable`] with the required fields set; optional fields start unset or empty.
2955    #[must_use]
2956    pub fn new(name: impl Into<String>, value: impl Into<String>) -> Self {
2957        Self {
2958            name: name.into(),
2959            value: value.into(),
2960            meta: None,
2961        }
2962    }
2963
2964    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
2965    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
2966    /// these keys.
2967    ///
2968    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
2969    #[must_use]
2970    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2971        self.meta = meta.into_option();
2972        self
2973    }
2974}
2975
2976/// An HTTP header to set when making requests to the MCP server.
2977#[skip_serializing_none]
2978#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2979#[serde(rename_all = "camelCase")]
2980#[non_exhaustive]
2981pub struct HttpHeader {
2982    /// The name of the HTTP header.
2983    pub name: String,
2984    /// The value to set for the HTTP header.
2985    pub value: String,
2986    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
2987    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
2988    /// these keys.
2989    ///
2990    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
2991    #[serde(rename = "_meta")]
2992    pub meta: Option<Meta>,
2993}
2994
2995impl HttpHeader {
2996    /// Builds [`HttpHeader`] with the required fields set; optional fields start unset or empty.
2997    #[must_use]
2998    pub fn new(name: impl Into<String>, value: impl Into<String>) -> Self {
2999        Self {
3000            name: name.into(),
3001            value: value.into(),
3002            meta: None,
3003        }
3004    }
3005
3006    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
3007    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
3008    /// these keys.
3009    ///
3010    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
3011    #[must_use]
3012    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3013        self.meta = meta.into_option();
3014        self
3015    }
3016}
3017
3018// Prompt
3019
3020/// Request parameters for sending a user prompt to the agent.
3021///
3022/// Contains the user's message and any additional context.
3023///
3024/// See protocol docs: [User Message](https://agentclientprotocol.com/protocol/prompt-turn#1-user-message)
3025#[skip_serializing_none]
3026#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq)]
3027#[schemars(extend("x-side" = "agent", "x-method" = SESSION_PROMPT_METHOD_NAME))]
3028#[serde(rename_all = "camelCase")]
3029#[non_exhaustive]
3030pub struct PromptRequest {
3031    /// The ID of the session to send this user message to
3032    pub session_id: SessionId,
3033    /// The blocks of content that compose the user's message.
3034    ///
3035    /// As a baseline, the Agent MUST support [`ContentBlock::Text`] and [`ContentBlock::ResourceLink`],
3036    /// while other variants are optionally enabled via [`PromptCapabilities`].
3037    ///
3038    /// The Client MUST adapt its interface according to [`PromptCapabilities`].
3039    ///
3040    /// The client MAY include referenced pieces of context as either
3041    /// [`ContentBlock::Resource`] or [`ContentBlock::ResourceLink`].
3042    ///
3043    /// When available, [`ContentBlock::Resource`] is preferred
3044    /// as it avoids extra round-trips and allows the message to include
3045    /// pieces of context from sources the agent may not have access to.
3046    pub prompt: Vec<ContentBlock>,
3047    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
3048    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
3049    /// these keys.
3050    ///
3051    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
3052    #[serde(rename = "_meta")]
3053    pub meta: Option<Meta>,
3054}
3055
3056impl PromptRequest {
3057    /// Builds [`PromptRequest`] with the required request fields set; optional fields start unset or empty.
3058    #[must_use]
3059    pub fn new(session_id: impl Into<SessionId>, prompt: Vec<ContentBlock>) -> Self {
3060        Self {
3061            session_id: session_id.into(),
3062            prompt,
3063            meta: None,
3064        }
3065    }
3066
3067    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
3068    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
3069    /// these keys.
3070    ///
3071    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
3072    #[must_use]
3073    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3074        self.meta = meta.into_option();
3075        self
3076    }
3077}
3078
3079/// Response from processing a user prompt.
3080///
3081/// See protocol docs: [Check for Completion](https://agentclientprotocol.com/protocol/prompt-turn#4-check-for-completion)
3082#[serde_as]
3083#[skip_serializing_none]
3084#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3085#[schemars(extend("x-side" = "agent", "x-method" = SESSION_PROMPT_METHOD_NAME))]
3086#[serde(rename_all = "camelCase")]
3087#[non_exhaustive]
3088pub struct PromptResponse {
3089    /// Indicates why the agent stopped processing the turn.
3090    pub stop_reason: StopReason,
3091    /// **UNSTABLE**
3092    ///
3093    /// This capability is not part of the spec yet, and may be removed or changed at any point.
3094    ///
3095    /// Token usage for this turn (optional).
3096    #[cfg(feature = "unstable_end_turn_token_usage")]
3097    #[serde_as(deserialize_as = "DefaultOnError")]
3098    #[schemars(extend("x-deserialize-default-on-error" = true))]
3099    #[serde(default)]
3100    pub usage: Option<Usage>,
3101    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
3102    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
3103    /// these keys.
3104    ///
3105    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
3106    #[serde(rename = "_meta")]
3107    pub meta: Option<Meta>,
3108}
3109
3110impl PromptResponse {
3111    /// Builds [`PromptResponse`] with the required response fields set; optional fields start unset or empty.
3112    #[must_use]
3113    pub fn new(stop_reason: StopReason) -> Self {
3114        Self {
3115            stop_reason,
3116            #[cfg(feature = "unstable_end_turn_token_usage")]
3117            usage: None,
3118            meta: None,
3119        }
3120    }
3121
3122    /// **UNSTABLE**
3123    ///
3124    /// This capability is not part of the spec yet, and may be removed or changed at any point.
3125    ///
3126    /// Token usage for this turn.
3127    #[cfg(feature = "unstable_end_turn_token_usage")]
3128    #[must_use]
3129    pub fn usage(mut self, usage: impl IntoOption<Usage>) -> Self {
3130        self.usage = usage.into_option();
3131        self
3132    }
3133
3134    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
3135    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
3136    /// these keys.
3137    ///
3138    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
3139    #[must_use]
3140    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3141        self.meta = meta.into_option();
3142        self
3143    }
3144}
3145
3146/// Reasons why an agent stops processing a prompt turn.
3147///
3148/// See protocol docs: [Stop Reasons](https://agentclientprotocol.com/protocol/prompt-turn#stop-reasons)
3149#[derive(Debug, Copy, Clone, Eq, PartialEq, Serialize, Deserialize, JsonSchema)]
3150#[serde(rename_all = "snake_case")]
3151#[non_exhaustive]
3152pub enum StopReason {
3153    /// The turn ended successfully.
3154    EndTurn,
3155    /// The turn ended because the agent reached the maximum number of tokens.
3156    MaxTokens,
3157    /// The turn ended because the agent reached the maximum number of allowed
3158    /// agent requests between user turns.
3159    MaxTurnRequests,
3160    /// The turn ended because the agent refused to continue. The user prompt
3161    /// and everything that comes after it won't be included in the next
3162    /// prompt, so this should be reflected in the UI.
3163    Refusal,
3164    /// The turn was cancelled by the client via `session/cancel`.
3165    ///
3166    /// This stop reason MUST be returned when the client sends a `session/cancel`
3167    /// notification, even if the cancellation causes exceptions in underlying operations.
3168    /// Agents should catch these exceptions and return this semantically meaningful
3169    /// response to confirm successful cancellation.
3170    Cancelled,
3171}
3172
3173/// **UNSTABLE**
3174///
3175/// This capability is not part of the spec yet, and may be removed or changed at any point.
3176///
3177/// Token usage information for a prompt turn.
3178#[cfg(feature = "unstable_end_turn_token_usage")]
3179#[skip_serializing_none]
3180#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3181#[serde(rename_all = "camelCase")]
3182#[non_exhaustive]
3183pub struct Usage {
3184    /// Sum of all token types across session.
3185    pub total_tokens: u64,
3186    /// Total input tokens across all turns.
3187    pub input_tokens: u64,
3188    /// Total output tokens across all turns.
3189    pub output_tokens: u64,
3190    /// Total thought/reasoning tokens
3191    pub thought_tokens: Option<u64>,
3192    /// Total cache read tokens.
3193    pub cached_read_tokens: Option<u64>,
3194    /// Total cache write tokens.
3195    pub cached_write_tokens: Option<u64>,
3196    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
3197    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
3198    /// these keys.
3199    ///
3200    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
3201    #[serde(rename = "_meta")]
3202    pub meta: Option<Meta>,
3203}
3204
3205#[cfg(feature = "unstable_end_turn_token_usage")]
3206impl Usage {
3207    /// Builds [`Usage`] with the required fields set; optional fields start unset or empty.
3208    #[must_use]
3209    pub fn new(total_tokens: u64, input_tokens: u64, output_tokens: u64) -> Self {
3210        Self {
3211            total_tokens,
3212            input_tokens,
3213            output_tokens,
3214            thought_tokens: None,
3215            cached_read_tokens: None,
3216            cached_write_tokens: None,
3217            meta: None,
3218        }
3219    }
3220
3221    /// Total thought/reasoning tokens
3222    #[must_use]
3223    pub fn thought_tokens(mut self, thought_tokens: impl IntoOption<u64>) -> Self {
3224        self.thought_tokens = thought_tokens.into_option();
3225        self
3226    }
3227
3228    /// Total cache read tokens.
3229    #[must_use]
3230    pub fn cached_read_tokens(mut self, cached_read_tokens: impl IntoOption<u64>) -> Self {
3231        self.cached_read_tokens = cached_read_tokens.into_option();
3232        self
3233    }
3234
3235    /// Total cache write tokens.
3236    #[must_use]
3237    pub fn cached_write_tokens(mut self, cached_write_tokens: impl IntoOption<u64>) -> Self {
3238        self.cached_write_tokens = cached_write_tokens.into_option();
3239        self
3240    }
3241
3242    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
3243    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
3244    /// these keys.
3245    ///
3246    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
3247    #[must_use]
3248    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3249        self.meta = meta.into_option();
3250        self
3251    }
3252}
3253
3254// Providers
3255
3256/// **UNSTABLE**
3257///
3258/// This capability is not part of the spec yet, and may be removed or changed at any point.
3259///
3260/// Well-known API protocol identifiers for LLM providers.
3261///
3262/// Agents and clients MUST handle unknown protocol identifiers gracefully.
3263///
3264/// Protocol names beginning with `_` are free for custom use, like other ACP extension methods.
3265/// Protocol names that do not begin with `_` are reserved for the ACP spec.
3266#[cfg(feature = "unstable_llm_providers")]
3267#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3268#[serde(rename_all = "snake_case")]
3269#[non_exhaustive]
3270#[expect(clippy::doc_markdown)]
3271pub enum LlmProtocol {
3272    /// Anthropic API protocol.
3273    Anthropic,
3274    /// OpenAI API protocol.
3275    #[serde(rename = "openai")]
3276    OpenAi,
3277    /// Azure OpenAI API protocol.
3278    Azure,
3279    /// Google Vertex AI API protocol.
3280    Vertex,
3281    /// AWS Bedrock API protocol.
3282    Bedrock,
3283    /// Unknown or custom protocol.
3284    #[serde(untagged)]
3285    Other(String),
3286}
3287
3288/// **UNSTABLE**
3289///
3290/// This capability is not part of the spec yet, and may be removed or changed at any point.
3291///
3292/// Current effective non-secret routing configuration for a provider.
3293#[cfg(feature = "unstable_llm_providers")]
3294#[skip_serializing_none]
3295#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3296#[serde(rename_all = "camelCase")]
3297#[non_exhaustive]
3298pub struct ProviderCurrentConfig {
3299    /// Protocol currently used by this provider.
3300    pub api_type: LlmProtocol,
3301    /// Base URL currently used by this provider.
3302    pub base_url: String,
3303    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
3304    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
3305    /// these keys.
3306    ///
3307    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
3308    #[serde(rename = "_meta")]
3309    pub meta: Option<Meta>,
3310}
3311
3312#[cfg(feature = "unstable_llm_providers")]
3313impl ProviderCurrentConfig {
3314    /// Builds [`ProviderCurrentConfig`] with the required fields set; optional fields start unset or empty.
3315    #[must_use]
3316    pub fn new(api_type: LlmProtocol, base_url: impl Into<String>) -> Self {
3317        Self {
3318            api_type,
3319            base_url: base_url.into(),
3320            meta: None,
3321        }
3322    }
3323
3324    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
3325    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
3326    /// these keys.
3327    ///
3328    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
3329    #[must_use]
3330    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3331        self.meta = meta.into_option();
3332        self
3333    }
3334}
3335
3336/// **UNSTABLE**
3337///
3338/// This capability is not part of the spec yet, and may be removed or changed at any point.
3339///
3340/// Information about a configurable LLM provider.
3341#[cfg(feature = "unstable_llm_providers")]
3342#[serde_as]
3343#[skip_serializing_none]
3344#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3345#[serde(rename_all = "camelCase")]
3346#[non_exhaustive]
3347pub struct ProviderInfo {
3348    /// Provider identifier, for example "main" or "openai".
3349    pub id: String,
3350    /// Supported protocol types for this provider.
3351    #[serde_as(deserialize_as = "DefaultOnError<VecSkipError<_, SkipListener>>")]
3352    #[schemars(extend("x-deserialize-default-on-error" = true, "x-deserialize-skip-invalid-items" = true))]
3353    pub supported: Vec<LlmProtocol>,
3354    /// Whether this provider is mandatory and cannot be disabled via `providers/disable`.
3355    /// If true, clients must not call `providers/disable` for this id.
3356    pub required: bool,
3357    /// Current effective non-secret routing config.
3358    /// Null or omitted means provider is disabled.
3359    pub current: Option<ProviderCurrentConfig>,
3360    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
3361    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
3362    /// these keys.
3363    ///
3364    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
3365    #[serde(rename = "_meta")]
3366    pub meta: Option<Meta>,
3367}
3368
3369#[cfg(feature = "unstable_llm_providers")]
3370impl ProviderInfo {
3371    /// Builds [`ProviderInfo`] with the required fields set; optional fields start unset or empty.
3372    #[must_use]
3373    pub fn new(
3374        id: impl Into<String>,
3375        supported: Vec<LlmProtocol>,
3376        required: bool,
3377        current: impl IntoOption<ProviderCurrentConfig>,
3378    ) -> Self {
3379        Self {
3380            id: id.into(),
3381            supported,
3382            required,
3383            current: current.into_option(),
3384            meta: None,
3385        }
3386    }
3387
3388    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
3389    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
3390    /// these keys.
3391    ///
3392    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
3393    #[must_use]
3394    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3395        self.meta = meta.into_option();
3396        self
3397    }
3398}
3399
3400/// **UNSTABLE**
3401///
3402/// This capability is not part of the spec yet, and may be removed or changed at any point.
3403///
3404/// Request parameters for `providers/list`.
3405#[cfg(feature = "unstable_llm_providers")]
3406#[skip_serializing_none]
3407#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3408#[schemars(extend("x-side" = "agent", "x-method" = PROVIDERS_LIST_METHOD_NAME))]
3409#[serde(rename_all = "camelCase")]
3410#[non_exhaustive]
3411pub struct ListProvidersRequest {
3412    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
3413    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
3414    /// these keys.
3415    ///
3416    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
3417    #[serde(rename = "_meta")]
3418    pub meta: Option<Meta>,
3419}
3420
3421#[cfg(feature = "unstable_llm_providers")]
3422impl ListProvidersRequest {
3423    /// Builds [`ListProvidersRequest`] with the required request fields set; optional fields start unset or empty.
3424    #[must_use]
3425    pub fn new() -> Self {
3426        Self::default()
3427    }
3428
3429    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
3430    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
3431    /// these keys.
3432    ///
3433    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
3434    #[must_use]
3435    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3436        self.meta = meta.into_option();
3437        self
3438    }
3439}
3440
3441/// **UNSTABLE**
3442///
3443/// This capability is not part of the spec yet, and may be removed or changed at any point.
3444///
3445/// Response to `providers/list`.
3446#[cfg(feature = "unstable_llm_providers")]
3447#[serde_as]
3448#[skip_serializing_none]
3449#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3450#[schemars(extend("x-side" = "agent", "x-method" = PROVIDERS_LIST_METHOD_NAME))]
3451#[serde(rename_all = "camelCase")]
3452#[non_exhaustive]
3453pub struct ListProvidersResponse {
3454    /// Configurable providers with current routing info suitable for UI display.
3455    #[serde_as(deserialize_as = "DefaultOnError<VecSkipError<_, SkipListener>>")]
3456    #[schemars(extend("x-deserialize-default-on-error" = true, "x-deserialize-skip-invalid-items" = true))]
3457    pub providers: Vec<ProviderInfo>,
3458    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
3459    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
3460    /// these keys.
3461    ///
3462    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
3463    #[serde(rename = "_meta")]
3464    pub meta: Option<Meta>,
3465}
3466
3467#[cfg(feature = "unstable_llm_providers")]
3468impl ListProvidersResponse {
3469    /// Builds [`ListProvidersResponse`] with the required response fields set; optional fields start unset or empty.
3470    #[must_use]
3471    pub fn new(providers: Vec<ProviderInfo>) -> Self {
3472        Self {
3473            providers,
3474            meta: None,
3475        }
3476    }
3477
3478    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
3479    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
3480    /// these keys.
3481    ///
3482    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
3483    #[must_use]
3484    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3485        self.meta = meta.into_option();
3486        self
3487    }
3488}
3489
3490/// **UNSTABLE**
3491///
3492/// This capability is not part of the spec yet, and may be removed or changed at any point.
3493///
3494/// Request parameters for `providers/set`.
3495///
3496/// Replaces the full configuration for one provider id.
3497#[cfg(feature = "unstable_llm_providers")]
3498#[skip_serializing_none]
3499#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3500#[schemars(extend("x-side" = "agent", "x-method" = PROVIDERS_SET_METHOD_NAME))]
3501#[serde(rename_all = "camelCase")]
3502#[non_exhaustive]
3503pub struct SetProviderRequest {
3504    /// Provider id to configure.
3505    pub id: String,
3506    /// Protocol type for this provider.
3507    pub api_type: LlmProtocol,
3508    /// Base URL for requests sent through this provider.
3509    pub base_url: String,
3510    /// Full headers map for this provider.
3511    /// May include authorization, routing, or other integration-specific headers.
3512    #[serde(default, skip_serializing_if = "HashMap::is_empty")]
3513    pub headers: HashMap<String, String>,
3514    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
3515    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
3516    /// these keys.
3517    ///
3518    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
3519    #[serde(rename = "_meta")]
3520    pub meta: Option<Meta>,
3521}
3522
3523#[cfg(feature = "unstable_llm_providers")]
3524impl SetProviderRequest {
3525    /// Builds [`SetProviderRequest`] with the required request fields set; optional fields start unset or empty.
3526    #[must_use]
3527    pub fn new(id: impl Into<String>, api_type: LlmProtocol, base_url: impl Into<String>) -> Self {
3528        Self {
3529            id: id.into(),
3530            api_type,
3531            base_url: base_url.into(),
3532            headers: HashMap::new(),
3533            meta: None,
3534        }
3535    }
3536
3537    /// Full headers map for this provider.
3538    /// May include authorization, routing, or other integration-specific headers.
3539    #[must_use]
3540    pub fn headers(mut self, headers: HashMap<String, String>) -> Self {
3541        self.headers = headers;
3542        self
3543    }
3544
3545    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
3546    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
3547    /// these keys.
3548    ///
3549    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
3550    #[must_use]
3551    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3552        self.meta = meta.into_option();
3553        self
3554    }
3555}
3556
3557/// **UNSTABLE**
3558///
3559/// This capability is not part of the spec yet, and may be removed or changed at any point.
3560///
3561/// Response to `providers/set`.
3562#[cfg(feature = "unstable_llm_providers")]
3563#[skip_serializing_none]
3564#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3565#[schemars(extend("x-side" = "agent", "x-method" = PROVIDERS_SET_METHOD_NAME))]
3566#[serde(rename_all = "camelCase")]
3567#[non_exhaustive]
3568pub struct SetProviderResponse {
3569    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
3570    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
3571    /// these keys.
3572    ///
3573    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
3574    #[serde(rename = "_meta")]
3575    pub meta: Option<Meta>,
3576}
3577
3578#[cfg(feature = "unstable_llm_providers")]
3579impl SetProviderResponse {
3580    /// Builds [`SetProviderResponse`] with the required response fields set; optional fields start unset or empty.
3581    #[must_use]
3582    pub fn new() -> Self {
3583        Self::default()
3584    }
3585
3586    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
3587    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
3588    /// these keys.
3589    ///
3590    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
3591    #[must_use]
3592    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3593        self.meta = meta.into_option();
3594        self
3595    }
3596}
3597
3598/// **UNSTABLE**
3599///
3600/// This capability is not part of the spec yet, and may be removed or changed at any point.
3601///
3602/// Request parameters for `providers/disable`.
3603#[cfg(feature = "unstable_llm_providers")]
3604#[skip_serializing_none]
3605#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3606#[schemars(extend("x-side" = "agent", "x-method" = PROVIDERS_DISABLE_METHOD_NAME))]
3607#[serde(rename_all = "camelCase")]
3608#[non_exhaustive]
3609pub struct DisableProviderRequest {
3610    /// Provider id to disable.
3611    pub id: String,
3612    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
3613    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
3614    /// these keys.
3615    ///
3616    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
3617    #[serde(rename = "_meta")]
3618    pub meta: Option<Meta>,
3619}
3620
3621#[cfg(feature = "unstable_llm_providers")]
3622impl DisableProviderRequest {
3623    /// Builds [`DisableProviderRequest`] with the required request fields set; optional fields start unset or empty.
3624    #[must_use]
3625    pub fn new(id: impl Into<String>) -> Self {
3626        Self {
3627            id: id.into(),
3628            meta: None,
3629        }
3630    }
3631
3632    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
3633    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
3634    /// these keys.
3635    ///
3636    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
3637    #[must_use]
3638    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3639        self.meta = meta.into_option();
3640        self
3641    }
3642}
3643
3644/// **UNSTABLE**
3645///
3646/// This capability is not part of the spec yet, and may be removed or changed at any point.
3647///
3648/// Response to `providers/disable`.
3649#[cfg(feature = "unstable_llm_providers")]
3650#[skip_serializing_none]
3651#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3652#[schemars(extend("x-side" = "agent", "x-method" = PROVIDERS_DISABLE_METHOD_NAME))]
3653#[serde(rename_all = "camelCase")]
3654#[non_exhaustive]
3655pub struct DisableProviderResponse {
3656    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
3657    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
3658    /// these keys.
3659    ///
3660    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
3661    #[serde(rename = "_meta")]
3662    pub meta: Option<Meta>,
3663}
3664
3665#[cfg(feature = "unstable_llm_providers")]
3666impl DisableProviderResponse {
3667    /// Builds [`DisableProviderResponse`] with the required response fields set; optional fields start unset or empty.
3668    #[must_use]
3669    pub fn new() -> Self {
3670        Self::default()
3671    }
3672
3673    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
3674    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
3675    /// these keys.
3676    ///
3677    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
3678    #[must_use]
3679    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3680        self.meta = meta.into_option();
3681        self
3682    }
3683}
3684
3685// Capabilities
3686
3687/// Capabilities supported by the agent.
3688///
3689/// Advertised during initialization to inform the client about
3690/// available features and content types.
3691///
3692/// See protocol docs: [Agent Capabilities](https://agentclientprotocol.com/protocol/initialization#agent-capabilities)
3693#[serde_as]
3694#[skip_serializing_none]
3695#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3696#[serde(rename_all = "camelCase")]
3697#[non_exhaustive]
3698pub struct AgentCapabilities {
3699    /// Whether the agent supports `session/load`.
3700    #[serde(default)]
3701    pub load_session: bool,
3702    /// Prompt capabilities supported by the agent.
3703    #[serde(default)]
3704    pub prompt_capabilities: PromptCapabilities,
3705    /// MCP capabilities supported by the agent.
3706    #[serde(default)]
3707    pub mcp_capabilities: McpCapabilities,
3708    /// Session lifecycle and prompt capabilities advertised by the agent.
3709    #[serde(default)]
3710    pub session_capabilities: SessionCapabilities,
3711    /// Authentication-related capabilities supported by the agent.
3712    #[serde(default)]
3713    pub auth: AgentAuthCapabilities,
3714    /// **UNSTABLE**
3715    ///
3716    /// This capability is not part of the spec yet, and may be removed or changed at any point.
3717    ///
3718    /// Provider configuration capabilities supported by the agent.
3719    ///
3720    /// By supplying `{}` it means that the agent supports provider configuration methods.
3721    #[cfg(feature = "unstable_llm_providers")]
3722    #[serde_as(deserialize_as = "DefaultOnError")]
3723    #[schemars(extend("x-deserialize-default-on-error" = true))]
3724    #[serde(default)]
3725    pub providers: Option<ProvidersCapabilities>,
3726    /// **UNSTABLE**
3727    ///
3728    /// This capability is not part of the spec yet, and may be removed or changed at any point.
3729    ///
3730    /// NES (Next Edit Suggestions) capabilities supported by the agent.
3731    #[cfg(feature = "unstable_nes")]
3732    #[serde_as(deserialize_as = "DefaultOnError")]
3733    #[schemars(extend("x-deserialize-default-on-error" = true))]
3734    #[serde(default)]
3735    pub nes: Option<NesCapabilities>,
3736    /// **UNSTABLE**
3737    ///
3738    /// This capability is not part of the spec yet, and may be removed or changed at any point.
3739    ///
3740    /// The position encoding selected by the agent from the client's supported encodings.
3741    #[cfg(feature = "unstable_nes")]
3742    #[serde_as(deserialize_as = "DefaultOnError")]
3743    #[schemars(extend("x-deserialize-default-on-error" = true))]
3744    #[serde(default)]
3745    pub position_encoding: Option<PositionEncodingKind>,
3746    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
3747    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
3748    /// these keys.
3749    ///
3750    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
3751    #[serde(rename = "_meta")]
3752    pub meta: Option<Meta>,
3753}
3754
3755impl AgentCapabilities {
3756    /// Builds an empty [`AgentCapabilities`]; use builder methods to advertise supported sub-capabilities.
3757    #[must_use]
3758    pub fn new() -> Self {
3759        Self::default()
3760    }
3761
3762    /// Whether the agent supports `session/load`.
3763    #[must_use]
3764    pub fn load_session(mut self, load_session: bool) -> Self {
3765        self.load_session = load_session;
3766        self
3767    }
3768
3769    /// Prompt capabilities supported by the agent.
3770    #[must_use]
3771    pub fn prompt_capabilities(mut self, prompt_capabilities: PromptCapabilities) -> Self {
3772        self.prompt_capabilities = prompt_capabilities;
3773        self
3774    }
3775
3776    /// MCP capabilities supported by the agent.
3777    #[must_use]
3778    pub fn mcp_capabilities(mut self, mcp_capabilities: McpCapabilities) -> Self {
3779        self.mcp_capabilities = mcp_capabilities;
3780        self
3781    }
3782
3783    /// Session capabilities supported by the agent.
3784    #[must_use]
3785    pub fn session_capabilities(mut self, session_capabilities: SessionCapabilities) -> Self {
3786        self.session_capabilities = session_capabilities;
3787        self
3788    }
3789
3790    /// Authentication-related capabilities supported by the agent.
3791    #[must_use]
3792    pub fn auth(mut self, auth: AgentAuthCapabilities) -> Self {
3793        self.auth = auth;
3794        self
3795    }
3796
3797    /// **UNSTABLE**
3798    ///
3799    /// This capability is not part of the spec yet, and may be removed or changed at any point.
3800    ///
3801    /// Provider configuration capabilities supported by the agent.
3802    #[cfg(feature = "unstable_llm_providers")]
3803    #[must_use]
3804    pub fn providers(mut self, providers: impl IntoOption<ProvidersCapabilities>) -> Self {
3805        self.providers = providers.into_option();
3806        self
3807    }
3808
3809    /// **UNSTABLE**
3810    ///
3811    /// This capability is not part of the spec yet, and may be removed or changed at any point.
3812    ///
3813    /// NES (Next Edit Suggestions) capabilities supported by the agent.
3814    #[cfg(feature = "unstable_nes")]
3815    #[must_use]
3816    pub fn nes(mut self, nes: impl IntoOption<NesCapabilities>) -> Self {
3817        self.nes = nes.into_option();
3818        self
3819    }
3820
3821    /// **UNSTABLE**
3822    ///
3823    /// The position encoding selected by the agent from the client's supported encodings.
3824    #[cfg(feature = "unstable_nes")]
3825    #[must_use]
3826    pub fn position_encoding(
3827        mut self,
3828        position_encoding: impl IntoOption<PositionEncodingKind>,
3829    ) -> Self {
3830        self.position_encoding = position_encoding.into_option();
3831        self
3832    }
3833
3834    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
3835    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
3836    /// these keys.
3837    ///
3838    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
3839    #[must_use]
3840    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3841        self.meta = meta.into_option();
3842        self
3843    }
3844}
3845
3846/// **UNSTABLE**
3847///
3848/// This capability is not part of the spec yet, and may be removed or changed at any point.
3849///
3850/// Provider configuration capabilities supported by the agent.
3851///
3852/// By supplying `{}` it means that the agent supports provider configuration methods.
3853#[cfg(feature = "unstable_llm_providers")]
3854#[skip_serializing_none]
3855#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3856#[non_exhaustive]
3857pub struct ProvidersCapabilities {
3858    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
3859    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
3860    /// these keys.
3861    ///
3862    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
3863    #[serde(rename = "_meta")]
3864    pub meta: Option<Meta>,
3865}
3866
3867#[cfg(feature = "unstable_llm_providers")]
3868impl ProvidersCapabilities {
3869    /// Builds an empty [`ProvidersCapabilities`]; use builder methods to advertise supported sub-capabilities.
3870    #[must_use]
3871    pub fn new() -> Self {
3872        Self::default()
3873    }
3874
3875    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
3876    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
3877    /// these keys.
3878    ///
3879    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
3880    #[must_use]
3881    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3882        self.meta = meta.into_option();
3883        self
3884    }
3885}
3886
3887/// Session capabilities supported by the agent.
3888///
3889/// As a baseline, all Agents **MUST** support `session/new`, `session/prompt`, `session/cancel`, and `session/update`.
3890///
3891/// Optionally, they **MAY** support other session methods and notifications by specifying additional capabilities.
3892///
3893/// Note: `session/load` is still handled by the top-level `load_session` capability. This will be unified in future versions of the protocol.
3894///
3895/// See protocol docs: [Session Capabilities](https://agentclientprotocol.com/protocol/initialization#session-capabilities)
3896#[serde_as]
3897#[skip_serializing_none]
3898#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3899#[serde(rename_all = "camelCase")]
3900#[non_exhaustive]
3901pub struct SessionCapabilities {
3902    /// Whether the agent supports `session/list`.
3903    #[serde_as(deserialize_as = "DefaultOnError")]
3904    #[schemars(extend("x-deserialize-default-on-error" = true))]
3905    #[serde(default)]
3906    pub list: Option<SessionListCapabilities>,
3907    /// Whether the agent supports `session/delete`.
3908    ///
3909    /// Optional. Omitted or `null` both mean the agent does not advertise support.
3910    /// Supplying `{}` means the agent supports deleting sessions from `session/list`.
3911    #[serde_as(deserialize_as = "DefaultOnError")]
3912    #[schemars(extend("x-deserialize-default-on-error" = true))]
3913    #[serde(default)]
3914    pub delete: Option<SessionDeleteCapabilities>,
3915    /// Whether the agent supports `additionalDirectories` on supported session lifecycle requests.
3916    ///
3917    /// Agents that also support `session/list` may return
3918    /// `SessionInfo.additionalDirectories` to report the complete ordered
3919    /// additional-root list associated with a listed session.
3920    #[serde_as(deserialize_as = "DefaultOnError")]
3921    #[schemars(extend("x-deserialize-default-on-error" = true))]
3922    #[serde(default)]
3923    pub additional_directories: Option<SessionAdditionalDirectoriesCapabilities>,
3924    /// **UNSTABLE**
3925    ///
3926    /// This capability is not part of the spec yet, and may be removed or changed at any point.
3927    ///
3928    /// Whether the agent supports `session/fork`.
3929    #[cfg(feature = "unstable_session_fork")]
3930    #[serde_as(deserialize_as = "DefaultOnError")]
3931    #[schemars(extend("x-deserialize-default-on-error" = true))]
3932    #[serde(default)]
3933    pub fork: Option<SessionForkCapabilities>,
3934    /// Whether the agent supports `session/resume`.
3935    #[serde_as(deserialize_as = "DefaultOnError")]
3936    #[schemars(extend("x-deserialize-default-on-error" = true))]
3937    #[serde(default)]
3938    pub resume: Option<SessionResumeCapabilities>,
3939    /// Whether the agent supports `session/close`.
3940    #[serde_as(deserialize_as = "DefaultOnError")]
3941    #[schemars(extend("x-deserialize-default-on-error" = true))]
3942    #[serde(default)]
3943    pub close: Option<SessionCloseCapabilities>,
3944    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
3945    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
3946    /// these keys.
3947    ///
3948    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
3949    #[serde(rename = "_meta")]
3950    pub meta: Option<Meta>,
3951}
3952
3953impl SessionCapabilities {
3954    /// Builds an empty [`SessionCapabilities`]; use builder methods to advertise supported sub-capabilities.
3955    #[must_use]
3956    pub fn new() -> Self {
3957        Self::default()
3958    }
3959
3960    /// Whether the agent supports `session/list`.
3961    #[must_use]
3962    pub fn list(mut self, list: impl IntoOption<SessionListCapabilities>) -> Self {
3963        self.list = list.into_option();
3964        self
3965    }
3966
3967    /// Whether the agent supports `session/delete`.
3968    ///
3969    /// Omitted or `null` both mean the agent does not advertise support.
3970    /// Supplying `{}` means the agent supports deleting sessions from `session/list`.
3971    #[must_use]
3972    pub fn delete(mut self, delete: impl IntoOption<SessionDeleteCapabilities>) -> Self {
3973        self.delete = delete.into_option();
3974        self
3975    }
3976
3977    /// Whether the agent supports `additionalDirectories` on supported session lifecycle requests.
3978    ///
3979    /// Agents that also support `session/list` may return
3980    /// `SessionInfo.additionalDirectories` to report the complete ordered
3981    /// additional-root list associated with a listed session.
3982    #[must_use]
3983    pub fn additional_directories(
3984        mut self,
3985        additional_directories: impl IntoOption<SessionAdditionalDirectoriesCapabilities>,
3986    ) -> Self {
3987        self.additional_directories = additional_directories.into_option();
3988        self
3989    }
3990
3991    #[cfg(feature = "unstable_session_fork")]
3992    /// Whether the agent supports `session/fork`.
3993    #[must_use]
3994    pub fn fork(mut self, fork: impl IntoOption<SessionForkCapabilities>) -> Self {
3995        self.fork = fork.into_option();
3996        self
3997    }
3998
3999    /// Whether the agent supports `session/resume`.
4000    #[must_use]
4001    pub fn resume(mut self, resume: impl IntoOption<SessionResumeCapabilities>) -> Self {
4002        self.resume = resume.into_option();
4003        self
4004    }
4005
4006    /// Whether the agent supports `session/close`.
4007    #[must_use]
4008    pub fn close(mut self, close: impl IntoOption<SessionCloseCapabilities>) -> Self {
4009        self.close = close.into_option();
4010        self
4011    }
4012
4013    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
4014    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
4015    /// these keys.
4016    ///
4017    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
4018    #[must_use]
4019    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4020        self.meta = meta.into_option();
4021        self
4022    }
4023}
4024
4025/// Capabilities for the `session/list` method.
4026///
4027/// By supplying `{}` it means that the agent supports listing of sessions.
4028#[skip_serializing_none]
4029#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
4030#[non_exhaustive]
4031pub struct SessionListCapabilities {
4032    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
4033    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
4034    /// these keys.
4035    ///
4036    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
4037    #[serde(rename = "_meta")]
4038    pub meta: Option<Meta>,
4039}
4040
4041impl SessionListCapabilities {
4042    /// Builds an empty [`SessionListCapabilities`]; use builder methods to advertise supported sub-capabilities.
4043    #[must_use]
4044    pub fn new() -> Self {
4045        Self::default()
4046    }
4047
4048    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
4049    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
4050    /// these keys.
4051    ///
4052    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
4053    #[must_use]
4054    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4055        self.meta = meta.into_option();
4056        self
4057    }
4058}
4059
4060/// Capabilities for the `session/delete` method.
4061///
4062/// Supplying `{}` means the agent supports deleting sessions from `session/list`.
4063#[skip_serializing_none]
4064#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
4065#[non_exhaustive]
4066pub struct SessionDeleteCapabilities {
4067    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
4068    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
4069    /// these keys.
4070    ///
4071    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
4072    #[serde(rename = "_meta")]
4073    pub meta: Option<Meta>,
4074}
4075
4076impl SessionDeleteCapabilities {
4077    /// Builds an empty [`SessionDeleteCapabilities`]; use builder methods to advertise supported sub-capabilities.
4078    #[must_use]
4079    pub fn new() -> Self {
4080        Self::default()
4081    }
4082
4083    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
4084    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
4085    /// these keys.
4086    ///
4087    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
4088    #[must_use]
4089    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4090        self.meta = meta.into_option();
4091        self
4092    }
4093}
4094
4095/// Capabilities for additional session directories support.
4096///
4097/// By supplying `{}` it means that the agent supports the `additionalDirectories`
4098/// field on supported session lifecycle requests. Agents that also support
4099/// `session/list` may return `SessionInfo.additionalDirectories` to report the
4100/// complete ordered additional-root list associated with a listed session.
4101#[skip_serializing_none]
4102#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
4103#[non_exhaustive]
4104pub struct SessionAdditionalDirectoriesCapabilities {
4105    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
4106    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
4107    /// these keys.
4108    ///
4109    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
4110    #[serde(rename = "_meta")]
4111    pub meta: Option<Meta>,
4112}
4113
4114impl SessionAdditionalDirectoriesCapabilities {
4115    /// Builds an empty [`SessionAdditionalDirectoriesCapabilities`]; use builder methods to advertise supported sub-capabilities.
4116    #[must_use]
4117    pub fn new() -> Self {
4118        Self::default()
4119    }
4120
4121    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
4122    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
4123    /// these keys.
4124    ///
4125    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
4126    #[must_use]
4127    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4128        self.meta = meta.into_option();
4129        self
4130    }
4131}
4132
4133/// **UNSTABLE**
4134///
4135/// This capability is not part of the spec yet, and may be removed or changed at any point.
4136///
4137/// Capabilities for the `session/fork` method.
4138///
4139/// By supplying `{}` it means that the agent supports forking of sessions.
4140#[cfg(feature = "unstable_session_fork")]
4141#[skip_serializing_none]
4142#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
4143#[non_exhaustive]
4144pub struct SessionForkCapabilities {
4145    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
4146    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
4147    /// these keys.
4148    ///
4149    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
4150    #[serde(rename = "_meta")]
4151    pub meta: Option<Meta>,
4152}
4153
4154#[cfg(feature = "unstable_session_fork")]
4155impl SessionForkCapabilities {
4156    /// Builds an empty [`SessionForkCapabilities`]; use builder methods to advertise supported sub-capabilities.
4157    #[must_use]
4158    pub fn new() -> Self {
4159        Self::default()
4160    }
4161
4162    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
4163    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
4164    /// these keys.
4165    ///
4166    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
4167    #[must_use]
4168    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4169        self.meta = meta.into_option();
4170        self
4171    }
4172}
4173
4174/// Capabilities for the `session/resume` method.
4175///
4176/// By supplying `{}` it means that the agent supports resuming of sessions.
4177#[skip_serializing_none]
4178#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
4179#[non_exhaustive]
4180pub struct SessionResumeCapabilities {
4181    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
4182    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
4183    /// these keys.
4184    ///
4185    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
4186    #[serde(rename = "_meta")]
4187    pub meta: Option<Meta>,
4188}
4189
4190impl SessionResumeCapabilities {
4191    /// Builds an empty [`SessionResumeCapabilities`]; use builder methods to advertise supported sub-capabilities.
4192    #[must_use]
4193    pub fn new() -> Self {
4194        Self::default()
4195    }
4196
4197    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
4198    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
4199    /// these keys.
4200    ///
4201    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
4202    #[must_use]
4203    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4204        self.meta = meta.into_option();
4205        self
4206    }
4207}
4208
4209/// Capabilities for the `session/close` method.
4210///
4211/// By supplying `{}` it means that the agent supports closing of sessions.
4212#[skip_serializing_none]
4213#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
4214#[non_exhaustive]
4215pub struct SessionCloseCapabilities {
4216    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
4217    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
4218    /// these keys.
4219    ///
4220    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
4221    #[serde(rename = "_meta")]
4222    pub meta: Option<Meta>,
4223}
4224
4225impl SessionCloseCapabilities {
4226    /// Builds an empty [`SessionCloseCapabilities`]; use builder methods to advertise supported sub-capabilities.
4227    #[must_use]
4228    pub fn new() -> Self {
4229        Self::default()
4230    }
4231
4232    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
4233    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
4234    /// these keys.
4235    ///
4236    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
4237    #[must_use]
4238    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4239        self.meta = meta.into_option();
4240        self
4241    }
4242}
4243
4244/// Prompt capabilities supported by the agent in `session/prompt` requests.
4245///
4246/// Baseline agent functionality requires support for [`ContentBlock::Text`]
4247/// and [`ContentBlock::ResourceLink`] in prompt requests.
4248///
4249/// Other variants must be explicitly opted in to.
4250/// Capabilities for different types of content in prompt requests.
4251///
4252/// Indicates which content types beyond the baseline (text and resource links)
4253/// the agent can process.
4254///
4255/// See protocol docs: [Prompt Capabilities](https://agentclientprotocol.com/protocol/initialization#prompt-capabilities)
4256#[skip_serializing_none]
4257#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
4258#[serde(rename_all = "camelCase")]
4259#[non_exhaustive]
4260pub struct PromptCapabilities {
4261    /// Agent supports [`ContentBlock::Image`].
4262    #[serde(default)]
4263    pub image: bool,
4264    /// Agent supports [`ContentBlock::Audio`].
4265    #[serde(default)]
4266    pub audio: bool,
4267    /// Agent supports embedded context in `session/prompt` requests.
4268    ///
4269    /// When enabled, the Client is allowed to include [`ContentBlock::Resource`]
4270    /// in prompt requests for pieces of context that are referenced in the message.
4271    #[serde(default)]
4272    pub embedded_context: bool,
4273    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
4274    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
4275    /// these keys.
4276    ///
4277    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
4278    #[serde(rename = "_meta")]
4279    pub meta: Option<Meta>,
4280}
4281
4282impl PromptCapabilities {
4283    /// Builds an empty [`PromptCapabilities`]; use builder methods to advertise supported sub-capabilities.
4284    #[must_use]
4285    pub fn new() -> Self {
4286        Self::default()
4287    }
4288
4289    /// Agent supports [`ContentBlock::Image`].
4290    #[must_use]
4291    pub fn image(mut self, image: bool) -> Self {
4292        self.image = image;
4293        self
4294    }
4295
4296    /// Agent supports [`ContentBlock::Audio`].
4297    #[must_use]
4298    pub fn audio(mut self, audio: bool) -> Self {
4299        self.audio = audio;
4300        self
4301    }
4302
4303    /// Agent supports embedded context in `session/prompt` requests.
4304    ///
4305    /// When enabled, the Client is allowed to include [`ContentBlock::Resource`]
4306    /// in prompt requests for pieces of context that are referenced in the message.
4307    #[must_use]
4308    pub fn embedded_context(mut self, embedded_context: bool) -> Self {
4309        self.embedded_context = embedded_context;
4310        self
4311    }
4312
4313    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
4314    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
4315    /// these keys.
4316    ///
4317    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
4318    #[must_use]
4319    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4320        self.meta = meta.into_option();
4321        self
4322    }
4323}
4324
4325/// MCP capabilities supported by the agent
4326#[skip_serializing_none]
4327#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
4328#[serde(rename_all = "camelCase")]
4329#[non_exhaustive]
4330pub struct McpCapabilities {
4331    /// Agent supports [`McpServer::Http`].
4332    #[serde(default)]
4333    pub http: bool,
4334    /// Agent supports [`McpServer::Sse`].
4335    #[serde(default)]
4336    pub sse: bool,
4337    /// **UNSTABLE**
4338    ///
4339    /// This capability is not part of the spec yet, and may be removed or changed at any point.
4340    ///
4341    /// Agent supports [`McpServer::Acp`].
4342    #[cfg(feature = "unstable_mcp_over_acp")]
4343    #[serde(default)]
4344    pub acp: bool,
4345    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
4346    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
4347    /// these keys.
4348    ///
4349    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
4350    #[serde(rename = "_meta")]
4351    pub meta: Option<Meta>,
4352}
4353
4354impl McpCapabilities {
4355    /// Builds an empty [`McpCapabilities`]; use builder methods to advertise supported sub-capabilities.
4356    #[must_use]
4357    pub fn new() -> Self {
4358        Self::default()
4359    }
4360
4361    /// Agent supports [`McpServer::Http`].
4362    #[must_use]
4363    pub fn http(mut self, http: bool) -> Self {
4364        self.http = http;
4365        self
4366    }
4367
4368    /// Agent supports [`McpServer::Sse`].
4369    #[must_use]
4370    pub fn sse(mut self, sse: bool) -> Self {
4371        self.sse = sse;
4372        self
4373    }
4374
4375    /// **UNSTABLE**
4376    ///
4377    /// This capability is not part of the spec yet, and may be removed or changed at any point.
4378    ///
4379    /// Agent supports [`McpServer::Acp`].
4380    #[cfg(feature = "unstable_mcp_over_acp")]
4381    #[must_use]
4382    pub fn acp(mut self, acp: bool) -> Self {
4383        self.acp = acp;
4384        self
4385    }
4386
4387    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
4388    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
4389    /// these keys.
4390    ///
4391    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
4392    #[must_use]
4393    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4394        self.meta = meta.into_option();
4395        self
4396    }
4397}
4398
4399// Method schema
4400
4401/// Names of all methods that agents handle.
4402///
4403/// Provides a centralized definition of method names used in the protocol.
4404#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
4405#[non_exhaustive]
4406pub struct AgentMethodNames {
4407    /// Method for initializing the connection.
4408    pub initialize: &'static str,
4409    /// Method for authenticating with the agent.
4410    pub authenticate: &'static str,
4411    /// Method for listing configurable providers.
4412    #[cfg(feature = "unstable_llm_providers")]
4413    pub providers_list: &'static str,
4414    /// Method for setting provider configuration.
4415    #[cfg(feature = "unstable_llm_providers")]
4416    pub providers_set: &'static str,
4417    /// Method for disabling a provider.
4418    #[cfg(feature = "unstable_llm_providers")]
4419    pub providers_disable: &'static str,
4420    /// Method for creating a new session.
4421    pub session_new: &'static str,
4422    /// Method for loading an existing session.
4423    pub session_load: &'static str,
4424    /// Method for setting the mode for a session.
4425    pub session_set_mode: &'static str,
4426    /// Method for setting a configuration option for a session.
4427    pub session_set_config_option: &'static str,
4428    /// Method for sending a prompt to the agent.
4429    pub session_prompt: &'static str,
4430    /// Notification for cancelling operations.
4431    pub session_cancel: &'static str,
4432    /// Method for exchanging MCP-over-ACP messages.
4433    #[cfg(feature = "unstable_mcp_over_acp")]
4434    pub mcp_message: &'static str,
4435    /// Method for listing existing sessions.
4436    pub session_list: &'static str,
4437    /// Method for deleting an existing session.
4438    pub session_delete: &'static str,
4439    /// Method for forking an existing session.
4440    #[cfg(feature = "unstable_session_fork")]
4441    pub session_fork: &'static str,
4442    /// Method for resuming an existing session.
4443    pub session_resume: &'static str,
4444    /// Method for closing an active session.
4445    pub session_close: &'static str,
4446    /// Method for logging out of an authenticated session.
4447    pub logout: &'static str,
4448    /// Method for starting an NES session.
4449    #[cfg(feature = "unstable_nes")]
4450    pub nes_start: &'static str,
4451    /// Method for requesting a suggestion.
4452    #[cfg(feature = "unstable_nes")]
4453    pub nes_suggest: &'static str,
4454    /// Notification for accepting a suggestion.
4455    #[cfg(feature = "unstable_nes")]
4456    pub nes_accept: &'static str,
4457    /// Notification for rejecting a suggestion.
4458    #[cfg(feature = "unstable_nes")]
4459    pub nes_reject: &'static str,
4460    /// Method for closing an NES session.
4461    #[cfg(feature = "unstable_nes")]
4462    pub nes_close: &'static str,
4463    /// Notification for document open events.
4464    #[cfg(feature = "unstable_nes")]
4465    pub document_did_open: &'static str,
4466    /// Notification for document change events.
4467    #[cfg(feature = "unstable_nes")]
4468    pub document_did_change: &'static str,
4469    /// Notification for document close events.
4470    #[cfg(feature = "unstable_nes")]
4471    pub document_did_close: &'static str,
4472    /// Notification for document save events.
4473    #[cfg(feature = "unstable_nes")]
4474    pub document_did_save: &'static str,
4475    /// Notification for document focus events.
4476    #[cfg(feature = "unstable_nes")]
4477    pub document_did_focus: &'static str,
4478}
4479
4480/// Constant containing all agent method names.
4481pub const AGENT_METHOD_NAMES: AgentMethodNames = AgentMethodNames {
4482    initialize: INITIALIZE_METHOD_NAME,
4483    authenticate: AUTHENTICATE_METHOD_NAME,
4484    #[cfg(feature = "unstable_llm_providers")]
4485    providers_list: PROVIDERS_LIST_METHOD_NAME,
4486    #[cfg(feature = "unstable_llm_providers")]
4487    providers_set: PROVIDERS_SET_METHOD_NAME,
4488    #[cfg(feature = "unstable_llm_providers")]
4489    providers_disable: PROVIDERS_DISABLE_METHOD_NAME,
4490    session_new: SESSION_NEW_METHOD_NAME,
4491    session_load: SESSION_LOAD_METHOD_NAME,
4492    session_set_mode: SESSION_SET_MODE_METHOD_NAME,
4493    session_set_config_option: SESSION_SET_CONFIG_OPTION_METHOD_NAME,
4494    session_prompt: SESSION_PROMPT_METHOD_NAME,
4495    session_cancel: SESSION_CANCEL_METHOD_NAME,
4496    #[cfg(feature = "unstable_mcp_over_acp")]
4497    mcp_message: MCP_MESSAGE_METHOD_NAME,
4498    session_list: SESSION_LIST_METHOD_NAME,
4499    session_delete: SESSION_DELETE_METHOD_NAME,
4500    #[cfg(feature = "unstable_session_fork")]
4501    session_fork: SESSION_FORK_METHOD_NAME,
4502    session_resume: SESSION_RESUME_METHOD_NAME,
4503    session_close: SESSION_CLOSE_METHOD_NAME,
4504    logout: LOGOUT_METHOD_NAME,
4505    #[cfg(feature = "unstable_nes")]
4506    nes_start: NES_START_METHOD_NAME,
4507    #[cfg(feature = "unstable_nes")]
4508    nes_suggest: NES_SUGGEST_METHOD_NAME,
4509    #[cfg(feature = "unstable_nes")]
4510    nes_accept: NES_ACCEPT_METHOD_NAME,
4511    #[cfg(feature = "unstable_nes")]
4512    nes_reject: NES_REJECT_METHOD_NAME,
4513    #[cfg(feature = "unstable_nes")]
4514    nes_close: NES_CLOSE_METHOD_NAME,
4515    #[cfg(feature = "unstable_nes")]
4516    document_did_open: DOCUMENT_DID_OPEN_METHOD_NAME,
4517    #[cfg(feature = "unstable_nes")]
4518    document_did_change: DOCUMENT_DID_CHANGE_METHOD_NAME,
4519    #[cfg(feature = "unstable_nes")]
4520    document_did_close: DOCUMENT_DID_CLOSE_METHOD_NAME,
4521    #[cfg(feature = "unstable_nes")]
4522    document_did_save: DOCUMENT_DID_SAVE_METHOD_NAME,
4523    #[cfg(feature = "unstable_nes")]
4524    document_did_focus: DOCUMENT_DID_FOCUS_METHOD_NAME,
4525};
4526
4527/// Method name for the initialize request.
4528pub(crate) const INITIALIZE_METHOD_NAME: &str = "initialize";
4529/// Method name for the authenticate request.
4530pub(crate) const AUTHENTICATE_METHOD_NAME: &str = "authenticate";
4531/// Method name for listing configurable providers.
4532#[cfg(feature = "unstable_llm_providers")]
4533pub(crate) const PROVIDERS_LIST_METHOD_NAME: &str = "providers/list";
4534/// Method name for setting provider configuration.
4535#[cfg(feature = "unstable_llm_providers")]
4536pub(crate) const PROVIDERS_SET_METHOD_NAME: &str = "providers/set";
4537/// Method name for disabling a provider.
4538#[cfg(feature = "unstable_llm_providers")]
4539pub(crate) const PROVIDERS_DISABLE_METHOD_NAME: &str = "providers/disable";
4540/// Method name for creating a new session.
4541pub(crate) const SESSION_NEW_METHOD_NAME: &str = "session/new";
4542/// Method name for loading an existing session.
4543pub(crate) const SESSION_LOAD_METHOD_NAME: &str = "session/load";
4544/// Method name for setting the mode for a session.
4545pub(crate) const SESSION_SET_MODE_METHOD_NAME: &str = "session/set_mode";
4546/// Method name for setting a configuration option for a session.
4547pub(crate) const SESSION_SET_CONFIG_OPTION_METHOD_NAME: &str = "session/set_config_option";
4548/// Method name for sending a prompt.
4549pub(crate) const SESSION_PROMPT_METHOD_NAME: &str = "session/prompt";
4550/// Method name for the cancel notification.
4551pub(crate) const SESSION_CANCEL_METHOD_NAME: &str = "session/cancel";
4552/// Method name for listing existing sessions.
4553pub(crate) const SESSION_LIST_METHOD_NAME: &str = "session/list";
4554/// Method name for deleting an existing session.
4555pub(crate) const SESSION_DELETE_METHOD_NAME: &str = "session/delete";
4556/// Method name for forking an existing session.
4557#[cfg(feature = "unstable_session_fork")]
4558pub(crate) const SESSION_FORK_METHOD_NAME: &str = "session/fork";
4559/// Method name for resuming an existing session.
4560pub(crate) const SESSION_RESUME_METHOD_NAME: &str = "session/resume";
4561/// Method name for closing an active session.
4562pub(crate) const SESSION_CLOSE_METHOD_NAME: &str = "session/close";
4563/// Method name for logging out of an authenticated session.
4564pub(crate) const LOGOUT_METHOD_NAME: &str = "logout";
4565
4566/// All possible requests that a client can send to an agent.
4567///
4568/// This enum is used internally for routing RPC requests. You typically won't need
4569/// to use this directly.
4570///
4571/// This enum encompasses all method calls from client to agent.
4572#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
4573#[serde(untagged)]
4574#[schemars(inline)]
4575#[non_exhaustive]
4576#[allow(clippy::large_enum_variant)]
4577pub enum ClientRequest {
4578    /// Establishes the connection with a client and negotiates protocol capabilities.
4579    ///
4580    /// This method is called once at the beginning of the connection to:
4581    /// - Negotiate the protocol version to use
4582    /// - Exchange capability information between client and agent
4583    /// - Determine available authentication methods
4584    ///
4585    /// The agent should respond with its supported protocol version and capabilities.
4586    ///
4587    /// See protocol docs: [Initialization](https://agentclientprotocol.com/protocol/initialization)
4588    InitializeRequest(InitializeRequest),
4589    /// Authenticates the client using the specified authentication method.
4590    ///
4591    /// Called when the agent requires authentication before allowing session creation.
4592    /// The client provides the authentication method ID that was advertised during initialization.
4593    ///
4594    /// After successful authentication, the client can proceed to create sessions with
4595    /// `new_session` without receiving an `auth_required` error.
4596    ///
4597    /// See protocol docs: [Initialization](https://agentclientprotocol.com/protocol/initialization)
4598    AuthenticateRequest(AuthenticateRequest),
4599    /// **UNSTABLE**
4600    ///
4601    /// This capability is not part of the spec yet, and may be removed or changed at any point.
4602    ///
4603    /// Lists providers that can be configured by the client.
4604    #[cfg(feature = "unstable_llm_providers")]
4605    ListProvidersRequest(ListProvidersRequest),
4606    /// **UNSTABLE**
4607    ///
4608    /// This capability is not part of the spec yet, and may be removed or changed at any point.
4609    ///
4610    /// Replaces the configuration for a provider.
4611    #[cfg(feature = "unstable_llm_providers")]
4612    SetProviderRequest(SetProviderRequest),
4613    /// **UNSTABLE**
4614    ///
4615    /// This capability is not part of the spec yet, and may be removed or changed at any point.
4616    ///
4617    /// Disables a provider.
4618    #[cfg(feature = "unstable_llm_providers")]
4619    DisableProviderRequest(DisableProviderRequest),
4620    /// Logs out of the current authenticated state.
4621    ///
4622    /// After a successful logout, all new sessions will require authentication.
4623    /// There is no guarantee about the behavior of already running sessions.
4624    LogoutRequest(LogoutRequest),
4625    /// Creates a new conversation session with the agent.
4626    ///
4627    /// Sessions represent independent conversation contexts with their own history and state.
4628    ///
4629    /// The agent should:
4630    /// - Create a new session context
4631    /// - Connect to any specified MCP servers
4632    /// - Return a unique session ID for future requests
4633    ///
4634    /// May return an `auth_required` error if the agent requires authentication.
4635    ///
4636    /// See protocol docs: [Session Setup](https://agentclientprotocol.com/protocol/session-setup)
4637    NewSessionRequest(NewSessionRequest),
4638    /// Loads an existing session to resume a previous conversation.
4639    ///
4640    /// This method is only available if the agent advertises the `loadSession` capability.
4641    ///
4642    /// The agent should:
4643    /// - Restore the session context and conversation history
4644    /// - Connect to the specified MCP servers
4645    /// - Stream the entire conversation history back to the client via notifications
4646    ///
4647    /// See protocol docs: [Loading Sessions](https://agentclientprotocol.com/protocol/session-setup#loading-sessions)
4648    LoadSessionRequest(LoadSessionRequest),
4649    /// Lists existing sessions known to the agent.
4650    ///
4651    /// This method is only available if the agent advertises the `sessionCapabilities.list` capability.
4652    ///
4653    /// The agent should return metadata about sessions with optional filtering and pagination support.
4654    ListSessionsRequest(ListSessionsRequest),
4655    /// Deletes an existing session from `session/list`.
4656    ///
4657    /// This method is only available if the agent advertises the `sessionCapabilities.delete` capability.
4658    DeleteSessionRequest(DeleteSessionRequest),
4659    #[cfg(feature = "unstable_session_fork")]
4660    /// **UNSTABLE**
4661    ///
4662    /// This capability is not part of the spec yet, and may be removed or changed at any point.
4663    ///
4664    /// Forks an existing session to create a new independent session.
4665    ///
4666    /// This method is only available if the agent advertises the `session.fork` capability.
4667    ///
4668    /// The agent should create a new session with the same conversation context as the
4669    /// original, allowing operations like generating summaries without affecting the
4670    /// original session's history.
4671    ForkSessionRequest(ForkSessionRequest),
4672    /// Resumes an existing session without returning previous messages.
4673    ///
4674    /// This method is only available if the agent advertises the `sessionCapabilities.resume` capability.
4675    ///
4676    /// The agent should resume the session context, allowing the conversation to continue
4677    /// without replaying the message history (unlike `session/load`).
4678    ResumeSessionRequest(ResumeSessionRequest),
4679    /// Closes an active session and frees up any resources associated with it.
4680    ///
4681    /// This method is only available if the agent advertises the `sessionCapabilities.close` capability.
4682    ///
4683    /// The agent must cancel any ongoing work (as if `session/cancel` was called)
4684    /// and then free up any resources associated with the session.
4685    CloseSessionRequest(CloseSessionRequest),
4686    /// Sets the current mode for a session.
4687    ///
4688    /// Allows switching between different agent modes (e.g., "ask", "architect", "code")
4689    /// that affect system prompts, tool availability, and permission behaviors.
4690    ///
4691    /// The mode must be one of the modes advertised in `availableModes` during session
4692    /// creation or loading. Agents may also change modes autonomously and notify the
4693    /// client via `current_mode_update` notifications.
4694    ///
4695    /// This method can be called at any time during a session, whether the Agent is
4696    /// idle or actively generating a response.
4697    ///
4698    /// See protocol docs: [Session Modes](https://agentclientprotocol.com/protocol/session-modes)
4699    SetSessionModeRequest(SetSessionModeRequest),
4700    /// Sets the current value for a session configuration option.
4701    SetSessionConfigOptionRequest(SetSessionConfigOptionRequest),
4702    /// Processes a user prompt within a session.
4703    ///
4704    /// This method handles the whole lifecycle of a prompt:
4705    /// - Receives user messages with optional context (files, images, etc.)
4706    /// - Processes the prompt using language models
4707    /// - Reports language model content and tool calls to the Clients
4708    /// - Requests permission to run tools
4709    /// - Executes any requested tool calls
4710    /// - Returns when the turn is complete with a stop reason
4711    ///
4712    /// See protocol docs: [Prompt Turn](https://agentclientprotocol.com/protocol/prompt-turn)
4713    PromptRequest(PromptRequest),
4714    #[cfg(feature = "unstable_nes")]
4715    /// **UNSTABLE**
4716    ///
4717    /// This capability is not part of the spec yet, and may be removed or changed at any point.
4718    ///
4719    /// Starts an NES session.
4720    StartNesRequest(StartNesRequest),
4721    #[cfg(feature = "unstable_nes")]
4722    /// **UNSTABLE**
4723    ///
4724    /// This capability is not part of the spec yet, and may be removed or changed at any point.
4725    ///
4726    /// Requests a code suggestion.
4727    SuggestNesRequest(SuggestNesRequest),
4728    #[cfg(feature = "unstable_nes")]
4729    /// **UNSTABLE**
4730    ///
4731    /// This capability is not part of the spec yet, and may be removed or changed at any point.
4732    ///
4733    /// Closes an active NES session and frees up any resources associated with it.
4734    ///
4735    /// The agent must cancel any ongoing work and then free up any resources
4736    /// associated with the NES session.
4737    CloseNesRequest(CloseNesRequest),
4738    /// **UNSTABLE**
4739    ///
4740    /// This capability is not part of the spec yet, and may be removed or changed at any point.
4741    ///
4742    /// Exchanges an MCP-over-ACP message.
4743    #[cfg(feature = "unstable_mcp_over_acp")]
4744    MessageMcpRequest(MessageMcpRequest),
4745    /// Handles extension method requests from the client.
4746    ///
4747    /// Extension methods provide a way to add custom functionality while maintaining
4748    /// protocol compatibility.
4749    ///
4750    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
4751    ExtMethodRequest(ExtRequest),
4752}
4753
4754impl ClientRequest {
4755    /// Returns the corresponding method name of the request.
4756    #[must_use]
4757    pub fn method(&self) -> &str {
4758        match self {
4759            Self::InitializeRequest(_) => AGENT_METHOD_NAMES.initialize,
4760            Self::AuthenticateRequest(_) => AGENT_METHOD_NAMES.authenticate,
4761            #[cfg(feature = "unstable_llm_providers")]
4762            Self::ListProvidersRequest(_) => AGENT_METHOD_NAMES.providers_list,
4763            #[cfg(feature = "unstable_llm_providers")]
4764            Self::SetProviderRequest(_) => AGENT_METHOD_NAMES.providers_set,
4765            #[cfg(feature = "unstable_llm_providers")]
4766            Self::DisableProviderRequest(_) => AGENT_METHOD_NAMES.providers_disable,
4767            Self::LogoutRequest(_) => AGENT_METHOD_NAMES.logout,
4768            Self::NewSessionRequest(_) => AGENT_METHOD_NAMES.session_new,
4769            Self::LoadSessionRequest(_) => AGENT_METHOD_NAMES.session_load,
4770            Self::ListSessionsRequest(_) => AGENT_METHOD_NAMES.session_list,
4771            Self::DeleteSessionRequest(_) => AGENT_METHOD_NAMES.session_delete,
4772            #[cfg(feature = "unstable_session_fork")]
4773            Self::ForkSessionRequest(_) => AGENT_METHOD_NAMES.session_fork,
4774            Self::ResumeSessionRequest(_) => AGENT_METHOD_NAMES.session_resume,
4775            Self::CloseSessionRequest(_) => AGENT_METHOD_NAMES.session_close,
4776            Self::SetSessionModeRequest(_) => AGENT_METHOD_NAMES.session_set_mode,
4777            Self::SetSessionConfigOptionRequest(_) => AGENT_METHOD_NAMES.session_set_config_option,
4778            Self::PromptRequest(_) => AGENT_METHOD_NAMES.session_prompt,
4779            #[cfg(feature = "unstable_nes")]
4780            Self::StartNesRequest(_) => AGENT_METHOD_NAMES.nes_start,
4781            #[cfg(feature = "unstable_nes")]
4782            Self::SuggestNesRequest(_) => AGENT_METHOD_NAMES.nes_suggest,
4783            #[cfg(feature = "unstable_nes")]
4784            Self::CloseNesRequest(_) => AGENT_METHOD_NAMES.nes_close,
4785            #[cfg(feature = "unstable_mcp_over_acp")]
4786            Self::MessageMcpRequest(_) => AGENT_METHOD_NAMES.mcp_message,
4787            Self::ExtMethodRequest(ext_request) => &ext_request.method,
4788        }
4789    }
4790}
4791
4792/// All possible responses that an agent can send to a client.
4793///
4794/// This enum is used internally for routing RPC responses. You typically won't need
4795/// to use this directly - the responses are handled automatically by the connection.
4796///
4797/// These are responses to the corresponding `ClientRequest` variants.
4798#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
4799#[serde(untagged)]
4800#[schemars(inline)]
4801#[non_exhaustive]
4802#[allow(clippy::large_enum_variant)]
4803pub enum AgentResponse {
4804    /// Successful result returned for a `initialize` request.
4805    InitializeResponse(InitializeResponse),
4806    /// Successful result returned for a `authenticate` request.
4807    AuthenticateResponse(#[serde(default)] AuthenticateResponse),
4808    /// Successful result returned for a `providers/list` request.
4809    #[cfg(feature = "unstable_llm_providers")]
4810    ListProvidersResponse(ListProvidersResponse),
4811    /// Successful result returned for a `providers/set` request.
4812    #[cfg(feature = "unstable_llm_providers")]
4813    SetProviderResponse(#[serde(default)] SetProviderResponse),
4814    /// Successful result returned for a `providers/disable` request.
4815    #[cfg(feature = "unstable_llm_providers")]
4816    DisableProviderResponse(#[serde(default)] DisableProviderResponse),
4817    /// Successful result returned for a `logout` request.
4818    LogoutResponse(#[serde(default)] LogoutResponse),
4819    /// Successful result returned for a `session/new` request.
4820    NewSessionResponse(NewSessionResponse),
4821    /// Successful result returned for a `session/load` request.
4822    LoadSessionResponse(#[serde(default)] LoadSessionResponse),
4823    /// Successful result returned for a `session/list` request.
4824    ListSessionsResponse(ListSessionsResponse),
4825    /// Successful result returned for a `session/delete` request.
4826    DeleteSessionResponse(#[serde(default)] DeleteSessionResponse),
4827    /// Successful result returned for a `session/fork` request.
4828    #[cfg(feature = "unstable_session_fork")]
4829    ForkSessionResponse(ForkSessionResponse),
4830    /// Successful result returned for a `session/resume` request.
4831    ResumeSessionResponse(#[serde(default)] ResumeSessionResponse),
4832    /// Successful result returned for a `session/close` request.
4833    CloseSessionResponse(#[serde(default)] CloseSessionResponse),
4834    /// Successful result returned for a `session/set_mode` request.
4835    SetSessionModeResponse(#[serde(default)] SetSessionModeResponse),
4836    /// Successful result returned for a `session/set_config_option` request.
4837    SetSessionConfigOptionResponse(SetSessionConfigOptionResponse),
4838    /// Successful result returned for a `session/prompt` request.
4839    PromptResponse(PromptResponse),
4840    /// Successful result returned for a `nes/start` request.
4841    #[cfg(feature = "unstable_nes")]
4842    StartNesResponse(StartNesResponse),
4843    /// Successful result returned for a `nes/suggest` request.
4844    #[cfg(feature = "unstable_nes")]
4845    SuggestNesResponse(SuggestNesResponse),
4846    /// Successful result returned for a `nes/close` request.
4847    #[cfg(feature = "unstable_nes")]
4848    CloseNesResponse(#[serde(default)] CloseNesResponse),
4849    /// Successful result returned by an extension method outside the core ACP method set.
4850    ExtMethodResponse(ExtResponse),
4851    /// Successful result returned by an MCP-over-ACP `mcp/message` request.
4852    #[cfg(feature = "unstable_mcp_over_acp")]
4853    MessageMcpResponse(MessageMcpResponse),
4854}
4855
4856/// All possible notifications that a client can send to an agent.
4857///
4858/// This enum is used internally for routing RPC notifications. You typically won't need
4859/// to use this directly.
4860///
4861/// Notifications do not expect a response.
4862#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
4863#[serde(untagged)]
4864#[schemars(inline)]
4865#[non_exhaustive]
4866#[allow(clippy::large_enum_variant)]
4867pub enum ClientNotification {
4868    /// Cancels ongoing operations for a session.
4869    ///
4870    /// This is a notification sent by the client to cancel an ongoing prompt turn.
4871    ///
4872    /// Upon receiving this notification, the Agent SHOULD:
4873    /// - Stop all language model requests as soon as possible
4874    /// - Abort all tool call invocations in progress
4875    /// - Send any pending `session/update` notifications
4876    /// - Respond to the original `session/prompt` request with `StopReason::Cancelled`
4877    ///
4878    /// See protocol docs: [Cancellation](https://agentclientprotocol.com/protocol/prompt-turn#cancellation)
4879    CancelNotification(CancelNotification),
4880    #[cfg(feature = "unstable_nes")]
4881    /// **UNSTABLE**
4882    ///
4883    /// Notification sent when a file is opened in the editor.
4884    DidOpenDocumentNotification(DidOpenDocumentNotification),
4885    #[cfg(feature = "unstable_nes")]
4886    /// **UNSTABLE**
4887    ///
4888    /// Notification sent when a file is edited.
4889    DidChangeDocumentNotification(DidChangeDocumentNotification),
4890    #[cfg(feature = "unstable_nes")]
4891    /// **UNSTABLE**
4892    ///
4893    /// Notification sent when a file is closed.
4894    DidCloseDocumentNotification(DidCloseDocumentNotification),
4895    #[cfg(feature = "unstable_nes")]
4896    /// **UNSTABLE**
4897    ///
4898    /// Notification sent when a file is saved.
4899    DidSaveDocumentNotification(DidSaveDocumentNotification),
4900    #[cfg(feature = "unstable_nes")]
4901    /// **UNSTABLE**
4902    ///
4903    /// Notification sent when a file becomes the active editor tab.
4904    DidFocusDocumentNotification(DidFocusDocumentNotification),
4905    #[cfg(feature = "unstable_nes")]
4906    /// **UNSTABLE**
4907    ///
4908    /// Notification sent when a suggestion is accepted.
4909    AcceptNesNotification(AcceptNesNotification),
4910    #[cfg(feature = "unstable_nes")]
4911    /// **UNSTABLE**
4912    ///
4913    /// Notification sent when a suggestion is rejected.
4914    RejectNesNotification(RejectNesNotification),
4915    /// **UNSTABLE**
4916    ///
4917    /// This capability is not part of the spec yet, and may be removed or changed at any point.
4918    ///
4919    /// Sends an MCP-over-ACP notification.
4920    #[cfg(feature = "unstable_mcp_over_acp")]
4921    MessageMcpNotification(MessageMcpNotification),
4922    /// Handles extension notifications from the client.
4923    ///
4924    /// Extension notifications provide a way to send one-way messages for custom functionality
4925    /// while maintaining protocol compatibility.
4926    ///
4927    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
4928    ExtNotification(ExtNotification),
4929}
4930
4931impl ClientNotification {
4932    /// Returns the corresponding method name of the notification.
4933    #[must_use]
4934    pub fn method(&self) -> &str {
4935        match self {
4936            Self::CancelNotification(_) => AGENT_METHOD_NAMES.session_cancel,
4937            #[cfg(feature = "unstable_nes")]
4938            Self::DidOpenDocumentNotification(_) => AGENT_METHOD_NAMES.document_did_open,
4939            #[cfg(feature = "unstable_nes")]
4940            Self::DidChangeDocumentNotification(_) => AGENT_METHOD_NAMES.document_did_change,
4941            #[cfg(feature = "unstable_nes")]
4942            Self::DidCloseDocumentNotification(_) => AGENT_METHOD_NAMES.document_did_close,
4943            #[cfg(feature = "unstable_nes")]
4944            Self::DidSaveDocumentNotification(_) => AGENT_METHOD_NAMES.document_did_save,
4945            #[cfg(feature = "unstable_nes")]
4946            Self::DidFocusDocumentNotification(_) => AGENT_METHOD_NAMES.document_did_focus,
4947            #[cfg(feature = "unstable_nes")]
4948            Self::AcceptNesNotification(_) => AGENT_METHOD_NAMES.nes_accept,
4949            #[cfg(feature = "unstable_nes")]
4950            Self::RejectNesNotification(_) => AGENT_METHOD_NAMES.nes_reject,
4951            #[cfg(feature = "unstable_mcp_over_acp")]
4952            Self::MessageMcpNotification(_) => AGENT_METHOD_NAMES.mcp_message,
4953            Self::ExtNotification(ext_notification) => &ext_notification.method,
4954        }
4955    }
4956}
4957
4958/// Notification to cancel ongoing operations for a session.
4959///
4960/// See protocol docs: [Cancellation](https://agentclientprotocol.com/protocol/prompt-turn#cancellation)
4961#[skip_serializing_none]
4962#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
4963#[schemars(extend("x-side" = "agent", "x-method" = SESSION_CANCEL_METHOD_NAME))]
4964#[serde(rename_all = "camelCase")]
4965#[non_exhaustive]
4966pub struct CancelNotification {
4967    /// The ID of the session to cancel operations for.
4968    pub session_id: SessionId,
4969    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
4970    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
4971    /// these keys.
4972    ///
4973    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
4974    #[serde(rename = "_meta")]
4975    pub meta: Option<Meta>,
4976}
4977
4978impl CancelNotification {
4979    /// Builds [`CancelNotification`] with the required notification fields set; optional fields start unset or empty.
4980    #[must_use]
4981    pub fn new(session_id: impl Into<SessionId>) -> Self {
4982        Self {
4983            session_id: session_id.into(),
4984            meta: None,
4985        }
4986    }
4987
4988    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
4989    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
4990    /// these keys.
4991    ///
4992    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
4993    #[must_use]
4994    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4995        self.meta = meta.into_option();
4996        self
4997    }
4998}
4999
5000#[cfg(test)]
5001mod test_serialization {
5002    use super::*;
5003    use serde_json::json;
5004
5005    #[cfg(feature = "unstable_boolean_config")]
5006    fn test_meta() -> Meta {
5007        json!({ "source": "test" }).as_object().unwrap().clone()
5008    }
5009
5010    #[cfg(feature = "unstable_boolean_config")]
5011    fn serialized_meta_key_count(value: &impl serde::Serialize) -> usize {
5012        serde_json::to_string(value)
5013            .unwrap()
5014            .matches("\"_meta\"")
5015            .count()
5016    }
5017
5018    #[test]
5019    fn test_mcp_server_stdio_serialization() {
5020        let server = McpServer::Stdio(
5021            McpServerStdio::new("test-server", "/usr/bin/server")
5022                .args(vec!["--port".to_string(), "3000".to_string()])
5023                .env(vec![EnvVariable::new("API_KEY", "secret123")]),
5024        );
5025
5026        let json = serde_json::to_value(&server).unwrap();
5027        assert_eq!(
5028            json,
5029            json!({
5030                "name": "test-server",
5031                "command": "/usr/bin/server",
5032                "args": ["--port", "3000"],
5033                "env": [
5034                    {
5035                        "name": "API_KEY",
5036                        "value": "secret123"
5037                    }
5038                ]
5039            })
5040        );
5041
5042        let deserialized: McpServer = serde_json::from_value(json).unwrap();
5043        match deserialized {
5044            McpServer::Stdio(McpServerStdio {
5045                name,
5046                command,
5047                args,
5048                env,
5049                meta: _,
5050            }) => {
5051                assert_eq!(name, "test-server");
5052                assert_eq!(command, PathBuf::from("/usr/bin/server"));
5053                assert_eq!(args, vec!["--port", "3000"]);
5054                assert_eq!(env.len(), 1);
5055                assert_eq!(env[0].name, "API_KEY");
5056                assert_eq!(env[0].value, "secret123");
5057            }
5058            _ => panic!("Expected Stdio variant"),
5059        }
5060    }
5061
5062    #[test]
5063    fn test_mcp_server_http_serialization() {
5064        let server = McpServer::Http(
5065            McpServerHttp::new("http-server", "https://api.example.com").headers(vec![
5066                HttpHeader::new("Authorization", "Bearer token123"),
5067                HttpHeader::new("Content-Type", "application/json"),
5068            ]),
5069        );
5070
5071        let json = serde_json::to_value(&server).unwrap();
5072        assert_eq!(
5073            json,
5074            json!({
5075                "type": "http",
5076                "name": "http-server",
5077                "url": "https://api.example.com",
5078                "headers": [
5079                    {
5080                        "name": "Authorization",
5081                        "value": "Bearer token123"
5082                    },
5083                    {
5084                        "name": "Content-Type",
5085                        "value": "application/json"
5086                    }
5087                ]
5088            })
5089        );
5090
5091        let deserialized: McpServer = serde_json::from_value(json).unwrap();
5092        match deserialized {
5093            McpServer::Http(McpServerHttp {
5094                name,
5095                url,
5096                headers,
5097                meta: _,
5098            }) => {
5099                assert_eq!(name, "http-server");
5100                assert_eq!(url, "https://api.example.com");
5101                assert_eq!(headers.len(), 2);
5102                assert_eq!(headers[0].name, "Authorization");
5103                assert_eq!(headers[0].value, "Bearer token123");
5104                assert_eq!(headers[1].name, "Content-Type");
5105                assert_eq!(headers[1].value, "application/json");
5106            }
5107            _ => panic!("Expected Http variant"),
5108        }
5109    }
5110
5111    #[cfg(feature = "unstable_mcp_over_acp")]
5112    #[test]
5113    fn test_mcp_server_acp_serialization() {
5114        let server = McpServer::Acp(McpServerAcp::new("project-tools", "project-tools-id"));
5115
5116        let json = serde_json::to_value(&server).unwrap();
5117        assert_eq!(
5118            json,
5119            json!({
5120                "type": "acp",
5121                "name": "project-tools",
5122                "id": "project-tools-id"
5123            })
5124        );
5125
5126        let deserialized: McpServer = serde_json::from_value(json).unwrap();
5127        match deserialized {
5128            McpServer::Acp(McpServerAcp { name, id, meta: _ }) => {
5129                assert_eq!(name, "project-tools");
5130                assert_eq!(id, McpServerAcpId::new("project-tools-id"));
5131            }
5132            _ => panic!("Expected Acp variant"),
5133        }
5134    }
5135
5136    #[cfg(feature = "unstable_mcp_over_acp")]
5137    #[test]
5138    fn test_client_mcp_message_method_names() {
5139        assert_eq!(AGENT_METHOD_NAMES.mcp_message, "mcp/message");
5140
5141        assert_eq!(
5142            ClientRequest::MessageMcpRequest(MessageMcpRequest::new("conn-1", "tools/list"))
5143                .method(),
5144            "mcp/message"
5145        );
5146        assert_eq!(
5147            ClientNotification::MessageMcpNotification(MessageMcpNotification::new(
5148                "conn-1",
5149                "notifications/progress"
5150            ))
5151            .method(),
5152            "mcp/message"
5153        );
5154    }
5155
5156    #[cfg(feature = "unstable_mcp_over_acp")]
5157    #[test]
5158    fn test_mcp_server_acp_schema() {
5159        let mcp_server_schema = serde_json::to_value(schemars::schema_for!(McpServer)).unwrap();
5160        assert!(json_contains_entry(
5161            &mcp_server_schema,
5162            "const",
5163            &json!("acp")
5164        ));
5165        assert!(json_contains_entry(
5166            &mcp_server_schema,
5167            "$ref",
5168            &json!("#/$defs/McpServerAcp")
5169        ));
5170
5171        let capabilities_schema =
5172            serde_json::to_value(schemars::schema_for!(McpCapabilities)).unwrap();
5173        assert!(json_contains_key(&capabilities_schema, "acp"));
5174    }
5175
5176    #[cfg(feature = "unstable_mcp_over_acp")]
5177    fn json_contains_entry(
5178        value: &serde_json::Value,
5179        key: &str,
5180        expected: &serde_json::Value,
5181    ) -> bool {
5182        match value {
5183            serde_json::Value::Object(map) => {
5184                map.get(key) == Some(expected)
5185                    || map
5186                        .values()
5187                        .any(|value| json_contains_entry(value, key, expected))
5188            }
5189            serde_json::Value::Array(values) => values
5190                .iter()
5191                .any(|value| json_contains_entry(value, key, expected)),
5192            _ => false,
5193        }
5194    }
5195
5196    #[cfg(feature = "unstable_mcp_over_acp")]
5197    fn json_contains_key(value: &serde_json::Value, key: &str) -> bool {
5198        match value {
5199            serde_json::Value::Object(map) => {
5200                map.contains_key(key) || map.values().any(|value| json_contains_key(value, key))
5201            }
5202            serde_json::Value::Array(values) => {
5203                values.iter().any(|value| json_contains_key(value, key))
5204            }
5205            _ => false,
5206        }
5207    }
5208
5209    #[test]
5210    fn test_mcp_server_sse_serialization() {
5211        let server = McpServer::Sse(
5212            McpServerSse::new("sse-server", "https://sse.example.com/events")
5213                .headers(vec![HttpHeader::new("X-API-Key", "apikey456")]),
5214        );
5215
5216        let json = serde_json::to_value(&server).unwrap();
5217        assert_eq!(
5218            json,
5219            json!({
5220                "type": "sse",
5221                "name": "sse-server",
5222                "url": "https://sse.example.com/events",
5223                "headers": [
5224                    {
5225                        "name": "X-API-Key",
5226                        "value": "apikey456"
5227                    }
5228                ]
5229            })
5230        );
5231
5232        let deserialized: McpServer = serde_json::from_value(json).unwrap();
5233        match deserialized {
5234            McpServer::Sse(McpServerSse {
5235                name,
5236                url,
5237                headers,
5238                meta: _,
5239            }) => {
5240                assert_eq!(name, "sse-server");
5241                assert_eq!(url, "https://sse.example.com/events");
5242                assert_eq!(headers.len(), 1);
5243                assert_eq!(headers[0].name, "X-API-Key");
5244                assert_eq!(headers[0].value, "apikey456");
5245            }
5246            _ => panic!("Expected Sse variant"),
5247        }
5248    }
5249
5250    #[test]
5251    fn test_session_config_option_category_known_variants() {
5252        // Test serialization of known variants
5253        assert_eq!(
5254            serde_json::to_value(&SessionConfigOptionCategory::Mode).unwrap(),
5255            json!("mode")
5256        );
5257        assert_eq!(
5258            serde_json::to_value(&SessionConfigOptionCategory::Model).unwrap(),
5259            json!("model")
5260        );
5261        #[cfg(feature = "unstable_model_config_category")]
5262        assert_eq!(
5263            serde_json::to_value(&SessionConfigOptionCategory::ModelConfig).unwrap(),
5264            json!("model_config")
5265        );
5266        assert_eq!(
5267            serde_json::to_value(&SessionConfigOptionCategory::ThoughtLevel).unwrap(),
5268            json!("thought_level")
5269        );
5270
5271        // Test deserialization of known variants
5272        assert_eq!(
5273            serde_json::from_str::<SessionConfigOptionCategory>("\"mode\"").unwrap(),
5274            SessionConfigOptionCategory::Mode
5275        );
5276        assert_eq!(
5277            serde_json::from_str::<SessionConfigOptionCategory>("\"model\"").unwrap(),
5278            SessionConfigOptionCategory::Model
5279        );
5280        #[cfg(feature = "unstable_model_config_category")]
5281        assert_eq!(
5282            serde_json::from_str::<SessionConfigOptionCategory>("\"model_config\"").unwrap(),
5283            SessionConfigOptionCategory::ModelConfig
5284        );
5285        assert_eq!(
5286            serde_json::from_str::<SessionConfigOptionCategory>("\"thought_level\"").unwrap(),
5287            SessionConfigOptionCategory::ThoughtLevel
5288        );
5289    }
5290
5291    #[test]
5292    fn test_session_config_option_category_unknown_variants() {
5293        // Test that unknown strings are captured in Other variant
5294        let unknown: SessionConfigOptionCategory =
5295            serde_json::from_str("\"some_future_category\"").unwrap();
5296        assert_eq!(
5297            unknown,
5298            SessionConfigOptionCategory::Other("some_future_category".to_string())
5299        );
5300
5301        // Test round-trip of unknown category
5302        let json = serde_json::to_value(&unknown).unwrap();
5303        assert_eq!(json, json!("some_future_category"));
5304    }
5305
5306    #[cfg(not(feature = "unstable_model_config_category"))]
5307    #[test]
5308    fn test_session_config_option_model_config_is_unknown_without_feature() {
5309        let unknown: SessionConfigOptionCategory =
5310            serde_json::from_str("\"model_config\"").unwrap();
5311        assert_eq!(
5312            unknown,
5313            SessionConfigOptionCategory::Other("model_config".to_string())
5314        );
5315    }
5316
5317    #[test]
5318    fn test_session_config_option_category_custom_categories() {
5319        // Category names beginning with `_` are free for custom use
5320        let custom: SessionConfigOptionCategory =
5321            serde_json::from_str("\"_my_custom_category\"").unwrap();
5322        assert_eq!(
5323            custom,
5324            SessionConfigOptionCategory::Other("_my_custom_category".to_string())
5325        );
5326
5327        // Test round-trip preserves the custom category name
5328        let json = serde_json::to_value(&custom).unwrap();
5329        assert_eq!(json, json!("_my_custom_category"));
5330
5331        // Deserialize back and verify
5332        let deserialized: SessionConfigOptionCategory = serde_json::from_value(json).unwrap();
5333        assert_eq!(
5334            deserialized,
5335            SessionConfigOptionCategory::Other("_my_custom_category".to_string()),
5336        );
5337    }
5338
5339    #[test]
5340    fn test_auth_method_agent_serialization() {
5341        let method = AuthMethod::Agent(AuthMethodAgent::new("default-auth", "Default Auth"));
5342
5343        let json = serde_json::to_value(&method).unwrap();
5344        assert_eq!(
5345            json,
5346            json!({
5347                "id": "default-auth",
5348                "name": "Default Auth"
5349            })
5350        );
5351        // description should be omitted when None
5352        assert!(!json.as_object().unwrap().contains_key("description"));
5353        // Agent variant should not emit a `type` field (backward compat)
5354        assert!(!json.as_object().unwrap().contains_key("type"));
5355
5356        let deserialized: AuthMethod = serde_json::from_value(json).unwrap();
5357        match deserialized {
5358            AuthMethod::Agent(AuthMethodAgent { id, name, .. }) => {
5359                assert_eq!(id.0.as_ref(), "default-auth");
5360                assert_eq!(name, "Default Auth");
5361            }
5362            #[cfg(feature = "unstable_auth_methods")]
5363            _ => panic!("Expected Agent variant"),
5364        }
5365    }
5366
5367    #[test]
5368    fn test_auth_method_explicit_agent_deserialization() {
5369        // An explicit `"type": "agent"` should also deserialize to Agent
5370        let json = json!({
5371            "id": "agent-auth",
5372            "name": "Agent Auth",
5373            "type": "agent"
5374        });
5375
5376        let deserialized: AuthMethod = serde_json::from_value(json).unwrap();
5377        assert!(matches!(deserialized, AuthMethod::Agent(_)));
5378    }
5379
5380    #[test]
5381    fn test_session_delete_serialization() {
5382        assert_eq!(AGENT_METHOD_NAMES.session_delete, "session/delete");
5383        assert_eq!(
5384            ClientRequest::DeleteSessionRequest(DeleteSessionRequest::new("sess_abc123")).method(),
5385            "session/delete"
5386        );
5387        assert_eq!(
5388            serde_json::to_value(DeleteSessionRequest::new("sess_abc123")).unwrap(),
5389            json!({
5390                "sessionId": "sess_abc123"
5391            })
5392        );
5393        assert_eq!(
5394            serde_json::to_value(DeleteSessionResponse::new()).unwrap(),
5395            json!({})
5396        );
5397        assert_eq!(
5398            serde_json::to_value(
5399                SessionCapabilities::new().delete(SessionDeleteCapabilities::new())
5400            )
5401            .unwrap(),
5402            json!({
5403                "delete": {}
5404            })
5405        );
5406    }
5407    #[test]
5408    fn test_session_additional_directories_serialization() {
5409        assert_eq!(
5410            serde_json::to_value(NewSessionRequest::new("/home/user/project")).unwrap(),
5411            json!({
5412                "cwd": "/home/user/project",
5413                "mcpServers": []
5414            })
5415        );
5416        assert_eq!(
5417            serde_json::to_value(
5418                NewSessionRequest::new("/home/user/project").additional_directories(vec![
5419                    PathBuf::from("/home/user/shared-lib"),
5420                    PathBuf::from("/home/user/product-docs"),
5421                ])
5422            )
5423            .unwrap(),
5424            json!({
5425                "cwd": "/home/user/project",
5426                "additionalDirectories": [
5427                    "/home/user/shared-lib",
5428                    "/home/user/product-docs"
5429                ],
5430                "mcpServers": []
5431            })
5432        );
5433        assert_eq!(
5434            serde_json::to_value(SessionInfo::new("sess_abc123", "/home/user/project")).unwrap(),
5435            json!({
5436                "sessionId": "sess_abc123",
5437                "cwd": "/home/user/project"
5438            })
5439        );
5440        assert_eq!(
5441            serde_json::to_value(
5442                SessionInfo::new("sess_abc123", "/home/user/project").additional_directories(vec![
5443                    PathBuf::from("/home/user/shared-lib"),
5444                    PathBuf::from("/home/user/product-docs"),
5445                ])
5446            )
5447            .unwrap(),
5448            json!({
5449                "sessionId": "sess_abc123",
5450                "cwd": "/home/user/project",
5451                "additionalDirectories": [
5452                    "/home/user/shared-lib",
5453                    "/home/user/product-docs"
5454                ]
5455            })
5456        );
5457        assert_eq!(
5458            serde_json::from_value::<SessionInfo>(json!({
5459                "sessionId": "sess_abc123",
5460                "cwd": "/home/user/project"
5461            }))
5462            .unwrap()
5463            .additional_directories,
5464            Vec::<PathBuf>::new()
5465        );
5466    }
5467    #[test]
5468    fn test_session_additional_directories_capabilities_serialization() {
5469        assert_eq!(
5470            serde_json::to_value(
5471                SessionCapabilities::new()
5472                    .additional_directories(SessionAdditionalDirectoriesCapabilities::new())
5473            )
5474            .unwrap(),
5475            json!({
5476                "additionalDirectories": {}
5477            })
5478        );
5479    }
5480
5481    #[cfg(feature = "unstable_auth_methods")]
5482    #[test]
5483    fn test_auth_method_env_var_serialization() {
5484        let method = AuthMethod::EnvVar(AuthMethodEnvVar::new(
5485            "api-key",
5486            "API Key",
5487            vec![AuthEnvVar::new("API_KEY")],
5488        ));
5489
5490        let json = serde_json::to_value(&method).unwrap();
5491        assert_eq!(
5492            json,
5493            json!({
5494                "id": "api-key",
5495                "name": "API Key",
5496                "type": "env_var",
5497                "vars": [{"name": "API_KEY"}]
5498            })
5499        );
5500        // secret defaults to true and should be omitted; optional defaults to false and should be omitted
5501        assert!(!json["vars"][0].as_object().unwrap().contains_key("secret"));
5502        assert!(
5503            !json["vars"][0]
5504                .as_object()
5505                .unwrap()
5506                .contains_key("optional")
5507        );
5508
5509        let deserialized: AuthMethod = serde_json::from_value(json).unwrap();
5510        match deserialized {
5511            AuthMethod::EnvVar(AuthMethodEnvVar {
5512                id,
5513                name: method_name,
5514                vars,
5515                link,
5516                ..
5517            }) => {
5518                assert_eq!(id.0.as_ref(), "api-key");
5519                assert_eq!(method_name, "API Key");
5520                assert_eq!(vars.len(), 1);
5521                assert_eq!(vars[0].name, "API_KEY");
5522                assert!(vars[0].secret);
5523                assert!(!vars[0].optional);
5524                assert!(link.is_none());
5525            }
5526            _ => panic!("Expected EnvVar variant"),
5527        }
5528    }
5529
5530    #[cfg(feature = "unstable_auth_methods")]
5531    #[test]
5532    fn test_auth_method_env_var_with_link_serialization() {
5533        let method = AuthMethod::EnvVar(
5534            AuthMethodEnvVar::new("api-key", "API Key", vec![AuthEnvVar::new("API_KEY")])
5535                .link("https://example.com/keys"),
5536        );
5537
5538        let json = serde_json::to_value(&method).unwrap();
5539        assert_eq!(
5540            json,
5541            json!({
5542                "id": "api-key",
5543                "name": "API Key",
5544                "type": "env_var",
5545                "vars": [{"name": "API_KEY"}],
5546                "link": "https://example.com/keys"
5547            })
5548        );
5549
5550        let deserialized: AuthMethod = serde_json::from_value(json).unwrap();
5551        match deserialized {
5552            AuthMethod::EnvVar(AuthMethodEnvVar { link, .. }) => {
5553                assert_eq!(link.as_deref(), Some("https://example.com/keys"));
5554            }
5555            _ => panic!("Expected EnvVar variant"),
5556        }
5557    }
5558
5559    #[cfg(feature = "unstable_auth_methods")]
5560    #[test]
5561    fn test_auth_method_env_var_multiple_vars() {
5562        let method = AuthMethod::EnvVar(AuthMethodEnvVar::new(
5563            "azure-openai",
5564            "Azure OpenAI",
5565            vec![
5566                AuthEnvVar::new("AZURE_OPENAI_API_KEY").label("API Key"),
5567                AuthEnvVar::new("AZURE_OPENAI_ENDPOINT")
5568                    .label("Endpoint URL")
5569                    .secret(false),
5570                AuthEnvVar::new("AZURE_OPENAI_API_VERSION")
5571                    .label("API Version")
5572                    .secret(false)
5573                    .optional(true),
5574            ],
5575        ));
5576
5577        let json = serde_json::to_value(&method).unwrap();
5578        assert_eq!(
5579            json,
5580            json!({
5581                "id": "azure-openai",
5582                "name": "Azure OpenAI",
5583                "type": "env_var",
5584                "vars": [
5585                    {"name": "AZURE_OPENAI_API_KEY", "label": "API Key"},
5586                    {"name": "AZURE_OPENAI_ENDPOINT", "label": "Endpoint URL", "secret": false},
5587                    {"name": "AZURE_OPENAI_API_VERSION", "label": "API Version", "secret": false, "optional": true}
5588                ]
5589            })
5590        );
5591
5592        let deserialized: AuthMethod = serde_json::from_value(json).unwrap();
5593        match deserialized {
5594            AuthMethod::EnvVar(AuthMethodEnvVar { vars, .. }) => {
5595                assert_eq!(vars.len(), 3);
5596                // First var: secret (default true), not optional (default false)
5597                assert_eq!(vars[0].name, "AZURE_OPENAI_API_KEY");
5598                assert_eq!(vars[0].label.as_deref(), Some("API Key"));
5599                assert!(vars[0].secret);
5600                assert!(!vars[0].optional);
5601                // Second var: not a secret, not optional
5602                assert_eq!(vars[1].name, "AZURE_OPENAI_ENDPOINT");
5603                assert!(!vars[1].secret);
5604                assert!(!vars[1].optional);
5605                // Third var: not a secret, optional
5606                assert_eq!(vars[2].name, "AZURE_OPENAI_API_VERSION");
5607                assert!(!vars[2].secret);
5608                assert!(vars[2].optional);
5609            }
5610            _ => panic!("Expected EnvVar variant"),
5611        }
5612    }
5613
5614    #[cfg(feature = "unstable_auth_methods")]
5615    #[test]
5616    fn test_auth_method_terminal_serialization() {
5617        let method = AuthMethod::Terminal(AuthMethodTerminal::new("tui-auth", "Terminal Auth"));
5618
5619        let json = serde_json::to_value(&method).unwrap();
5620        assert_eq!(
5621            json,
5622            json!({
5623                "id": "tui-auth",
5624                "name": "Terminal Auth",
5625                "type": "terminal"
5626            })
5627        );
5628        // args and env should be omitted when empty
5629        assert!(!json.as_object().unwrap().contains_key("args"));
5630        assert!(!json.as_object().unwrap().contains_key("env"));
5631
5632        let deserialized: AuthMethod = serde_json::from_value(json).unwrap();
5633        match deserialized {
5634            AuthMethod::Terminal(AuthMethodTerminal { args, env, .. }) => {
5635                assert!(args.is_empty());
5636                assert!(env.is_empty());
5637            }
5638            _ => panic!("Expected Terminal variant"),
5639        }
5640    }
5641
5642    #[cfg(feature = "unstable_auth_methods")]
5643    #[test]
5644    fn test_auth_method_terminal_with_args_and_env_serialization() {
5645        use std::collections::HashMap;
5646
5647        let mut env = HashMap::new();
5648        env.insert("TERM".to_string(), "xterm-256color".to_string());
5649
5650        let method = AuthMethod::Terminal(
5651            AuthMethodTerminal::new("tui-auth", "Terminal Auth")
5652                .args(vec!["--interactive".to_string(), "--color".to_string()])
5653                .env(env),
5654        );
5655
5656        let json = serde_json::to_value(&method).unwrap();
5657        assert_eq!(
5658            json,
5659            json!({
5660                "id": "tui-auth",
5661                "name": "Terminal Auth",
5662                "type": "terminal",
5663                "args": ["--interactive", "--color"],
5664                "env": {
5665                    "TERM": "xterm-256color"
5666                }
5667            })
5668        );
5669
5670        let deserialized: AuthMethod = serde_json::from_value(json).unwrap();
5671        match deserialized {
5672            AuthMethod::Terminal(AuthMethodTerminal { args, env, .. }) => {
5673                assert_eq!(args, vec!["--interactive", "--color"]);
5674                assert_eq!(env.len(), 1);
5675                assert_eq!(env.get("TERM").unwrap(), "xterm-256color");
5676            }
5677            _ => panic!("Expected Terminal variant"),
5678        }
5679    }
5680
5681    #[cfg(feature = "unstable_boolean_config")]
5682    #[test]
5683    fn test_session_config_option_value_id_serialize() {
5684        let val = SessionConfigOptionValue::value_id("model-1");
5685        let json = serde_json::to_value(&val).unwrap();
5686        // ValueId omits the "type" field (it's the default)
5687        assert_eq!(json, json!({ "value": "model-1" }));
5688        assert!(!json.as_object().unwrap().contains_key("type"));
5689    }
5690
5691    #[cfg(feature = "unstable_boolean_config")]
5692    #[test]
5693    fn test_session_config_option_value_boolean_serialize() {
5694        let val = SessionConfigOptionValue::boolean(true);
5695        let json = serde_json::to_value(&val).unwrap();
5696        assert_eq!(json, json!({ "type": "boolean", "value": true }));
5697    }
5698
5699    #[cfg(feature = "unstable_boolean_config")]
5700    #[test]
5701    fn test_session_config_option_value_deserialize_no_type() {
5702        // Missing "type" should default to ValueId
5703        let json = json!({ "value": "model-1" });
5704        let val: SessionConfigOptionValue = serde_json::from_value(json).unwrap();
5705        assert_eq!(val, SessionConfigOptionValue::value_id("model-1"));
5706        assert_eq!(val.as_value_id().unwrap().to_string(), "model-1");
5707    }
5708
5709    #[cfg(feature = "unstable_boolean_config")]
5710    #[test]
5711    fn test_session_config_option_value_deserialize_boolean() {
5712        let json = json!({ "type": "boolean", "value": true });
5713        let val: SessionConfigOptionValue = serde_json::from_value(json).unwrap();
5714        assert_eq!(val, SessionConfigOptionValue::boolean(true));
5715        assert_eq!(val.as_bool(), Some(true));
5716    }
5717
5718    #[cfg(feature = "unstable_boolean_config")]
5719    #[test]
5720    fn test_session_config_option_value_deserialize_boolean_false() {
5721        let json = json!({ "type": "boolean", "value": false });
5722        let val: SessionConfigOptionValue = serde_json::from_value(json).unwrap();
5723        assert_eq!(val, SessionConfigOptionValue::boolean(false));
5724        assert_eq!(val.as_bool(), Some(false));
5725    }
5726
5727    #[cfg(feature = "unstable_boolean_config")]
5728    #[test]
5729    fn test_session_config_option_value_deserialize_unknown_type_with_string_value() {
5730        // Unknown type with a string value gracefully falls back to ValueId
5731        let json = json!({ "type": "text", "value": "freeform input" });
5732        let val: SessionConfigOptionValue = serde_json::from_value(json).unwrap();
5733        assert_eq!(val.as_value_id().unwrap().to_string(), "freeform input");
5734    }
5735
5736    #[cfg(feature = "unstable_boolean_config")]
5737    #[test]
5738    fn test_session_config_option_value_roundtrip_value_id() {
5739        let original = SessionConfigOptionValue::value_id("option-a");
5740        let json = serde_json::to_value(&original).unwrap();
5741        let roundtripped: SessionConfigOptionValue = serde_json::from_value(json).unwrap();
5742        assert_eq!(original, roundtripped);
5743    }
5744
5745    #[cfg(feature = "unstable_boolean_config")]
5746    #[test]
5747    fn test_session_config_option_value_roundtrip_boolean() {
5748        let original = SessionConfigOptionValue::boolean(false);
5749        let json = serde_json::to_value(&original).unwrap();
5750        let roundtripped: SessionConfigOptionValue = serde_json::from_value(json).unwrap();
5751        assert_eq!(original, roundtripped);
5752    }
5753
5754    #[cfg(feature = "unstable_boolean_config")]
5755    #[test]
5756    fn test_session_config_option_value_type_mismatch_boolean_with_string() {
5757        // type says "boolean" but value is a string — falls to untagged ValueId
5758        let json = json!({ "type": "boolean", "value": "not a bool" });
5759        let result = serde_json::from_value::<SessionConfigOptionValue>(json);
5760        // serde tries Boolean first (fails), then falls to untagged ValueId (succeeds)
5761        assert!(result.is_ok());
5762        assert_eq!(
5763            result.unwrap().as_value_id().unwrap().to_string(),
5764            "not a bool"
5765        );
5766    }
5767
5768    #[cfg(feature = "unstable_boolean_config")]
5769    #[test]
5770    fn test_session_config_option_value_from_impls() {
5771        let from_str: SessionConfigOptionValue = "model-1".into();
5772        assert_eq!(from_str.as_value_id().unwrap().to_string(), "model-1");
5773
5774        let from_id: SessionConfigOptionValue = SessionConfigValueId::new("model-2").into();
5775        assert_eq!(from_id.as_value_id().unwrap().to_string(), "model-2");
5776
5777        let from_bool: SessionConfigOptionValue = true.into();
5778        assert_eq!(from_bool.as_bool(), Some(true));
5779    }
5780
5781    #[cfg(feature = "unstable_boolean_config")]
5782    #[test]
5783    fn test_set_session_config_option_request_value_id() {
5784        let req = SetSessionConfigOptionRequest::new("sess_1", "model", "model-1");
5785        let json = serde_json::to_value(&req).unwrap();
5786        assert_eq!(
5787            json,
5788            json!({
5789                "sessionId": "sess_1",
5790                "configId": "model",
5791                "value": "model-1"
5792            })
5793        );
5794        // No "type" field for value_id
5795        assert!(!json.as_object().unwrap().contains_key("type"));
5796    }
5797
5798    #[cfg(feature = "unstable_boolean_config")]
5799    #[test]
5800    fn test_set_session_config_option_request_boolean() {
5801        let req = SetSessionConfigOptionRequest::new("sess_1", "brave_mode", true);
5802        let json = serde_json::to_value(&req).unwrap();
5803        assert_eq!(
5804            json,
5805            json!({
5806                "sessionId": "sess_1",
5807                "configId": "brave_mode",
5808                "type": "boolean",
5809                "value": true
5810            })
5811        );
5812    }
5813
5814    #[cfg(feature = "unstable_boolean_config")]
5815    #[test]
5816    fn test_set_session_config_option_request_deserialize_no_type() {
5817        // Backwards-compatible: no "type" field → value_id
5818        let json = json!({
5819            "sessionId": "sess_1",
5820            "configId": "model",
5821            "value": "model-1"
5822        });
5823        let req: SetSessionConfigOptionRequest = serde_json::from_value(json).unwrap();
5824        assert_eq!(req.session_id.to_string(), "sess_1");
5825        assert_eq!(req.config_id.to_string(), "model");
5826        assert_eq!(req.value.as_value_id().unwrap().to_string(), "model-1");
5827    }
5828
5829    #[cfg(feature = "unstable_boolean_config")]
5830    #[test]
5831    fn test_set_session_config_option_request_deserialize_boolean() {
5832        let json = json!({
5833            "sessionId": "sess_1",
5834            "configId": "brave_mode",
5835            "type": "boolean",
5836            "value": true
5837        });
5838        let req: SetSessionConfigOptionRequest = serde_json::from_value(json).unwrap();
5839        assert_eq!(req.value.as_bool(), Some(true));
5840    }
5841
5842    #[cfg(feature = "unstable_boolean_config")]
5843    #[test]
5844    fn test_set_session_config_option_request_roundtrip_value_id() {
5845        let original = SetSessionConfigOptionRequest::new("s", "c", "v");
5846        let json = serde_json::to_value(&original).unwrap();
5847        let roundtripped: SetSessionConfigOptionRequest = serde_json::from_value(json).unwrap();
5848        assert_eq!(original, roundtripped);
5849    }
5850
5851    #[cfg(feature = "unstable_boolean_config")]
5852    #[test]
5853    fn test_set_session_config_option_request_roundtrip_boolean() {
5854        let original = SetSessionConfigOptionRequest::new("s", "c", false);
5855        let json = serde_json::to_value(&original).unwrap();
5856        let roundtripped: SetSessionConfigOptionRequest = serde_json::from_value(json).unwrap();
5857        assert_eq!(original, roundtripped);
5858    }
5859
5860    #[cfg(feature = "unstable_boolean_config")]
5861    #[test]
5862    fn test_session_config_boolean_serialization() {
5863        let cfg = SessionConfigBoolean::new(true);
5864        let json = serde_json::to_value(&cfg).unwrap();
5865        assert_eq!(json, json!({ "currentValue": true }));
5866
5867        let deserialized: SessionConfigBoolean = serde_json::from_value(json).unwrap();
5868        assert!(deserialized.current_value);
5869    }
5870
5871    #[cfg(feature = "unstable_boolean_config")]
5872    #[test]
5873    fn test_session_config_option_boolean_variant() {
5874        let opt = SessionConfigOption::boolean("brave_mode", "Brave Mode", false)
5875            .description("Skip confirmation prompts")
5876            .meta(test_meta());
5877        assert_eq!(serialized_meta_key_count(&opt), 1);
5878
5879        let json = serde_json::to_value(&opt).unwrap();
5880        assert_eq!(
5881            json,
5882            json!({
5883                "id": "brave_mode",
5884                "name": "Brave Mode",
5885                "description": "Skip confirmation prompts",
5886                "type": "boolean",
5887                "currentValue": false,
5888                "_meta": {
5889                    "source": "test"
5890                }
5891            })
5892        );
5893
5894        let deserialized: SessionConfigOption = serde_json::from_value(json).unwrap();
5895        assert_eq!(deserialized.id.to_string(), "brave_mode");
5896        assert_eq!(deserialized.name, "Brave Mode");
5897        match deserialized.kind {
5898            SessionConfigKind::Boolean(ref b) => assert!(!b.current_value),
5899            _ => panic!("Expected Boolean kind"),
5900        }
5901    }
5902
5903    #[cfg(feature = "unstable_boolean_config")]
5904    #[test]
5905    fn test_session_config_option_select_still_works() {
5906        // Make sure existing select options are unaffected
5907        let opt = SessionConfigOption::select(
5908            "model",
5909            "Model",
5910            "model-1",
5911            vec![
5912                SessionConfigSelectOption::new("model-1", "Model 1"),
5913                SessionConfigSelectOption::new("model-2", "Model 2"),
5914            ],
5915        )
5916        .meta(test_meta());
5917        assert_eq!(serialized_meta_key_count(&opt), 1);
5918
5919        let json = serde_json::to_value(&opt).unwrap();
5920        assert_eq!(json["type"], "select");
5921        assert_eq!(json["currentValue"], "model-1");
5922        assert_eq!(json["options"].as_array().unwrap().len(), 2);
5923        assert_eq!(json["_meta"]["source"], "test");
5924
5925        let deserialized: SessionConfigOption = serde_json::from_value(json).unwrap();
5926        match deserialized.kind {
5927            SessionConfigKind::Select(ref s) => {
5928                assert_eq!(s.current_value.to_string(), "model-1");
5929            }
5930            _ => panic!("Expected Select kind"),
5931        }
5932    }
5933
5934    #[cfg(feature = "unstable_llm_providers")]
5935    #[test]
5936    fn test_llm_protocol_known_variants() {
5937        assert_eq!(
5938            serde_json::to_value(&LlmProtocol::Anthropic).unwrap(),
5939            json!("anthropic")
5940        );
5941        assert_eq!(
5942            serde_json::to_value(&LlmProtocol::OpenAi).unwrap(),
5943            json!("openai")
5944        );
5945        assert_eq!(
5946            serde_json::to_value(&LlmProtocol::Azure).unwrap(),
5947            json!("azure")
5948        );
5949        assert_eq!(
5950            serde_json::to_value(&LlmProtocol::Vertex).unwrap(),
5951            json!("vertex")
5952        );
5953        assert_eq!(
5954            serde_json::to_value(&LlmProtocol::Bedrock).unwrap(),
5955            json!("bedrock")
5956        );
5957
5958        assert_eq!(
5959            serde_json::from_str::<LlmProtocol>("\"anthropic\"").unwrap(),
5960            LlmProtocol::Anthropic
5961        );
5962        assert_eq!(
5963            serde_json::from_str::<LlmProtocol>("\"openai\"").unwrap(),
5964            LlmProtocol::OpenAi
5965        );
5966        assert_eq!(
5967            serde_json::from_str::<LlmProtocol>("\"azure\"").unwrap(),
5968            LlmProtocol::Azure
5969        );
5970        assert_eq!(
5971            serde_json::from_str::<LlmProtocol>("\"vertex\"").unwrap(),
5972            LlmProtocol::Vertex
5973        );
5974        assert_eq!(
5975            serde_json::from_str::<LlmProtocol>("\"bedrock\"").unwrap(),
5976            LlmProtocol::Bedrock
5977        );
5978    }
5979
5980    #[cfg(feature = "unstable_llm_providers")]
5981    #[test]
5982    fn test_llm_protocol_unknown_variant() {
5983        let unknown: LlmProtocol = serde_json::from_str("\"cohere\"").unwrap();
5984        assert_eq!(unknown, LlmProtocol::Other("cohere".to_string()));
5985
5986        let json = serde_json::to_value(&unknown).unwrap();
5987        assert_eq!(json, json!("cohere"));
5988    }
5989
5990    #[cfg(feature = "unstable_llm_providers")]
5991    #[test]
5992    fn test_provider_current_config_serialization() {
5993        let config =
5994            ProviderCurrentConfig::new(LlmProtocol::Anthropic, "https://api.anthropic.com");
5995
5996        let json = serde_json::to_value(&config).unwrap();
5997        assert_eq!(
5998            json,
5999            json!({
6000                "apiType": "anthropic",
6001                "baseUrl": "https://api.anthropic.com"
6002            })
6003        );
6004
6005        let deserialized: ProviderCurrentConfig = serde_json::from_value(json).unwrap();
6006        assert_eq!(deserialized.api_type, LlmProtocol::Anthropic);
6007        assert_eq!(deserialized.base_url, "https://api.anthropic.com");
6008    }
6009
6010    #[cfg(feature = "unstable_llm_providers")]
6011    #[test]
6012    fn test_provider_info_with_current_config() {
6013        let info = ProviderInfo::new(
6014            "main",
6015            vec![LlmProtocol::Anthropic, LlmProtocol::OpenAi],
6016            true,
6017            Some(ProviderCurrentConfig::new(
6018                LlmProtocol::Anthropic,
6019                "https://api.anthropic.com",
6020            )),
6021        );
6022
6023        let json = serde_json::to_value(&info).unwrap();
6024        assert_eq!(
6025            json,
6026            json!({
6027                "id": "main",
6028                "supported": ["anthropic", "openai"],
6029                "required": true,
6030                "current": {
6031                    "apiType": "anthropic",
6032                    "baseUrl": "https://api.anthropic.com"
6033                }
6034            })
6035        );
6036
6037        let deserialized: ProviderInfo = serde_json::from_value(json).unwrap();
6038        assert_eq!(deserialized.id, "main");
6039        assert_eq!(deserialized.supported.len(), 2);
6040        assert!(deserialized.required);
6041        assert!(deserialized.current.is_some());
6042        assert_eq!(
6043            deserialized.current.as_ref().unwrap().api_type,
6044            LlmProtocol::Anthropic
6045        );
6046    }
6047
6048    #[cfg(feature = "unstable_llm_providers")]
6049    #[test]
6050    fn test_provider_info_disabled() {
6051        let info = ProviderInfo::new(
6052            "secondary",
6053            vec![LlmProtocol::OpenAi],
6054            false,
6055            None::<ProviderCurrentConfig>,
6056        );
6057
6058        let json = serde_json::to_value(&info).unwrap();
6059        assert_eq!(
6060            json,
6061            json!({
6062                "id": "secondary",
6063                "supported": ["openai"],
6064                "required": false
6065            })
6066        );
6067
6068        let deserialized: ProviderInfo = serde_json::from_value(json).unwrap();
6069        assert_eq!(deserialized.id, "secondary");
6070        assert!(!deserialized.required);
6071        assert!(deserialized.current.is_none());
6072    }
6073
6074    #[cfg(feature = "unstable_llm_providers")]
6075    #[test]
6076    fn test_provider_info_missing_current_defaults_to_none() {
6077        // current is optional; omitting it should decode as None
6078        let json = json!({
6079            "id": "main",
6080            "supported": ["anthropic"],
6081            "required": true
6082        });
6083        let deserialized: ProviderInfo = serde_json::from_value(json).unwrap();
6084        assert!(deserialized.current.is_none());
6085    }
6086
6087    #[cfg(feature = "unstable_llm_providers")]
6088    #[test]
6089    fn test_provider_info_explicit_null_current_decodes_to_none() {
6090        // current: null and an omitted current are equivalent on the wire;
6091        // both must deserialize into None so the disabled state is preserved
6092        // regardless of which form the peer chose to send.
6093        let json = json!({
6094            "id": "main",
6095            "supported": ["anthropic"],
6096            "required": true,
6097            "current": null
6098        });
6099        let deserialized: ProviderInfo = serde_json::from_value(json).unwrap();
6100        assert!(deserialized.current.is_none());
6101    }
6102
6103    #[cfg(feature = "unstable_llm_providers")]
6104    #[test]
6105    fn test_list_providers_response_serialization() {
6106        let response = ListProvidersResponse::new(vec![ProviderInfo::new(
6107            "main",
6108            vec![LlmProtocol::Anthropic],
6109            true,
6110            Some(ProviderCurrentConfig::new(
6111                LlmProtocol::Anthropic,
6112                "https://api.anthropic.com",
6113            )),
6114        )]);
6115
6116        let json = serde_json::to_value(&response).unwrap();
6117        assert_eq!(json["providers"].as_array().unwrap().len(), 1);
6118        assert_eq!(json["providers"][0]["id"], "main");
6119
6120        let deserialized: ListProvidersResponse = serde_json::from_value(json).unwrap();
6121        assert_eq!(deserialized.providers.len(), 1);
6122    }
6123
6124    #[cfg(feature = "unstable_llm_providers")]
6125    #[test]
6126    fn test_set_provider_request_serialization() {
6127        use std::collections::HashMap;
6128
6129        let mut headers = HashMap::new();
6130        headers.insert("Authorization".to_string(), "Bearer sk-test".to_string());
6131
6132        let request =
6133            SetProviderRequest::new("main", LlmProtocol::OpenAi, "https://api.openai.com/v1")
6134                .headers(headers);
6135
6136        let json = serde_json::to_value(&request).unwrap();
6137        assert_eq!(
6138            json,
6139            json!({
6140                "id": "main",
6141                "apiType": "openai",
6142                "baseUrl": "https://api.openai.com/v1",
6143                "headers": {
6144                    "Authorization": "Bearer sk-test"
6145                }
6146            })
6147        );
6148
6149        let deserialized: SetProviderRequest = serde_json::from_value(json).unwrap();
6150        assert_eq!(deserialized.id, "main");
6151        assert_eq!(deserialized.api_type, LlmProtocol::OpenAi);
6152        assert_eq!(deserialized.base_url, "https://api.openai.com/v1");
6153        assert_eq!(deserialized.headers.len(), 1);
6154        assert_eq!(
6155            deserialized.headers.get("Authorization").unwrap(),
6156            "Bearer sk-test"
6157        );
6158    }
6159
6160    #[cfg(feature = "unstable_llm_providers")]
6161    #[test]
6162    fn test_set_provider_request_omits_empty_headers() {
6163        let request =
6164            SetProviderRequest::new("main", LlmProtocol::Anthropic, "https://api.anthropic.com");
6165
6166        let json = serde_json::to_value(&request).unwrap();
6167        // headers should be omitted when empty
6168        assert!(!json.as_object().unwrap().contains_key("headers"));
6169    }
6170
6171    #[cfg(feature = "unstable_llm_providers")]
6172    #[test]
6173    fn test_disable_provider_request_serialization() {
6174        let request = DisableProviderRequest::new("secondary");
6175
6176        let json = serde_json::to_value(&request).unwrap();
6177        assert_eq!(json, json!({ "id": "secondary" }));
6178
6179        let deserialized: DisableProviderRequest = serde_json::from_value(json).unwrap();
6180        assert_eq!(deserialized.id, "secondary");
6181    }
6182
6183    #[cfg(feature = "unstable_llm_providers")]
6184    #[test]
6185    fn test_providers_capabilities_serialization() {
6186        let caps = ProvidersCapabilities::new();
6187
6188        let json = serde_json::to_value(&caps).unwrap();
6189        assert_eq!(json, json!({}));
6190
6191        let deserialized: ProvidersCapabilities = serde_json::from_value(json).unwrap();
6192        assert!(deserialized.meta.is_none());
6193    }
6194
6195    #[cfg(feature = "unstable_llm_providers")]
6196    #[test]
6197    fn test_agent_capabilities_with_providers() {
6198        let caps = AgentCapabilities::new().providers(ProvidersCapabilities::new());
6199
6200        let json = serde_json::to_value(&caps).unwrap();
6201        assert_eq!(json["providers"], json!({}));
6202
6203        let deserialized: AgentCapabilities = serde_json::from_value(json).unwrap();
6204        assert!(deserialized.providers.is_some());
6205    }
6206}