Skip to main content

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