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