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