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