Skip to main content

agent_client_protocol_schema/v1/
agent.rs

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