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