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