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