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