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