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