Skip to main content

agent_client_protocol_schema/v1/
agent.rs

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