Skip to main content

agent_client_protocol_schema/v1/
agent.rs

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