agent_client_protocol_schema/v1/client.rs
1//! Methods and notifications the client handles/receives.
2//!
3//! This module defines the Client trait and all associated types for implementing
4//! a client that interacts with AI coding agents via the Agent Client Protocol (ACP).
5
6use std::{path::PathBuf, sync::Arc};
7
8use derive_more::{Display, From};
9use schemars::JsonSchema;
10use serde::{Deserialize, Serialize};
11use serde_with::{DefaultOnError, VecSkipError, serde_as, skip_serializing_none};
12
13#[cfg(feature = "unstable_elicitation")]
14use super::{
15 CompleteElicitationNotification, CreateElicitationRequest, CreateElicitationResponse,
16 ElicitationCapabilities,
17};
18use crate::{IntoMaybeUndefined, IntoOption, MaybeUndefined, SkipListener};
19
20use super::{
21 ContentBlock, EnvVariable, ExtNotification, ExtRequest, ExtResponse, Meta, Plan,
22 SessionConfigOption, SessionId, SessionModeId, ToolCall, ToolCallUpdate,
23};
24#[cfg(feature = "unstable_plan_operations")]
25use super::{PlanCapabilities, PlanRemoved, PlanUpdate};
26
27#[cfg(feature = "unstable_mcp_over_acp")]
28use super::mcp::{
29 ConnectMcpRequest, ConnectMcpResponse, DisconnectMcpRequest, DisconnectMcpResponse,
30 MCP_CONNECT_METHOD_NAME, MCP_DISCONNECT_METHOD_NAME, MCP_MESSAGE_METHOD_NAME,
31 MessageMcpNotification, MessageMcpRequest, MessageMcpResponse,
32};
33
34#[cfg(feature = "unstable_nes")]
35use super::{ClientNesCapabilities, PositionEncodingKind};
36
37// Session updates
38
39/// Notification containing a session update from the agent.
40///
41/// Used to stream real-time progress and results during prompt processing.
42///
43/// See protocol docs: [Agent Reports Output](https://agentclientprotocol.com/protocol/prompt-turn#3-agent-reports-output)
44#[skip_serializing_none]
45#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq)]
46#[schemars(extend("x-side" = "client", "x-method" = SESSION_UPDATE_NOTIFICATION))]
47#[serde(rename_all = "camelCase")]
48#[non_exhaustive]
49pub struct SessionNotification {
50 /// The ID of the session this update pertains to.
51 pub session_id: SessionId,
52 /// The actual update content.
53 pub update: SessionUpdate,
54 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
55 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
56 /// these keys.
57 ///
58 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
59 #[serde(rename = "_meta")]
60 pub meta: Option<Meta>,
61}
62
63impl SessionNotification {
64 /// Builds [`SessionNotification`] with the required notification fields set; optional fields start unset or empty.
65 #[must_use]
66 pub fn new(session_id: impl Into<SessionId>, update: SessionUpdate) -> Self {
67 Self {
68 session_id: session_id.into(),
69 update,
70 meta: None,
71 }
72 }
73
74 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
75 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
76 /// these keys.
77 ///
78 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
79 #[must_use]
80 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
81 self.meta = meta.into_option();
82 self
83 }
84}
85
86/// Different types of updates that can be sent during session processing.
87///
88/// These updates provide real-time feedback about the agent's progress.
89///
90/// See protocol docs: [Agent Reports Output](https://agentclientprotocol.com/protocol/prompt-turn#3-agent-reports-output)
91#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq)]
92#[serde(tag = "sessionUpdate", rename_all = "snake_case")]
93#[schemars(extend("discriminator" = {"propertyName": "sessionUpdate"}))]
94#[non_exhaustive]
95pub enum SessionUpdate {
96 /// A chunk of the user's message being streamed.
97 UserMessageChunk(ContentChunk),
98 /// A chunk of the agent's response being streamed.
99 AgentMessageChunk(ContentChunk),
100 /// A chunk of the agent's internal reasoning being streamed.
101 AgentThoughtChunk(ContentChunk),
102 /// Notification that a new tool call has been initiated.
103 ToolCall(ToolCall),
104 /// Update on the status or results of a tool call.
105 ToolCallUpdate(ToolCallUpdate),
106 /// The agent's execution plan for complex tasks.
107 /// See protocol docs: [Agent Plan](https://agentclientprotocol.com/protocol/agent-plan)
108 Plan(Plan),
109 /// **UNSTABLE**
110 ///
111 /// This capability is not part of the spec yet, and may be removed or changed at any point.
112 ///
113 /// A content update for a plan identified by ID.
114 #[cfg(feature = "unstable_plan_operations")]
115 PlanUpdate(PlanUpdate),
116 /// **UNSTABLE**
117 ///
118 /// This capability is not part of the spec yet, and may be removed or changed at any point.
119 ///
120 /// Removal notice for a plan identified by ID.
121 #[cfg(feature = "unstable_plan_operations")]
122 PlanRemoved(PlanRemoved),
123 /// Available commands are ready or have changed
124 AvailableCommandsUpdate(AvailableCommandsUpdate),
125 /// The current mode of the session has changed
126 ///
127 /// See protocol docs: [Session Modes](https://agentclientprotocol.com/protocol/session-modes)
128 CurrentModeUpdate(CurrentModeUpdate),
129 /// Session configuration options have been updated.
130 ConfigOptionUpdate(ConfigOptionUpdate),
131 /// Session metadata has been updated (title, timestamps, custom metadata)
132 SessionInfoUpdate(SessionInfoUpdate),
133 /// Context window and cost update for the session.
134 UsageUpdate(UsageUpdate),
135}
136
137/// The current mode of the session has changed
138///
139/// See protocol docs: [Session Modes](https://agentclientprotocol.com/protocol/session-modes)
140#[skip_serializing_none]
141#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
142#[serde(rename_all = "camelCase")]
143#[non_exhaustive]
144pub struct CurrentModeUpdate {
145 /// The ID of the current mode
146 pub current_mode_id: SessionModeId,
147 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
148 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
149 /// these keys.
150 ///
151 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
152 #[serde(rename = "_meta")]
153 pub meta: Option<Meta>,
154}
155
156impl CurrentModeUpdate {
157 /// Builds [`CurrentModeUpdate`] with the required fields set; optional fields start unset or empty.
158 #[must_use]
159 pub fn new(current_mode_id: impl Into<SessionModeId>) -> Self {
160 Self {
161 current_mode_id: current_mode_id.into(),
162 meta: None,
163 }
164 }
165
166 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
167 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
168 /// these keys.
169 ///
170 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
171 #[must_use]
172 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
173 self.meta = meta.into_option();
174 self
175 }
176}
177
178/// Session configuration options have been updated.
179#[serde_as]
180#[skip_serializing_none]
181#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
182#[serde(rename_all = "camelCase")]
183#[non_exhaustive]
184pub struct ConfigOptionUpdate {
185 /// The full set of configuration options and their current values.
186 #[serde_as(deserialize_as = "DefaultOnError<VecSkipError<_, SkipListener>>")]
187 #[schemars(extend("x-deserialize-default-on-error" = true, "x-deserialize-skip-invalid-items" = true))]
188 pub config_options: Vec<SessionConfigOption>,
189 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
190 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
191 /// these keys.
192 ///
193 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
194 #[serde(rename = "_meta")]
195 pub meta: Option<Meta>,
196}
197
198impl ConfigOptionUpdate {
199 /// Builds [`ConfigOptionUpdate`] with the required fields set; optional fields start unset or empty.
200 #[must_use]
201 pub fn new(config_options: Vec<SessionConfigOption>) -> Self {
202 Self {
203 config_options,
204 meta: None,
205 }
206 }
207
208 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
209 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
210 /// these keys.
211 ///
212 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
213 #[must_use]
214 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
215 self.meta = meta.into_option();
216 self
217 }
218}
219
220/// Update to session metadata. All fields are optional to support partial updates.
221///
222/// Agents send this notification to update session information like title or custom metadata.
223/// This allows clients to display dynamic session names and track session state changes.
224#[skip_serializing_none]
225#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
226#[serde(rename_all = "camelCase")]
227#[non_exhaustive]
228pub struct SessionInfoUpdate {
229 /// Human-readable title for the session. Set to null to clear.
230 #[serde(default, skip_serializing_if = "MaybeUndefined::is_undefined")]
231 pub title: MaybeUndefined<String>,
232 /// ISO 8601 timestamp of last activity. Set to null to clear.
233 #[serde(default, skip_serializing_if = "MaybeUndefined::is_undefined")]
234 pub updated_at: MaybeUndefined<String>,
235 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
236 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
237 /// these keys.
238 ///
239 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
240 #[serde(rename = "_meta")]
241 pub meta: Option<Meta>,
242}
243
244impl SessionInfoUpdate {
245 /// Builds [`SessionInfoUpdate`] with the required fields set; optional fields start unset or empty.
246 #[must_use]
247 pub fn new() -> Self {
248 Self::default()
249 }
250
251 /// Human-readable title for the session. Set to null to clear.
252 #[must_use]
253 pub fn title(mut self, title: impl IntoMaybeUndefined<String>) -> Self {
254 self.title = title.into_maybe_undefined();
255 self
256 }
257
258 /// ISO 8601 timestamp of last activity. Set to null to clear.
259 #[must_use]
260 pub fn updated_at(mut self, updated_at: impl IntoMaybeUndefined<String>) -> Self {
261 self.updated_at = updated_at.into_maybe_undefined();
262 self
263 }
264
265 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
266 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
267 /// these keys.
268 ///
269 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
270 #[must_use]
271 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
272 self.meta = meta.into_option();
273 self
274 }
275}
276
277/// Context window and cost update for a session.
278#[serde_as]
279#[skip_serializing_none]
280#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq)]
281#[serde(rename_all = "camelCase")]
282#[non_exhaustive]
283pub struct UsageUpdate {
284 /// Tokens currently in context.
285 pub used: u64,
286 /// Total context window size in tokens.
287 pub size: u64,
288 /// Cumulative session cost (optional).
289 #[serde_as(deserialize_as = "DefaultOnError")]
290 #[schemars(extend("x-deserialize-default-on-error" = true))]
291 #[serde(default)]
292 pub cost: Option<Cost>,
293 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
294 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
295 /// these keys.
296 ///
297 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
298 #[serde(rename = "_meta")]
299 pub meta: Option<Meta>,
300}
301
302impl UsageUpdate {
303 /// Builds [`UsageUpdate`] with the required fields set; optional fields start unset or empty.
304 #[must_use]
305 pub fn new(used: u64, size: u64) -> Self {
306 Self {
307 used,
308 size,
309 cost: None,
310 meta: None,
311 }
312 }
313
314 /// Cumulative session cost (optional).
315 #[must_use]
316 pub fn cost(mut self, cost: impl IntoOption<Cost>) -> Self {
317 self.cost = cost.into_option();
318 self
319 }
320
321 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
322 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
323 /// these keys.
324 ///
325 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
326 #[must_use]
327 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
328 self.meta = meta.into_option();
329 self
330 }
331}
332
333/// Cost information for a session.
334#[skip_serializing_none]
335#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq)]
336#[serde(rename_all = "camelCase")]
337#[non_exhaustive]
338pub struct Cost {
339 /// Total cumulative cost for session.
340 pub amount: f64,
341 /// ISO 4217 currency code (e.g., "USD", "EUR").
342 pub currency: String,
343 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
344 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
345 /// these keys.
346 ///
347 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
348 #[serde(rename = "_meta")]
349 pub meta: Option<Meta>,
350}
351
352impl Cost {
353 /// Builds [`Cost`] with the required fields set; optional fields start unset or empty.
354 #[must_use]
355 pub fn new(amount: f64, currency: impl Into<String>) -> Self {
356 Self {
357 amount,
358 currency: currency.into(),
359 meta: None,
360 }
361 }
362
363 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
364 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
365 /// these keys.
366 ///
367 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
368 #[must_use]
369 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
370 self.meta = meta.into_option();
371 self
372 }
373}
374
375/// A streamed item of content
376#[skip_serializing_none]
377#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq)]
378#[serde(rename_all = "camelCase")]
379#[non_exhaustive]
380pub struct ContentChunk {
381 /// A single item of content
382 pub content: ContentBlock,
383 /// A unique identifier for the message this chunk belongs to.
384 ///
385 /// All chunks belonging to the same message share the same `messageId`.
386 /// A change in `messageId` indicates a new message has started.
387 pub message_id: Option<MessageId>,
388 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
389 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
390 /// these keys.
391 ///
392 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
393 #[serde(rename = "_meta")]
394 pub meta: Option<Meta>,
395}
396
397impl ContentChunk {
398 /// Builds [`ContentChunk`] with the required fields set; optional fields start unset or empty.
399 #[must_use]
400 pub fn new(content: ContentBlock) -> Self {
401 Self {
402 content,
403 message_id: None,
404 meta: None,
405 }
406 }
407
408 /// A unique identifier for the message this chunk belongs to.
409 ///
410 /// All chunks belonging to the same message share the same `messageId`.
411 /// A change in `messageId` indicates a new message has started.
412 #[must_use]
413 pub fn message_id(mut self, message_id: impl IntoOption<MessageId>) -> Self {
414 self.message_id = message_id.into_option();
415 self
416 }
417
418 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
419 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
420 /// these keys.
421 ///
422 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
423 #[must_use]
424 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
425 self.meta = meta.into_option();
426 self
427 }
428}
429
430/// Unique identifier for a message within a session.
431#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq, Hash, Display, From)]
432#[serde(transparent)]
433#[from(Arc<str>, String, &'static str)]
434#[non_exhaustive]
435pub struct MessageId(pub Arc<str>);
436
437impl MessageId {
438 /// Wraps a protocol string as a typed [`MessageId`].
439 #[must_use]
440 pub fn new(id: impl Into<Arc<str>>) -> Self {
441 Self(id.into())
442 }
443}
444
445impl IntoOption<MessageId> for &str {
446 fn into_option(self) -> Option<MessageId> {
447 Some(MessageId::new(self))
448 }
449}
450
451/// Available commands are ready or have changed
452#[serde_as]
453#[skip_serializing_none]
454#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
455#[serde(rename_all = "camelCase")]
456#[non_exhaustive]
457pub struct AvailableCommandsUpdate {
458 /// Commands the agent can execute
459 #[serde_as(deserialize_as = "DefaultOnError<VecSkipError<_, SkipListener>>")]
460 #[schemars(extend("x-deserialize-default-on-error" = true, "x-deserialize-skip-invalid-items" = true))]
461 pub available_commands: Vec<AvailableCommand>,
462 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
463 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
464 /// these keys.
465 ///
466 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
467 #[serde(rename = "_meta")]
468 pub meta: Option<Meta>,
469}
470
471impl AvailableCommandsUpdate {
472 /// Builds [`AvailableCommandsUpdate`] with the required fields set; optional fields start unset or empty.
473 #[must_use]
474 pub fn new(available_commands: Vec<AvailableCommand>) -> Self {
475 Self {
476 available_commands,
477 meta: None,
478 }
479 }
480
481 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
482 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
483 /// these keys.
484 ///
485 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
486 #[must_use]
487 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
488 self.meta = meta.into_option();
489 self
490 }
491}
492
493/// Information about a command.
494#[serde_as]
495#[skip_serializing_none]
496#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
497#[serde(rename_all = "camelCase")]
498#[non_exhaustive]
499pub struct AvailableCommand {
500 /// Command name (e.g., `create_plan`, `research_codebase`).
501 pub name: String,
502 /// Human-readable description of what the command does.
503 pub description: String,
504 /// Input for the command if required
505 #[serde_as(deserialize_as = "DefaultOnError")]
506 #[schemars(extend("x-deserialize-default-on-error" = true))]
507 #[serde(default)]
508 pub input: Option<AvailableCommandInput>,
509 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
510 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
511 /// these keys.
512 ///
513 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
514 #[serde(rename = "_meta")]
515 pub meta: Option<Meta>,
516}
517
518impl AvailableCommand {
519 /// Builds [`AvailableCommand`] with the required fields set; optional fields start unset or empty.
520 #[must_use]
521 pub fn new(name: impl Into<String>, description: impl Into<String>) -> Self {
522 Self {
523 name: name.into(),
524 description: description.into(),
525 input: None,
526 meta: None,
527 }
528 }
529
530 /// Input for the command if required
531 #[must_use]
532 pub fn input(mut self, input: impl IntoOption<AvailableCommandInput>) -> Self {
533 self.input = input.into_option();
534 self
535 }
536
537 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
538 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
539 /// these keys.
540 ///
541 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
542 #[must_use]
543 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
544 self.meta = meta.into_option();
545 self
546 }
547}
548
549/// The input specification for a command.
550#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
551#[serde(untagged, rename_all = "camelCase")]
552#[non_exhaustive]
553pub enum AvailableCommandInput {
554 /// All text that was typed after the command name is provided as input.
555 Unstructured(UnstructuredCommandInput),
556}
557
558/// All text that was typed after the command name is provided as input.
559#[skip_serializing_none]
560#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
561#[serde(rename_all = "camelCase")]
562#[non_exhaustive]
563pub struct UnstructuredCommandInput {
564 /// A hint to display when the input hasn't been provided yet
565 pub hint: String,
566 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
567 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
568 /// these keys.
569 ///
570 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
571 #[serde(rename = "_meta")]
572 pub meta: Option<Meta>,
573}
574
575impl UnstructuredCommandInput {
576 /// Builds [`UnstructuredCommandInput`] with the required fields set; optional fields start unset or empty.
577 #[must_use]
578 pub fn new(hint: impl Into<String>) -> Self {
579 Self {
580 hint: hint.into(),
581 meta: None,
582 }
583 }
584
585 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
586 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
587 /// these keys.
588 ///
589 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
590 #[must_use]
591 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
592 self.meta = meta.into_option();
593 self
594 }
595}
596
597// Permission
598
599/// Request for user permission to execute a tool call.
600///
601/// Sent when the agent needs authorization before performing a sensitive operation.
602///
603/// See protocol docs: [Requesting Permission](https://agentclientprotocol.com/protocol/tool-calls#requesting-permission)
604#[skip_serializing_none]
605#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq)]
606#[schemars(extend("x-side" = "client", "x-method" = SESSION_REQUEST_PERMISSION_METHOD_NAME))]
607#[serde(rename_all = "camelCase")]
608#[non_exhaustive]
609pub struct RequestPermissionRequest {
610 /// The session ID for this request.
611 pub session_id: SessionId,
612 /// Details about the tool call requiring permission.
613 pub tool_call: ToolCallUpdate,
614 /// Available permission options for the user to choose from.
615 pub options: Vec<PermissionOption>,
616 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
617 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
618 /// these keys.
619 ///
620 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
621 #[serde(rename = "_meta")]
622 pub meta: Option<Meta>,
623}
624
625impl RequestPermissionRequest {
626 /// Builds [`RequestPermissionRequest`] with the required request fields set; optional fields start unset or empty.
627 #[must_use]
628 pub fn new(
629 session_id: impl Into<SessionId>,
630 tool_call: ToolCallUpdate,
631 options: Vec<PermissionOption>,
632 ) -> Self {
633 Self {
634 session_id: session_id.into(),
635 tool_call,
636 options,
637 meta: None,
638 }
639 }
640
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 #[must_use]
647 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
648 self.meta = meta.into_option();
649 self
650 }
651}
652
653/// An option presented to the user when requesting permission.
654#[skip_serializing_none]
655#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
656#[serde(rename_all = "camelCase")]
657#[non_exhaustive]
658pub struct PermissionOption {
659 /// Unique identifier for this permission option.
660 pub option_id: PermissionOptionId,
661 /// Human-readable label to display to the user.
662 pub name: String,
663 /// Hint about the nature of this permission option.
664 pub kind: PermissionOptionKind,
665 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
666 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
667 /// these keys.
668 ///
669 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
670 #[serde(rename = "_meta")]
671 pub meta: Option<Meta>,
672}
673
674impl PermissionOption {
675 /// Builds [`PermissionOption`] with the required fields set; optional fields start unset or empty.
676 #[must_use]
677 pub fn new(
678 option_id: impl Into<PermissionOptionId>,
679 name: impl Into<String>,
680 kind: PermissionOptionKind,
681 ) -> Self {
682 Self {
683 option_id: option_id.into(),
684 name: name.into(),
685 kind,
686 meta: None,
687 }
688 }
689
690 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
691 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
692 /// these keys.
693 ///
694 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
695 #[must_use]
696 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
697 self.meta = meta.into_option();
698 self
699 }
700}
701
702/// Unique identifier for a permission option.
703#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq, Hash, Display, From)]
704#[serde(transparent)]
705#[from(Arc<str>, String, &'static str)]
706#[non_exhaustive]
707pub struct PermissionOptionId(pub Arc<str>);
708
709impl PermissionOptionId {
710 /// Wraps a protocol string as a typed [`PermissionOptionId`].
711 #[must_use]
712 pub fn new(id: impl Into<Arc<str>>) -> Self {
713 Self(id.into())
714 }
715}
716
717/// The type of permission option being presented to the user.
718///
719/// Helps clients choose appropriate icons and UI treatment.
720#[derive(Debug, Clone, Copy, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
721#[serde(rename_all = "snake_case")]
722#[non_exhaustive]
723pub enum PermissionOptionKind {
724 /// Allow this operation only this time.
725 AllowOnce,
726 /// Allow this operation and remember the choice.
727 AllowAlways,
728 /// Reject this operation only this time.
729 RejectOnce,
730 /// Reject this operation and remember the choice.
731 RejectAlways,
732}
733
734/// Response to a permission request.
735#[skip_serializing_none]
736#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
737#[schemars(extend("x-side" = "client", "x-method" = SESSION_REQUEST_PERMISSION_METHOD_NAME))]
738#[serde(rename_all = "camelCase")]
739#[non_exhaustive]
740pub struct RequestPermissionResponse {
741 /// The user's decision on the permission request.
742 // This extra-level is unfortunately needed because the output must be an object
743 pub outcome: RequestPermissionOutcome,
744 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
745 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
746 /// these keys.
747 ///
748 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
749 #[serde(rename = "_meta")]
750 pub meta: Option<Meta>,
751}
752
753impl RequestPermissionResponse {
754 /// Builds [`RequestPermissionResponse`] with the required response fields set; optional fields start unset or empty.
755 #[must_use]
756 pub fn new(outcome: RequestPermissionOutcome) -> Self {
757 Self {
758 outcome,
759 meta: None,
760 }
761 }
762
763 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
764 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
765 /// these keys.
766 ///
767 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
768 #[must_use]
769 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
770 self.meta = meta.into_option();
771 self
772 }
773}
774
775/// The outcome of a permission request.
776#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
777#[serde(tag = "outcome", rename_all = "snake_case")]
778#[schemars(extend("discriminator" = {"propertyName": "outcome"}))]
779#[non_exhaustive]
780pub enum RequestPermissionOutcome {
781 /// The prompt turn was cancelled before the user responded.
782 ///
783 /// When a client sends a `session/cancel` notification to cancel an ongoing
784 /// prompt turn, it MUST respond to all pending `session/request_permission`
785 /// requests with this `Cancelled` outcome.
786 ///
787 /// See protocol docs: [Cancellation](https://agentclientprotocol.com/protocol/prompt-turn#cancellation)
788 Cancelled,
789 /// The user selected one of the provided options.
790 #[serde(rename_all = "camelCase")]
791 Selected(SelectedPermissionOutcome),
792}
793
794/// The user selected one of the provided options.
795#[skip_serializing_none]
796#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
797#[serde(rename_all = "camelCase")]
798#[non_exhaustive]
799pub struct SelectedPermissionOutcome {
800 /// The ID of the option the user selected.
801 pub option_id: PermissionOptionId,
802 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
803 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
804 /// these keys.
805 ///
806 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
807 #[serde(rename = "_meta")]
808 pub meta: Option<Meta>,
809}
810
811impl SelectedPermissionOutcome {
812 /// Builds [`SelectedPermissionOutcome`] with the required fields set; optional fields start unset or empty.
813 #[must_use]
814 pub fn new(option_id: impl Into<PermissionOptionId>) -> Self {
815 Self {
816 option_id: option_id.into(),
817 meta: None,
818 }
819 }
820
821 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
822 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
823 /// these keys.
824 ///
825 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
826 #[must_use]
827 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
828 self.meta = meta.into_option();
829 self
830 }
831}
832
833// Write text file
834
835/// Request to write content to a text file.
836///
837/// Only available if the client supports the `fs.writeTextFile` capability.
838#[skip_serializing_none]
839#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
840#[schemars(extend("x-side" = "client", "x-method" = FS_WRITE_TEXT_FILE_METHOD_NAME))]
841#[serde(rename_all = "camelCase")]
842#[non_exhaustive]
843pub struct WriteTextFileRequest {
844 /// The session ID for this request.
845 pub session_id: SessionId,
846 /// Absolute path to the file to write.
847 pub path: PathBuf,
848 /// The text content to write to the file.
849 pub content: String,
850 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
851 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
852 /// these keys.
853 ///
854 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
855 #[serde(rename = "_meta")]
856 pub meta: Option<Meta>,
857}
858
859impl WriteTextFileRequest {
860 /// Builds [`WriteTextFileRequest`] with the required request fields set; optional fields start unset or empty.
861 #[must_use]
862 pub fn new(
863 session_id: impl Into<SessionId>,
864 path: impl Into<PathBuf>,
865 content: impl Into<String>,
866 ) -> Self {
867 Self {
868 session_id: session_id.into(),
869 path: path.into(),
870 content: content.into(),
871 meta: None,
872 }
873 }
874
875 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
876 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
877 /// these keys.
878 ///
879 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
880 #[must_use]
881 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
882 self.meta = meta.into_option();
883 self
884 }
885}
886
887/// Response to `fs/write_text_file`
888#[skip_serializing_none]
889#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
890#[serde(rename_all = "camelCase")]
891#[schemars(extend("x-side" = "client", "x-method" = FS_WRITE_TEXT_FILE_METHOD_NAME))]
892#[non_exhaustive]
893pub struct WriteTextFileResponse {
894 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
895 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
896 /// these keys.
897 ///
898 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
899 #[serde(rename = "_meta")]
900 pub meta: Option<Meta>,
901}
902
903impl WriteTextFileResponse {
904 /// Builds [`WriteTextFileResponse`] with the required response fields set; optional fields start unset or empty.
905 #[must_use]
906 pub fn new() -> Self {
907 Self::default()
908 }
909
910 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
911 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
912 /// these keys.
913 ///
914 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
915 #[must_use]
916 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
917 self.meta = meta.into_option();
918 self
919 }
920}
921
922// Read text file
923
924/// Request to read content from a text file.
925///
926/// Only available if the client supports the `fs.readTextFile` capability.
927#[skip_serializing_none]
928#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
929#[schemars(extend("x-side" = "client", "x-method" = FS_READ_TEXT_FILE_METHOD_NAME))]
930#[serde(rename_all = "camelCase")]
931#[non_exhaustive]
932pub struct ReadTextFileRequest {
933 /// The session ID for this request.
934 pub session_id: SessionId,
935 /// Absolute path to the file to read.
936 pub path: PathBuf,
937 /// Line number to start reading from (1-based).
938 pub line: Option<u32>,
939 /// Maximum number of lines to read.
940 pub limit: Option<u32>,
941 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
942 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
943 /// these keys.
944 ///
945 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
946 #[serde(rename = "_meta")]
947 pub meta: Option<Meta>,
948}
949
950impl ReadTextFileRequest {
951 /// Builds [`ReadTextFileRequest`] with the required request fields set; optional fields start unset or empty.
952 #[must_use]
953 pub fn new(session_id: impl Into<SessionId>, path: impl Into<PathBuf>) -> Self {
954 Self {
955 session_id: session_id.into(),
956 path: path.into(),
957 line: None,
958 limit: None,
959 meta: None,
960 }
961 }
962
963 /// Line number to start reading from (1-based).
964 #[must_use]
965 pub fn line(mut self, line: impl IntoOption<u32>) -> Self {
966 self.line = line.into_option();
967 self
968 }
969
970 /// Maximum number of lines to read.
971 #[must_use]
972 pub fn limit(mut self, limit: impl IntoOption<u32>) -> Self {
973 self.limit = limit.into_option();
974 self
975 }
976
977 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
978 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
979 /// these keys.
980 ///
981 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
982 #[must_use]
983 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
984 self.meta = meta.into_option();
985 self
986 }
987}
988
989/// Response containing the contents of a text file.
990#[skip_serializing_none]
991#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
992#[schemars(extend("x-side" = "client", "x-method" = FS_READ_TEXT_FILE_METHOD_NAME))]
993#[serde(rename_all = "camelCase")]
994#[non_exhaustive]
995pub struct ReadTextFileResponse {
996 /// Content payload returned by this response.
997 pub content: String,
998 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
999 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1000 /// these keys.
1001 ///
1002 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1003 #[serde(rename = "_meta")]
1004 pub meta: Option<Meta>,
1005}
1006
1007impl ReadTextFileResponse {
1008 /// Builds [`ReadTextFileResponse`] with the required response fields set; optional fields start unset or empty.
1009 #[must_use]
1010 pub fn new(content: impl Into<String>) -> Self {
1011 Self {
1012 content: content.into(),
1013 meta: None,
1014 }
1015 }
1016
1017 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1018 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1019 /// these keys.
1020 ///
1021 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1022 #[must_use]
1023 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1024 self.meta = meta.into_option();
1025 self
1026 }
1027}
1028
1029// Terminals
1030
1031/// Typed identifier used for terminal values on the wire.
1032#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq, Hash, Display, From)]
1033#[serde(transparent)]
1034#[from(Arc<str>, String, &'static str)]
1035#[non_exhaustive]
1036pub struct TerminalId(pub Arc<str>);
1037
1038impl TerminalId {
1039 /// Wraps a protocol string as a typed [`TerminalId`].
1040 #[must_use]
1041 pub fn new(id: impl Into<Arc<str>>) -> Self {
1042 Self(id.into())
1043 }
1044}
1045
1046/// Request to create a new terminal and execute a command.
1047#[skip_serializing_none]
1048#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1049#[serde(rename_all = "camelCase")]
1050#[schemars(extend("x-side" = "client", "x-method" = TERMINAL_CREATE_METHOD_NAME))]
1051#[non_exhaustive]
1052pub struct CreateTerminalRequest {
1053 /// The session ID for this request.
1054 pub session_id: SessionId,
1055 /// The command to execute.
1056 pub command: String,
1057 /// Array of command arguments.
1058 #[serde(default, skip_serializing_if = "Vec::is_empty")]
1059 pub args: Vec<String>,
1060 /// Environment variables for the command.
1061 #[serde(default, skip_serializing_if = "Vec::is_empty")]
1062 pub env: Vec<EnvVariable>,
1063 /// Working directory for the command (absolute path).
1064 pub cwd: Option<PathBuf>,
1065 /// Maximum number of output bytes to retain.
1066 ///
1067 /// When the limit is exceeded, the Client truncates from the beginning of the output
1068 /// to stay within the limit.
1069 ///
1070 /// The Client MUST ensure truncation happens at a character boundary to maintain valid
1071 /// string output, even if this means the retained output is slightly less than the
1072 /// specified limit.
1073 pub output_byte_limit: Option<u64>,
1074 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1075 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1076 /// these keys.
1077 ///
1078 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1079 #[serde(rename = "_meta")]
1080 pub meta: Option<Meta>,
1081}
1082
1083impl CreateTerminalRequest {
1084 /// Builds [`CreateTerminalRequest`] with the required request fields set; optional fields start unset or empty.
1085 #[must_use]
1086 pub fn new(session_id: impl Into<SessionId>, command: impl Into<String>) -> Self {
1087 Self {
1088 session_id: session_id.into(),
1089 command: command.into(),
1090 args: Vec::new(),
1091 env: Vec::new(),
1092 cwd: None,
1093 output_byte_limit: None,
1094 meta: None,
1095 }
1096 }
1097
1098 /// Array of command arguments.
1099 #[must_use]
1100 pub fn args(mut self, args: Vec<String>) -> Self {
1101 self.args = args;
1102 self
1103 }
1104
1105 /// Environment variables for the command.
1106 #[must_use]
1107 pub fn env(mut self, env: Vec<EnvVariable>) -> Self {
1108 self.env = env;
1109 self
1110 }
1111
1112 /// Working directory for the command (absolute path).
1113 #[must_use]
1114 pub fn cwd(mut self, cwd: impl IntoOption<PathBuf>) -> Self {
1115 self.cwd = cwd.into_option();
1116 self
1117 }
1118
1119 /// Maximum number of output bytes to retain.
1120 ///
1121 /// When the limit is exceeded, the Client truncates from the beginning of the output
1122 /// to stay within the limit.
1123 ///
1124 /// The Client MUST ensure truncation happens at a character boundary to maintain valid
1125 /// string output, even if this means the retained output is slightly less than the
1126 /// specified limit.
1127 #[must_use]
1128 pub fn output_byte_limit(mut self, output_byte_limit: impl IntoOption<u64>) -> Self {
1129 self.output_byte_limit = output_byte_limit.into_option();
1130 self
1131 }
1132
1133 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1134 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1135 /// these keys.
1136 ///
1137 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1138 #[must_use]
1139 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1140 self.meta = meta.into_option();
1141 self
1142 }
1143}
1144
1145/// Response containing the ID of the created terminal.
1146#[skip_serializing_none]
1147#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1148#[serde(rename_all = "camelCase")]
1149#[schemars(extend("x-side" = "client", "x-method" = TERMINAL_CREATE_METHOD_NAME))]
1150#[non_exhaustive]
1151pub struct CreateTerminalResponse {
1152 /// The unique identifier for the created terminal.
1153 pub terminal_id: TerminalId,
1154 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1155 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1156 /// these keys.
1157 ///
1158 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1159 #[serde(rename = "_meta")]
1160 pub meta: Option<Meta>,
1161}
1162
1163impl CreateTerminalResponse {
1164 /// Builds [`CreateTerminalResponse`] with the required response fields set; optional fields start unset or empty.
1165 #[must_use]
1166 pub fn new(terminal_id: impl Into<TerminalId>) -> Self {
1167 Self {
1168 terminal_id: terminal_id.into(),
1169 meta: None,
1170 }
1171 }
1172
1173 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1174 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1175 /// these keys.
1176 ///
1177 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1178 #[must_use]
1179 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1180 self.meta = meta.into_option();
1181 self
1182 }
1183}
1184
1185/// Request to get the current output and status of a terminal.
1186#[skip_serializing_none]
1187#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1188#[serde(rename_all = "camelCase")]
1189#[schemars(extend("x-side" = "client", "x-method" = TERMINAL_OUTPUT_METHOD_NAME))]
1190#[non_exhaustive]
1191pub struct TerminalOutputRequest {
1192 /// The session ID for this request.
1193 pub session_id: SessionId,
1194 /// The ID of the terminal to get output from.
1195 pub terminal_id: TerminalId,
1196 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1197 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1198 /// these keys.
1199 ///
1200 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1201 #[serde(rename = "_meta")]
1202 pub meta: Option<Meta>,
1203}
1204
1205impl TerminalOutputRequest {
1206 /// Builds [`TerminalOutputRequest`] with the required request fields set; optional fields start unset or empty.
1207 #[must_use]
1208 pub fn new(session_id: impl Into<SessionId>, terminal_id: impl Into<TerminalId>) -> Self {
1209 Self {
1210 session_id: session_id.into(),
1211 terminal_id: terminal_id.into(),
1212 meta: None,
1213 }
1214 }
1215
1216 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1217 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1218 /// these keys.
1219 ///
1220 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1221 #[must_use]
1222 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1223 self.meta = meta.into_option();
1224 self
1225 }
1226}
1227
1228/// Response containing the terminal output and exit status.
1229#[skip_serializing_none]
1230#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1231#[serde(rename_all = "camelCase")]
1232#[schemars(extend("x-side" = "client", "x-method" = TERMINAL_OUTPUT_METHOD_NAME))]
1233#[non_exhaustive]
1234pub struct TerminalOutputResponse {
1235 /// The terminal output captured so far.
1236 pub output: String,
1237 /// Whether the output was truncated due to byte limits.
1238 pub truncated: bool,
1239 /// Exit status if the command has completed.
1240 pub exit_status: Option<TerminalExitStatus>,
1241 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1242 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1243 /// these keys.
1244 ///
1245 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1246 #[serde(rename = "_meta")]
1247 pub meta: Option<Meta>,
1248}
1249
1250impl TerminalOutputResponse {
1251 /// Builds [`TerminalOutputResponse`] with the required response fields set; optional fields start unset or empty.
1252 #[must_use]
1253 pub fn new(output: impl Into<String>, truncated: bool) -> Self {
1254 Self {
1255 output: output.into(),
1256 truncated,
1257 exit_status: None,
1258 meta: None,
1259 }
1260 }
1261
1262 /// Exit status if the command has completed.
1263 #[must_use]
1264 pub fn exit_status(mut self, exit_status: impl IntoOption<TerminalExitStatus>) -> Self {
1265 self.exit_status = exit_status.into_option();
1266 self
1267 }
1268
1269 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1270 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1271 /// these keys.
1272 ///
1273 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1274 #[must_use]
1275 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1276 self.meta = meta.into_option();
1277 self
1278 }
1279}
1280
1281/// Request to release a terminal and free its resources.
1282#[skip_serializing_none]
1283#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1284#[serde(rename_all = "camelCase")]
1285#[schemars(extend("x-side" = "client", "x-method" = TERMINAL_RELEASE_METHOD_NAME))]
1286#[non_exhaustive]
1287pub struct ReleaseTerminalRequest {
1288 /// The session ID for this request.
1289 pub session_id: SessionId,
1290 /// The ID of the terminal to release.
1291 pub terminal_id: TerminalId,
1292 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1293 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1294 /// these keys.
1295 ///
1296 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1297 #[serde(rename = "_meta")]
1298 pub meta: Option<Meta>,
1299}
1300
1301impl ReleaseTerminalRequest {
1302 /// Builds [`ReleaseTerminalRequest`] with the required request fields set; optional fields start unset or empty.
1303 #[must_use]
1304 pub fn new(session_id: impl Into<SessionId>, terminal_id: impl Into<TerminalId>) -> Self {
1305 Self {
1306 session_id: session_id.into(),
1307 terminal_id: terminal_id.into(),
1308 meta: None,
1309 }
1310 }
1311
1312 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1313 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1314 /// these keys.
1315 ///
1316 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1317 #[must_use]
1318 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1319 self.meta = meta.into_option();
1320 self
1321 }
1322}
1323
1324/// Response to terminal/release method
1325#[skip_serializing_none]
1326#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1327#[serde(rename_all = "camelCase")]
1328#[schemars(extend("x-side" = "client", "x-method" = TERMINAL_RELEASE_METHOD_NAME))]
1329#[non_exhaustive]
1330pub struct ReleaseTerminalResponse {
1331 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1332 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1333 /// these keys.
1334 ///
1335 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1336 #[serde(rename = "_meta")]
1337 pub meta: Option<Meta>,
1338}
1339
1340impl ReleaseTerminalResponse {
1341 /// Builds [`ReleaseTerminalResponse`] with the required response fields set; optional fields start unset or empty.
1342 #[must_use]
1343 pub fn new() -> Self {
1344 Self::default()
1345 }
1346
1347 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1348 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1349 /// these keys.
1350 ///
1351 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1352 #[must_use]
1353 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1354 self.meta = meta.into_option();
1355 self
1356 }
1357}
1358
1359/// Request to kill a terminal without releasing it.
1360#[skip_serializing_none]
1361#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1362#[serde(rename_all = "camelCase")]
1363#[schemars(extend("x-side" = "client", "x-method" = TERMINAL_KILL_METHOD_NAME))]
1364#[non_exhaustive]
1365pub struct KillTerminalRequest {
1366 /// The session ID for this request.
1367 pub session_id: SessionId,
1368 /// The ID of the terminal to kill.
1369 pub terminal_id: TerminalId,
1370 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1371 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1372 /// these keys.
1373 ///
1374 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1375 #[serde(rename = "_meta")]
1376 pub meta: Option<Meta>,
1377}
1378
1379impl KillTerminalRequest {
1380 /// Builds [`KillTerminalRequest`] with the required request fields set; optional fields start unset or empty.
1381 #[must_use]
1382 pub fn new(session_id: impl Into<SessionId>, terminal_id: impl Into<TerminalId>) -> Self {
1383 Self {
1384 session_id: session_id.into(),
1385 terminal_id: terminal_id.into(),
1386 meta: None,
1387 }
1388 }
1389
1390 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1391 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1392 /// these keys.
1393 ///
1394 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1395 #[must_use]
1396 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1397 self.meta = meta.into_option();
1398 self
1399 }
1400}
1401
1402/// Response to `terminal/kill` method
1403#[skip_serializing_none]
1404#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1405#[serde(rename_all = "camelCase")]
1406#[schemars(extend("x-side" = "client", "x-method" = TERMINAL_KILL_METHOD_NAME))]
1407#[non_exhaustive]
1408pub struct KillTerminalResponse {
1409 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1410 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1411 /// these keys.
1412 ///
1413 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1414 #[serde(rename = "_meta")]
1415 pub meta: Option<Meta>,
1416}
1417
1418impl KillTerminalResponse {
1419 /// Builds [`KillTerminalResponse`] with the required response fields set; optional fields start unset or empty.
1420 #[must_use]
1421 pub fn new() -> Self {
1422 Self::default()
1423 }
1424
1425 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1426 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1427 /// these keys.
1428 ///
1429 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1430 #[must_use]
1431 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1432 self.meta = meta.into_option();
1433 self
1434 }
1435}
1436
1437/// Request to wait for a terminal command to exit.
1438#[skip_serializing_none]
1439#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1440#[serde(rename_all = "camelCase")]
1441#[schemars(extend("x-side" = "client", "x-method" = TERMINAL_WAIT_FOR_EXIT_METHOD_NAME))]
1442#[non_exhaustive]
1443pub struct WaitForTerminalExitRequest {
1444 /// The session ID for this request.
1445 pub session_id: SessionId,
1446 /// The ID of the terminal to wait for.
1447 pub terminal_id: TerminalId,
1448 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1449 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1450 /// these keys.
1451 ///
1452 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1453 #[serde(rename = "_meta")]
1454 pub meta: Option<Meta>,
1455}
1456
1457impl WaitForTerminalExitRequest {
1458 /// Builds [`WaitForTerminalExitRequest`] with the required request fields set; optional fields start unset or empty.
1459 #[must_use]
1460 pub fn new(session_id: impl Into<SessionId>, terminal_id: impl Into<TerminalId>) -> Self {
1461 Self {
1462 session_id: session_id.into(),
1463 terminal_id: terminal_id.into(),
1464 meta: None,
1465 }
1466 }
1467
1468 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1469 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1470 /// these keys.
1471 ///
1472 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1473 #[must_use]
1474 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1475 self.meta = meta.into_option();
1476 self
1477 }
1478}
1479
1480/// Response containing the exit status of a terminal command.
1481#[skip_serializing_none]
1482#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1483#[serde(rename_all = "camelCase")]
1484#[schemars(extend("x-side" = "client", "x-method" = TERMINAL_WAIT_FOR_EXIT_METHOD_NAME))]
1485#[non_exhaustive]
1486pub struct WaitForTerminalExitResponse {
1487 /// The exit status of the terminal command.
1488 #[serde(flatten)]
1489 pub exit_status: TerminalExitStatus,
1490 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1491 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1492 /// these keys.
1493 ///
1494 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1495 #[serde(rename = "_meta")]
1496 pub meta: Option<Meta>,
1497}
1498
1499impl WaitForTerminalExitResponse {
1500 /// Builds [`WaitForTerminalExitResponse`] with the required response fields set; optional fields start unset or empty.
1501 #[must_use]
1502 pub fn new(exit_status: TerminalExitStatus) -> Self {
1503 Self {
1504 exit_status,
1505 meta: None,
1506 }
1507 }
1508
1509 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1510 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1511 /// these keys.
1512 ///
1513 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1514 #[must_use]
1515 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1516 self.meta = meta.into_option();
1517 self
1518 }
1519}
1520
1521/// Exit status of a terminal command.
1522#[skip_serializing_none]
1523#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1524#[serde(rename_all = "camelCase")]
1525#[non_exhaustive]
1526pub struct TerminalExitStatus {
1527 /// The process exit code (may be null if terminated by signal).
1528 pub exit_code: Option<u32>,
1529 /// The signal that terminated the process (may be null if exited normally).
1530 pub signal: Option<String>,
1531 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1532 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1533 /// these keys.
1534 ///
1535 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1536 #[serde(rename = "_meta")]
1537 pub meta: Option<Meta>,
1538}
1539
1540impl TerminalExitStatus {
1541 /// Builds [`TerminalExitStatus`] with the required fields set; optional fields start unset or empty.
1542 #[must_use]
1543 pub fn new() -> Self {
1544 Self::default()
1545 }
1546
1547 /// The process exit code (may be null if terminated by signal).
1548 #[must_use]
1549 pub fn exit_code(mut self, exit_code: impl IntoOption<u32>) -> Self {
1550 self.exit_code = exit_code.into_option();
1551 self
1552 }
1553
1554 /// The signal that terminated the process (may be null if exited normally).
1555 #[must_use]
1556 pub fn signal(mut self, signal: impl IntoOption<String>) -> Self {
1557 self.signal = signal.into_option();
1558 self
1559 }
1560
1561 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1562 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1563 /// these keys.
1564 ///
1565 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1566 #[must_use]
1567 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1568 self.meta = meta.into_option();
1569 self
1570 }
1571}
1572
1573// Capabilities
1574
1575/// Capabilities supported by the client.
1576///
1577/// Advertised during initialization to inform the agent about
1578/// available features and methods.
1579///
1580/// See protocol docs: [Client Capabilities](https://agentclientprotocol.com/protocol/initialization#client-capabilities)
1581#[serde_as]
1582#[skip_serializing_none]
1583#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1584#[serde(rename_all = "camelCase")]
1585#[non_exhaustive]
1586pub struct ClientCapabilities {
1587 /// File system capabilities supported by the client.
1588 /// Determines which file operations the agent can request.
1589 #[serde(default)]
1590 pub fs: FileSystemCapabilities,
1591 /// Whether the Client support all `terminal/*` methods.
1592 #[serde(default)]
1593 pub terminal: bool,
1594 /// **UNSTABLE**
1595 ///
1596 /// This capability is not part of the spec yet, and may be removed or changed at any point.
1597 ///
1598 /// Whether the client supports `plan_update` and `plan_removed` session updates.
1599 ///
1600 /// Optional. Omitted means the client does not advertise support.
1601 /// Supplying `{}` means the client can receive both update types.
1602 #[cfg(feature = "unstable_plan_operations")]
1603 #[serde_as(deserialize_as = "DefaultOnError")]
1604 #[schemars(extend("x-deserialize-default-on-error" = true))]
1605 #[serde(default)]
1606 pub plan: Option<PlanCapabilities>,
1607 /// **UNSTABLE**
1608 ///
1609 /// This capability is not part of the spec yet, and may be removed or changed at any point.
1610 ///
1611 /// Authentication capabilities supported by the client.
1612 /// Determines which authentication method types the agent may include
1613 /// in its `InitializeResponse`.
1614 #[cfg(feature = "unstable_auth_methods")]
1615 #[serde(default)]
1616 pub auth: AuthCapabilities,
1617 /// **UNSTABLE**
1618 ///
1619 /// This capability is not part of the spec yet, and may be removed or changed at any point.
1620 ///
1621 /// Elicitation capabilities supported by the client.
1622 /// Determines which elicitation modes the agent may use.
1623 #[cfg(feature = "unstable_elicitation")]
1624 #[serde_as(deserialize_as = "DefaultOnError")]
1625 #[schemars(extend("x-deserialize-default-on-error" = true))]
1626 #[serde(default)]
1627 pub elicitation: Option<ElicitationCapabilities>,
1628 /// **UNSTABLE**
1629 ///
1630 /// This capability is not part of the spec yet, and may be removed or changed at any point.
1631 ///
1632 /// NES (Next Edit Suggestions) capabilities supported by the client.
1633 #[cfg(feature = "unstable_nes")]
1634 #[serde_as(deserialize_as = "DefaultOnError")]
1635 #[schemars(extend("x-deserialize-default-on-error" = true))]
1636 #[serde(default)]
1637 pub nes: Option<ClientNesCapabilities>,
1638 /// **UNSTABLE**
1639 ///
1640 /// This capability is not part of the spec yet, and may be removed or changed at any point.
1641 ///
1642 /// The position encodings supported by the client, in order of preference.
1643 #[cfg(feature = "unstable_nes")]
1644 #[serde_as(deserialize_as = "DefaultOnError<VecSkipError<_, SkipListener>>")]
1645 #[schemars(extend("x-deserialize-default-on-error" = true, "x-deserialize-skip-invalid-items" = true))]
1646 #[serde(default, skip_serializing_if = "Vec::is_empty")]
1647 pub position_encodings: Vec<PositionEncodingKind>,
1648
1649 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1650 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1651 /// these keys.
1652 ///
1653 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1654 #[serde(rename = "_meta")]
1655 pub meta: Option<Meta>,
1656}
1657
1658impl ClientCapabilities {
1659 /// Builds an empty [`ClientCapabilities`]; use builder methods to advertise supported sub-capabilities.
1660 #[must_use]
1661 pub fn new() -> Self {
1662 Self::default()
1663 }
1664
1665 /// File system capabilities supported by the client.
1666 /// Determines which file operations the agent can request.
1667 #[must_use]
1668 pub fn fs(mut self, fs: FileSystemCapabilities) -> Self {
1669 self.fs = fs;
1670 self
1671 }
1672
1673 /// Whether the Client support all `terminal/*` methods.
1674 #[must_use]
1675 pub fn terminal(mut self, terminal: bool) -> Self {
1676 self.terminal = terminal;
1677 self
1678 }
1679
1680 /// **UNSTABLE**
1681 ///
1682 /// This capability is not part of the spec yet, and may be removed or changed at any point.
1683 ///
1684 /// Whether the client supports `plan_update` and `plan_removed` session updates.
1685 ///
1686 /// Omitted means the client does not advertise support.
1687 /// Supplying `{}` means the client can receive both update types.
1688 #[cfg(feature = "unstable_plan_operations")]
1689 #[must_use]
1690 pub fn plan(mut self, plan: impl IntoOption<PlanCapabilities>) -> Self {
1691 self.plan = plan.into_option();
1692 self
1693 }
1694
1695 /// **UNSTABLE**
1696 ///
1697 /// This capability is not part of the spec yet, and may be removed or changed at any point.
1698 ///
1699 /// Authentication capabilities supported by the client.
1700 /// Determines which authentication method types the agent may include
1701 /// in its `InitializeResponse`.
1702 #[cfg(feature = "unstable_auth_methods")]
1703 #[must_use]
1704 pub fn auth(mut self, auth: AuthCapabilities) -> Self {
1705 self.auth = auth;
1706 self
1707 }
1708
1709 /// **UNSTABLE**
1710 ///
1711 /// This capability is not part of the spec yet, and may be removed or changed at any point.
1712 ///
1713 /// Elicitation capabilities supported by the client.
1714 /// Determines which elicitation modes the agent may use.
1715 #[cfg(feature = "unstable_elicitation")]
1716 #[must_use]
1717 pub fn elicitation(mut self, elicitation: impl IntoOption<ElicitationCapabilities>) -> Self {
1718 self.elicitation = elicitation.into_option();
1719 self
1720 }
1721
1722 /// **UNSTABLE**
1723 ///
1724 /// NES (Next Edit Suggestions) capabilities supported by the client.
1725 #[cfg(feature = "unstable_nes")]
1726 #[must_use]
1727 pub fn nes(mut self, nes: impl IntoOption<ClientNesCapabilities>) -> Self {
1728 self.nes = nes.into_option();
1729 self
1730 }
1731
1732 /// **UNSTABLE**
1733 ///
1734 /// The position encodings supported by the client, in order of preference.
1735 #[cfg(feature = "unstable_nes")]
1736 #[must_use]
1737 pub fn position_encodings(mut self, position_encodings: Vec<PositionEncodingKind>) -> Self {
1738 self.position_encodings = position_encodings;
1739 self
1740 }
1741
1742 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1743 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1744 /// these keys.
1745 ///
1746 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1747 #[must_use]
1748 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1749 self.meta = meta.into_option();
1750 self
1751 }
1752}
1753
1754/// **UNSTABLE**
1755///
1756/// This capability is not part of the spec yet, and may be removed or changed at any point.
1757///
1758/// Authentication capabilities supported by the client.
1759///
1760/// Advertised during initialization to inform the agent which authentication
1761/// method types the client can handle. This governs opt-in types that require
1762/// additional client-side support.
1763#[cfg(feature = "unstable_auth_methods")]
1764#[skip_serializing_none]
1765#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1766#[serde(rename_all = "camelCase")]
1767#[non_exhaustive]
1768pub struct AuthCapabilities {
1769 /// Whether the client supports `terminal` authentication methods.
1770 ///
1771 /// When `true`, the agent may include `terminal` entries in its authentication methods.
1772 #[serde(default)]
1773 pub terminal: bool,
1774 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1775 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1776 /// these keys.
1777 ///
1778 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1779 #[serde(rename = "_meta")]
1780 pub meta: Option<Meta>,
1781}
1782
1783#[cfg(feature = "unstable_auth_methods")]
1784impl AuthCapabilities {
1785 /// Builds an empty [`AuthCapabilities`]; use builder methods to advertise supported sub-capabilities.
1786 #[must_use]
1787 pub fn new() -> Self {
1788 Self::default()
1789 }
1790
1791 /// Whether the client supports `terminal` authentication methods.
1792 ///
1793 /// When `true`, the agent may include `AuthMethod::Terminal`
1794 /// entries in its authentication methods.
1795 #[must_use]
1796 pub fn terminal(mut self, terminal: bool) -> Self {
1797 self.terminal = terminal;
1798 self
1799 }
1800
1801 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1802 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1803 /// these keys.
1804 ///
1805 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1806 #[must_use]
1807 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1808 self.meta = meta.into_option();
1809 self
1810 }
1811}
1812
1813/// File system capabilities that a client may support.
1814///
1815/// See protocol docs: [FileSystem](https://agentclientprotocol.com/protocol/initialization#filesystem)
1816#[skip_serializing_none]
1817#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1818#[serde(rename_all = "camelCase")]
1819#[non_exhaustive]
1820pub struct FileSystemCapabilities {
1821 /// Whether the Client supports `fs/read_text_file` requests.
1822 #[serde(default)]
1823 pub read_text_file: bool,
1824 /// Whether the Client supports `fs/write_text_file` requests.
1825 #[serde(default)]
1826 pub write_text_file: bool,
1827 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1828 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1829 /// these keys.
1830 ///
1831 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1832 #[serde(rename = "_meta")]
1833 pub meta: Option<Meta>,
1834}
1835
1836impl FileSystemCapabilities {
1837 /// Builds an empty [`FileSystemCapabilities`]; use builder methods to advertise supported sub-capabilities.
1838 #[must_use]
1839 pub fn new() -> Self {
1840 Self::default()
1841 }
1842
1843 /// Whether the Client supports `fs/read_text_file` requests.
1844 #[must_use]
1845 pub fn read_text_file(mut self, read_text_file: bool) -> Self {
1846 self.read_text_file = read_text_file;
1847 self
1848 }
1849
1850 /// Whether the Client supports `fs/write_text_file` requests.
1851 #[must_use]
1852 pub fn write_text_file(mut self, write_text_file: bool) -> Self {
1853 self.write_text_file = write_text_file;
1854 self
1855 }
1856
1857 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1858 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1859 /// these keys.
1860 ///
1861 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1862 #[must_use]
1863 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1864 self.meta = meta.into_option();
1865 self
1866 }
1867}
1868
1869// Method schema
1870
1871/// Names of all methods that clients handle.
1872///
1873/// Provides a centralized definition of method names used in the protocol.
1874#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
1875#[non_exhaustive]
1876pub struct ClientMethodNames {
1877 /// Method for requesting permission from the user.
1878 pub session_request_permission: &'static str,
1879 /// Notification for session updates.
1880 pub session_update: &'static str,
1881 /// Method for writing text files.
1882 pub fs_write_text_file: &'static str,
1883 /// Method for reading text files.
1884 pub fs_read_text_file: &'static str,
1885 /// Method for creating new terminals.
1886 pub terminal_create: &'static str,
1887 /// Method for getting terminals output.
1888 pub terminal_output: &'static str,
1889 /// Method for releasing a terminal.
1890 pub terminal_release: &'static str,
1891 /// Method for waiting for a terminal to finish.
1892 pub terminal_wait_for_exit: &'static str,
1893 /// Method for killing a terminal.
1894 pub terminal_kill: &'static str,
1895 /// Method for opening an MCP-over-ACP connection.
1896 #[cfg(feature = "unstable_mcp_over_acp")]
1897 pub mcp_connect: &'static str,
1898 /// Method for exchanging MCP-over-ACP messages.
1899 #[cfg(feature = "unstable_mcp_over_acp")]
1900 pub mcp_message: &'static str,
1901 /// Method for closing an MCP-over-ACP connection.
1902 #[cfg(feature = "unstable_mcp_over_acp")]
1903 pub mcp_disconnect: &'static str,
1904 /// Method for elicitation.
1905 #[cfg(feature = "unstable_elicitation")]
1906 pub elicitation_create: &'static str,
1907 /// Notification for elicitation completion.
1908 #[cfg(feature = "unstable_elicitation")]
1909 pub elicitation_complete: &'static str,
1910}
1911
1912/// Constant containing all client method names.
1913pub const CLIENT_METHOD_NAMES: ClientMethodNames = ClientMethodNames {
1914 session_update: SESSION_UPDATE_NOTIFICATION,
1915 session_request_permission: SESSION_REQUEST_PERMISSION_METHOD_NAME,
1916 fs_write_text_file: FS_WRITE_TEXT_FILE_METHOD_NAME,
1917 fs_read_text_file: FS_READ_TEXT_FILE_METHOD_NAME,
1918 terminal_create: TERMINAL_CREATE_METHOD_NAME,
1919 terminal_output: TERMINAL_OUTPUT_METHOD_NAME,
1920 terminal_release: TERMINAL_RELEASE_METHOD_NAME,
1921 terminal_wait_for_exit: TERMINAL_WAIT_FOR_EXIT_METHOD_NAME,
1922 terminal_kill: TERMINAL_KILL_METHOD_NAME,
1923 #[cfg(feature = "unstable_mcp_over_acp")]
1924 mcp_connect: MCP_CONNECT_METHOD_NAME,
1925 #[cfg(feature = "unstable_mcp_over_acp")]
1926 mcp_message: MCP_MESSAGE_METHOD_NAME,
1927 #[cfg(feature = "unstable_mcp_over_acp")]
1928 mcp_disconnect: MCP_DISCONNECT_METHOD_NAME,
1929 #[cfg(feature = "unstable_elicitation")]
1930 elicitation_create: ELICITATION_CREATE_METHOD_NAME,
1931 #[cfg(feature = "unstable_elicitation")]
1932 elicitation_complete: ELICITATION_COMPLETE_NOTIFICATION,
1933};
1934
1935/// Notification name for session updates.
1936pub(crate) const SESSION_UPDATE_NOTIFICATION: &str = "session/update";
1937/// Method name for requesting user permission.
1938pub(crate) const SESSION_REQUEST_PERMISSION_METHOD_NAME: &str = "session/request_permission";
1939/// Method name for writing text files.
1940pub(crate) const FS_WRITE_TEXT_FILE_METHOD_NAME: &str = "fs/write_text_file";
1941/// Method name for reading text files.
1942pub(crate) const FS_READ_TEXT_FILE_METHOD_NAME: &str = "fs/read_text_file";
1943/// Method name for creating a new terminal.
1944pub(crate) const TERMINAL_CREATE_METHOD_NAME: &str = "terminal/create";
1945/// Method for getting terminals output.
1946pub(crate) const TERMINAL_OUTPUT_METHOD_NAME: &str = "terminal/output";
1947/// Method for releasing a terminal.
1948pub(crate) const TERMINAL_RELEASE_METHOD_NAME: &str = "terminal/release";
1949/// Method for waiting for a terminal to finish.
1950pub(crate) const TERMINAL_WAIT_FOR_EXIT_METHOD_NAME: &str = "terminal/wait_for_exit";
1951/// Method for killing a terminal.
1952pub(crate) const TERMINAL_KILL_METHOD_NAME: &str = "terminal/kill";
1953/// Method name for elicitation.
1954#[cfg(feature = "unstable_elicitation")]
1955pub(crate) const ELICITATION_CREATE_METHOD_NAME: &str = "elicitation/create";
1956/// Notification name for elicitation completion.
1957#[cfg(feature = "unstable_elicitation")]
1958pub(crate) const ELICITATION_COMPLETE_NOTIFICATION: &str = "elicitation/complete";
1959
1960/// All possible requests that an agent can send to a client.
1961///
1962/// This enum is used internally for routing RPC requests. You typically won't need
1963/// to use this directly.
1964///
1965/// This enum encompasses all method calls from agent to client.
1966#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
1967#[serde(untagged)]
1968#[schemars(inline)]
1969#[non_exhaustive]
1970#[allow(clippy::large_enum_variant)]
1971pub enum AgentRequest {
1972 /// Writes content to a text file in the client's file system.
1973 ///
1974 /// Only available if the client advertises the `fs.writeTextFile` capability.
1975 /// Allows the agent to create or modify files within the client's environment.
1976 ///
1977 /// See protocol docs: [Client](https://agentclientprotocol.com/protocol/overview#client)
1978 WriteTextFileRequest(WriteTextFileRequest),
1979 /// Reads content from a text file in the client's file system.
1980 ///
1981 /// Only available if the client advertises the `fs.readTextFile` capability.
1982 /// Allows the agent to access file contents within the client's environment.
1983 ///
1984 /// See protocol docs: [Client](https://agentclientprotocol.com/protocol/overview#client)
1985 ReadTextFileRequest(ReadTextFileRequest),
1986 /// Requests permission from the user for a tool call operation.
1987 ///
1988 /// Called by the agent when it needs user authorization before executing
1989 /// a potentially sensitive operation. The client should present the options
1990 /// to the user and return their decision.
1991 ///
1992 /// If the client cancels the prompt turn via `session/cancel`, it MUST
1993 /// respond to this request with `RequestPermissionOutcome::Cancelled`.
1994 ///
1995 /// See protocol docs: [Requesting Permission](https://agentclientprotocol.com/protocol/tool-calls#requesting-permission)
1996 RequestPermissionRequest(RequestPermissionRequest),
1997 /// Executes a command in a new terminal
1998 ///
1999 /// Only available if the `terminal` Client capability is set to `true`.
2000 ///
2001 /// Returns a `TerminalId` that can be used with other terminal methods
2002 /// to get the current output, wait for exit, and kill the command.
2003 ///
2004 /// The `TerminalId` can also be used to embed the terminal in a tool call
2005 /// by using the `ToolCallContent::Terminal` variant.
2006 ///
2007 /// The Agent is responsible for releasing the terminal by using the `terminal/release`
2008 /// method.
2009 ///
2010 /// See protocol docs: [Terminals](https://agentclientprotocol.com/protocol/terminals)
2011 CreateTerminalRequest(CreateTerminalRequest),
2012 /// Gets the terminal output and exit status
2013 ///
2014 /// Returns the current content in the terminal without waiting for the command to exit.
2015 /// If the command has already exited, the exit status is included.
2016 ///
2017 /// See protocol docs: [Terminals](https://agentclientprotocol.com/protocol/terminals)
2018 TerminalOutputRequest(TerminalOutputRequest),
2019 /// Releases a terminal
2020 ///
2021 /// The command is killed if it hasn't exited yet. Use `terminal/wait_for_exit`
2022 /// to wait for the command to exit before releasing the terminal.
2023 ///
2024 /// After release, the `TerminalId` can no longer be used with other `terminal/*` methods,
2025 /// but tool calls that already contain it, continue to display its output.
2026 ///
2027 /// The `terminal/kill` method can be used to terminate the command without releasing
2028 /// the terminal, allowing the Agent to call `terminal/output` and other methods.
2029 ///
2030 /// See protocol docs: [Terminals](https://agentclientprotocol.com/protocol/terminals)
2031 ReleaseTerminalRequest(ReleaseTerminalRequest),
2032 /// Waits for the terminal command to exit and return its exit status
2033 ///
2034 /// See protocol docs: [Terminals](https://agentclientprotocol.com/protocol/terminals)
2035 WaitForTerminalExitRequest(WaitForTerminalExitRequest),
2036 /// Kills the terminal command without releasing the terminal
2037 ///
2038 /// While `terminal/release` will also kill the command, this method will keep
2039 /// the `TerminalId` valid so it can be used with other methods.
2040 ///
2041 /// This method can be helpful when implementing command timeouts which terminate
2042 /// the command as soon as elapsed, and then get the final output so it can be sent
2043 /// to the model.
2044 ///
2045 /// Note: Call `terminal/release` when `TerminalId` is no longer needed.
2046 ///
2047 /// See protocol docs: [Terminals](https://agentclientprotocol.com/protocol/terminals)
2048 KillTerminalRequest(KillTerminalRequest),
2049 /// **UNSTABLE**
2050 ///
2051 /// This capability is not part of the spec yet, and may be removed or changed at any point.
2052 ///
2053 /// Requests structured user input via a form or URL.
2054 #[cfg(feature = "unstable_elicitation")]
2055 CreateElicitationRequest(CreateElicitationRequest),
2056 /// **UNSTABLE**
2057 ///
2058 /// This capability is not part of the spec yet, and may be removed or changed at any point.
2059 ///
2060 /// Opens an MCP-over-ACP connection.
2061 #[cfg(feature = "unstable_mcp_over_acp")]
2062 ConnectMcpRequest(ConnectMcpRequest),
2063 /// **UNSTABLE**
2064 ///
2065 /// This capability is not part of the spec yet, and may be removed or changed at any point.
2066 ///
2067 /// Exchanges an MCP-over-ACP message.
2068 #[cfg(feature = "unstable_mcp_over_acp")]
2069 MessageMcpRequest(MessageMcpRequest),
2070 /// **UNSTABLE**
2071 ///
2072 /// This capability is not part of the spec yet, and may be removed or changed at any point.
2073 ///
2074 /// Closes an MCP-over-ACP connection.
2075 #[cfg(feature = "unstable_mcp_over_acp")]
2076 DisconnectMcpRequest(DisconnectMcpRequest),
2077 /// Handles extension method requests from the agent.
2078 ///
2079 /// Allows the Agent to send an arbitrary request that is not part of the ACP spec.
2080 /// Extension methods provide a way to add custom functionality while maintaining
2081 /// protocol compatibility.
2082 ///
2083 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
2084 ExtMethodRequest(ExtRequest),
2085}
2086
2087impl AgentRequest {
2088 /// Returns the corresponding method name of the request.
2089 #[must_use]
2090 pub fn method(&self) -> &str {
2091 match self {
2092 Self::WriteTextFileRequest(_) => CLIENT_METHOD_NAMES.fs_write_text_file,
2093 Self::ReadTextFileRequest(_) => CLIENT_METHOD_NAMES.fs_read_text_file,
2094 Self::RequestPermissionRequest(_) => CLIENT_METHOD_NAMES.session_request_permission,
2095 Self::CreateTerminalRequest(_) => CLIENT_METHOD_NAMES.terminal_create,
2096 Self::TerminalOutputRequest(_) => CLIENT_METHOD_NAMES.terminal_output,
2097 Self::ReleaseTerminalRequest(_) => CLIENT_METHOD_NAMES.terminal_release,
2098 Self::WaitForTerminalExitRequest(_) => CLIENT_METHOD_NAMES.terminal_wait_for_exit,
2099 Self::KillTerminalRequest(_) => CLIENT_METHOD_NAMES.terminal_kill,
2100 #[cfg(feature = "unstable_elicitation")]
2101 Self::CreateElicitationRequest(_) => CLIENT_METHOD_NAMES.elicitation_create,
2102 #[cfg(feature = "unstable_mcp_over_acp")]
2103 Self::ConnectMcpRequest(_) => CLIENT_METHOD_NAMES.mcp_connect,
2104 #[cfg(feature = "unstable_mcp_over_acp")]
2105 Self::MessageMcpRequest(_) => CLIENT_METHOD_NAMES.mcp_message,
2106 #[cfg(feature = "unstable_mcp_over_acp")]
2107 Self::DisconnectMcpRequest(_) => CLIENT_METHOD_NAMES.mcp_disconnect,
2108 Self::ExtMethodRequest(ext_request) => &ext_request.method,
2109 }
2110 }
2111}
2112
2113/// All possible responses that a client can send to an agent.
2114///
2115/// This enum is used internally for routing RPC responses. You typically won't need
2116/// to use this directly - the responses are handled automatically by the connection.
2117///
2118/// These are responses to the corresponding `AgentRequest` variants.
2119#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
2120#[serde(untagged)]
2121#[schemars(inline)]
2122#[non_exhaustive]
2123pub enum ClientResponse {
2124 /// Successful result returned for a `fs/write_text_file` request.
2125 WriteTextFileResponse(#[serde(default)] WriteTextFileResponse),
2126 /// Successful result returned for a `fs/read_text_file` request.
2127 ReadTextFileResponse(ReadTextFileResponse),
2128 /// Successful result returned for a `session/request_permission` request.
2129 RequestPermissionResponse(RequestPermissionResponse),
2130 /// Successful result returned for a `terminal/create` request.
2131 CreateTerminalResponse(CreateTerminalResponse),
2132 /// Successful result returned for a `terminal/output` request.
2133 TerminalOutputResponse(TerminalOutputResponse),
2134 /// Successful result returned for a `terminal/release` request.
2135 ReleaseTerminalResponse(#[serde(default)] ReleaseTerminalResponse),
2136 /// Successful result returned for a `terminal/wait_for_exit` request.
2137 WaitForTerminalExitResponse(WaitForTerminalExitResponse),
2138 /// Successful result returned for a `terminal/kill` request.
2139 KillTerminalResponse(#[serde(default)] KillTerminalResponse),
2140 /// Successful result returned for a `elicitation/create` request.
2141 #[cfg(feature = "unstable_elicitation")]
2142 CreateElicitationResponse(CreateElicitationResponse),
2143 /// Successful result returned for a `mcp/connect` request.
2144 #[cfg(feature = "unstable_mcp_over_acp")]
2145 ConnectMcpResponse(ConnectMcpResponse),
2146 /// Successful result returned for a `mcp/disconnect` request.
2147 #[cfg(feature = "unstable_mcp_over_acp")]
2148 DisconnectMcpResponse(#[serde(default)] DisconnectMcpResponse),
2149 /// Successful result returned by an extension method outside the core ACP method set.
2150 ExtMethodResponse(ExtResponse),
2151 /// Successful result returned by an MCP-over-ACP `mcp/message` request.
2152 #[cfg(feature = "unstable_mcp_over_acp")]
2153 MessageMcpResponse(MessageMcpResponse),
2154}
2155
2156/// All possible notifications that an agent can send to a client.
2157///
2158/// This enum is used internally for routing RPC notifications. You typically won't need
2159/// to use this directly.
2160///
2161/// Notifications do not expect a response.
2162#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
2163#[serde(untagged)]
2164#[expect(clippy::large_enum_variant)]
2165#[schemars(inline)]
2166#[non_exhaustive]
2167pub enum AgentNotification {
2168 /// Handles session update notifications from the agent.
2169 ///
2170 /// This is a notification endpoint (no response expected) that receives
2171 /// real-time updates about session progress, including message chunks,
2172 /// tool calls, and execution plans.
2173 ///
2174 /// Note: Clients SHOULD continue accepting tool call updates even after
2175 /// sending a `session/cancel` notification, as the agent may send final
2176 /// updates before responding with the cancelled stop reason.
2177 ///
2178 /// See protocol docs: [Agent Reports Output](https://agentclientprotocol.com/protocol/prompt-turn#3-agent-reports-output)
2179 SessionNotification(SessionNotification),
2180 /// **UNSTABLE**
2181 ///
2182 /// This capability is not part of the spec yet, and may be removed or changed at any point.
2183 ///
2184 /// Notification that a URL-based elicitation has completed.
2185 #[cfg(feature = "unstable_elicitation")]
2186 CompleteElicitationNotification(CompleteElicitationNotification),
2187 /// **UNSTABLE**
2188 ///
2189 /// This capability is not part of the spec yet, and may be removed or changed at any point.
2190 ///
2191 /// Receives an MCP-over-ACP notification.
2192 #[cfg(feature = "unstable_mcp_over_acp")]
2193 MessageMcpNotification(MessageMcpNotification),
2194 /// Handles extension notifications from the agent.
2195 ///
2196 /// Allows the Agent to send an arbitrary notification that is not part of the ACP spec.
2197 /// Extension notifications provide a way to send one-way messages for custom functionality
2198 /// while maintaining protocol compatibility.
2199 ///
2200 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
2201 ExtNotification(ExtNotification),
2202}
2203
2204impl AgentNotification {
2205 /// Returns the corresponding method name of the notification.
2206 #[must_use]
2207 pub fn method(&self) -> &str {
2208 match self {
2209 Self::SessionNotification(_) => CLIENT_METHOD_NAMES.session_update,
2210 #[cfg(feature = "unstable_elicitation")]
2211 Self::CompleteElicitationNotification(_) => CLIENT_METHOD_NAMES.elicitation_complete,
2212 #[cfg(feature = "unstable_mcp_over_acp")]
2213 Self::MessageMcpNotification(_) => CLIENT_METHOD_NAMES.mcp_message,
2214 Self::ExtNotification(ext_notification) => &ext_notification.method,
2215 }
2216 }
2217}
2218
2219#[cfg(test)]
2220mod tests {
2221 use super::*;
2222
2223 #[test]
2224 fn test_serialization_behavior() {
2225 use serde_json::json;
2226
2227 assert_eq!(
2228 serde_json::from_value::<SessionInfoUpdate>(json!({})).unwrap(),
2229 SessionInfoUpdate {
2230 title: MaybeUndefined::Undefined,
2231 updated_at: MaybeUndefined::Undefined,
2232 meta: None
2233 }
2234 );
2235 assert_eq!(
2236 serde_json::from_value::<SessionInfoUpdate>(json!({"title": null, "updatedAt": null}))
2237 .unwrap(),
2238 SessionInfoUpdate {
2239 title: MaybeUndefined::Null,
2240 updated_at: MaybeUndefined::Null,
2241 meta: None
2242 }
2243 );
2244 assert_eq!(
2245 serde_json::from_value::<SessionInfoUpdate>(
2246 json!({"title": "title", "updatedAt": "timestamp"})
2247 )
2248 .unwrap(),
2249 SessionInfoUpdate {
2250 title: MaybeUndefined::Value("title".to_string()),
2251 updated_at: MaybeUndefined::Value("timestamp".to_string()),
2252 meta: None
2253 }
2254 );
2255
2256 assert_eq!(
2257 serde_json::to_value(SessionInfoUpdate::new()).unwrap(),
2258 json!({})
2259 );
2260 assert_eq!(
2261 serde_json::to_value(SessionInfoUpdate::new().title("title")).unwrap(),
2262 json!({"title": "title"})
2263 );
2264 assert_eq!(
2265 serde_json::to_value(SessionInfoUpdate::new().title(None)).unwrap(),
2266 json!({"title": null})
2267 );
2268 assert_eq!(
2269 serde_json::to_value(
2270 SessionInfoUpdate::new()
2271 .title("title")
2272 .title(MaybeUndefined::Undefined)
2273 )
2274 .unwrap(),
2275 json!({})
2276 );
2277 }
2278
2279 #[test]
2280 fn test_content_chunk_message_id_serialization() {
2281 use serde_json::json;
2282
2283 assert_eq!(
2284 serde_json::to_value(SessionUpdate::AgentMessageChunk(ContentChunk::new(
2285 ContentBlock::Text(crate::v1::TextContent::new("Hello"))
2286 )))
2287 .unwrap(),
2288 json!({
2289 "sessionUpdate": "agent_message_chunk",
2290 "content": {
2291 "type": "text",
2292 "text": "Hello"
2293 }
2294 })
2295 );
2296
2297 assert_eq!(
2298 serde_json::to_value(SessionUpdate::AgentMessageChunk(
2299 ContentChunk::new(ContentBlock::Text(crate::v1::TextContent::new("Hello")))
2300 .message_id("msg_agent_c42b9")
2301 ))
2302 .unwrap(),
2303 json!({
2304 "sessionUpdate": "agent_message_chunk",
2305 "messageId": "msg_agent_c42b9",
2306 "content": {
2307 "type": "text",
2308 "text": "Hello"
2309 }
2310 })
2311 );
2312
2313 let SessionUpdate::AgentMessageChunk(chunk) = serde_json::from_value(json!({
2314 "sessionUpdate": "agent_message_chunk",
2315 "messageId": null,
2316 "content": {
2317 "type": "text",
2318 "text": "Hello"
2319 }
2320 }))
2321 .unwrap() else {
2322 panic!("expected agent message chunk");
2323 };
2324
2325 assert_eq!(chunk.message_id, None);
2326 }
2327
2328 #[test]
2329 fn test_usage_update_serialization() {
2330 use serde_json::json;
2331
2332 assert_eq!(
2333 serde_json::to_value(SessionUpdate::UsageUpdate(UsageUpdate::new(
2334 53_000, 200_000
2335 )))
2336 .unwrap(),
2337 json!({
2338 "sessionUpdate": "usage_update",
2339 "used": 53000,
2340 "size": 200_000
2341 })
2342 );
2343
2344 assert_eq!(
2345 serde_json::to_value(SessionUpdate::UsageUpdate(
2346 UsageUpdate::new(53_000, 200_000).cost(Cost::new(0.045, "USD"))
2347 ))
2348 .unwrap(),
2349 json!({
2350 "sessionUpdate": "usage_update",
2351 "used": 53000,
2352 "size": 200_000,
2353 "cost": {
2354 "amount": 0.045,
2355 "currency": "USD"
2356 }
2357 })
2358 );
2359
2360 let SessionUpdate::UsageUpdate(update) = serde_json::from_value(json!({
2361 "sessionUpdate": "usage_update",
2362 "used": 53000,
2363 "size": 200_000,
2364 "cost": null
2365 }))
2366 .unwrap() else {
2367 panic!("expected usage update");
2368 };
2369
2370 assert_eq!(update.cost, None);
2371 }
2372
2373 #[cfg(feature = "unstable_nes")]
2374 #[test]
2375 fn test_client_capabilities_position_encodings_serialization() {
2376 use serde_json::json;
2377
2378 let capabilities = ClientCapabilities::new().position_encodings(vec![
2379 PositionEncodingKind::Utf32,
2380 PositionEncodingKind::Utf16,
2381 ]);
2382 let json = serde_json::to_value(&capabilities).unwrap();
2383
2384 assert_eq!(json["positionEncodings"], json!(["utf-32", "utf-16"]));
2385 }
2386
2387 #[cfg(feature = "unstable_plan_operations")]
2388 #[test]
2389 fn test_plan_operations_serialization() {
2390 use serde_json::json;
2391
2392 use crate::v1::{PlanEntry, PlanEntryPriority, PlanEntryStatus, PlanUpdateContent};
2393
2394 let plan_update = SessionUpdate::PlanUpdate(PlanUpdate::new(PlanUpdateContent::items(
2395 "plan-1",
2396 vec![PlanEntry::new(
2397 "Step 1",
2398 PlanEntryPriority::High,
2399 PlanEntryStatus::Pending,
2400 )],
2401 )));
2402
2403 assert_eq!(
2404 serde_json::to_value(plan_update).unwrap(),
2405 json!({
2406 "sessionUpdate": "plan_update",
2407 "plan": {
2408 "type": "items",
2409 "id": "plan-1",
2410 "entries": [
2411 {
2412 "content": "Step 1",
2413 "priority": "high",
2414 "status": "pending"
2415 }
2416 ]
2417 }
2418 })
2419 );
2420
2421 assert_eq!(
2422 serde_json::to_value(SessionUpdate::PlanRemoved(PlanRemoved::new("plan-1"))).unwrap(),
2423 json!({
2424 "sessionUpdate": "plan_removed",
2425 "id": "plan-1"
2426 })
2427 );
2428
2429 let capabilities = ClientCapabilities::new().plan(PlanCapabilities::new());
2430 let json = serde_json::to_value(&capabilities).unwrap();
2431 assert_eq!(json["plan"], json!({}));
2432
2433 assert_eq!(
2434 serde_json::from_value::<ClientCapabilities>(json!({ "plan": null }))
2435 .unwrap()
2436 .plan,
2437 None
2438 );
2439 }
2440
2441 #[cfg(feature = "unstable_mcp_over_acp")]
2442 #[test]
2443 fn test_agent_mcp_request_method_names() {
2444 use serde_json::json;
2445
2446 let params: serde_json::Map<String, serde_json::Value> =
2447 [("cursor".to_string(), json!("abc"))].into_iter().collect();
2448
2449 assert_eq!(CLIENT_METHOD_NAMES.mcp_connect, "mcp/connect");
2450 assert_eq!(CLIENT_METHOD_NAMES.mcp_message, "mcp/message");
2451 assert_eq!(CLIENT_METHOD_NAMES.mcp_disconnect, "mcp/disconnect");
2452
2453 assert_eq!(
2454 AgentRequest::ConnectMcpRequest(ConnectMcpRequest::new("server-1")).method(),
2455 "mcp/connect"
2456 );
2457 assert_eq!(
2458 AgentRequest::MessageMcpRequest(MessageMcpRequest::new("conn-1", "tools/list"))
2459 .method(),
2460 "mcp/message"
2461 );
2462 assert_eq!(
2463 AgentRequest::DisconnectMcpRequest(DisconnectMcpRequest::new("conn-1")).method(),
2464 "mcp/disconnect"
2465 );
2466 assert_eq!(
2467 AgentNotification::MessageMcpNotification(MessageMcpNotification::new(
2468 "conn-1",
2469 "notifications/progress"
2470 ))
2471 .method(),
2472 "mcp/message"
2473 );
2474
2475 assert_eq!(
2476 serde_json::to_value(ConnectMcpRequest::new("server-1")).unwrap(),
2477 json!({ "acpId": "server-1" })
2478 );
2479 assert_eq!(
2480 serde_json::to_value(ConnectMcpResponse::new("conn-1")).unwrap(),
2481 json!({ "connectionId": "conn-1" })
2482 );
2483 assert_eq!(
2484 serde_json::to_value(MessageMcpRequest::new("conn-1", "tools/list").params(params))
2485 .unwrap(),
2486 json!({
2487 "connectionId": "conn-1",
2488 "method": "tools/list",
2489 "params": { "cursor": "abc" }
2490 })
2491 );
2492 assert_eq!(
2493 serde_json::to_value(DisconnectMcpRequest::new("conn-1")).unwrap(),
2494 json!({ "connectionId": "conn-1" })
2495 );
2496 assert_eq!(
2497 serde_json::to_value(MessageMcpNotification::new(
2498 "conn-1",
2499 "notifications/progress"
2500 ))
2501 .unwrap(),
2502 json!({
2503 "connectionId": "conn-1",
2504 "method": "notifications/progress"
2505 })
2506 );
2507
2508 let request_with_null_params: MessageMcpRequest = serde_json::from_value(json!({
2509 "connectionId": "conn-1",
2510 "method": "tools/list",
2511 "params": null
2512 }))
2513 .unwrap();
2514 assert_eq!(request_with_null_params.params, None);
2515 }
2516}