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