Skip to main content

agent_client_protocol_schema/v1/
agent.rs

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