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