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