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