agent_client_protocol_schema/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(feature = "unstable_auth_methods")]
9use std::collections::HashMap;
10
11use derive_more::{Display, From};
12use schemars::JsonSchema;
13use serde::{Deserialize, Serialize};
14
15use crate::{
16 ClientCapabilities, ContentBlock, ExtNotification, ExtRequest, ExtResponse, IntoOption, Meta,
17 ProtocolVersion, SessionId,
18};
19
20// Initialize
21
22/// Request parameters for the initialize method.
23///
24/// Sent by the client to establish connection and negotiate capabilities.
25///
26/// See protocol docs: [Initialization](https://agentclientprotocol.com/protocol/initialization)
27#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
28#[schemars(extend("x-side" = "agent", "x-method" = INITIALIZE_METHOD_NAME))]
29#[serde(rename_all = "camelCase")]
30#[non_exhaustive]
31pub struct InitializeRequest {
32 /// The latest protocol version supported by the client.
33 pub protocol_version: ProtocolVersion,
34 /// Capabilities supported by the client.
35 #[serde(default)]
36 pub client_capabilities: ClientCapabilities,
37 /// Information about the Client name and version sent to the Agent.
38 ///
39 /// Note: in future versions of the protocol, this will be required.
40 #[serde(skip_serializing_if = "Option::is_none")]
41 pub client_info: Option<Implementation>,
42 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
43 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
44 /// these keys.
45 ///
46 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
47 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
48 pub meta: Option<Meta>,
49}
50
51impl InitializeRequest {
52 #[must_use]
53 pub fn new(protocol_version: ProtocolVersion) -> Self {
54 Self {
55 protocol_version,
56 client_capabilities: ClientCapabilities::default(),
57 client_info: None,
58 meta: None,
59 }
60 }
61
62 /// Capabilities supported by the client.
63 #[must_use]
64 pub fn client_capabilities(mut self, client_capabilities: ClientCapabilities) -> Self {
65 self.client_capabilities = client_capabilities;
66 self
67 }
68
69 /// Information about the Client name and version sent to the Agent.
70 #[must_use]
71 pub fn client_info(mut self, client_info: impl IntoOption<Implementation>) -> Self {
72 self.client_info = client_info.into_option();
73 self
74 }
75
76 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
77 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
78 /// these keys.
79 ///
80 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
81 #[must_use]
82 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
83 self.meta = meta.into_option();
84 self
85 }
86}
87
88/// Response to the `initialize` method.
89///
90/// Contains the negotiated protocol version and agent capabilities.
91///
92/// See protocol docs: [Initialization](https://agentclientprotocol.com/protocol/initialization)
93#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
94#[schemars(extend("x-side" = "agent", "x-method" = INITIALIZE_METHOD_NAME))]
95#[serde(rename_all = "camelCase")]
96#[non_exhaustive]
97pub struct InitializeResponse {
98 /// The protocol version the client specified if supported by the agent,
99 /// or the latest protocol version supported by the agent.
100 ///
101 /// The client should disconnect, if it doesn't support this version.
102 pub protocol_version: ProtocolVersion,
103 /// Capabilities supported by the agent.
104 #[serde(default)]
105 pub agent_capabilities: AgentCapabilities,
106 /// Authentication methods supported by the agent.
107 #[serde(default)]
108 pub auth_methods: Vec<AuthMethod>,
109 /// Information about the Agent name and version sent to the Client.
110 ///
111 /// Note: in future versions of the protocol, this will be required.
112 #[serde(skip_serializing_if = "Option::is_none")]
113 pub agent_info: Option<Implementation>,
114 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
115 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
116 /// these keys.
117 ///
118 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
119 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
120 pub meta: Option<Meta>,
121}
122
123impl InitializeResponse {
124 #[must_use]
125 pub fn new(protocol_version: ProtocolVersion) -> Self {
126 Self {
127 protocol_version,
128 agent_capabilities: AgentCapabilities::default(),
129 auth_methods: vec![],
130 agent_info: None,
131 meta: None,
132 }
133 }
134
135 /// Capabilities supported by the agent.
136 #[must_use]
137 pub fn agent_capabilities(mut self, agent_capabilities: AgentCapabilities) -> Self {
138 self.agent_capabilities = agent_capabilities;
139 self
140 }
141
142 /// Authentication methods supported by the agent.
143 #[must_use]
144 pub fn auth_methods(mut self, auth_methods: Vec<AuthMethod>) -> Self {
145 self.auth_methods = auth_methods;
146 self
147 }
148
149 /// Information about the Agent name and version sent to the Client.
150 #[must_use]
151 pub fn agent_info(mut self, agent_info: impl IntoOption<Implementation>) -> Self {
152 self.agent_info = agent_info.into_option();
153 self
154 }
155
156 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
157 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
158 /// these keys.
159 ///
160 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
161 #[must_use]
162 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
163 self.meta = meta.into_option();
164 self
165 }
166}
167
168/// Metadata about the implementation of the client or agent.
169/// Describes the name and version of an MCP implementation, with an optional
170/// title for UI representation.
171#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
172#[serde(rename_all = "camelCase")]
173#[non_exhaustive]
174pub struct Implementation {
175 /// Intended for programmatic or logical use, but can be used as a display
176 /// name fallback if title isn’t present.
177 pub name: String,
178 /// Intended for UI and end-user contexts — optimized to be human-readable
179 /// and easily understood.
180 ///
181 /// If not provided, the name should be used for display.
182 pub title: Option<String>,
183 /// Version of the implementation. Can be displayed to the user or used
184 /// for debugging or metrics purposes. (e.g. "1.0.0").
185 pub version: String,
186 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
187 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
188 /// these keys.
189 ///
190 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
191 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
192 pub meta: Option<Meta>,
193}
194
195impl Implementation {
196 #[must_use]
197 pub fn new(name: impl Into<String>, version: impl Into<String>) -> Self {
198 Self {
199 name: name.into(),
200 title: None,
201 version: version.into(),
202 meta: None,
203 }
204 }
205
206 /// Intended for UI and end-user contexts — optimized to be human-readable
207 /// and easily understood.
208 ///
209 /// If not provided, the name should be used for display.
210 #[must_use]
211 pub fn title(mut self, title: impl IntoOption<String>) -> Self {
212 self.title = title.into_option();
213 self
214 }
215
216 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
217 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
218 /// these keys.
219 ///
220 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
221 #[must_use]
222 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
223 self.meta = meta.into_option();
224 self
225 }
226}
227
228// Authentication
229
230/// Request parameters for the authenticate method.
231///
232/// Specifies which authentication method to use.
233#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
234#[schemars(extend("x-side" = "agent", "x-method" = AUTHENTICATE_METHOD_NAME))]
235#[serde(rename_all = "camelCase")]
236#[non_exhaustive]
237pub struct AuthenticateRequest {
238 /// The ID of the authentication method to use.
239 /// Must be one of the methods advertised in the initialize response.
240 pub method_id: AuthMethodId,
241 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
242 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
243 /// these keys.
244 ///
245 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
246 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
247 pub meta: Option<Meta>,
248}
249
250impl AuthenticateRequest {
251 #[must_use]
252 pub fn new(method_id: impl Into<AuthMethodId>) -> Self {
253 Self {
254 method_id: method_id.into(),
255 meta: None,
256 }
257 }
258
259 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
260 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
261 /// these keys.
262 ///
263 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
264 #[must_use]
265 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
266 self.meta = meta.into_option();
267 self
268 }
269}
270
271/// Response to the `authenticate` method.
272#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
273#[schemars(extend("x-side" = "agent", "x-method" = AUTHENTICATE_METHOD_NAME))]
274#[serde(rename_all = "camelCase")]
275#[non_exhaustive]
276pub struct AuthenticateResponse {
277 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
278 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
279 /// these keys.
280 ///
281 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
282 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
283 pub meta: Option<Meta>,
284}
285
286impl AuthenticateResponse {
287 #[must_use]
288 pub fn new() -> Self {
289 Self::default()
290 }
291
292 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
293 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
294 /// these keys.
295 ///
296 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
297 #[must_use]
298 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
299 self.meta = meta.into_option();
300 self
301 }
302}
303
304// Logout
305
306/// **UNSTABLE**
307///
308/// This capability is not part of the spec yet, and may be removed or changed at any point.
309///
310/// Request parameters for the logout method.
311///
312/// Terminates the current authenticated session.
313#[cfg(feature = "unstable_logout")]
314#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
315#[schemars(extend("x-side" = "agent", "x-method" = LOGOUT_METHOD_NAME))]
316#[serde(rename_all = "camelCase")]
317#[non_exhaustive]
318pub struct LogoutRequest {
319 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
320 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
321 /// these keys.
322 ///
323 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
324 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
325 pub meta: Option<Meta>,
326}
327
328#[cfg(feature = "unstable_logout")]
329impl LogoutRequest {
330 #[must_use]
331 pub fn new() -> Self {
332 Self::default()
333 }
334
335 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
336 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
337 /// these keys.
338 ///
339 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
340 #[must_use]
341 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
342 self.meta = meta.into_option();
343 self
344 }
345}
346
347/// **UNSTABLE**
348///
349/// This capability is not part of the spec yet, and may be removed or changed at any point.
350///
351/// Response to the `logout` method.
352#[cfg(feature = "unstable_logout")]
353#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
354#[schemars(extend("x-side" = "agent", "x-method" = LOGOUT_METHOD_NAME))]
355#[serde(rename_all = "camelCase")]
356#[non_exhaustive]
357pub struct LogoutResponse {
358 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
359 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
360 /// these keys.
361 ///
362 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
363 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
364 pub meta: Option<Meta>,
365}
366
367#[cfg(feature = "unstable_logout")]
368impl LogoutResponse {
369 #[must_use]
370 pub fn new() -> Self {
371 Self::default()
372 }
373
374 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
375 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
376 /// these keys.
377 ///
378 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
379 #[must_use]
380 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
381 self.meta = meta.into_option();
382 self
383 }
384}
385
386/// **UNSTABLE**
387///
388/// This capability is not part of the spec yet, and may be removed or changed at any point.
389///
390/// Authentication-related capabilities supported by the agent.
391#[cfg(feature = "unstable_logout")]
392#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
393#[serde(rename_all = "camelCase")]
394#[non_exhaustive]
395pub struct AgentAuthCapabilities {
396 /// Whether the agent supports the logout method.
397 ///
398 /// By supplying `{}` it means that the agent supports the logout method.
399 #[serde(skip_serializing_if = "Option::is_none")]
400 pub logout: Option<LogoutCapabilities>,
401 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
402 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
403 /// these keys.
404 ///
405 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
406 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
407 pub meta: Option<Meta>,
408}
409
410#[cfg(feature = "unstable_logout")]
411impl AgentAuthCapabilities {
412 #[must_use]
413 pub fn new() -> Self {
414 Self::default()
415 }
416
417 /// Whether the agent supports the logout method.
418 #[must_use]
419 pub fn logout(mut self, logout: impl IntoOption<LogoutCapabilities>) -> Self {
420 self.logout = logout.into_option();
421 self
422 }
423
424 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
425 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
426 /// these keys.
427 ///
428 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
429 #[must_use]
430 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
431 self.meta = meta.into_option();
432 self
433 }
434}
435
436/// **UNSTABLE**
437///
438/// This capability is not part of the spec yet, and may be removed or changed at any point.
439///
440/// Logout capabilities supported by the agent.
441///
442/// By supplying `{}` it means that the agent supports the logout method.
443#[cfg(feature = "unstable_logout")]
444#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
445#[non_exhaustive]
446pub struct LogoutCapabilities {
447 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
448 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
449 /// these keys.
450 ///
451 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
452 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
453 pub meta: Option<Meta>,
454}
455
456#[cfg(feature = "unstable_logout")]
457impl LogoutCapabilities {
458 #[must_use]
459 pub fn new() -> Self {
460 Self::default()
461 }
462
463 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
464 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
465 /// these keys.
466 ///
467 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
468 #[must_use]
469 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
470 self.meta = meta.into_option();
471 self
472 }
473}
474
475#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq, Hash, Display, From)]
476#[serde(transparent)]
477#[from(Arc<str>, String, &'static str)]
478#[non_exhaustive]
479pub struct AuthMethodId(pub Arc<str>);
480
481impl AuthMethodId {
482 #[must_use]
483 pub fn new(id: impl Into<Arc<str>>) -> Self {
484 Self(id.into())
485 }
486}
487
488/// Describes an available authentication method.
489///
490/// The `type` field acts as the discriminator in the serialized JSON form.
491/// When no `type` is present, the method is treated as `agent`.
492#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
493#[serde(tag = "type", rename_all = "snake_case")]
494#[non_exhaustive]
495pub enum AuthMethod {
496 /// **UNSTABLE**
497 ///
498 /// This capability is not part of the spec yet, and may be removed or changed at any point.
499 ///
500 /// User provides a key that the client passes to the agent as an environment variable.
501 #[cfg(feature = "unstable_auth_methods")]
502 EnvVar(AuthMethodEnvVar),
503 /// **UNSTABLE**
504 ///
505 /// This capability is not part of the spec yet, and may be removed or changed at any point.
506 ///
507 /// Client runs an interactive terminal for the user to authenticate via a TUI.
508 #[cfg(feature = "unstable_auth_methods")]
509 Terminal(AuthMethodTerminal),
510 /// Agent handles authentication itself.
511 ///
512 /// This is the default when no `type` is specified.
513 #[serde(untagged)]
514 Agent(AuthMethodAgent),
515}
516
517impl AuthMethod {
518 /// The unique identifier for this authentication method.
519 #[must_use]
520 pub fn id(&self) -> &AuthMethodId {
521 match self {
522 Self::Agent(a) => &a.id,
523 #[cfg(feature = "unstable_auth_methods")]
524 Self::EnvVar(e) => &e.id,
525 #[cfg(feature = "unstable_auth_methods")]
526 Self::Terminal(t) => &t.id,
527 }
528 }
529
530 /// The human-readable name of this authentication method.
531 #[must_use]
532 pub fn name(&self) -> &str {
533 match self {
534 Self::Agent(a) => &a.name,
535 #[cfg(feature = "unstable_auth_methods")]
536 Self::EnvVar(e) => &e.name,
537 #[cfg(feature = "unstable_auth_methods")]
538 Self::Terminal(t) => &t.name,
539 }
540 }
541
542 /// Optional description providing more details about this authentication method.
543 #[must_use]
544 pub fn description(&self) -> Option<&str> {
545 match self {
546 Self::Agent(a) => a.description.as_deref(),
547 #[cfg(feature = "unstable_auth_methods")]
548 Self::EnvVar(e) => e.description.as_deref(),
549 #[cfg(feature = "unstable_auth_methods")]
550 Self::Terminal(t) => t.description.as_deref(),
551 }
552 }
553
554 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
555 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
556 /// these keys.
557 ///
558 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
559 #[must_use]
560 pub fn meta(&self) -> Option<&Meta> {
561 match self {
562 Self::Agent(a) => a.meta.as_ref(),
563 #[cfg(feature = "unstable_auth_methods")]
564 Self::EnvVar(e) => e.meta.as_ref(),
565 #[cfg(feature = "unstable_auth_methods")]
566 Self::Terminal(t) => t.meta.as_ref(),
567 }
568 }
569}
570
571/// Agent handles authentication itself.
572///
573/// This is the default authentication method type.
574#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
575#[serde(rename_all = "camelCase")]
576#[non_exhaustive]
577pub struct AuthMethodAgent {
578 /// Unique identifier for this authentication method.
579 pub id: AuthMethodId,
580 /// Human-readable name of the authentication method.
581 pub name: String,
582 /// Optional description providing more details about this authentication method.
583 #[serde(skip_serializing_if = "Option::is_none")]
584 pub description: Option<String>,
585 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
586 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
587 /// these keys.
588 ///
589 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
590 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
591 pub meta: Option<Meta>,
592}
593
594impl AuthMethodAgent {
595 #[must_use]
596 pub fn new(id: impl Into<AuthMethodId>, name: impl Into<String>) -> Self {
597 Self {
598 id: id.into(),
599 name: name.into(),
600 description: None,
601 meta: None,
602 }
603 }
604
605 /// Optional description providing more details about this authentication method.
606 #[must_use]
607 pub fn description(mut self, description: impl IntoOption<String>) -> Self {
608 self.description = description.into_option();
609 self
610 }
611
612 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
613 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
614 /// these keys.
615 ///
616 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
617 #[must_use]
618 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
619 self.meta = meta.into_option();
620 self
621 }
622}
623
624/// **UNSTABLE**
625///
626/// This capability is not part of the spec yet, and may be removed or changed at any point.
627///
628/// Environment variable authentication method.
629///
630/// The user provides credentials that the client passes to the agent as environment variables.
631#[cfg(feature = "unstable_auth_methods")]
632#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
633#[serde(rename_all = "camelCase")]
634#[non_exhaustive]
635pub struct AuthMethodEnvVar {
636 /// Unique identifier for this authentication method.
637 pub id: AuthMethodId,
638 /// Human-readable name of the authentication method.
639 pub name: String,
640 /// Optional description providing more details about this authentication method.
641 #[serde(skip_serializing_if = "Option::is_none")]
642 pub description: Option<String>,
643 /// The environment variables the client should set.
644 pub vars: Vec<AuthEnvVar>,
645 /// Optional link to a page where the user can obtain their credentials.
646 #[serde(skip_serializing_if = "Option::is_none")]
647 pub link: Option<String>,
648 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
649 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
650 /// these keys.
651 ///
652 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
653 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
654 pub meta: Option<Meta>,
655}
656
657#[cfg(feature = "unstable_auth_methods")]
658impl AuthMethodEnvVar {
659 #[must_use]
660 pub fn new(
661 id: impl Into<AuthMethodId>,
662 name: impl Into<String>,
663 vars: Vec<AuthEnvVar>,
664 ) -> Self {
665 Self {
666 id: id.into(),
667 name: name.into(),
668 description: None,
669 vars,
670 link: None,
671 meta: None,
672 }
673 }
674
675 /// Optional link to a page where the user can obtain their credentials.
676 #[must_use]
677 pub fn link(mut self, link: impl IntoOption<String>) -> Self {
678 self.link = link.into_option();
679 self
680 }
681
682 /// Optional description providing more details about this authentication method.
683 #[must_use]
684 pub fn description(mut self, description: impl IntoOption<String>) -> Self {
685 self.description = description.into_option();
686 self
687 }
688
689 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
690 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
691 /// these keys.
692 ///
693 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
694 #[must_use]
695 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
696 self.meta = meta.into_option();
697 self
698 }
699}
700
701/// **UNSTABLE**
702///
703/// This capability is not part of the spec yet, and may be removed or changed at any point.
704///
705/// Describes a single environment variable for an [`AuthMethodEnvVar`] authentication method.
706#[cfg(feature = "unstable_auth_methods")]
707#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
708#[serde(rename_all = "camelCase")]
709#[non_exhaustive]
710pub struct AuthEnvVar {
711 /// The environment variable name (e.g. `"OPENAI_API_KEY"`).
712 pub name: String,
713 /// Human-readable label for this variable, displayed in client UI.
714 #[serde(skip_serializing_if = "Option::is_none")]
715 pub label: Option<String>,
716 /// Whether this value is a secret (e.g. API key, token).
717 /// Clients should use a password-style input for secret vars.
718 ///
719 /// Defaults to `true`.
720 #[serde(default = "default_true", skip_serializing_if = "is_true")]
721 #[schemars(extend("default" = true))]
722 pub secret: bool,
723 /// Whether this variable is optional.
724 ///
725 /// Defaults to `false`.
726 #[serde(default, skip_serializing_if = "is_false")]
727 #[schemars(extend("default" = false))]
728 pub optional: bool,
729 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
730 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
731 /// these keys.
732 ///
733 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
734 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
735 pub meta: Option<Meta>,
736}
737
738#[cfg(feature = "unstable_auth_methods")]
739fn default_true() -> bool {
740 true
741}
742
743#[cfg(feature = "unstable_auth_methods")]
744#[expect(clippy::trivially_copy_pass_by_ref)]
745fn is_true(v: &bool) -> bool {
746 *v
747}
748
749#[cfg(feature = "unstable_auth_methods")]
750#[expect(clippy::trivially_copy_pass_by_ref)]
751fn is_false(v: &bool) -> bool {
752 !*v
753}
754
755#[cfg(feature = "unstable_auth_methods")]
756impl AuthEnvVar {
757 /// Creates a new auth env var.
758 #[must_use]
759 pub fn new(name: impl Into<String>) -> Self {
760 Self {
761 name: name.into(),
762 label: None,
763 secret: true,
764 optional: false,
765 meta: None,
766 }
767 }
768
769 /// Human-readable label for this variable, displayed in client UI.
770 #[must_use]
771 pub fn label(mut self, label: impl IntoOption<String>) -> Self {
772 self.label = label.into_option();
773 self
774 }
775
776 /// Whether this value is a secret (e.g. API key, token).
777 /// Clients should use a password-style input for secret vars.
778 #[must_use]
779 pub fn secret(mut self, secret: bool) -> Self {
780 self.secret = secret;
781 self
782 }
783
784 /// Whether this variable is optional.
785 #[must_use]
786 pub fn optional(mut self, optional: bool) -> Self {
787 self.optional = optional;
788 self
789 }
790
791 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
792 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
793 /// these keys.
794 ///
795 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
796 #[must_use]
797 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
798 self.meta = meta.into_option();
799 self
800 }
801}
802
803/// **UNSTABLE**
804///
805/// This capability is not part of the spec yet, and may be removed or changed at any point.
806///
807/// Terminal-based authentication method.
808///
809/// The client runs an interactive terminal for the user to authenticate via a TUI.
810#[cfg(feature = "unstable_auth_methods")]
811#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
812#[serde(rename_all = "camelCase")]
813#[non_exhaustive]
814pub struct AuthMethodTerminal {
815 /// Unique identifier for this authentication method.
816 pub id: AuthMethodId,
817 /// Human-readable name of the authentication method.
818 pub name: String,
819 /// Optional description providing more details about this authentication method.
820 #[serde(skip_serializing_if = "Option::is_none")]
821 pub description: Option<String>,
822 /// Additional arguments to pass when running the agent binary for terminal auth.
823 #[serde(default, skip_serializing_if = "Vec::is_empty")]
824 pub args: Vec<String>,
825 /// Additional environment variables to set when running the agent binary for terminal auth.
826 #[serde(default, skip_serializing_if = "HashMap::is_empty")]
827 pub env: HashMap<String, String>,
828 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
829 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
830 /// these keys.
831 ///
832 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
833 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
834 pub meta: Option<Meta>,
835}
836
837#[cfg(feature = "unstable_auth_methods")]
838impl AuthMethodTerminal {
839 #[must_use]
840 pub fn new(id: impl Into<AuthMethodId>, name: impl Into<String>) -> Self {
841 Self {
842 id: id.into(),
843 name: name.into(),
844 description: None,
845 args: Vec::new(),
846 env: HashMap::new(),
847 meta: None,
848 }
849 }
850
851 /// Additional arguments to pass when running the agent binary for terminal auth.
852 #[must_use]
853 pub fn args(mut self, args: Vec<String>) -> Self {
854 self.args = args;
855 self
856 }
857
858 /// Additional environment variables to set when running the agent binary for terminal auth.
859 #[must_use]
860 pub fn env(mut self, env: HashMap<String, String>) -> Self {
861 self.env = env;
862 self
863 }
864
865 /// Optional description providing more details about this authentication method.
866 #[must_use]
867 pub fn description(mut self, description: impl IntoOption<String>) -> Self {
868 self.description = description.into_option();
869 self
870 }
871
872 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
873 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
874 /// these keys.
875 ///
876 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
877 #[must_use]
878 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
879 self.meta = meta.into_option();
880 self
881 }
882}
883
884// New session
885
886/// Request parameters for creating a new session.
887///
888/// See protocol docs: [Creating a Session](https://agentclientprotocol.com/protocol/session-setup#creating-a-session)
889#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
890#[schemars(extend("x-side" = "agent", "x-method" = SESSION_NEW_METHOD_NAME))]
891#[serde(rename_all = "camelCase")]
892#[non_exhaustive]
893pub struct NewSessionRequest {
894 /// The working directory for this session. Must be an absolute path.
895 pub cwd: PathBuf,
896 /// List of MCP (Model Context Protocol) servers the agent should connect to.
897 pub mcp_servers: Vec<McpServer>,
898 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
899 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
900 /// these keys.
901 ///
902 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
903 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
904 pub meta: Option<Meta>,
905}
906
907impl NewSessionRequest {
908 #[must_use]
909 pub fn new(cwd: impl Into<PathBuf>) -> Self {
910 Self {
911 cwd: cwd.into(),
912 mcp_servers: vec![],
913 meta: None,
914 }
915 }
916
917 /// List of MCP (Model Context Protocol) servers the agent should connect to.
918 #[must_use]
919 pub fn mcp_servers(mut self, mcp_servers: Vec<McpServer>) -> Self {
920 self.mcp_servers = mcp_servers;
921 self
922 }
923
924 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
925 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
926 /// these keys.
927 ///
928 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
929 #[must_use]
930 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
931 self.meta = meta.into_option();
932 self
933 }
934}
935
936/// Response from creating a new session.
937///
938/// See protocol docs: [Creating a Session](https://agentclientprotocol.com/protocol/session-setup#creating-a-session)
939#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
940#[schemars(extend("x-side" = "agent", "x-method" = SESSION_NEW_METHOD_NAME))]
941#[serde(rename_all = "camelCase")]
942#[non_exhaustive]
943pub struct NewSessionResponse {
944 /// Unique identifier for the created session.
945 ///
946 /// Used in all subsequent requests for this conversation.
947 pub session_id: SessionId,
948 /// Initial mode state if supported by the Agent
949 ///
950 /// See protocol docs: [Session Modes](https://agentclientprotocol.com/protocol/session-modes)
951 #[serde(skip_serializing_if = "Option::is_none")]
952 pub modes: Option<SessionModeState>,
953 /// **UNSTABLE**
954 ///
955 /// This capability is not part of the spec yet, and may be removed or changed at any point.
956 ///
957 /// Initial model state if supported by the Agent
958 #[cfg(feature = "unstable_session_model")]
959 #[serde(skip_serializing_if = "Option::is_none")]
960 pub models: Option<SessionModelState>,
961 /// Initial session configuration options if supported by the Agent.
962 #[serde(skip_serializing_if = "Option::is_none")]
963 pub config_options: Option<Vec<SessionConfigOption>>,
964 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
965 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
966 /// these keys.
967 ///
968 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
969 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
970 pub meta: Option<Meta>,
971}
972
973impl NewSessionResponse {
974 #[must_use]
975 pub fn new(session_id: impl Into<SessionId>) -> Self {
976 Self {
977 session_id: session_id.into(),
978 modes: None,
979 #[cfg(feature = "unstable_session_model")]
980 models: None,
981 config_options: None,
982 meta: None,
983 }
984 }
985
986 /// Initial mode state if supported by the Agent
987 ///
988 /// See protocol docs: [Session Modes](https://agentclientprotocol.com/protocol/session-modes)
989 #[must_use]
990 pub fn modes(mut self, modes: impl IntoOption<SessionModeState>) -> Self {
991 self.modes = modes.into_option();
992 self
993 }
994
995 /// **UNSTABLE**
996 ///
997 /// This capability is not part of the spec yet, and may be removed or changed at any point.
998 ///
999 /// Initial model state if supported by the Agent
1000 #[cfg(feature = "unstable_session_model")]
1001 #[must_use]
1002 pub fn models(mut self, models: impl IntoOption<SessionModelState>) -> Self {
1003 self.models = models.into_option();
1004 self
1005 }
1006
1007 /// Initial session configuration options if supported by the Agent.
1008 #[must_use]
1009 pub fn config_options(
1010 mut self,
1011 config_options: impl IntoOption<Vec<SessionConfigOption>>,
1012 ) -> Self {
1013 self.config_options = config_options.into_option();
1014 self
1015 }
1016
1017 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1018 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1019 /// these keys.
1020 ///
1021 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1022 #[must_use]
1023 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1024 self.meta = meta.into_option();
1025 self
1026 }
1027}
1028
1029// Load session
1030
1031/// Request parameters for loading an existing session.
1032///
1033/// Only available if the Agent supports the `loadSession` capability.
1034///
1035/// See protocol docs: [Loading Sessions](https://agentclientprotocol.com/protocol/session-setup#loading-sessions)
1036#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1037#[schemars(extend("x-side" = "agent", "x-method" = SESSION_LOAD_METHOD_NAME))]
1038#[serde(rename_all = "camelCase")]
1039#[non_exhaustive]
1040pub struct LoadSessionRequest {
1041 /// List of MCP servers to connect to for this session.
1042 pub mcp_servers: Vec<McpServer>,
1043 /// The working directory for this session.
1044 pub cwd: PathBuf,
1045 /// The ID of the session to load.
1046 pub session_id: SessionId,
1047 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1048 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1049 /// these keys.
1050 ///
1051 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1052 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
1053 pub meta: Option<Meta>,
1054}
1055
1056impl LoadSessionRequest {
1057 #[must_use]
1058 pub fn new(session_id: impl Into<SessionId>, cwd: impl Into<PathBuf>) -> Self {
1059 Self {
1060 mcp_servers: vec![],
1061 cwd: cwd.into(),
1062 session_id: session_id.into(),
1063 meta: None,
1064 }
1065 }
1066
1067 /// List of MCP servers to connect to for this session.
1068 #[must_use]
1069 pub fn mcp_servers(mut self, mcp_servers: Vec<McpServer>) -> Self {
1070 self.mcp_servers = mcp_servers;
1071 self
1072 }
1073
1074 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1075 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1076 /// these keys.
1077 ///
1078 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1079 #[must_use]
1080 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1081 self.meta = meta.into_option();
1082 self
1083 }
1084}
1085
1086/// Response from loading an existing session.
1087#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1088#[schemars(extend("x-side" = "agent", "x-method" = SESSION_LOAD_METHOD_NAME))]
1089#[serde(rename_all = "camelCase")]
1090#[non_exhaustive]
1091pub struct LoadSessionResponse {
1092 /// Initial mode state if supported by the Agent
1093 ///
1094 /// See protocol docs: [Session Modes](https://agentclientprotocol.com/protocol/session-modes)
1095 #[serde(default, skip_serializing_if = "Option::is_none")]
1096 pub modes: Option<SessionModeState>,
1097 /// **UNSTABLE**
1098 ///
1099 /// This capability is not part of the spec yet, and may be removed or changed at any point.
1100 ///
1101 /// Initial model state if supported by the Agent
1102 #[cfg(feature = "unstable_session_model")]
1103 #[serde(default, skip_serializing_if = "Option::is_none")]
1104 pub models: Option<SessionModelState>,
1105 /// Initial session configuration options if supported by the Agent.
1106 #[serde(default, skip_serializing_if = "Option::is_none")]
1107 pub config_options: Option<Vec<SessionConfigOption>>,
1108 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1109 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1110 /// these keys.
1111 ///
1112 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1113 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
1114 pub meta: Option<Meta>,
1115}
1116
1117impl LoadSessionResponse {
1118 #[must_use]
1119 pub fn new() -> Self {
1120 Self::default()
1121 }
1122
1123 /// Initial mode state if supported by the Agent
1124 ///
1125 /// See protocol docs: [Session Modes](https://agentclientprotocol.com/protocol/session-modes)
1126 #[must_use]
1127 pub fn modes(mut self, modes: impl IntoOption<SessionModeState>) -> Self {
1128 self.modes = modes.into_option();
1129 self
1130 }
1131
1132 /// **UNSTABLE**
1133 ///
1134 /// This capability is not part of the spec yet, and may be removed or changed at any point.
1135 ///
1136 /// Initial model state if supported by the Agent
1137 #[cfg(feature = "unstable_session_model")]
1138 #[must_use]
1139 pub fn models(mut self, models: impl IntoOption<SessionModelState>) -> Self {
1140 self.models = models.into_option();
1141 self
1142 }
1143
1144 /// Initial session configuration options if supported by the Agent.
1145 #[must_use]
1146 pub fn config_options(
1147 mut self,
1148 config_options: impl IntoOption<Vec<SessionConfigOption>>,
1149 ) -> Self {
1150 self.config_options = config_options.into_option();
1151 self
1152 }
1153
1154 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1155 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1156 /// these keys.
1157 ///
1158 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1159 #[must_use]
1160 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1161 self.meta = meta.into_option();
1162 self
1163 }
1164}
1165
1166// Fork session
1167
1168/// **UNSTABLE**
1169///
1170/// This capability is not part of the spec yet, and may be removed or changed at any point.
1171///
1172/// Request parameters for forking an existing session.
1173///
1174/// Creates a new session based on the context of an existing one, allowing
1175/// operations like generating summaries without affecting the original session's history.
1176///
1177/// Only available if the Agent supports the `session.fork` capability.
1178#[cfg(feature = "unstable_session_fork")]
1179#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1180#[schemars(extend("x-side" = "agent", "x-method" = SESSION_FORK_METHOD_NAME))]
1181#[serde(rename_all = "camelCase")]
1182#[non_exhaustive]
1183pub struct ForkSessionRequest {
1184 /// The ID of the session to fork.
1185 pub session_id: SessionId,
1186 /// The working directory for this session.
1187 pub cwd: PathBuf,
1188 /// List of MCP servers to connect to for this session.
1189 #[serde(default, skip_serializing_if = "Vec::is_empty")]
1190 pub mcp_servers: Vec<McpServer>,
1191 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1192 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1193 /// these keys.
1194 ///
1195 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1196 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
1197 pub meta: Option<Meta>,
1198}
1199
1200#[cfg(feature = "unstable_session_fork")]
1201impl ForkSessionRequest {
1202 #[must_use]
1203 pub fn new(session_id: impl Into<SessionId>, cwd: impl Into<PathBuf>) -> Self {
1204 Self {
1205 session_id: session_id.into(),
1206 cwd: cwd.into(),
1207 mcp_servers: vec![],
1208 meta: None,
1209 }
1210 }
1211
1212 /// List of MCP servers to connect to for this session.
1213 #[must_use]
1214 pub fn mcp_servers(mut self, mcp_servers: Vec<McpServer>) -> Self {
1215 self.mcp_servers = mcp_servers;
1216 self
1217 }
1218
1219 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1220 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1221 /// these keys.
1222 ///
1223 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1224 #[must_use]
1225 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1226 self.meta = meta.into_option();
1227 self
1228 }
1229}
1230
1231/// **UNSTABLE**
1232///
1233/// This capability is not part of the spec yet, and may be removed or changed at any point.
1234///
1235/// Response from forking an existing session.
1236#[cfg(feature = "unstable_session_fork")]
1237#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1238#[schemars(extend("x-side" = "agent", "x-method" = SESSION_FORK_METHOD_NAME))]
1239#[serde(rename_all = "camelCase")]
1240#[non_exhaustive]
1241pub struct ForkSessionResponse {
1242 /// Unique identifier for the newly created forked session.
1243 pub session_id: SessionId,
1244 /// Initial mode state if supported by the Agent
1245 ///
1246 /// See protocol docs: [Session Modes](https://agentclientprotocol.com/protocol/session-modes)
1247 #[serde(skip_serializing_if = "Option::is_none")]
1248 pub modes: Option<SessionModeState>,
1249 /// **UNSTABLE**
1250 ///
1251 /// This capability is not part of the spec yet, and may be removed or changed at any point.
1252 ///
1253 /// Initial model state if supported by the Agent
1254 #[cfg(feature = "unstable_session_model")]
1255 #[serde(skip_serializing_if = "Option::is_none")]
1256 pub models: Option<SessionModelState>,
1257 /// Initial session configuration options if supported by the Agent.
1258 #[serde(skip_serializing_if = "Option::is_none")]
1259 pub config_options: Option<Vec<SessionConfigOption>>,
1260 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1261 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1262 /// these keys.
1263 ///
1264 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1265 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
1266 pub meta: Option<Meta>,
1267}
1268
1269#[cfg(feature = "unstable_session_fork")]
1270impl ForkSessionResponse {
1271 #[must_use]
1272 pub fn new(session_id: impl Into<SessionId>) -> Self {
1273 Self {
1274 session_id: session_id.into(),
1275 modes: None,
1276 #[cfg(feature = "unstable_session_model")]
1277 models: None,
1278 config_options: None,
1279 meta: None,
1280 }
1281 }
1282
1283 /// Initial mode state if supported by the Agent
1284 ///
1285 /// See protocol docs: [Session Modes](https://agentclientprotocol.com/protocol/session-modes)
1286 #[must_use]
1287 pub fn modes(mut self, modes: impl IntoOption<SessionModeState>) -> Self {
1288 self.modes = modes.into_option();
1289 self
1290 }
1291
1292 /// **UNSTABLE**
1293 ///
1294 /// This capability is not part of the spec yet, and may be removed or changed at any point.
1295 ///
1296 /// Initial model state if supported by the Agent
1297 #[cfg(feature = "unstable_session_model")]
1298 #[must_use]
1299 pub fn models(mut self, models: impl IntoOption<SessionModelState>) -> Self {
1300 self.models = models.into_option();
1301 self
1302 }
1303
1304 /// Initial session configuration options if supported by the Agent.
1305 #[must_use]
1306 pub fn config_options(
1307 mut self,
1308 config_options: impl IntoOption<Vec<SessionConfigOption>>,
1309 ) -> Self {
1310 self.config_options = config_options.into_option();
1311 self
1312 }
1313
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 #[must_use]
1320 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1321 self.meta = meta.into_option();
1322 self
1323 }
1324}
1325
1326// Resume session
1327
1328/// **UNSTABLE**
1329///
1330/// This capability is not part of the spec yet, and may be removed or changed at any point.
1331///
1332/// Request parameters for resuming an existing session.
1333///
1334/// Resumes an existing session without returning previous messages (unlike `session/load`).
1335/// This is useful for agents that can resume sessions but don't implement full session loading.
1336///
1337/// Only available if the Agent supports the `session.resume` capability.
1338#[cfg(feature = "unstable_session_resume")]
1339#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1340#[schemars(extend("x-side" = "agent", "x-method" = SESSION_RESUME_METHOD_NAME))]
1341#[serde(rename_all = "camelCase")]
1342#[non_exhaustive]
1343pub struct ResumeSessionRequest {
1344 /// The ID of the session to resume.
1345 pub session_id: SessionId,
1346 /// The working directory for this session.
1347 pub cwd: PathBuf,
1348 /// List of MCP servers to connect to for this session.
1349 #[serde(default, skip_serializing_if = "Vec::is_empty")]
1350 pub mcp_servers: Vec<McpServer>,
1351 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1352 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1353 /// these keys.
1354 ///
1355 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1356 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
1357 pub meta: Option<Meta>,
1358}
1359
1360#[cfg(feature = "unstable_session_resume")]
1361impl ResumeSessionRequest {
1362 #[must_use]
1363 pub fn new(session_id: impl Into<SessionId>, cwd: impl Into<PathBuf>) -> Self {
1364 Self {
1365 session_id: session_id.into(),
1366 cwd: cwd.into(),
1367 mcp_servers: vec![],
1368 meta: None,
1369 }
1370 }
1371
1372 /// List of MCP servers to connect to for this session.
1373 #[must_use]
1374 pub fn mcp_servers(mut self, mcp_servers: Vec<McpServer>) -> Self {
1375 self.mcp_servers = mcp_servers;
1376 self
1377 }
1378
1379 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1380 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1381 /// these keys.
1382 ///
1383 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1384 #[must_use]
1385 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1386 self.meta = meta.into_option();
1387 self
1388 }
1389}
1390
1391/// **UNSTABLE**
1392///
1393/// This capability is not part of the spec yet, and may be removed or changed at any point.
1394///
1395/// Response from resuming an existing session.
1396#[cfg(feature = "unstable_session_resume")]
1397#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1398#[schemars(extend("x-side" = "agent", "x-method" = SESSION_RESUME_METHOD_NAME))]
1399#[serde(rename_all = "camelCase")]
1400#[non_exhaustive]
1401pub struct ResumeSessionResponse {
1402 /// Initial mode state if supported by the Agent
1403 ///
1404 /// See protocol docs: [Session Modes](https://agentclientprotocol.com/protocol/session-modes)
1405 #[serde(default, skip_serializing_if = "Option::is_none")]
1406 pub modes: Option<SessionModeState>,
1407 /// **UNSTABLE**
1408 ///
1409 /// This capability is not part of the spec yet, and may be removed or changed at any point.
1410 ///
1411 /// Initial model state if supported by the Agent
1412 #[cfg(feature = "unstable_session_model")]
1413 #[serde(default, skip_serializing_if = "Option::is_none")]
1414 pub models: Option<SessionModelState>,
1415 /// Initial session configuration options if supported by the Agent.
1416 #[serde(default, skip_serializing_if = "Option::is_none")]
1417 pub config_options: Option<Vec<SessionConfigOption>>,
1418 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1419 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1420 /// these keys.
1421 ///
1422 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1423 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
1424 pub meta: Option<Meta>,
1425}
1426
1427#[cfg(feature = "unstable_session_resume")]
1428impl ResumeSessionResponse {
1429 #[must_use]
1430 pub fn new() -> Self {
1431 Self::default()
1432 }
1433
1434 /// Initial mode state if supported by the Agent
1435 ///
1436 /// See protocol docs: [Session Modes](https://agentclientprotocol.com/protocol/session-modes)
1437 #[must_use]
1438 pub fn modes(mut self, modes: impl IntoOption<SessionModeState>) -> Self {
1439 self.modes = modes.into_option();
1440 self
1441 }
1442
1443 /// **UNSTABLE**
1444 ///
1445 /// This capability is not part of the spec yet, and may be removed or changed at any point.
1446 ///
1447 /// Initial model state if supported by the Agent
1448 #[cfg(feature = "unstable_session_model")]
1449 #[must_use]
1450 pub fn models(mut self, models: impl IntoOption<SessionModelState>) -> Self {
1451 self.models = models.into_option();
1452 self
1453 }
1454
1455 /// Initial session configuration options if supported by the Agent.
1456 #[must_use]
1457 pub fn config_options(
1458 mut self,
1459 config_options: impl IntoOption<Vec<SessionConfigOption>>,
1460 ) -> Self {
1461 self.config_options = config_options.into_option();
1462 self
1463 }
1464
1465 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1466 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1467 /// these keys.
1468 ///
1469 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1470 #[must_use]
1471 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1472 self.meta = meta.into_option();
1473 self
1474 }
1475}
1476
1477// Close session
1478
1479/// **UNSTABLE**
1480///
1481/// This capability is not part of the spec yet, and may be removed or changed at any point.
1482///
1483/// Request parameters for closing an active session.
1484///
1485/// If supported, the agent **must** cancel any ongoing work related to the session
1486/// (treat it as if `session/cancel` was called) and then free up any resources
1487/// associated with the session.
1488///
1489/// Only available if the Agent supports the `session.close` capability.
1490#[cfg(feature = "unstable_session_close")]
1491#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1492#[schemars(extend("x-side" = "agent", "x-method" = SESSION_CLOSE_METHOD_NAME))]
1493#[serde(rename_all = "camelCase")]
1494#[non_exhaustive]
1495pub struct CloseSessionRequest {
1496 /// The ID of the session to close.
1497 pub session_id: SessionId,
1498 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1499 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1500 /// these keys.
1501 ///
1502 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1503 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
1504 pub meta: Option<Meta>,
1505}
1506
1507#[cfg(feature = "unstable_session_close")]
1508impl CloseSessionRequest {
1509 #[must_use]
1510 pub fn new(session_id: impl Into<SessionId>) -> Self {
1511 Self {
1512 session_id: session_id.into(),
1513 meta: None,
1514 }
1515 }
1516
1517 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1518 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1519 /// these keys.
1520 ///
1521 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1522 #[must_use]
1523 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1524 self.meta = meta.into_option();
1525 self
1526 }
1527}
1528
1529/// **UNSTABLE**
1530///
1531/// This capability is not part of the spec yet, and may be removed or changed at any point.
1532///
1533/// Response from closing a session.
1534#[cfg(feature = "unstable_session_close")]
1535#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1536#[schemars(extend("x-side" = "agent", "x-method" = SESSION_CLOSE_METHOD_NAME))]
1537#[serde(rename_all = "camelCase")]
1538#[non_exhaustive]
1539pub struct CloseSessionResponse {
1540 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1541 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1542 /// these keys.
1543 ///
1544 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1545 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
1546 pub meta: Option<Meta>,
1547}
1548
1549#[cfg(feature = "unstable_session_close")]
1550impl CloseSessionResponse {
1551 #[must_use]
1552 pub fn new() -> Self {
1553 Self::default()
1554 }
1555
1556 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1557 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1558 /// these keys.
1559 ///
1560 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1561 #[must_use]
1562 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1563 self.meta = meta.into_option();
1564 self
1565 }
1566}
1567
1568// List sessions
1569
1570/// Request parameters for listing existing sessions.
1571///
1572/// Only available if the Agent supports the `sessionCapabilities.list` capability.
1573#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1574#[schemars(extend("x-side" = "agent", "x-method" = SESSION_LIST_METHOD_NAME))]
1575#[serde(rename_all = "camelCase")]
1576#[non_exhaustive]
1577pub struct ListSessionsRequest {
1578 /// Filter sessions by working directory. Must be an absolute path.
1579 #[serde(skip_serializing_if = "Option::is_none")]
1580 pub cwd: Option<PathBuf>,
1581 /// Opaque cursor token from a previous response's nextCursor field for cursor-based pagination
1582 #[serde(skip_serializing_if = "Option::is_none")]
1583 pub cursor: Option<String>,
1584 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1585 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1586 /// these keys.
1587 ///
1588 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1589 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
1590 pub meta: Option<Meta>,
1591}
1592
1593impl ListSessionsRequest {
1594 #[must_use]
1595 pub fn new() -> Self {
1596 Self::default()
1597 }
1598
1599 /// Filter sessions by working directory. Must be an absolute path.
1600 #[must_use]
1601 pub fn cwd(mut self, cwd: impl IntoOption<PathBuf>) -> Self {
1602 self.cwd = cwd.into_option();
1603 self
1604 }
1605
1606 /// Opaque cursor token from a previous response's nextCursor field for cursor-based pagination
1607 #[must_use]
1608 pub fn cursor(mut self, cursor: impl IntoOption<String>) -> Self {
1609 self.cursor = cursor.into_option();
1610 self
1611 }
1612
1613 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1614 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1615 /// these keys.
1616 ///
1617 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1618 #[must_use]
1619 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1620 self.meta = meta.into_option();
1621 self
1622 }
1623}
1624
1625/// Response from listing sessions.
1626#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1627#[schemars(extend("x-side" = "agent", "x-method" = SESSION_LIST_METHOD_NAME))]
1628#[serde(rename_all = "camelCase")]
1629#[non_exhaustive]
1630pub struct ListSessionsResponse {
1631 /// Array of session information objects
1632 pub sessions: Vec<SessionInfo>,
1633 /// Opaque cursor token. If present, pass this in the next request's cursor parameter
1634 /// to fetch the next page. If absent, there are no more results.
1635 #[serde(skip_serializing_if = "Option::is_none")]
1636 pub next_cursor: Option<String>,
1637 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1638 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1639 /// these keys.
1640 ///
1641 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1642 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
1643 pub meta: Option<Meta>,
1644}
1645
1646impl ListSessionsResponse {
1647 #[must_use]
1648 pub fn new(sessions: Vec<SessionInfo>) -> Self {
1649 Self {
1650 sessions,
1651 next_cursor: None,
1652 meta: None,
1653 }
1654 }
1655
1656 #[must_use]
1657 pub fn next_cursor(mut self, next_cursor: impl IntoOption<String>) -> Self {
1658 self.next_cursor = next_cursor.into_option();
1659 self
1660 }
1661
1662 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1663 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1664 /// these keys.
1665 ///
1666 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1667 #[must_use]
1668 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1669 self.meta = meta.into_option();
1670 self
1671 }
1672}
1673
1674/// Information about a session returned by session/list
1675#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1676#[serde(rename_all = "camelCase")]
1677#[non_exhaustive]
1678pub struct SessionInfo {
1679 /// Unique identifier for the session
1680 pub session_id: SessionId,
1681 /// The working directory for this session. Must be an absolute path.
1682 pub cwd: PathBuf,
1683 /// Human-readable title for the session
1684 #[serde(skip_serializing_if = "Option::is_none")]
1685 pub title: Option<String>,
1686 /// ISO 8601 timestamp of last activity
1687 #[serde(skip_serializing_if = "Option::is_none")]
1688 pub updated_at: Option<String>,
1689 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1690 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1691 /// these keys.
1692 ///
1693 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1694 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
1695 pub meta: Option<Meta>,
1696}
1697
1698impl SessionInfo {
1699 #[must_use]
1700 pub fn new(session_id: impl Into<SessionId>, cwd: impl Into<PathBuf>) -> Self {
1701 Self {
1702 session_id: session_id.into(),
1703 cwd: cwd.into(),
1704 title: None,
1705 updated_at: None,
1706 meta: None,
1707 }
1708 }
1709
1710 /// Human-readable title for the session
1711 #[must_use]
1712 pub fn title(mut self, title: impl IntoOption<String>) -> Self {
1713 self.title = title.into_option();
1714 self
1715 }
1716
1717 /// ISO 8601 timestamp of last activity
1718 #[must_use]
1719 pub fn updated_at(mut self, updated_at: impl IntoOption<String>) -> Self {
1720 self.updated_at = updated_at.into_option();
1721 self
1722 }
1723
1724 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1725 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1726 /// these keys.
1727 ///
1728 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1729 #[must_use]
1730 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1731 self.meta = meta.into_option();
1732 self
1733 }
1734}
1735
1736// Session modes
1737
1738/// The set of modes and the one currently active.
1739#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1740#[serde(rename_all = "camelCase")]
1741#[non_exhaustive]
1742pub struct SessionModeState {
1743 /// The current mode the Agent is in.
1744 pub current_mode_id: SessionModeId,
1745 /// The set of modes that the Agent can operate in
1746 pub available_modes: Vec<SessionMode>,
1747 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1748 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1749 /// these keys.
1750 ///
1751 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1752 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
1753 pub meta: Option<Meta>,
1754}
1755
1756impl SessionModeState {
1757 #[must_use]
1758 pub fn new(
1759 current_mode_id: impl Into<SessionModeId>,
1760 available_modes: Vec<SessionMode>,
1761 ) -> Self {
1762 Self {
1763 current_mode_id: current_mode_id.into(),
1764 available_modes,
1765 meta: None,
1766 }
1767 }
1768
1769 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1770 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1771 /// these keys.
1772 ///
1773 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1774 #[must_use]
1775 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1776 self.meta = meta.into_option();
1777 self
1778 }
1779}
1780
1781/// A mode the agent can operate in.
1782///
1783/// See protocol docs: [Session Modes](https://agentclientprotocol.com/protocol/session-modes)
1784#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1785#[serde(rename_all = "camelCase")]
1786#[non_exhaustive]
1787pub struct SessionMode {
1788 pub id: SessionModeId,
1789 pub name: String,
1790 #[serde(default, skip_serializing_if = "Option::is_none")]
1791 pub description: Option<String>,
1792 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1793 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1794 /// these keys.
1795 ///
1796 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1797 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
1798 pub meta: Option<Meta>,
1799}
1800
1801impl SessionMode {
1802 #[must_use]
1803 pub fn new(id: impl Into<SessionModeId>, name: impl Into<String>) -> Self {
1804 Self {
1805 id: id.into(),
1806 name: name.into(),
1807 description: None,
1808 meta: None,
1809 }
1810 }
1811
1812 #[must_use]
1813 pub fn description(mut self, description: impl IntoOption<String>) -> Self {
1814 self.description = description.into_option();
1815 self
1816 }
1817
1818 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1819 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1820 /// these keys.
1821 ///
1822 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1823 #[must_use]
1824 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1825 self.meta = meta.into_option();
1826 self
1827 }
1828}
1829
1830/// Unique identifier for a Session Mode.
1831#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq, Hash, From, Display)]
1832#[serde(transparent)]
1833#[from(Arc<str>, String, &'static str)]
1834#[non_exhaustive]
1835pub struct SessionModeId(pub Arc<str>);
1836
1837impl SessionModeId {
1838 #[must_use]
1839 pub fn new(id: impl Into<Arc<str>>) -> Self {
1840 Self(id.into())
1841 }
1842}
1843
1844/// Request parameters for setting a session mode.
1845#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1846#[schemars(extend("x-side" = "agent", "x-method" = SESSION_SET_MODE_METHOD_NAME))]
1847#[serde(rename_all = "camelCase")]
1848#[non_exhaustive]
1849pub struct SetSessionModeRequest {
1850 /// The ID of the session to set the mode for.
1851 pub session_id: SessionId,
1852 /// The ID of the mode to set.
1853 pub mode_id: SessionModeId,
1854 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1855 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1856 /// these keys.
1857 ///
1858 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1859 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
1860 pub meta: Option<Meta>,
1861}
1862
1863impl SetSessionModeRequest {
1864 #[must_use]
1865 pub fn new(session_id: impl Into<SessionId>, mode_id: impl Into<SessionModeId>) -> Self {
1866 Self {
1867 session_id: session_id.into(),
1868 mode_id: mode_id.into(),
1869 meta: None,
1870 }
1871 }
1872
1873 #[must_use]
1874 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1875 self.meta = meta.into_option();
1876 self
1877 }
1878}
1879
1880/// Response to `session/set_mode` method.
1881#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1882#[schemars(extend("x-side" = "agent", "x-method" = SESSION_SET_MODE_METHOD_NAME))]
1883#[serde(rename_all = "camelCase")]
1884#[non_exhaustive]
1885pub struct SetSessionModeResponse {
1886 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1887 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1888 /// these keys.
1889 ///
1890 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1891 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
1892 pub meta: Option<Meta>,
1893}
1894
1895impl SetSessionModeResponse {
1896 #[must_use]
1897 pub fn new() -> Self {
1898 Self::default()
1899 }
1900
1901 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1902 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1903 /// these keys.
1904 ///
1905 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1906 #[must_use]
1907 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1908 self.meta = meta.into_option();
1909 self
1910 }
1911}
1912
1913// Session config options
1914
1915/// Unique identifier for a session configuration option.
1916#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq, Hash, From, Display)]
1917#[serde(transparent)]
1918#[from(Arc<str>, String, &'static str)]
1919#[non_exhaustive]
1920pub struct SessionConfigId(pub Arc<str>);
1921
1922impl SessionConfigId {
1923 #[must_use]
1924 pub fn new(id: impl Into<Arc<str>>) -> Self {
1925 Self(id.into())
1926 }
1927}
1928
1929/// Unique identifier for a session configuration option value.
1930#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq, Hash, From, Display)]
1931#[serde(transparent)]
1932#[from(Arc<str>, String, &'static str)]
1933#[non_exhaustive]
1934pub struct SessionConfigValueId(pub Arc<str>);
1935
1936impl SessionConfigValueId {
1937 #[must_use]
1938 pub fn new(id: impl Into<Arc<str>>) -> Self {
1939 Self(id.into())
1940 }
1941}
1942
1943/// Unique identifier for a session configuration option value group.
1944#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq, Hash, From, Display)]
1945#[serde(transparent)]
1946#[from(Arc<str>, String, &'static str)]
1947#[non_exhaustive]
1948pub struct SessionConfigGroupId(pub Arc<str>);
1949
1950impl SessionConfigGroupId {
1951 #[must_use]
1952 pub fn new(id: impl Into<Arc<str>>) -> Self {
1953 Self(id.into())
1954 }
1955}
1956
1957/// A possible value for a session configuration option.
1958#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1959#[serde(rename_all = "camelCase")]
1960#[non_exhaustive]
1961pub struct SessionConfigSelectOption {
1962 /// Unique identifier for this option value.
1963 pub value: SessionConfigValueId,
1964 /// Human-readable label for this option value.
1965 pub name: String,
1966 /// Optional description for this option value.
1967 #[serde(default, skip_serializing_if = "Option::is_none")]
1968 pub description: Option<String>,
1969 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1970 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1971 /// these keys.
1972 ///
1973 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1974 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
1975 pub meta: Option<Meta>,
1976}
1977
1978impl SessionConfigSelectOption {
1979 #[must_use]
1980 pub fn new(value: impl Into<SessionConfigValueId>, name: impl Into<String>) -> Self {
1981 Self {
1982 value: value.into(),
1983 name: name.into(),
1984 description: None,
1985 meta: None,
1986 }
1987 }
1988
1989 #[must_use]
1990 pub fn description(mut self, description: impl IntoOption<String>) -> Self {
1991 self.description = description.into_option();
1992 self
1993 }
1994
1995 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1996 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1997 /// these keys.
1998 ///
1999 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
2000 #[must_use]
2001 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2002 self.meta = meta.into_option();
2003 self
2004 }
2005}
2006
2007/// A group of possible values for a session configuration option.
2008#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2009#[serde(rename_all = "camelCase")]
2010#[non_exhaustive]
2011pub struct SessionConfigSelectGroup {
2012 /// Unique identifier for this group.
2013 pub group: SessionConfigGroupId,
2014 /// Human-readable label for this group.
2015 pub name: String,
2016 /// The set of option values in this group.
2017 pub options: Vec<SessionConfigSelectOption>,
2018 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
2019 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
2020 /// these keys.
2021 ///
2022 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
2023 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
2024 pub meta: Option<Meta>,
2025}
2026
2027impl SessionConfigSelectGroup {
2028 #[must_use]
2029 pub fn new(
2030 group: impl Into<SessionConfigGroupId>,
2031 name: impl Into<String>,
2032 options: Vec<SessionConfigSelectOption>,
2033 ) -> Self {
2034 Self {
2035 group: group.into(),
2036 name: name.into(),
2037 options,
2038 meta: None,
2039 }
2040 }
2041
2042 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
2043 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
2044 /// these keys.
2045 ///
2046 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
2047 #[must_use]
2048 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2049 self.meta = meta.into_option();
2050 self
2051 }
2052}
2053
2054/// Possible values for a session configuration option.
2055#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2056#[serde(untagged)]
2057#[non_exhaustive]
2058pub enum SessionConfigSelectOptions {
2059 /// A flat list of options with no grouping.
2060 Ungrouped(Vec<SessionConfigSelectOption>),
2061 /// A list of options grouped under headers.
2062 Grouped(Vec<SessionConfigSelectGroup>),
2063}
2064
2065impl From<Vec<SessionConfigSelectOption>> for SessionConfigSelectOptions {
2066 fn from(options: Vec<SessionConfigSelectOption>) -> Self {
2067 SessionConfigSelectOptions::Ungrouped(options)
2068 }
2069}
2070
2071impl From<Vec<SessionConfigSelectGroup>> for SessionConfigSelectOptions {
2072 fn from(groups: Vec<SessionConfigSelectGroup>) -> Self {
2073 SessionConfigSelectOptions::Grouped(groups)
2074 }
2075}
2076
2077/// A single-value selector (dropdown) session configuration option payload.
2078#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2079#[serde(rename_all = "camelCase")]
2080#[non_exhaustive]
2081pub struct SessionConfigSelect {
2082 /// The currently selected value.
2083 pub current_value: SessionConfigValueId,
2084 /// The set of selectable options.
2085 pub options: SessionConfigSelectOptions,
2086}
2087
2088impl SessionConfigSelect {
2089 #[must_use]
2090 pub fn new(
2091 current_value: impl Into<SessionConfigValueId>,
2092 options: impl Into<SessionConfigSelectOptions>,
2093 ) -> Self {
2094 Self {
2095 current_value: current_value.into(),
2096 options: options.into(),
2097 }
2098 }
2099}
2100
2101/// **UNSTABLE**
2102///
2103/// This capability is not part of the spec yet, and may be removed or changed at any point.
2104///
2105/// A boolean on/off toggle session configuration option payload.
2106#[cfg(feature = "unstable_boolean_config")]
2107#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2108#[serde(rename_all = "camelCase")]
2109#[non_exhaustive]
2110pub struct SessionConfigBoolean {
2111 /// The current value of the boolean option.
2112 pub current_value: bool,
2113}
2114
2115#[cfg(feature = "unstable_boolean_config")]
2116impl SessionConfigBoolean {
2117 #[must_use]
2118 pub fn new(current_value: bool) -> Self {
2119 Self { current_value }
2120 }
2121}
2122
2123/// Semantic category for a session configuration option.
2124///
2125/// This is intended to help Clients distinguish broadly common selectors (e.g. model selector vs
2126/// session mode selector vs thought/reasoning level) for UX purposes (keyboard shortcuts, icons,
2127/// placement). It MUST NOT be required for correctness. Clients MUST handle missing or unknown
2128/// categories gracefully.
2129///
2130/// Category names beginning with `_` are free for custom use, like other ACP extension methods.
2131/// Category names that do not begin with `_` are reserved for the ACP spec.
2132#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2133#[serde(rename_all = "snake_case")]
2134#[non_exhaustive]
2135pub enum SessionConfigOptionCategory {
2136 /// Session mode selector.
2137 Mode,
2138 /// Model selector.
2139 Model,
2140 /// Thought/reasoning level selector.
2141 ThoughtLevel,
2142 /// Unknown / uncategorized selector.
2143 #[serde(untagged)]
2144 Other(String),
2145}
2146
2147/// Type-specific session configuration option payload.
2148#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2149#[serde(tag = "type", rename_all = "snake_case")]
2150#[schemars(extend("discriminator" = {"propertyName": "type"}))]
2151#[non_exhaustive]
2152pub enum SessionConfigKind {
2153 /// Single-value selector (dropdown).
2154 Select(SessionConfigSelect),
2155 /// **UNSTABLE**
2156 ///
2157 /// This capability is not part of the spec yet, and may be removed or changed at any point.
2158 ///
2159 /// Boolean on/off toggle.
2160 #[cfg(feature = "unstable_boolean_config")]
2161 Boolean(SessionConfigBoolean),
2162}
2163
2164/// A session configuration option selector and its current state.
2165#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2166#[serde(rename_all = "camelCase")]
2167#[non_exhaustive]
2168pub struct SessionConfigOption {
2169 /// Unique identifier for the configuration option.
2170 pub id: SessionConfigId,
2171 /// Human-readable label for the option.
2172 pub name: String,
2173 /// Optional description for the Client to display to the user.
2174 #[serde(default, skip_serializing_if = "Option::is_none")]
2175 pub description: Option<String>,
2176 /// Optional semantic category for this option (UX only).
2177 #[serde(default, skip_serializing_if = "Option::is_none")]
2178 pub category: Option<SessionConfigOptionCategory>,
2179 /// Type-specific fields for this configuration option.
2180 #[serde(flatten)]
2181 pub kind: SessionConfigKind,
2182 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
2183 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
2184 /// these keys.
2185 ///
2186 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
2187 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
2188 pub meta: Option<Meta>,
2189}
2190
2191impl SessionConfigOption {
2192 #[must_use]
2193 pub fn new(
2194 id: impl Into<SessionConfigId>,
2195 name: impl Into<String>,
2196 kind: SessionConfigKind,
2197 ) -> Self {
2198 Self {
2199 id: id.into(),
2200 name: name.into(),
2201 description: None,
2202 category: None,
2203 kind,
2204 meta: None,
2205 }
2206 }
2207
2208 #[must_use]
2209 pub fn select(
2210 id: impl Into<SessionConfigId>,
2211 name: impl Into<String>,
2212 current_value: impl Into<SessionConfigValueId>,
2213 options: impl Into<SessionConfigSelectOptions>,
2214 ) -> Self {
2215 Self::new(
2216 id,
2217 name,
2218 SessionConfigKind::Select(SessionConfigSelect::new(current_value, options)),
2219 )
2220 }
2221
2222 /// **UNSTABLE**
2223 ///
2224 /// This capability is not part of the spec yet, and may be removed or changed at any point.
2225 #[cfg(feature = "unstable_boolean_config")]
2226 #[must_use]
2227 pub fn boolean(
2228 id: impl Into<SessionConfigId>,
2229 name: impl Into<String>,
2230 current_value: bool,
2231 ) -> Self {
2232 Self::new(
2233 id,
2234 name,
2235 SessionConfigKind::Boolean(SessionConfigBoolean::new(current_value)),
2236 )
2237 }
2238
2239 #[must_use]
2240 pub fn description(mut self, description: impl IntoOption<String>) -> Self {
2241 self.description = description.into_option();
2242 self
2243 }
2244
2245 #[must_use]
2246 pub fn category(mut self, category: impl IntoOption<SessionConfigOptionCategory>) -> Self {
2247 self.category = category.into_option();
2248 self
2249 }
2250
2251 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
2252 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
2253 /// these keys.
2254 ///
2255 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
2256 #[must_use]
2257 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2258 self.meta = meta.into_option();
2259 self
2260 }
2261}
2262
2263/// **UNSTABLE**
2264///
2265/// This capability is not part of the spec yet, and may be removed or changed at any point.
2266///
2267/// The value to set for a session configuration option.
2268///
2269/// The `type` field acts as the discriminator in the serialized JSON form.
2270/// When no `type` is present, the value is treated as a [`SessionConfigValueId`]
2271/// via the [`ValueId`](Self::ValueId) fallback variant.
2272///
2273/// The `type` discriminator describes the *shape* of the value, not the option
2274/// kind. For example every option kind that picks from a list of ids
2275/// (`select`, `radio`, …) would use [`ValueId`](Self::ValueId), while a
2276/// future freeform text option would get its own variant.
2277#[cfg(feature = "unstable_boolean_config")]
2278#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2279#[serde(tag = "type", rename_all = "snake_case")]
2280#[non_exhaustive]
2281pub enum SessionConfigOptionValue {
2282 /// A boolean value (`type: "boolean"`).
2283 Boolean {
2284 /// The boolean value.
2285 value: bool,
2286 },
2287 /// A [`SessionConfigValueId`] string value.
2288 ///
2289 /// This is the default when `type` is absent on the wire. Unknown `type`
2290 /// values with string payloads also gracefully deserialize into this
2291 /// variant.
2292 #[serde(untagged)]
2293 ValueId {
2294 /// The value ID.
2295 value: SessionConfigValueId,
2296 },
2297}
2298
2299#[cfg(feature = "unstable_boolean_config")]
2300impl SessionConfigOptionValue {
2301 /// Create a value-id option value (used by `select` and other id-based option types).
2302 #[must_use]
2303 pub fn value_id(id: impl Into<SessionConfigValueId>) -> Self {
2304 Self::ValueId { value: id.into() }
2305 }
2306
2307 /// Create a boolean option value.
2308 #[must_use]
2309 pub fn boolean(val: bool) -> Self {
2310 Self::Boolean { value: val }
2311 }
2312
2313 /// Return the inner [`SessionConfigValueId`] if this is a
2314 /// [`ValueId`](Self::ValueId) value.
2315 #[must_use]
2316 pub fn as_value_id(&self) -> Option<&SessionConfigValueId> {
2317 match self {
2318 Self::ValueId { value } => Some(value),
2319 _ => None,
2320 }
2321 }
2322
2323 /// Return the inner [`bool`] if this is a [`Boolean`](Self::Boolean) value.
2324 #[must_use]
2325 pub fn as_bool(&self) -> Option<bool> {
2326 match self {
2327 Self::Boolean { value } => Some(*value),
2328 _ => None,
2329 }
2330 }
2331}
2332
2333#[cfg(feature = "unstable_boolean_config")]
2334impl From<SessionConfigValueId> for SessionConfigOptionValue {
2335 fn from(value: SessionConfigValueId) -> Self {
2336 Self::ValueId { value }
2337 }
2338}
2339
2340#[cfg(feature = "unstable_boolean_config")]
2341impl From<bool> for SessionConfigOptionValue {
2342 fn from(value: bool) -> Self {
2343 Self::Boolean { value }
2344 }
2345}
2346
2347#[cfg(feature = "unstable_boolean_config")]
2348impl From<&str> for SessionConfigOptionValue {
2349 fn from(value: &str) -> Self {
2350 Self::ValueId {
2351 value: SessionConfigValueId::new(value),
2352 }
2353 }
2354}
2355
2356/// Request parameters for setting a session configuration option.
2357#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2358#[schemars(extend("x-side" = "agent", "x-method" = SESSION_SET_CONFIG_OPTION_METHOD_NAME))]
2359#[serde(rename_all = "camelCase")]
2360#[non_exhaustive]
2361pub struct SetSessionConfigOptionRequest {
2362 /// The ID of the session to set the configuration option for.
2363 pub session_id: SessionId,
2364 /// The ID of the configuration option to set.
2365 pub config_id: SessionConfigId,
2366 /// The value to set, including a `type` discriminator and the raw `value`.
2367 ///
2368 /// When `type` is absent on the wire, defaults to treating the value as a
2369 /// [`SessionConfigValueId`] for `select` options.
2370 #[cfg(feature = "unstable_boolean_config")]
2371 #[serde(flatten)]
2372 pub value: SessionConfigOptionValue,
2373 /// The ID of the configuration option value to set.
2374 #[cfg(not(feature = "unstable_boolean_config"))]
2375 pub value: SessionConfigValueId,
2376 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
2377 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
2378 /// these keys.
2379 ///
2380 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
2381 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
2382 pub meta: Option<Meta>,
2383}
2384
2385impl SetSessionConfigOptionRequest {
2386 #[cfg(feature = "unstable_boolean_config")]
2387 #[must_use]
2388 pub fn new(
2389 session_id: impl Into<SessionId>,
2390 config_id: impl Into<SessionConfigId>,
2391 value: impl Into<SessionConfigOptionValue>,
2392 ) -> Self {
2393 Self {
2394 session_id: session_id.into(),
2395 config_id: config_id.into(),
2396 value: value.into(),
2397 meta: None,
2398 }
2399 }
2400
2401 #[cfg(not(feature = "unstable_boolean_config"))]
2402 #[must_use]
2403 pub fn new(
2404 session_id: impl Into<SessionId>,
2405 config_id: impl Into<SessionConfigId>,
2406 value: impl Into<SessionConfigValueId>,
2407 ) -> Self {
2408 Self {
2409 session_id: session_id.into(),
2410 config_id: config_id.into(),
2411 value: value.into(),
2412 meta: None,
2413 }
2414 }
2415
2416 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
2417 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
2418 /// these keys.
2419 ///
2420 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
2421 #[must_use]
2422 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2423 self.meta = meta.into_option();
2424 self
2425 }
2426}
2427
2428/// Response to `session/set_config_option` method.
2429#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2430#[schemars(extend("x-side" = "agent", "x-method" = SESSION_SET_CONFIG_OPTION_METHOD_NAME))]
2431#[serde(rename_all = "camelCase")]
2432#[non_exhaustive]
2433pub struct SetSessionConfigOptionResponse {
2434 /// The full set of configuration options and their current values.
2435 pub config_options: Vec<SessionConfigOption>,
2436 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
2437 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
2438 /// these keys.
2439 ///
2440 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
2441 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
2442 pub meta: Option<Meta>,
2443}
2444
2445impl SetSessionConfigOptionResponse {
2446 #[must_use]
2447 pub fn new(config_options: Vec<SessionConfigOption>) -> Self {
2448 Self {
2449 config_options,
2450 meta: None,
2451 }
2452 }
2453
2454 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
2455 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
2456 /// these keys.
2457 ///
2458 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
2459 #[must_use]
2460 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2461 self.meta = meta.into_option();
2462 self
2463 }
2464}
2465
2466// MCP
2467
2468/// Configuration for connecting to an MCP (Model Context Protocol) server.
2469///
2470/// MCP servers provide tools and context that the agent can use when
2471/// processing prompts.
2472///
2473/// See protocol docs: [MCP Servers](https://agentclientprotocol.com/protocol/session-setup#mcp-servers)
2474#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2475#[serde(tag = "type", rename_all = "snake_case")]
2476#[non_exhaustive]
2477pub enum McpServer {
2478 /// HTTP transport configuration
2479 ///
2480 /// Only available when the Agent capabilities indicate `mcp_capabilities.http` is `true`.
2481 Http(McpServerHttp),
2482 /// SSE transport configuration
2483 ///
2484 /// Only available when the Agent capabilities indicate `mcp_capabilities.sse` is `true`.
2485 Sse(McpServerSse),
2486 /// Stdio transport configuration
2487 ///
2488 /// All Agents MUST support this transport.
2489 #[serde(untagged)]
2490 Stdio(McpServerStdio),
2491}
2492
2493/// HTTP transport configuration for MCP.
2494#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2495#[serde(rename_all = "camelCase")]
2496#[non_exhaustive]
2497pub struct McpServerHttp {
2498 /// Human-readable name identifying this MCP server.
2499 pub name: String,
2500 /// URL to the MCP server.
2501 pub url: String,
2502 /// HTTP headers to set when making requests to the MCP server.
2503 pub headers: Vec<HttpHeader>,
2504 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
2505 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
2506 /// these keys.
2507 ///
2508 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
2509 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
2510 pub meta: Option<Meta>,
2511}
2512
2513impl McpServerHttp {
2514 #[must_use]
2515 pub fn new(name: impl Into<String>, url: impl Into<String>) -> Self {
2516 Self {
2517 name: name.into(),
2518 url: url.into(),
2519 headers: Vec::new(),
2520 meta: None,
2521 }
2522 }
2523
2524 /// HTTP headers to set when making requests to the MCP server.
2525 #[must_use]
2526 pub fn headers(mut self, headers: Vec<HttpHeader>) -> Self {
2527 self.headers = headers;
2528 self
2529 }
2530
2531 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
2532 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
2533 /// these keys.
2534 ///
2535 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
2536 #[must_use]
2537 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2538 self.meta = meta.into_option();
2539 self
2540 }
2541}
2542
2543/// SSE transport configuration for MCP.
2544#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2545#[serde(rename_all = "camelCase")]
2546#[non_exhaustive]
2547pub struct McpServerSse {
2548 /// Human-readable name identifying this MCP server.
2549 pub name: String,
2550 /// URL to the MCP server.
2551 pub url: String,
2552 /// HTTP headers to set when making requests to the MCP server.
2553 pub headers: Vec<HttpHeader>,
2554 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
2555 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
2556 /// these keys.
2557 ///
2558 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
2559 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
2560 pub meta: Option<Meta>,
2561}
2562
2563impl McpServerSse {
2564 #[must_use]
2565 pub fn new(name: impl Into<String>, url: impl Into<String>) -> Self {
2566 Self {
2567 name: name.into(),
2568 url: url.into(),
2569 headers: Vec::new(),
2570 meta: None,
2571 }
2572 }
2573
2574 /// HTTP headers to set when making requests to the MCP server.
2575 #[must_use]
2576 pub fn headers(mut self, headers: Vec<HttpHeader>) -> Self {
2577 self.headers = headers;
2578 self
2579 }
2580
2581 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
2582 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
2583 /// these keys.
2584 ///
2585 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
2586 #[must_use]
2587 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2588 self.meta = meta.into_option();
2589 self
2590 }
2591}
2592
2593/// Stdio transport configuration for MCP.
2594#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2595#[serde(rename_all = "camelCase")]
2596#[non_exhaustive]
2597pub struct McpServerStdio {
2598 /// Human-readable name identifying this MCP server.
2599 pub name: String,
2600 /// Path to the MCP server executable.
2601 pub command: PathBuf,
2602 /// Command-line arguments to pass to the MCP server.
2603 pub args: Vec<String>,
2604 /// Environment variables to set when launching the MCP server.
2605 pub env: Vec<EnvVariable>,
2606 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
2607 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
2608 /// these keys.
2609 ///
2610 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
2611 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
2612 pub meta: Option<Meta>,
2613}
2614
2615impl McpServerStdio {
2616 #[must_use]
2617 pub fn new(name: impl Into<String>, command: impl Into<PathBuf>) -> Self {
2618 Self {
2619 name: name.into(),
2620 command: command.into(),
2621 args: Vec::new(),
2622 env: Vec::new(),
2623 meta: None,
2624 }
2625 }
2626
2627 /// Command-line arguments to pass to the MCP server.
2628 #[must_use]
2629 pub fn args(mut self, args: Vec<String>) -> Self {
2630 self.args = args;
2631 self
2632 }
2633
2634 /// Environment variables to set when launching the MCP server.
2635 #[must_use]
2636 pub fn env(mut self, env: Vec<EnvVariable>) -> Self {
2637 self.env = env;
2638 self
2639 }
2640
2641 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
2642 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
2643 /// these keys.
2644 ///
2645 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
2646 #[must_use]
2647 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2648 self.meta = meta.into_option();
2649 self
2650 }
2651}
2652
2653/// An environment variable to set when launching an MCP server.
2654#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2655#[serde(rename_all = "camelCase")]
2656#[non_exhaustive]
2657pub struct EnvVariable {
2658 /// The name of the environment variable.
2659 pub name: String,
2660 /// The value to set for the environment variable.
2661 pub value: String,
2662 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
2663 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
2664 /// these keys.
2665 ///
2666 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
2667 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
2668 pub meta: Option<Meta>,
2669}
2670
2671impl EnvVariable {
2672 #[must_use]
2673 pub fn new(name: impl Into<String>, value: impl Into<String>) -> Self {
2674 Self {
2675 name: name.into(),
2676 value: value.into(),
2677 meta: None,
2678 }
2679 }
2680
2681 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
2682 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
2683 /// these keys.
2684 ///
2685 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
2686 #[must_use]
2687 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2688 self.meta = meta.into_option();
2689 self
2690 }
2691}
2692
2693/// An HTTP header to set when making requests to the MCP server.
2694#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2695#[serde(rename_all = "camelCase")]
2696#[non_exhaustive]
2697pub struct HttpHeader {
2698 /// The name of the HTTP header.
2699 pub name: String,
2700 /// The value to set for the HTTP header.
2701 pub value: String,
2702 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
2703 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
2704 /// these keys.
2705 ///
2706 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
2707 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
2708 pub meta: Option<Meta>,
2709}
2710
2711impl HttpHeader {
2712 #[must_use]
2713 pub fn new(name: impl Into<String>, value: impl Into<String>) -> Self {
2714 Self {
2715 name: name.into(),
2716 value: value.into(),
2717 meta: None,
2718 }
2719 }
2720
2721 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
2722 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
2723 /// these keys.
2724 ///
2725 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
2726 #[must_use]
2727 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2728 self.meta = meta.into_option();
2729 self
2730 }
2731}
2732
2733// Prompt
2734
2735/// Request parameters for sending a user prompt to the agent.
2736///
2737/// Contains the user's message and any additional context.
2738///
2739/// See protocol docs: [User Message](https://agentclientprotocol.com/protocol/prompt-turn#1-user-message)
2740#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq)]
2741#[schemars(extend("x-side" = "agent", "x-method" = SESSION_PROMPT_METHOD_NAME))]
2742#[serde(rename_all = "camelCase")]
2743#[non_exhaustive]
2744pub struct PromptRequest {
2745 /// The ID of the session to send this user message to
2746 pub session_id: SessionId,
2747 /// **UNSTABLE**
2748 ///
2749 /// This capability is not part of the spec yet, and may be removed or changed at any point.
2750 ///
2751 /// A client-generated unique identifier for this user message.
2752 ///
2753 /// If provided, the Agent SHOULD echo this value as `userMessageId` in the
2754 /// [`PromptResponse`] to confirm it was recorded.
2755 /// Both clients and agents MUST use UUID format for message IDs.
2756 #[cfg(feature = "unstable_message_id")]
2757 #[serde(skip_serializing_if = "Option::is_none")]
2758 pub message_id: Option<String>,
2759 /// The blocks of content that compose the user's message.
2760 ///
2761 /// As a baseline, the Agent MUST support [`ContentBlock::Text`] and [`ContentBlock::ResourceLink`],
2762 /// while other variants are optionally enabled via [`PromptCapabilities`].
2763 ///
2764 /// The Client MUST adapt its interface according to [`PromptCapabilities`].
2765 ///
2766 /// The client MAY include referenced pieces of context as either
2767 /// [`ContentBlock::Resource`] or [`ContentBlock::ResourceLink`].
2768 ///
2769 /// When available, [`ContentBlock::Resource`] is preferred
2770 /// as it avoids extra round-trips and allows the message to include
2771 /// pieces of context from sources the agent may not have access to.
2772 pub prompt: Vec<ContentBlock>,
2773 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
2774 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
2775 /// these keys.
2776 ///
2777 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
2778 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
2779 pub meta: Option<Meta>,
2780}
2781
2782impl PromptRequest {
2783 #[must_use]
2784 pub fn new(session_id: impl Into<SessionId>, prompt: Vec<ContentBlock>) -> Self {
2785 Self {
2786 session_id: session_id.into(),
2787 #[cfg(feature = "unstable_message_id")]
2788 message_id: None,
2789 prompt,
2790 meta: None,
2791 }
2792 }
2793
2794 /// **UNSTABLE**
2795 ///
2796 /// This capability is not part of the spec yet, and may be removed or changed at any point.
2797 ///
2798 /// A client-generated unique identifier for this user message.
2799 ///
2800 /// If provided, the Agent SHOULD echo this value as `userMessageId` in the
2801 /// [`PromptResponse`] to confirm it was recorded.
2802 /// Both clients and agents MUST use UUID format for message IDs.
2803 #[cfg(feature = "unstable_message_id")]
2804 #[must_use]
2805 pub fn message_id(mut self, message_id: impl IntoOption<String>) -> Self {
2806 self.message_id = message_id.into_option();
2807 self
2808 }
2809
2810 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
2811 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
2812 /// these keys.
2813 ///
2814 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
2815 #[must_use]
2816 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2817 self.meta = meta.into_option();
2818 self
2819 }
2820}
2821
2822/// Response from processing a user prompt.
2823///
2824/// See protocol docs: [Check for Completion](https://agentclientprotocol.com/protocol/prompt-turn#4-check-for-completion)
2825#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2826#[schemars(extend("x-side" = "agent", "x-method" = SESSION_PROMPT_METHOD_NAME))]
2827#[serde(rename_all = "camelCase")]
2828#[non_exhaustive]
2829pub struct PromptResponse {
2830 /// **UNSTABLE**
2831 ///
2832 /// This capability is not part of the spec yet, and may be removed or changed at any point.
2833 ///
2834 /// The acknowledged user message ID.
2835 ///
2836 /// If the client provided a `messageId` in the [`PromptRequest`], the agent echoes it here
2837 /// to confirm it was recorded. If the client did not provide one, the agent MAY assign one
2838 /// and return it here. Absence of this field indicates the agent did not record a message ID.
2839 #[cfg(feature = "unstable_message_id")]
2840 #[serde(skip_serializing_if = "Option::is_none")]
2841 pub user_message_id: Option<String>,
2842 /// Indicates why the agent stopped processing the turn.
2843 pub stop_reason: StopReason,
2844 /// **UNSTABLE**
2845 ///
2846 /// This capability is not part of the spec yet, and may be removed or changed at any point.
2847 ///
2848 /// Token usage for this turn (optional).
2849 #[cfg(feature = "unstable_session_usage")]
2850 #[serde(skip_serializing_if = "Option::is_none")]
2851 pub usage: Option<Usage>,
2852 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
2853 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
2854 /// these keys.
2855 ///
2856 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
2857 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
2858 pub meta: Option<Meta>,
2859}
2860
2861impl PromptResponse {
2862 #[must_use]
2863 pub fn new(stop_reason: StopReason) -> Self {
2864 Self {
2865 #[cfg(feature = "unstable_message_id")]
2866 user_message_id: None,
2867 stop_reason,
2868 #[cfg(feature = "unstable_session_usage")]
2869 usage: None,
2870 meta: None,
2871 }
2872 }
2873
2874 /// **UNSTABLE**
2875 ///
2876 /// This capability is not part of the spec yet, and may be removed or changed at any point.
2877 ///
2878 /// The acknowledged user message ID.
2879 ///
2880 /// If the client provided a `messageId` in the [`PromptRequest`], the agent echoes it here
2881 /// to confirm it was recorded. If the client did not provide one, the agent MAY assign one
2882 /// and return it here. Absence of this field indicates the agent did not record a message ID.
2883 #[cfg(feature = "unstable_message_id")]
2884 #[must_use]
2885 pub fn user_message_id(mut self, user_message_id: impl IntoOption<String>) -> Self {
2886 self.user_message_id = user_message_id.into_option();
2887 self
2888 }
2889
2890 /// **UNSTABLE**
2891 ///
2892 /// This capability is not part of the spec yet, and may be removed or changed at any point.
2893 ///
2894 /// Token usage for this turn.
2895 #[cfg(feature = "unstable_session_usage")]
2896 #[must_use]
2897 pub fn usage(mut self, usage: impl IntoOption<Usage>) -> Self {
2898 self.usage = usage.into_option();
2899 self
2900 }
2901
2902 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
2903 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
2904 /// these keys.
2905 ///
2906 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
2907 #[must_use]
2908 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2909 self.meta = meta.into_option();
2910 self
2911 }
2912}
2913
2914/// Reasons why an agent stops processing a prompt turn.
2915///
2916/// See protocol docs: [Stop Reasons](https://agentclientprotocol.com/protocol/prompt-turn#stop-reasons)
2917#[derive(Debug, Copy, Clone, Eq, PartialEq, Serialize, Deserialize, JsonSchema)]
2918#[serde(rename_all = "snake_case")]
2919#[non_exhaustive]
2920pub enum StopReason {
2921 /// The turn ended successfully.
2922 EndTurn,
2923 /// The turn ended because the agent reached the maximum number of tokens.
2924 MaxTokens,
2925 /// The turn ended because the agent reached the maximum number of allowed
2926 /// agent requests between user turns.
2927 MaxTurnRequests,
2928 /// The turn ended because the agent refused to continue. The user prompt
2929 /// and everything that comes after it won't be included in the next
2930 /// prompt, so this should be reflected in the UI.
2931 Refusal,
2932 /// The turn was cancelled by the client via `session/cancel`.
2933 ///
2934 /// This stop reason MUST be returned when the client sends a `session/cancel`
2935 /// notification, even if the cancellation causes exceptions in underlying operations.
2936 /// Agents should catch these exceptions and return this semantically meaningful
2937 /// response to confirm successful cancellation.
2938 Cancelled,
2939}
2940
2941/// **UNSTABLE**
2942///
2943/// This capability is not part of the spec yet, and may be removed or changed at any point.
2944///
2945/// Token usage information for a prompt turn.
2946#[cfg(feature = "unstable_session_usage")]
2947#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2948#[serde(rename_all = "camelCase")]
2949#[non_exhaustive]
2950pub struct Usage {
2951 /// Sum of all token types across session.
2952 pub total_tokens: u64,
2953 /// Total input tokens across all turns.
2954 pub input_tokens: u64,
2955 /// Total output tokens across all turns.
2956 pub output_tokens: u64,
2957 /// Total thought/reasoning tokens
2958 #[serde(skip_serializing_if = "Option::is_none")]
2959 pub thought_tokens: Option<u64>,
2960 /// Total cache read tokens.
2961 #[serde(skip_serializing_if = "Option::is_none")]
2962 pub cached_read_tokens: Option<u64>,
2963 /// Total cache write tokens.
2964 #[serde(skip_serializing_if = "Option::is_none")]
2965 pub cached_write_tokens: Option<u64>,
2966}
2967
2968#[cfg(feature = "unstable_session_usage")]
2969impl Usage {
2970 #[must_use]
2971 pub fn new(total_tokens: u64, input_tokens: u64, output_tokens: u64) -> Self {
2972 Self {
2973 total_tokens,
2974 input_tokens,
2975 output_tokens,
2976 thought_tokens: None,
2977 cached_read_tokens: None,
2978 cached_write_tokens: None,
2979 }
2980 }
2981
2982 /// Total thought/reasoning tokens
2983 #[must_use]
2984 pub fn thought_tokens(mut self, thought_tokens: impl IntoOption<u64>) -> Self {
2985 self.thought_tokens = thought_tokens.into_option();
2986 self
2987 }
2988
2989 /// Total cache read tokens.
2990 #[must_use]
2991 pub fn cached_read_tokens(mut self, cached_read_tokens: impl IntoOption<u64>) -> Self {
2992 self.cached_read_tokens = cached_read_tokens.into_option();
2993 self
2994 }
2995
2996 /// Total cache write tokens.
2997 #[must_use]
2998 pub fn cached_write_tokens(mut self, cached_write_tokens: impl IntoOption<u64>) -> Self {
2999 self.cached_write_tokens = cached_write_tokens.into_option();
3000 self
3001 }
3002}
3003
3004// Model
3005
3006/// **UNSTABLE**
3007///
3008/// This capability is not part of the spec yet, and may be removed or changed at any point.
3009///
3010/// The set of models and the one currently active.
3011#[cfg(feature = "unstable_session_model")]
3012#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3013#[serde(rename_all = "camelCase")]
3014#[non_exhaustive]
3015pub struct SessionModelState {
3016 /// The current model the Agent is in.
3017 pub current_model_id: ModelId,
3018 /// The set of models that the Agent can use
3019 pub available_models: Vec<ModelInfo>,
3020 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
3021 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
3022 /// these keys.
3023 ///
3024 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
3025 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
3026 pub meta: Option<Meta>,
3027}
3028
3029#[cfg(feature = "unstable_session_model")]
3030impl SessionModelState {
3031 #[must_use]
3032 pub fn new(current_model_id: impl Into<ModelId>, available_models: Vec<ModelInfo>) -> Self {
3033 Self {
3034 current_model_id: current_model_id.into(),
3035 available_models,
3036 meta: None,
3037 }
3038 }
3039
3040 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
3041 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
3042 /// these keys.
3043 ///
3044 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
3045 #[must_use]
3046 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3047 self.meta = meta.into_option();
3048 self
3049 }
3050}
3051
3052/// **UNSTABLE**
3053///
3054/// This capability is not part of the spec yet, and may be removed or changed at any point.
3055///
3056/// A unique identifier for a model.
3057#[cfg(feature = "unstable_session_model")]
3058#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq, Hash, Display, From)]
3059#[serde(transparent)]
3060#[from(Arc<str>, String, &'static str)]
3061#[non_exhaustive]
3062pub struct ModelId(pub Arc<str>);
3063
3064#[cfg(feature = "unstable_session_model")]
3065impl ModelId {
3066 #[must_use]
3067 pub fn new(id: impl Into<Arc<str>>) -> Self {
3068 Self(id.into())
3069 }
3070}
3071
3072/// **UNSTABLE**
3073///
3074/// This capability is not part of the spec yet, and may be removed or changed at any point.
3075///
3076/// Information about a selectable model.
3077#[cfg(feature = "unstable_session_model")]
3078#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3079#[serde(rename_all = "camelCase")]
3080#[non_exhaustive]
3081pub struct ModelInfo {
3082 /// Unique identifier for the model.
3083 pub model_id: ModelId,
3084 /// Human-readable name of the model.
3085 pub name: String,
3086 /// Optional description of the model.
3087 #[serde(default, skip_serializing_if = "Option::is_none")]
3088 pub description: Option<String>,
3089 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
3090 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
3091 /// these keys.
3092 ///
3093 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
3094 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
3095 pub meta: Option<Meta>,
3096}
3097
3098#[cfg(feature = "unstable_session_model")]
3099impl ModelInfo {
3100 #[must_use]
3101 pub fn new(model_id: impl Into<ModelId>, name: impl Into<String>) -> Self {
3102 Self {
3103 model_id: model_id.into(),
3104 name: name.into(),
3105 description: None,
3106 meta: None,
3107 }
3108 }
3109
3110 /// Optional description of the model.
3111 #[must_use]
3112 pub fn description(mut self, description: impl IntoOption<String>) -> Self {
3113 self.description = description.into_option();
3114 self
3115 }
3116
3117 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
3118 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
3119 /// these keys.
3120 ///
3121 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
3122 #[must_use]
3123 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3124 self.meta = meta.into_option();
3125 self
3126 }
3127}
3128
3129/// **UNSTABLE**
3130///
3131/// This capability is not part of the spec yet, and may be removed or changed at any point.
3132///
3133/// Request parameters for setting a session model.
3134#[cfg(feature = "unstable_session_model")]
3135#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3136#[schemars(extend("x-side" = "agent", "x-method" = SESSION_SET_MODEL_METHOD_NAME))]
3137#[serde(rename_all = "camelCase")]
3138#[non_exhaustive]
3139pub struct SetSessionModelRequest {
3140 /// The ID of the session to set the model for.
3141 pub session_id: SessionId,
3142 /// The ID of the model to set.
3143 pub model_id: ModelId,
3144 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
3145 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
3146 /// these keys.
3147 ///
3148 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
3149 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
3150 pub meta: Option<Meta>,
3151}
3152
3153#[cfg(feature = "unstable_session_model")]
3154impl SetSessionModelRequest {
3155 #[must_use]
3156 pub fn new(session_id: impl Into<SessionId>, model_id: impl Into<ModelId>) -> Self {
3157 Self {
3158 session_id: session_id.into(),
3159 model_id: model_id.into(),
3160 meta: None,
3161 }
3162 }
3163
3164 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
3165 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
3166 /// these keys.
3167 ///
3168 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
3169 #[must_use]
3170 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3171 self.meta = meta.into_option();
3172 self
3173 }
3174}
3175
3176/// **UNSTABLE**
3177///
3178/// This capability is not part of the spec yet, and may be removed or changed at any point.
3179///
3180/// Response to `session/set_model` method.
3181#[cfg(feature = "unstable_session_model")]
3182#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3183#[schemars(extend("x-side" = "agent", "x-method" = SESSION_SET_MODEL_METHOD_NAME))]
3184#[serde(rename_all = "camelCase")]
3185#[non_exhaustive]
3186pub struct SetSessionModelResponse {
3187 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
3188 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
3189 /// these keys.
3190 ///
3191 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
3192 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
3193 pub meta: Option<Meta>,
3194}
3195
3196#[cfg(feature = "unstable_session_model")]
3197impl SetSessionModelResponse {
3198 #[must_use]
3199 pub fn new() -> Self {
3200 Self::default()
3201 }
3202
3203 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
3204 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
3205 /// these keys.
3206 ///
3207 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
3208 #[must_use]
3209 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3210 self.meta = meta.into_option();
3211 self
3212 }
3213}
3214
3215// Capabilities
3216
3217/// Capabilities supported by the agent.
3218///
3219/// Advertised during initialization to inform the client about
3220/// available features and content types.
3221///
3222/// See protocol docs: [Agent Capabilities](https://agentclientprotocol.com/protocol/initialization#agent-capabilities)
3223#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3224#[serde(rename_all = "camelCase")]
3225#[non_exhaustive]
3226pub struct AgentCapabilities {
3227 /// Whether the agent supports `session/load`.
3228 #[serde(default)]
3229 pub load_session: bool,
3230 /// Prompt capabilities supported by the agent.
3231 #[serde(default)]
3232 pub prompt_capabilities: PromptCapabilities,
3233 /// MCP capabilities supported by the agent.
3234 #[serde(default)]
3235 pub mcp_capabilities: McpCapabilities,
3236 #[serde(default)]
3237 pub session_capabilities: SessionCapabilities,
3238 /// **UNSTABLE**
3239 ///
3240 /// This capability is not part of the spec yet, and may be removed or changed at any point.
3241 ///
3242 /// Authentication-related capabilities supported by the agent.
3243 #[cfg(feature = "unstable_logout")]
3244 #[serde(default)]
3245 pub auth: AgentAuthCapabilities,
3246 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
3247 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
3248 /// these keys.
3249 ///
3250 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
3251 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
3252 pub meta: Option<Meta>,
3253}
3254
3255impl AgentCapabilities {
3256 #[must_use]
3257 pub fn new() -> Self {
3258 Self::default()
3259 }
3260
3261 /// Whether the agent supports `session/load`.
3262 #[must_use]
3263 pub fn load_session(mut self, load_session: bool) -> Self {
3264 self.load_session = load_session;
3265 self
3266 }
3267
3268 /// Prompt capabilities supported by the agent.
3269 #[must_use]
3270 pub fn prompt_capabilities(mut self, prompt_capabilities: PromptCapabilities) -> Self {
3271 self.prompt_capabilities = prompt_capabilities;
3272 self
3273 }
3274
3275 /// MCP capabilities supported by the agent.
3276 #[must_use]
3277 pub fn mcp_capabilities(mut self, mcp_capabilities: McpCapabilities) -> Self {
3278 self.mcp_capabilities = mcp_capabilities;
3279 self
3280 }
3281
3282 /// Session capabilities supported by the agent.
3283 #[must_use]
3284 pub fn session_capabilities(mut self, session_capabilities: SessionCapabilities) -> Self {
3285 self.session_capabilities = session_capabilities;
3286 self
3287 }
3288
3289 /// **UNSTABLE**
3290 ///
3291 /// This capability is not part of the spec yet, and may be removed or changed at any point.
3292 ///
3293 /// Authentication-related capabilities supported by the agent.
3294 #[cfg(feature = "unstable_logout")]
3295 #[must_use]
3296 pub fn auth(mut self, auth: AgentAuthCapabilities) -> Self {
3297 self.auth = auth;
3298 self
3299 }
3300
3301 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
3302 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
3303 /// these keys.
3304 ///
3305 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
3306 #[must_use]
3307 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3308 self.meta = meta.into_option();
3309 self
3310 }
3311}
3312
3313/// Session capabilities supported by the agent.
3314///
3315/// As a baseline, all Agents **MUST** support `session/new`, `session/prompt`, `session/cancel`, and `session/update`.
3316///
3317/// Optionally, they **MAY** support other session methods and notifications by specifying additional capabilities.
3318///
3319/// Note: `session/load` is still handled by the top-level `load_session` capability. This will be unified in future versions of the protocol.
3320///
3321/// See protocol docs: [Session Capabilities](https://agentclientprotocol.com/protocol/initialization#session-capabilities)
3322#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3323#[non_exhaustive]
3324pub struct SessionCapabilities {
3325 /// Whether the agent supports `session/list`.
3326 #[serde(skip_serializing_if = "Option::is_none")]
3327 pub list: Option<SessionListCapabilities>,
3328 /// **UNSTABLE**
3329 ///
3330 /// This capability is not part of the spec yet, and may be removed or changed at any point.
3331 ///
3332 /// Whether the agent supports `session/fork`.
3333 #[cfg(feature = "unstable_session_fork")]
3334 #[serde(skip_serializing_if = "Option::is_none")]
3335 pub fork: Option<SessionForkCapabilities>,
3336 /// **UNSTABLE**
3337 ///
3338 /// This capability is not part of the spec yet, and may be removed or changed at any point.
3339 ///
3340 /// Whether the agent supports `session/resume`.
3341 #[cfg(feature = "unstable_session_resume")]
3342 #[serde(skip_serializing_if = "Option::is_none")]
3343 pub resume: Option<SessionResumeCapabilities>,
3344 /// **UNSTABLE**
3345 ///
3346 /// This capability is not part of the spec yet, and may be removed or changed at any point.
3347 ///
3348 /// Whether the agent supports `session/close`.
3349 #[cfg(feature = "unstable_session_close")]
3350 #[serde(skip_serializing_if = "Option::is_none")]
3351 pub close: Option<SessionCloseCapabilities>,
3352 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
3353 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
3354 /// these keys.
3355 ///
3356 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
3357 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
3358 pub meta: Option<Meta>,
3359}
3360
3361impl SessionCapabilities {
3362 #[must_use]
3363 pub fn new() -> Self {
3364 Self::default()
3365 }
3366
3367 /// Whether the agent supports `session/list`.
3368 #[must_use]
3369 pub fn list(mut self, list: impl IntoOption<SessionListCapabilities>) -> Self {
3370 self.list = list.into_option();
3371 self
3372 }
3373
3374 #[cfg(feature = "unstable_session_fork")]
3375 /// Whether the agent supports `session/fork`.
3376 #[must_use]
3377 pub fn fork(mut self, fork: impl IntoOption<SessionForkCapabilities>) -> Self {
3378 self.fork = fork.into_option();
3379 self
3380 }
3381
3382 #[cfg(feature = "unstable_session_resume")]
3383 /// Whether the agent supports `session/resume`.
3384 #[must_use]
3385 pub fn resume(mut self, resume: impl IntoOption<SessionResumeCapabilities>) -> Self {
3386 self.resume = resume.into_option();
3387 self
3388 }
3389
3390 #[cfg(feature = "unstable_session_close")]
3391 /// Whether the agent supports `session/close`.
3392 #[must_use]
3393 pub fn close(mut self, close: impl IntoOption<SessionCloseCapabilities>) -> Self {
3394 self.close = close.into_option();
3395 self
3396 }
3397
3398 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
3399 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
3400 /// these keys.
3401 ///
3402 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
3403 #[must_use]
3404 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3405 self.meta = meta.into_option();
3406 self
3407 }
3408}
3409
3410/// Capabilities for the `session/list` method.
3411///
3412/// By supplying `{}` it means that the agent supports listing of sessions.
3413#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3414#[non_exhaustive]
3415pub struct SessionListCapabilities {
3416 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
3417 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
3418 /// these keys.
3419 ///
3420 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
3421 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
3422 pub meta: Option<Meta>,
3423}
3424
3425impl SessionListCapabilities {
3426 #[must_use]
3427 pub fn new() -> Self {
3428 Self::default()
3429 }
3430 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
3431 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
3432 /// these keys.
3433 ///
3434 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
3435 #[must_use]
3436 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3437 self.meta = meta.into_option();
3438 self
3439 }
3440}
3441
3442/// **UNSTABLE**
3443///
3444/// This capability is not part of the spec yet, and may be removed or changed at any point.
3445///
3446/// Capabilities for the `session/fork` method.
3447///
3448/// By supplying `{}` it means that the agent supports forking of sessions.
3449#[cfg(feature = "unstable_session_fork")]
3450#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3451#[non_exhaustive]
3452pub struct SessionForkCapabilities {
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(skip_serializing_if = "Option::is_none", rename = "_meta")]
3459 pub meta: Option<Meta>,
3460}
3461
3462#[cfg(feature = "unstable_session_fork")]
3463impl SessionForkCapabilities {
3464 #[must_use]
3465 pub fn new() -> Self {
3466 Self::default()
3467 }
3468
3469 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
3470 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
3471 /// these keys.
3472 ///
3473 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
3474 #[must_use]
3475 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3476 self.meta = meta.into_option();
3477 self
3478 }
3479}
3480
3481/// **UNSTABLE**
3482///
3483/// This capability is not part of the spec yet, and may be removed or changed at any point.
3484///
3485/// Capabilities for the `session/resume` method.
3486///
3487/// By supplying `{}` it means that the agent supports resuming of sessions.
3488#[cfg(feature = "unstable_session_resume")]
3489#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3490#[non_exhaustive]
3491pub struct SessionResumeCapabilities {
3492 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
3493 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
3494 /// these keys.
3495 ///
3496 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
3497 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
3498 pub meta: Option<Meta>,
3499}
3500
3501#[cfg(feature = "unstable_session_resume")]
3502impl SessionResumeCapabilities {
3503 #[must_use]
3504 pub fn new() -> Self {
3505 Self::default()
3506 }
3507
3508 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
3509 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
3510 /// these keys.
3511 ///
3512 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
3513 #[must_use]
3514 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3515 self.meta = meta.into_option();
3516 self
3517 }
3518}
3519
3520/// **UNSTABLE**
3521///
3522/// This capability is not part of the spec yet, and may be removed or changed at any point.
3523///
3524/// Capabilities for the `session/close` method.
3525///
3526/// By supplying `{}` it means that the agent supports closing of sessions.
3527#[cfg(feature = "unstable_session_close")]
3528#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3529#[non_exhaustive]
3530pub struct SessionCloseCapabilities {
3531 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
3532 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
3533 /// these keys.
3534 ///
3535 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
3536 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
3537 pub meta: Option<Meta>,
3538}
3539
3540#[cfg(feature = "unstable_session_close")]
3541impl SessionCloseCapabilities {
3542 #[must_use]
3543 pub fn new() -> Self {
3544 Self::default()
3545 }
3546
3547 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
3548 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
3549 /// these keys.
3550 ///
3551 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
3552 #[must_use]
3553 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3554 self.meta = meta.into_option();
3555 self
3556 }
3557}
3558
3559/// Prompt capabilities supported by the agent in `session/prompt` requests.
3560///
3561/// Baseline agent functionality requires support for [`ContentBlock::Text`]
3562/// and [`ContentBlock::ResourceLink`] in prompt requests.
3563///
3564/// Other variants must be explicitly opted in to.
3565/// Capabilities for different types of content in prompt requests.
3566///
3567/// Indicates which content types beyond the baseline (text and resource links)
3568/// the agent can process.
3569///
3570/// See protocol docs: [Prompt Capabilities](https://agentclientprotocol.com/protocol/initialization#prompt-capabilities)
3571#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3572#[serde(rename_all = "camelCase")]
3573#[non_exhaustive]
3574pub struct PromptCapabilities {
3575 /// Agent supports [`ContentBlock::Image`].
3576 #[serde(default)]
3577 pub image: bool,
3578 /// Agent supports [`ContentBlock::Audio`].
3579 #[serde(default)]
3580 pub audio: bool,
3581 /// Agent supports embedded context in `session/prompt` requests.
3582 ///
3583 /// When enabled, the Client is allowed to include [`ContentBlock::Resource`]
3584 /// in prompt requests for pieces of context that are referenced in the message.
3585 #[serde(default)]
3586 pub embedded_context: bool,
3587 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
3588 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
3589 /// these keys.
3590 ///
3591 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
3592 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
3593 pub meta: Option<Meta>,
3594}
3595
3596impl PromptCapabilities {
3597 #[must_use]
3598 pub fn new() -> Self {
3599 Self::default()
3600 }
3601
3602 /// Agent supports [`ContentBlock::Image`].
3603 #[must_use]
3604 pub fn image(mut self, image: bool) -> Self {
3605 self.image = image;
3606 self
3607 }
3608
3609 /// Agent supports [`ContentBlock::Audio`].
3610 #[must_use]
3611 pub fn audio(mut self, audio: bool) -> Self {
3612 self.audio = audio;
3613 self
3614 }
3615
3616 /// Agent supports embedded context in `session/prompt` requests.
3617 ///
3618 /// When enabled, the Client is allowed to include [`ContentBlock::Resource`]
3619 /// in prompt requests for pieces of context that are referenced in the message.
3620 #[must_use]
3621 pub fn embedded_context(mut self, embedded_context: bool) -> Self {
3622 self.embedded_context = embedded_context;
3623 self
3624 }
3625
3626 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
3627 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
3628 /// these keys.
3629 ///
3630 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
3631 #[must_use]
3632 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3633 self.meta = meta.into_option();
3634 self
3635 }
3636}
3637
3638/// MCP capabilities supported by the agent
3639#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
3640#[serde(rename_all = "camelCase")]
3641#[non_exhaustive]
3642pub struct McpCapabilities {
3643 /// Agent supports [`McpServer::Http`].
3644 #[serde(default)]
3645 pub http: bool,
3646 /// Agent supports [`McpServer::Sse`].
3647 #[serde(default)]
3648 pub sse: bool,
3649 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
3650 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
3651 /// these keys.
3652 ///
3653 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
3654 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
3655 pub meta: Option<Meta>,
3656}
3657
3658impl McpCapabilities {
3659 #[must_use]
3660 pub fn new() -> Self {
3661 Self::default()
3662 }
3663
3664 /// Agent supports [`McpServer::Http`].
3665 #[must_use]
3666 pub fn http(mut self, http: bool) -> Self {
3667 self.http = http;
3668 self
3669 }
3670
3671 /// Agent supports [`McpServer::Sse`].
3672 #[must_use]
3673 pub fn sse(mut self, sse: bool) -> Self {
3674 self.sse = sse;
3675 self
3676 }
3677
3678 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
3679 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
3680 /// these keys.
3681 ///
3682 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
3683 #[must_use]
3684 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
3685 self.meta = meta.into_option();
3686 self
3687 }
3688}
3689
3690// Method schema
3691
3692/// Names of all methods that agents handle.
3693///
3694/// Provides a centralized definition of method names used in the protocol.
3695#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
3696#[non_exhaustive]
3697pub struct AgentMethodNames {
3698 /// Method for initializing the connection.
3699 pub initialize: &'static str,
3700 /// Method for authenticating with the agent.
3701 pub authenticate: &'static str,
3702 /// Method for creating a new session.
3703 pub session_new: &'static str,
3704 /// Method for loading an existing session.
3705 pub session_load: &'static str,
3706 /// Method for setting the mode for a session.
3707 pub session_set_mode: &'static str,
3708 /// Method for setting a configuration option for a session.
3709 pub session_set_config_option: &'static str,
3710 /// Method for sending a prompt to the agent.
3711 pub session_prompt: &'static str,
3712 /// Notification for cancelling operations.
3713 pub session_cancel: &'static str,
3714 /// Method for selecting a model for a given session.
3715 #[cfg(feature = "unstable_session_model")]
3716 pub session_set_model: &'static str,
3717 /// Method for listing existing sessions.
3718 pub session_list: &'static str,
3719 /// Method for forking an existing session.
3720 #[cfg(feature = "unstable_session_fork")]
3721 pub session_fork: &'static str,
3722 /// Method for resuming an existing session.
3723 #[cfg(feature = "unstable_session_resume")]
3724 pub session_resume: &'static str,
3725 /// Method for closing an active session.
3726 #[cfg(feature = "unstable_session_close")]
3727 pub session_close: &'static str,
3728 /// Method for logging out of an authenticated session.
3729 #[cfg(feature = "unstable_logout")]
3730 pub logout: &'static str,
3731}
3732
3733/// Constant containing all agent method names.
3734pub const AGENT_METHOD_NAMES: AgentMethodNames = AgentMethodNames {
3735 initialize: INITIALIZE_METHOD_NAME,
3736 authenticate: AUTHENTICATE_METHOD_NAME,
3737 session_new: SESSION_NEW_METHOD_NAME,
3738 session_load: SESSION_LOAD_METHOD_NAME,
3739 session_set_mode: SESSION_SET_MODE_METHOD_NAME,
3740 session_set_config_option: SESSION_SET_CONFIG_OPTION_METHOD_NAME,
3741 session_prompt: SESSION_PROMPT_METHOD_NAME,
3742 session_cancel: SESSION_CANCEL_METHOD_NAME,
3743 #[cfg(feature = "unstable_session_model")]
3744 session_set_model: SESSION_SET_MODEL_METHOD_NAME,
3745 session_list: SESSION_LIST_METHOD_NAME,
3746 #[cfg(feature = "unstable_session_fork")]
3747 session_fork: SESSION_FORK_METHOD_NAME,
3748 #[cfg(feature = "unstable_session_resume")]
3749 session_resume: SESSION_RESUME_METHOD_NAME,
3750 #[cfg(feature = "unstable_session_close")]
3751 session_close: SESSION_CLOSE_METHOD_NAME,
3752 #[cfg(feature = "unstable_logout")]
3753 logout: LOGOUT_METHOD_NAME,
3754};
3755
3756/// Method name for the initialize request.
3757pub(crate) const INITIALIZE_METHOD_NAME: &str = "initialize";
3758/// Method name for the authenticate request.
3759pub(crate) const AUTHENTICATE_METHOD_NAME: &str = "authenticate";
3760/// Method name for creating a new session.
3761pub(crate) const SESSION_NEW_METHOD_NAME: &str = "session/new";
3762/// Method name for loading an existing session.
3763pub(crate) const SESSION_LOAD_METHOD_NAME: &str = "session/load";
3764/// Method name for setting the mode for a session.
3765pub(crate) const SESSION_SET_MODE_METHOD_NAME: &str = "session/set_mode";
3766/// Method name for setting a configuration option for a session.
3767pub(crate) const SESSION_SET_CONFIG_OPTION_METHOD_NAME: &str = "session/set_config_option";
3768/// Method name for sending a prompt.
3769pub(crate) const SESSION_PROMPT_METHOD_NAME: &str = "session/prompt";
3770/// Method name for the cancel notification.
3771pub(crate) const SESSION_CANCEL_METHOD_NAME: &str = "session/cancel";
3772/// Method name for selecting a model for a given session.
3773#[cfg(feature = "unstable_session_model")]
3774pub(crate) const SESSION_SET_MODEL_METHOD_NAME: &str = "session/set_model";
3775/// Method name for listing existing sessions.
3776pub(crate) const SESSION_LIST_METHOD_NAME: &str = "session/list";
3777/// Method name for forking an existing session.
3778#[cfg(feature = "unstable_session_fork")]
3779pub(crate) const SESSION_FORK_METHOD_NAME: &str = "session/fork";
3780/// Method name for resuming an existing session.
3781#[cfg(feature = "unstable_session_resume")]
3782pub(crate) const SESSION_RESUME_METHOD_NAME: &str = "session/resume";
3783/// Method name for closing an active session.
3784#[cfg(feature = "unstable_session_close")]
3785pub(crate) const SESSION_CLOSE_METHOD_NAME: &str = "session/close";
3786/// Method name for logging out of an authenticated session.
3787#[cfg(feature = "unstable_logout")]
3788pub(crate) const LOGOUT_METHOD_NAME: &str = "logout";
3789
3790/// All possible requests that a client can send to an agent.
3791///
3792/// This enum is used internally for routing RPC requests. You typically won't need
3793/// to use this directly - instead, use the methods on the [`Agent`] trait.
3794///
3795/// This enum encompasses all method calls from client to agent.
3796#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
3797#[serde(untagged)]
3798#[schemars(inline)]
3799#[non_exhaustive]
3800#[allow(clippy::large_enum_variant)]
3801pub enum ClientRequest {
3802 /// Establishes the connection with a client and negotiates protocol capabilities.
3803 ///
3804 /// This method is called once at the beginning of the connection to:
3805 /// - Negotiate the protocol version to use
3806 /// - Exchange capability information between client and agent
3807 /// - Determine available authentication methods
3808 ///
3809 /// The agent should respond with its supported protocol version and capabilities.
3810 ///
3811 /// See protocol docs: [Initialization](https://agentclientprotocol.com/protocol/initialization)
3812 InitializeRequest(InitializeRequest),
3813 /// Authenticates the client using the specified authentication method.
3814 ///
3815 /// Called when the agent requires authentication before allowing session creation.
3816 /// The client provides the authentication method ID that was advertised during initialization.
3817 ///
3818 /// After successful authentication, the client can proceed to create sessions with
3819 /// `new_session` without receiving an `auth_required` error.
3820 ///
3821 /// See protocol docs: [Initialization](https://agentclientprotocol.com/protocol/initialization)
3822 AuthenticateRequest(AuthenticateRequest),
3823 /// **UNSTABLE**
3824 ///
3825 /// This capability is not part of the spec yet, and may be removed or changed at any point.
3826 ///
3827 /// Logs out of the current authenticated state.
3828 ///
3829 /// After a successful logout, all new sessions will require authentication.
3830 /// There is no guarantee about the behavior of already running sessions.
3831 #[cfg(feature = "unstable_logout")]
3832 LogoutRequest(LogoutRequest),
3833 /// Creates a new conversation session with the agent.
3834 ///
3835 /// Sessions represent independent conversation contexts with their own history and state.
3836 ///
3837 /// The agent should:
3838 /// - Create a new session context
3839 /// - Connect to any specified MCP servers
3840 /// - Return a unique session ID for future requests
3841 ///
3842 /// May return an `auth_required` error if the agent requires authentication.
3843 ///
3844 /// See protocol docs: [Session Setup](https://agentclientprotocol.com/protocol/session-setup)
3845 NewSessionRequest(NewSessionRequest),
3846 /// Loads an existing session to resume a previous conversation.
3847 ///
3848 /// This method is only available if the agent advertises the `loadSession` capability.
3849 ///
3850 /// The agent should:
3851 /// - Restore the session context and conversation history
3852 /// - Connect to the specified MCP servers
3853 /// - Stream the entire conversation history back to the client via notifications
3854 ///
3855 /// See protocol docs: [Loading Sessions](https://agentclientprotocol.com/protocol/session-setup#loading-sessions)
3856 LoadSessionRequest(LoadSessionRequest),
3857 /// Lists existing sessions known to the agent.
3858 ///
3859 /// This method is only available if the agent advertises the `sessionCapabilities.list` capability.
3860 ///
3861 /// The agent should return metadata about sessions with optional filtering and pagination support.
3862 ListSessionsRequest(ListSessionsRequest),
3863 #[cfg(feature = "unstable_session_fork")]
3864 /// **UNSTABLE**
3865 ///
3866 /// This capability is not part of the spec yet, and may be removed or changed at any point.
3867 ///
3868 /// Forks an existing session to create a new independent session.
3869 ///
3870 /// This method is only available if the agent advertises the `session.fork` capability.
3871 ///
3872 /// The agent should create a new session with the same conversation context as the
3873 /// original, allowing operations like generating summaries without affecting the
3874 /// original session's history.
3875 ForkSessionRequest(ForkSessionRequest),
3876 #[cfg(feature = "unstable_session_resume")]
3877 /// **UNSTABLE**
3878 ///
3879 /// This capability is not part of the spec yet, and may be removed or changed at any point.
3880 ///
3881 /// Resumes an existing session without returning previous messages.
3882 ///
3883 /// This method is only available if the agent advertises the `session.resume` capability.
3884 ///
3885 /// The agent should resume the session context, allowing the conversation to continue
3886 /// without replaying the message history (unlike `session/load`).
3887 ResumeSessionRequest(ResumeSessionRequest),
3888 #[cfg(feature = "unstable_session_close")]
3889 /// **UNSTABLE**
3890 ///
3891 /// This capability is not part of the spec yet, and may be removed or changed at any point.
3892 ///
3893 /// Closes an active session and frees up any resources associated with it.
3894 ///
3895 /// This method is only available if the agent advertises the `session.close` capability.
3896 ///
3897 /// The agent must cancel any ongoing work (as if `session/cancel` was called)
3898 /// and then free up any resources associated with the session.
3899 CloseSessionRequest(CloseSessionRequest),
3900 /// Sets the current mode for a session.
3901 ///
3902 /// Allows switching between different agent modes (e.g., "ask", "architect", "code")
3903 /// that affect system prompts, tool availability, and permission behaviors.
3904 ///
3905 /// The mode must be one of the modes advertised in `availableModes` during session
3906 /// creation or loading. Agents may also change modes autonomously and notify the
3907 /// client via `current_mode_update` notifications.
3908 ///
3909 /// This method can be called at any time during a session, whether the Agent is
3910 /// idle or actively generating a response.
3911 ///
3912 /// See protocol docs: [Session Modes](https://agentclientprotocol.com/protocol/session-modes)
3913 SetSessionModeRequest(SetSessionModeRequest),
3914 /// Sets the current value for a session configuration option.
3915 SetSessionConfigOptionRequest(SetSessionConfigOptionRequest),
3916 /// Processes a user prompt within a session.
3917 ///
3918 /// This method handles the whole lifecycle of a prompt:
3919 /// - Receives user messages with optional context (files, images, etc.)
3920 /// - Processes the prompt using language models
3921 /// - Reports language model content and tool calls to the Clients
3922 /// - Requests permission to run tools
3923 /// - Executes any requested tool calls
3924 /// - Returns when the turn is complete with a stop reason
3925 ///
3926 /// See protocol docs: [Prompt Turn](https://agentclientprotocol.com/protocol/prompt-turn)
3927 PromptRequest(PromptRequest),
3928 #[cfg(feature = "unstable_session_model")]
3929 /// **UNSTABLE**
3930 ///
3931 /// This capability is not part of the spec yet, and may be removed or changed at any point.
3932 ///
3933 /// Select a model for a given session.
3934 SetSessionModelRequest(SetSessionModelRequest),
3935 /// Handles extension method requests from the client.
3936 ///
3937 /// Extension methods provide a way to add custom functionality while maintaining
3938 /// protocol compatibility.
3939 ///
3940 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
3941 ExtMethodRequest(ExtRequest),
3942}
3943
3944impl ClientRequest {
3945 /// Returns the corresponding method name of the request.
3946 #[must_use]
3947 pub fn method(&self) -> &str {
3948 match self {
3949 Self::InitializeRequest(_) => AGENT_METHOD_NAMES.initialize,
3950 Self::AuthenticateRequest(_) => AGENT_METHOD_NAMES.authenticate,
3951 #[cfg(feature = "unstable_logout")]
3952 Self::LogoutRequest(_) => AGENT_METHOD_NAMES.logout,
3953 Self::NewSessionRequest(_) => AGENT_METHOD_NAMES.session_new,
3954 Self::LoadSessionRequest(_) => AGENT_METHOD_NAMES.session_load,
3955 Self::ListSessionsRequest(_) => AGENT_METHOD_NAMES.session_list,
3956 #[cfg(feature = "unstable_session_fork")]
3957 Self::ForkSessionRequest(_) => AGENT_METHOD_NAMES.session_fork,
3958 #[cfg(feature = "unstable_session_resume")]
3959 Self::ResumeSessionRequest(_) => AGENT_METHOD_NAMES.session_resume,
3960 #[cfg(feature = "unstable_session_close")]
3961 Self::CloseSessionRequest(_) => AGENT_METHOD_NAMES.session_close,
3962 Self::SetSessionModeRequest(_) => AGENT_METHOD_NAMES.session_set_mode,
3963 Self::SetSessionConfigOptionRequest(_) => AGENT_METHOD_NAMES.session_set_config_option,
3964 Self::PromptRequest(_) => AGENT_METHOD_NAMES.session_prompt,
3965 #[cfg(feature = "unstable_session_model")]
3966 Self::SetSessionModelRequest(_) => AGENT_METHOD_NAMES.session_set_model,
3967 Self::ExtMethodRequest(ext_request) => &ext_request.method,
3968 }
3969 }
3970}
3971
3972/// All possible responses that an agent can send to a client.
3973///
3974/// This enum is used internally for routing RPC responses. You typically won't need
3975/// to use this directly - the responses are handled automatically by the connection.
3976///
3977/// These are responses to the corresponding `ClientRequest` variants.
3978#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
3979#[serde(untagged)]
3980#[schemars(inline)]
3981#[non_exhaustive]
3982#[allow(clippy::large_enum_variant)]
3983pub enum AgentResponse {
3984 InitializeResponse(InitializeResponse),
3985 AuthenticateResponse(#[serde(default)] AuthenticateResponse),
3986 #[cfg(feature = "unstable_logout")]
3987 LogoutResponse(#[serde(default)] LogoutResponse),
3988 NewSessionResponse(NewSessionResponse),
3989 LoadSessionResponse(#[serde(default)] LoadSessionResponse),
3990 ListSessionsResponse(ListSessionsResponse),
3991 #[cfg(feature = "unstable_session_fork")]
3992 ForkSessionResponse(ForkSessionResponse),
3993 #[cfg(feature = "unstable_session_resume")]
3994 ResumeSessionResponse(#[serde(default)] ResumeSessionResponse),
3995 #[cfg(feature = "unstable_session_close")]
3996 CloseSessionResponse(#[serde(default)] CloseSessionResponse),
3997 SetSessionModeResponse(#[serde(default)] SetSessionModeResponse),
3998 SetSessionConfigOptionResponse(SetSessionConfigOptionResponse),
3999 PromptResponse(PromptResponse),
4000 #[cfg(feature = "unstable_session_model")]
4001 SetSessionModelResponse(#[serde(default)] SetSessionModelResponse),
4002 ExtMethodResponse(ExtResponse),
4003}
4004
4005/// All possible notifications that a client can send to an agent.
4006///
4007/// This enum is used internally for routing RPC notifications. You typically won't need
4008/// to use this directly - use the notification methods on the [`Agent`] trait instead.
4009///
4010/// Notifications do not expect a response.
4011#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
4012#[serde(untagged)]
4013#[schemars(inline)]
4014#[non_exhaustive]
4015pub enum ClientNotification {
4016 /// Cancels ongoing operations for a session.
4017 ///
4018 /// This is a notification sent by the client to cancel an ongoing prompt turn.
4019 ///
4020 /// Upon receiving this notification, the Agent SHOULD:
4021 /// - Stop all language model requests as soon as possible
4022 /// - Abort all tool call invocations in progress
4023 /// - Send any pending `session/update` notifications
4024 /// - Respond to the original `session/prompt` request with `StopReason::Cancelled`
4025 ///
4026 /// See protocol docs: [Cancellation](https://agentclientprotocol.com/protocol/prompt-turn#cancellation)
4027 CancelNotification(CancelNotification),
4028 /// Handles extension notifications from the client.
4029 ///
4030 /// Extension notifications provide a way to send one-way messages for custom functionality
4031 /// while maintaining protocol compatibility.
4032 ///
4033 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
4034 ExtNotification(ExtNotification),
4035}
4036
4037impl ClientNotification {
4038 /// Returns the corresponding method name of the notification.
4039 #[must_use]
4040 pub fn method(&self) -> &str {
4041 match self {
4042 Self::CancelNotification(_) => AGENT_METHOD_NAMES.session_cancel,
4043 Self::ExtNotification(ext_notification) => &ext_notification.method,
4044 }
4045 }
4046}
4047
4048/// Notification to cancel ongoing operations for a session.
4049///
4050/// See protocol docs: [Cancellation](https://agentclientprotocol.com/protocol/prompt-turn#cancellation)
4051#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
4052#[schemars(extend("x-side" = "agent", "x-method" = SESSION_CANCEL_METHOD_NAME))]
4053#[serde(rename_all = "camelCase")]
4054#[non_exhaustive]
4055pub struct CancelNotification {
4056 /// The ID of the session to cancel operations for.
4057 pub session_id: SessionId,
4058 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
4059 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
4060 /// these keys.
4061 ///
4062 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
4063 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
4064 pub meta: Option<Meta>,
4065}
4066
4067impl CancelNotification {
4068 #[must_use]
4069 pub fn new(session_id: impl Into<SessionId>) -> Self {
4070 Self {
4071 session_id: session_id.into(),
4072 meta: None,
4073 }
4074 }
4075
4076 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
4077 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
4078 /// these keys.
4079 ///
4080 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
4081 #[must_use]
4082 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
4083 self.meta = meta.into_option();
4084 self
4085 }
4086}
4087
4088#[cfg(test)]
4089mod test_serialization {
4090 use super::*;
4091 use serde_json::json;
4092
4093 #[test]
4094 fn test_mcp_server_stdio_serialization() {
4095 let server = McpServer::Stdio(
4096 McpServerStdio::new("test-server", "/usr/bin/server")
4097 .args(vec!["--port".to_string(), "3000".to_string()])
4098 .env(vec![EnvVariable::new("API_KEY", "secret123")]),
4099 );
4100
4101 let json = serde_json::to_value(&server).unwrap();
4102 assert_eq!(
4103 json,
4104 json!({
4105 "name": "test-server",
4106 "command": "/usr/bin/server",
4107 "args": ["--port", "3000"],
4108 "env": [
4109 {
4110 "name": "API_KEY",
4111 "value": "secret123"
4112 }
4113 ]
4114 })
4115 );
4116
4117 let deserialized: McpServer = serde_json::from_value(json).unwrap();
4118 match deserialized {
4119 McpServer::Stdio(McpServerStdio {
4120 name,
4121 command,
4122 args,
4123 env,
4124 meta: _,
4125 }) => {
4126 assert_eq!(name, "test-server");
4127 assert_eq!(command, PathBuf::from("/usr/bin/server"));
4128 assert_eq!(args, vec!["--port", "3000"]);
4129 assert_eq!(env.len(), 1);
4130 assert_eq!(env[0].name, "API_KEY");
4131 assert_eq!(env[0].value, "secret123");
4132 }
4133 _ => panic!("Expected Stdio variant"),
4134 }
4135 }
4136
4137 #[test]
4138 fn test_mcp_server_http_serialization() {
4139 let server = McpServer::Http(
4140 McpServerHttp::new("http-server", "https://api.example.com").headers(vec![
4141 HttpHeader::new("Authorization", "Bearer token123"),
4142 HttpHeader::new("Content-Type", "application/json"),
4143 ]),
4144 );
4145
4146 let json = serde_json::to_value(&server).unwrap();
4147 assert_eq!(
4148 json,
4149 json!({
4150 "type": "http",
4151 "name": "http-server",
4152 "url": "https://api.example.com",
4153 "headers": [
4154 {
4155 "name": "Authorization",
4156 "value": "Bearer token123"
4157 },
4158 {
4159 "name": "Content-Type",
4160 "value": "application/json"
4161 }
4162 ]
4163 })
4164 );
4165
4166 let deserialized: McpServer = serde_json::from_value(json).unwrap();
4167 match deserialized {
4168 McpServer::Http(McpServerHttp {
4169 name,
4170 url,
4171 headers,
4172 meta: _,
4173 }) => {
4174 assert_eq!(name, "http-server");
4175 assert_eq!(url, "https://api.example.com");
4176 assert_eq!(headers.len(), 2);
4177 assert_eq!(headers[0].name, "Authorization");
4178 assert_eq!(headers[0].value, "Bearer token123");
4179 assert_eq!(headers[1].name, "Content-Type");
4180 assert_eq!(headers[1].value, "application/json");
4181 }
4182 _ => panic!("Expected Http variant"),
4183 }
4184 }
4185
4186 #[test]
4187 fn test_mcp_server_sse_serialization() {
4188 let server = McpServer::Sse(
4189 McpServerSse::new("sse-server", "https://sse.example.com/events")
4190 .headers(vec![HttpHeader::new("X-API-Key", "apikey456")]),
4191 );
4192
4193 let json = serde_json::to_value(&server).unwrap();
4194 assert_eq!(
4195 json,
4196 json!({
4197 "type": "sse",
4198 "name": "sse-server",
4199 "url": "https://sse.example.com/events",
4200 "headers": [
4201 {
4202 "name": "X-API-Key",
4203 "value": "apikey456"
4204 }
4205 ]
4206 })
4207 );
4208
4209 let deserialized: McpServer = serde_json::from_value(json).unwrap();
4210 match deserialized {
4211 McpServer::Sse(McpServerSse {
4212 name,
4213 url,
4214 headers,
4215 meta: _,
4216 }) => {
4217 assert_eq!(name, "sse-server");
4218 assert_eq!(url, "https://sse.example.com/events");
4219 assert_eq!(headers.len(), 1);
4220 assert_eq!(headers[0].name, "X-API-Key");
4221 assert_eq!(headers[0].value, "apikey456");
4222 }
4223 _ => panic!("Expected Sse variant"),
4224 }
4225 }
4226
4227 #[test]
4228 fn test_session_config_option_category_known_variants() {
4229 // Test serialization of known variants
4230 assert_eq!(
4231 serde_json::to_value(&SessionConfigOptionCategory::Mode).unwrap(),
4232 json!("mode")
4233 );
4234 assert_eq!(
4235 serde_json::to_value(&SessionConfigOptionCategory::Model).unwrap(),
4236 json!("model")
4237 );
4238 assert_eq!(
4239 serde_json::to_value(&SessionConfigOptionCategory::ThoughtLevel).unwrap(),
4240 json!("thought_level")
4241 );
4242
4243 // Test deserialization of known variants
4244 assert_eq!(
4245 serde_json::from_str::<SessionConfigOptionCategory>("\"mode\"").unwrap(),
4246 SessionConfigOptionCategory::Mode
4247 );
4248 assert_eq!(
4249 serde_json::from_str::<SessionConfigOptionCategory>("\"model\"").unwrap(),
4250 SessionConfigOptionCategory::Model
4251 );
4252 assert_eq!(
4253 serde_json::from_str::<SessionConfigOptionCategory>("\"thought_level\"").unwrap(),
4254 SessionConfigOptionCategory::ThoughtLevel
4255 );
4256 }
4257
4258 #[test]
4259 fn test_session_config_option_category_unknown_variants() {
4260 // Test that unknown strings are captured in Other variant
4261 let unknown: SessionConfigOptionCategory =
4262 serde_json::from_str("\"some_future_category\"").unwrap();
4263 assert_eq!(
4264 unknown,
4265 SessionConfigOptionCategory::Other("some_future_category".to_string())
4266 );
4267
4268 // Test round-trip of unknown category
4269 let json = serde_json::to_value(&unknown).unwrap();
4270 assert_eq!(json, json!("some_future_category"));
4271 }
4272
4273 #[test]
4274 fn test_session_config_option_category_custom_categories() {
4275 // Category names beginning with `_` are free for custom use
4276 let custom: SessionConfigOptionCategory =
4277 serde_json::from_str("\"_my_custom_category\"").unwrap();
4278 assert_eq!(
4279 custom,
4280 SessionConfigOptionCategory::Other("_my_custom_category".to_string())
4281 );
4282
4283 // Test round-trip preserves the custom category name
4284 let json = serde_json::to_value(&custom).unwrap();
4285 assert_eq!(json, json!("_my_custom_category"));
4286
4287 // Deserialize back and verify
4288 let deserialized: SessionConfigOptionCategory = serde_json::from_value(json).unwrap();
4289 assert_eq!(
4290 deserialized,
4291 SessionConfigOptionCategory::Other("_my_custom_category".to_string()),
4292 );
4293 }
4294
4295 #[test]
4296 fn test_auth_method_agent_serialization() {
4297 let method = AuthMethod::Agent(AuthMethodAgent::new("default-auth", "Default Auth"));
4298
4299 let json = serde_json::to_value(&method).unwrap();
4300 assert_eq!(
4301 json,
4302 json!({
4303 "id": "default-auth",
4304 "name": "Default Auth"
4305 })
4306 );
4307 // description should be omitted when None
4308 assert!(!json.as_object().unwrap().contains_key("description"));
4309 // Agent variant should not emit a `type` field (backward compat)
4310 assert!(!json.as_object().unwrap().contains_key("type"));
4311
4312 let deserialized: AuthMethod = serde_json::from_value(json).unwrap();
4313 match deserialized {
4314 AuthMethod::Agent(AuthMethodAgent { id, name, .. }) => {
4315 assert_eq!(id.0.as_ref(), "default-auth");
4316 assert_eq!(name, "Default Auth");
4317 }
4318 #[cfg(feature = "unstable_auth_methods")]
4319 _ => panic!("Expected Agent variant"),
4320 }
4321 }
4322
4323 #[test]
4324 fn test_auth_method_explicit_agent_deserialization() {
4325 // An explicit `"type": "agent"` should also deserialize to Agent
4326 let json = json!({
4327 "id": "agent-auth",
4328 "name": "Agent Auth",
4329 "type": "agent"
4330 });
4331
4332 let deserialized: AuthMethod = serde_json::from_value(json).unwrap();
4333 assert!(matches!(deserialized, AuthMethod::Agent(_)));
4334 }
4335
4336 #[cfg(feature = "unstable_auth_methods")]
4337 #[test]
4338 fn test_auth_method_env_var_serialization() {
4339 let method = AuthMethod::EnvVar(AuthMethodEnvVar::new(
4340 "api-key",
4341 "API Key",
4342 vec![AuthEnvVar::new("API_KEY")],
4343 ));
4344
4345 let json = serde_json::to_value(&method).unwrap();
4346 assert_eq!(
4347 json,
4348 json!({
4349 "id": "api-key",
4350 "name": "API Key",
4351 "type": "env_var",
4352 "vars": [{"name": "API_KEY"}]
4353 })
4354 );
4355 // secret defaults to true and should be omitted; optional defaults to false and should be omitted
4356 assert!(!json["vars"][0].as_object().unwrap().contains_key("secret"));
4357 assert!(
4358 !json["vars"][0]
4359 .as_object()
4360 .unwrap()
4361 .contains_key("optional")
4362 );
4363
4364 let deserialized: AuthMethod = serde_json::from_value(json).unwrap();
4365 match deserialized {
4366 AuthMethod::EnvVar(AuthMethodEnvVar {
4367 id,
4368 name: method_name,
4369 vars,
4370 link,
4371 ..
4372 }) => {
4373 assert_eq!(id.0.as_ref(), "api-key");
4374 assert_eq!(method_name, "API Key");
4375 assert_eq!(vars.len(), 1);
4376 assert_eq!(vars[0].name, "API_KEY");
4377 assert!(vars[0].secret);
4378 assert!(!vars[0].optional);
4379 assert!(link.is_none());
4380 }
4381 _ => panic!("Expected EnvVar variant"),
4382 }
4383 }
4384
4385 #[cfg(feature = "unstable_auth_methods")]
4386 #[test]
4387 fn test_auth_method_env_var_with_link_serialization() {
4388 let method = AuthMethod::EnvVar(
4389 AuthMethodEnvVar::new("api-key", "API Key", vec![AuthEnvVar::new("API_KEY")])
4390 .link("https://example.com/keys"),
4391 );
4392
4393 let json = serde_json::to_value(&method).unwrap();
4394 assert_eq!(
4395 json,
4396 json!({
4397 "id": "api-key",
4398 "name": "API Key",
4399 "type": "env_var",
4400 "vars": [{"name": "API_KEY"}],
4401 "link": "https://example.com/keys"
4402 })
4403 );
4404
4405 let deserialized: AuthMethod = serde_json::from_value(json).unwrap();
4406 match deserialized {
4407 AuthMethod::EnvVar(AuthMethodEnvVar { link, .. }) => {
4408 assert_eq!(link.as_deref(), Some("https://example.com/keys"));
4409 }
4410 _ => panic!("Expected EnvVar variant"),
4411 }
4412 }
4413
4414 #[cfg(feature = "unstable_auth_methods")]
4415 #[test]
4416 fn test_auth_method_env_var_multiple_vars() {
4417 let method = AuthMethod::EnvVar(AuthMethodEnvVar::new(
4418 "azure-openai",
4419 "Azure OpenAI",
4420 vec![
4421 AuthEnvVar::new("AZURE_OPENAI_API_KEY").label("API Key"),
4422 AuthEnvVar::new("AZURE_OPENAI_ENDPOINT")
4423 .label("Endpoint URL")
4424 .secret(false),
4425 AuthEnvVar::new("AZURE_OPENAI_API_VERSION")
4426 .label("API Version")
4427 .secret(false)
4428 .optional(true),
4429 ],
4430 ));
4431
4432 let json = serde_json::to_value(&method).unwrap();
4433 assert_eq!(
4434 json,
4435 json!({
4436 "id": "azure-openai",
4437 "name": "Azure OpenAI",
4438 "type": "env_var",
4439 "vars": [
4440 {"name": "AZURE_OPENAI_API_KEY", "label": "API Key"},
4441 {"name": "AZURE_OPENAI_ENDPOINT", "label": "Endpoint URL", "secret": false},
4442 {"name": "AZURE_OPENAI_API_VERSION", "label": "API Version", "secret": false, "optional": true}
4443 ]
4444 })
4445 );
4446
4447 let deserialized: AuthMethod = serde_json::from_value(json).unwrap();
4448 match deserialized {
4449 AuthMethod::EnvVar(AuthMethodEnvVar { vars, .. }) => {
4450 assert_eq!(vars.len(), 3);
4451 // First var: secret (default true), not optional (default false)
4452 assert_eq!(vars[0].name, "AZURE_OPENAI_API_KEY");
4453 assert_eq!(vars[0].label.as_deref(), Some("API Key"));
4454 assert!(vars[0].secret);
4455 assert!(!vars[0].optional);
4456 // Second var: not a secret, not optional
4457 assert_eq!(vars[1].name, "AZURE_OPENAI_ENDPOINT");
4458 assert!(!vars[1].secret);
4459 assert!(!vars[1].optional);
4460 // Third var: not a secret, optional
4461 assert_eq!(vars[2].name, "AZURE_OPENAI_API_VERSION");
4462 assert!(!vars[2].secret);
4463 assert!(vars[2].optional);
4464 }
4465 _ => panic!("Expected EnvVar variant"),
4466 }
4467 }
4468
4469 #[cfg(feature = "unstable_auth_methods")]
4470 #[test]
4471 fn test_auth_method_terminal_serialization() {
4472 let method = AuthMethod::Terminal(AuthMethodTerminal::new("tui-auth", "Terminal Auth"));
4473
4474 let json = serde_json::to_value(&method).unwrap();
4475 assert_eq!(
4476 json,
4477 json!({
4478 "id": "tui-auth",
4479 "name": "Terminal Auth",
4480 "type": "terminal"
4481 })
4482 );
4483 // args and env should be omitted when empty
4484 assert!(!json.as_object().unwrap().contains_key("args"));
4485 assert!(!json.as_object().unwrap().contains_key("env"));
4486
4487 let deserialized: AuthMethod = serde_json::from_value(json).unwrap();
4488 match deserialized {
4489 AuthMethod::Terminal(AuthMethodTerminal { args, env, .. }) => {
4490 assert!(args.is_empty());
4491 assert!(env.is_empty());
4492 }
4493 _ => panic!("Expected Terminal variant"),
4494 }
4495 }
4496
4497 #[cfg(feature = "unstable_auth_methods")]
4498 #[test]
4499 fn test_auth_method_terminal_with_args_and_env_serialization() {
4500 use std::collections::HashMap;
4501
4502 let mut env = HashMap::new();
4503 env.insert("TERM".to_string(), "xterm-256color".to_string());
4504
4505 let method = AuthMethod::Terminal(
4506 AuthMethodTerminal::new("tui-auth", "Terminal Auth")
4507 .args(vec!["--interactive".to_string(), "--color".to_string()])
4508 .env(env),
4509 );
4510
4511 let json = serde_json::to_value(&method).unwrap();
4512 assert_eq!(
4513 json,
4514 json!({
4515 "id": "tui-auth",
4516 "name": "Terminal Auth",
4517 "type": "terminal",
4518 "args": ["--interactive", "--color"],
4519 "env": {
4520 "TERM": "xterm-256color"
4521 }
4522 })
4523 );
4524
4525 let deserialized: AuthMethod = serde_json::from_value(json).unwrap();
4526 match deserialized {
4527 AuthMethod::Terminal(AuthMethodTerminal { args, env, .. }) => {
4528 assert_eq!(args, vec!["--interactive", "--color"]);
4529 assert_eq!(env.len(), 1);
4530 assert_eq!(env.get("TERM").unwrap(), "xterm-256color");
4531 }
4532 _ => panic!("Expected Terminal variant"),
4533 }
4534 }
4535
4536 #[cfg(feature = "unstable_boolean_config")]
4537 #[test]
4538 fn test_session_config_option_value_id_serialize() {
4539 let val = SessionConfigOptionValue::value_id("model-1");
4540 let json = serde_json::to_value(&val).unwrap();
4541 // ValueId omits the "type" field (it's the default)
4542 assert_eq!(json, json!({ "value": "model-1" }));
4543 assert!(!json.as_object().unwrap().contains_key("type"));
4544 }
4545
4546 #[cfg(feature = "unstable_boolean_config")]
4547 #[test]
4548 fn test_session_config_option_value_boolean_serialize() {
4549 let val = SessionConfigOptionValue::boolean(true);
4550 let json = serde_json::to_value(&val).unwrap();
4551 assert_eq!(json, json!({ "type": "boolean", "value": true }));
4552 }
4553
4554 #[cfg(feature = "unstable_boolean_config")]
4555 #[test]
4556 fn test_session_config_option_value_deserialize_no_type() {
4557 // Missing "type" should default to ValueId
4558 let json = json!({ "value": "model-1" });
4559 let val: SessionConfigOptionValue = serde_json::from_value(json).unwrap();
4560 assert_eq!(val, SessionConfigOptionValue::value_id("model-1"));
4561 assert_eq!(val.as_value_id().unwrap().to_string(), "model-1");
4562 }
4563
4564 #[cfg(feature = "unstable_boolean_config")]
4565 #[test]
4566 fn test_session_config_option_value_deserialize_boolean() {
4567 let json = json!({ "type": "boolean", "value": true });
4568 let val: SessionConfigOptionValue = serde_json::from_value(json).unwrap();
4569 assert_eq!(val, SessionConfigOptionValue::boolean(true));
4570 assert_eq!(val.as_bool(), Some(true));
4571 }
4572
4573 #[cfg(feature = "unstable_boolean_config")]
4574 #[test]
4575 fn test_session_config_option_value_deserialize_boolean_false() {
4576 let json = json!({ "type": "boolean", "value": false });
4577 let val: SessionConfigOptionValue = serde_json::from_value(json).unwrap();
4578 assert_eq!(val, SessionConfigOptionValue::boolean(false));
4579 assert_eq!(val.as_bool(), Some(false));
4580 }
4581
4582 #[cfg(feature = "unstable_boolean_config")]
4583 #[test]
4584 fn test_session_config_option_value_deserialize_unknown_type_with_string_value() {
4585 // Unknown type with a string value gracefully falls back to ValueId
4586 let json = json!({ "type": "text", "value": "freeform input" });
4587 let val: SessionConfigOptionValue = serde_json::from_value(json).unwrap();
4588 assert_eq!(val.as_value_id().unwrap().to_string(), "freeform input");
4589 }
4590
4591 #[cfg(feature = "unstable_boolean_config")]
4592 #[test]
4593 fn test_session_config_option_value_roundtrip_value_id() {
4594 let original = SessionConfigOptionValue::value_id("option-a");
4595 let json = serde_json::to_value(&original).unwrap();
4596 let roundtripped: SessionConfigOptionValue = serde_json::from_value(json).unwrap();
4597 assert_eq!(original, roundtripped);
4598 }
4599
4600 #[cfg(feature = "unstable_boolean_config")]
4601 #[test]
4602 fn test_session_config_option_value_roundtrip_boolean() {
4603 let original = SessionConfigOptionValue::boolean(false);
4604 let json = serde_json::to_value(&original).unwrap();
4605 let roundtripped: SessionConfigOptionValue = serde_json::from_value(json).unwrap();
4606 assert_eq!(original, roundtripped);
4607 }
4608
4609 #[cfg(feature = "unstable_boolean_config")]
4610 #[test]
4611 fn test_session_config_option_value_type_mismatch_boolean_with_string() {
4612 // type says "boolean" but value is a string — falls to untagged ValueId
4613 let json = json!({ "type": "boolean", "value": "not a bool" });
4614 let result = serde_json::from_value::<SessionConfigOptionValue>(json);
4615 // serde tries Boolean first (fails), then falls to untagged ValueId (succeeds)
4616 assert!(result.is_ok());
4617 assert_eq!(
4618 result.unwrap().as_value_id().unwrap().to_string(),
4619 "not a bool"
4620 );
4621 }
4622
4623 #[cfg(feature = "unstable_boolean_config")]
4624 #[test]
4625 fn test_session_config_option_value_from_impls() {
4626 let from_str: SessionConfigOptionValue = "model-1".into();
4627 assert_eq!(from_str.as_value_id().unwrap().to_string(), "model-1");
4628
4629 let from_id: SessionConfigOptionValue = SessionConfigValueId::new("model-2").into();
4630 assert_eq!(from_id.as_value_id().unwrap().to_string(), "model-2");
4631
4632 let from_bool: SessionConfigOptionValue = true.into();
4633 assert_eq!(from_bool.as_bool(), Some(true));
4634 }
4635
4636 #[cfg(feature = "unstable_boolean_config")]
4637 #[test]
4638 fn test_set_session_config_option_request_value_id() {
4639 let req = SetSessionConfigOptionRequest::new("sess_1", "model", "model-1");
4640 let json = serde_json::to_value(&req).unwrap();
4641 assert_eq!(
4642 json,
4643 json!({
4644 "sessionId": "sess_1",
4645 "configId": "model",
4646 "value": "model-1"
4647 })
4648 );
4649 // No "type" field for value_id
4650 assert!(!json.as_object().unwrap().contains_key("type"));
4651 }
4652
4653 #[cfg(feature = "unstable_boolean_config")]
4654 #[test]
4655 fn test_set_session_config_option_request_boolean() {
4656 let req = SetSessionConfigOptionRequest::new("sess_1", "brave_mode", true);
4657 let json = serde_json::to_value(&req).unwrap();
4658 assert_eq!(
4659 json,
4660 json!({
4661 "sessionId": "sess_1",
4662 "configId": "brave_mode",
4663 "type": "boolean",
4664 "value": true
4665 })
4666 );
4667 }
4668
4669 #[cfg(feature = "unstable_boolean_config")]
4670 #[test]
4671 fn test_set_session_config_option_request_deserialize_no_type() {
4672 // Backwards-compatible: no "type" field → value_id
4673 let json = json!({
4674 "sessionId": "sess_1",
4675 "configId": "model",
4676 "value": "model-1"
4677 });
4678 let req: SetSessionConfigOptionRequest = serde_json::from_value(json).unwrap();
4679 assert_eq!(req.session_id.to_string(), "sess_1");
4680 assert_eq!(req.config_id.to_string(), "model");
4681 assert_eq!(req.value.as_value_id().unwrap().to_string(), "model-1");
4682 }
4683
4684 #[cfg(feature = "unstable_boolean_config")]
4685 #[test]
4686 fn test_set_session_config_option_request_deserialize_boolean() {
4687 let json = json!({
4688 "sessionId": "sess_1",
4689 "configId": "brave_mode",
4690 "type": "boolean",
4691 "value": true
4692 });
4693 let req: SetSessionConfigOptionRequest = serde_json::from_value(json).unwrap();
4694 assert_eq!(req.value.as_bool(), Some(true));
4695 }
4696
4697 #[cfg(feature = "unstable_boolean_config")]
4698 #[test]
4699 fn test_set_session_config_option_request_roundtrip_value_id() {
4700 let original = SetSessionConfigOptionRequest::new("s", "c", "v");
4701 let json = serde_json::to_value(&original).unwrap();
4702 let roundtripped: SetSessionConfigOptionRequest = serde_json::from_value(json).unwrap();
4703 assert_eq!(original, roundtripped);
4704 }
4705
4706 #[cfg(feature = "unstable_boolean_config")]
4707 #[test]
4708 fn test_set_session_config_option_request_roundtrip_boolean() {
4709 let original = SetSessionConfigOptionRequest::new("s", "c", false);
4710 let json = serde_json::to_value(&original).unwrap();
4711 let roundtripped: SetSessionConfigOptionRequest = serde_json::from_value(json).unwrap();
4712 assert_eq!(original, roundtripped);
4713 }
4714
4715 #[cfg(feature = "unstable_boolean_config")]
4716 #[test]
4717 fn test_session_config_boolean_serialization() {
4718 let cfg = SessionConfigBoolean::new(true);
4719 let json = serde_json::to_value(&cfg).unwrap();
4720 assert_eq!(json, json!({ "currentValue": true }));
4721
4722 let deserialized: SessionConfigBoolean = serde_json::from_value(json).unwrap();
4723 assert!(deserialized.current_value);
4724 }
4725
4726 #[cfg(feature = "unstable_boolean_config")]
4727 #[test]
4728 fn test_session_config_option_boolean_variant() {
4729 let opt = SessionConfigOption::boolean("brave_mode", "Brave Mode", false)
4730 .description("Skip confirmation prompts");
4731 let json = serde_json::to_value(&opt).unwrap();
4732 assert_eq!(
4733 json,
4734 json!({
4735 "id": "brave_mode",
4736 "name": "Brave Mode",
4737 "description": "Skip confirmation prompts",
4738 "type": "boolean",
4739 "currentValue": false
4740 })
4741 );
4742
4743 let deserialized: SessionConfigOption = serde_json::from_value(json).unwrap();
4744 assert_eq!(deserialized.id.to_string(), "brave_mode");
4745 assert_eq!(deserialized.name, "Brave Mode");
4746 match deserialized.kind {
4747 SessionConfigKind::Boolean(ref b) => assert!(!b.current_value),
4748 _ => panic!("Expected Boolean kind"),
4749 }
4750 }
4751
4752 #[cfg(feature = "unstable_boolean_config")]
4753 #[test]
4754 fn test_session_config_option_select_still_works() {
4755 // Make sure existing select options are unaffected
4756 let opt = SessionConfigOption::select(
4757 "model",
4758 "Model",
4759 "model-1",
4760 vec![
4761 SessionConfigSelectOption::new("model-1", "Model 1"),
4762 SessionConfigSelectOption::new("model-2", "Model 2"),
4763 ],
4764 );
4765 let json = serde_json::to_value(&opt).unwrap();
4766 assert_eq!(json["type"], "select");
4767 assert_eq!(json["currentValue"], "model-1");
4768 assert_eq!(json["options"].as_array().unwrap().len(), 2);
4769
4770 let deserialized: SessionConfigOption = serde_json::from_value(json).unwrap();
4771 match deserialized.kind {
4772 SessionConfigKind::Select(ref s) => {
4773 assert_eq!(s.current_value.to_string(), "model-1");
4774 }
4775 _ => panic!("Expected Select kind"),
4776 }
4777 }
4778}