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