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