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