Skip to main content

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