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
8use std::collections::HashMap;
9
10use derive_more::{Display, From};
11use serde::{Deserialize, Serialize};
12use serde_with::{DefaultOnError, DefaultOnNull, VecSkipError, serde_as, skip_serializing_none};
13
14use crate::{IntoOption, ProtocolVersion};
15
16use super::{
17    ClientCapabilities, ContentBlock, ExtNotification, ExtRequest, ExtResponse, Meta, SessionId,
18};
19
20#[cfg(all(feature = "unstable_auth_status", feature = "schemars"))]
21use super::AUTH_STATUS_UPDATE_NOTIFICATION;
22#[cfg(feature = "unstable_mcp_over_acp")]
23use super::mcp::{MCP_MESSAGE_METHOD_NAME, MessageMcpNotification};
24
25// Initialize
26
27/// Request parameters for the initialize method.
28///
29/// Sent by the client to establish connection and negotiate capabilities.
30///
31/// See protocol docs: [Initialization](https://agentclientprotocol.com/protocol/v1/initialization)
32#[serde_as]
33#[skip_serializing_none]
34#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
35#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
36#[cfg_attr(feature = "schemars", schemars(extend("x-side" = "agent", "x-method" = INITIALIZE_METHOD_NAME)))]
37#[serde(rename_all = "camelCase")]
38#[non_exhaustive]
39pub struct InitializeRequest {
40    /// The latest protocol version supported by the client.
41    pub protocol_version: ProtocolVersion,
42    /// Capabilities supported by the client.
43    #[serde_as(deserialize_as = "DefaultOnError")]
44    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
45    #[serde(default)]
46    pub client_capabilities: ClientCapabilities,
47    /// Information about the Client name and version sent to the Agent.
48    ///
49    /// Note: in future versions of the protocol, this will be required.
50    #[serde_as(deserialize_as = "DefaultOnError")]
51    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
52    #[serde(default)]
53    pub client_info: Option<Implementation>,
54    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
55    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
56    /// these keys.
57    ///
58    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v1/extensibility)
59    #[serde_as(deserialize_as = "DefaultOnError")]
60    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
61    #[serde(default)]
62    #[serde(rename = "_meta")]
63    pub meta: Option<Meta>,
64}
65
66impl InitializeRequest {
67    /// Builds [`InitializeRequest`] with the required request fields set. Optional fields start unset or empty.
68    #[must_use]
69    pub fn new(protocol_version: ProtocolVersion) -> Self {
70        Self {
71            protocol_version,
72            client_capabilities: ClientCapabilities::default(),
73            client_info: None,
74            meta: None,
75        }
76    }
77
78    /// Capabilities supported by the client.
79    #[must_use]
80    pub fn client_capabilities(mut self, client_capabilities: ClientCapabilities) -> Self {
81        self.client_capabilities = client_capabilities;
82        self
83    }
84
85    /// Information about the Client name and version sent to the Agent.
86    #[must_use]
87    pub fn client_info(mut self, client_info: impl IntoOption<Implementation>) -> Self {
88        self.client_info = client_info.into_option();
89        self
90    }
91
92    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
93    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
94    /// these keys.
95    ///
96    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v1/extensibility)
97    #[must_use]
98    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
99        self.meta = meta.into_option();
100        self
101    }
102}
103
104/// Response to the `initialize` method.
105///
106/// Contains the negotiated protocol version and agent capabilities.
107///
108/// See protocol docs: [Initialization](https://agentclientprotocol.com/protocol/v1/initialization)
109#[serde_as]
110#[skip_serializing_none]
111#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
112#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
113#[cfg_attr(feature = "schemars", schemars(extend("x-side" = "agent", "x-method" = INITIALIZE_METHOD_NAME)))]
114#[serde(rename_all = "camelCase")]
115#[non_exhaustive]
116pub struct InitializeResponse {
117    /// The protocol version the client specified if supported by the agent,
118    /// or the latest protocol version supported by the agent.
119    ///
120    /// The client should disconnect, if it doesn't support this version.
121    pub protocol_version: ProtocolVersion,
122    /// Capabilities supported by the agent.
123    #[serde_as(deserialize_as = "DefaultOnError")]
124    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
125    #[serde(default)]
126    pub agent_capabilities: AgentCapabilities,
127    /// Authentication methods supported by the agent.
128    #[serde_as(deserialize_as = "DefaultOnError<VecSkipError<_>>")]
129    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true, "x-deserialize-skip-invalid-items" = true)))]
130    #[serde(default)]
131    pub auth_methods: Vec<AuthMethod>,
132    /// Information about the Agent name and version sent to the Client.
133    ///
134    /// Note: in future versions of the protocol, this will be required.
135    #[serde_as(deserialize_as = "DefaultOnError")]
136    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
137    #[serde(default)]
138    pub agent_info: Option<Implementation>,
139    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
140    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
141    /// these keys.
142    ///
143    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v1/extensibility)
144    #[serde_as(deserialize_as = "DefaultOnError")]
145    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
146    #[serde(default)]
147    #[serde(rename = "_meta")]
148    pub meta: Option<Meta>,
149}
150
151impl InitializeResponse {
152    /// Builds [`InitializeResponse`] with the required response fields set. Optional fields start unset or empty.
153    #[must_use]
154    pub fn new(protocol_version: ProtocolVersion) -> Self {
155        Self {
156            protocol_version,
157            agent_capabilities: AgentCapabilities::default(),
158            auth_methods: vec![],
159            agent_info: None,
160            meta: None,
161        }
162    }
163
164    /// Capabilities supported by the agent.
165    #[must_use]
166    pub fn agent_capabilities(mut self, agent_capabilities: AgentCapabilities) -> Self {
167        self.agent_capabilities = agent_capabilities;
168        self
169    }
170
171    /// Authentication methods supported by the agent.
172    #[must_use]
173    pub fn auth_methods(mut self, auth_methods: Vec<AuthMethod>) -> Self {
174        self.auth_methods = auth_methods;
175        self
176    }
177
178    /// Information about the Agent name and version sent to the Client.
179    #[must_use]
180    pub fn agent_info(mut self, agent_info: impl IntoOption<Implementation>) -> Self {
181        self.agent_info = agent_info.into_option();
182        self
183    }
184
185    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
186    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
187    /// these keys.
188    ///
189    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v1/extensibility)
190    #[must_use]
191    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
192        self.meta = meta.into_option();
193        self
194    }
195}
196
197/// Metadata about the implementation of the client or agent.
198/// Describes the name and version of an ACP implementation, with an optional
199/// title for UI representation.
200#[serde_as]
201#[skip_serializing_none]
202#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
203#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
204#[serde(rename_all = "camelCase")]
205#[non_exhaustive]
206pub struct Implementation {
207    /// Intended for programmatic or logical use, but can be used as a display
208    /// name fallback if title isn't present.
209    pub name: String,
210    /// Intended for UI and end-user contexts and optimized to be human-readable
211    /// and easily understood.
212    ///
213    /// If not provided, the name should be used for display.
214    #[serde_as(deserialize_as = "DefaultOnError")]
215    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
216    #[serde(default)]
217    pub title: Option<String>,
218    /// Version of the implementation. Can be displayed to the user or used
219    /// for debugging or metrics purposes. (e.g. "1.0.0").
220    pub version: String,
221    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
222    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
223    /// these keys.
224    ///
225    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v1/extensibility)
226    #[serde_as(deserialize_as = "DefaultOnError")]
227    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
228    #[serde(default)]
229    #[serde(rename = "_meta")]
230    pub meta: Option<Meta>,
231}
232
233impl Implementation {
234    /// Builds [`Implementation`] with the required fields set. Optional fields start unset or empty.
235    #[must_use]
236    pub fn new(name: impl Into<String>, version: impl Into<String>) -> Self {
237        Self {
238            name: name.into(),
239            title: None,
240            version: version.into(),
241            meta: None,
242        }
243    }
244
245    /// Intended for UI and end-user contexts and optimized to be human-readable
246    /// and easily understood.
247    ///
248    /// If not provided, the name should be used for display.
249    #[must_use]
250    pub fn title(mut self, title: impl IntoOption<String>) -> Self {
251        self.title = title.into_option();
252        self
253    }
254
255    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
256    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
257    /// these keys.
258    ///
259    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v1/extensibility)
260    #[must_use]
261    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
262        self.meta = meta.into_option();
263        self
264    }
265}
266
267// Authentication
268
269/// Request parameters for the authenticate method.
270///
271/// Specifies which authentication method to use.
272#[serde_as]
273#[skip_serializing_none]
274#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
275#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
276#[cfg_attr(feature = "schemars", schemars(extend("x-side" = "agent", "x-method" = AUTHENTICATE_METHOD_NAME)))]
277#[serde(rename_all = "camelCase")]
278#[non_exhaustive]
279pub struct AuthenticateRequest {
280    /// The ID of the authentication method to use.
281    /// Must be one of the methods advertised in the initialize response.
282    pub method_id: AuthMethodId,
283    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
284    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
285    /// these keys.
286    ///
287    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v1/extensibility)
288    #[serde_as(deserialize_as = "DefaultOnError")]
289    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
290    #[serde(default)]
291    #[serde(rename = "_meta")]
292    pub meta: Option<Meta>,
293}
294
295impl AuthenticateRequest {
296    /// Builds [`AuthenticateRequest`] with the required request fields set. Optional fields start unset or empty.
297    #[must_use]
298    pub fn new(method_id: impl Into<AuthMethodId>) -> Self {
299        Self {
300            method_id: method_id.into(),
301            meta: None,
302        }
303    }
304
305    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
306    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
307    /// these keys.
308    ///
309    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v1/extensibility)
310    #[must_use]
311    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
312        self.meta = meta.into_option();
313        self
314    }
315}
316
317crate::serde_util::default_on_null! {
318    /// Response to the `authenticate` method.
319    #[serde_as]
320    #[skip_serializing_none]
321    #[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
322    #[derive(Default, Debug, Clone, Serialize, PartialEq, Eq)]
323    #[cfg_attr(feature = "schemars", schemars(extend("x-side" = "agent", "x-method" = AUTHENTICATE_METHOD_NAME)))]
324    #[serde(rename_all = "camelCase")]
325    #[non_exhaustive]
326    pub struct AuthenticateResponse {
327        /// The _meta property is reserved by ACP to allow clients and agents to attach additional
328        /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
329        /// these keys.
330        ///
331        /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v1/extensibility)
332        #[serde_as(deserialize_as = "DefaultOnError")]
333        #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
334        #[serde(default)]
335        #[serde(rename = "_meta")]
336        pub meta: Option<Meta>,
337    }
338}
339
340impl AuthenticateResponse {
341    /// Builds [`AuthenticateResponse`] with the required response fields set. Optional fields start unset or empty.
342    #[must_use]
343    pub fn new() -> Self {
344        Self::default()
345    }
346
347    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
348    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
349    /// these keys.
350    ///
351    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v1/extensibility)
352    #[must_use]
353    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
354        self.meta = meta.into_option();
355        self
356    }
357}
358
359// Logout
360
361crate::serde_util::default_on_null! {
362    /// Request parameters for the logout method.
363    ///
364    /// Terminates the current authenticated session.
365    #[serde_as]
366    #[skip_serializing_none]
367    #[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
368    #[derive(Default, Debug, Clone, Serialize, PartialEq, Eq)]
369    #[cfg_attr(feature = "schemars", schemars(extend("x-side" = "agent", "x-method" = LOGOUT_METHOD_NAME)))]
370    #[serde(rename_all = "camelCase")]
371    #[non_exhaustive]
372    pub struct LogoutRequest {
373        /// The _meta property is reserved by ACP to allow clients and agents to attach additional
374        /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
375        /// these keys.
376        ///
377        /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v1/extensibility)
378        #[serde_as(deserialize_as = "DefaultOnError")]
379        #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
380        #[serde(default)]
381        #[serde(rename = "_meta")]
382        pub meta: Option<Meta>,
383    }
384}
385
386impl LogoutRequest {
387    /// Builds [`LogoutRequest`] with the required request fields set. Optional fields start unset or empty.
388    #[must_use]
389    pub fn new() -> Self {
390        Self::default()
391    }
392
393    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
394    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
395    /// these keys.
396    ///
397    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v1/extensibility)
398    #[must_use]
399    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
400        self.meta = meta.into_option();
401        self
402    }
403}
404
405crate::serde_util::default_on_null! {
406    /// Response to the `logout` method.
407    #[serde_as]
408    #[skip_serializing_none]
409    #[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
410    #[derive(Default, Debug, Clone, Serialize, PartialEq, Eq)]
411    #[cfg_attr(feature = "schemars", schemars(extend("x-side" = "agent", "x-method" = LOGOUT_METHOD_NAME)))]
412    #[serde(rename_all = "camelCase")]
413    #[non_exhaustive]
414    pub struct LogoutResponse {
415        /// The _meta property is reserved by ACP to allow clients and agents to attach additional
416        /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
417        /// these keys.
418        ///
419        /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v1/extensibility)
420        #[serde_as(deserialize_as = "DefaultOnError")]
421        #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
422        #[serde(default)]
423        #[serde(rename = "_meta")]
424        pub meta: Option<Meta>,
425    }
426}
427
428impl LogoutResponse {
429    /// Builds [`LogoutResponse`] with the required response fields set. Optional fields start unset or empty.
430    #[must_use]
431    pub fn new() -> Self {
432        Self::default()
433    }
434
435    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
436    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
437    /// these keys.
438    ///
439    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v1/extensibility)
440    #[must_use]
441    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
442        self.meta = meta.into_option();
443        self
444    }
445}
446
447// Auth status
448
449#[cfg(feature = "unstable_auth_status")]
450crate::serde_util::default_on_null! {
451    /// **UNSTABLE**
452    ///
453    /// This capability is not part of the spec yet, and may be removed or changed at any point.
454    ///
455    /// Request parameters for the `auth/status` method.
456    ///
457    /// Queries the agent's current authentication state without changing it.
458    ///
459    /// Agents MUST NOT reject it with `auth_required` (`-32000`), since Clients call it to learn
460    /// whether authentication is required.
461    #[serde_as]
462    #[skip_serializing_none]
463    #[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
464    #[derive(Default, Debug, Clone, Serialize, PartialEq, Eq)]
465    #[cfg_attr(feature = "schemars", schemars(extend("x-side" = "agent", "x-method" = AUTH_STATUS_METHOD_NAME)))]
466    #[serde(rename_all = "camelCase")]
467    #[non_exhaustive]
468    pub struct AuthStatusRequest {
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/v1/extensibility)
474        #[serde_as(deserialize_as = "DefaultOnError")]
475        #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
476        #[serde(default)]
477        #[serde(rename = "_meta")]
478        pub meta: Option<Meta>,
479    }
480}
481
482#[cfg(feature = "unstable_auth_status")]
483impl AuthStatusRequest {
484    /// Builds [`AuthStatusRequest`] with the required request fields set. Optional fields start unset or empty.
485    #[must_use]
486    pub fn new() -> Self {
487        Self::default()
488    }
489
490    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
491    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
492    /// these keys.
493    ///
494    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v1/extensibility)
495    #[must_use]
496    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
497        self.meta = meta.into_option();
498        self
499    }
500}
501
502/// **UNSTABLE**
503///
504/// This capability is not part of the spec yet, and may be removed or changed at any point.
505///
506/// Response to the `auth/status` method.
507#[cfg(feature = "unstable_auth_status")]
508#[serde_as]
509#[skip_serializing_none]
510#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
511#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
512#[cfg_attr(feature = "schemars", schemars(extend("x-side" = "agent", "x-method" = AUTH_STATUS_METHOD_NAME)))]
513#[serde(rename_all = "camelCase")]
514#[non_exhaustive]
515pub struct AuthStatusResponse {
516    /// Whether the agent can start sessions without the user signing in first.
517    ///
518    /// This is the only field clients should act on. Clients MUST treat values they
519    /// do not recognize as `unknown`.
520    pub state: AuthState,
521    /// The accounts the agent has configured, for display.
522    ///
523    /// Optional. Omitted and empty are equivalent and mean no accounts are reported.
524    /// Agents that hold credentials for several providers or accounts SHOULD list each
525    /// of them and mark the ones in effect with `active`.
526    #[serde_as(deserialize_as = "DefaultOnError<VecSkipError<_>>")]
527    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true, "x-deserialize-skip-invalid-items" = true)))]
528    #[serde(default, skip_serializing_if = "Vec::is_empty")]
529    pub accounts: Vec<AuthAccount>,
530    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
531    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
532    /// these keys.
533    ///
534    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v1/extensibility)
535    #[serde_as(deserialize_as = "DefaultOnError")]
536    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
537    #[serde(default)]
538    #[serde(rename = "_meta")]
539    pub meta: Option<Meta>,
540}
541
542#[cfg(feature = "unstable_auth_status")]
543impl AuthStatusResponse {
544    /// Builds [`AuthStatusResponse`] with the required fields set. Optional fields start unset or empty.
545    #[must_use]
546    pub fn new(state: AuthState) -> Self {
547        Self {
548            state,
549            accounts: vec![],
550            meta: None,
551        }
552    }
553
554    /// The accounts the agent has configured, for display.
555    #[must_use]
556    pub fn accounts(mut self, accounts: Vec<AuthAccount>) -> Self {
557        self.accounts = accounts;
558        self
559    }
560
561    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
562    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
563    /// these keys.
564    ///
565    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v1/extensibility)
566    #[must_use]
567    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
568        self.meta = meta.into_option();
569        self
570    }
571}
572
573/// **UNSTABLE**
574///
575/// This capability is not part of the spec yet, and may be removed or changed at any point.
576///
577/// Notification sent by the agent when its authentication status changes.
578///
579/// Carries the same fields as the `auth/status` response. Agents that advertise the
580/// `auth.status` capability MAY send it at any time after `initialize`, and SHOULD only
581/// send it when the reported status differs from the last one sent on the connection.
582#[cfg(feature = "unstable_auth_status")]
583#[serde_as]
584#[skip_serializing_none]
585#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
586#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
587#[cfg_attr(feature = "schemars", schemars(extend("x-side" = "client", "x-method" = AUTH_STATUS_UPDATE_NOTIFICATION)))]
588#[serde(rename_all = "camelCase")]
589#[non_exhaustive]
590pub struct AuthStatusUpdateNotification {
591    /// Whether the agent can start sessions without the user signing in first.
592    ///
593    /// This is the only field clients should act on. Clients MUST treat values they
594    /// do not recognize as `unknown`.
595    pub state: AuthState,
596    /// The accounts the agent has configured, for display.
597    ///
598    /// Optional. Omitted and empty are equivalent and mean no accounts are reported.
599    /// Agents that hold credentials for several providers or accounts SHOULD list each
600    /// of them and mark the ones in effect with `active`.
601    #[serde_as(deserialize_as = "DefaultOnError<VecSkipError<_>>")]
602    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true, "x-deserialize-skip-invalid-items" = true)))]
603    #[serde(default, skip_serializing_if = "Vec::is_empty")]
604    pub accounts: Vec<AuthAccount>,
605    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
606    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
607    /// these keys.
608    ///
609    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v1/extensibility)
610    #[serde_as(deserialize_as = "DefaultOnError")]
611    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
612    #[serde(default)]
613    #[serde(rename = "_meta")]
614    pub meta: Option<Meta>,
615}
616
617#[cfg(feature = "unstable_auth_status")]
618impl AuthStatusUpdateNotification {
619    /// Builds [`AuthStatusUpdateNotification`] with the required fields set. Optional fields start unset or empty.
620    #[must_use]
621    pub fn new(state: AuthState) -> Self {
622        Self {
623            state,
624            accounts: vec![],
625            meta: None,
626        }
627    }
628
629    /// The accounts the agent has configured, for display.
630    #[must_use]
631    pub fn accounts(mut self, accounts: Vec<AuthAccount>) -> Self {
632        self.accounts = accounts;
633        self
634    }
635
636    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
637    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
638    /// these keys.
639    ///
640    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v1/extensibility)
641    #[must_use]
642    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
643        self.meta = meta.into_option();
644        self
645    }
646}
647
648/// **UNSTABLE**
649///
650/// This capability is not part of the spec yet, and may be removed or changed at any point.
651///
652/// The agent's overall authentication state.
653#[cfg(feature = "unstable_auth_status")]
654#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
655#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
656#[serde(rename_all = "snake_case")]
657#[non_exhaustive]
658pub enum AuthState {
659    /// Credentials are configured. This does not guarantee that they are valid.
660    Authenticated,
661    /// The user needs to sign in. This includes credentials that are missing,
662    /// expired, or known to be invalid.
663    Unauthenticated,
664    /// No authentication is needed, for example because the agent uses a local model.
665    NotRequired,
666    /// The agent cannot currently determine the state.
667    Unknown,
668    /// Custom or future authentication state.
669    ///
670    /// Values beginning with `_` are reserved for implementation-specific
671    /// extensions. Unknown values that do not begin with `_` are reserved for
672    /// future ACP variants.
673    #[serde(untagged)]
674    Other(String),
675}
676
677/// **UNSTABLE**
678///
679/// This capability is not part of the spec yet, and may be removed or changed at any point.
680///
681/// An account or credential the agent has configured, such as a signed-in user
682/// account or an API key.
683///
684/// All fields are display information only. Clients MUST NOT use them as stable
685/// account identifiers, and SHOULD NOT log them or send them elsewhere, such as to
686/// telemetry.
687#[cfg(feature = "unstable_auth_status")]
688#[serde_as]
689#[skip_serializing_none]
690#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
691#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
692#[serde(rename_all = "camelCase")]
693#[non_exhaustive]
694pub struct AuthAccount {
695    /// Human-readable name for the account, suitable for display on its own,
696    /// for example `Claude Max`, `OpenAI API key`, or `Vertex AI`.
697    pub label: String,
698    /// Whether the agent currently uses this account by default.
699    ///
700    /// Several accounts MAY be active, for example one per provider.
701    ///
702    /// Optional. Omitted and `null` are equivalent and mean the agent does not indicate whether this account is in effect.
703    #[serde_as(deserialize_as = "DefaultOnError")]
704    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
705    #[serde(default)]
706    pub active: Option<bool>,
707    /// Display name of the user, such as a username or full name.
708    ///
709    /// Optional. Omitted and `null` are equivalent and mean no name is reported.
710    #[serde_as(deserialize_as = "DefaultOnError")]
711    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
712    #[serde(default)]
713    pub name: Option<String>,
714    /// Email address of the user.
715    ///
716    /// Optional. Omitted and `null` are equivalent and mean no email is reported.
717    #[serde_as(deserialize_as = "DefaultOnError")]
718    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
719    #[serde(default)]
720    pub email: Option<String>,
721    /// Display name of the organization, team, or workspace the account is using.
722    ///
723    /// Optional. Omitted and `null` are equivalent and mean no organization is reported.
724    #[serde_as(deserialize_as = "DefaultOnError")]
725    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
726    #[serde(default)]
727    pub organization: Option<String>,
728    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
729    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
730    /// these keys.
731    ///
732    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v1/extensibility)
733    #[serde_as(deserialize_as = "DefaultOnError")]
734    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
735    #[serde(default)]
736    #[serde(rename = "_meta")]
737    pub meta: Option<Meta>,
738}
739
740#[cfg(feature = "unstable_auth_status")]
741impl AuthAccount {
742    /// Builds [`AuthAccount`] with the required fields set. Optional fields start unset or empty.
743    #[must_use]
744    pub fn new(label: impl Into<String>) -> Self {
745        Self {
746            label: label.into(),
747            active: None,
748            name: None,
749            email: None,
750            organization: None,
751            meta: None,
752        }
753    }
754
755    /// Whether the agent currently uses this account by default.
756    #[must_use]
757    pub fn active(mut self, active: impl IntoOption<bool>) -> Self {
758        self.active = active.into_option();
759        self
760    }
761
762    /// Display name of the user, such as a username or full name.
763    #[must_use]
764    pub fn name(mut self, name: impl IntoOption<String>) -> Self {
765        self.name = name.into_option();
766        self
767    }
768
769    /// Email address of the user.
770    #[must_use]
771    pub fn email(mut self, email: impl IntoOption<String>) -> Self {
772        self.email = email.into_option();
773        self
774    }
775
776    /// Display name of the organization, team, or workspace the account is using.
777    #[must_use]
778    pub fn organization(mut self, organization: impl IntoOption<String>) -> Self {
779        self.organization = organization.into_option();
780        self
781    }
782
783    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
784    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
785    /// these keys.
786    ///
787    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v1/extensibility)
788    #[must_use]
789    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
790        self.meta = meta.into_option();
791        self
792    }
793}
794
795/// **UNSTABLE**
796///
797/// This capability is not part of the spec yet, and may be removed or changed at any point.
798///
799/// Auth status capabilities supported by the agent.
800///
801/// Supplying `{}` means the agent supports the `auth/status` method.
802#[cfg(feature = "unstable_auth_status")]
803#[serde_as]
804#[skip_serializing_none]
805#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
806#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
807#[non_exhaustive]
808pub struct AuthStatusCapabilities {
809    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
810    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
811    /// these keys.
812    ///
813    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v1/extensibility)
814    #[serde_as(deserialize_as = "DefaultOnError")]
815    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
816    #[serde(default)]
817    #[serde(rename = "_meta")]
818    pub meta: Option<Meta>,
819}
820
821#[cfg(feature = "unstable_auth_status")]
822impl AuthStatusCapabilities {
823    /// Builds an empty [`AuthStatusCapabilities`]. Use builder methods to advertise supported sub-capabilities.
824    #[must_use]
825    pub fn new() -> Self {
826        Self::default()
827    }
828
829    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
830    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
831    /// these keys.
832    ///
833    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v1/extensibility)
834    #[must_use]
835    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
836        self.meta = meta.into_option();
837        self
838    }
839}
840
841/// Authentication-related capabilities supported by the agent.
842#[serde_as]
843#[skip_serializing_none]
844#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
845#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
846#[serde(rename_all = "camelCase")]
847#[non_exhaustive]
848pub struct AgentAuthCapabilities {
849    /// **UNSTABLE**
850    ///
851    /// This capability is not part of the spec yet, and may be removed or changed at any point.
852    ///
853    /// Whether the agent supports the `auth/status` method.
854    ///
855    /// Optional. Omitted or `null` both mean the agent does not advertise support.
856    /// Supplying `{}` means the agent supports the `auth/status` method.
857    #[cfg(feature = "unstable_auth_status")]
858    #[serde_as(deserialize_as = "DefaultOnError")]
859    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
860    #[serde(default)]
861    pub status: Option<AuthStatusCapabilities>,
862    /// Whether the agent supports the logout method.
863    ///
864    /// Optional. Omitted or `null` both mean the agent does not advertise support.
865    /// Supplying `{}` means the agent supports the logout method.
866    #[serde_as(deserialize_as = "DefaultOnError")]
867    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
868    #[serde(default)]
869    pub logout: Option<LogoutCapabilities>,
870    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
871    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
872    /// these keys.
873    ///
874    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v1/extensibility)
875    #[serde_as(deserialize_as = "DefaultOnError")]
876    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
877    #[serde(default)]
878    #[serde(rename = "_meta")]
879    pub meta: Option<Meta>,
880}
881
882impl AgentAuthCapabilities {
883    /// Builds an empty [`AgentAuthCapabilities`]. Use builder methods to advertise supported sub-capabilities.
884    #[must_use]
885    pub fn new() -> Self {
886        Self::default()
887    }
888
889    /// **UNSTABLE**
890    ///
891    /// This capability is not part of the spec yet, and may be removed or changed at any point.
892    ///
893    /// Whether the agent supports the `auth/status` method.
894    #[cfg(feature = "unstable_auth_status")]
895    #[must_use]
896    pub fn status(mut self, status: impl IntoOption<AuthStatusCapabilities>) -> Self {
897        self.status = status.into_option();
898        self
899    }
900
901    /// Whether the agent supports the logout method.
902    #[must_use]
903    pub fn logout(mut self, logout: impl IntoOption<LogoutCapabilities>) -> Self {
904        self.logout = logout.into_option();
905        self
906    }
907
908    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
909    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
910    /// these keys.
911    ///
912    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v1/extensibility)
913    #[must_use]
914    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
915        self.meta = meta.into_option();
916        self
917    }
918}
919
920/// Logout capabilities supported by the agent.
921///
922/// Supplying `{}` means the agent supports the logout method.
923#[serde_as]
924#[skip_serializing_none]
925#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
926#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
927#[non_exhaustive]
928pub struct LogoutCapabilities {
929    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
930    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
931    /// these keys.
932    ///
933    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v1/extensibility)
934    #[serde_as(deserialize_as = "DefaultOnError")]
935    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
936    #[serde(default)]
937    #[serde(rename = "_meta")]
938    pub meta: Option<Meta>,
939}
940
941impl LogoutCapabilities {
942    /// Builds an empty [`LogoutCapabilities`]. Use builder methods to advertise supported sub-capabilities.
943    #[must_use]
944    pub fn new() -> Self {
945        Self::default()
946    }
947
948    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
949    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
950    /// these keys.
951    ///
952    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v1/extensibility)
953    #[must_use]
954    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
955        self.meta = meta.into_option();
956        self
957    }
958}
959
960/// Typed identifier used for auth method values on the wire.
961#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
962#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash, Display, From)]
963#[serde(transparent)]
964#[from(Arc<str>, String, &'static str)]
965#[non_exhaustive]
966pub struct AuthMethodId(pub Arc<str>);
967
968impl AuthMethodId {
969    /// Wraps a protocol string as a typed [`AuthMethodId`].
970    #[must_use]
971    pub fn new(id: impl Into<Arc<str>>) -> Self {
972        Self(id.into())
973    }
974}
975
976/// Describes an available authentication method.
977///
978/// The `type` field acts as the discriminator in the serialized JSON form.
979/// When no `type` is present, the method is treated as `agent`.
980#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
981#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
982#[serde(tag = "type", rename_all = "snake_case")]
983#[non_exhaustive]
984pub enum AuthMethod {
985    /// Client runs the configured agent program as a separate interactive
986    /// process, without passing this method to `authenticate`.
987    Terminal(AuthMethodTerminal),
988    /// Agent handles authentication itself through `authenticate`.
989    ///
990    /// This is the default when no `type` is specified.
991    #[serde(untagged, deserialize_with = "deserialize_agent_auth_method_fallback")]
992    Agent(AuthMethodAgent),
993}
994
995/// Deserializes the untagged `agent` fallback of [`AuthMethod`].
996///
997/// A `terminal` method that fails its own schema must not fall through to
998/// `agent`, or the client would pass it to `authenticate`.
999fn deserialize_agent_auth_method_fallback<'de, D>(
1000    deserializer: D,
1001) -> Result<AuthMethodAgent, D::Error>
1002where
1003    D: serde::Deserializer<'de>,
1004{
1005    let value = serde_json::Value::deserialize(deserializer)?;
1006    if value.get("type").and_then(serde_json::Value::as_str) == Some("terminal") {
1007        return Err(serde::de::Error::custom(
1008            "known authentication method `terminal` did not match its schema",
1009        ));
1010    }
1011    AuthMethodAgent::deserialize(value).map_err(serde::de::Error::custom)
1012}
1013
1014impl AuthMethod {
1015    /// The unique identifier for this authentication method.
1016    #[must_use]
1017    pub fn id(&self) -> &AuthMethodId {
1018        match self {
1019            Self::Agent(a) => &a.id,
1020            Self::Terminal(t) => &t.id,
1021        }
1022    }
1023
1024    /// The human-readable name of this authentication method.
1025    #[must_use]
1026    pub fn name(&self) -> &str {
1027        match self {
1028            Self::Agent(a) => &a.name,
1029            Self::Terminal(t) => &t.name,
1030        }
1031    }
1032
1033    /// Optional human-readable description of this authentication method.
1034    #[must_use]
1035    pub fn description(&self) -> Option<&str> {
1036        match self {
1037            Self::Agent(a) => a.description.as_deref(),
1038            Self::Terminal(t) => t.description.as_deref(),
1039        }
1040    }
1041
1042    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1043    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1044    /// these keys.
1045    ///
1046    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v1/extensibility)
1047    #[must_use]
1048    pub fn meta(&self) -> Option<&Meta> {
1049        match self {
1050            Self::Agent(a) => a.meta.as_ref(),
1051            Self::Terminal(t) => t.meta.as_ref(),
1052        }
1053    }
1054}
1055
1056/// Agent handles authentication itself through `authenticate`.
1057///
1058/// This is the default authentication method type.
1059#[serde_as]
1060#[skip_serializing_none]
1061#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1062#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
1063#[serde(rename_all = "camelCase")]
1064#[non_exhaustive]
1065pub struct AuthMethodAgent {
1066    /// Unique identifier for this authentication method.
1067    pub id: AuthMethodId,
1068    /// Human-readable name of the authentication method.
1069    pub name: String,
1070    /// Optional human-readable description of this authentication method.
1071    #[serde_as(deserialize_as = "DefaultOnError")]
1072    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
1073    #[serde(default)]
1074    pub description: Option<String>,
1075    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1076    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1077    /// these keys.
1078    ///
1079    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v1/extensibility)
1080    #[serde_as(deserialize_as = "DefaultOnError")]
1081    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
1082    #[serde(default)]
1083    #[serde(rename = "_meta")]
1084    pub meta: Option<Meta>,
1085}
1086
1087impl AuthMethodAgent {
1088    /// Builds [`AuthMethodAgent`] with the required fields set. Optional fields start unset or empty.
1089    #[must_use]
1090    pub fn new(id: impl Into<AuthMethodId>, name: impl Into<String>) -> Self {
1091        Self {
1092            id: id.into(),
1093            name: name.into(),
1094            description: None,
1095            meta: None,
1096        }
1097    }
1098
1099    /// Optional human-readable description of this authentication method.
1100    #[must_use]
1101    pub fn description(mut self, description: impl IntoOption<String>) -> Self {
1102        self.description = description.into_option();
1103        self
1104    }
1105
1106    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1107    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1108    /// these keys.
1109    ///
1110    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v1/extensibility)
1111    #[must_use]
1112    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1113        self.meta = meta.into_option();
1114        self
1115    }
1116}
1117
1118/// Terminal-based authentication method.
1119///
1120/// The client runs the configured agent program as a separate interactive
1121/// process for the user to authenticate via a TUI. Agents MUST advertise this
1122/// method only when the client enabled its terminal authentication capability.
1123/// A zero exit status signals success. Any other termination signals failure.
1124/// The client MUST NOT pass this method to `authenticate`.
1125#[serde_as]
1126#[skip_serializing_none]
1127#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1128#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
1129#[serde(rename_all = "camelCase")]
1130#[non_exhaustive]
1131pub struct AuthMethodTerminal {
1132    /// Unique identifier for this authentication method.
1133    pub id: AuthMethodId,
1134    /// Human-readable name of the authentication method.
1135    pub name: String,
1136    /// Optional human-readable description of this authentication method.
1137    #[serde_as(deserialize_as = "DefaultOnError")]
1138    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
1139    #[serde(default)]
1140    pub description: Option<String>,
1141    /// Additional arguments to append to the configured agent invocation for terminal auth.
1142    #[serde_as(deserialize_as = "DefaultOnNull")]
1143    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-null" = true)))]
1144    #[serde(default, skip_serializing_if = "Vec::is_empty")]
1145    pub args: Vec<String>,
1146    /// Additional environment variables to set on the configured agent invocation for terminal auth.
1147    /// These values override same-named variables in the base launch configuration.
1148    #[serde_as(deserialize_as = "DefaultOnNull")]
1149    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-null" = true)))]
1150    #[serde(default, skip_serializing_if = "HashMap::is_empty")]
1151    pub env: HashMap<String, String>,
1152    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1153    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1154    /// these keys.
1155    ///
1156    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v1/extensibility)
1157    #[serde_as(deserialize_as = "DefaultOnError")]
1158    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
1159    #[serde(default)]
1160    #[serde(rename = "_meta")]
1161    pub meta: Option<Meta>,
1162}
1163
1164impl AuthMethodTerminal {
1165    /// Builds [`AuthMethodTerminal`] with the required fields set. Optional fields start unset or empty.
1166    #[must_use]
1167    pub fn new(id: impl Into<AuthMethodId>, name: impl Into<String>) -> Self {
1168        Self {
1169            id: id.into(),
1170            name: name.into(),
1171            description: None,
1172            args: Vec::new(),
1173            env: HashMap::new(),
1174            meta: None,
1175        }
1176    }
1177
1178    /// Additional arguments to append to the configured agent invocation for terminal auth.
1179    #[must_use]
1180    pub fn args(mut self, args: Vec<String>) -> Self {
1181        self.args = args;
1182        self
1183    }
1184
1185    /// Additional environment variables to set on the configured agent invocation for terminal auth.
1186    /// These values override same-named variables in the base launch configuration.
1187    #[must_use]
1188    pub fn env(mut self, env: HashMap<String, String>) -> Self {
1189        self.env = env;
1190        self
1191    }
1192
1193    /// Optional human-readable description of this authentication method.
1194    #[must_use]
1195    pub fn description(mut self, description: impl IntoOption<String>) -> Self {
1196        self.description = description.into_option();
1197        self
1198    }
1199
1200    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1201    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1202    /// these keys.
1203    ///
1204    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v1/extensibility)
1205    #[must_use]
1206    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1207        self.meta = meta.into_option();
1208        self
1209    }
1210}
1211
1212// New session
1213
1214/// Request parameters for creating a new session.
1215///
1216/// See protocol docs: [Creating a Session](https://agentclientprotocol.com/protocol/v1/session-setup#creating-a-session)
1217#[serde_as]
1218#[skip_serializing_none]
1219#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1220#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
1221#[cfg_attr(feature = "schemars", schemars(extend("x-side" = "agent", "x-method" = SESSION_NEW_METHOD_NAME)))]
1222#[serde(rename_all = "camelCase")]
1223#[non_exhaustive]
1224pub struct NewSessionRequest {
1225    /// The working directory for this session. Must be an absolute path.
1226    pub cwd: PathBuf,
1227    /// Additional workspace roots for this session. Each path must be absolute.
1228    ///
1229    /// These expand the session's filesystem scope without changing `cwd`, which
1230    /// remains the base for relative paths. When omitted or empty, no
1231    /// additional roots are activated for the new session.
1232    #[serde_as(deserialize_as = "DefaultOnNull")]
1233    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-null" = true)))]
1234    #[serde(default, skip_serializing_if = "Vec::is_empty")]
1235    pub additional_directories: Vec<PathBuf>,
1236    /// List of MCP (Model Context Protocol) servers the agent should connect to.
1237    #[serde_as(deserialize_as = "DefaultOnNull")]
1238    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-null" = true)))]
1239    pub mcp_servers: Vec<McpServer>,
1240    /// System-level instructions for the new session.
1241    ///
1242    /// Optional. Omitted and `null` are equivalent and mean the Agent uses its
1243    /// own default instructions. Clients MUST only send this when the Agent
1244    /// advertises `sessionCapabilities.systemPrompt`.
1245    #[serde(default)]
1246    pub system_prompt: Option<SystemPrompt>,
1247    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1248    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1249    /// these keys.
1250    ///
1251    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v1/extensibility)
1252    #[serde_as(deserialize_as = "DefaultOnError")]
1253    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
1254    #[serde(default)]
1255    #[serde(rename = "_meta")]
1256    pub meta: Option<Meta>,
1257}
1258
1259impl NewSessionRequest {
1260    /// Builds [`NewSessionRequest`] with the required request fields set. Optional fields start unset or empty.
1261    #[must_use]
1262    pub fn new(cwd: impl Into<PathBuf>) -> Self {
1263        Self {
1264            cwd: cwd.into(),
1265            additional_directories: vec![],
1266            mcp_servers: vec![],
1267            system_prompt: None,
1268            meta: None,
1269        }
1270    }
1271
1272    /// Additional workspace roots for this session. Each path must be absolute.
1273    #[must_use]
1274    pub fn additional_directories(mut self, additional_directories: Vec<PathBuf>) -> Self {
1275        self.additional_directories = additional_directories;
1276        self
1277    }
1278
1279    /// List of MCP (Model Context Protocol) servers the agent should connect to.
1280    #[must_use]
1281    pub fn mcp_servers(mut self, mcp_servers: Vec<McpServer>) -> Self {
1282        self.mcp_servers = mcp_servers;
1283        self
1284    }
1285
1286    /// System-level instructions for the new session.
1287    #[must_use]
1288    pub fn system_prompt(mut self, system_prompt: impl IntoOption<SystemPrompt>) -> Self {
1289        self.system_prompt = system_prompt.into_option();
1290        self
1291    }
1292
1293    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1294    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1295    /// these keys.
1296    ///
1297    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v1/extensibility)
1298    #[must_use]
1299    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1300        self.meta = meta.into_option();
1301        self
1302    }
1303}
1304
1305/// Response from creating a new session.
1306///
1307/// See protocol docs: [Creating a Session](https://agentclientprotocol.com/protocol/v1/session-setup#creating-a-session)
1308#[serde_as]
1309#[skip_serializing_none]
1310#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1311#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
1312#[cfg_attr(feature = "schemars", schemars(extend("x-side" = "agent", "x-method" = SESSION_NEW_METHOD_NAME)))]
1313#[serde(rename_all = "camelCase")]
1314#[non_exhaustive]
1315pub struct NewSessionResponse {
1316    /// Unique identifier for the created session.
1317    ///
1318    /// Used in all subsequent requests for this conversation.
1319    pub session_id: SessionId,
1320    /// Initial mode state if supported by the Agent
1321    ///
1322    /// See protocol docs: [Session Modes](https://agentclientprotocol.com/protocol/v1/session-modes)
1323    #[serde_as(deserialize_as = "DefaultOnError")]
1324    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
1325    #[serde(default)]
1326    pub modes: Option<SessionModeState>,
1327    /// Initial session configuration options if supported by the Agent.
1328    #[serde_as(deserialize_as = "DefaultOnError<Option<VecSkipError<_>>>")]
1329    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true, "x-deserialize-skip-invalid-items" = true)))]
1330    #[serde(default)]
1331    pub config_options: Option<Vec<SessionConfigOption>>,
1332    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1333    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1334    /// these keys.
1335    ///
1336    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v1/extensibility)
1337    #[serde_as(deserialize_as = "DefaultOnError")]
1338    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
1339    #[serde(default)]
1340    #[serde(rename = "_meta")]
1341    pub meta: Option<Meta>,
1342}
1343
1344impl NewSessionResponse {
1345    /// Builds [`NewSessionResponse`] with the required response fields set. Optional fields start unset or empty.
1346    #[must_use]
1347    pub fn new(session_id: impl Into<SessionId>) -> Self {
1348        Self {
1349            session_id: session_id.into(),
1350            modes: None,
1351            config_options: None,
1352            meta: None,
1353        }
1354    }
1355
1356    /// Initial mode state if supported by the Agent
1357    ///
1358    /// See protocol docs: [Session Modes](https://agentclientprotocol.com/protocol/v1/session-modes)
1359    #[must_use]
1360    pub fn modes(mut self, modes: impl IntoOption<SessionModeState>) -> Self {
1361        self.modes = modes.into_option();
1362        self
1363    }
1364
1365    /// Initial session configuration options if supported by the Agent.
1366    #[must_use]
1367    pub fn config_options(
1368        mut self,
1369        config_options: impl IntoOption<Vec<SessionConfigOption>>,
1370    ) -> Self {
1371        self.config_options = config_options.into_option();
1372        self
1373    }
1374
1375    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1376    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1377    /// these keys.
1378    ///
1379    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v1/extensibility)
1380    #[must_use]
1381    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1382        self.meta = meta.into_option();
1383        self
1384    }
1385}
1386
1387// Load session
1388
1389/// Request parameters for loading an existing session.
1390///
1391/// Only available if the Agent supports the `loadSession` capability.
1392///
1393/// See protocol docs: [Loading Sessions](https://agentclientprotocol.com/protocol/v1/session-setup#loading-sessions)
1394#[serde_as]
1395#[skip_serializing_none]
1396#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1397#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
1398#[cfg_attr(feature = "schemars", schemars(extend("x-side" = "agent", "x-method" = SESSION_LOAD_METHOD_NAME)))]
1399#[serde(rename_all = "camelCase")]
1400#[non_exhaustive]
1401pub struct LoadSessionRequest {
1402    /// List of MCP servers to connect to for this session.
1403    #[serde_as(deserialize_as = "DefaultOnNull")]
1404    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-null" = true)))]
1405    pub mcp_servers: Vec<McpServer>,
1406    /// The working directory for this session. Must be an absolute path.
1407    pub cwd: PathBuf,
1408    /// Additional workspace roots to activate for this session. Each path must be absolute.
1409    ///
1410    /// When omitted or empty, no additional roots are activated. When non-empty,
1411    /// this is the complete resulting additional-root list for the loaded
1412    /// session. It may differ from any previously used or reported list as long as
1413    /// the request `cwd` matches the session's `cwd`.
1414    #[serde_as(deserialize_as = "DefaultOnNull")]
1415    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-null" = true)))]
1416    #[serde(default, skip_serializing_if = "Vec::is_empty")]
1417    pub additional_directories: Vec<PathBuf>,
1418    /// The ID of the session to load.
1419    pub session_id: SessionId,
1420    /// System-level instructions for the loaded session.
1421    ///
1422    /// Optional. Omitted and `null` are equivalent. The Agent may then keep a
1423    /// system prompt it stored with the session or use its default instructions.
1424    /// Clients MUST only send this when the Agent advertises
1425    /// `sessionCapabilities.systemPrompt`, and SHOULD send the same value they used
1426    /// when the session was created.
1427    #[serde(default)]
1428    pub system_prompt: Option<SystemPrompt>,
1429    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1430    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1431    /// these keys.
1432    ///
1433    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v1/extensibility)
1434    #[serde_as(deserialize_as = "DefaultOnError")]
1435    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
1436    #[serde(default)]
1437    #[serde(rename = "_meta")]
1438    pub meta: Option<Meta>,
1439}
1440
1441impl LoadSessionRequest {
1442    /// Builds [`LoadSessionRequest`] with the required request fields set. Optional fields start unset or empty.
1443    #[must_use]
1444    pub fn new(session_id: impl Into<SessionId>, cwd: impl Into<PathBuf>) -> Self {
1445        Self {
1446            mcp_servers: vec![],
1447            cwd: cwd.into(),
1448            additional_directories: vec![],
1449            session_id: session_id.into(),
1450            system_prompt: None,
1451            meta: None,
1452        }
1453    }
1454
1455    /// Additional workspace roots to activate for this session. Each path must be absolute.
1456    #[must_use]
1457    pub fn additional_directories(mut self, additional_directories: Vec<PathBuf>) -> Self {
1458        self.additional_directories = additional_directories;
1459        self
1460    }
1461
1462    /// List of MCP servers to connect to for this session.
1463    #[must_use]
1464    pub fn mcp_servers(mut self, mcp_servers: Vec<McpServer>) -> Self {
1465        self.mcp_servers = mcp_servers;
1466        self
1467    }
1468
1469    /// System-level instructions for the loaded session.
1470    #[must_use]
1471    pub fn system_prompt(mut self, system_prompt: impl IntoOption<SystemPrompt>) -> Self {
1472        self.system_prompt = system_prompt.into_option();
1473        self
1474    }
1475
1476    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1477    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1478    /// these keys.
1479    ///
1480    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v1/extensibility)
1481    #[must_use]
1482    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1483        self.meta = meta.into_option();
1484        self
1485    }
1486}
1487
1488crate::serde_util::default_on_null! {
1489    /// Response from loading an existing session.
1490    #[serde_as]
1491    #[skip_serializing_none]
1492    #[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1493    #[derive(Default, Debug, Clone, Serialize, PartialEq, Eq)]
1494    #[cfg_attr(feature = "schemars", schemars(extend("x-side" = "agent", "x-method" = SESSION_LOAD_METHOD_NAME)))]
1495    #[serde(rename_all = "camelCase")]
1496    #[non_exhaustive]
1497    pub struct LoadSessionResponse {
1498        /// Initial mode state if supported by the Agent
1499        ///
1500        /// See protocol docs: [Session Modes](https://agentclientprotocol.com/protocol/v1/session-modes)
1501        #[serde_as(deserialize_as = "DefaultOnError")]
1502        #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
1503        #[serde(default)]
1504        pub modes: Option<SessionModeState>,
1505        /// Initial session configuration options if supported by the Agent.
1506        #[serde_as(deserialize_as = "DefaultOnError<Option<VecSkipError<_>>>")]
1507        #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true, "x-deserialize-skip-invalid-items" = true)))]
1508        #[serde(default)]
1509        pub config_options: Option<Vec<SessionConfigOption>>,
1510        /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1511        /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1512        /// these keys.
1513        ///
1514        /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v1/extensibility)
1515        #[serde_as(deserialize_as = "DefaultOnError")]
1516        #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
1517        #[serde(default)]
1518        #[serde(rename = "_meta")]
1519        pub meta: Option<Meta>,
1520    }
1521}
1522
1523impl LoadSessionResponse {
1524    /// Builds [`LoadSessionResponse`] with the required response fields set. Optional fields start unset or empty.
1525    #[must_use]
1526    pub fn new() -> Self {
1527        Self::default()
1528    }
1529
1530    /// Initial mode state if supported by the Agent
1531    ///
1532    /// See protocol docs: [Session Modes](https://agentclientprotocol.com/protocol/v1/session-modes)
1533    #[must_use]
1534    pub fn modes(mut self, modes: impl IntoOption<SessionModeState>) -> Self {
1535        self.modes = modes.into_option();
1536        self
1537    }
1538
1539    /// Initial session configuration options if supported by the Agent.
1540    #[must_use]
1541    pub fn config_options(
1542        mut self,
1543        config_options: impl IntoOption<Vec<SessionConfigOption>>,
1544    ) -> Self {
1545        self.config_options = config_options.into_option();
1546        self
1547    }
1548
1549    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1550    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1551    /// these keys.
1552    ///
1553    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v1/extensibility)
1554    #[must_use]
1555    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1556        self.meta = meta.into_option();
1557        self
1558    }
1559}
1560
1561// Fork session
1562
1563/// **UNSTABLE**
1564///
1565/// This capability is not part of the spec yet, and may be removed or changed at any point.
1566///
1567/// Request parameters for forking an existing session.
1568///
1569/// Creates a new session based on the context of an existing one, allowing
1570/// operations like generating summaries without affecting the original session's history.
1571///
1572/// Only available if the Agent supports the `session.fork` capability.
1573#[cfg(feature = "unstable_session_fork")]
1574#[serde_as]
1575#[skip_serializing_none]
1576#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1577#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
1578#[cfg_attr(feature = "schemars", schemars(extend("x-side" = "agent", "x-method" = SESSION_FORK_METHOD_NAME)))]
1579#[serde(rename_all = "camelCase")]
1580#[non_exhaustive]
1581pub struct ForkSessionRequest {
1582    /// The ID of the session to fork.
1583    pub session_id: SessionId,
1584    /// The working directory for this session. Must be an absolute path.
1585    pub cwd: PathBuf,
1586    /// Additional workspace roots to activate for this session. Each path must be absolute.
1587    ///
1588    /// When omitted or empty, no additional roots are activated. When non-empty,
1589    /// this is the complete resulting additional-root list for the forked
1590    /// session.
1591    #[serde_as(deserialize_as = "DefaultOnNull")]
1592    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-null" = true)))]
1593    #[serde(default, skip_serializing_if = "Vec::is_empty")]
1594    pub additional_directories: Vec<PathBuf>,
1595    /// List of MCP servers to connect to for this session.
1596    #[serde_as(deserialize_as = "DefaultOnNull")]
1597    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-null" = true)))]
1598    #[serde(default, skip_serializing_if = "Vec::is_empty")]
1599    pub mcp_servers: Vec<McpServer>,
1600    /// System-level instructions for the forked session.
1601    ///
1602    /// Optional. Omitted and `null` are equivalent. The Agent may then keep a
1603    /// system prompt it stored with the source session or use its default
1604    /// instructions. Clients MUST only send this when the Agent advertises
1605    /// `sessionCapabilities.systemPrompt`, and SHOULD send the same value they used
1606    /// for the source session.
1607    #[serde(default)]
1608    pub system_prompt: Option<SystemPrompt>,
1609    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1610    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1611    /// these keys.
1612    ///
1613    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v1/extensibility)
1614    #[serde_as(deserialize_as = "DefaultOnError")]
1615    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
1616    #[serde(default)]
1617    #[serde(rename = "_meta")]
1618    pub meta: Option<Meta>,
1619}
1620
1621#[cfg(feature = "unstable_session_fork")]
1622impl ForkSessionRequest {
1623    /// Builds [`ForkSessionRequest`] with the required request fields set. Optional fields start unset or empty.
1624    #[must_use]
1625    pub fn new(session_id: impl Into<SessionId>, cwd: impl Into<PathBuf>) -> Self {
1626        Self {
1627            session_id: session_id.into(),
1628            cwd: cwd.into(),
1629            additional_directories: vec![],
1630            mcp_servers: vec![],
1631            system_prompt: None,
1632            meta: None,
1633        }
1634    }
1635
1636    /// Additional workspace roots to activate for this session. Each path must be absolute.
1637    #[must_use]
1638    pub fn additional_directories(mut self, additional_directories: Vec<PathBuf>) -> Self {
1639        self.additional_directories = additional_directories;
1640        self
1641    }
1642
1643    /// List of MCP servers to connect to for this session.
1644    #[must_use]
1645    pub fn mcp_servers(mut self, mcp_servers: Vec<McpServer>) -> Self {
1646        self.mcp_servers = mcp_servers;
1647        self
1648    }
1649
1650    /// System-level instructions for the forked session.
1651    #[must_use]
1652    pub fn system_prompt(mut self, system_prompt: impl IntoOption<SystemPrompt>) -> Self {
1653        self.system_prompt = system_prompt.into_option();
1654        self
1655    }
1656
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/v1/extensibility)
1662    #[must_use]
1663    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1664        self.meta = meta.into_option();
1665        self
1666    }
1667}
1668
1669/// **UNSTABLE**
1670///
1671/// This capability is not part of the spec yet, and may be removed or changed at any point.
1672///
1673/// Response from forking an existing session.
1674#[cfg(feature = "unstable_session_fork")]
1675#[serde_as]
1676#[skip_serializing_none]
1677#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1678#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
1679#[cfg_attr(feature = "schemars", schemars(extend("x-side" = "agent", "x-method" = SESSION_FORK_METHOD_NAME)))]
1680#[serde(rename_all = "camelCase")]
1681#[non_exhaustive]
1682pub struct ForkSessionResponse {
1683    /// Unique identifier for the newly created forked session.
1684    pub session_id: SessionId,
1685    /// Initial mode state if supported by the Agent
1686    ///
1687    /// See protocol docs: [Session Modes](https://agentclientprotocol.com/protocol/v1/session-modes)
1688    #[serde_as(deserialize_as = "DefaultOnError")]
1689    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
1690    #[serde(default)]
1691    pub modes: Option<SessionModeState>,
1692    /// Initial session configuration options if supported by the Agent.
1693    #[serde_as(deserialize_as = "DefaultOnError<Option<VecSkipError<_>>>")]
1694    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true, "x-deserialize-skip-invalid-items" = true)))]
1695    #[serde(default)]
1696    pub config_options: Option<Vec<SessionConfigOption>>,
1697    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1698    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1699    /// these keys.
1700    ///
1701    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v1/extensibility)
1702    #[serde_as(deserialize_as = "DefaultOnError")]
1703    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
1704    #[serde(default)]
1705    #[serde(rename = "_meta")]
1706    pub meta: Option<Meta>,
1707}
1708
1709#[cfg(feature = "unstable_session_fork")]
1710impl ForkSessionResponse {
1711    /// Builds [`ForkSessionResponse`] with the required response fields set. Optional fields start unset or empty.
1712    #[must_use]
1713    pub fn new(session_id: impl Into<SessionId>) -> Self {
1714        Self {
1715            session_id: session_id.into(),
1716            modes: None,
1717            config_options: None,
1718            meta: None,
1719        }
1720    }
1721
1722    /// Initial mode state if supported by the Agent
1723    ///
1724    /// See protocol docs: [Session Modes](https://agentclientprotocol.com/protocol/v1/session-modes)
1725    #[must_use]
1726    pub fn modes(mut self, modes: impl IntoOption<SessionModeState>) -> Self {
1727        self.modes = modes.into_option();
1728        self
1729    }
1730
1731    /// Initial session configuration options if supported by the Agent.
1732    #[must_use]
1733    pub fn config_options(
1734        mut self,
1735        config_options: impl IntoOption<Vec<SessionConfigOption>>,
1736    ) -> Self {
1737        self.config_options = config_options.into_option();
1738        self
1739    }
1740
1741    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1742    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1743    /// these keys.
1744    ///
1745    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v1/extensibility)
1746    #[must_use]
1747    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1748        self.meta = meta.into_option();
1749        self
1750    }
1751}
1752
1753// Resume session
1754
1755/// Request parameters for resuming an existing session.
1756///
1757/// Resumes an existing session without returning previous messages (unlike `session/load`).
1758/// This is useful for agents that can resume sessions but don't implement full session loading.
1759///
1760/// Only available if the Agent supports the `sessionCapabilities.resume` capability.
1761#[serde_as]
1762#[skip_serializing_none]
1763#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1764#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
1765#[cfg_attr(feature = "schemars", schemars(extend("x-side" = "agent", "x-method" = SESSION_RESUME_METHOD_NAME)))]
1766#[serde(rename_all = "camelCase")]
1767#[non_exhaustive]
1768pub struct ResumeSessionRequest {
1769    /// The ID of the session to resume.
1770    pub session_id: SessionId,
1771    /// The working directory for this session. Must be an absolute path.
1772    pub cwd: PathBuf,
1773    /// Additional workspace roots to activate for this session. Each path must be absolute.
1774    ///
1775    /// When omitted or empty, no additional roots are activated. When non-empty,
1776    /// this is the complete resulting additional-root list for the resumed
1777    /// session. It may differ from any previously used or reported list as long as
1778    /// the request `cwd` matches the session's `cwd`.
1779    #[serde_as(deserialize_as = "DefaultOnNull")]
1780    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-null" = true)))]
1781    #[serde(default, skip_serializing_if = "Vec::is_empty")]
1782    pub additional_directories: Vec<PathBuf>,
1783    /// List of MCP servers to connect to for this session.
1784    #[serde_as(deserialize_as = "DefaultOnNull")]
1785    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-null" = true)))]
1786    #[serde(default, skip_serializing_if = "Vec::is_empty")]
1787    pub mcp_servers: Vec<McpServer>,
1788    /// System-level instructions for the resumed session.
1789    ///
1790    /// Optional. Omitted and `null` are equivalent. The Agent may then keep a
1791    /// system prompt it stored with the session or use its default instructions.
1792    /// Clients MUST only send this when the Agent advertises
1793    /// `sessionCapabilities.systemPrompt`, and SHOULD send the same value they used
1794    /// when the session was created.
1795    #[serde(default)]
1796    pub system_prompt: Option<SystemPrompt>,
1797    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1798    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1799    /// these keys.
1800    ///
1801    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v1/extensibility)
1802    #[serde_as(deserialize_as = "DefaultOnError")]
1803    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
1804    #[serde(default)]
1805    #[serde(rename = "_meta")]
1806    pub meta: Option<Meta>,
1807}
1808
1809impl ResumeSessionRequest {
1810    /// Builds [`ResumeSessionRequest`] with the required request fields set. Optional fields start unset or empty.
1811    #[must_use]
1812    pub fn new(session_id: impl Into<SessionId>, cwd: impl Into<PathBuf>) -> Self {
1813        Self {
1814            session_id: session_id.into(),
1815            cwd: cwd.into(),
1816            additional_directories: vec![],
1817            mcp_servers: vec![],
1818            system_prompt: None,
1819            meta: None,
1820        }
1821    }
1822
1823    /// Additional workspace roots to activate for this session. Each path must be absolute.
1824    #[must_use]
1825    pub fn additional_directories(mut self, additional_directories: Vec<PathBuf>) -> Self {
1826        self.additional_directories = additional_directories;
1827        self
1828    }
1829
1830    /// List of MCP servers to connect to for this session.
1831    #[must_use]
1832    pub fn mcp_servers(mut self, mcp_servers: Vec<McpServer>) -> Self {
1833        self.mcp_servers = mcp_servers;
1834        self
1835    }
1836
1837    /// System-level instructions for the resumed session.
1838    #[must_use]
1839    pub fn system_prompt(mut self, system_prompt: impl IntoOption<SystemPrompt>) -> Self {
1840        self.system_prompt = system_prompt.into_option();
1841        self
1842    }
1843
1844    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1845    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1846    /// these keys.
1847    ///
1848    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v1/extensibility)
1849    #[must_use]
1850    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1851        self.meta = meta.into_option();
1852        self
1853    }
1854}
1855
1856crate::serde_util::default_on_null! {
1857    /// Response from resuming an existing session.
1858    #[serde_as]
1859    #[skip_serializing_none]
1860    #[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1861    #[derive(Default, Debug, Clone, Serialize, PartialEq, Eq)]
1862    #[cfg_attr(feature = "schemars", schemars(extend("x-side" = "agent", "x-method" = SESSION_RESUME_METHOD_NAME)))]
1863    #[serde(rename_all = "camelCase")]
1864    #[non_exhaustive]
1865    pub struct ResumeSessionResponse {
1866        /// Initial mode state if supported by the Agent
1867        ///
1868        /// See protocol docs: [Session Modes](https://agentclientprotocol.com/protocol/v1/session-modes)
1869        #[serde_as(deserialize_as = "DefaultOnError")]
1870        #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
1871        #[serde(default)]
1872        pub modes: Option<SessionModeState>,
1873        /// Initial session configuration options if supported by the Agent.
1874        #[serde_as(deserialize_as = "DefaultOnError<Option<VecSkipError<_>>>")]
1875        #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true, "x-deserialize-skip-invalid-items" = true)))]
1876        #[serde(default)]
1877        pub config_options: Option<Vec<SessionConfigOption>>,
1878        /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1879        /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1880        /// these keys.
1881        ///
1882        /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v1/extensibility)
1883        #[serde_as(deserialize_as = "DefaultOnError")]
1884        #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
1885        #[serde(default)]
1886        #[serde(rename = "_meta")]
1887        pub meta: Option<Meta>,
1888    }
1889}
1890
1891impl ResumeSessionResponse {
1892    /// Builds [`ResumeSessionResponse`] with the required response fields set. Optional fields start unset or empty.
1893    #[must_use]
1894    pub fn new() -> Self {
1895        Self::default()
1896    }
1897
1898    /// Initial mode state if supported by the Agent
1899    ///
1900    /// See protocol docs: [Session Modes](https://agentclientprotocol.com/protocol/v1/session-modes)
1901    #[must_use]
1902    pub fn modes(mut self, modes: impl IntoOption<SessionModeState>) -> Self {
1903        self.modes = modes.into_option();
1904        self
1905    }
1906
1907    /// Initial session configuration options if supported by the Agent.
1908    #[must_use]
1909    pub fn config_options(
1910        mut self,
1911        config_options: impl IntoOption<Vec<SessionConfigOption>>,
1912    ) -> Self {
1913        self.config_options = config_options.into_option();
1914        self
1915    }
1916
1917    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1918    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1919    /// these keys.
1920    ///
1921    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v1/extensibility)
1922    #[must_use]
1923    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1924        self.meta = meta.into_option();
1925        self
1926    }
1927}
1928
1929// Close session
1930
1931/// Request parameters for closing an active session.
1932///
1933/// If supported, the agent **must** cancel any ongoing work related to the session
1934/// (treat it as if `session/cancel` was called) and then free up any resources
1935/// associated with the session.
1936///
1937/// Only available if the Agent supports the `sessionCapabilities.close` capability.
1938#[serde_as]
1939#[skip_serializing_none]
1940#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1941#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
1942#[cfg_attr(feature = "schemars", schemars(extend("x-side" = "agent", "x-method" = SESSION_CLOSE_METHOD_NAME)))]
1943#[serde(rename_all = "camelCase")]
1944#[non_exhaustive]
1945pub struct CloseSessionRequest {
1946    /// The ID of the session to close.
1947    pub session_id: SessionId,
1948    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1949    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1950    /// these keys.
1951    ///
1952    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v1/extensibility)
1953    #[serde_as(deserialize_as = "DefaultOnError")]
1954    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
1955    #[serde(default)]
1956    #[serde(rename = "_meta")]
1957    pub meta: Option<Meta>,
1958}
1959
1960impl CloseSessionRequest {
1961    /// Builds [`CloseSessionRequest`] with the required request fields set. Optional fields start unset or empty.
1962    #[must_use]
1963    pub fn new(session_id: impl Into<SessionId>) -> Self {
1964        Self {
1965            session_id: session_id.into(),
1966            meta: None,
1967        }
1968    }
1969
1970    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1971    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1972    /// these keys.
1973    ///
1974    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v1/extensibility)
1975    #[must_use]
1976    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1977        self.meta = meta.into_option();
1978        self
1979    }
1980}
1981
1982crate::serde_util::default_on_null! {
1983    /// Response from closing a session.
1984    #[serde_as]
1985    #[skip_serializing_none]
1986    #[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1987    #[derive(Default, Debug, Clone, Serialize, PartialEq, Eq)]
1988    #[cfg_attr(feature = "schemars", schemars(extend("x-side" = "agent", "x-method" = SESSION_CLOSE_METHOD_NAME)))]
1989    #[serde(rename_all = "camelCase")]
1990    #[non_exhaustive]
1991    pub struct CloseSessionResponse {
1992        /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1993        /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1994        /// these keys.
1995        ///
1996        /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v1/extensibility)
1997        #[serde_as(deserialize_as = "DefaultOnError")]
1998        #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
1999        #[serde(default)]
2000        #[serde(rename = "_meta")]
2001        pub meta: Option<Meta>,
2002    }
2003}
2004
2005impl CloseSessionResponse {
2006    /// Builds [`CloseSessionResponse`] with the required response fields set. Optional fields start unset or empty.
2007    #[must_use]
2008    pub fn new() -> Self {
2009        Self::default()
2010    }
2011
2012    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
2013    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
2014    /// these keys.
2015    ///
2016    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v1/extensibility)
2017    #[must_use]
2018    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2019        self.meta = meta.into_option();
2020        self
2021    }
2022}
2023
2024// Session status
2025
2026/// **UNSTABLE**
2027///
2028/// This capability is not part of the spec yet, and may be removed or changed at any point.
2029///
2030/// Request parameters for checking the status of a session.
2031///
2032/// Only available if the Agent supports the `sessionCapabilities.status` capability.
2033///
2034/// `session/status` MUST NOT have side effects. The Agent does not load, resume, create,
2035/// close, or change the session, and does not attach the requesting connection to it.
2036/// A session the Agent does not know gets `-32002` with the requested `sessionId` in `data`.
2037#[cfg(feature = "unstable_session_status")]
2038#[serde_as]
2039#[skip_serializing_none]
2040#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2041#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
2042#[cfg_attr(feature = "schemars", schemars(extend("x-side" = "agent", "x-method" = SESSION_STATUS_METHOD_NAME)))]
2043#[serde(rename_all = "camelCase")]
2044#[non_exhaustive]
2045pub struct SessionStatusRequest {
2046    /// The ID of the session to check.
2047    pub session_id: SessionId,
2048    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
2049    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
2050    /// these keys.
2051    ///
2052    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v1/extensibility)
2053    #[serde_as(deserialize_as = "DefaultOnError")]
2054    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
2055    #[serde(default)]
2056    #[serde(rename = "_meta")]
2057    pub meta: Option<Meta>,
2058}
2059
2060#[cfg(feature = "unstable_session_status")]
2061impl SessionStatusRequest {
2062    /// Builds [`SessionStatusRequest`] with the required request fields set. Optional fields start unset or empty.
2063    #[must_use]
2064    pub fn new(session_id: impl Into<SessionId>) -> Self {
2065        Self {
2066            session_id: session_id.into(),
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/v1/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/// **UNSTABLE**
2084///
2085/// This capability is not part of the spec yet, and may be removed or changed at any point.
2086///
2087/// Response from checking the status of a session.
2088///
2089/// The result is a snapshot. A session reported `open` may be closed or evicted before
2090/// the Client's next request.
2091#[cfg(feature = "unstable_session_status")]
2092#[serde_as]
2093#[skip_serializing_none]
2094#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2095#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
2096#[cfg_attr(feature = "schemars", schemars(extend("x-side" = "agent", "x-method" = SESSION_STATUS_METHOD_NAME)))]
2097#[serde(rename_all = "camelCase")]
2098#[non_exhaustive]
2099pub struct SessionStatusResponse {
2100    /// Whether the Agent has the session in memory.
2101    ///
2102    /// Required. Clients MUST treat a value they do not recognize as `saved`.
2103    pub status: SessionStatus,
2104    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
2105    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
2106    /// these keys.
2107    ///
2108    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v1/extensibility)
2109    #[serde_as(deserialize_as = "DefaultOnError")]
2110    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
2111    #[serde(default)]
2112    #[serde(rename = "_meta")]
2113    pub meta: Option<Meta>,
2114}
2115
2116#[cfg(feature = "unstable_session_status")]
2117impl SessionStatusResponse {
2118    /// Builds [`SessionStatusResponse`] with the required response fields set. Optional fields start unset or empty.
2119    #[must_use]
2120    pub fn new(status: SessionStatus) -> Self {
2121        Self { status, meta: None }
2122    }
2123
2124    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
2125    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
2126    /// these keys.
2127    ///
2128    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v1/extensibility)
2129    #[must_use]
2130    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2131        self.meta = meta.into_option();
2132        self
2133    }
2134}
2135
2136/// **UNSTABLE**
2137///
2138/// This capability is not part of the spec yet, and may be removed or changed at any point.
2139///
2140/// Whether the Agent has a session in memory, as reported by `session/status`.
2141#[cfg(feature = "unstable_session_status")]
2142#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2143#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
2144#[serde(rename_all = "snake_case")]
2145#[non_exhaustive]
2146pub enum SessionStatus {
2147    /// The Agent has the session in memory, for any connection.
2148    ///
2149    /// This does not mean the requesting connection is attached to it. A Client that did
2150    /// not create or resume the session on its own connection MUST still call
2151    /// `session/load` or `session/resume` before sending `session/prompt` or expecting
2152    /// `session/update` notifications.
2153    Open,
2154    /// The Agent knows the session and can resume it, but does not have it in memory.
2155    ///
2156    /// The Client can call `session/load` or `session/resume` to start it.
2157    Saved,
2158    /// Custom or future session status.
2159    ///
2160    /// Values beginning with `_` are reserved for implementation-specific
2161    /// extensions. Unknown values that do not begin with `_` are reserved for
2162    /// future ACP variants. Clients MUST treat a value they do not recognize as
2163    /// `saved`.
2164    #[serde(untagged)]
2165    Other(String),
2166}
2167
2168// List sessions
2169
2170crate::serde_util::default_on_null! {
2171    /// Request parameters for listing existing sessions.
2172    ///
2173    /// Only available if the Agent supports the `sessionCapabilities.list` capability.
2174    #[serde_as]
2175    #[skip_serializing_none]
2176    #[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2177    #[derive(Default, Debug, Clone, Serialize, PartialEq, Eq)]
2178    #[cfg_attr(feature = "schemars", schemars(extend("x-side" = "agent", "x-method" = SESSION_LIST_METHOD_NAME)))]
2179    #[serde(rename_all = "camelCase")]
2180    #[non_exhaustive]
2181    pub struct ListSessionsRequest {
2182        /// Filter sessions by working directory. Must be an absolute path.
2183        #[serde(default)]
2184        pub cwd: Option<PathBuf>,
2185        /// Opaque cursor token from a previous response's nextCursor field for cursor-based pagination
2186        #[serde(default)]
2187        pub cursor: Option<String>,
2188        /// **UNSTABLE**
2189        ///
2190        /// This capability is not part of the spec yet, and may be removed or changed at any point.
2191        ///
2192        /// Filter sessions by archive state.
2193        ///
2194        /// Optional. Omitted and `null` are equivalent and mean `exclude`. Only send this when
2195        /// the Agent advertises the `sessionCapabilities.archive` capability. The filter combines with `cwd` and
2196        /// applies before pagination. Clients keep the same value when following `nextCursor`.
2197        #[cfg(feature = "unstable_session_archive")]
2198        #[serde(default)]
2199        pub archived: Option<SessionArchiveFilter>,
2200        /// The _meta property is reserved by ACP to allow clients and agents to attach additional
2201        /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
2202        /// these keys.
2203        ///
2204        /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v1/extensibility)
2205        #[serde_as(deserialize_as = "DefaultOnError")]
2206        #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
2207        #[serde(default)]
2208        #[serde(rename = "_meta")]
2209        pub meta: Option<Meta>,
2210    }
2211}
2212
2213impl ListSessionsRequest {
2214    /// Builds [`ListSessionsRequest`] with the required request fields set. Optional fields start unset or empty.
2215    #[must_use]
2216    pub fn new() -> Self {
2217        Self::default()
2218    }
2219
2220    /// Filter sessions by working directory. Must be an absolute path.
2221    #[must_use]
2222    pub fn cwd(mut self, cwd: impl IntoOption<PathBuf>) -> Self {
2223        self.cwd = cwd.into_option();
2224        self
2225    }
2226
2227    /// Opaque cursor token from a previous response's nextCursor field for cursor-based pagination
2228    #[must_use]
2229    pub fn cursor(mut self, cursor: impl IntoOption<String>) -> Self {
2230        self.cursor = cursor.into_option();
2231        self
2232    }
2233
2234    /// **UNSTABLE**
2235    ///
2236    /// This capability is not part of the spec yet, and may be removed or changed at any point.
2237    ///
2238    /// Filter sessions by archive state.
2239    #[cfg(feature = "unstable_session_archive")]
2240    #[must_use]
2241    pub fn archived(mut self, archived: impl IntoOption<SessionArchiveFilter>) -> Self {
2242        self.archived = archived.into_option();
2243        self
2244    }
2245
2246    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
2247    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
2248    /// these keys.
2249    ///
2250    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v1/extensibility)
2251    #[must_use]
2252    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2253        self.meta = meta.into_option();
2254        self
2255    }
2256}
2257
2258/// Response from listing sessions.
2259#[serde_as]
2260#[skip_serializing_none]
2261#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2262#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
2263#[cfg_attr(feature = "schemars", schemars(extend("x-side" = "agent", "x-method" = SESSION_LIST_METHOD_NAME)))]
2264#[serde(rename_all = "camelCase")]
2265#[non_exhaustive]
2266pub struct ListSessionsResponse {
2267    /// Array of session information objects
2268    #[serde_as(deserialize_as = "DefaultOnError<VecSkipError<_>>")]
2269    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true, "x-deserialize-skip-invalid-items" = true)))]
2270    pub sessions: Vec<SessionInfo>,
2271    /// Opaque cursor token. If present, pass this in the next request's cursor parameter
2272    /// to fetch the next page. If absent, there are no more results.
2273    #[serde_as(deserialize_as = "DefaultOnError")]
2274    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
2275    #[serde(default)]
2276    pub next_cursor: Option<String>,
2277    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
2278    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
2279    /// these keys.
2280    ///
2281    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v1/extensibility)
2282    #[serde_as(deserialize_as = "DefaultOnError")]
2283    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
2284    #[serde(default)]
2285    #[serde(rename = "_meta")]
2286    pub meta: Option<Meta>,
2287}
2288
2289impl ListSessionsResponse {
2290    /// Builds [`ListSessionsResponse`] with the required response fields set. Optional fields start unset or empty.
2291    #[must_use]
2292    pub fn new(sessions: Vec<SessionInfo>) -> Self {
2293        Self {
2294            sessions,
2295            next_cursor: None,
2296            meta: None,
2297        }
2298    }
2299
2300    /// Sets or clears the optional `nextCursor` field.
2301    #[must_use]
2302    pub fn next_cursor(mut self, next_cursor: impl IntoOption<String>) -> Self {
2303        self.next_cursor = next_cursor.into_option();
2304        self
2305    }
2306
2307    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
2308    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
2309    /// these keys.
2310    ///
2311    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v1/extensibility)
2312    #[must_use]
2313    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2314        self.meta = meta.into_option();
2315        self
2316    }
2317}
2318
2319// Delete session
2320
2321/// Request parameters for deleting an existing session from `session/list`.
2322///
2323/// Only available if the Agent supports the `sessionCapabilities.delete` capability.
2324#[serde_as]
2325#[skip_serializing_none]
2326#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2327#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
2328#[cfg_attr(feature = "schemars", schemars(extend("x-side" = "agent", "x-method" = SESSION_DELETE_METHOD_NAME)))]
2329#[serde(rename_all = "camelCase")]
2330#[non_exhaustive]
2331pub struct DeleteSessionRequest {
2332    /// The ID of the session to delete.
2333    pub session_id: SessionId,
2334    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
2335    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
2336    /// these keys.
2337    ///
2338    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v1/extensibility)
2339    #[serde_as(deserialize_as = "DefaultOnError")]
2340    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
2341    #[serde(default)]
2342    #[serde(rename = "_meta")]
2343    pub meta: Option<Meta>,
2344}
2345
2346impl DeleteSessionRequest {
2347    /// Builds [`DeleteSessionRequest`] with the required request fields set. Optional fields start unset or empty.
2348    #[must_use]
2349    pub fn new(session_id: impl Into<SessionId>) -> Self {
2350        Self {
2351            session_id: session_id.into(),
2352            meta: None,
2353        }
2354    }
2355
2356    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
2357    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
2358    /// these keys.
2359    ///
2360    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v1/extensibility)
2361    #[must_use]
2362    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2363        self.meta = meta.into_option();
2364        self
2365    }
2366}
2367
2368crate::serde_util::default_on_null! {
2369    /// Response from deleting a session.
2370    #[serde_as]
2371    #[skip_serializing_none]
2372    #[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2373    #[derive(Default, Debug, Clone, Serialize, PartialEq, Eq)]
2374    #[cfg_attr(feature = "schemars", schemars(extend("x-side" = "agent", "x-method" = SESSION_DELETE_METHOD_NAME)))]
2375    #[serde(rename_all = "camelCase")]
2376    #[non_exhaustive]
2377    pub struct DeleteSessionResponse {
2378        /// The _meta property is reserved by ACP to allow clients and agents to attach additional
2379        /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
2380        /// these keys.
2381        ///
2382        /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v1/extensibility)
2383        #[serde_as(deserialize_as = "DefaultOnError")]
2384        #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
2385        #[serde(default)]
2386        #[serde(rename = "_meta")]
2387        pub meta: Option<Meta>,
2388    }
2389}
2390
2391impl DeleteSessionResponse {
2392    /// Builds [`DeleteSessionResponse`] with the required response fields set. Optional fields start unset or empty.
2393    #[must_use]
2394    pub fn new() -> Self {
2395        Self::default()
2396    }
2397
2398    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
2399    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
2400    /// these keys.
2401    ///
2402    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v1/extensibility)
2403    #[must_use]
2404    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2405        self.meta = meta.into_option();
2406        self
2407    }
2408}
2409
2410// Archive session
2411
2412/// **UNSTABLE**
2413///
2414/// This capability is not part of the spec yet, and may be removed or changed at any point.
2415///
2416/// Request parameters for archiving a session.
2417///
2418/// Only available if the Agent supports the `sessionCapabilities.archive` capability.
2419///
2420/// Archiving hides the session from default `session/list` results. It keeps the session ID
2421/// and saved history. If the session is active, the Agent MUST cancel any ongoing work and
2422/// free the session's resources as if `session/close` had been called, then archive it.
2423/// Archiving an archived session succeeds. A session that does not exist gets `-32002`.
2424///
2425#[cfg(feature = "unstable_session_archive")]
2426#[serde_as]
2427#[skip_serializing_none]
2428#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2429#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
2430#[cfg_attr(feature = "schemars", schemars(extend("x-side" = "agent", "x-method" = SESSION_ARCHIVE_METHOD_NAME)))]
2431#[serde(rename_all = "camelCase")]
2432#[non_exhaustive]
2433pub struct ArchiveSessionRequest {
2434    /// The ID of the session to archive.
2435    pub session_id: SessionId,
2436    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
2437    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
2438    /// these keys.
2439    ///
2440    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v1/extensibility)
2441    #[serde_as(deserialize_as = "DefaultOnError")]
2442    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
2443    #[serde(default)]
2444    #[serde(rename = "_meta")]
2445    pub meta: Option<Meta>,
2446}
2447
2448#[cfg(feature = "unstable_session_archive")]
2449impl ArchiveSessionRequest {
2450    /// Builds [`ArchiveSessionRequest`] with the required request fields set. Optional fields start unset or empty.
2451    #[must_use]
2452    pub fn new(session_id: impl Into<SessionId>) -> Self {
2453        Self {
2454            session_id: session_id.into(),
2455            meta: None,
2456        }
2457    }
2458
2459    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
2460    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
2461    /// these keys.
2462    ///
2463    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v1/extensibility)
2464    #[must_use]
2465    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2466        self.meta = meta.into_option();
2467        self
2468    }
2469}
2470
2471#[cfg(feature = "unstable_session_archive")]
2472crate::serde_util::default_on_null! {
2473    /// **UNSTABLE**
2474    ///
2475    /// This capability is not part of the spec yet, and may be removed or changed at any point.
2476    ///
2477    /// Response from archiving a session.
2478    #[serde_as]
2479    #[skip_serializing_none]
2480    #[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2481    #[derive(Default, Debug, Clone, Serialize, PartialEq, Eq)]
2482    #[cfg_attr(feature = "schemars", schemars(extend("x-side" = "agent", "x-method" = SESSION_ARCHIVE_METHOD_NAME)))]
2483    #[serde(rename_all = "camelCase")]
2484    #[non_exhaustive]
2485    pub struct ArchiveSessionResponse {
2486        /// The _meta property is reserved by ACP to allow clients and agents to attach additional
2487        /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
2488        /// these keys.
2489        ///
2490        /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v1/extensibility)
2491        #[serde_as(deserialize_as = "DefaultOnError")]
2492        #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
2493        #[serde(default)]
2494        #[serde(rename = "_meta")]
2495        pub meta: Option<Meta>,
2496    }
2497}
2498
2499#[cfg(feature = "unstable_session_archive")]
2500impl ArchiveSessionResponse {
2501    /// Builds [`ArchiveSessionResponse`] with the required response fields set. Optional fields start unset or empty.
2502    #[must_use]
2503    pub fn new() -> Self {
2504        Self::default()
2505    }
2506
2507    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
2508    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
2509    /// these keys.
2510    ///
2511    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v1/extensibility)
2512    #[must_use]
2513    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2514        self.meta = meta.into_option();
2515        self
2516    }
2517}
2518
2519/// **UNSTABLE**
2520///
2521/// This capability is not part of the spec yet, and may be removed or changed at any point.
2522///
2523/// Request parameters for unarchiving a session.
2524///
2525/// Only available if the Agent supports the `sessionCapabilities.archive` capability.
2526///
2527/// Unarchiving returns the session to default `session/list` results with the same ID and
2528/// saved history. It never loads or resumes the session. Clients that want to continue an
2529/// archived session SHOULD unarchive it before calling `session/load` or `session/resume`.
2530/// Unarchiving a session that is not archived succeeds. A session that does not exist
2531/// gets `-32002`.
2532///
2533#[cfg(feature = "unstable_session_archive")]
2534#[serde_as]
2535#[skip_serializing_none]
2536#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2537#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
2538#[cfg_attr(feature = "schemars", schemars(extend("x-side" = "agent", "x-method" = SESSION_UNARCHIVE_METHOD_NAME)))]
2539#[serde(rename_all = "camelCase")]
2540#[non_exhaustive]
2541pub struct UnarchiveSessionRequest {
2542    /// The ID of the session to unarchive.
2543    pub session_id: SessionId,
2544    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
2545    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
2546    /// these keys.
2547    ///
2548    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v1/extensibility)
2549    #[serde_as(deserialize_as = "DefaultOnError")]
2550    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
2551    #[serde(default)]
2552    #[serde(rename = "_meta")]
2553    pub meta: Option<Meta>,
2554}
2555
2556#[cfg(feature = "unstable_session_archive")]
2557impl UnarchiveSessionRequest {
2558    /// Builds [`UnarchiveSessionRequest`] with the required request fields set. Optional fields start unset or empty.
2559    #[must_use]
2560    pub fn new(session_id: impl Into<SessionId>) -> Self {
2561        Self {
2562            session_id: session_id.into(),
2563            meta: None,
2564        }
2565    }
2566
2567    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
2568    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
2569    /// these keys.
2570    ///
2571    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v1/extensibility)
2572    #[must_use]
2573    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2574        self.meta = meta.into_option();
2575        self
2576    }
2577}
2578
2579#[cfg(feature = "unstable_session_archive")]
2580crate::serde_util::default_on_null! {
2581    /// **UNSTABLE**
2582    ///
2583    /// This capability is not part of the spec yet, and may be removed or changed at any point.
2584    ///
2585    /// Response from unarchiving a session.
2586    #[serde_as]
2587    #[skip_serializing_none]
2588    #[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2589    #[derive(Default, Debug, Clone, Serialize, PartialEq, Eq)]
2590    #[cfg_attr(feature = "schemars", schemars(extend("x-side" = "agent", "x-method" = SESSION_UNARCHIVE_METHOD_NAME)))]
2591    #[serde(rename_all = "camelCase")]
2592    #[non_exhaustive]
2593    pub struct UnarchiveSessionResponse {
2594        /// The _meta property is reserved by ACP to allow clients and agents to attach additional
2595        /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
2596        /// these keys.
2597        ///
2598        /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v1/extensibility)
2599        #[serde_as(deserialize_as = "DefaultOnError")]
2600        #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
2601        #[serde(default)]
2602        #[serde(rename = "_meta")]
2603        pub meta: Option<Meta>,
2604    }
2605}
2606
2607#[cfg(feature = "unstable_session_archive")]
2608impl UnarchiveSessionResponse {
2609    /// Builds [`UnarchiveSessionResponse`] with the required response fields set. Optional fields start unset or empty.
2610    #[must_use]
2611    pub fn new() -> Self {
2612        Self::default()
2613    }
2614
2615    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
2616    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
2617    /// these keys.
2618    ///
2619    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v1/extensibility)
2620    #[must_use]
2621    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2622        self.meta = meta.into_option();
2623        self
2624    }
2625}
2626
2627/// **UNSTABLE**
2628///
2629/// This capability is not part of the spec yet, and may be removed or changed at any point.
2630///
2631/// Which sessions `session/list` returns based on their archive state.
2632///
2633/// Unknown values are preserved so they can be stored, proxied, or forwarded. An Agent MUST
2634/// return `-32602` for a value it does not support rather than treating it as `exclude`.
2635#[cfg(feature = "unstable_session_archive")]
2636#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2637#[derive(Debug, Default, Clone, PartialEq, Eq, Serialize, Deserialize)]
2638#[serde(rename_all = "snake_case")]
2639#[non_exhaustive]
2640pub enum SessionArchiveFilter {
2641    /// Only sessions that are not archived. This is the default.
2642    #[default]
2643    Exclude,
2644    /// Both archived sessions and sessions that are not archived.
2645    Include,
2646    /// Only archived sessions.
2647    Only,
2648    /// Custom or future archive filter.
2649    ///
2650    /// Values beginning with `_` are reserved for implementation-specific
2651    /// extensions. Unknown values that do not begin with `_` are reserved for
2652    /// future ACP variants.
2653    #[serde(untagged)]
2654    Other(String),
2655}
2656
2657/// Information about a session returned by session/list
2658#[serde_as]
2659#[skip_serializing_none]
2660#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2661#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
2662#[serde(rename_all = "camelCase")]
2663#[non_exhaustive]
2664pub struct SessionInfo {
2665    /// Unique identifier for the session
2666    pub session_id: SessionId,
2667    /// The working directory for this session. Must be an absolute path.
2668    pub cwd: PathBuf,
2669    /// Additional workspace roots reported for this session. Each path must be absolute.
2670    ///
2671    /// When present, this is the complete ordered additional-root list reported
2672    /// by the Agent. Omitted and empty values are equivalent: the response
2673    /// reports no additional roots.
2674    #[serde_as(deserialize_as = "DefaultOnError<VecSkipError<_>>")]
2675    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true, "x-deserialize-skip-invalid-items" = true)))]
2676    #[serde(default, skip_serializing_if = "Vec::is_empty")]
2677    pub additional_directories: Vec<PathBuf>,
2678
2679    /// Human-readable title for the session
2680    #[serde_as(deserialize_as = "DefaultOnError")]
2681    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
2682    #[serde(default)]
2683    pub title: Option<String>,
2684    /// ISO 8601 timestamp of last activity
2685    #[serde_as(deserialize_as = "DefaultOnError")]
2686    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
2687    #[serde(default)]
2688    pub updated_at: Option<String>,
2689    /// **UNSTABLE**
2690    ///
2691    /// This capability is not part of the spec yet, and may be removed or changed at any point.
2692    ///
2693    /// Whether the session is archived.
2694    ///
2695    /// Optional. Omitted and `null` are equivalent and mean the archive state is not reported.
2696    /// Agents that advertise the `sessionCapabilities.archive` capability MUST include it on every listed session.
2697    #[cfg(feature = "unstable_session_archive")]
2698    #[serde_as(deserialize_as = "DefaultOnError")]
2699    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
2700    #[serde(default)]
2701    pub archived: Option<bool>,
2702    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
2703    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
2704    /// these keys.
2705    ///
2706    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v1/extensibility)
2707    #[serde_as(deserialize_as = "DefaultOnError")]
2708    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
2709    #[serde(default)]
2710    #[serde(rename = "_meta")]
2711    pub meta: Option<Meta>,
2712}
2713
2714impl SessionInfo {
2715    /// Builds [`SessionInfo`] with the required fields set. Optional fields start unset or empty.
2716    #[must_use]
2717    pub fn new(session_id: impl Into<SessionId>, cwd: impl Into<PathBuf>) -> Self {
2718        Self {
2719            session_id: session_id.into(),
2720            cwd: cwd.into(),
2721            additional_directories: vec![],
2722            title: None,
2723            updated_at: None,
2724            #[cfg(feature = "unstable_session_archive")]
2725            archived: None,
2726            meta: None,
2727        }
2728    }
2729
2730    /// Additional workspace roots reported for this session. Each path must be absolute.
2731    #[must_use]
2732    pub fn additional_directories(mut self, additional_directories: Vec<PathBuf>) -> Self {
2733        self.additional_directories = additional_directories;
2734        self
2735    }
2736
2737    /// Human-readable title for the session
2738    #[must_use]
2739    pub fn title(mut self, title: impl IntoOption<String>) -> Self {
2740        self.title = title.into_option();
2741        self
2742    }
2743
2744    /// ISO 8601 timestamp of last activity
2745    #[must_use]
2746    pub fn updated_at(mut self, updated_at: impl IntoOption<String>) -> Self {
2747        self.updated_at = updated_at.into_option();
2748        self
2749    }
2750
2751    /// **UNSTABLE**
2752    ///
2753    /// This capability is not part of the spec yet, and may be removed or changed at any point.
2754    ///
2755    /// Whether the session is archived.
2756    #[cfg(feature = "unstable_session_archive")]
2757    #[must_use]
2758    pub fn archived(mut self, archived: impl IntoOption<bool>) -> Self {
2759        self.archived = archived.into_option();
2760        self
2761    }
2762
2763    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
2764    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
2765    /// these keys.
2766    ///
2767    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v1/extensibility)
2768    #[must_use]
2769    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2770        self.meta = meta.into_option();
2771        self
2772    }
2773}
2774
2775// Set session title
2776
2777/// **UNSTABLE**
2778///
2779/// This capability is not part of the spec yet, and may be removed or changed at any point.
2780///
2781/// Request parameters for setting the title of a session.
2782///
2783/// Only available if the Agent supports the `sessionCapabilities.title` capability.
2784///
2785/// The session does not need to be active on the connection. Any session the Agent would
2786/// return from `session/list` can be retitled. A session that does not exist gets `-32002`.
2787///
2788/// The Agent responds only after it has stored the title. After a successful response, the
2789/// Agent SHOULD NOT replace the title with one it generates automatically.
2790#[cfg(feature = "unstable_session_set_title")]
2791#[serde_as]
2792#[skip_serializing_none]
2793#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2794#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
2795#[cfg_attr(feature = "schemars", schemars(extend("x-side" = "agent", "x-method" = SESSION_SET_TITLE_METHOD_NAME)))]
2796#[serde(rename_all = "camelCase")]
2797#[non_exhaustive]
2798pub struct SetSessionTitleRequest {
2799    /// The ID of the session to retitle.
2800    pub session_id: SessionId,
2801    /// The new title for the session.
2802    ///
2803    /// Required and non-null. Omission and explicit `null` are both invalid. The Agent MAY
2804    /// normalize the title before storing it, for example by trimming whitespace or
2805    /// truncating it. The Agent rejects a title that fails its validation, including one
2806    /// that is empty after normalization, with `-32602`.
2807    pub title: String,
2808    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
2809    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
2810    /// these keys.
2811    ///
2812    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v1/extensibility)
2813    #[serde_as(deserialize_as = "DefaultOnError")]
2814    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
2815    #[serde(default)]
2816    #[serde(rename = "_meta")]
2817    pub meta: Option<Meta>,
2818}
2819
2820#[cfg(feature = "unstable_session_set_title")]
2821impl SetSessionTitleRequest {
2822    /// Builds [`SetSessionTitleRequest`] with the required request fields set. Optional fields start unset or empty.
2823    #[must_use]
2824    pub fn new(session_id: impl Into<SessionId>, title: impl Into<String>) -> Self {
2825        Self {
2826            session_id: session_id.into(),
2827            title: title.into(),
2828            meta: None,
2829        }
2830    }
2831
2832    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
2833    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
2834    /// these keys.
2835    ///
2836    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v1/extensibility)
2837    #[must_use]
2838    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2839        self.meta = meta.into_option();
2840        self
2841    }
2842}
2843
2844/// **UNSTABLE**
2845///
2846/// This capability is not part of the spec yet, and may be removed or changed at any point.
2847///
2848/// Response from setting the title of a session.
2849#[cfg(feature = "unstable_session_set_title")]
2850#[serde_as]
2851#[skip_serializing_none]
2852#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2853#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
2854#[cfg_attr(feature = "schemars", schemars(extend("x-side" = "agent", "x-method" = SESSION_SET_TITLE_METHOD_NAME)))]
2855#[serde(rename_all = "camelCase")]
2856#[non_exhaustive]
2857pub struct SetSessionTitleResponse {
2858    /// The title the Agent stored.
2859    ///
2860    /// This differs from the requested title if the Agent normalized it. Clients SHOULD
2861    /// display this value rather than the one they sent.
2862    pub title: String,
2863    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
2864    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
2865    /// these keys.
2866    ///
2867    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v1/extensibility)
2868    #[serde_as(deserialize_as = "DefaultOnError")]
2869    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
2870    #[serde(default)]
2871    #[serde(rename = "_meta")]
2872    pub meta: Option<Meta>,
2873}
2874
2875#[cfg(feature = "unstable_session_set_title")]
2876impl SetSessionTitleResponse {
2877    /// Builds [`SetSessionTitleResponse`] with the required response fields set. Optional fields start unset or empty.
2878    #[must_use]
2879    pub fn new(title: impl Into<String>) -> Self {
2880        Self {
2881            title: title.into(),
2882            meta: None,
2883        }
2884    }
2885
2886    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
2887    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
2888    /// these keys.
2889    ///
2890    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v1/extensibility)
2891    #[must_use]
2892    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2893        self.meta = meta.into_option();
2894        self
2895    }
2896}
2897
2898// Session modes
2899
2900/// The set of modes and the one currently active.
2901#[serde_as]
2902#[skip_serializing_none]
2903#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2904#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
2905#[serde(rename_all = "camelCase")]
2906#[non_exhaustive]
2907pub struct SessionModeState {
2908    /// The current mode the Agent is in.
2909    pub current_mode_id: SessionModeId,
2910    /// The set of modes that the Agent can operate in
2911    #[serde_as(deserialize_as = "DefaultOnError<VecSkipError<_>>")]
2912    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true, "x-deserialize-skip-invalid-items" = true)))]
2913    pub available_modes: Vec<SessionMode>,
2914    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
2915    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
2916    /// these keys.
2917    ///
2918    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v1/extensibility)
2919    #[serde_as(deserialize_as = "DefaultOnError")]
2920    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
2921    #[serde(default)]
2922    #[serde(rename = "_meta")]
2923    pub meta: Option<Meta>,
2924}
2925
2926impl SessionModeState {
2927    /// Builds [`SessionModeState`] with the required fields set. Optional fields start unset or empty.
2928    #[must_use]
2929    pub fn new(
2930        current_mode_id: impl Into<SessionModeId>,
2931        available_modes: Vec<SessionMode>,
2932    ) -> Self {
2933        Self {
2934            current_mode_id: current_mode_id.into(),
2935            available_modes,
2936            meta: None,
2937        }
2938    }
2939
2940    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
2941    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
2942    /// these keys.
2943    ///
2944    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v1/extensibility)
2945    #[must_use]
2946    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2947        self.meta = meta.into_option();
2948        self
2949    }
2950}
2951
2952/// A mode the agent can operate in.
2953///
2954/// See protocol docs: [Session Modes](https://agentclientprotocol.com/protocol/v1/session-modes)
2955#[serde_as]
2956#[skip_serializing_none]
2957#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2958#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
2959#[serde(rename_all = "camelCase")]
2960#[non_exhaustive]
2961pub struct SessionMode {
2962    /// Stable identifier used to refer to this protocol object in later messages.
2963    pub id: SessionModeId,
2964    /// Human-readable name shown for this protocol object.
2965    pub name: String,
2966    /// Optional human-readable details shown with this protocol object.
2967    #[serde_as(deserialize_as = "DefaultOnError")]
2968    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
2969    #[serde(default)]
2970    pub description: Option<String>,
2971    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
2972    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
2973    /// these keys.
2974    ///
2975    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v1/extensibility)
2976    #[serde_as(deserialize_as = "DefaultOnError")]
2977    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
2978    #[serde(default)]
2979    #[serde(rename = "_meta")]
2980    pub meta: Option<Meta>,
2981}
2982
2983impl SessionMode {
2984    /// Builds [`SessionMode`] with the required fields set. Optional fields start unset or empty.
2985    #[must_use]
2986    pub fn new(id: impl Into<SessionModeId>, name: impl Into<String>) -> Self {
2987        Self {
2988            id: id.into(),
2989            name: name.into(),
2990            description: None,
2991            meta: None,
2992        }
2993    }
2994
2995    /// Sets or clears the optional `description` field.
2996    #[must_use]
2997    pub fn description(mut self, description: impl IntoOption<String>) -> Self {
2998        self.description = description.into_option();
2999        self
3000    }
3001
3002    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
3003    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
3004    /// these keys.
3005    ///
3006    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v1/extensibility)
3007    #[must_use]
3008    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3009        self.meta = meta.into_option();
3010        self
3011    }
3012}
3013
3014/// Unique identifier for a Session Mode.
3015#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
3016#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash, From, Display)]
3017#[serde(transparent)]
3018#[from(Arc<str>, String, &'static str)]
3019#[non_exhaustive]
3020pub struct SessionModeId(pub Arc<str>);
3021
3022impl SessionModeId {
3023    /// Wraps a protocol string as a typed [`SessionModeId`].
3024    #[must_use]
3025    pub fn new(id: impl Into<Arc<str>>) -> Self {
3026        Self(id.into())
3027    }
3028}
3029
3030/// Request parameters for setting a session mode.
3031#[serde_as]
3032#[skip_serializing_none]
3033#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
3034#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
3035#[cfg_attr(feature = "schemars", schemars(extend("x-side" = "agent", "x-method" = SESSION_SET_MODE_METHOD_NAME)))]
3036#[serde(rename_all = "camelCase")]
3037#[non_exhaustive]
3038pub struct SetSessionModeRequest {
3039    /// The ID of the session to set the mode for.
3040    pub session_id: SessionId,
3041    /// The ID of the mode to set.
3042    pub mode_id: SessionModeId,
3043    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
3044    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
3045    /// these keys.
3046    ///
3047    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v1/extensibility)
3048    #[serde_as(deserialize_as = "DefaultOnError")]
3049    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
3050    #[serde(default)]
3051    #[serde(rename = "_meta")]
3052    pub meta: Option<Meta>,
3053}
3054
3055impl SetSessionModeRequest {
3056    /// Builds [`SetSessionModeRequest`] with the required request fields set. Optional fields start unset or empty.
3057    #[must_use]
3058    pub fn new(session_id: impl Into<SessionId>, mode_id: impl Into<SessionModeId>) -> Self {
3059        Self {
3060            session_id: session_id.into(),
3061            mode_id: mode_id.into(),
3062            meta: None,
3063        }
3064    }
3065
3066    /// Sets or clears ACP `_meta` extension metadata.
3067    #[must_use]
3068    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3069        self.meta = meta.into_option();
3070        self
3071    }
3072}
3073
3074crate::serde_util::default_on_null! {
3075    /// Response to `session/set_mode` method.
3076    #[serde_as]
3077    #[skip_serializing_none]
3078    #[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
3079    #[derive(Default, Debug, Clone, Serialize, PartialEq, Eq)]
3080    #[cfg_attr(feature = "schemars", schemars(extend("x-side" = "agent", "x-method" = SESSION_SET_MODE_METHOD_NAME)))]
3081    #[serde(rename_all = "camelCase")]
3082    #[non_exhaustive]
3083    pub struct SetSessionModeResponse {
3084        /// The _meta property is reserved by ACP to allow clients and agents to attach additional
3085        /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
3086        /// these keys.
3087        ///
3088        /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v1/extensibility)
3089        #[serde_as(deserialize_as = "DefaultOnError")]
3090        #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
3091        #[serde(default)]
3092        #[serde(rename = "_meta")]
3093        pub meta: Option<Meta>,
3094    }
3095}
3096
3097impl SetSessionModeResponse {
3098    /// Builds [`SetSessionModeResponse`] with the required response fields set. Optional fields start unset or empty.
3099    #[must_use]
3100    pub fn new() -> Self {
3101        Self::default()
3102    }
3103
3104    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
3105    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
3106    /// these keys.
3107    ///
3108    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v1/extensibility)
3109    #[must_use]
3110    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3111        self.meta = meta.into_option();
3112        self
3113    }
3114}
3115
3116// Session config options
3117
3118/// Unique identifier for a session configuration option.
3119#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
3120#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash, From, Display)]
3121#[serde(transparent)]
3122#[from(Arc<str>, String, &'static str)]
3123#[non_exhaustive]
3124pub struct SessionConfigId(pub Arc<str>);
3125
3126impl SessionConfigId {
3127    /// Wraps a protocol string as a typed [`SessionConfigId`].
3128    #[must_use]
3129    pub fn new(id: impl Into<Arc<str>>) -> Self {
3130        Self(id.into())
3131    }
3132}
3133
3134/// Unique identifier for a session configuration option value.
3135#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
3136#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash, From, Display)]
3137#[serde(transparent)]
3138#[from(Arc<str>, String, &'static str)]
3139#[non_exhaustive]
3140pub struct SessionConfigValueId(pub Arc<str>);
3141
3142impl SessionConfigValueId {
3143    /// Wraps a protocol string as a typed [`SessionConfigValueId`].
3144    #[must_use]
3145    pub fn new(id: impl Into<Arc<str>>) -> Self {
3146        Self(id.into())
3147    }
3148}
3149
3150/// Unique identifier for a session configuration option value group.
3151#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
3152#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash, From, Display)]
3153#[serde(transparent)]
3154#[from(Arc<str>, String, &'static str)]
3155#[non_exhaustive]
3156pub struct SessionConfigGroupId(pub Arc<str>);
3157
3158impl SessionConfigGroupId {
3159    /// Wraps a protocol string as a typed [`SessionConfigGroupId`].
3160    #[must_use]
3161    pub fn new(id: impl Into<Arc<str>>) -> Self {
3162        Self(id.into())
3163    }
3164}
3165
3166/// A possible value for a session configuration option.
3167#[serde_as]
3168#[skip_serializing_none]
3169#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
3170#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
3171#[serde(rename_all = "camelCase")]
3172#[non_exhaustive]
3173pub struct SessionConfigSelectOption {
3174    /// Unique identifier for this option value.
3175    pub value: SessionConfigValueId,
3176    /// Human-readable label for this option value.
3177    pub name: String,
3178    /// Optional description for this option value.
3179    #[serde_as(deserialize_as = "DefaultOnError")]
3180    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
3181    #[serde(default)]
3182    pub description: Option<String>,
3183    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
3184    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
3185    /// these keys.
3186    ///
3187    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v1/extensibility)
3188    #[serde_as(deserialize_as = "DefaultOnError")]
3189    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
3190    #[serde(default)]
3191    #[serde(rename = "_meta")]
3192    pub meta: Option<Meta>,
3193}
3194
3195impl SessionConfigSelectOption {
3196    /// Builds [`SessionConfigSelectOption`] with the required fields set. Optional fields start unset or empty.
3197    #[must_use]
3198    pub fn new(value: impl Into<SessionConfigValueId>, name: impl Into<String>) -> Self {
3199        Self {
3200            value: value.into(),
3201            name: name.into(),
3202            description: None,
3203            meta: None,
3204        }
3205    }
3206
3207    /// Sets or clears the optional `description` field.
3208    #[must_use]
3209    pub fn description(mut self, description: impl IntoOption<String>) -> Self {
3210        self.description = description.into_option();
3211        self
3212    }
3213
3214    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
3215    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
3216    /// these keys.
3217    ///
3218    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v1/extensibility)
3219    #[must_use]
3220    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3221        self.meta = meta.into_option();
3222        self
3223    }
3224}
3225
3226/// A group of possible values for a session configuration option.
3227#[serde_as]
3228#[skip_serializing_none]
3229#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
3230#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
3231#[serde(rename_all = "camelCase")]
3232#[non_exhaustive]
3233pub struct SessionConfigSelectGroup {
3234    /// Unique identifier for this group.
3235    pub group: SessionConfigGroupId,
3236    /// Human-readable label for this group.
3237    pub name: String,
3238    /// The set of option values in this group.
3239    #[serde_as(deserialize_as = "DefaultOnError<VecSkipError<_>>")]
3240    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true, "x-deserialize-skip-invalid-items" = true)))]
3241    pub options: Vec<SessionConfigSelectOption>,
3242    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
3243    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
3244    /// these keys.
3245    ///
3246    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v1/extensibility)
3247    #[serde_as(deserialize_as = "DefaultOnError")]
3248    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
3249    #[serde(default)]
3250    #[serde(rename = "_meta")]
3251    pub meta: Option<Meta>,
3252}
3253
3254impl SessionConfigSelectGroup {
3255    /// Builds [`SessionConfigSelectGroup`] with the required fields set. Optional fields start unset or empty.
3256    #[must_use]
3257    pub fn new(
3258        group: impl Into<SessionConfigGroupId>,
3259        name: impl Into<String>,
3260        options: Vec<SessionConfigSelectOption>,
3261    ) -> Self {
3262        Self {
3263            group: group.into(),
3264            name: name.into(),
3265            options,
3266            meta: None,
3267        }
3268    }
3269
3270    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
3271    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
3272    /// these keys.
3273    ///
3274    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v1/extensibility)
3275    #[must_use]
3276    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3277        self.meta = meta.into_option();
3278        self
3279    }
3280}
3281
3282/// Possible values for a session configuration option.
3283#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
3284#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
3285#[serde(untagged)]
3286#[non_exhaustive]
3287pub enum SessionConfigSelectOptions {
3288    /// A flat list of options with no grouping.
3289    Ungrouped(Vec<SessionConfigSelectOption>),
3290    /// A list of options grouped under headers.
3291    Grouped(Vec<SessionConfigSelectGroup>),
3292}
3293
3294impl From<Vec<SessionConfigSelectOption>> for SessionConfigSelectOptions {
3295    fn from(options: Vec<SessionConfigSelectOption>) -> Self {
3296        SessionConfigSelectOptions::Ungrouped(options)
3297    }
3298}
3299
3300impl From<Vec<SessionConfigSelectGroup>> for SessionConfigSelectOptions {
3301    fn from(groups: Vec<SessionConfigSelectGroup>) -> Self {
3302        SessionConfigSelectOptions::Grouped(groups)
3303    }
3304}
3305
3306/// A single-value selector (dropdown) session configuration option payload.
3307#[skip_serializing_none]
3308#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
3309#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
3310#[serde(rename_all = "camelCase")]
3311#[non_exhaustive]
3312pub struct SessionConfigSelect {
3313    /// The currently selected value.
3314    pub current_value: SessionConfigValueId,
3315    /// The set of selectable options.
3316    pub options: SessionConfigSelectOptions,
3317}
3318
3319impl SessionConfigSelect {
3320    /// Builds [`SessionConfigSelect`] with the required fields set. Optional fields start unset or empty.
3321    #[must_use]
3322    pub fn new(
3323        current_value: impl Into<SessionConfigValueId>,
3324        options: impl Into<SessionConfigSelectOptions>,
3325    ) -> Self {
3326        Self {
3327            current_value: current_value.into(),
3328            options: options.into(),
3329        }
3330    }
3331}
3332
3333/// A boolean on/off toggle session configuration option payload.
3334#[skip_serializing_none]
3335#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
3336#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
3337#[serde(rename_all = "camelCase")]
3338#[non_exhaustive]
3339pub struct SessionConfigBoolean {
3340    /// The current value of the boolean option.
3341    pub current_value: bool,
3342}
3343
3344impl SessionConfigBoolean {
3345    /// Builds [`SessionConfigBoolean`] with the required fields set. Optional fields start unset or empty.
3346    #[must_use]
3347    pub fn new(current_value: bool) -> Self {
3348        Self { current_value }
3349    }
3350}
3351
3352/// Semantic category for a session configuration option.
3353///
3354/// This is intended to help Clients distinguish broadly common selectors (e.g. model selector vs
3355/// session mode selector vs thought/reasoning level) for UX purposes (keyboard shortcuts, icons,
3356/// placement). It MUST NOT be required for correctness. Clients MUST handle missing or unknown
3357/// categories gracefully.
3358///
3359/// Category names beginning with `_` are free for custom use, like other ACP extension methods.
3360/// Category names that do not begin with `_` are reserved for the ACP spec.
3361#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
3362#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
3363#[serde(rename_all = "snake_case")]
3364#[non_exhaustive]
3365pub enum SessionConfigOptionCategory {
3366    /// Session mode selector.
3367    Mode,
3368    /// Model selector.
3369    Model,
3370    /// Model-related configuration parameter.
3371    ModelConfig,
3372    /// Thought/reasoning level selector.
3373    ThoughtLevel,
3374    /// Unknown / uncategorized selector.
3375    #[serde(untagged)]
3376    Other(String),
3377}
3378
3379/// Type-specific session configuration option payload.
3380#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
3381#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
3382#[serde(tag = "type", rename_all = "snake_case")]
3383#[cfg_attr(feature = "schemars", schemars(extend("discriminator" = {"propertyName": "type"})))]
3384#[non_exhaustive]
3385pub enum SessionConfigKind {
3386    /// Single-value selector (dropdown).
3387    Select(SessionConfigSelect),
3388    /// Boolean on/off toggle.
3389    Boolean(SessionConfigBoolean),
3390}
3391
3392/// A session configuration option selector and its current state.
3393#[serde_as]
3394#[skip_serializing_none]
3395#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
3396#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
3397#[serde(rename_all = "camelCase")]
3398#[non_exhaustive]
3399pub struct SessionConfigOption {
3400    /// Unique identifier for the configuration option.
3401    pub id: SessionConfigId,
3402    /// Human-readable label for the option.
3403    pub name: String,
3404    /// Optional description for the Client to display to the user.
3405    #[serde_as(deserialize_as = "DefaultOnError")]
3406    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
3407    #[serde(default)]
3408    pub description: Option<String>,
3409    /// Optional semantic category for this option (UX only).
3410    #[serde_as(deserialize_as = "DefaultOnError")]
3411    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
3412    #[serde(default)]
3413    pub category: Option<SessionConfigOptionCategory>,
3414    /// Type-specific fields for this configuration option.
3415    #[serde(flatten)]
3416    pub kind: SessionConfigKind,
3417    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
3418    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
3419    /// these keys.
3420    ///
3421    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v1/extensibility)
3422    #[serde_as(deserialize_as = "DefaultOnError")]
3423    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
3424    #[serde(default)]
3425    #[serde(rename = "_meta")]
3426    pub meta: Option<Meta>,
3427}
3428
3429impl SessionConfigOption {
3430    /// Builds [`SessionConfigOption`] with the required fields set. Optional fields start unset or empty.
3431    #[must_use]
3432    pub fn new(
3433        id: impl Into<SessionConfigId>,
3434        name: impl Into<String>,
3435        kind: SessionConfigKind,
3436    ) -> Self {
3437        Self {
3438            id: id.into(),
3439            name: name.into(),
3440            description: None,
3441            category: None,
3442            kind,
3443            meta: None,
3444        }
3445    }
3446
3447    /// Builds a select-style session configuration option with its current value and choices.
3448    #[must_use]
3449    pub fn select(
3450        id: impl Into<SessionConfigId>,
3451        name: impl Into<String>,
3452        current_value: impl Into<SessionConfigValueId>,
3453        options: impl Into<SessionConfigSelectOptions>,
3454    ) -> Self {
3455        Self::new(
3456            id,
3457            name,
3458            SessionConfigKind::Select(SessionConfigSelect::new(current_value, options)),
3459        )
3460    }
3461
3462    /// Builds a boolean-style session configuration option with its current value.
3463    #[must_use]
3464    pub fn boolean(
3465        id: impl Into<SessionConfigId>,
3466        name: impl Into<String>,
3467        current_value: bool,
3468    ) -> Self {
3469        Self::new(
3470            id,
3471            name,
3472            SessionConfigKind::Boolean(SessionConfigBoolean::new(current_value)),
3473        )
3474    }
3475
3476    /// Sets or clears the optional `description` field.
3477    #[must_use]
3478    pub fn description(mut self, description: impl IntoOption<String>) -> Self {
3479        self.description = description.into_option();
3480        self
3481    }
3482
3483    /// Sets or clears the optional `category` field.
3484    #[must_use]
3485    pub fn category(mut self, category: impl IntoOption<SessionConfigOptionCategory>) -> Self {
3486        self.category = category.into_option();
3487        self
3488    }
3489
3490    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
3491    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
3492    /// these keys.
3493    ///
3494    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v1/extensibility)
3495    #[must_use]
3496    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3497        self.meta = meta.into_option();
3498        self
3499    }
3500}
3501
3502/// The value to set for a session configuration option.
3503///
3504/// The `type` field acts as the discriminator in the serialized JSON form.
3505/// When no `type` is present, the value is treated as a [`SessionConfigValueId`]
3506/// via the [`ValueId`](Self::ValueId) fallback variant.
3507///
3508/// The `type` discriminator describes the *shape* of the value, not the option
3509/// kind. For example every option kind that picks from a list of ids
3510/// (`select`, `radio`, …) would use [`ValueId`](Self::ValueId), while a
3511/// future freeform text option would get its own variant.
3512#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
3513#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
3514#[serde(tag = "type", rename_all = "snake_case")]
3515#[non_exhaustive]
3516pub enum SessionConfigOptionValue {
3517    /// A boolean value (`type: "boolean"`).
3518    Boolean {
3519        /// The boolean value.
3520        value: bool,
3521    },
3522    /// A `SessionConfigValueId` string value.
3523    ///
3524    /// This is the default when `type` is absent on the wire. Unknown `type`
3525    /// values with string payloads also gracefully deserialize into this
3526    /// variant.
3527    #[serde(untagged)]
3528    ValueId {
3529        /// The value ID.
3530        value: SessionConfigValueId,
3531    },
3532}
3533
3534impl SessionConfigOptionValue {
3535    /// Create a value-id option value (used by `select` and other id-based option types).
3536    #[must_use]
3537    pub fn value_id(id: impl Into<SessionConfigValueId>) -> Self {
3538        Self::ValueId { value: id.into() }
3539    }
3540
3541    /// Create a boolean option value.
3542    #[must_use]
3543    pub fn boolean(val: bool) -> Self {
3544        Self::Boolean { value: val }
3545    }
3546
3547    /// Return the inner [`SessionConfigValueId`] if this is a
3548    /// [`ValueId`](Self::ValueId) value.
3549    #[must_use]
3550    pub fn as_value_id(&self) -> Option<&SessionConfigValueId> {
3551        match self {
3552            Self::ValueId { value } => Some(value),
3553            _ => None,
3554        }
3555    }
3556
3557    /// Return the inner [`bool`] if this is a [`Boolean`](Self::Boolean) value.
3558    #[must_use]
3559    pub fn as_bool(&self) -> Option<bool> {
3560        match self {
3561            Self::Boolean { value } => Some(*value),
3562            _ => None,
3563        }
3564    }
3565}
3566
3567impl From<SessionConfigValueId> for SessionConfigOptionValue {
3568    fn from(value: SessionConfigValueId) -> Self {
3569        Self::ValueId { value }
3570    }
3571}
3572
3573impl From<bool> for SessionConfigOptionValue {
3574    fn from(value: bool) -> Self {
3575        Self::Boolean { value }
3576    }
3577}
3578
3579impl From<&str> for SessionConfigOptionValue {
3580    fn from(value: &str) -> Self {
3581        Self::ValueId {
3582            value: SessionConfigValueId::new(value),
3583        }
3584    }
3585}
3586
3587/// Request parameters for setting a session configuration option.
3588#[serde_as]
3589#[skip_serializing_none]
3590#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
3591#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
3592#[cfg_attr(feature = "schemars", schemars(extend("x-side" = "agent", "x-method" = SESSION_SET_CONFIG_OPTION_METHOD_NAME)))]
3593#[serde(rename_all = "camelCase")]
3594#[non_exhaustive]
3595pub struct SetSessionConfigOptionRequest {
3596    /// The ID of the session to set the configuration option for.
3597    pub session_id: SessionId,
3598    /// The ID of the configuration option to set.
3599    pub config_id: SessionConfigId,
3600    /// The value to set, including a `type` discriminator and the raw `value`.
3601    ///
3602    /// When `type` is absent on the wire, defaults to treating the value as a
3603    /// [`SessionConfigValueId`] for `select` options.
3604    #[serde(flatten)]
3605    pub value: SessionConfigOptionValue,
3606    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
3607    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
3608    /// these keys.
3609    ///
3610    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v1/extensibility)
3611    #[serde_as(deserialize_as = "DefaultOnError")]
3612    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
3613    #[serde(default)]
3614    #[serde(rename = "_meta")]
3615    pub meta: Option<Meta>,
3616}
3617
3618impl SetSessionConfigOptionRequest {
3619    /// Builds [`SetSessionConfigOptionRequest`] with the required request fields set. Optional fields start unset or empty.
3620    #[must_use]
3621    pub fn new(
3622        session_id: impl Into<SessionId>,
3623        config_id: impl Into<SessionConfigId>,
3624        value: impl Into<SessionConfigOptionValue>,
3625    ) -> Self {
3626        Self {
3627            session_id: session_id.into(),
3628            config_id: config_id.into(),
3629            value: value.into(),
3630            meta: None,
3631        }
3632    }
3633
3634    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
3635    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
3636    /// these keys.
3637    ///
3638    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v1/extensibility)
3639    #[must_use]
3640    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3641        self.meta = meta.into_option();
3642        self
3643    }
3644}
3645
3646/// Response to `session/set_config_option` method.
3647#[serde_as]
3648#[skip_serializing_none]
3649#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
3650#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
3651#[cfg_attr(feature = "schemars", schemars(extend("x-side" = "agent", "x-method" = SESSION_SET_CONFIG_OPTION_METHOD_NAME)))]
3652#[serde(rename_all = "camelCase")]
3653#[non_exhaustive]
3654pub struct SetSessionConfigOptionResponse {
3655    /// The full set of configuration options and their current values.
3656    #[serde_as(deserialize_as = "DefaultOnError<VecSkipError<_>>")]
3657    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true, "x-deserialize-skip-invalid-items" = true)))]
3658    pub config_options: Vec<SessionConfigOption>,
3659    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
3660    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
3661    /// these keys.
3662    ///
3663    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v1/extensibility)
3664    #[serde_as(deserialize_as = "DefaultOnError")]
3665    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
3666    #[serde(default)]
3667    #[serde(rename = "_meta")]
3668    pub meta: Option<Meta>,
3669}
3670
3671impl SetSessionConfigOptionResponse {
3672    /// Builds [`SetSessionConfigOptionResponse`] with the required response fields set. Optional fields start unset or empty.
3673    #[must_use]
3674    pub fn new(config_options: Vec<SessionConfigOption>) -> Self {
3675        Self {
3676            config_options,
3677            meta: None,
3678        }
3679    }
3680
3681    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
3682    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
3683    /// these keys.
3684    ///
3685    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v1/extensibility)
3686    #[must_use]
3687    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3688        self.meta = meta.into_option();
3689        self
3690    }
3691}
3692
3693// MCP
3694
3695/// Configuration for connecting to an MCP (Model Context Protocol) server.
3696///
3697/// MCP servers provide tools and context that the agent can use when
3698/// processing prompts.
3699///
3700/// See protocol docs: [MCP Servers](https://agentclientprotocol.com/protocol/v1/session-setup#mcp-servers)
3701#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
3702#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
3703#[serde(tag = "type", rename_all = "snake_case")]
3704#[non_exhaustive]
3705pub enum McpServer {
3706    /// HTTP transport configuration
3707    ///
3708    /// Only available when the Agent capabilities indicate `mcp_capabilities.http` is `true`.
3709    Http(McpServerHttp),
3710    /// SSE transport configuration
3711    ///
3712    /// Only available when the Agent capabilities indicate `mcp_capabilities.sse` is `true`.
3713    Sse(McpServerSse),
3714    /// **UNSTABLE**
3715    ///
3716    /// This capability is not part of the spec yet, and may be removed or changed at any point.
3717    ///
3718    /// ACP transport configuration
3719    ///
3720    /// Only available when the Agent capabilities indicate `mcp_capabilities.acp` is `true`.
3721    /// The MCP server is provided by an ACP component and communicates over the ACP channel.
3722    #[cfg(feature = "unstable_mcp_over_acp")]
3723    Acp(McpServerAcp),
3724    /// Stdio transport configuration
3725    ///
3726    /// All Agents MUST support this transport.
3727    #[serde(untagged)]
3728    Stdio(McpServerStdio),
3729}
3730
3731/// HTTP transport configuration for MCP.
3732#[serde_as]
3733#[skip_serializing_none]
3734#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
3735#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
3736#[serde(rename_all = "camelCase")]
3737#[non_exhaustive]
3738pub struct McpServerHttp {
3739    /// Human-readable name identifying this MCP server.
3740    pub name: String,
3741    /// URL to the MCP server.
3742    pub url: String,
3743    /// HTTP headers to set when making requests to the MCP server.
3744    #[serde_as(deserialize_as = "DefaultOnNull")]
3745    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-null" = true)))]
3746    pub headers: Vec<HttpHeader>,
3747    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
3748    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
3749    /// these keys.
3750    ///
3751    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v1/extensibility)
3752    #[serde_as(deserialize_as = "DefaultOnError")]
3753    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
3754    #[serde(default)]
3755    #[serde(rename = "_meta")]
3756    pub meta: Option<Meta>,
3757}
3758
3759impl McpServerHttp {
3760    /// Builds [`McpServerHttp`] with the required fields set. Optional fields start unset or empty.
3761    #[must_use]
3762    pub fn new(name: impl Into<String>, url: impl Into<String>) -> Self {
3763        Self {
3764            name: name.into(),
3765            url: url.into(),
3766            headers: Vec::new(),
3767            meta: None,
3768        }
3769    }
3770
3771    /// HTTP headers to set when making requests to the MCP server.
3772    #[must_use]
3773    pub fn headers(mut self, headers: Vec<HttpHeader>) -> Self {
3774        self.headers = headers;
3775        self
3776    }
3777
3778    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
3779    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
3780    /// these keys.
3781    ///
3782    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v1/extensibility)
3783    #[must_use]
3784    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3785        self.meta = meta.into_option();
3786        self
3787    }
3788}
3789
3790/// SSE transport configuration for MCP.
3791#[serde_as]
3792#[skip_serializing_none]
3793#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
3794#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
3795#[serde(rename_all = "camelCase")]
3796#[non_exhaustive]
3797pub struct McpServerSse {
3798    /// Human-readable name identifying this MCP server.
3799    pub name: String,
3800    /// URL to the MCP server.
3801    pub url: String,
3802    /// HTTP headers to set when making requests to the MCP server.
3803    #[serde_as(deserialize_as = "DefaultOnNull")]
3804    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-null" = true)))]
3805    pub headers: Vec<HttpHeader>,
3806    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
3807    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
3808    /// these keys.
3809    ///
3810    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v1/extensibility)
3811    #[serde_as(deserialize_as = "DefaultOnError")]
3812    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
3813    #[serde(default)]
3814    #[serde(rename = "_meta")]
3815    pub meta: Option<Meta>,
3816}
3817
3818impl McpServerSse {
3819    /// Builds [`McpServerSse`] with the required fields set. Optional fields start unset or empty.
3820    #[must_use]
3821    pub fn new(name: impl Into<String>, url: impl Into<String>) -> Self {
3822        Self {
3823            name: name.into(),
3824            url: url.into(),
3825            headers: Vec::new(),
3826            meta: None,
3827        }
3828    }
3829
3830    /// HTTP headers to set when making requests to the MCP server.
3831    #[must_use]
3832    pub fn headers(mut self, headers: Vec<HttpHeader>) -> Self {
3833        self.headers = headers;
3834        self
3835    }
3836
3837    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
3838    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
3839    /// these keys.
3840    ///
3841    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v1/extensibility)
3842    #[must_use]
3843    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3844        self.meta = meta.into_option();
3845        self
3846    }
3847}
3848
3849/// **UNSTABLE**
3850///
3851/// This capability is not part of the spec yet, and may be removed or changed at any point.
3852///
3853/// Unique identifier for an MCP server using the ACP transport.
3854///
3855/// The value is opaque and generated by the ACP component providing the MCP server. It is
3856/// used by `mcp/message` to route requests to the component that declared the server.
3857#[cfg(feature = "unstable_mcp_over_acp")]
3858#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
3859#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash, Display, From)]
3860#[serde(transparent)]
3861#[from(Arc<str>, String, &'static str)]
3862#[non_exhaustive]
3863pub struct McpServerAcpId(pub Arc<str>);
3864
3865#[cfg(feature = "unstable_mcp_over_acp")]
3866impl McpServerAcpId {
3867    /// Wraps a protocol string as a typed [`McpServerAcpId`].
3868    #[must_use]
3869    pub fn new(id: impl Into<Arc<str>>) -> Self {
3870        Self(id.into())
3871    }
3872}
3873
3874/// **UNSTABLE**
3875///
3876/// This capability is not part of the spec yet, and may be removed or changed at any point.
3877///
3878/// ACP transport configuration for MCP.
3879///
3880/// The MCP server is provided by an ACP component and communicates over the ACP channel
3881/// using `mcp/message`.
3882#[serde_as]
3883#[skip_serializing_none]
3884#[cfg(feature = "unstable_mcp_over_acp")]
3885#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
3886#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
3887#[serde(rename_all = "camelCase")]
3888#[non_exhaustive]
3889pub struct McpServerAcp {
3890    /// Human-readable name identifying this MCP server.
3891    pub name: String,
3892    /// Unique identifier for this MCP server, generated by the component providing it.
3893    ///
3894    /// Providers MUST NOT reuse an ID for multiple ACP-transport MCP servers that are visible
3895    /// on the same ACP connection.
3896    pub server_id: McpServerAcpId,
3897    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
3898    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
3899    /// these keys.
3900    ///
3901    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v1/extensibility)
3902    #[serde_as(deserialize_as = "DefaultOnError")]
3903    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
3904    #[serde(default)]
3905    #[serde(rename = "_meta")]
3906    pub meta: Option<Meta>,
3907}
3908
3909#[cfg(feature = "unstable_mcp_over_acp")]
3910impl McpServerAcp {
3911    /// Builds [`McpServerAcp`] with the required fields set. Optional fields start unset or empty.
3912    #[must_use]
3913    pub fn new(name: impl Into<String>, id: impl Into<McpServerAcpId>) -> Self {
3914        Self {
3915            name: name.into(),
3916            server_id: id.into(),
3917            meta: None,
3918        }
3919    }
3920
3921    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
3922    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
3923    /// these keys.
3924    ///
3925    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v1/extensibility)
3926    #[must_use]
3927    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3928        self.meta = meta.into_option();
3929        self
3930    }
3931}
3932
3933/// Stdio transport configuration for MCP.
3934#[serde_as]
3935#[skip_serializing_none]
3936#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
3937#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
3938#[serde(rename_all = "camelCase")]
3939#[non_exhaustive]
3940pub struct McpServerStdio {
3941    /// Human-readable name identifying this MCP server.
3942    pub name: String,
3943    /// Absolute path to the MCP server executable.
3944    pub command: PathBuf,
3945    /// Command-line arguments to pass to the MCP server.
3946    #[serde_as(deserialize_as = "DefaultOnNull")]
3947    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-null" = true)))]
3948    pub args: Vec<String>,
3949    /// Environment variables to set when launching the MCP server.
3950    #[serde_as(deserialize_as = "DefaultOnNull")]
3951    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-null" = true)))]
3952    pub env: Vec<EnvVariable>,
3953    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
3954    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
3955    /// these keys.
3956    ///
3957    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v1/extensibility)
3958    #[serde_as(deserialize_as = "DefaultOnError")]
3959    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
3960    #[serde(default)]
3961    #[serde(rename = "_meta")]
3962    pub meta: Option<Meta>,
3963}
3964
3965impl McpServerStdio {
3966    /// Builds [`McpServerStdio`] with the required fields set. Optional fields start unset or empty.
3967    #[must_use]
3968    pub fn new(name: impl Into<String>, command: impl Into<PathBuf>) -> Self {
3969        Self {
3970            name: name.into(),
3971            command: command.into(),
3972            args: Vec::new(),
3973            env: Vec::new(),
3974            meta: None,
3975        }
3976    }
3977
3978    /// Command-line arguments to pass to the MCP server.
3979    #[must_use]
3980    pub fn args(mut self, args: Vec<String>) -> Self {
3981        self.args = args;
3982        self
3983    }
3984
3985    /// Environment variables to set when launching the MCP server.
3986    #[must_use]
3987    pub fn env(mut self, env: Vec<EnvVariable>) -> Self {
3988        self.env = env;
3989        self
3990    }
3991
3992    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
3993    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
3994    /// these keys.
3995    ///
3996    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v1/extensibility)
3997    #[must_use]
3998    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3999        self.meta = meta.into_option();
4000        self
4001    }
4002}
4003
4004/// An environment variable to set when launching an MCP server.
4005#[serde_as]
4006#[skip_serializing_none]
4007#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
4008#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
4009#[serde(rename_all = "camelCase")]
4010#[non_exhaustive]
4011pub struct EnvVariable {
4012    /// The name of the environment variable.
4013    pub name: String,
4014    /// The value to set for the environment variable.
4015    pub value: String,
4016    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
4017    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
4018    /// these keys.
4019    ///
4020    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v1/extensibility)
4021    #[serde_as(deserialize_as = "DefaultOnError")]
4022    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
4023    #[serde(default)]
4024    #[serde(rename = "_meta")]
4025    pub meta: Option<Meta>,
4026}
4027
4028impl EnvVariable {
4029    /// Builds [`EnvVariable`] with the required fields set. Optional fields start unset or empty.
4030    #[must_use]
4031    pub fn new(name: impl Into<String>, value: impl Into<String>) -> Self {
4032        Self {
4033            name: name.into(),
4034            value: value.into(),
4035            meta: None,
4036        }
4037    }
4038
4039    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
4040    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
4041    /// these keys.
4042    ///
4043    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v1/extensibility)
4044    #[must_use]
4045    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4046        self.meta = meta.into_option();
4047        self
4048    }
4049}
4050
4051/// An HTTP header to set when making requests to the MCP server.
4052#[serde_as]
4053#[skip_serializing_none]
4054#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
4055#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
4056#[serde(rename_all = "camelCase")]
4057#[non_exhaustive]
4058pub struct HttpHeader {
4059    /// The name of the HTTP header.
4060    pub name: String,
4061    /// The value to set for the HTTP header.
4062    pub value: String,
4063    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
4064    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
4065    /// these keys.
4066    ///
4067    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v1/extensibility)
4068    #[serde_as(deserialize_as = "DefaultOnError")]
4069    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
4070    #[serde(default)]
4071    #[serde(rename = "_meta")]
4072    pub meta: Option<Meta>,
4073}
4074
4075impl HttpHeader {
4076    /// Builds [`HttpHeader`] with the required fields set. Optional fields start unset or empty.
4077    #[must_use]
4078    pub fn new(name: impl Into<String>, value: impl Into<String>) -> Self {
4079        Self {
4080            name: name.into(),
4081            value: value.into(),
4082            meta: None,
4083        }
4084    }
4085
4086    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
4087    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
4088    /// these keys.
4089    ///
4090    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v1/extensibility)
4091    #[must_use]
4092    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4093        self.meta = meta.into_option();
4094        self
4095    }
4096}
4097
4098// System prompt
4099
4100/// Client-provided system-level instructions for a session.
4101///
4102/// Clients MUST only send this when the Agent advertises
4103/// `sessionCapabilities.systemPrompt`. Agents that cannot apply it, for example
4104/// because of an unadvertised mode or an unsupported content block type, MUST
4105/// return an error instead of creating, loading, or resuming the session.
4106#[serde_as]
4107#[skip_serializing_none]
4108#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
4109#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
4110#[serde(rename_all = "camelCase")]
4111#[non_exhaustive]
4112pub struct SystemPrompt {
4113    /// How the Agent combines `content` with its own instructions.
4114    ///
4115    /// Required. Agents MUST return an error for a mode they do not support rather than
4116    /// treating it as `append` or `override`.
4117    pub mode: SystemPromptMode,
4118    /// The system prompt content.
4119    ///
4120    /// Agents advertising the capability MUST accept `text` content blocks.
4121    /// Clients MUST NOT send other content block types until a future
4122    /// capability allows them, and Agents MUST return an error for content
4123    /// blocks they do not support.
4124    ///
4125    /// Clients MUST NOT send an empty array. Agents MAY reject one with
4126    /// `-32602` without creating, loading, or resuming the session.
4127    pub content: Vec<ContentBlock>,
4128    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
4129    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
4130    /// these keys.
4131    ///
4132    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v1/extensibility)
4133    #[serde_as(deserialize_as = "DefaultOnError")]
4134    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
4135    #[serde(default)]
4136    #[serde(rename = "_meta")]
4137    pub meta: Option<Meta>,
4138}
4139
4140impl SystemPrompt {
4141    /// Builds [`SystemPrompt`] with the required fields set. Optional fields start unset or empty.
4142    ///
4143    /// `mode` starts as [`SystemPromptMode::Append`]. Use [`SystemPrompt::mode`]
4144    /// to request another mode.
4145    #[must_use]
4146    pub fn new(content: Vec<ContentBlock>) -> Self {
4147        Self {
4148            mode: SystemPromptMode::default(),
4149            content,
4150            meta: None,
4151        }
4152    }
4153
4154    /// How the Agent combines `content` with its own instructions.
4155    #[must_use]
4156    pub fn mode(mut self, mode: SystemPromptMode) -> Self {
4157        self.mode = mode;
4158        self
4159    }
4160
4161    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
4162    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
4163    /// these keys.
4164    ///
4165    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v1/extensibility)
4166    #[must_use]
4167    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4168        self.meta = meta.into_option();
4169        self
4170    }
4171}
4172
4173/// How the Agent combines a client-provided system prompt with its own instructions.
4174///
4175/// Unknown modes are preserved so they can be stored,
4176/// proxied, or forwarded. An Agent MUST return an error for a mode it does not
4177/// support rather than treating it as `append` or `override`.
4178#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
4179#[derive(Debug, Default, Clone, PartialEq, Eq, Serialize, Deserialize)]
4180#[serde(rename_all = "snake_case")]
4181#[non_exhaustive]
4182pub enum SystemPromptMode {
4183    /// Add the content to the Agent's own instructions rather than replacing them.
4184    ///
4185    /// Every Agent that advertises `sessionCapabilities.systemPrompt` supports this mode.
4186    /// Agents SHOULD give the content system-level precedence, for example in the
4187    /// model's system prompt or developer instructions rather than in user-turn
4188    /// content. Where it is placed and how it is formatted is implementation-defined.
4189    #[default]
4190    Append,
4191    /// Replace the Agent's built-in default instructions with the content.
4192    ///
4193    /// This does not change tool availability, MCP servers, permissions, or session
4194    /// configuration. Context the Agent supplies from the workspace or environment
4195    /// MAY still be included. Clients that use this mode take responsibility for any
4196    /// tool guidance or safety instructions the Agent's default instructions
4197    /// provided, and MUST only use it when the Agent advertises
4198    /// `sessionCapabilities.systemPrompt.mode.override`.
4199    Override,
4200    /// Custom or future system prompt mode.
4201    ///
4202    /// Values beginning with `_` are reserved for implementation-specific
4203    /// extensions. Unknown values that do not begin with `_` are reserved for
4204    /// future ACP variants.
4205    #[serde(untagged)]
4206    Other(String),
4207}
4208
4209// Prompt
4210
4211/// Request parameters for sending a user prompt to the agent.
4212///
4213/// Contains the user's message and any additional context.
4214///
4215/// See protocol docs: [User Message](https://agentclientprotocol.com/protocol/v1/prompt-turn#1-user-message)
4216#[serde_as]
4217#[skip_serializing_none]
4218#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
4219#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
4220#[cfg_attr(feature = "schemars", schemars(extend("x-side" = "agent", "x-method" = SESSION_PROMPT_METHOD_NAME)))]
4221#[serde(rename_all = "camelCase")]
4222#[non_exhaustive]
4223pub struct PromptRequest {
4224    /// The ID of the session to send this user message to
4225    pub session_id: SessionId,
4226    /// The blocks of content that compose the user's message.
4227    ///
4228    /// As a baseline, the Agent MUST support `text` and `resource_link` content blocks,
4229    /// while other variants are optionally enabled via `PromptCapabilities`.
4230    ///
4231    /// The Client MUST adapt its interface according to `PromptCapabilities`.
4232    ///
4233    /// The client MAY include referenced pieces of context as either
4234    /// `resource` or `resource_link` content blocks.
4235    ///
4236    /// When available, `resource` is preferred
4237    /// as it avoids extra round-trips and allows the message to include
4238    /// pieces of context from sources the agent may not have access to.
4239    pub prompt: Vec<ContentBlock>,
4240    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
4241    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
4242    /// these keys.
4243    ///
4244    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v1/extensibility)
4245    #[serde_as(deserialize_as = "DefaultOnError")]
4246    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
4247    #[serde(default)]
4248    #[serde(rename = "_meta")]
4249    pub meta: Option<Meta>,
4250}
4251
4252impl PromptRequest {
4253    /// Builds [`PromptRequest`] with the required request fields set. Optional fields start unset or empty.
4254    #[must_use]
4255    pub fn new(session_id: impl Into<SessionId>, prompt: Vec<ContentBlock>) -> Self {
4256        Self {
4257            session_id: session_id.into(),
4258            prompt,
4259            meta: None,
4260        }
4261    }
4262
4263    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
4264    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
4265    /// these keys.
4266    ///
4267    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v1/extensibility)
4268    #[must_use]
4269    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4270        self.meta = meta.into_option();
4271        self
4272    }
4273}
4274
4275/// Response from processing a user prompt.
4276///
4277/// See protocol docs: [Check for Completion](https://agentclientprotocol.com/protocol/v1/prompt-turn#4-check-for-completion)
4278#[serde_as]
4279#[skip_serializing_none]
4280#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
4281#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
4282#[cfg_attr(feature = "schemars", schemars(extend("x-side" = "agent", "x-method" = SESSION_PROMPT_METHOD_NAME)))]
4283#[serde(rename_all = "camelCase")]
4284#[non_exhaustive]
4285pub struct PromptResponse {
4286    /// Indicates why the agent stopped processing the turn.
4287    pub stop_reason: StopReason,
4288    /// **UNSTABLE**
4289    ///
4290    /// This capability is not part of the spec yet, and may be removed or changed at any point.
4291    ///
4292    /// Token usage for this turn (optional).
4293    #[cfg(feature = "unstable_end_turn_token_usage")]
4294    #[serde_as(deserialize_as = "DefaultOnError")]
4295    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
4296    #[serde(default)]
4297    pub usage: Option<Usage>,
4298    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
4299    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
4300    /// these keys.
4301    ///
4302    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v1/extensibility)
4303    #[serde_as(deserialize_as = "DefaultOnError")]
4304    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
4305    #[serde(default)]
4306    #[serde(rename = "_meta")]
4307    pub meta: Option<Meta>,
4308}
4309
4310impl PromptResponse {
4311    /// Builds [`PromptResponse`] with the required response fields set. Optional fields start unset or empty.
4312    #[must_use]
4313    pub fn new(stop_reason: StopReason) -> Self {
4314        Self {
4315            stop_reason,
4316            #[cfg(feature = "unstable_end_turn_token_usage")]
4317            usage: None,
4318            meta: None,
4319        }
4320    }
4321
4322    /// **UNSTABLE**
4323    ///
4324    /// This capability is not part of the spec yet, and may be removed or changed at any point.
4325    ///
4326    /// Token usage for this turn.
4327    #[cfg(feature = "unstable_end_turn_token_usage")]
4328    #[must_use]
4329    pub fn usage(mut self, usage: impl IntoOption<Usage>) -> Self {
4330        self.usage = usage.into_option();
4331        self
4332    }
4333
4334    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
4335    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
4336    /// these keys.
4337    ///
4338    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v1/extensibility)
4339    #[must_use]
4340    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4341        self.meta = meta.into_option();
4342        self
4343    }
4344}
4345
4346/// Reasons why an agent stops processing a prompt turn.
4347///
4348/// See protocol docs: [Stop Reasons](https://agentclientprotocol.com/protocol/v1/prompt-turn#stop-reasons)
4349#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
4350#[derive(Debug, Copy, Clone, Eq, PartialEq, Serialize, Deserialize)]
4351#[serde(rename_all = "snake_case")]
4352#[non_exhaustive]
4353pub enum StopReason {
4354    /// The turn ended successfully.
4355    EndTurn,
4356    /// The turn ended because the agent reached the maximum number of tokens.
4357    MaxTokens,
4358    /// The turn ended because the agent reached the maximum number of allowed
4359    /// agent requests between user turns.
4360    MaxTurnRequests,
4361    /// The turn ended because the agent refused to continue. The user prompt
4362    /// and everything that comes after it won't be included in the next
4363    /// prompt, so this should be reflected in the UI.
4364    Refusal,
4365    /// The turn was cancelled by the client via `session/cancel`.
4366    ///
4367    /// This stop reason MUST be returned when the client sends a `session/cancel`
4368    /// notification, even if the cancellation causes exceptions in underlying operations.
4369    /// Agents should catch these exceptions and return this semantically meaningful
4370    /// response to confirm successful cancellation.
4371    Cancelled,
4372}
4373
4374/// **UNSTABLE**
4375///
4376/// This capability is not part of the spec yet, and may be removed or changed at any point.
4377///
4378/// Token usage information for a prompt turn.
4379#[cfg(feature = "unstable_end_turn_token_usage")]
4380#[serde_as]
4381#[skip_serializing_none]
4382#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
4383#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
4384#[serde(rename_all = "camelCase")]
4385#[non_exhaustive]
4386pub struct Usage {
4387    /// Sum of all token types across session.
4388    pub total_tokens: u64,
4389    /// Total input tokens across all turns.
4390    pub input_tokens: u64,
4391    /// Total output tokens across all turns.
4392    pub output_tokens: u64,
4393    /// Total thought/reasoning tokens
4394    #[serde_as(deserialize_as = "DefaultOnError")]
4395    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
4396    #[serde(default)]
4397    pub thought_tokens: Option<u64>,
4398    /// Total cache read tokens.
4399    #[serde_as(deserialize_as = "DefaultOnError")]
4400    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
4401    #[serde(default)]
4402    pub cached_read_tokens: Option<u64>,
4403    /// Total cache write tokens.
4404    #[serde_as(deserialize_as = "DefaultOnError")]
4405    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
4406    #[serde(default)]
4407    pub cached_write_tokens: Option<u64>,
4408    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
4409    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
4410    /// these keys.
4411    ///
4412    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v1/extensibility)
4413    #[serde_as(deserialize_as = "DefaultOnError")]
4414    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
4415    #[serde(default)]
4416    #[serde(rename = "_meta")]
4417    pub meta: Option<Meta>,
4418}
4419
4420#[cfg(feature = "unstable_end_turn_token_usage")]
4421impl Usage {
4422    /// Builds [`Usage`] with the required fields set. Optional fields start unset or empty.
4423    #[must_use]
4424    pub fn new(total_tokens: u64, input_tokens: u64, output_tokens: u64) -> Self {
4425        Self {
4426            total_tokens,
4427            input_tokens,
4428            output_tokens,
4429            thought_tokens: None,
4430            cached_read_tokens: None,
4431            cached_write_tokens: None,
4432            meta: None,
4433        }
4434    }
4435
4436    /// Total thought/reasoning tokens
4437    #[must_use]
4438    pub fn thought_tokens(mut self, thought_tokens: impl IntoOption<u64>) -> Self {
4439        self.thought_tokens = thought_tokens.into_option();
4440        self
4441    }
4442
4443    /// Total cache read tokens.
4444    #[must_use]
4445    pub fn cached_read_tokens(mut self, cached_read_tokens: impl IntoOption<u64>) -> Self {
4446        self.cached_read_tokens = cached_read_tokens.into_option();
4447        self
4448    }
4449
4450    /// Total cache write tokens.
4451    #[must_use]
4452    pub fn cached_write_tokens(mut self, cached_write_tokens: impl IntoOption<u64>) -> Self {
4453        self.cached_write_tokens = cached_write_tokens.into_option();
4454        self
4455    }
4456
4457    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
4458    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
4459    /// these keys.
4460    ///
4461    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v1/extensibility)
4462    #[must_use]
4463    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4464        self.meta = meta.into_option();
4465        self
4466    }
4467}
4468
4469// Providers
4470
4471/// **UNSTABLE**
4472///
4473/// This capability is not part of the spec yet, and may be removed or changed at any point.
4474///
4475/// Well-known API protocol identifiers for LLM providers.
4476///
4477/// Agents and clients MUST handle unknown protocol identifiers gracefully.
4478///
4479/// Protocol names beginning with `_` are free for custom use, like other ACP extension methods.
4480/// Protocol names that do not begin with `_` are reserved for the ACP spec.
4481#[cfg(feature = "unstable_llm_providers")]
4482#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
4483#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
4484#[serde(rename_all = "snake_case")]
4485#[non_exhaustive]
4486#[expect(clippy::doc_markdown)]
4487pub enum LlmProtocol {
4488    /// Anthropic API protocol.
4489    Anthropic,
4490    /// OpenAI API protocol.
4491    #[serde(rename = "openai")]
4492    OpenAi,
4493    /// Azure OpenAI API protocol.
4494    Azure,
4495    /// Google Vertex AI API protocol.
4496    Vertex,
4497    /// AWS Bedrock API protocol.
4498    Bedrock,
4499    /// Unknown or custom protocol.
4500    #[serde(untagged)]
4501    Other(String),
4502}
4503
4504/// **UNSTABLE**
4505///
4506/// This capability is not part of the spec yet, and may be removed or changed at any point.
4507///
4508/// Current effective non-secret routing configuration for a provider.
4509#[cfg(feature = "unstable_llm_providers")]
4510#[serde_as]
4511#[skip_serializing_none]
4512#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
4513#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
4514#[serde(rename_all = "camelCase")]
4515#[non_exhaustive]
4516pub struct ProviderCurrentConfig {
4517    /// Protocol currently used by this provider.
4518    pub api_type: LlmProtocol,
4519    /// Base URL currently used by this provider.
4520    pub base_url: String,
4521    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
4522    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
4523    /// these keys.
4524    ///
4525    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v1/extensibility)
4526    #[serde_as(deserialize_as = "DefaultOnError")]
4527    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
4528    #[serde(default)]
4529    #[serde(rename = "_meta")]
4530    pub meta: Option<Meta>,
4531}
4532
4533#[cfg(feature = "unstable_llm_providers")]
4534impl ProviderCurrentConfig {
4535    /// Builds [`ProviderCurrentConfig`] with the required fields set. Optional fields start unset or empty.
4536    #[must_use]
4537    pub fn new(api_type: LlmProtocol, base_url: impl Into<String>) -> Self {
4538        Self {
4539            api_type,
4540            base_url: base_url.into(),
4541            meta: None,
4542        }
4543    }
4544
4545    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
4546    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
4547    /// these keys.
4548    ///
4549    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v1/extensibility)
4550    #[must_use]
4551    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4552        self.meta = meta.into_option();
4553        self
4554    }
4555}
4556
4557/// **UNSTABLE**
4558///
4559/// This capability is not part of the spec yet, and may be removed or changed at any point.
4560///
4561/// Unique identifier for a configurable LLM provider.
4562#[cfg(feature = "unstable_llm_providers")]
4563#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
4564#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash, Display, From)]
4565#[serde(transparent)]
4566#[from(Arc<str>, String, &'static str)]
4567#[non_exhaustive]
4568pub struct ProviderId(pub Arc<str>);
4569
4570#[cfg(feature = "unstable_llm_providers")]
4571impl ProviderId {
4572    /// Wraps a protocol string as a typed [`ProviderId`].
4573    #[must_use]
4574    pub fn new(id: impl Into<Arc<str>>) -> Self {
4575        Self(id.into())
4576    }
4577}
4578
4579/// **UNSTABLE**
4580///
4581/// This capability is not part of the spec yet, and may be removed or changed at any point.
4582///
4583/// Information about a configurable LLM provider.
4584#[cfg(feature = "unstable_llm_providers")]
4585#[serde_as]
4586#[skip_serializing_none]
4587#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
4588#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
4589#[serde(rename_all = "camelCase")]
4590#[non_exhaustive]
4591pub struct ProviderInfo {
4592    /// Provider identifier, for example "main" or "openai".
4593    pub provider_id: ProviderId,
4594    /// Supported protocol types for this provider.
4595    #[serde_as(deserialize_as = "DefaultOnError<VecSkipError<_>>")]
4596    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true, "x-deserialize-skip-invalid-items" = true)))]
4597    pub supported: Vec<LlmProtocol>,
4598    /// Whether this provider is mandatory and cannot be disabled via `providers/disable`.
4599    /// If true, clients must not call `providers/disable` for this provider ID.
4600    pub required: bool,
4601    /// Current effective non-secret routing config.
4602    /// Null or omitted means provider is disabled.
4603    #[serde(default)]
4604    pub current: Option<ProviderCurrentConfig>,
4605    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
4606    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
4607    /// these keys.
4608    ///
4609    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v1/extensibility)
4610    #[serde_as(deserialize_as = "DefaultOnError")]
4611    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
4612    #[serde(default)]
4613    #[serde(rename = "_meta")]
4614    pub meta: Option<Meta>,
4615}
4616
4617#[cfg(feature = "unstable_llm_providers")]
4618impl ProviderInfo {
4619    /// Builds [`ProviderInfo`] with the required fields set. Optional fields start unset or empty.
4620    #[must_use]
4621    pub fn new(
4622        provider_id: impl Into<ProviderId>,
4623        supported: Vec<LlmProtocol>,
4624        required: bool,
4625        current: impl IntoOption<ProviderCurrentConfig>,
4626    ) -> Self {
4627        Self {
4628            provider_id: provider_id.into(),
4629            supported,
4630            required,
4631            current: current.into_option(),
4632            meta: None,
4633        }
4634    }
4635
4636    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
4637    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
4638    /// these keys.
4639    ///
4640    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v1/extensibility)
4641    #[must_use]
4642    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4643        self.meta = meta.into_option();
4644        self
4645    }
4646}
4647
4648#[cfg(feature = "unstable_llm_providers")]
4649crate::serde_util::default_on_null! {
4650    /// **UNSTABLE**
4651    ///
4652    /// This capability is not part of the spec yet, and may be removed or changed at any point.
4653    ///
4654    /// Request parameters for `providers/list`.
4655    #[serde_as]
4656    #[skip_serializing_none]
4657    #[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
4658    #[derive(Default, Debug, Clone, Serialize, PartialEq, Eq)]
4659    #[cfg_attr(feature = "schemars", schemars(extend("x-side" = "agent", "x-method" = PROVIDERS_LIST_METHOD_NAME)))]
4660    #[serde(rename_all = "camelCase")]
4661    #[non_exhaustive]
4662    pub struct ListProvidersRequest {
4663        /// The _meta property is reserved by ACP to allow clients and agents to attach additional
4664        /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
4665        /// these keys.
4666        ///
4667        /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v1/extensibility)
4668        #[serde_as(deserialize_as = "DefaultOnError")]
4669        #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
4670        #[serde(default)]
4671        #[serde(rename = "_meta")]
4672        pub meta: Option<Meta>,
4673    }
4674}
4675
4676#[cfg(feature = "unstable_llm_providers")]
4677impl ListProvidersRequest {
4678    /// Builds [`ListProvidersRequest`] with the required request fields set. Optional fields start unset or empty.
4679    #[must_use]
4680    pub fn new() -> Self {
4681        Self::default()
4682    }
4683
4684    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
4685    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
4686    /// these keys.
4687    ///
4688    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v1/extensibility)
4689    #[must_use]
4690    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4691        self.meta = meta.into_option();
4692        self
4693    }
4694}
4695
4696/// **UNSTABLE**
4697///
4698/// This capability is not part of the spec yet, and may be removed or changed at any point.
4699///
4700/// Response to `providers/list`.
4701#[cfg(feature = "unstable_llm_providers")]
4702#[serde_as]
4703#[skip_serializing_none]
4704#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
4705#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
4706#[cfg_attr(feature = "schemars", schemars(extend("x-side" = "agent", "x-method" = PROVIDERS_LIST_METHOD_NAME)))]
4707#[serde(rename_all = "camelCase")]
4708#[non_exhaustive]
4709pub struct ListProvidersResponse {
4710    /// Configurable providers with current routing info suitable for UI display.
4711    pub providers: Vec<ProviderInfo>,
4712    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
4713    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
4714    /// these keys.
4715    ///
4716    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v1/extensibility)
4717    #[serde_as(deserialize_as = "DefaultOnError")]
4718    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
4719    #[serde(default)]
4720    #[serde(rename = "_meta")]
4721    pub meta: Option<Meta>,
4722}
4723
4724#[cfg(feature = "unstable_llm_providers")]
4725impl ListProvidersResponse {
4726    /// Builds [`ListProvidersResponse`] with the required response fields set. Optional fields start unset or empty.
4727    #[must_use]
4728    pub fn new(providers: Vec<ProviderInfo>) -> Self {
4729        Self {
4730            providers,
4731            meta: None,
4732        }
4733    }
4734
4735    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
4736    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
4737    /// these keys.
4738    ///
4739    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v1/extensibility)
4740    #[must_use]
4741    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4742        self.meta = meta.into_option();
4743        self
4744    }
4745}
4746
4747/// **UNSTABLE**
4748///
4749/// This capability is not part of the spec yet, and may be removed or changed at any point.
4750///
4751/// Request parameters for `providers/set`.
4752///
4753/// Replaces the full configuration for one provider ID.
4754#[cfg(feature = "unstable_llm_providers")]
4755#[serde_as]
4756#[skip_serializing_none]
4757#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
4758#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
4759#[cfg_attr(feature = "schemars", schemars(extend("x-side" = "agent", "x-method" = PROVIDERS_SET_METHOD_NAME)))]
4760#[serde(rename_all = "camelCase")]
4761#[non_exhaustive]
4762pub struct SetProviderRequest {
4763    /// Provider ID to configure.
4764    pub provider_id: ProviderId,
4765    /// Protocol type for this provider.
4766    pub api_type: LlmProtocol,
4767    /// Base URL for requests sent through this provider.
4768    pub base_url: String,
4769    /// Full headers map for this provider.
4770    /// May include authorization, routing, or other integration-specific headers.
4771    #[serde(default, skip_serializing_if = "HashMap::is_empty")]
4772    pub headers: HashMap<String, String>,
4773    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
4774    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
4775    /// these keys.
4776    ///
4777    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v1/extensibility)
4778    #[serde_as(deserialize_as = "DefaultOnError")]
4779    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
4780    #[serde(default)]
4781    #[serde(rename = "_meta")]
4782    pub meta: Option<Meta>,
4783}
4784
4785#[cfg(feature = "unstable_llm_providers")]
4786impl SetProviderRequest {
4787    /// Builds [`SetProviderRequest`] with the required request fields set. Optional fields start unset or empty.
4788    #[must_use]
4789    pub fn new(
4790        provider_id: impl Into<ProviderId>,
4791        api_type: LlmProtocol,
4792        base_url: impl Into<String>,
4793    ) -> Self {
4794        Self {
4795            provider_id: provider_id.into(),
4796            api_type,
4797            base_url: base_url.into(),
4798            headers: HashMap::new(),
4799            meta: None,
4800        }
4801    }
4802
4803    /// Full headers map for this provider.
4804    /// May include authorization, routing, or other integration-specific headers.
4805    #[must_use]
4806    pub fn headers(mut self, headers: HashMap<String, String>) -> Self {
4807        self.headers = headers;
4808        self
4809    }
4810
4811    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
4812    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
4813    /// these keys.
4814    ///
4815    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v1/extensibility)
4816    #[must_use]
4817    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4818        self.meta = meta.into_option();
4819        self
4820    }
4821}
4822
4823#[cfg(feature = "unstable_llm_providers")]
4824crate::serde_util::default_on_null! {
4825    /// **UNSTABLE**
4826    ///
4827    /// This capability is not part of the spec yet, and may be removed or changed at any point.
4828    ///
4829    /// Response to `providers/set`.
4830    #[serde_as]
4831    #[skip_serializing_none]
4832    #[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
4833    #[derive(Default, Debug, Clone, Serialize, PartialEq, Eq)]
4834    #[cfg_attr(feature = "schemars", schemars(extend("x-side" = "agent", "x-method" = PROVIDERS_SET_METHOD_NAME)))]
4835    #[serde(rename_all = "camelCase")]
4836    #[non_exhaustive]
4837    pub struct SetProviderResponse {
4838        /// The _meta property is reserved by ACP to allow clients and agents to attach additional
4839        /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
4840        /// these keys.
4841        ///
4842        /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v1/extensibility)
4843        #[serde_as(deserialize_as = "DefaultOnError")]
4844        #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
4845        #[serde(default)]
4846        #[serde(rename = "_meta")]
4847        pub meta: Option<Meta>,
4848    }
4849}
4850
4851#[cfg(feature = "unstable_llm_providers")]
4852impl SetProviderResponse {
4853    /// Builds [`SetProviderResponse`] with the required response fields set. Optional fields start unset or empty.
4854    #[must_use]
4855    pub fn new() -> Self {
4856        Self::default()
4857    }
4858
4859    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
4860    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
4861    /// these keys.
4862    ///
4863    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v1/extensibility)
4864    #[must_use]
4865    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4866        self.meta = meta.into_option();
4867        self
4868    }
4869}
4870
4871/// **UNSTABLE**
4872///
4873/// This capability is not part of the spec yet, and may be removed or changed at any point.
4874///
4875/// Request parameters for `providers/disable`.
4876#[cfg(feature = "unstable_llm_providers")]
4877#[serde_as]
4878#[skip_serializing_none]
4879#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
4880#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
4881#[cfg_attr(feature = "schemars", schemars(extend("x-side" = "agent", "x-method" = PROVIDERS_DISABLE_METHOD_NAME)))]
4882#[serde(rename_all = "camelCase")]
4883#[non_exhaustive]
4884pub struct DisableProviderRequest {
4885    /// Provider ID to disable.
4886    pub provider_id: ProviderId,
4887    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
4888    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
4889    /// these keys.
4890    ///
4891    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v1/extensibility)
4892    #[serde_as(deserialize_as = "DefaultOnError")]
4893    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
4894    #[serde(default)]
4895    #[serde(rename = "_meta")]
4896    pub meta: Option<Meta>,
4897}
4898
4899#[cfg(feature = "unstable_llm_providers")]
4900impl DisableProviderRequest {
4901    /// Builds [`DisableProviderRequest`] with the required request fields set. Optional fields start unset or empty.
4902    #[must_use]
4903    pub fn new(provider_id: impl Into<ProviderId>) -> Self {
4904        Self {
4905            provider_id: provider_id.into(),
4906            meta: None,
4907        }
4908    }
4909
4910    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
4911    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
4912    /// these keys.
4913    ///
4914    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v1/extensibility)
4915    #[must_use]
4916    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4917        self.meta = meta.into_option();
4918        self
4919    }
4920}
4921
4922#[cfg(feature = "unstable_llm_providers")]
4923crate::serde_util::default_on_null! {
4924    /// **UNSTABLE**
4925    ///
4926    /// This capability is not part of the spec yet, and may be removed or changed at any point.
4927    ///
4928    /// Response to `providers/disable`.
4929    #[serde_as]
4930    #[skip_serializing_none]
4931    #[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
4932    #[derive(Default, Debug, Clone, Serialize, PartialEq, Eq)]
4933    #[cfg_attr(feature = "schemars", schemars(extend("x-side" = "agent", "x-method" = PROVIDERS_DISABLE_METHOD_NAME)))]
4934    #[serde(rename_all = "camelCase")]
4935    #[non_exhaustive]
4936    pub struct DisableProviderResponse {
4937        /// The _meta property is reserved by ACP to allow clients and agents to attach additional
4938        /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
4939        /// these keys.
4940        ///
4941        /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v1/extensibility)
4942        #[serde_as(deserialize_as = "DefaultOnError")]
4943        #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
4944        #[serde(default)]
4945        #[serde(rename = "_meta")]
4946        pub meta: Option<Meta>,
4947    }
4948}
4949
4950#[cfg(feature = "unstable_llm_providers")]
4951impl DisableProviderResponse {
4952    /// Builds [`DisableProviderResponse`] with the required response fields set. Optional fields start unset or empty.
4953    #[must_use]
4954    pub fn new() -> Self {
4955        Self::default()
4956    }
4957
4958    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
4959    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
4960    /// these keys.
4961    ///
4962    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v1/extensibility)
4963    #[must_use]
4964    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4965        self.meta = meta.into_option();
4966        self
4967    }
4968}
4969
4970// Capabilities
4971
4972/// Capabilities supported by the agent.
4973///
4974/// Advertised during initialization to inform the client about
4975/// available features and content types.
4976///
4977/// See protocol docs: [Agent Capabilities](https://agentclientprotocol.com/protocol/v1/initialization#agent-capabilities)
4978#[serde_as]
4979#[skip_serializing_none]
4980#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
4981#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
4982#[serde(rename_all = "camelCase")]
4983#[non_exhaustive]
4984pub struct AgentCapabilities {
4985    /// Whether the agent supports `session/load`.
4986    #[serde_as(deserialize_as = "DefaultOnError")]
4987    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
4988    #[serde(default)]
4989    pub load_session: bool,
4990    /// Prompt capabilities supported by the agent.
4991    #[serde_as(deserialize_as = "DefaultOnError")]
4992    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
4993    #[serde(default)]
4994    pub prompt_capabilities: PromptCapabilities,
4995    /// MCP capabilities supported by the agent.
4996    #[serde_as(deserialize_as = "DefaultOnError")]
4997    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
4998    #[serde(default)]
4999    pub mcp_capabilities: McpCapabilities,
5000    /// Session lifecycle and prompt capabilities advertised by the agent.
5001    #[serde_as(deserialize_as = "DefaultOnError")]
5002    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
5003    #[serde(default)]
5004    pub session_capabilities: SessionCapabilities,
5005    /// Authentication-related capabilities supported by the agent.
5006    #[serde_as(deserialize_as = "DefaultOnError")]
5007    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
5008    #[serde(default)]
5009    pub auth: AgentAuthCapabilities,
5010    /// **UNSTABLE**
5011    ///
5012    /// This capability is not part of the spec yet, and may be removed or changed at any point.
5013    ///
5014    /// Provider configuration capabilities supported by the agent.
5015    ///
5016    /// Optional. Omitted or `null` both mean the agent does not advertise support.
5017    /// Supplying `{}` means the agent supports provider configuration methods.
5018    #[cfg(feature = "unstable_llm_providers")]
5019    #[serde_as(deserialize_as = "DefaultOnError")]
5020    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
5021    #[serde(default)]
5022    pub providers: Option<ProvidersCapabilities>,
5023    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
5024    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
5025    /// these keys.
5026    ///
5027    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v1/extensibility)
5028    #[serde_as(deserialize_as = "DefaultOnError")]
5029    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
5030    #[serde(default)]
5031    #[serde(rename = "_meta")]
5032    pub meta: Option<Meta>,
5033}
5034
5035impl AgentCapabilities {
5036    /// Builds an empty [`AgentCapabilities`]. Use builder methods to advertise supported sub-capabilities.
5037    #[must_use]
5038    pub fn new() -> Self {
5039        Self::default()
5040    }
5041
5042    /// Whether the agent supports `session/load`.
5043    #[must_use]
5044    pub fn load_session(mut self, load_session: bool) -> Self {
5045        self.load_session = load_session;
5046        self
5047    }
5048
5049    /// Prompt capabilities supported by the agent.
5050    #[must_use]
5051    pub fn prompt_capabilities(mut self, prompt_capabilities: PromptCapabilities) -> Self {
5052        self.prompt_capabilities = prompt_capabilities;
5053        self
5054    }
5055
5056    /// MCP capabilities supported by the agent.
5057    #[must_use]
5058    pub fn mcp_capabilities(mut self, mcp_capabilities: McpCapabilities) -> Self {
5059        self.mcp_capabilities = mcp_capabilities;
5060        self
5061    }
5062
5063    /// Session capabilities supported by the agent.
5064    #[must_use]
5065    pub fn session_capabilities(mut self, session_capabilities: SessionCapabilities) -> Self {
5066        self.session_capabilities = session_capabilities;
5067        self
5068    }
5069
5070    /// Authentication-related capabilities supported by the agent.
5071    #[must_use]
5072    pub fn auth(mut self, auth: AgentAuthCapabilities) -> Self {
5073        self.auth = auth;
5074        self
5075    }
5076
5077    /// **UNSTABLE**
5078    ///
5079    /// This capability is not part of the spec yet, and may be removed or changed at any point.
5080    ///
5081    /// Provider configuration capabilities supported by the agent.
5082    #[cfg(feature = "unstable_llm_providers")]
5083    #[must_use]
5084    pub fn providers(mut self, providers: impl IntoOption<ProvidersCapabilities>) -> Self {
5085        self.providers = providers.into_option();
5086        self
5087    }
5088
5089    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
5090    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
5091    /// these keys.
5092    ///
5093    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v1/extensibility)
5094    #[must_use]
5095    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
5096        self.meta = meta.into_option();
5097        self
5098    }
5099}
5100
5101/// **UNSTABLE**
5102///
5103/// This capability is not part of the spec yet, and may be removed or changed at any point.
5104///
5105/// Provider configuration capabilities supported by the agent.
5106///
5107/// Supplying `{}` means the agent supports provider configuration methods.
5108#[cfg(feature = "unstable_llm_providers")]
5109#[serde_as]
5110#[skip_serializing_none]
5111#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
5112#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
5113#[non_exhaustive]
5114pub struct ProvidersCapabilities {
5115    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
5116    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
5117    /// these keys.
5118    ///
5119    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v1/extensibility)
5120    #[serde_as(deserialize_as = "DefaultOnError")]
5121    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
5122    #[serde(default)]
5123    #[serde(rename = "_meta")]
5124    pub meta: Option<Meta>,
5125}
5126
5127#[cfg(feature = "unstable_llm_providers")]
5128impl ProvidersCapabilities {
5129    /// Builds an empty [`ProvidersCapabilities`]. Use builder methods to advertise supported sub-capabilities.
5130    #[must_use]
5131    pub fn new() -> Self {
5132        Self::default()
5133    }
5134
5135    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
5136    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
5137    /// these keys.
5138    ///
5139    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v1/extensibility)
5140    #[must_use]
5141    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
5142        self.meta = meta.into_option();
5143        self
5144    }
5145}
5146
5147/// Session capabilities supported by the agent.
5148///
5149/// As a baseline, all Agents **MUST** support `session/new`, `session/prompt`, `session/cancel`, and `session/update`.
5150///
5151/// Optionally, they **MAY** support other session methods and notifications by specifying additional capabilities.
5152///
5153/// Note: `session/load` is still handled by the top-level `loadSession` capability. This will be unified in future versions of the protocol.
5154///
5155/// See protocol docs: [Session Capabilities](https://agentclientprotocol.com/protocol/v1/initialization#session-capabilities)
5156#[serde_as]
5157#[skip_serializing_none]
5158#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
5159#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
5160#[serde(rename_all = "camelCase")]
5161#[non_exhaustive]
5162pub struct SessionCapabilities {
5163    /// Whether the agent supports `session/list`.
5164    ///
5165    /// Optional. Omitted or `null` both mean the agent does not advertise support.
5166    /// Supplying `{}` means the agent supports listing sessions.
5167    #[serde_as(deserialize_as = "DefaultOnError")]
5168    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
5169    #[serde(default)]
5170    pub list: Option<SessionListCapabilities>,
5171    /// Whether the agent supports `session/delete`.
5172    ///
5173    /// Optional. Omitted or `null` both mean the agent does not advertise support.
5174    /// Supplying `{}` means the agent supports deleting sessions from `session/list`.
5175    #[serde_as(deserialize_as = "DefaultOnError")]
5176    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
5177    #[serde(default)]
5178    pub delete: Option<SessionDeleteCapabilities>,
5179    /// Whether the agent supports `additionalDirectories` on supported session lifecycle requests.
5180    ///
5181    /// Optional. Omitted or `null` both mean the agent does not advertise support.
5182    /// Supplying `{}` means the agent supports `additionalDirectories` on
5183    /// supported session lifecycle requests.
5184    ///
5185    /// Agents that also support `session/list` may return
5186    /// `SessionInfo.additionalDirectories` to report the complete ordered
5187    /// additional-root list associated with a listed session.
5188    #[serde_as(deserialize_as = "DefaultOnError")]
5189    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
5190    #[serde(default)]
5191    pub additional_directories: Option<SessionAdditionalDirectoriesCapabilities>,
5192    /// Whether the agent supports `systemPrompt` on session lifecycle requests.
5193    ///
5194    /// Optional. Omitted or `null` both mean the agent does not advertise support.
5195    /// Supplying `{}` means the agent supports `systemPrompt` in `append` mode.
5196    #[serde_as(deserialize_as = "DefaultOnError")]
5197    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
5198    #[serde(default)]
5199    pub system_prompt: Option<SessionSystemPromptCapabilities>,
5200    /// **UNSTABLE**
5201    ///
5202    /// This capability is not part of the spec yet, and may be removed or changed at any point.
5203    ///
5204    /// Whether the agent supports `session/fork`.
5205    ///
5206    /// Optional. Omitted or `null` both mean the agent does not advertise support.
5207    /// Supplying `{}` means the agent supports forking sessions.
5208    #[cfg(feature = "unstable_session_fork")]
5209    #[serde_as(deserialize_as = "DefaultOnError")]
5210    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
5211    #[serde(default)]
5212    pub fork: Option<SessionForkCapabilities>,
5213    /// **UNSTABLE**
5214    ///
5215    /// This capability is not part of the spec yet, and may be removed or changed at any point.
5216    ///
5217    /// Whether the agent supports `session/archive` and `session/unarchive`.
5218    ///
5219    /// Optional. Omitted or `null` both mean the agent does not advertise support.
5220    /// Supplying `{}` means the agent supports both methods, the `archived` filter on
5221    /// `session/list`, and `SessionInfo.archived`. Agents that advertise it MUST also advertise `sessionCapabilities.list`.
5222    #[cfg(feature = "unstable_session_archive")]
5223    #[serde_as(deserialize_as = "DefaultOnError")]
5224    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
5225    #[serde(default)]
5226    pub archive: Option<SessionArchiveCapabilities>,
5227    /// **UNSTABLE**
5228    ///
5229    /// This capability is not part of the spec yet, and may be removed or changed at any point.
5230    ///
5231    /// Whether the agent supports `session/status`.
5232    ///
5233    /// Optional. Omitted or `null` both mean the agent does not advertise support.
5234    /// Supplying `{}` means the agent supports checking session status.
5235    #[cfg(feature = "unstable_session_status")]
5236    #[serde_as(deserialize_as = "DefaultOnError")]
5237    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
5238    #[serde(default)]
5239    pub status: Option<SessionStatusCapabilities>,
5240    /// **UNSTABLE**
5241    ///
5242    /// This capability is not part of the spec yet, and may be removed or changed at any point.
5243    ///
5244    /// Whether the agent supports `session/set_title`.
5245    ///
5246    /// Agents report titles through `session/list` and `session_info_update` without this
5247    /// capability. It only advertises that Clients can set titles.
5248    ///
5249    /// Optional. Omitted or `null` both mean the agent does not advertise support.
5250    /// Supplying `{}` means the agent supports setting session titles.
5251    #[cfg(feature = "unstable_session_set_title")]
5252    #[serde_as(deserialize_as = "DefaultOnError")]
5253    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
5254    #[serde(default)]
5255    pub title: Option<SessionTitleCapabilities>,
5256    /// Whether the agent supports `session/resume`.
5257    ///
5258    /// Optional. Omitted or `null` both mean the agent does not advertise support.
5259    /// Supplying `{}` means the agent supports resuming sessions.
5260    #[serde_as(deserialize_as = "DefaultOnError")]
5261    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
5262    #[serde(default)]
5263    pub resume: Option<SessionResumeCapabilities>,
5264    /// Whether the agent supports `session/close`.
5265    ///
5266    /// Optional. Omitted or `null` both mean the agent does not advertise support.
5267    /// Supplying `{}` means the agent supports closing sessions.
5268    #[serde_as(deserialize_as = "DefaultOnError")]
5269    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
5270    #[serde(default)]
5271    pub close: Option<SessionCloseCapabilities>,
5272    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
5273    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
5274    /// these keys.
5275    ///
5276    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v1/extensibility)
5277    #[serde_as(deserialize_as = "DefaultOnError")]
5278    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
5279    #[serde(default)]
5280    #[serde(rename = "_meta")]
5281    pub meta: Option<Meta>,
5282}
5283
5284impl SessionCapabilities {
5285    /// Builds an empty [`SessionCapabilities`]. Use builder methods to advertise supported sub-capabilities.
5286    #[must_use]
5287    pub fn new() -> Self {
5288        Self::default()
5289    }
5290
5291    /// Whether the agent supports `session/list`.
5292    ///
5293    /// Omitted or `null` both mean the agent does not advertise support.
5294    /// Supplying `{}` means the agent supports listing sessions.
5295    #[must_use]
5296    pub fn list(mut self, list: impl IntoOption<SessionListCapabilities>) -> Self {
5297        self.list = list.into_option();
5298        self
5299    }
5300
5301    /// Whether the agent supports `session/delete`.
5302    ///
5303    /// Omitted or `null` both mean the agent does not advertise support.
5304    /// Supplying `{}` means the agent supports deleting sessions from `session/list`.
5305    #[must_use]
5306    pub fn delete(mut self, delete: impl IntoOption<SessionDeleteCapabilities>) -> Self {
5307        self.delete = delete.into_option();
5308        self
5309    }
5310
5311    /// Whether the agent supports `additionalDirectories` on supported session lifecycle requests.
5312    ///
5313    /// Omitted or `null` both mean the agent does not advertise support.
5314    /// Supplying `{}` means the agent supports `additionalDirectories` on
5315    /// supported session lifecycle requests.
5316    ///
5317    /// Agents that also support `session/list` may return
5318    /// `SessionInfo.additionalDirectories` to report the complete ordered
5319    /// additional-root list associated with a listed session.
5320    #[must_use]
5321    pub fn additional_directories(
5322        mut self,
5323        additional_directories: impl IntoOption<SessionAdditionalDirectoriesCapabilities>,
5324    ) -> Self {
5325        self.additional_directories = additional_directories.into_option();
5326        self
5327    }
5328
5329    /// Whether the agent supports `systemPrompt` on session lifecycle requests.
5330    ///
5331    /// Omitted or `null` both mean the agent does not advertise support.
5332    /// Supplying `{}` means the agent supports `systemPrompt` in `append` mode.
5333    #[must_use]
5334    pub fn system_prompt(
5335        mut self,
5336        system_prompt: impl IntoOption<SessionSystemPromptCapabilities>,
5337    ) -> Self {
5338        self.system_prompt = system_prompt.into_option();
5339        self
5340    }
5341
5342    #[cfg(feature = "unstable_session_fork")]
5343    /// Whether the agent supports `session/fork`.
5344    ///
5345    /// Omitted or `null` both mean the agent does not advertise support.
5346    /// Supplying `{}` means the agent supports forking sessions.
5347    #[must_use]
5348    pub fn fork(mut self, fork: impl IntoOption<SessionForkCapabilities>) -> Self {
5349        self.fork = fork.into_option();
5350        self
5351    }
5352
5353    /// **UNSTABLE**
5354    ///
5355    /// This capability is not part of the spec yet, and may be removed or changed at any point.
5356    ///
5357    /// Whether the agent supports `session/archive` and `session/unarchive`.
5358    ///
5359    /// Omitted or `null` both mean the agent does not advertise support.
5360    /// Supplying `{}` means the agent supports both methods, the `archived` filter on
5361    /// `session/list`, and `SessionInfo.archived`.
5362    #[cfg(feature = "unstable_session_archive")]
5363    #[must_use]
5364    pub fn archive(mut self, archive: impl IntoOption<SessionArchiveCapabilities>) -> Self {
5365        self.archive = archive.into_option();
5366        self
5367    }
5368
5369    /// **UNSTABLE**
5370    ///
5371    /// This capability is not part of the spec yet, and may be removed or changed at any point.
5372    ///
5373    /// Whether the agent supports `session/status`.
5374    ///
5375    /// Omitted or `null` both mean the agent does not advertise support.
5376    /// Supplying `{}` means the agent supports checking session status.
5377    #[cfg(feature = "unstable_session_status")]
5378    #[must_use]
5379    pub fn status(mut self, status: impl IntoOption<SessionStatusCapabilities>) -> Self {
5380        self.status = status.into_option();
5381        self
5382    }
5383
5384    /// **UNSTABLE**
5385    ///
5386    /// This capability is not part of the spec yet, and may be removed or changed at any point.
5387    ///
5388    /// Whether the agent supports `session/set_title`.
5389    ///
5390    /// Agents report titles through `session/list` and `session_info_update` without this
5391    /// capability. It only advertises that Clients can set titles.
5392    ///
5393    /// Omitted or `null` both mean the agent does not advertise support.
5394    /// Supplying `{}` means the agent supports setting session titles.
5395    #[cfg(feature = "unstable_session_set_title")]
5396    #[must_use]
5397    pub fn title(mut self, title: impl IntoOption<SessionTitleCapabilities>) -> Self {
5398        self.title = title.into_option();
5399        self
5400    }
5401
5402    /// Whether the agent supports `session/resume`.
5403    ///
5404    /// Omitted or `null` both mean the agent does not advertise support.
5405    /// Supplying `{}` means the agent supports resuming sessions.
5406    #[must_use]
5407    pub fn resume(mut self, resume: impl IntoOption<SessionResumeCapabilities>) -> Self {
5408        self.resume = resume.into_option();
5409        self
5410    }
5411
5412    /// Whether the agent supports `session/close`.
5413    ///
5414    /// Omitted or `null` both mean the agent does not advertise support.
5415    /// Supplying `{}` means the agent supports closing sessions.
5416    #[must_use]
5417    pub fn close(mut self, close: impl IntoOption<SessionCloseCapabilities>) -> Self {
5418        self.close = close.into_option();
5419        self
5420    }
5421
5422    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
5423    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
5424    /// these keys.
5425    ///
5426    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v1/extensibility)
5427    #[must_use]
5428    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
5429        self.meta = meta.into_option();
5430        self
5431    }
5432}
5433
5434/// Capabilities for the `session/list` method.
5435///
5436/// Supplying `{}` means the agent supports listing sessions.
5437#[serde_as]
5438#[skip_serializing_none]
5439#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
5440#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
5441#[non_exhaustive]
5442pub struct SessionListCapabilities {
5443    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
5444    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
5445    /// these keys.
5446    ///
5447    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v1/extensibility)
5448    #[serde_as(deserialize_as = "DefaultOnError")]
5449    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
5450    #[serde(default)]
5451    #[serde(rename = "_meta")]
5452    pub meta: Option<Meta>,
5453}
5454
5455impl SessionListCapabilities {
5456    /// Builds an empty [`SessionListCapabilities`]. Use builder methods to advertise supported sub-capabilities.
5457    #[must_use]
5458    pub fn new() -> Self {
5459        Self::default()
5460    }
5461
5462    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
5463    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
5464    /// these keys.
5465    ///
5466    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v1/extensibility)
5467    #[must_use]
5468    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
5469        self.meta = meta.into_option();
5470        self
5471    }
5472}
5473
5474/// Capabilities for the `session/delete` method.
5475///
5476/// Supplying `{}` means the agent supports deleting sessions from `session/list`.
5477#[serde_as]
5478#[skip_serializing_none]
5479#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
5480#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
5481#[non_exhaustive]
5482pub struct SessionDeleteCapabilities {
5483    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
5484    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
5485    /// these keys.
5486    ///
5487    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v1/extensibility)
5488    #[serde_as(deserialize_as = "DefaultOnError")]
5489    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
5490    #[serde(default)]
5491    #[serde(rename = "_meta")]
5492    pub meta: Option<Meta>,
5493}
5494
5495impl SessionDeleteCapabilities {
5496    /// Builds an empty [`SessionDeleteCapabilities`]. Use builder methods to advertise supported sub-capabilities.
5497    #[must_use]
5498    pub fn new() -> Self {
5499        Self::default()
5500    }
5501
5502    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
5503    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
5504    /// these keys.
5505    ///
5506    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v1/extensibility)
5507    #[must_use]
5508    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
5509        self.meta = meta.into_option();
5510        self
5511    }
5512}
5513
5514/// Capabilities for additional session directories support.
5515///
5516/// Supplying `{}` means the agent supports the `additionalDirectories` field on
5517/// supported session lifecycle requests. Agents that also support
5518/// `session/list` may return `SessionInfo.additionalDirectories` to report the
5519/// complete ordered additional-root list associated with a listed session.
5520#[serde_as]
5521#[skip_serializing_none]
5522#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
5523#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
5524#[non_exhaustive]
5525pub struct SessionAdditionalDirectoriesCapabilities {
5526    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
5527    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
5528    /// these keys.
5529    ///
5530    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v1/extensibility)
5531    #[serde_as(deserialize_as = "DefaultOnError")]
5532    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
5533    #[serde(default)]
5534    #[serde(rename = "_meta")]
5535    pub meta: Option<Meta>,
5536}
5537
5538impl SessionAdditionalDirectoriesCapabilities {
5539    /// Builds an empty [`SessionAdditionalDirectoriesCapabilities`]. Use builder methods to advertise supported sub-capabilities.
5540    #[must_use]
5541    pub fn new() -> Self {
5542        Self::default()
5543    }
5544
5545    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
5546    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
5547    /// these keys.
5548    ///
5549    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v1/extensibility)
5550    #[must_use]
5551    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
5552        self.meta = meta.into_option();
5553        self
5554    }
5555}
5556
5557/// Capabilities for client-provided system prompts.
5558///
5559/// Supplying `{}` means the agent supports `systemPrompt` on session lifecycle
5560/// requests in `append` mode.
5561#[serde_as]
5562#[skip_serializing_none]
5563#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
5564#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
5565#[serde(rename_all = "camelCase")]
5566#[non_exhaustive]
5567pub struct SessionSystemPromptCapabilities {
5568    /// Delivery modes the agent supports in addition to `append`.
5569    ///
5570    /// Optional. Omitted or `null` both mean the agent supports only `append`.
5571    #[serde_as(deserialize_as = "DefaultOnError")]
5572    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
5573    #[serde(default)]
5574    pub mode: Option<SessionSystemPromptModeCapabilities>,
5575    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
5576    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
5577    /// these keys.
5578    ///
5579    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v1/extensibility)
5580    #[serde_as(deserialize_as = "DefaultOnError")]
5581    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
5582    #[serde(default)]
5583    #[serde(rename = "_meta")]
5584    pub meta: Option<Meta>,
5585}
5586
5587impl SessionSystemPromptCapabilities {
5588    /// Builds an empty [`SessionSystemPromptCapabilities`]. Use builder methods to advertise supported sub-capabilities.
5589    #[must_use]
5590    pub fn new() -> Self {
5591        Self::default()
5592    }
5593
5594    /// Delivery modes the agent supports in addition to `append`.
5595    ///
5596    /// Omitted or `null` both mean the agent supports only `append`.
5597    #[must_use]
5598    pub fn mode(mut self, mode: impl IntoOption<SessionSystemPromptModeCapabilities>) -> Self {
5599        self.mode = mode.into_option();
5600        self
5601    }
5602
5603    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
5604    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
5605    /// these keys.
5606    ///
5607    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v1/extensibility)
5608    #[must_use]
5609    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
5610        self.meta = meta.into_option();
5611        self
5612    }
5613}
5614
5615/// System prompt delivery modes the agent supports in addition to `append`.
5616///
5617/// `append` has no entry because every agent advertising
5618/// `sessionCapabilities.systemPrompt` supports it.
5619#[serde_as]
5620#[skip_serializing_none]
5621#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
5622#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
5623#[serde(rename_all = "camelCase")]
5624#[non_exhaustive]
5625pub struct SessionSystemPromptModeCapabilities {
5626    /// Whether the agent supports `override` mode.
5627    ///
5628    /// Optional. Omitted or `null` both mean the agent does not advertise support.
5629    /// Supplying `{}` means the agent supports replacing its built-in default
5630    /// instructions with the client-provided system prompt.
5631    #[serde_as(deserialize_as = "DefaultOnError")]
5632    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
5633    #[serde(default, rename = "override")]
5634    pub override_: Option<SessionSystemPromptOverrideCapabilities>,
5635    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
5636    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
5637    /// these keys.
5638    ///
5639    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v1/extensibility)
5640    #[serde_as(deserialize_as = "DefaultOnError")]
5641    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
5642    #[serde(default)]
5643    #[serde(rename = "_meta")]
5644    pub meta: Option<Meta>,
5645}
5646
5647impl SessionSystemPromptModeCapabilities {
5648    /// Builds an empty [`SessionSystemPromptModeCapabilities`]. Use builder methods to advertise supported sub-capabilities.
5649    #[must_use]
5650    pub fn new() -> Self {
5651        Self::default()
5652    }
5653
5654    /// Whether the agent supports `override` mode.
5655    ///
5656    /// Omitted or `null` both mean the agent does not advertise support.
5657    /// Supplying `{}` means the agent supports replacing its built-in default
5658    /// instructions with the client-provided system prompt.
5659    #[must_use]
5660    pub fn override_(
5661        mut self,
5662        override_: impl IntoOption<SessionSystemPromptOverrideCapabilities>,
5663    ) -> Self {
5664        self.override_ = override_.into_option();
5665        self
5666    }
5667
5668    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
5669    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
5670    /// these keys.
5671    ///
5672    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v1/extensibility)
5673    #[must_use]
5674    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
5675        self.meta = meta.into_option();
5676        self
5677    }
5678}
5679
5680/// Capabilities for the `override` system prompt mode.
5681///
5682/// Supplying `{}` means the agent supports replacing its built-in default
5683/// instructions with the client-provided system prompt.
5684#[serde_as]
5685#[skip_serializing_none]
5686#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
5687#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
5688#[non_exhaustive]
5689pub struct SessionSystemPromptOverrideCapabilities {
5690    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
5691    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
5692    /// these keys.
5693    ///
5694    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v1/extensibility)
5695    #[serde_as(deserialize_as = "DefaultOnError")]
5696    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
5697    #[serde(default)]
5698    #[serde(rename = "_meta")]
5699    pub meta: Option<Meta>,
5700}
5701
5702impl SessionSystemPromptOverrideCapabilities {
5703    /// Builds an empty [`SessionSystemPromptOverrideCapabilities`]. Use builder methods to advertise supported sub-capabilities.
5704    #[must_use]
5705    pub fn new() -> Self {
5706        Self::default()
5707    }
5708
5709    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
5710    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
5711    /// these keys.
5712    ///
5713    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v1/extensibility)
5714    #[must_use]
5715    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
5716        self.meta = meta.into_option();
5717        self
5718    }
5719}
5720
5721/// **UNSTABLE**
5722///
5723/// This capability is not part of the spec yet, and may be removed or changed at any point.
5724///
5725/// Capabilities for the `session/fork` method.
5726///
5727/// Supplying `{}` means the agent supports forking sessions.
5728#[cfg(feature = "unstable_session_fork")]
5729#[serde_as]
5730#[skip_serializing_none]
5731#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
5732#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
5733#[non_exhaustive]
5734pub struct SessionForkCapabilities {
5735    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
5736    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
5737    /// these keys.
5738    ///
5739    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v1/extensibility)
5740    #[serde_as(deserialize_as = "DefaultOnError")]
5741    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
5742    #[serde(default)]
5743    #[serde(rename = "_meta")]
5744    pub meta: Option<Meta>,
5745}
5746
5747#[cfg(feature = "unstable_session_fork")]
5748impl SessionForkCapabilities {
5749    /// Builds an empty [`SessionForkCapabilities`]. Use builder methods to advertise supported sub-capabilities.
5750    #[must_use]
5751    pub fn new() -> Self {
5752        Self::default()
5753    }
5754
5755    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
5756    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
5757    /// these keys.
5758    ///
5759    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v1/extensibility)
5760    #[must_use]
5761    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
5762        self.meta = meta.into_option();
5763        self
5764    }
5765}
5766
5767/// **UNSTABLE**
5768///
5769/// This capability is not part of the spec yet, and may be removed or changed at any point.
5770///
5771/// Capabilities for `session/archive` and `session/unarchive`.
5772///
5773/// Supplying `{}` means the agent supports both methods, the `archived` filter on
5774/// `session/list`, and `SessionInfo.archived`.
5775#[cfg(feature = "unstable_session_archive")]
5776#[serde_as]
5777#[skip_serializing_none]
5778#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
5779#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
5780#[non_exhaustive]
5781pub struct SessionArchiveCapabilities {
5782    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
5783    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
5784    /// these keys.
5785    ///
5786    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v1/extensibility)
5787    #[serde_as(deserialize_as = "DefaultOnError")]
5788    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
5789    #[serde(default)]
5790    #[serde(rename = "_meta")]
5791    pub meta: Option<Meta>,
5792}
5793
5794#[cfg(feature = "unstable_session_archive")]
5795impl SessionArchiveCapabilities {
5796    /// Builds an empty [`SessionArchiveCapabilities`]. Use builder methods to advertise supported sub-capabilities.
5797    #[must_use]
5798    pub fn new() -> Self {
5799        Self::default()
5800    }
5801
5802    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
5803    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
5804    /// these keys.
5805    ///
5806    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v1/extensibility)
5807    #[must_use]
5808    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
5809        self.meta = meta.into_option();
5810        self
5811    }
5812}
5813
5814/// **UNSTABLE**
5815///
5816/// This capability is not part of the spec yet, and may be removed or changed at any point.
5817///
5818/// Capabilities for the `session/status` method.
5819///
5820/// Supplying `{}` means the agent supports checking session status.
5821#[cfg(feature = "unstable_session_status")]
5822#[serde_as]
5823#[skip_serializing_none]
5824#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
5825#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
5826#[non_exhaustive]
5827pub struct SessionStatusCapabilities {
5828    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
5829    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
5830    /// these keys.
5831    ///
5832    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v1/extensibility)
5833    #[serde_as(deserialize_as = "DefaultOnError")]
5834    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
5835    #[serde(default)]
5836    #[serde(rename = "_meta")]
5837    pub meta: Option<Meta>,
5838}
5839
5840#[cfg(feature = "unstable_session_status")]
5841impl SessionStatusCapabilities {
5842    /// Builds an empty [`SessionStatusCapabilities`]. Use builder methods to advertise supported sub-capabilities.
5843    #[must_use]
5844    pub fn new() -> Self {
5845        Self::default()
5846    }
5847
5848    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
5849    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
5850    /// these keys.
5851    ///
5852    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v1/extensibility)
5853    #[must_use]
5854    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
5855        self.meta = meta.into_option();
5856        self
5857    }
5858}
5859
5860/// **UNSTABLE**
5861///
5862/// This capability is not part of the spec yet, and may be removed or changed at any point.
5863///
5864/// Capabilities for Client-set session titles.
5865///
5866/// Supplying `{}` means the agent supports `session/set_title`. Agents report titles
5867/// through `session/list` and `session_info_update` without this capability.
5868#[cfg(feature = "unstable_session_set_title")]
5869#[serde_as]
5870#[skip_serializing_none]
5871#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
5872#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
5873#[non_exhaustive]
5874pub struct SessionTitleCapabilities {
5875    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
5876    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
5877    /// these keys.
5878    ///
5879    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v1/extensibility)
5880    #[serde_as(deserialize_as = "DefaultOnError")]
5881    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
5882    #[serde(default)]
5883    #[serde(rename = "_meta")]
5884    pub meta: Option<Meta>,
5885}
5886
5887#[cfg(feature = "unstable_session_set_title")]
5888impl SessionTitleCapabilities {
5889    /// Builds an empty [`SessionTitleCapabilities`]. Use builder methods to advertise supported sub-capabilities.
5890    #[must_use]
5891    pub fn new() -> Self {
5892        Self::default()
5893    }
5894
5895    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
5896    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
5897    /// these keys.
5898    ///
5899    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v1/extensibility)
5900    #[must_use]
5901    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
5902        self.meta = meta.into_option();
5903        self
5904    }
5905}
5906
5907/// Capabilities for the `session/resume` method.
5908///
5909/// Supplying `{}` means the agent supports resuming sessions.
5910#[serde_as]
5911#[skip_serializing_none]
5912#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
5913#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
5914#[non_exhaustive]
5915pub struct SessionResumeCapabilities {
5916    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
5917    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
5918    /// these keys.
5919    ///
5920    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v1/extensibility)
5921    #[serde_as(deserialize_as = "DefaultOnError")]
5922    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
5923    #[serde(default)]
5924    #[serde(rename = "_meta")]
5925    pub meta: Option<Meta>,
5926}
5927
5928impl SessionResumeCapabilities {
5929    /// Builds an empty [`SessionResumeCapabilities`]. Use builder methods to advertise supported sub-capabilities.
5930    #[must_use]
5931    pub fn new() -> Self {
5932        Self::default()
5933    }
5934
5935    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
5936    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
5937    /// these keys.
5938    ///
5939    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v1/extensibility)
5940    #[must_use]
5941    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
5942        self.meta = meta.into_option();
5943        self
5944    }
5945}
5946
5947/// Capabilities for the `session/close` method.
5948///
5949/// Supplying `{}` means the agent supports closing sessions.
5950#[serde_as]
5951#[skip_serializing_none]
5952#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
5953#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
5954#[non_exhaustive]
5955pub struct SessionCloseCapabilities {
5956    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
5957    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
5958    /// these keys.
5959    ///
5960    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v1/extensibility)
5961    #[serde_as(deserialize_as = "DefaultOnError")]
5962    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
5963    #[serde(default)]
5964    #[serde(rename = "_meta")]
5965    pub meta: Option<Meta>,
5966}
5967
5968impl SessionCloseCapabilities {
5969    /// Builds an empty [`SessionCloseCapabilities`]. Use builder methods to advertise supported sub-capabilities.
5970    #[must_use]
5971    pub fn new() -> Self {
5972        Self::default()
5973    }
5974
5975    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
5976    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
5977    /// these keys.
5978    ///
5979    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v1/extensibility)
5980    #[must_use]
5981    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
5982        self.meta = meta.into_option();
5983        self
5984    }
5985}
5986
5987/// Prompt capabilities supported by the agent in `session/prompt` requests.
5988///
5989/// Baseline agent functionality requires support for `text`
5990/// and `resource_link` content blocks in prompt requests.
5991///
5992/// Other variants must be explicitly opted in to.
5993/// Capabilities for different types of content in prompt requests.
5994///
5995/// Indicates which content types beyond the baseline (text and resource links)
5996/// the agent can process.
5997///
5998/// See protocol docs: [Prompt Capabilities](https://agentclientprotocol.com/protocol/v1/initialization#prompt-capabilities)
5999#[serde_as]
6000#[skip_serializing_none]
6001#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
6002#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
6003#[serde(rename_all = "camelCase")]
6004#[non_exhaustive]
6005pub struct PromptCapabilities {
6006    /// Agent supports `image` content blocks.
6007    #[serde_as(deserialize_as = "DefaultOnError")]
6008    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
6009    #[serde(default)]
6010    pub image: bool,
6011    /// Agent supports `audio` content blocks.
6012    #[serde_as(deserialize_as = "DefaultOnError")]
6013    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
6014    #[serde(default)]
6015    pub audio: bool,
6016    /// Agent supports embedded context in `session/prompt` requests.
6017    ///
6018    /// When enabled, the Client is allowed to include `resource` content blocks
6019    /// in prompt requests for pieces of context that are referenced in the message.
6020    #[serde_as(deserialize_as = "DefaultOnError")]
6021    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
6022    #[serde(default)]
6023    pub embedded_context: bool,
6024    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
6025    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
6026    /// these keys.
6027    ///
6028    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v1/extensibility)
6029    #[serde_as(deserialize_as = "DefaultOnError")]
6030    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
6031    #[serde(default)]
6032    #[serde(rename = "_meta")]
6033    pub meta: Option<Meta>,
6034}
6035
6036impl PromptCapabilities {
6037    /// Builds an empty [`PromptCapabilities`]. Use builder methods to advertise supported sub-capabilities.
6038    #[must_use]
6039    pub fn new() -> Self {
6040        Self::default()
6041    }
6042
6043    /// Agent supports `image` content blocks.
6044    #[must_use]
6045    pub fn image(mut self, image: bool) -> Self {
6046        self.image = image;
6047        self
6048    }
6049
6050    /// Agent supports `audio` content blocks.
6051    #[must_use]
6052    pub fn audio(mut self, audio: bool) -> Self {
6053        self.audio = audio;
6054        self
6055    }
6056
6057    /// Agent supports embedded context in `session/prompt` requests.
6058    ///
6059    /// When enabled, the Client is allowed to include `resource` content blocks
6060    /// in prompt requests for pieces of context that are referenced in the message.
6061    #[must_use]
6062    pub fn embedded_context(mut self, embedded_context: bool) -> Self {
6063        self.embedded_context = embedded_context;
6064        self
6065    }
6066
6067    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
6068    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
6069    /// these keys.
6070    ///
6071    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v1/extensibility)
6072    #[must_use]
6073    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
6074        self.meta = meta.into_option();
6075        self
6076    }
6077}
6078
6079/// MCP capabilities supported by the agent
6080#[serde_as]
6081#[skip_serializing_none]
6082#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
6083#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
6084#[serde(rename_all = "camelCase")]
6085#[non_exhaustive]
6086pub struct McpCapabilities {
6087    /// Agent supports `http` MCP servers.
6088    #[serde_as(deserialize_as = "DefaultOnError")]
6089    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
6090    #[serde(default)]
6091    pub http: bool,
6092    /// Agent supports `sse` MCP servers.
6093    #[serde_as(deserialize_as = "DefaultOnError")]
6094    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
6095    #[serde(default)]
6096    pub sse: bool,
6097    /// **UNSTABLE**
6098    ///
6099    /// This capability is not part of the spec yet, and may be removed or changed at any point.
6100    ///
6101    /// Agent supports `acp` MCP servers.
6102    #[cfg(feature = "unstable_mcp_over_acp")]
6103    #[serde_as(deserialize_as = "DefaultOnError")]
6104    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
6105    #[serde(default)]
6106    pub acp: bool,
6107    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
6108    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
6109    /// these keys.
6110    ///
6111    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v1/extensibility)
6112    #[serde_as(deserialize_as = "DefaultOnError")]
6113    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
6114    #[serde(default)]
6115    #[serde(rename = "_meta")]
6116    pub meta: Option<Meta>,
6117}
6118
6119impl McpCapabilities {
6120    /// Builds an empty [`McpCapabilities`]. Use builder methods to advertise supported sub-capabilities.
6121    #[must_use]
6122    pub fn new() -> Self {
6123        Self::default()
6124    }
6125
6126    /// Agent supports `http` MCP servers.
6127    #[must_use]
6128    pub fn http(mut self, http: bool) -> Self {
6129        self.http = http;
6130        self
6131    }
6132
6133    /// Agent supports `sse` MCP servers.
6134    #[must_use]
6135    pub fn sse(mut self, sse: bool) -> Self {
6136        self.sse = sse;
6137        self
6138    }
6139
6140    /// **UNSTABLE**
6141    ///
6142    /// This capability is not part of the spec yet, and may be removed or changed at any point.
6143    ///
6144    /// Agent supports `acp` MCP servers.
6145    #[cfg(feature = "unstable_mcp_over_acp")]
6146    #[must_use]
6147    pub fn acp(mut self, acp: bool) -> Self {
6148        self.acp = acp;
6149        self
6150    }
6151
6152    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
6153    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
6154    /// these keys.
6155    ///
6156    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v1/extensibility)
6157    #[must_use]
6158    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
6159        self.meta = meta.into_option();
6160        self
6161    }
6162}
6163
6164// Method schema
6165
6166/// Names of all methods that agents handle.
6167///
6168/// Provides a centralized definition of method names used in the protocol.
6169#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
6170#[non_exhaustive]
6171pub struct AgentMethodNames {
6172    /// Method for initializing the connection.
6173    pub initialize: &'static str,
6174    /// Method for authenticating with the agent.
6175    pub authenticate: &'static str,
6176    /// Method for listing configurable providers.
6177    #[cfg(feature = "unstable_llm_providers")]
6178    pub providers_list: &'static str,
6179    /// Method for setting provider configuration.
6180    #[cfg(feature = "unstable_llm_providers")]
6181    pub providers_set: &'static str,
6182    /// Method for disabling a provider.
6183    #[cfg(feature = "unstable_llm_providers")]
6184    pub providers_disable: &'static str,
6185    /// Method for creating a new session.
6186    pub session_new: &'static str,
6187    /// Method for loading an existing session.
6188    pub session_load: &'static str,
6189    /// Method for setting the mode for a session.
6190    pub session_set_mode: &'static str,
6191    /// Method for setting a configuration option for a session.
6192    pub session_set_config_option: &'static str,
6193    /// Method for sending a prompt to the agent.
6194    pub session_prompt: &'static str,
6195    /// Notification for cancelling operations.
6196    pub session_cancel: &'static str,
6197    /// Method for exchanging MCP-over-ACP messages.
6198    #[cfg(feature = "unstable_mcp_over_acp")]
6199    pub mcp_message: &'static str,
6200    /// Method for listing existing sessions.
6201    pub session_list: &'static str,
6202    /// Method for deleting an existing session.
6203    pub session_delete: &'static str,
6204    /// Method for forking an existing session.
6205    #[cfg(feature = "unstable_session_fork")]
6206    pub session_fork: &'static str,
6207    /// Method for archiving a session.
6208    #[cfg(feature = "unstable_session_archive")]
6209    pub session_archive: &'static str,
6210    /// Method for unarchiving a session.
6211    #[cfg(feature = "unstable_session_archive")]
6212    pub session_unarchive: &'static str,
6213    /// Method for checking the status of a session.
6214    #[cfg(feature = "unstable_session_status")]
6215    pub session_status: &'static str,
6216    /// Method for setting the title of a session.
6217    #[cfg(feature = "unstable_session_set_title")]
6218    pub session_set_title: &'static str,
6219    /// Method for resuming an existing session.
6220    pub session_resume: &'static str,
6221    /// Method for closing an active session.
6222    pub session_close: &'static str,
6223    /// Method for logging out of an authenticated session.
6224    pub logout: &'static str,
6225    /// Method for querying the agent's authentication state.
6226    #[cfg(feature = "unstable_auth_status")]
6227    pub auth_status: &'static str,
6228}
6229
6230/// Constant containing all agent method names.
6231pub const AGENT_METHOD_NAMES: AgentMethodNames = AgentMethodNames {
6232    initialize: INITIALIZE_METHOD_NAME,
6233    authenticate: AUTHENTICATE_METHOD_NAME,
6234    #[cfg(feature = "unstable_llm_providers")]
6235    providers_list: PROVIDERS_LIST_METHOD_NAME,
6236    #[cfg(feature = "unstable_llm_providers")]
6237    providers_set: PROVIDERS_SET_METHOD_NAME,
6238    #[cfg(feature = "unstable_llm_providers")]
6239    providers_disable: PROVIDERS_DISABLE_METHOD_NAME,
6240    session_new: SESSION_NEW_METHOD_NAME,
6241    session_load: SESSION_LOAD_METHOD_NAME,
6242    session_set_mode: SESSION_SET_MODE_METHOD_NAME,
6243    session_set_config_option: SESSION_SET_CONFIG_OPTION_METHOD_NAME,
6244    session_prompt: SESSION_PROMPT_METHOD_NAME,
6245    session_cancel: SESSION_CANCEL_METHOD_NAME,
6246    #[cfg(feature = "unstable_mcp_over_acp")]
6247    mcp_message: MCP_MESSAGE_METHOD_NAME,
6248    session_list: SESSION_LIST_METHOD_NAME,
6249    session_delete: SESSION_DELETE_METHOD_NAME,
6250    #[cfg(feature = "unstable_session_fork")]
6251    session_fork: SESSION_FORK_METHOD_NAME,
6252    #[cfg(feature = "unstable_session_archive")]
6253    session_archive: SESSION_ARCHIVE_METHOD_NAME,
6254    #[cfg(feature = "unstable_session_archive")]
6255    session_unarchive: SESSION_UNARCHIVE_METHOD_NAME,
6256    #[cfg(feature = "unstable_session_status")]
6257    session_status: SESSION_STATUS_METHOD_NAME,
6258    #[cfg(feature = "unstable_session_set_title")]
6259    session_set_title: SESSION_SET_TITLE_METHOD_NAME,
6260    session_resume: SESSION_RESUME_METHOD_NAME,
6261    session_close: SESSION_CLOSE_METHOD_NAME,
6262    logout: LOGOUT_METHOD_NAME,
6263    #[cfg(feature = "unstable_auth_status")]
6264    auth_status: AUTH_STATUS_METHOD_NAME,
6265};
6266
6267/// Method name for the initialize request.
6268pub(crate) const INITIALIZE_METHOD_NAME: &str = "initialize";
6269/// Method name for the authenticate request.
6270pub(crate) const AUTHENTICATE_METHOD_NAME: &str = "authenticate";
6271/// Method name for listing configurable providers.
6272#[cfg(feature = "unstable_llm_providers")]
6273pub(crate) const PROVIDERS_LIST_METHOD_NAME: &str = "providers/list";
6274/// Method name for setting provider configuration.
6275#[cfg(feature = "unstable_llm_providers")]
6276pub(crate) const PROVIDERS_SET_METHOD_NAME: &str = "providers/set";
6277/// Method name for disabling a provider.
6278#[cfg(feature = "unstable_llm_providers")]
6279pub(crate) const PROVIDERS_DISABLE_METHOD_NAME: &str = "providers/disable";
6280/// Method name for creating a new session.
6281pub(crate) const SESSION_NEW_METHOD_NAME: &str = "session/new";
6282/// Method name for loading an existing session.
6283pub(crate) const SESSION_LOAD_METHOD_NAME: &str = "session/load";
6284/// Method name for setting the mode for a session.
6285pub(crate) const SESSION_SET_MODE_METHOD_NAME: &str = "session/set_mode";
6286/// Method name for setting a configuration option for a session.
6287pub(crate) const SESSION_SET_CONFIG_OPTION_METHOD_NAME: &str = "session/set_config_option";
6288/// Method name for sending a prompt.
6289pub(crate) const SESSION_PROMPT_METHOD_NAME: &str = "session/prompt";
6290/// Method name for the cancel notification.
6291pub(crate) const SESSION_CANCEL_METHOD_NAME: &str = "session/cancel";
6292/// Method name for listing existing sessions.
6293pub(crate) const SESSION_LIST_METHOD_NAME: &str = "session/list";
6294/// Method name for deleting an existing session.
6295pub(crate) const SESSION_DELETE_METHOD_NAME: &str = "session/delete";
6296/// Method name for forking an existing session.
6297#[cfg(feature = "unstable_session_fork")]
6298pub(crate) const SESSION_FORK_METHOD_NAME: &str = "session/fork";
6299/// Method name for archiving a session.
6300#[cfg(feature = "unstable_session_archive")]
6301pub(crate) const SESSION_ARCHIVE_METHOD_NAME: &str = "session/archive";
6302/// Method name for unarchiving a session.
6303#[cfg(feature = "unstable_session_archive")]
6304pub(crate) const SESSION_UNARCHIVE_METHOD_NAME: &str = "session/unarchive";
6305/// Method name for checking the status of a session.
6306#[cfg(feature = "unstable_session_status")]
6307pub(crate) const SESSION_STATUS_METHOD_NAME: &str = "session/status";
6308/// Method name for setting the title of a session.
6309#[cfg(feature = "unstable_session_set_title")]
6310pub(crate) const SESSION_SET_TITLE_METHOD_NAME: &str = "session/set_title";
6311/// Method name for resuming an existing session.
6312pub(crate) const SESSION_RESUME_METHOD_NAME: &str = "session/resume";
6313/// Method name for closing an active session.
6314pub(crate) const SESSION_CLOSE_METHOD_NAME: &str = "session/close";
6315/// Method name for logging out of an authenticated session.
6316pub(crate) const LOGOUT_METHOD_NAME: &str = "logout";
6317/// Method name for the `auth/status` request.
6318#[cfg(feature = "unstable_auth_status")]
6319pub(crate) const AUTH_STATUS_METHOD_NAME: &str = "auth/status";
6320
6321/// All possible requests that a client can send to an agent.
6322///
6323/// This enum is used internally for routing RPC requests. You typically won't need
6324/// to use this directly.
6325///
6326/// This enum encompasses all method calls from client to agent.
6327#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
6328#[derive(Clone, Debug, Serialize, Deserialize)]
6329#[serde(untagged)]
6330#[cfg_attr(feature = "schemars", schemars(inline))]
6331#[non_exhaustive]
6332#[allow(clippy::large_enum_variant)]
6333pub enum ClientRequest {
6334    /// Establishes the connection with a client and negotiates protocol capabilities.
6335    ///
6336    /// This method is called once at the beginning of the connection to:
6337    /// - Negotiate the protocol version to use
6338    /// - Exchange capability information between client and agent
6339    /// - Determine available authentication methods
6340    ///
6341    /// The agent should respond with its supported protocol version and capabilities.
6342    ///
6343    /// See protocol docs: [Initialization](https://agentclientprotocol.com/protocol/v1/initialization)
6344    InitializeRequest(InitializeRequest),
6345    /// Authenticates the client using the specified authentication method.
6346    ///
6347    /// Called when the agent requires authentication before allowing session creation.
6348    /// The client provides an authentication method ID that was advertised during
6349    /// initialization and whose type defines the `authenticate` flow.
6350    ///
6351    /// After successful authentication, the client can proceed to create sessions with
6352    /// `session/new` without receiving an `auth_required` (`-32000`) error.
6353    ///
6354    /// See protocol docs: [Initialization](https://agentclientprotocol.com/protocol/v1/initialization)
6355    AuthenticateRequest(AuthenticateRequest),
6356    /// **UNSTABLE**
6357    ///
6358    /// This capability is not part of the spec yet, and may be removed or changed at any point.
6359    ///
6360    /// Lists providers that can be configured by the client.
6361    #[cfg(feature = "unstable_llm_providers")]
6362    ListProvidersRequest(ListProvidersRequest),
6363    /// **UNSTABLE**
6364    ///
6365    /// This capability is not part of the spec yet, and may be removed or changed at any point.
6366    ///
6367    /// Replaces the configuration for a provider.
6368    #[cfg(feature = "unstable_llm_providers")]
6369    SetProviderRequest(SetProviderRequest),
6370    /// **UNSTABLE**
6371    ///
6372    /// This capability is not part of the spec yet, and may be removed or changed at any point.
6373    ///
6374    /// Disables a provider.
6375    #[cfg(feature = "unstable_llm_providers")]
6376    DisableProviderRequest(DisableProviderRequest),
6377    /// Logs out of the current authenticated state.
6378    ///
6379    /// After a successful logout, all new sessions will require authentication.
6380    /// There is no guarantee about the behavior of already running sessions.
6381    LogoutRequest(LogoutRequest),
6382    /// **UNSTABLE**
6383    ///
6384    /// This capability is not part of the spec yet, and may be removed or changed at any point.
6385    ///
6386    /// Queries the agent's current authentication state.
6387    ///
6388    /// This method is only available if the agent advertises the `auth.status` capability.
6389    /// It MUST NOT change any agent state, and agents MUST NOT reject it with `auth_required`.
6390    #[cfg(feature = "unstable_auth_status")]
6391    AuthStatusRequest(AuthStatusRequest),
6392    /// Creates a new conversation session with the agent.
6393    ///
6394    /// Sessions represent independent conversation contexts with their own history and state.
6395    ///
6396    /// The agent should:
6397    /// - Create a new session context
6398    /// - Connect to any specified MCP servers
6399    /// - Return a unique session ID for future requests
6400    ///
6401    /// May return an `auth_required` (`-32000`) error if the agent requires authentication.
6402    ///
6403    /// See protocol docs: [Session Setup](https://agentclientprotocol.com/protocol/v1/session-setup)
6404    NewSessionRequest(NewSessionRequest),
6405    /// Loads an existing session to resume a previous conversation.
6406    ///
6407    /// This method is only available if the agent advertises the `loadSession` capability.
6408    ///
6409    /// The agent should:
6410    /// - Restore the session context and conversation history
6411    /// - Connect to the specified MCP servers
6412    /// - Stream the entire conversation history back to the client via notifications
6413    ///
6414    /// See protocol docs: [Loading Sessions](https://agentclientprotocol.com/protocol/v1/session-setup#loading-sessions)
6415    LoadSessionRequest(LoadSessionRequest),
6416    /// Lists existing sessions known to the agent.
6417    ///
6418    /// This method is only available if the agent advertises the `sessionCapabilities.list` capability.
6419    ///
6420    /// The agent should return metadata about sessions with optional filtering and pagination support.
6421    ListSessionsRequest(ListSessionsRequest),
6422    /// Deletes an existing session from `session/list`.
6423    ///
6424    /// This method is only available if the agent advertises the `sessionCapabilities.delete` capability.
6425    DeleteSessionRequest(DeleteSessionRequest),
6426    #[cfg(feature = "unstable_session_fork")]
6427    /// **UNSTABLE**
6428    ///
6429    /// This capability is not part of the spec yet, and may be removed or changed at any point.
6430    ///
6431    /// Forks an existing session to create a new independent session.
6432    ///
6433    /// This method is only available if the agent advertises the `session.fork` capability.
6434    ///
6435    /// The agent should create a new session with the same conversation context as the
6436    /// original, allowing operations like generating summaries without affecting the
6437    /// original session's history.
6438    ///
6439    /// As with `session/new`, the forked session is active once the agent responds,
6440    /// set up with the request's `cwd`, `additionalDirectories`, and `mcpServers`.
6441    /// The client can prompt it without calling `session/load` or `session/resume` first.
6442    ForkSessionRequest(ForkSessionRequest),
6443    #[cfg(feature = "unstable_session_archive")]
6444    /// **UNSTABLE**
6445    ///
6446    /// This capability is not part of the spec yet, and may be removed or changed at any point.
6447    ///
6448    /// Archives a session, hiding it from default `session/list` results.
6449    ///
6450    /// This method is only available if the agent advertises the `sessionCapabilities.archive` capability.
6451    ArchiveSessionRequest(ArchiveSessionRequest),
6452    #[cfg(feature = "unstable_session_archive")]
6453    /// **UNSTABLE**
6454    ///
6455    /// This capability is not part of the spec yet, and may be removed or changed at any point.
6456    ///
6457    /// Unarchives a session, returning it to default `session/list` results.
6458    ///
6459    /// This method is only available if the agent advertises the `sessionCapabilities.archive` capability.
6460    UnarchiveSessionRequest(UnarchiveSessionRequest),
6461    #[cfg(feature = "unstable_session_status")]
6462    /// **UNSTABLE**
6463    ///
6464    /// This capability is not part of the spec yet, and may be removed or changed at any point.
6465    ///
6466    /// Checks whether the Agent has a session in memory, without changing it.
6467    ///
6468    /// This method is only available if the agent advertises the `sessionCapabilities.status` capability.
6469    SessionStatusRequest(SessionStatusRequest),
6470    #[cfg(feature = "unstable_session_set_title")]
6471    /// **UNSTABLE**
6472    ///
6473    /// This capability is not part of the spec yet, and may be removed or changed at any point.
6474    ///
6475    /// Sets the title of a session.
6476    ///
6477    /// This method is only available if the agent advertises the `sessionCapabilities.title` capability.
6478    ///
6479    /// The session does not need to be active on the connection. The agent stores the
6480    /// title and returns the stored title, which may be normalized.
6481    SetSessionTitleRequest(SetSessionTitleRequest),
6482    /// Resumes an existing session without returning previous messages.
6483    ///
6484    /// This method is only available if the agent advertises the `sessionCapabilities.resume` capability.
6485    ///
6486    /// The agent should resume the session context, allowing the conversation to continue
6487    /// without replaying the message history (unlike `session/load`).
6488    ResumeSessionRequest(ResumeSessionRequest),
6489    /// Closes an active session and frees up any resources associated with it.
6490    ///
6491    /// This method is only available if the agent advertises the `sessionCapabilities.close` capability.
6492    ///
6493    /// The agent must cancel any ongoing work (as if `session/cancel` was called)
6494    /// and then free up any resources associated with the session.
6495    CloseSessionRequest(CloseSessionRequest),
6496    /// Sets the current mode for a session.
6497    ///
6498    /// Allows switching between different agent modes (e.g., "ask", "architect", "code")
6499    /// that affect system prompts, tool availability, and permission behaviors.
6500    ///
6501    /// The mode must be one of the modes advertised in `availableModes` during session
6502    /// creation or loading. Agents may also change modes autonomously and notify the
6503    /// client via `current_mode_update` notifications.
6504    ///
6505    /// This method can be called at any time during a session, whether the Agent is
6506    /// idle or actively generating a response.
6507    ///
6508    /// See protocol docs: [Session Modes](https://agentclientprotocol.com/protocol/v1/session-modes)
6509    SetSessionModeRequest(SetSessionModeRequest),
6510    /// Sets the current value for a session configuration option.
6511    SetSessionConfigOptionRequest(SetSessionConfigOptionRequest),
6512    /// Processes a user prompt within a session.
6513    ///
6514    /// This method handles the whole lifecycle of a prompt:
6515    /// - Receives user messages with optional context (files, images, etc.)
6516    /// - Processes the prompt using language models
6517    /// - Reports language model content and tool calls to the Clients
6518    /// - Requests permission to run tools
6519    /// - Executes any requested tool calls
6520    /// - Returns when the turn is complete with a stop reason
6521    ///
6522    /// See protocol docs: [Prompt Turn](https://agentclientprotocol.com/protocol/v1/prompt-turn)
6523    PromptRequest(PromptRequest),
6524    /// Handles extension method requests from the client.
6525    ///
6526    /// Extension methods provide a way to add custom functionality while maintaining
6527    /// protocol compatibility.
6528    ///
6529    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v1/extensibility)
6530    ExtMethodRequest(ExtRequest),
6531}
6532
6533impl ClientRequest {
6534    /// Returns the corresponding method name of the request.
6535    #[must_use]
6536    pub fn method(&self) -> &str {
6537        match self {
6538            Self::InitializeRequest(_) => AGENT_METHOD_NAMES.initialize,
6539            Self::AuthenticateRequest(_) => AGENT_METHOD_NAMES.authenticate,
6540            #[cfg(feature = "unstable_llm_providers")]
6541            Self::ListProvidersRequest(_) => AGENT_METHOD_NAMES.providers_list,
6542            #[cfg(feature = "unstable_llm_providers")]
6543            Self::SetProviderRequest(_) => AGENT_METHOD_NAMES.providers_set,
6544            #[cfg(feature = "unstable_llm_providers")]
6545            Self::DisableProviderRequest(_) => AGENT_METHOD_NAMES.providers_disable,
6546            Self::LogoutRequest(_) => AGENT_METHOD_NAMES.logout,
6547            #[cfg(feature = "unstable_auth_status")]
6548            Self::AuthStatusRequest(_) => AGENT_METHOD_NAMES.auth_status,
6549            Self::NewSessionRequest(_) => AGENT_METHOD_NAMES.session_new,
6550            Self::LoadSessionRequest(_) => AGENT_METHOD_NAMES.session_load,
6551            Self::ListSessionsRequest(_) => AGENT_METHOD_NAMES.session_list,
6552            Self::DeleteSessionRequest(_) => AGENT_METHOD_NAMES.session_delete,
6553            #[cfg(feature = "unstable_session_fork")]
6554            Self::ForkSessionRequest(_) => AGENT_METHOD_NAMES.session_fork,
6555            #[cfg(feature = "unstable_session_archive")]
6556            Self::ArchiveSessionRequest(_) => AGENT_METHOD_NAMES.session_archive,
6557            #[cfg(feature = "unstable_session_archive")]
6558            Self::UnarchiveSessionRequest(_) => AGENT_METHOD_NAMES.session_unarchive,
6559            #[cfg(feature = "unstable_session_status")]
6560            Self::SessionStatusRequest(_) => AGENT_METHOD_NAMES.session_status,
6561            #[cfg(feature = "unstable_session_set_title")]
6562            Self::SetSessionTitleRequest(_) => AGENT_METHOD_NAMES.session_set_title,
6563            Self::ResumeSessionRequest(_) => AGENT_METHOD_NAMES.session_resume,
6564            Self::CloseSessionRequest(_) => AGENT_METHOD_NAMES.session_close,
6565            Self::SetSessionModeRequest(_) => AGENT_METHOD_NAMES.session_set_mode,
6566            Self::SetSessionConfigOptionRequest(_) => AGENT_METHOD_NAMES.session_set_config_option,
6567            Self::PromptRequest(_) => AGENT_METHOD_NAMES.session_prompt,
6568            Self::ExtMethodRequest(ext_request) => &ext_request.method,
6569        }
6570    }
6571}
6572
6573/// All possible responses that an agent can send to a client.
6574///
6575/// This enum is used internally for routing RPC responses. You typically won't need
6576/// to use this directly - the responses are handled automatically by the connection.
6577///
6578/// These are responses to the corresponding `ClientRequest` variants.
6579#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
6580#[derive(Clone, Debug, Serialize, Deserialize)]
6581#[serde(untagged)]
6582#[cfg_attr(feature = "schemars", schemars(inline))]
6583#[non_exhaustive]
6584#[allow(clippy::large_enum_variant)]
6585pub enum AgentResponse {
6586    /// Successful result returned for a `initialize` request.
6587    InitializeResponse(InitializeResponse),
6588    /// Successful result returned for a `authenticate` request.
6589    AuthenticateResponse(#[serde(default)] AuthenticateResponse),
6590    /// Successful result returned for a `providers/list` request.
6591    #[cfg(feature = "unstable_llm_providers")]
6592    ListProvidersResponse(ListProvidersResponse),
6593    /// Successful result returned for a `providers/set` request.
6594    #[cfg(feature = "unstable_llm_providers")]
6595    SetProviderResponse(#[serde(default)] SetProviderResponse),
6596    /// Successful result returned for a `providers/disable` request.
6597    #[cfg(feature = "unstable_llm_providers")]
6598    DisableProviderResponse(#[serde(default)] DisableProviderResponse),
6599    /// Successful result returned for a `logout` request.
6600    LogoutResponse(#[serde(default)] LogoutResponse),
6601    /// Successful result returned for an `auth/status` request.
6602    #[cfg(feature = "unstable_auth_status")]
6603    AuthStatusResponse(AuthStatusResponse),
6604    /// Successful result returned for a `session/new` request.
6605    NewSessionResponse(NewSessionResponse),
6606    /// Successful result returned for a `session/load` request.
6607    LoadSessionResponse(#[serde(default)] LoadSessionResponse),
6608    /// Successful result returned for a `session/list` request.
6609    ListSessionsResponse(ListSessionsResponse),
6610    /// Successful result returned for a `session/delete` request.
6611    DeleteSessionResponse(#[serde(default)] DeleteSessionResponse),
6612    /// Successful result returned for a `session/fork` request.
6613    #[cfg(feature = "unstable_session_fork")]
6614    ForkSessionResponse(ForkSessionResponse),
6615    /// Successful result returned for a `session/archive` request.
6616    #[cfg(feature = "unstable_session_archive")]
6617    ArchiveSessionResponse(#[serde(default)] ArchiveSessionResponse),
6618    /// Successful result returned for a `session/unarchive` request.
6619    #[cfg(feature = "unstable_session_archive")]
6620    UnarchiveSessionResponse(#[serde(default)] UnarchiveSessionResponse),
6621    /// Successful result returned for a `session/status` request.
6622    #[cfg(feature = "unstable_session_status")]
6623    SessionStatusResponse(SessionStatusResponse),
6624    /// Successful result returned for a `session/set_title` request.
6625    #[cfg(feature = "unstable_session_set_title")]
6626    SetSessionTitleResponse(SetSessionTitleResponse),
6627    /// Successful result returned for a `session/resume` request.
6628    ResumeSessionResponse(#[serde(default)] ResumeSessionResponse),
6629    /// Successful result returned for a `session/close` request.
6630    CloseSessionResponse(#[serde(default)] CloseSessionResponse),
6631    /// Successful result returned for a `session/set_mode` request.
6632    SetSessionModeResponse(#[serde(default)] SetSessionModeResponse),
6633    /// Successful result returned for a `session/set_config_option` request.
6634    SetSessionConfigOptionResponse(SetSessionConfigOptionResponse),
6635    /// Successful result returned for a `session/prompt` request.
6636    PromptResponse(PromptResponse),
6637    /// Successful result returned by an extension method outside the core ACP method set.
6638    ExtMethodResponse(ExtResponse),
6639}
6640
6641/// All possible notifications that a client can send to an agent.
6642///
6643/// This enum is used internally for routing RPC notifications. You typically won't need
6644/// to use this directly.
6645///
6646/// Notifications do not expect a response.
6647#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
6648#[derive(Clone, Debug, Serialize, Deserialize)]
6649#[serde(untagged)]
6650#[cfg_attr(feature = "schemars", schemars(inline))]
6651#[non_exhaustive]
6652#[allow(clippy::large_enum_variant)]
6653pub enum ClientNotification {
6654    /// Cancels ongoing operations for a session.
6655    ///
6656    /// This is a notification sent by the client to cancel an ongoing prompt turn.
6657    ///
6658    /// Upon receiving this notification, the Agent SHOULD:
6659    /// - Stop all language model requests as soon as possible
6660    /// - Abort all tool call invocations in progress
6661    /// - Send any pending `session/update` notifications
6662    /// - Respond to the original `session/prompt` request with the `cancelled` stop reason
6663    ///
6664    /// See protocol docs: [Cancellation](https://agentclientprotocol.com/protocol/v1/prompt-turn#cancellation)
6665    CancelNotification(CancelNotification),
6666    /// **UNSTABLE**
6667    ///
6668    /// This capability is not part of the spec yet, and may be removed or changed at any point.
6669    ///
6670    /// Sends an MCP-over-ACP notification.
6671    #[cfg(feature = "unstable_mcp_over_acp")]
6672    MessageMcpNotification(MessageMcpNotification),
6673    /// Handles extension notifications from the client.
6674    ///
6675    /// Extension notifications provide a way to send one-way messages for custom functionality
6676    /// while maintaining protocol compatibility.
6677    ///
6678    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v1/extensibility)
6679    ExtNotification(ExtNotification),
6680}
6681
6682impl ClientNotification {
6683    /// Returns the corresponding method name of the notification.
6684    #[must_use]
6685    pub fn method(&self) -> &str {
6686        match self {
6687            Self::CancelNotification(_) => AGENT_METHOD_NAMES.session_cancel,
6688            #[cfg(feature = "unstable_mcp_over_acp")]
6689            Self::MessageMcpNotification(_) => AGENT_METHOD_NAMES.mcp_message,
6690            Self::ExtNotification(ext_notification) => &ext_notification.method,
6691        }
6692    }
6693}
6694
6695/// Notification to cancel ongoing operations for a session.
6696///
6697/// See protocol docs: [Cancellation](https://agentclientprotocol.com/protocol/v1/prompt-turn#cancellation)
6698#[serde_as]
6699#[skip_serializing_none]
6700#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
6701#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
6702#[cfg_attr(feature = "schemars", schemars(extend("x-side" = "agent", "x-method" = SESSION_CANCEL_METHOD_NAME)))]
6703#[serde(rename_all = "camelCase")]
6704#[non_exhaustive]
6705pub struct CancelNotification {
6706    /// The ID of the session to cancel operations for.
6707    pub session_id: SessionId,
6708    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
6709    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
6710    /// these keys.
6711    ///
6712    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v1/extensibility)
6713    #[serde_as(deserialize_as = "DefaultOnError")]
6714    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
6715    #[serde(default)]
6716    #[serde(rename = "_meta")]
6717    pub meta: Option<Meta>,
6718}
6719
6720impl CancelNotification {
6721    /// Builds [`CancelNotification`] with the required notification fields set. Optional fields start unset or empty.
6722    #[must_use]
6723    pub fn new(session_id: impl Into<SessionId>) -> Self {
6724        Self {
6725            session_id: session_id.into(),
6726            meta: None,
6727        }
6728    }
6729
6730    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
6731    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
6732    /// these keys.
6733    ///
6734    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v1/extensibility)
6735    #[must_use]
6736    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
6737        self.meta = meta.into_option();
6738        self
6739    }
6740}
6741
6742#[cfg(test)]
6743mod test_serialization {
6744    use super::*;
6745    use serde_json::json;
6746
6747    fn test_meta() -> Meta {
6748        json!({ "source": "test" }).as_object().unwrap().clone()
6749    }
6750
6751    fn serialized_meta_key_count(value: &impl serde::Serialize) -> usize {
6752        serde_json::to_string(value)
6753            .unwrap()
6754            .matches("\"_meta\"")
6755            .count()
6756    }
6757
6758    /// v1 reports prompt failures as JSON-RPC errors. Only the unstable subagent
6759    /// snapshot has an `error` stop reason, because a child has no prompt response.
6760    #[test]
6761    fn prompt_response_has_no_error_stop_reason() {
6762        assert_eq!(
6763            serde_json::from_value::<PromptResponse>(json!({ "stopReason": "end_turn" }))
6764                .unwrap()
6765                .stop_reason,
6766            StopReason::EndTurn
6767        );
6768        assert!(
6769            serde_json::from_value::<PromptResponse>(json!({ "stopReason": "error" })).is_err()
6770        );
6771    }
6772
6773    #[test]
6774    fn test_initialize_capabilities_default_on_malformed_values() {
6775        let request: InitializeRequest = serde_json::from_value(json!({
6776            "protocolVersion": 1,
6777            "clientCapabilities": false
6778        }))
6779        .unwrap();
6780        assert_eq!(request.client_capabilities, ClientCapabilities::default());
6781
6782        let response: InitializeResponse = serde_json::from_value(json!({
6783            "protocolVersion": 1,
6784            "agentCapabilities": false
6785        }))
6786        .unwrap();
6787        assert_eq!(response.agent_capabilities, AgentCapabilities::default());
6788    }
6789
6790    #[test]
6791    fn test_agent_capabilities_default_on_malformed_values() {
6792        let capabilities: AgentCapabilities = serde_json::from_value(json!({
6793            "loadSession": "yes",
6794            "promptCapabilities": {
6795                "image": "yes",
6796                "audio": true,
6797                "embeddedContext": {}
6798            },
6799            "mcpCapabilities": {
6800                "http": "yes",
6801                "sse": true
6802            },
6803            "sessionCapabilities": false,
6804            "auth": false
6805        }))
6806        .unwrap();
6807
6808        assert!(!capabilities.load_session);
6809        assert!(!capabilities.prompt_capabilities.image);
6810        assert!(capabilities.prompt_capabilities.audio);
6811        assert!(!capabilities.prompt_capabilities.embedded_context);
6812        assert!(!capabilities.mcp_capabilities.http);
6813        assert!(capabilities.mcp_capabilities.sse);
6814        assert_eq!(
6815            capabilities.session_capabilities,
6816            SessionCapabilities::default()
6817        );
6818        assert_eq!(capabilities.auth, AgentAuthCapabilities::default());
6819    }
6820
6821    #[test]
6822    fn test_mcp_server_stdio_serialization() {
6823        let server = McpServer::Stdio(
6824            McpServerStdio::new("test-server", "/usr/bin/server")
6825                .args(vec!["--port".to_string(), "3000".to_string()])
6826                .env(vec![EnvVariable::new("API_KEY", "secret123")]),
6827        );
6828
6829        let json = serde_json::to_value(&server).unwrap();
6830        assert_eq!(
6831            json,
6832            json!({
6833                "name": "test-server",
6834                "command": "/usr/bin/server",
6835                "args": ["--port", "3000"],
6836                "env": [
6837                    {
6838                        "name": "API_KEY",
6839                        "value": "secret123"
6840                    }
6841                ]
6842            })
6843        );
6844
6845        let deserialized: McpServer = serde_json::from_value(json).unwrap();
6846        match deserialized {
6847            McpServer::Stdio(McpServerStdio {
6848                name,
6849                command,
6850                args,
6851                env,
6852                meta: _,
6853            }) => {
6854                assert_eq!(name, "test-server");
6855                assert_eq!(command, PathBuf::from("/usr/bin/server"));
6856                assert_eq!(args, vec!["--port", "3000"]);
6857                assert_eq!(env.len(), 1);
6858                assert_eq!(env[0].name, "API_KEY");
6859                assert_eq!(env[0].value, "secret123");
6860            }
6861            _ => panic!("Expected Stdio variant"),
6862        }
6863    }
6864
6865    #[test]
6866    fn test_mcp_server_http_serialization() {
6867        let server = McpServer::Http(
6868            McpServerHttp::new("http-server", "https://api.example.com").headers(vec![
6869                HttpHeader::new("Authorization", "Bearer token123"),
6870                HttpHeader::new("Content-Type", "application/json"),
6871            ]),
6872        );
6873
6874        let json = serde_json::to_value(&server).unwrap();
6875        assert_eq!(
6876            json,
6877            json!({
6878                "type": "http",
6879                "name": "http-server",
6880                "url": "https://api.example.com",
6881                "headers": [
6882                    {
6883                        "name": "Authorization",
6884                        "value": "Bearer token123"
6885                    },
6886                    {
6887                        "name": "Content-Type",
6888                        "value": "application/json"
6889                    }
6890                ]
6891            })
6892        );
6893
6894        let deserialized: McpServer = serde_json::from_value(json).unwrap();
6895        match deserialized {
6896            McpServer::Http(McpServerHttp {
6897                name,
6898                url,
6899                headers,
6900                meta: _,
6901            }) => {
6902                assert_eq!(name, "http-server");
6903                assert_eq!(url, "https://api.example.com");
6904                assert_eq!(headers.len(), 2);
6905                assert_eq!(headers[0].name, "Authorization");
6906                assert_eq!(headers[0].value, "Bearer token123");
6907                assert_eq!(headers[1].name, "Content-Type");
6908                assert_eq!(headers[1].value, "application/json");
6909            }
6910            _ => panic!("Expected Http variant"),
6911        }
6912    }
6913
6914    #[cfg(feature = "unstable_mcp_over_acp")]
6915    #[test]
6916    fn test_mcp_server_acp_serialization() {
6917        let server = McpServer::Acp(McpServerAcp::new("project-tools", "project-tools-id"));
6918
6919        let json = serde_json::to_value(&server).unwrap();
6920        assert_eq!(
6921            json,
6922            json!({
6923                "type": "acp",
6924                "name": "project-tools",
6925                "serverId": "project-tools-id"
6926            })
6927        );
6928
6929        let deserialized: McpServer = serde_json::from_value(json).unwrap();
6930        match deserialized {
6931            McpServer::Acp(McpServerAcp {
6932                name,
6933                server_id: id,
6934                meta: _,
6935            }) => {
6936                assert_eq!(name, "project-tools");
6937                assert_eq!(id, McpServerAcpId::new("project-tools-id"));
6938            }
6939            _ => panic!("Expected Acp variant"),
6940        }
6941    }
6942
6943    #[cfg(feature = "unstable_mcp_over_acp")]
6944    #[test]
6945    fn test_client_mcp_message_method_names() {
6946        use serde_json::json;
6947
6948        assert_eq!(AGENT_METHOD_NAMES.mcp_message, "mcp/message");
6949
6950        let notification =
6951            MessageMcpNotification::new("server-1", "req-1", "notifications/progress");
6952        assert_eq!(
6953            ClientNotification::MessageMcpNotification(notification.clone()).method(),
6954            "mcp/message"
6955        );
6956        assert_eq!(
6957            serde_json::to_value(notification).unwrap(),
6958            json!({
6959                "serverId": "server-1",
6960                "requestId": "req-1",
6961                "method": "notifications/progress"
6962            })
6963        );
6964        let notification: MessageMcpNotification = serde_json::from_value(json!({
6965            "serverId": "server-1", "requestId": "req-1", "method": "notifications/progress",
6966            "params": null, "_meta": null
6967        }))
6968        .unwrap();
6969        assert_eq!(notification.params, None);
6970        assert_eq!(notification.meta, None);
6971        for key in ["serverId", "requestId", "method"] {
6972            let mut value = json!({"serverId":"server-1", "requestId":"req-1", "method":"notifications/progress"});
6973            value.as_object_mut().unwrap().remove(key);
6974            assert!(serde_json::from_value::<MessageMcpNotification>(value).is_err());
6975        }
6976    }
6977
6978    #[cfg(all(feature = "unstable_mcp_over_acp", feature = "schemars"))]
6979    #[test]
6980    fn test_mcp_server_acp_schema() {
6981        let mcp_server_schema = serde_json::to_value(schemars::schema_for!(McpServer)).unwrap();
6982        assert!(json_contains_entry(
6983            &mcp_server_schema,
6984            "const",
6985            &json!("acp")
6986        ));
6987        assert!(json_contains_entry(
6988            &mcp_server_schema,
6989            "$ref",
6990            &json!("#/$defs/McpServerAcp")
6991        ));
6992
6993        let capabilities_schema =
6994            serde_json::to_value(schemars::schema_for!(McpCapabilities)).unwrap();
6995        assert!(json_contains_key(&capabilities_schema, "acp"));
6996    }
6997
6998    #[cfg(all(feature = "unstable_mcp_over_acp", feature = "schemars"))]
6999    fn json_contains_entry(
7000        value: &serde_json::Value,
7001        key: &str,
7002        expected: &serde_json::Value,
7003    ) -> bool {
7004        match value {
7005            serde_json::Value::Object(map) => {
7006                map.get(key) == Some(expected)
7007                    || map
7008                        .values()
7009                        .any(|value| json_contains_entry(value, key, expected))
7010            }
7011            serde_json::Value::Array(values) => values
7012                .iter()
7013                .any(|value| json_contains_entry(value, key, expected)),
7014            _ => false,
7015        }
7016    }
7017
7018    #[cfg(all(feature = "unstable_mcp_over_acp", feature = "schemars"))]
7019    fn json_contains_key(value: &serde_json::Value, key: &str) -> bool {
7020        match value {
7021            serde_json::Value::Object(map) => {
7022                map.contains_key(key) || map.values().any(|value| json_contains_key(value, key))
7023            }
7024            serde_json::Value::Array(values) => {
7025                values.iter().any(|value| json_contains_key(value, key))
7026            }
7027            _ => false,
7028        }
7029    }
7030
7031    #[test]
7032    fn test_mcp_server_sse_serialization() {
7033        let server = McpServer::Sse(
7034            McpServerSse::new("sse-server", "https://sse.example.com/events")
7035                .headers(vec![HttpHeader::new("X-API-Key", "apikey456")]),
7036        );
7037
7038        let json = serde_json::to_value(&server).unwrap();
7039        assert_eq!(
7040            json,
7041            json!({
7042                "type": "sse",
7043                "name": "sse-server",
7044                "url": "https://sse.example.com/events",
7045                "headers": [
7046                    {
7047                        "name": "X-API-Key",
7048                        "value": "apikey456"
7049                    }
7050                ]
7051            })
7052        );
7053
7054        let deserialized: McpServer = serde_json::from_value(json).unwrap();
7055        match deserialized {
7056            McpServer::Sse(McpServerSse {
7057                name,
7058                url,
7059                headers,
7060                meta: _,
7061            }) => {
7062                assert_eq!(name, "sse-server");
7063                assert_eq!(url, "https://sse.example.com/events");
7064                assert_eq!(headers.len(), 1);
7065                assert_eq!(headers[0].name, "X-API-Key");
7066                assert_eq!(headers[0].value, "apikey456");
7067            }
7068            _ => panic!("Expected Sse variant"),
7069        }
7070    }
7071
7072    #[test]
7073    fn test_session_config_option_category_known_variants() {
7074        // Test serialization of known variants
7075        assert_eq!(
7076            serde_json::to_value(&SessionConfigOptionCategory::Mode).unwrap(),
7077            json!("mode")
7078        );
7079        assert_eq!(
7080            serde_json::to_value(&SessionConfigOptionCategory::Model).unwrap(),
7081            json!("model")
7082        );
7083        assert_eq!(
7084            serde_json::to_value(&SessionConfigOptionCategory::ModelConfig).unwrap(),
7085            json!("model_config")
7086        );
7087        assert_eq!(
7088            serde_json::to_value(&SessionConfigOptionCategory::ThoughtLevel).unwrap(),
7089            json!("thought_level")
7090        );
7091
7092        // Test deserialization of known variants
7093        assert_eq!(
7094            serde_json::from_str::<SessionConfigOptionCategory>("\"mode\"").unwrap(),
7095            SessionConfigOptionCategory::Mode
7096        );
7097        assert_eq!(
7098            serde_json::from_str::<SessionConfigOptionCategory>("\"model\"").unwrap(),
7099            SessionConfigOptionCategory::Model
7100        );
7101        assert_eq!(
7102            serde_json::from_str::<SessionConfigOptionCategory>("\"model_config\"").unwrap(),
7103            SessionConfigOptionCategory::ModelConfig
7104        );
7105        assert_eq!(
7106            serde_json::from_str::<SessionConfigOptionCategory>("\"thought_level\"").unwrap(),
7107            SessionConfigOptionCategory::ThoughtLevel
7108        );
7109    }
7110
7111    #[test]
7112    fn test_session_config_option_category_unknown_variants() {
7113        // Test that unknown strings are captured in Other variant
7114        let unknown: SessionConfigOptionCategory =
7115            serde_json::from_str("\"some_future_category\"").unwrap();
7116        assert_eq!(
7117            unknown,
7118            SessionConfigOptionCategory::Other("some_future_category".to_string())
7119        );
7120
7121        // Test round-trip of unknown category
7122        let json = serde_json::to_value(&unknown).unwrap();
7123        assert_eq!(json, json!("some_future_category"));
7124    }
7125
7126    #[test]
7127    fn test_session_config_option_category_custom_categories() {
7128        // Category names beginning with `_` are free for custom use
7129        let custom: SessionConfigOptionCategory =
7130            serde_json::from_str("\"_my_custom_category\"").unwrap();
7131        assert_eq!(
7132            custom,
7133            SessionConfigOptionCategory::Other("_my_custom_category".to_string())
7134        );
7135
7136        // Test round-trip preserves the custom category name
7137        let json = serde_json::to_value(&custom).unwrap();
7138        assert_eq!(json, json!("_my_custom_category"));
7139
7140        // Deserialize back and verify
7141        let deserialized: SessionConfigOptionCategory = serde_json::from_value(json).unwrap();
7142        assert_eq!(
7143            deserialized,
7144            SessionConfigOptionCategory::Other("_my_custom_category".to_string()),
7145        );
7146    }
7147
7148    #[test]
7149    fn test_auth_method_agent_serialization() {
7150        let method = AuthMethod::Agent(AuthMethodAgent::new("default-auth", "Default Auth"));
7151
7152        let json = serde_json::to_value(&method).unwrap();
7153        assert_eq!(
7154            json,
7155            json!({
7156                "id": "default-auth",
7157                "name": "Default Auth"
7158            })
7159        );
7160        // description should be omitted when None
7161        assert!(!json.as_object().unwrap().contains_key("description"));
7162        // Agent variant should not emit a `type` field (backward compat)
7163        assert!(!json.as_object().unwrap().contains_key("type"));
7164
7165        let deserialized: AuthMethod = serde_json::from_value(json).unwrap();
7166        match deserialized {
7167            AuthMethod::Agent(AuthMethodAgent { id, name, .. }) => {
7168                assert_eq!(id.0.as_ref(), "default-auth");
7169                assert_eq!(name, "Default Auth");
7170            }
7171            _ => panic!("Expected Agent variant"),
7172        }
7173    }
7174
7175    #[test]
7176    fn test_auth_method_explicit_agent_deserialization() {
7177        // An explicit `"type": "agent"` should also deserialize to Agent
7178        let json = json!({
7179            "id": "agent-auth",
7180            "name": "Agent Auth",
7181            "type": "agent"
7182        });
7183
7184        let deserialized: AuthMethod = serde_json::from_value(json).unwrap();
7185        assert!(matches!(deserialized, AuthMethod::Agent(_)));
7186    }
7187
7188    #[test]
7189    fn test_session_delete_serialization() {
7190        assert_eq!(AGENT_METHOD_NAMES.session_delete, "session/delete");
7191        assert_eq!(
7192            ClientRequest::DeleteSessionRequest(DeleteSessionRequest::new("sess_abc123")).method(),
7193            "session/delete"
7194        );
7195        assert_eq!(
7196            serde_json::to_value(DeleteSessionRequest::new("sess_abc123")).unwrap(),
7197            json!({
7198                "sessionId": "sess_abc123"
7199            })
7200        );
7201        assert_eq!(
7202            serde_json::to_value(DeleteSessionResponse::new()).unwrap(),
7203            json!({})
7204        );
7205        assert_eq!(
7206            serde_json::to_value(
7207                SessionCapabilities::new().delete(SessionDeleteCapabilities::new())
7208            )
7209            .unwrap(),
7210            json!({
7211                "delete": {}
7212            })
7213        );
7214    }
7215    #[cfg(feature = "unstable_session_set_title")]
7216    #[test]
7217    fn test_session_set_title_serialization() {
7218        assert_eq!(AGENT_METHOD_NAMES.session_set_title, "session/set_title");
7219        assert_eq!(
7220            ClientRequest::SetSessionTitleRequest(SetSessionTitleRequest::new(
7221                "sess_abc123",
7222                "Investigate OAuth timeout"
7223            ))
7224            .method(),
7225            "session/set_title"
7226        );
7227        assert_eq!(
7228            serde_json::to_value(SetSessionTitleRequest::new(
7229                "sess_abc123",
7230                "Investigate OAuth timeout"
7231            ))
7232            .unwrap(),
7233            json!({
7234                "sessionId": "sess_abc123",
7235                "title": "Investigate OAuth timeout"
7236            })
7237        );
7238        assert_eq!(
7239            serde_json::to_value(SetSessionTitleResponse::new("Investigate OAuth timeout"))
7240                .unwrap(),
7241            json!({
7242                "title": "Investigate OAuth timeout"
7243            })
7244        );
7245        assert_eq!(
7246            serde_json::to_value(SessionCapabilities::new().title(SessionTitleCapabilities::new()))
7247                .unwrap(),
7248            json!({
7249                "title": {}
7250            })
7251        );
7252    }
7253
7254    #[cfg(feature = "unstable_session_set_title")]
7255    #[test]
7256    fn test_session_set_title_requires_title() {
7257        for params in [
7258            json!({"sessionId": "sess_abc123"}),
7259            json!({"sessionId": "sess_abc123", "title": null}),
7260            json!({"sessionId": "sess_abc123", "title": 42}),
7261        ] {
7262            assert!(serde_json::from_value::<SetSessionTitleRequest>(params).is_err());
7263        }
7264        for result in [json!({}), json!({"title": null})] {
7265            assert!(serde_json::from_value::<SetSessionTitleResponse>(result).is_err());
7266        }
7267    }
7268
7269    #[cfg(feature = "unstable_session_status")]
7270    #[test]
7271    fn test_session_status_serialization() {
7272        assert_eq!(AGENT_METHOD_NAMES.session_status, "session/status");
7273        assert_eq!(
7274            ClientRequest::SessionStatusRequest(SessionStatusRequest::new("sess_abc123")).method(),
7275            "session/status"
7276        );
7277        assert_eq!(
7278            serde_json::to_value(SessionStatusRequest::new("sess_abc123")).unwrap(),
7279            json!({"sessionId": "sess_abc123"})
7280        );
7281        assert_eq!(
7282            serde_json::to_value(SessionStatusResponse::new(SessionStatus::Saved)).unwrap(),
7283            json!({"status": "saved"})
7284        );
7285        assert_eq!(
7286            serde_json::to_value(
7287                SessionCapabilities::new().status(SessionStatusCapabilities::new())
7288            )
7289            .unwrap(),
7290            json!({"status": {}})
7291        );
7292    }
7293
7294    #[cfg(feature = "unstable_session_status")]
7295    #[test]
7296    fn test_session_status_is_strict_and_open() {
7297        let custom =
7298            serde_json::from_value::<SessionStatusResponse>(json!({"status": "_suspended"}))
7299                .unwrap();
7300        assert_eq!(
7301            custom.status,
7302            SessionStatus::Other("_suspended".to_string())
7303        );
7304        assert_eq!(
7305            serde_json::to_value(&custom).unwrap(),
7306            json!({"status": "_suspended"})
7307        );
7308        for result in [json!({}), json!({"status": null}), json!({"status": 1})] {
7309            assert!(serde_json::from_value::<SessionStatusResponse>(result).is_err());
7310        }
7311        for params in [json!({}), json!({"sessionId": null})] {
7312            assert!(serde_json::from_value::<SessionStatusRequest>(params).is_err());
7313        }
7314    }
7315
7316    #[cfg(feature = "unstable_session_archive")]
7317    #[test]
7318    fn test_session_archive_serialization() {
7319        assert_eq!(AGENT_METHOD_NAMES.session_archive, "session/archive");
7320        assert_eq!(AGENT_METHOD_NAMES.session_unarchive, "session/unarchive");
7321        assert_eq!(
7322            ClientRequest::ArchiveSessionRequest(ArchiveSessionRequest::new("sess_abc123"))
7323                .method(),
7324            "session/archive"
7325        );
7326        assert_eq!(
7327            ClientRequest::UnarchiveSessionRequest(UnarchiveSessionRequest::new("sess_abc123"))
7328                .method(),
7329            "session/unarchive"
7330        );
7331        assert_eq!(
7332            serde_json::to_value(ArchiveSessionRequest::new("sess_abc123")).unwrap(),
7333            json!({"sessionId": "sess_abc123"})
7334        );
7335        assert_eq!(
7336            serde_json::to_value(UnarchiveSessionResponse::new()).unwrap(),
7337            json!({})
7338        );
7339        assert_eq!(
7340            serde_json::to_value(
7341                SessionCapabilities::new().archive(SessionArchiveCapabilities::new())
7342            )
7343            .unwrap(),
7344            json!({"archive": {}})
7345        );
7346        assert_eq!(
7347            serde_json::to_value(
7348                ListSessionsRequest::new()
7349                    .cwd("/home/user/project")
7350                    .archived(SessionArchiveFilter::Only)
7351            )
7352            .unwrap(),
7353            json!({"cwd": "/home/user/project", "archived": "only"})
7354        );
7355        assert_eq!(
7356            serde_json::to_value(
7357                SessionInfo::new("sess_abc123", "/home/user/project").archived(true)
7358            )
7359            .unwrap(),
7360            json!({"sessionId": "sess_abc123", "cwd": "/home/user/project", "archived": true})
7361        );
7362    }
7363
7364    #[cfg(feature = "unstable_session_archive")]
7365    #[test]
7366    fn test_session_archive_filter_is_strict_and_open() {
7367        for (value, expected) in [
7368            (json!(null), None),
7369            (json!("include"), Some(SessionArchiveFilter::Include)),
7370            (
7371                json!("_recent"),
7372                Some(SessionArchiveFilter::Other("_recent".to_string())),
7373            ),
7374        ] {
7375            let request =
7376                serde_json::from_value::<ListSessionsRequest>(json!({"archived": value})).unwrap();
7377            assert_eq!(request.archived, expected);
7378        }
7379        for value in [json!(true), json!(1), json!({})] {
7380            assert!(
7381                serde_json::from_value::<ListSessionsRequest>(json!({"archived": value})).is_err()
7382            );
7383        }
7384        let info = serde_json::from_value::<SessionInfo>(
7385            json!({"sessionId": "sess_abc123", "cwd": "/home/user/project", "archived": "yes"}),
7386        )
7387        .unwrap();
7388        assert_eq!(info.archived, None);
7389    }
7390
7391    #[test]
7392    fn test_session_additional_directories_serialization() {
7393        assert_eq!(
7394            serde_json::to_value(NewSessionRequest::new("/home/user/project")).unwrap(),
7395            json!({
7396                "cwd": "/home/user/project",
7397                "mcpServers": []
7398            })
7399        );
7400        assert_eq!(
7401            serde_json::to_value(
7402                NewSessionRequest::new("/home/user/project").additional_directories(vec![
7403                    PathBuf::from("/home/user/shared-lib"),
7404                    PathBuf::from("/home/user/product-docs"),
7405                ])
7406            )
7407            .unwrap(),
7408            json!({
7409                "cwd": "/home/user/project",
7410                "additionalDirectories": [
7411                    "/home/user/shared-lib",
7412                    "/home/user/product-docs"
7413                ],
7414                "mcpServers": []
7415            })
7416        );
7417        assert_eq!(
7418            serde_json::to_value(SessionInfo::new("sess_abc123", "/home/user/project")).unwrap(),
7419            json!({
7420                "sessionId": "sess_abc123",
7421                "cwd": "/home/user/project"
7422            })
7423        );
7424        assert_eq!(
7425            serde_json::to_value(
7426                SessionInfo::new("sess_abc123", "/home/user/project").additional_directories(vec![
7427                    PathBuf::from("/home/user/shared-lib"),
7428                    PathBuf::from("/home/user/product-docs"),
7429                ])
7430            )
7431            .unwrap(),
7432            json!({
7433                "sessionId": "sess_abc123",
7434                "cwd": "/home/user/project",
7435                "additionalDirectories": [
7436                    "/home/user/shared-lib",
7437                    "/home/user/product-docs"
7438                ]
7439            })
7440        );
7441        assert_eq!(
7442            serde_json::from_value::<SessionInfo>(json!({
7443                "sessionId": "sess_abc123",
7444                "cwd": "/home/user/project"
7445            }))
7446            .unwrap()
7447            .additional_directories,
7448            Vec::<PathBuf>::new()
7449        );
7450    }
7451    #[test]
7452    fn test_session_additional_directories_capabilities_serialization() {
7453        assert_eq!(
7454            serde_json::to_value(
7455                SessionCapabilities::new()
7456                    .additional_directories(SessionAdditionalDirectoriesCapabilities::new())
7457            )
7458            .unwrap(),
7459            json!({
7460                "additionalDirectories": {}
7461            })
7462        );
7463    }
7464
7465    #[test]
7466    fn test_session_system_prompt_capabilities_serialization() {
7467        assert_eq!(
7468            serde_json::to_value(
7469                SessionCapabilities::new().system_prompt(SessionSystemPromptCapabilities::new())
7470            )
7471            .unwrap(),
7472            json!({ "systemPrompt": {} })
7473        );
7474        assert_eq!(
7475            serde_json::to_value(
7476                SessionCapabilities::new().system_prompt(
7477                    SessionSystemPromptCapabilities::new().mode(
7478                        SessionSystemPromptModeCapabilities::new()
7479                            .override_(SessionSystemPromptOverrideCapabilities::new())
7480                    )
7481                )
7482            )
7483            .unwrap(),
7484            json!({ "systemPrompt": { "mode": { "override": {} } } })
7485        );
7486        assert_eq!(
7487            serde_json::from_value::<SessionCapabilities>(
7488                json!({ "systemPrompt": { "mode": { "override": {} } } })
7489            )
7490            .unwrap()
7491            .system_prompt
7492            .and_then(|capabilities| capabilities.mode)
7493            .and_then(|mode| mode.override_),
7494            Some(SessionSystemPromptOverrideCapabilities::new())
7495        );
7496
7497        // Capabilities fall back to "not advertised" when malformed.
7498        assert_eq!(
7499            serde_json::from_value::<SessionCapabilities>(json!({ "systemPrompt": "yes" }))
7500                .unwrap()
7501                .system_prompt,
7502            None
7503        );
7504        assert_eq!(
7505            serde_json::from_value::<SessionCapabilities>(
7506                json!({ "systemPrompt": { "mode": { "override": true } } })
7507            )
7508            .unwrap()
7509            .system_prompt,
7510            Some(
7511                SessionSystemPromptCapabilities::new()
7512                    .mode(SessionSystemPromptModeCapabilities::new())
7513            )
7514        );
7515        assert_eq!(
7516            serde_json::from_value::<SessionCapabilities>(
7517                json!({ "systemPrompt": { "mode": "override" } })
7518            )
7519            .unwrap()
7520            .system_prompt,
7521            Some(SessionSystemPromptCapabilities::new())
7522        );
7523    }
7524
7525    #[test]
7526    fn test_system_prompt_lifecycle_request_serialization() {
7527        let system_prompt = SystemPrompt::new(vec![ContentBlock::from(
7528            "You are a code review specialist.",
7529        )]);
7530        let system_prompt_json = json!({
7531            "mode": "append",
7532            "content": [{ "type": "text", "text": "You are a code review specialist." }]
7533        });
7534
7535        let request =
7536            NewSessionRequest::new("/home/user/project").system_prompt(system_prompt.clone());
7537        let request_json = json!({
7538            "cwd": "/home/user/project",
7539            "mcpServers": [],
7540            "systemPrompt": system_prompt_json
7541        });
7542        assert_eq!(serde_json::to_value(&request).unwrap(), request_json);
7543        assert_eq!(
7544            serde_json::from_value::<NewSessionRequest>(request_json).unwrap(),
7545            request
7546        );
7547
7548        assert_eq!(
7549            serde_json::to_value(
7550                LoadSessionRequest::new("sess_abc123", "/home/user/project")
7551                    .system_prompt(system_prompt.clone())
7552            )
7553            .unwrap()["systemPrompt"],
7554            system_prompt_json
7555        );
7556        assert_eq!(
7557            serde_json::to_value(
7558                ResumeSessionRequest::new("sess_abc123", "/home/user/project")
7559                    .system_prompt(system_prompt.clone())
7560            )
7561            .unwrap()["systemPrompt"],
7562            system_prompt_json
7563        );
7564        #[cfg(feature = "unstable_session_fork")]
7565        assert_eq!(
7566            serde_json::to_value(
7567                ForkSessionRequest::new("sess_abc123", "/home/user/project")
7568                    .system_prompt(system_prompt.clone())
7569            )
7570            .unwrap()["systemPrompt"],
7571            system_prompt_json
7572        );
7573
7574        let override_prompt =
7575            SystemPrompt::new(vec![ContentBlock::from("...")]).mode(SystemPromptMode::Override);
7576        let override_json = json!({
7577            "mode": "override",
7578            "content": [{ "type": "text", "text": "..." }]
7579        });
7580        assert_eq!(
7581            serde_json::to_value(&override_prompt).unwrap(),
7582            override_json
7583        );
7584        assert_eq!(
7585            serde_json::from_value::<SystemPrompt>(override_json).unwrap(),
7586            override_prompt
7587        );
7588    }
7589
7590    /// `SystemPrompt::new` defaults to `append` in Rust, but `mode` is required on
7591    /// the wire, so it is always serialized.
7592    #[test]
7593    fn test_system_prompt_new_defaults_to_append() {
7594        let system_prompt = SystemPrompt::new(vec![ContentBlock::from("...")]);
7595        assert_eq!(system_prompt.mode, SystemPromptMode::Append);
7596        assert_eq!(
7597            serde_json::to_value(&system_prompt).unwrap(),
7598            json!({ "mode": "append", "content": [{ "type": "text", "text": "..." }] })
7599        );
7600    }
7601
7602    /// Unknown modes follow the enum variant extension rule: they parse as
7603    /// `SystemPromptMode::Other` so they are not dropped, and an agent that does
7604    /// not support them must reject the request.
7605    #[test]
7606    fn test_system_prompt_preserves_unknown_modes() {
7607        for mode in ["_vendor_mode", "prepend"] {
7608            let system_prompt_json =
7609                json!({ "mode": mode, "content": [{ "type": "text", "text": "..." }] });
7610            let system_prompt: SystemPrompt =
7611                serde_json::from_value(system_prompt_json.clone()).unwrap();
7612            assert_eq!(
7613                system_prompt.mode,
7614                SystemPromptMode::Other(mode.to_string())
7615            );
7616            assert_eq!(
7617                serde_json::to_value(&system_prompt).unwrap(),
7618                system_prompt_json
7619            );
7620        }
7621    }
7622
7623    /// The receiver acts on `systemPrompt`, so malformed values fail the request
7624    /// (`-32602`) instead of creating a session without the prompt, and `null`
7625    /// is equivalent to omitting the field.
7626    fn assert_system_prompt_is_strict<T>(base: &serde_json::Value)
7627    where
7628        T: serde::de::DeserializeOwned + PartialEq + std::fmt::Debug,
7629    {
7630        let name = std::any::type_name::<T>();
7631        let with = |system_prompt: serde_json::Value| {
7632            let mut request = base.clone();
7633            request["systemPrompt"] = system_prompt;
7634            serde_json::from_value::<T>(request)
7635        };
7636
7637        for system_prompt in [
7638            json!("You are a code review specialist."),
7639            json!({ "content": [{ "type": "text", "text": "..." }] }),
7640            json!({ "mode": null, "content": [{ "type": "text", "text": "..." }] }),
7641            json!({ "mode": 1, "content": [{ "type": "text", "text": "..." }] }),
7642            json!({ "mode": "append" }),
7643            json!({ "mode": "append", "content": "..." }),
7644            json!({ "mode": "append", "content": [{ "type": "text" }] }),
7645            json!({ "mode": "append", "content": [{ "type": "video", "uri": "..." }] }),
7646        ] {
7647            assert!(
7648                with(system_prompt.clone()).is_err(),
7649                "{name}.systemPrompt: {system_prompt}"
7650            );
7651        }
7652
7653        assert_eq!(
7654            with(serde_json::Value::Null).unwrap(),
7655            serde_json::from_value::<T>(base.clone()).unwrap(),
7656            "{name}.systemPrompt"
7657        );
7658    }
7659
7660    #[test]
7661    fn test_session_setup_requests_reject_malformed_system_prompts() {
7662        assert!(
7663            serde_json::to_value(NewSessionRequest::new("/repo"))
7664                .unwrap()
7665                .get("systemPrompt")
7666                .is_none()
7667        );
7668        assert_system_prompt_is_strict::<NewSessionRequest>(&json!({
7669            "cwd": "/repo",
7670            "mcpServers": []
7671        }));
7672        assert_system_prompt_is_strict::<LoadSessionRequest>(&json!({
7673            "sessionId": "sess-1",
7674            "cwd": "/repo",
7675            "mcpServers": []
7676        }));
7677        assert_system_prompt_is_strict::<ResumeSessionRequest>(&json!({
7678            "sessionId": "sess-1",
7679            "cwd": "/repo"
7680        }));
7681        #[cfg(feature = "unstable_session_fork")]
7682        assert_system_prompt_is_strict::<ForkSessionRequest>(&json!({
7683            "sessionId": "sess-1",
7684            "cwd": "/repo"
7685        }));
7686    }
7687
7688    #[test]
7689    fn test_auth_method_terminal_serialization() {
7690        let method = AuthMethod::Terminal(AuthMethodTerminal::new("tui-auth", "Terminal Auth"));
7691
7692        let json = serde_json::to_value(&method).unwrap();
7693        assert_eq!(
7694            json,
7695            json!({
7696                "id": "tui-auth",
7697                "name": "Terminal Auth",
7698                "type": "terminal"
7699            })
7700        );
7701        // args and env should be omitted when empty
7702        assert!(!json.as_object().unwrap().contains_key("args"));
7703        assert!(!json.as_object().unwrap().contains_key("env"));
7704
7705        let deserialized: AuthMethod = serde_json::from_value(json).unwrap();
7706        match deserialized {
7707            AuthMethod::Terminal(AuthMethodTerminal { args, env, .. }) => {
7708                assert_eq!(args, Vec::<String>::new());
7709                assert!(env.is_empty());
7710            }
7711            _ => panic!("Expected Terminal variant"),
7712        }
7713    }
7714
7715    #[test]
7716    fn test_auth_method_terminal_with_args_and_env_serialization() {
7717        use std::collections::HashMap;
7718
7719        let mut env = HashMap::new();
7720        env.insert("TERM".to_string(), "xterm-256color".to_string());
7721
7722        let method = AuthMethod::Terminal(
7723            AuthMethodTerminal::new("tui-auth", "Terminal Auth")
7724                .args(vec!["--interactive".to_string(), "--color".to_string()])
7725                .env(env),
7726        );
7727
7728        let json = serde_json::to_value(&method).unwrap();
7729        assert_eq!(
7730            json,
7731            json!({
7732                "id": "tui-auth",
7733                "name": "Terminal Auth",
7734                "type": "terminal",
7735                "args": ["--interactive", "--color"],
7736                "env": {
7737                    "TERM": "xterm-256color"
7738                }
7739            })
7740        );
7741
7742        let deserialized: AuthMethod = serde_json::from_value(json).unwrap();
7743        match deserialized {
7744            AuthMethod::Terminal(AuthMethodTerminal { args, env, .. }) => {
7745                assert_eq!(args, vec!["--interactive", "--color"]);
7746                assert_eq!(env.len(), 1);
7747                assert_eq!(env.get("TERM").unwrap(), "xterm-256color");
7748            }
7749            _ => panic!("Expected Terminal variant"),
7750        }
7751    }
7752
7753    #[test]
7754    fn test_session_config_option_value_id_serialize() {
7755        let val = SessionConfigOptionValue::value_id("model-1");
7756        let json = serde_json::to_value(&val).unwrap();
7757        // ValueId omits the "type" field (it's the default)
7758        assert_eq!(json, json!({ "value": "model-1" }));
7759        assert!(!json.as_object().unwrap().contains_key("type"));
7760    }
7761
7762    #[test]
7763    fn test_session_config_option_value_boolean_serialize() {
7764        let val = SessionConfigOptionValue::boolean(true);
7765        let json = serde_json::to_value(&val).unwrap();
7766        assert_eq!(json, json!({ "type": "boolean", "value": true }));
7767    }
7768
7769    #[test]
7770    fn test_session_config_option_value_deserialize_no_type() {
7771        // Missing "type" should default to ValueId
7772        let json = json!({ "value": "model-1" });
7773        let val: SessionConfigOptionValue = serde_json::from_value(json).unwrap();
7774        assert_eq!(val, SessionConfigOptionValue::value_id("model-1"));
7775        assert_eq!(val.as_value_id().unwrap().to_string(), "model-1");
7776    }
7777
7778    #[test]
7779    fn test_session_config_option_value_deserialize_boolean() {
7780        let json = json!({ "type": "boolean", "value": true });
7781        let val: SessionConfigOptionValue = serde_json::from_value(json).unwrap();
7782        assert_eq!(val, SessionConfigOptionValue::boolean(true));
7783        assert_eq!(val.as_bool(), Some(true));
7784    }
7785
7786    #[test]
7787    fn test_session_config_option_value_deserialize_boolean_false() {
7788        let json = json!({ "type": "boolean", "value": false });
7789        let val: SessionConfigOptionValue = serde_json::from_value(json).unwrap();
7790        assert_eq!(val, SessionConfigOptionValue::boolean(false));
7791        assert_eq!(val.as_bool(), Some(false));
7792    }
7793
7794    #[test]
7795    fn test_session_config_option_value_deserialize_unknown_type_with_string_value() {
7796        // Unknown type with a string value gracefully falls back to ValueId
7797        let json = json!({ "type": "text", "value": "freeform input" });
7798        let val: SessionConfigOptionValue = serde_json::from_value(json).unwrap();
7799        assert_eq!(val.as_value_id().unwrap().to_string(), "freeform input");
7800    }
7801
7802    #[test]
7803    fn test_session_config_option_value_roundtrip_value_id() {
7804        let original = SessionConfigOptionValue::value_id("option-a");
7805        let json = serde_json::to_value(&original).unwrap();
7806        let roundtripped: SessionConfigOptionValue = serde_json::from_value(json).unwrap();
7807        assert_eq!(original, roundtripped);
7808    }
7809
7810    #[test]
7811    fn test_session_config_option_value_roundtrip_boolean() {
7812        let original = SessionConfigOptionValue::boolean(false);
7813        let json = serde_json::to_value(&original).unwrap();
7814        let roundtripped: SessionConfigOptionValue = serde_json::from_value(json).unwrap();
7815        assert_eq!(original, roundtripped);
7816    }
7817
7818    #[test]
7819    fn test_session_config_option_value_type_mismatch_boolean_with_string() {
7820        // type says "boolean" but value is a string — falls to untagged ValueId
7821        let json = json!({ "type": "boolean", "value": "not a bool" });
7822        let result = serde_json::from_value::<SessionConfigOptionValue>(json);
7823        // serde tries Boolean first (fails), then falls to untagged ValueId (succeeds)
7824        assert!(result.is_ok());
7825        assert_eq!(
7826            result.unwrap().as_value_id().unwrap().to_string(),
7827            "not a bool"
7828        );
7829    }
7830
7831    #[test]
7832    fn test_session_config_option_value_from_impls() {
7833        let from_str: SessionConfigOptionValue = "model-1".into();
7834        assert_eq!(from_str.as_value_id().unwrap().to_string(), "model-1");
7835
7836        let from_id: SessionConfigOptionValue = SessionConfigValueId::new("model-2").into();
7837        assert_eq!(from_id.as_value_id().unwrap().to_string(), "model-2");
7838
7839        let from_bool: SessionConfigOptionValue = true.into();
7840        assert_eq!(from_bool.as_bool(), Some(true));
7841    }
7842
7843    #[test]
7844    fn test_set_session_config_option_request_value_id() {
7845        let req = SetSessionConfigOptionRequest::new("sess_1", "model", "model-1");
7846        let json = serde_json::to_value(&req).unwrap();
7847        assert_eq!(
7848            json,
7849            json!({
7850                "sessionId": "sess_1",
7851                "configId": "model",
7852                "value": "model-1"
7853            })
7854        );
7855        // No "type" field for value_id
7856        assert!(!json.as_object().unwrap().contains_key("type"));
7857    }
7858
7859    #[test]
7860    fn test_set_session_config_option_request_boolean() {
7861        let req = SetSessionConfigOptionRequest::new("sess_1", "brave_mode", true);
7862        let json = serde_json::to_value(&req).unwrap();
7863        assert_eq!(
7864            json,
7865            json!({
7866                "sessionId": "sess_1",
7867                "configId": "brave_mode",
7868                "type": "boolean",
7869                "value": true
7870            })
7871        );
7872    }
7873
7874    #[test]
7875    fn test_set_session_config_option_request_deserialize_no_type() {
7876        // Backwards-compatible: no "type" field → value_id
7877        let json = json!({
7878            "sessionId": "sess_1",
7879            "configId": "model",
7880            "value": "model-1"
7881        });
7882        let req: SetSessionConfigOptionRequest = serde_json::from_value(json).unwrap();
7883        assert_eq!(req.session_id.to_string(), "sess_1");
7884        assert_eq!(req.config_id.to_string(), "model");
7885        assert_eq!(req.value.as_value_id().unwrap().to_string(), "model-1");
7886    }
7887
7888    #[test]
7889    fn test_set_session_config_option_request_deserialize_boolean() {
7890        let json = json!({
7891            "sessionId": "sess_1",
7892            "configId": "brave_mode",
7893            "type": "boolean",
7894            "value": true
7895        });
7896        let req: SetSessionConfigOptionRequest = serde_json::from_value(json).unwrap();
7897        assert_eq!(req.value.as_bool(), Some(true));
7898    }
7899
7900    #[test]
7901    fn test_set_session_config_option_request_roundtrip_value_id() {
7902        let original = SetSessionConfigOptionRequest::new("s", "c", "v");
7903        let json = serde_json::to_value(&original).unwrap();
7904        let roundtripped: SetSessionConfigOptionRequest = serde_json::from_value(json).unwrap();
7905        assert_eq!(original, roundtripped);
7906    }
7907
7908    #[test]
7909    fn test_set_session_config_option_request_roundtrip_boolean() {
7910        let original = SetSessionConfigOptionRequest::new("s", "c", false);
7911        let json = serde_json::to_value(&original).unwrap();
7912        let roundtripped: SetSessionConfigOptionRequest = serde_json::from_value(json).unwrap();
7913        assert_eq!(original, roundtripped);
7914    }
7915
7916    #[test]
7917    fn test_session_config_boolean_serialization() {
7918        let cfg = SessionConfigBoolean::new(true);
7919        let json = serde_json::to_value(&cfg).unwrap();
7920        assert_eq!(json, json!({ "currentValue": true }));
7921
7922        let deserialized: SessionConfigBoolean = serde_json::from_value(json).unwrap();
7923        assert!(deserialized.current_value);
7924    }
7925
7926    #[test]
7927    fn test_session_config_option_boolean_variant() {
7928        let opt = SessionConfigOption::boolean("brave_mode", "Brave Mode", false)
7929            .description("Skip confirmation prompts")
7930            .meta(test_meta());
7931        assert_eq!(serialized_meta_key_count(&opt), 1);
7932
7933        let json = serde_json::to_value(&opt).unwrap();
7934        assert_eq!(
7935            json,
7936            json!({
7937                "id": "brave_mode",
7938                "name": "Brave Mode",
7939                "description": "Skip confirmation prompts",
7940                "type": "boolean",
7941                "currentValue": false,
7942                "_meta": {
7943                    "source": "test"
7944                }
7945            })
7946        );
7947
7948        let deserialized: SessionConfigOption = serde_json::from_value(json).unwrap();
7949        assert_eq!(deserialized.id.to_string(), "brave_mode");
7950        assert_eq!(deserialized.name, "Brave Mode");
7951        match deserialized.kind {
7952            SessionConfigKind::Boolean(ref b) => assert!(!b.current_value),
7953            _ => panic!("Expected Boolean kind"),
7954        }
7955    }
7956
7957    #[test]
7958    fn test_session_config_option_select_still_works() {
7959        // Make sure existing select options are unaffected
7960        let opt = SessionConfigOption::select(
7961            "model",
7962            "Model",
7963            "model-1",
7964            vec![
7965                SessionConfigSelectOption::new("model-1", "Model 1"),
7966                SessionConfigSelectOption::new("model-2", "Model 2"),
7967            ],
7968        )
7969        .meta(test_meta());
7970        assert_eq!(serialized_meta_key_count(&opt), 1);
7971
7972        let json = serde_json::to_value(&opt).unwrap();
7973        assert_eq!(json["type"], "select");
7974        assert_eq!(json["currentValue"], "model-1");
7975        assert_eq!(json["options"].as_array().unwrap().len(), 2);
7976        assert_eq!(json["_meta"]["source"], "test");
7977
7978        let deserialized: SessionConfigOption = serde_json::from_value(json).unwrap();
7979        match deserialized.kind {
7980            SessionConfigKind::Select(ref s) => {
7981                assert_eq!(s.current_value.to_string(), "model-1");
7982            }
7983            _ => panic!("Expected Select kind"),
7984        }
7985    }
7986
7987    #[cfg(feature = "unstable_llm_providers")]
7988    #[test]
7989    fn test_llm_protocol_known_variants() {
7990        assert_eq!(
7991            serde_json::to_value(&LlmProtocol::Anthropic).unwrap(),
7992            json!("anthropic")
7993        );
7994        assert_eq!(
7995            serde_json::to_value(&LlmProtocol::OpenAi).unwrap(),
7996            json!("openai")
7997        );
7998        assert_eq!(
7999            serde_json::to_value(&LlmProtocol::Azure).unwrap(),
8000            json!("azure")
8001        );
8002        assert_eq!(
8003            serde_json::to_value(&LlmProtocol::Vertex).unwrap(),
8004            json!("vertex")
8005        );
8006        assert_eq!(
8007            serde_json::to_value(&LlmProtocol::Bedrock).unwrap(),
8008            json!("bedrock")
8009        );
8010
8011        assert_eq!(
8012            serde_json::from_str::<LlmProtocol>("\"anthropic\"").unwrap(),
8013            LlmProtocol::Anthropic
8014        );
8015        assert_eq!(
8016            serde_json::from_str::<LlmProtocol>("\"openai\"").unwrap(),
8017            LlmProtocol::OpenAi
8018        );
8019        assert_eq!(
8020            serde_json::from_str::<LlmProtocol>("\"azure\"").unwrap(),
8021            LlmProtocol::Azure
8022        );
8023        assert_eq!(
8024            serde_json::from_str::<LlmProtocol>("\"vertex\"").unwrap(),
8025            LlmProtocol::Vertex
8026        );
8027        assert_eq!(
8028            serde_json::from_str::<LlmProtocol>("\"bedrock\"").unwrap(),
8029            LlmProtocol::Bedrock
8030        );
8031    }
8032
8033    #[cfg(feature = "unstable_llm_providers")]
8034    #[test]
8035    fn test_llm_protocol_unknown_variant() {
8036        let unknown: LlmProtocol = serde_json::from_str("\"cohere\"").unwrap();
8037        assert_eq!(unknown, LlmProtocol::Other("cohere".to_string()));
8038
8039        let json = serde_json::to_value(&unknown).unwrap();
8040        assert_eq!(json, json!("cohere"));
8041    }
8042
8043    #[cfg(feature = "unstable_llm_providers")]
8044    #[test]
8045    fn test_provider_current_config_serialization() {
8046        let config =
8047            ProviderCurrentConfig::new(LlmProtocol::Anthropic, "https://api.anthropic.com");
8048
8049        let json = serde_json::to_value(&config).unwrap();
8050        assert_eq!(
8051            json,
8052            json!({
8053                "apiType": "anthropic",
8054                "baseUrl": "https://api.anthropic.com"
8055            })
8056        );
8057
8058        let deserialized: ProviderCurrentConfig = serde_json::from_value(json).unwrap();
8059        assert_eq!(deserialized.api_type, LlmProtocol::Anthropic);
8060        assert_eq!(deserialized.base_url, "https://api.anthropic.com");
8061    }
8062
8063    #[cfg(feature = "unstable_llm_providers")]
8064    #[test]
8065    fn test_provider_info_with_current_config() {
8066        let info = ProviderInfo::new(
8067            "main",
8068            vec![LlmProtocol::Anthropic, LlmProtocol::OpenAi],
8069            true,
8070            Some(ProviderCurrentConfig::new(
8071                LlmProtocol::Anthropic,
8072                "https://api.anthropic.com",
8073            )),
8074        );
8075
8076        let json = serde_json::to_value(&info).unwrap();
8077        assert_eq!(
8078            json,
8079            json!({
8080                "providerId": "main",
8081                "supported": ["anthropic", "openai"],
8082                "required": true,
8083                "current": {
8084                    "apiType": "anthropic",
8085                    "baseUrl": "https://api.anthropic.com"
8086                }
8087            })
8088        );
8089
8090        let deserialized: ProviderInfo = serde_json::from_value(json).unwrap();
8091        assert_eq!(deserialized.provider_id.to_string(), "main");
8092        assert_eq!(deserialized.supported.len(), 2);
8093        assert!(deserialized.required);
8094        assert!(deserialized.current.is_some());
8095        assert_eq!(
8096            deserialized.current.as_ref().unwrap().api_type,
8097            LlmProtocol::Anthropic
8098        );
8099    }
8100
8101    #[cfg(feature = "unstable_llm_providers")]
8102    #[test]
8103    fn test_provider_info_disabled() {
8104        let info = ProviderInfo::new(
8105            "secondary",
8106            vec![LlmProtocol::OpenAi],
8107            false,
8108            None::<ProviderCurrentConfig>,
8109        );
8110
8111        let json = serde_json::to_value(&info).unwrap();
8112        assert_eq!(
8113            json,
8114            json!({
8115                "providerId": "secondary",
8116                "supported": ["openai"],
8117                "required": false
8118            })
8119        );
8120
8121        let deserialized: ProviderInfo = serde_json::from_value(json).unwrap();
8122        assert_eq!(deserialized.provider_id.to_string(), "secondary");
8123        assert!(!deserialized.required);
8124        assert!(deserialized.current.is_none());
8125    }
8126
8127    #[cfg(feature = "unstable_llm_providers")]
8128    #[test]
8129    fn test_provider_info_missing_current_defaults_to_none() {
8130        // current is optional; omitting it should decode as None
8131        let json = json!({
8132            "providerId": "main",
8133            "supported": ["anthropic"],
8134            "required": true
8135        });
8136        let deserialized: ProviderInfo = serde_json::from_value(json).unwrap();
8137        assert!(deserialized.current.is_none());
8138    }
8139
8140    #[cfg(feature = "unstable_llm_providers")]
8141    #[test]
8142    fn test_provider_info_explicit_null_current_decodes_to_none() {
8143        // current: null and an omitted current are equivalent on the wire;
8144        // both must deserialize into None so the disabled state is preserved
8145        // regardless of which form the peer chose to send.
8146        let json = json!({
8147            "providerId": "main",
8148            "supported": ["anthropic"],
8149            "required": true,
8150            "current": null
8151        });
8152        let deserialized: ProviderInfo = serde_json::from_value(json).unwrap();
8153        assert!(deserialized.current.is_none());
8154    }
8155
8156    #[cfg(feature = "unstable_llm_providers")]
8157    #[test]
8158    fn test_list_providers_response_serialization() {
8159        let response = ListProvidersResponse::new(vec![ProviderInfo::new(
8160            "main",
8161            vec![LlmProtocol::Anthropic],
8162            true,
8163            Some(ProviderCurrentConfig::new(
8164                LlmProtocol::Anthropic,
8165                "https://api.anthropic.com",
8166            )),
8167        )]);
8168
8169        let json = serde_json::to_value(&response).unwrap();
8170        assert_eq!(json["providers"].as_array().unwrap().len(), 1);
8171        assert_eq!(json["providers"][0]["providerId"], "main");
8172
8173        let deserialized: ListProvidersResponse = serde_json::from_value(json).unwrap();
8174        assert_eq!(deserialized.providers.len(), 1);
8175    }
8176
8177    #[cfg(feature = "unstable_llm_providers")]
8178    #[test]
8179    fn test_set_provider_request_serialization() {
8180        use std::collections::HashMap;
8181
8182        let mut headers = HashMap::new();
8183        headers.insert("Authorization".to_string(), "Bearer sk-test".to_string());
8184
8185        let request =
8186            SetProviderRequest::new("main", LlmProtocol::OpenAi, "https://api.openai.com/v1")
8187                .headers(headers);
8188
8189        let json = serde_json::to_value(&request).unwrap();
8190        assert_eq!(
8191            json,
8192            json!({
8193                "providerId": "main",
8194                "apiType": "openai",
8195                "baseUrl": "https://api.openai.com/v1",
8196                "headers": {
8197                    "Authorization": "Bearer sk-test"
8198                }
8199            })
8200        );
8201
8202        let deserialized: SetProviderRequest = serde_json::from_value(json).unwrap();
8203        assert_eq!(deserialized.provider_id.to_string(), "main");
8204        assert_eq!(deserialized.api_type, LlmProtocol::OpenAi);
8205        assert_eq!(deserialized.base_url, "https://api.openai.com/v1");
8206        assert_eq!(deserialized.headers.len(), 1);
8207        assert_eq!(
8208            deserialized.headers.get("Authorization").unwrap(),
8209            "Bearer sk-test"
8210        );
8211    }
8212
8213    #[cfg(feature = "unstable_llm_providers")]
8214    #[test]
8215    fn test_set_provider_request_omits_empty_headers() {
8216        let request =
8217            SetProviderRequest::new("main", LlmProtocol::Anthropic, "https://api.anthropic.com");
8218
8219        let json = serde_json::to_value(&request).unwrap();
8220        // headers should be omitted when empty
8221        assert!(!json.as_object().unwrap().contains_key("headers"));
8222    }
8223
8224    #[cfg(feature = "unstable_llm_providers")]
8225    #[test]
8226    fn test_disable_provider_request_serialization() {
8227        let request = DisableProviderRequest::new("secondary");
8228
8229        let json = serde_json::to_value(&request).unwrap();
8230        assert_eq!(json, json!({ "providerId": "secondary" }));
8231
8232        let deserialized: DisableProviderRequest = serde_json::from_value(json).unwrap();
8233        assert_eq!(deserialized.provider_id.to_string(), "secondary");
8234    }
8235
8236    #[cfg(feature = "unstable_llm_providers")]
8237    #[test]
8238    fn test_providers_capabilities_serialization() {
8239        let caps = ProvidersCapabilities::new();
8240
8241        let json = serde_json::to_value(&caps).unwrap();
8242        assert_eq!(json, json!({}));
8243
8244        let deserialized: ProvidersCapabilities = serde_json::from_value(json).unwrap();
8245        assert!(deserialized.meta.is_none());
8246    }
8247
8248    #[cfg(feature = "unstable_llm_providers")]
8249    #[test]
8250    fn test_agent_capabilities_with_providers() {
8251        let caps = AgentCapabilities::new().providers(ProvidersCapabilities::new());
8252
8253        let json = serde_json::to_value(&caps).unwrap();
8254        assert_eq!(json["providers"], json!({}));
8255
8256        let deserialized: AgentCapabilities = serde_json::from_value(json).unwrap();
8257        assert!(deserialized.providers.is_some());
8258    }
8259
8260    #[test]
8261    fn prompt_request_rejects_malformed_content_block() {
8262        use serde_json::json;
8263
8264        assert!(
8265            serde_json::from_value::<PromptRequest>(json!({
8266                "sessionId": "sess-1",
8267                "prompt": [{"type": "text"}]
8268            }))
8269            .is_err()
8270        );
8271    }
8272
8273    #[test]
8274    fn prompt_request_rejects_non_array_prompt() {
8275        use serde_json::json;
8276
8277        assert!(
8278            serde_json::from_value::<PromptRequest>(json!({
8279                "sessionId": "sess-1",
8280                "prompt": "hello"
8281            }))
8282            .is_err()
8283        );
8284    }
8285
8286    fn assert_session_setup_lists_are_strict<T>(base: &serde_json::Value)
8287    where
8288        T: serde::de::DeserializeOwned + PartialEq + std::fmt::Debug,
8289    {
8290        let name = std::any::type_name::<T>();
8291        let with = |field: &str, value: serde_json::Value| {
8292            let mut request = base.clone();
8293            request[field] = value;
8294            serde_json::from_value::<T>(request)
8295        };
8296
8297        for (field, value) in [
8298            // Dropping the malformed server would start the session without it.
8299            (
8300                "mcpServers",
8301                json!([
8302                    {"name": "github", "command": "/usr/bin/gh-mcp", "args": [], "env": [{"name": "GITHUB_TOKEN", "value": null}]},
8303                    {"name": "fs", "command": "/usr/bin/fs-mcp", "args": [], "env": []}
8304                ]),
8305            ),
8306            ("mcpServers", json!({"name": "fs"})),
8307            ("additionalDirectories", json!(["/repo/lib", 42])),
8308            ("additionalDirectories", json!("/repo/lib")),
8309        ] {
8310            assert!(
8311                with(field, value.clone()).is_err(),
8312                "{name}.{field}: {value}"
8313            );
8314        }
8315
8316        let empty = serde_json::from_value::<T>(base.clone()).unwrap();
8317        for field in ["mcpServers", "additionalDirectories"] {
8318            assert_eq!(
8319                with(field, serde_json::Value::Null).unwrap(),
8320                empty,
8321                "{name}.{field}"
8322            );
8323        }
8324    }
8325
8326    #[test]
8327    fn session_setup_requests_reject_malformed_mcp_servers_and_directories() {
8328        assert_session_setup_lists_are_strict::<NewSessionRequest>(&json!({
8329            "cwd": "/repo",
8330            "mcpServers": []
8331        }));
8332        assert_session_setup_lists_are_strict::<LoadSessionRequest>(&json!({
8333            "sessionId": "sess-1",
8334            "cwd": "/repo",
8335            "mcpServers": []
8336        }));
8337        assert_session_setup_lists_are_strict::<ResumeSessionRequest>(&json!({
8338            "sessionId": "sess-1",
8339            "cwd": "/repo"
8340        }));
8341        #[cfg(feature = "unstable_session_fork")]
8342        assert_session_setup_lists_are_strict::<ForkSessionRequest>(&json!({
8343            "sessionId": "sess-1",
8344            "cwd": "/repo"
8345        }));
8346    }
8347
8348    #[test]
8349    fn mcp_server_lists_treat_null_as_empty() {
8350        let servers: Vec<McpServer> = serde_json::from_value(json!([
8351            {"name": "fs", "command": "/usr/bin/fs-mcp", "args": null, "env": null},
8352            {"type": "http", "name": "api", "url": "https://example.com/mcp", "headers": null},
8353            {"type": "sse", "name": "events", "url": "https://example.com/sse", "headers": null}
8354        ]))
8355        .unwrap();
8356
8357        assert_eq!(
8358            servers,
8359            vec![
8360                McpServer::Stdio(McpServerStdio::new("fs", "/usr/bin/fs-mcp")),
8361                McpServer::Http(McpServerHttp::new("api", "https://example.com/mcp")),
8362                McpServer::Sse(McpServerSse::new("events", "https://example.com/sse")),
8363            ]
8364        );
8365    }
8366
8367    #[test]
8368    fn terminal_auth_methods_reject_malformed_launch_config() {
8369        // The client spawns a process from `args` and `env`, so a malformed
8370        // method is dropped from `authMethods` instead of launched with
8371        // altered arguments or reinterpreted as an `agent` method.
8372        let response: InitializeResponse = serde_json::from_value(json!({
8373            "protocolVersion": 1,
8374            "authMethods": [
8375                {"type": "terminal", "id": "bad-args", "name": "Log in", "args": ["auth", "--port", 8123]},
8376                {"type": "terminal", "id": "bad-env", "name": "Log in", "env": {"AUTH_MODE": "device", "DEBUG": 1}},
8377                {"type": "terminal", "id": "null-config", "name": "Log in", "args": null, "env": null},
8378                {"id": "agent", "name": "Agent login"}
8379            ]
8380        }))
8381        .unwrap();
8382
8383        assert_eq!(
8384            response.auth_methods,
8385            vec![
8386                AuthMethod::Terminal(AuthMethodTerminal::new("null-config", "Log in")),
8387                AuthMethod::Agent(AuthMethodAgent::new("agent", "Agent login")),
8388            ]
8389        );
8390        assert!(
8391            serde_json::from_value::<AuthMethod>(json!({
8392                "type": "terminal",
8393                "id": "bad-args",
8394                "name": "Log in",
8395                "args": ["auth", 8123]
8396            }))
8397            .is_err()
8398        );
8399    }
8400
8401    #[cfg(feature = "unstable_auth_status")]
8402    #[test]
8403    fn auth_status_response_round_trips() {
8404        let response = AuthStatusResponse::new(AuthState::Authenticated).accounts(vec![
8405            AuthAccount::new("Anthropic API key").active(true),
8406            AuthAccount::new("Claude Max").email("user@example.com".to_string()),
8407        ]);
8408        let json = serde_json::to_value(&response).unwrap();
8409        assert_eq!(
8410            json,
8411            json!({
8412                "state": "authenticated",
8413                "accounts": [
8414                    {
8415                        "label": "Anthropic API key",
8416                        "active": true
8417                    },
8418                    {
8419                        "label": "Claude Max",
8420                        "email": "user@example.com"
8421                    }
8422                ]
8423            })
8424        );
8425        assert_eq!(
8426            serde_json::from_value::<AuthStatusResponse>(json).unwrap(),
8427            response
8428        );
8429        assert_eq!(
8430            serde_json::to_value(AuthStatusResponse::new(AuthState::NotRequired)).unwrap(),
8431            json!({"state": "not_required"})
8432        );
8433    }
8434
8435    #[cfg(feature = "unstable_auth_status")]
8436    #[test]
8437    fn auth_status_state_is_strict_and_accounts_are_lenient() {
8438        assert!(serde_json::from_value::<AuthStatusResponse>(json!({})).is_err());
8439        assert!(serde_json::from_value::<AuthStatusResponse>(json!({"state": null})).is_err());
8440        assert!(serde_json::from_value::<AuthStatusResponse>(json!({"state": 1})).is_err());
8441
8442        let response: AuthStatusResponse = serde_json::from_value(json!({
8443            "state": "_vendor_state",
8444            "accounts": [
8445                {"active": true},
8446                {
8447                    "label": "Vertex AI",
8448                    "active": "yes",
8449                    "email": ["not", "a", "string"]
8450                }
8451            ]
8452        }))
8453        .unwrap();
8454        assert_eq!(
8455            response,
8456            AuthStatusResponse::new(AuthState::Other("_vendor_state".to_string()))
8457                .accounts(vec![AuthAccount::new("Vertex AI")])
8458        );
8459        assert_eq!(
8460            serde_json::from_value::<AuthStatusResponse>(
8461                json!({"state": "unknown", "accounts": null})
8462            )
8463            .unwrap(),
8464            AuthStatusResponse::new(AuthState::Unknown)
8465        );
8466    }
8467
8468    #[cfg(feature = "unstable_auth_status")]
8469    #[test]
8470    fn auth_status_update_notification_routes() {
8471        use crate::v1::{AgentNotification, CLIENT_METHOD_NAMES};
8472
8473        assert_eq!(AGENT_METHOD_NAMES.auth_status, "auth/status");
8474        assert_eq!(CLIENT_METHOD_NAMES.auth_status_update, "auth/status_update");
8475        let notification = AgentNotification::AuthStatusUpdateNotification(
8476            AuthStatusUpdateNotification::new(AuthState::Unauthenticated),
8477        );
8478        assert_eq!(notification.method(), "auth/status_update");
8479        assert_eq!(
8480            serde_json::to_value(&notification).unwrap(),
8481            json!({"state": "unauthenticated"})
8482        );
8483    }
8484}