agent_client_protocol_schema/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};
11
12use crate::{
13 ContentBlock, ExtNotification, ExtRequest, ExtResponse, IntoOption, Meta, Plan, SessionId,
14 SessionModeId, ToolCall, ToolCallUpdate,
15};
16
17// Session updates
18
19/// Notification containing a session update from the agent.
20///
21/// Used to stream real-time progress and results during prompt processing.
22///
23/// See protocol docs: [Agent Reports Output](https://agentclientprotocol.com/protocol/prompt-turn#3-agent-reports-output)
24#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq)]
25#[schemars(extend("x-side" = "client", "x-method" = SESSION_UPDATE_NOTIFICATION))]
26#[serde(rename_all = "camelCase")]
27#[non_exhaustive]
28pub struct SessionNotification {
29 /// The ID of the session this update pertains to.
30 pub session_id: SessionId,
31 /// The actual update content.
32 pub update: SessionUpdate,
33 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
34 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
35 /// these keys.
36 ///
37 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
38 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
39 pub meta: Option<Meta>,
40}
41
42impl SessionNotification {
43 #[must_use]
44 pub fn new(session_id: impl Into<SessionId>, update: SessionUpdate) -> Self {
45 Self {
46 session_id: session_id.into(),
47 update,
48 meta: None,
49 }
50 }
51
52 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
53 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
54 /// these keys.
55 ///
56 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
57 #[must_use]
58 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
59 self.meta = meta.into_option();
60 self
61 }
62}
63
64/// Different types of updates that can be sent during session processing.
65///
66/// These updates provide real-time feedback about the agent's progress.
67///
68/// See protocol docs: [Agent Reports Output](https://agentclientprotocol.com/protocol/prompt-turn#3-agent-reports-output)
69#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq)]
70#[serde(tag = "sessionUpdate", rename_all = "snake_case")]
71#[schemars(extend("discriminator" = {"propertyName": "sessionUpdate"}))]
72#[non_exhaustive]
73pub enum SessionUpdate {
74 /// A chunk of the user's message being streamed.
75 UserMessageChunk(ContentChunk),
76 /// A chunk of the agent's response being streamed.
77 AgentMessageChunk(ContentChunk),
78 /// A chunk of the agent's internal reasoning being streamed.
79 AgentThoughtChunk(ContentChunk),
80 /// Notification that a new tool call has been initiated.
81 ToolCall(ToolCall),
82 /// Update on the status or results of a tool call.
83 ToolCallUpdate(ToolCallUpdate),
84 /// The agent's execution plan for complex tasks.
85 /// See protocol docs: [Agent Plan](https://agentclientprotocol.com/protocol/agent-plan)
86 Plan(Plan),
87 /// Available commands are ready or have changed
88 AvailableCommandsUpdate(AvailableCommandsUpdate),
89 /// The current mode of the session has changed
90 ///
91 /// See protocol docs: [Session Modes](https://agentclientprotocol.com/protocol/session-modes)
92 CurrentModeUpdate(CurrentModeUpdate),
93}
94
95/// The current mode of the session has changed
96///
97/// See protocol docs: [Session Modes](https://agentclientprotocol.com/protocol/session-modes)
98#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
99#[serde(rename_all = "camelCase")]
100#[non_exhaustive]
101pub struct CurrentModeUpdate {
102 /// The ID of the current mode
103 pub current_mode_id: SessionModeId,
104 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
105 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
106 /// these keys.
107 ///
108 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
109 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
110 pub meta: Option<Meta>,
111}
112
113impl CurrentModeUpdate {
114 #[must_use]
115 pub fn new(current_mode_id: impl Into<SessionModeId>) -> Self {
116 Self {
117 current_mode_id: current_mode_id.into(),
118 meta: None,
119 }
120 }
121
122 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
123 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
124 /// these keys.
125 ///
126 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
127 #[must_use]
128 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
129 self.meta = meta.into_option();
130 self
131 }
132}
133
134/// A streamed item of content
135#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq)]
136#[serde(rename_all = "camelCase")]
137#[non_exhaustive]
138pub struct ContentChunk {
139 /// A single item of content
140 pub content: ContentBlock,
141 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
142 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
143 /// these keys.
144 ///
145 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
146 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
147 pub meta: Option<Meta>,
148}
149
150impl ContentChunk {
151 #[must_use]
152 pub fn new(content: ContentBlock) -> Self {
153 Self {
154 content,
155 meta: None,
156 }
157 }
158
159 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
160 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
161 /// these keys.
162 ///
163 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
164 #[must_use]
165 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
166 self.meta = meta.into_option();
167 self
168 }
169}
170
171/// Available commands are ready or have changed
172#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
173#[serde(rename_all = "camelCase")]
174#[non_exhaustive]
175pub struct AvailableCommandsUpdate {
176 /// Commands the agent can execute
177 pub available_commands: Vec<AvailableCommand>,
178 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
179 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
180 /// these keys.
181 ///
182 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
183 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
184 pub meta: Option<Meta>,
185}
186
187impl AvailableCommandsUpdate {
188 #[must_use]
189 pub fn new(available_commands: Vec<AvailableCommand>) -> Self {
190 Self {
191 available_commands,
192 meta: None,
193 }
194 }
195
196 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
197 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
198 /// these keys.
199 ///
200 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
201 #[must_use]
202 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
203 self.meta = meta.into_option();
204 self
205 }
206}
207
208/// Information about a command.
209#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
210#[serde(rename_all = "camelCase")]
211#[non_exhaustive]
212pub struct AvailableCommand {
213 /// Command name (e.g., `create_plan`, `research_codebase`).
214 pub name: String,
215 /// Human-readable description of what the command does.
216 pub description: String,
217 /// Input for the command if required
218 pub input: Option<AvailableCommandInput>,
219 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
220 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
221 /// these keys.
222 ///
223 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
224 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
225 pub meta: Option<Meta>,
226}
227
228impl AvailableCommand {
229 pub fn new(name: impl Into<String>, description: impl Into<String>) -> Self {
230 Self {
231 name: name.into(),
232 description: description.into(),
233 input: None,
234 meta: None,
235 }
236 }
237
238 /// Input for the command if required
239 #[must_use]
240 pub fn input(mut self, input: impl IntoOption<AvailableCommandInput>) -> Self {
241 self.input = input.into_option();
242 self
243 }
244
245 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
246 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
247 /// these keys.
248 ///
249 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
250 #[must_use]
251 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
252 self.meta = meta.into_option();
253 self
254 }
255}
256
257/// The input specification for a command.
258#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
259#[serde(untagged, rename_all = "camelCase")]
260#[non_exhaustive]
261pub enum AvailableCommandInput {
262 /// All text that was typed after the command name is provided as input.
263 Unstructured(UnstructuredCommandInput),
264}
265
266/// All text that was typed after the command name is provided as input.
267#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
268#[serde(rename_all = "camelCase")]
269#[non_exhaustive]
270pub struct UnstructuredCommandInput {
271 /// A hint to display when the input hasn't been provided yet
272 pub hint: String,
273 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
274 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
275 /// these keys.
276 ///
277 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
278 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
279 pub meta: Option<Meta>,
280}
281
282impl UnstructuredCommandInput {
283 pub fn new(hint: impl Into<String>) -> Self {
284 Self {
285 hint: hint.into(),
286 meta: None,
287 }
288 }
289
290 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
291 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
292 /// these keys.
293 ///
294 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
295 #[must_use]
296 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
297 self.meta = meta.into_option();
298 self
299 }
300}
301
302// Permission
303
304/// Request for user permission to execute a tool call.
305///
306/// Sent when the agent needs authorization before performing a sensitive operation.
307///
308/// See protocol docs: [Requesting Permission](https://agentclientprotocol.com/protocol/tool-calls#requesting-permission)
309#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq)]
310#[schemars(extend("x-side" = "client", "x-method" = SESSION_REQUEST_PERMISSION_METHOD_NAME))]
311#[serde(rename_all = "camelCase")]
312#[non_exhaustive]
313pub struct RequestPermissionRequest {
314 /// The session ID for this request.
315 pub session_id: SessionId,
316 /// Details about the tool call requiring permission.
317 pub tool_call: ToolCallUpdate,
318 /// Available permission options for the user to choose from.
319 pub options: Vec<PermissionOption>,
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 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
326 pub meta: Option<Meta>,
327}
328
329impl RequestPermissionRequest {
330 #[must_use]
331 pub fn new(
332 session_id: impl Into<SessionId>,
333 tool_call: ToolCallUpdate,
334 options: Vec<PermissionOption>,
335 ) -> Self {
336 Self {
337 session_id: session_id.into(),
338 tool_call,
339 options,
340 meta: None,
341 }
342 }
343
344 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
345 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
346 /// these keys.
347 ///
348 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
349 #[must_use]
350 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
351 self.meta = meta.into_option();
352 self
353 }
354}
355
356/// An option presented to the user when requesting permission.
357#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
358#[serde(rename_all = "camelCase")]
359#[non_exhaustive]
360pub struct PermissionOption {
361 /// Unique identifier for this permission option.
362 pub option_id: PermissionOptionId,
363 /// Human-readable label to display to the user.
364 pub name: String,
365 /// Hint about the nature of this permission option.
366 pub kind: PermissionOptionKind,
367 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
368 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
369 /// these keys.
370 ///
371 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
372 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
373 pub meta: Option<Meta>,
374}
375
376impl PermissionOption {
377 pub fn new(
378 option_id: impl Into<PermissionOptionId>,
379 name: impl Into<String>,
380 kind: PermissionOptionKind,
381 ) -> Self {
382 Self {
383 option_id: option_id.into(),
384 name: name.into(),
385 kind,
386 meta: None,
387 }
388 }
389
390 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
391 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
392 /// these keys.
393 ///
394 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
395 #[must_use]
396 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
397 self.meta = meta.into_option();
398 self
399 }
400}
401
402/// Unique identifier for a permission option.
403#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq, Hash, Display, From)]
404#[serde(transparent)]
405#[from(Arc<str>, String, &'static str)]
406#[non_exhaustive]
407pub struct PermissionOptionId(pub Arc<str>);
408
409impl PermissionOptionId {
410 pub fn new(id: impl Into<Arc<str>>) -> Self {
411 Self(id.into())
412 }
413}
414
415/// The type of permission option being presented to the user.
416///
417/// Helps clients choose appropriate icons and UI treatment.
418#[derive(Debug, Clone, Copy, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
419#[serde(rename_all = "snake_case")]
420#[non_exhaustive]
421pub enum PermissionOptionKind {
422 /// Allow this operation only this time.
423 AllowOnce,
424 /// Allow this operation and remember the choice.
425 AllowAlways,
426 /// Reject this operation only this time.
427 RejectOnce,
428 /// Reject this operation and remember the choice.
429 RejectAlways,
430}
431
432/// Response to a permission request.
433#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
434#[schemars(extend("x-side" = "client", "x-method" = SESSION_REQUEST_PERMISSION_METHOD_NAME))]
435#[serde(rename_all = "camelCase")]
436#[non_exhaustive]
437pub struct RequestPermissionResponse {
438 /// The user's decision on the permission request.
439 // This extra-level is unfortunately needed because the output must be an object
440 pub outcome: RequestPermissionOutcome,
441 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
442 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
443 /// these keys.
444 ///
445 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
446 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
447 pub meta: Option<Meta>,
448}
449
450impl RequestPermissionResponse {
451 #[must_use]
452 pub fn new(outcome: RequestPermissionOutcome) -> Self {
453 Self {
454 outcome,
455 meta: None,
456 }
457 }
458
459 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
460 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
461 /// these keys.
462 ///
463 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
464 #[must_use]
465 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
466 self.meta = meta.into_option();
467 self
468 }
469}
470
471/// The outcome of a permission request.
472#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
473#[serde(tag = "outcome", rename_all = "snake_case")]
474#[schemars(extend("discriminator" = {"propertyName": "outcome"}))]
475#[non_exhaustive]
476pub enum RequestPermissionOutcome {
477 /// The prompt turn was cancelled before the user responded.
478 ///
479 /// When a client sends a `session/cancel` notification to cancel an ongoing
480 /// prompt turn, it MUST respond to all pending `session/request_permission`
481 /// requests with this `Cancelled` outcome.
482 ///
483 /// See protocol docs: [Cancellation](https://agentclientprotocol.com/protocol/prompt-turn#cancellation)
484 Cancelled,
485 /// The user selected one of the provided options.
486 #[serde(rename_all = "camelCase")]
487 Selected(SelectedPermissionOutcome),
488}
489
490/// The user selected one of the provided options.
491#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
492#[serde(rename_all = "camelCase")]
493#[non_exhaustive]
494pub struct SelectedPermissionOutcome {
495 /// The ID of the option the user selected.
496 pub option_id: PermissionOptionId,
497 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
498 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
499 /// these keys.
500 ///
501 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
502 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
503 pub meta: Option<Meta>,
504}
505
506impl SelectedPermissionOutcome {
507 #[must_use]
508 pub fn new(option_id: impl Into<PermissionOptionId>) -> Self {
509 Self {
510 option_id: option_id.into(),
511 meta: None,
512 }
513 }
514
515 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
516 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
517 /// these keys.
518 ///
519 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
520 #[must_use]
521 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
522 self.meta = meta.into_option();
523 self
524 }
525}
526
527// Write text file
528
529/// Request to write content to a text file.
530///
531/// Only available if the client supports the `fs.writeTextFile` capability.
532#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
533#[schemars(extend("x-side" = "client", "x-method" = FS_WRITE_TEXT_FILE_METHOD_NAME))]
534#[serde(rename_all = "camelCase")]
535#[non_exhaustive]
536pub struct WriteTextFileRequest {
537 /// The session ID for this request.
538 pub session_id: SessionId,
539 /// Absolute path to the file to write.
540 pub path: PathBuf,
541 /// The text content to write to the file.
542 pub content: String,
543 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
544 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
545 /// these keys.
546 ///
547 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
548 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
549 pub meta: Option<Meta>,
550}
551
552impl WriteTextFileRequest {
553 pub fn new(
554 session_id: impl Into<SessionId>,
555 path: impl Into<PathBuf>,
556 content: impl Into<String>,
557 ) -> Self {
558 Self {
559 session_id: session_id.into(),
560 path: path.into(),
561 content: content.into(),
562 meta: None,
563 }
564 }
565
566 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
567 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
568 /// these keys.
569 ///
570 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
571 #[must_use]
572 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
573 self.meta = meta.into_option();
574 self
575 }
576}
577
578/// Response to `fs/write_text_file`
579#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
580#[serde(default, rename_all = "camelCase")]
581#[schemars(extend("x-side" = "client", "x-method" = FS_WRITE_TEXT_FILE_METHOD_NAME))]
582#[non_exhaustive]
583pub struct WriteTextFileResponse {
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 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
590 pub meta: Option<Meta>,
591}
592
593impl WriteTextFileResponse {
594 #[must_use]
595 pub fn new() -> Self {
596 Self::default()
597 }
598
599 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
600 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
601 /// these keys.
602 ///
603 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
604 #[must_use]
605 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
606 self.meta = meta.into_option();
607 self
608 }
609}
610
611// Read text file
612
613/// Request to read content from a text file.
614///
615/// Only available if the client supports the `fs.readTextFile` capability.
616#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
617#[schemars(extend("x-side" = "client", "x-method" = FS_READ_TEXT_FILE_METHOD_NAME))]
618#[serde(rename_all = "camelCase")]
619#[non_exhaustive]
620pub struct ReadTextFileRequest {
621 /// The session ID for this request.
622 pub session_id: SessionId,
623 /// Absolute path to the file to read.
624 pub path: PathBuf,
625 /// Line number to start reading from (1-based).
626 #[serde(skip_serializing_if = "Option::is_none")]
627 pub line: Option<u32>,
628 /// Maximum number of lines to read.
629 #[serde(skip_serializing_if = "Option::is_none")]
630 pub limit: Option<u32>,
631 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
632 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
633 /// these keys.
634 ///
635 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
636 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
637 pub meta: Option<Meta>,
638}
639
640impl ReadTextFileRequest {
641 pub fn new(session_id: impl Into<SessionId>, path: impl Into<PathBuf>) -> Self {
642 Self {
643 session_id: session_id.into(),
644 path: path.into(),
645 line: None,
646 limit: None,
647 meta: None,
648 }
649 }
650
651 /// Line number to start reading from (1-based).
652 #[must_use]
653 pub fn line(mut self, line: impl IntoOption<u32>) -> Self {
654 self.line = line.into_option();
655 self
656 }
657
658 /// Maximum number of lines to read.
659 #[must_use]
660 pub fn limit(mut self, limit: impl IntoOption<u32>) -> Self {
661 self.limit = limit.into_option();
662 self
663 }
664
665 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
666 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
667 /// these keys.
668 ///
669 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
670 #[must_use]
671 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
672 self.meta = meta.into_option();
673 self
674 }
675}
676
677/// Response containing the contents of a text file.
678#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
679#[schemars(extend("x-side" = "client", "x-method" = FS_READ_TEXT_FILE_METHOD_NAME))]
680#[serde(rename_all = "camelCase")]
681#[non_exhaustive]
682pub struct ReadTextFileResponse {
683 pub content: String,
684 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
685 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
686 /// these keys.
687 ///
688 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
689 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
690 pub meta: Option<Meta>,
691}
692
693impl ReadTextFileResponse {
694 pub fn new(content: impl Into<String>) -> Self {
695 Self {
696 content: content.into(),
697 meta: None,
698 }
699 }
700
701 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
702 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
703 /// these keys.
704 ///
705 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
706 #[must_use]
707 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
708 self.meta = meta.into_option();
709 self
710 }
711}
712
713// Terminals
714
715#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq, Hash, Display, From)]
716#[serde(transparent)]
717#[from(Arc<str>, String, &'static str)]
718#[non_exhaustive]
719pub struct TerminalId(pub Arc<str>);
720
721impl TerminalId {
722 pub fn new(id: impl Into<Arc<str>>) -> Self {
723 Self(id.into())
724 }
725}
726
727/// Request to create a new terminal and execute a command.
728#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
729#[serde(rename_all = "camelCase")]
730#[schemars(extend("x-side" = "client", "x-method" = TERMINAL_CREATE_METHOD_NAME))]
731#[non_exhaustive]
732pub struct CreateTerminalRequest {
733 /// The session ID for this request.
734 pub session_id: SessionId,
735 /// The command to execute.
736 pub command: String,
737 /// Array of command arguments.
738 #[serde(default, skip_serializing_if = "Vec::is_empty")]
739 pub args: Vec<String>,
740 /// Environment variables for the command.
741 #[serde(default, skip_serializing_if = "Vec::is_empty")]
742 pub env: Vec<crate::EnvVariable>,
743 /// Working directory for the command (absolute path).
744 #[serde(skip_serializing_if = "Option::is_none")]
745 pub cwd: Option<PathBuf>,
746 /// Maximum number of output bytes to retain.
747 ///
748 /// When the limit is exceeded, the Client truncates from the beginning of the output
749 /// to stay within the limit.
750 ///
751 /// The Client MUST ensure truncation happens at a character boundary to maintain valid
752 /// string output, even if this means the retained output is slightly less than the
753 /// specified limit.
754 #[serde(skip_serializing_if = "Option::is_none")]
755 pub output_byte_limit: Option<u64>,
756 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
757 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
758 /// these keys.
759 ///
760 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
761 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
762 pub meta: Option<Meta>,
763}
764
765impl CreateTerminalRequest {
766 pub fn new(session_id: impl Into<SessionId>, command: impl Into<String>) -> Self {
767 Self {
768 session_id: session_id.into(),
769 command: command.into(),
770 args: Vec::new(),
771 env: Vec::new(),
772 cwd: None,
773 output_byte_limit: None,
774 meta: None,
775 }
776 }
777
778 /// Array of command arguments.
779 #[must_use]
780 pub fn args(mut self, args: Vec<String>) -> Self {
781 self.args = args;
782 self
783 }
784
785 /// Environment variables for the command.
786 #[must_use]
787 pub fn env(mut self, env: Vec<crate::EnvVariable>) -> Self {
788 self.env = env;
789 self
790 }
791
792 /// Working directory for the command (absolute path).
793 #[must_use]
794 pub fn cwd(mut self, cwd: impl IntoOption<PathBuf>) -> Self {
795 self.cwd = cwd.into_option();
796 self
797 }
798
799 /// Maximum number of output bytes to retain.
800 ///
801 /// When the limit is exceeded, the Client truncates from the beginning of the output
802 /// to stay within the limit.
803 ///
804 /// The Client MUST ensure truncation happens at a character boundary to maintain valid
805 /// string output, even if this means the retained output is slightly less than the
806 /// specified limit.
807 #[must_use]
808 pub fn output_byte_limit(mut self, output_byte_limit: impl IntoOption<u64>) -> Self {
809 self.output_byte_limit = output_byte_limit.into_option();
810 self
811 }
812
813 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
814 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
815 /// these keys.
816 ///
817 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
818 #[must_use]
819 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
820 self.meta = meta.into_option();
821 self
822 }
823}
824
825/// Response containing the ID of the created terminal.
826#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
827#[serde(rename_all = "camelCase")]
828#[schemars(extend("x-side" = "client", "x-method" = TERMINAL_CREATE_METHOD_NAME))]
829#[non_exhaustive]
830pub struct CreateTerminalResponse {
831 /// The unique identifier for the created terminal.
832 pub terminal_id: TerminalId,
833 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
834 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
835 /// these keys.
836 ///
837 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
838 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
839 pub meta: Option<Meta>,
840}
841
842impl CreateTerminalResponse {
843 #[must_use]
844 pub fn new(terminal_id: impl Into<TerminalId>) -> Self {
845 Self {
846 terminal_id: terminal_id.into(),
847 meta: None,
848 }
849 }
850
851 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
852 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
853 /// these keys.
854 ///
855 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
856 #[must_use]
857 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
858 self.meta = meta.into_option();
859 self
860 }
861}
862
863/// Request to get the current output and status of a terminal.
864#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
865#[serde(rename_all = "camelCase")]
866#[schemars(extend("x-side" = "client", "x-method" = TERMINAL_OUTPUT_METHOD_NAME))]
867#[non_exhaustive]
868pub struct TerminalOutputRequest {
869 /// The session ID for this request.
870 pub session_id: SessionId,
871 /// The ID of the terminal to get output from.
872 pub terminal_id: TerminalId,
873 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
874 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
875 /// these keys.
876 ///
877 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
878 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
879 pub meta: Option<Meta>,
880}
881
882impl TerminalOutputRequest {
883 #[must_use]
884 pub fn new(session_id: impl Into<SessionId>, terminal_id: impl Into<TerminalId>) -> Self {
885 Self {
886 session_id: session_id.into(),
887 terminal_id: terminal_id.into(),
888 meta: None,
889 }
890 }
891
892 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
893 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
894 /// these keys.
895 ///
896 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
897 #[must_use]
898 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
899 self.meta = meta.into_option();
900 self
901 }
902}
903
904/// Response containing the terminal output and exit status.
905#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
906#[serde(rename_all = "camelCase")]
907#[schemars(extend("x-side" = "client", "x-method" = TERMINAL_OUTPUT_METHOD_NAME))]
908#[non_exhaustive]
909pub struct TerminalOutputResponse {
910 /// The terminal output captured so far.
911 pub output: String,
912 /// Whether the output was truncated due to byte limits.
913 pub truncated: bool,
914 /// Exit status if the command has completed.
915 pub exit_status: Option<TerminalExitStatus>,
916 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
917 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
918 /// these keys.
919 ///
920 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
921 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
922 pub meta: Option<Meta>,
923}
924
925impl TerminalOutputResponse {
926 pub fn new(output: impl Into<String>, truncated: bool) -> Self {
927 Self {
928 output: output.into(),
929 truncated,
930 exit_status: None,
931 meta: None,
932 }
933 }
934
935 /// Exit status if the command has completed.
936 #[must_use]
937 pub fn exit_status(mut self, exit_status: impl IntoOption<TerminalExitStatus>) -> Self {
938 self.exit_status = exit_status.into_option();
939 self
940 }
941
942 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
943 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
944 /// these keys.
945 ///
946 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
947 #[must_use]
948 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
949 self.meta = meta.into_option();
950 self
951 }
952}
953
954/// Request to release a terminal and free its resources.
955#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
956#[serde(rename_all = "camelCase")]
957#[schemars(extend("x-side" = "client", "x-method" = TERMINAL_RELEASE_METHOD_NAME))]
958#[non_exhaustive]
959pub struct ReleaseTerminalRequest {
960 /// The session ID for this request.
961 pub session_id: SessionId,
962 /// The ID of the terminal to release.
963 pub terminal_id: TerminalId,
964 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
965 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
966 /// these keys.
967 ///
968 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
969 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
970 pub meta: Option<Meta>,
971}
972
973impl ReleaseTerminalRequest {
974 #[must_use]
975 pub fn new(session_id: impl Into<SessionId>, terminal_id: impl Into<TerminalId>) -> Self {
976 Self {
977 session_id: session_id.into(),
978 terminal_id: terminal_id.into(),
979 meta: None,
980 }
981 }
982
983 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
984 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
985 /// these keys.
986 ///
987 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
988 #[must_use]
989 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
990 self.meta = meta.into_option();
991 self
992 }
993}
994
995/// Response to terminal/release method
996#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
997#[serde(rename_all = "camelCase")]
998#[schemars(extend("x-side" = "client", "x-method" = TERMINAL_RELEASE_METHOD_NAME))]
999#[non_exhaustive]
1000pub struct ReleaseTerminalResponse {
1001 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1002 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1003 /// these keys.
1004 ///
1005 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1006 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
1007 pub meta: Option<Meta>,
1008}
1009
1010impl ReleaseTerminalResponse {
1011 #[must_use]
1012 pub fn new() -> Self {
1013 Self::default()
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/// Request to kill a terminal command without releasing the terminal.
1029#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1030#[serde(rename_all = "camelCase")]
1031#[schemars(extend("x-side" = "client", "x-method" = TERMINAL_KILL_METHOD_NAME))]
1032#[non_exhaustive]
1033pub struct KillTerminalCommandRequest {
1034 /// The session ID for this request.
1035 pub session_id: SessionId,
1036 /// The ID of the terminal to kill.
1037 pub terminal_id: TerminalId,
1038 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1039 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1040 /// these keys.
1041 ///
1042 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1043 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
1044 pub meta: Option<Meta>,
1045}
1046
1047impl KillTerminalCommandRequest {
1048 #[must_use]
1049 pub fn new(session_id: impl Into<SessionId>, terminal_id: impl Into<TerminalId>) -> Self {
1050 Self {
1051 session_id: session_id.into(),
1052 terminal_id: terminal_id.into(),
1053 meta: None,
1054 }
1055 }
1056
1057 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1058 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1059 /// these keys.
1060 ///
1061 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1062 #[must_use]
1063 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1064 self.meta = meta.into_option();
1065 self
1066 }
1067}
1068
1069/// Response to terminal/kill command method
1070#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1071#[serde(rename_all = "camelCase")]
1072#[schemars(extend("x-side" = "client", "x-method" = TERMINAL_KILL_METHOD_NAME))]
1073#[non_exhaustive]
1074pub struct KillTerminalCommandResponse {
1075 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1076 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1077 /// these keys.
1078 ///
1079 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1080 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
1081 pub meta: Option<Meta>,
1082}
1083
1084impl KillTerminalCommandResponse {
1085 #[must_use]
1086 pub fn new() -> Self {
1087 Self::default()
1088 }
1089
1090 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1091 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1092 /// these keys.
1093 ///
1094 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1095 #[must_use]
1096 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1097 self.meta = meta.into_option();
1098 self
1099 }
1100}
1101
1102/// Request to wait for a terminal command to exit.
1103#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1104#[serde(rename_all = "camelCase")]
1105#[schemars(extend("x-side" = "client", "x-method" = TERMINAL_WAIT_FOR_EXIT_METHOD_NAME))]
1106#[non_exhaustive]
1107pub struct WaitForTerminalExitRequest {
1108 /// The session ID for this request.
1109 pub session_id: SessionId,
1110 /// The ID of the terminal to wait for.
1111 pub terminal_id: TerminalId,
1112 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1113 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1114 /// these keys.
1115 ///
1116 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1117 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
1118 pub meta: Option<Meta>,
1119}
1120
1121impl WaitForTerminalExitRequest {
1122 #[must_use]
1123 pub fn new(session_id: impl Into<SessionId>, terminal_id: impl Into<TerminalId>) -> Self {
1124 Self {
1125 session_id: session_id.into(),
1126 terminal_id: terminal_id.into(),
1127 meta: None,
1128 }
1129 }
1130
1131 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1132 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1133 /// these keys.
1134 ///
1135 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1136 #[must_use]
1137 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1138 self.meta = meta.into_option();
1139 self
1140 }
1141}
1142
1143/// Response containing the exit status of a terminal command.
1144#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1145#[serde(rename_all = "camelCase")]
1146#[schemars(extend("x-side" = "client", "x-method" = TERMINAL_WAIT_FOR_EXIT_METHOD_NAME))]
1147#[non_exhaustive]
1148pub struct WaitForTerminalExitResponse {
1149 /// The exit status of the terminal command.
1150 #[serde(flatten)]
1151 pub exit_status: TerminalExitStatus,
1152 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1153 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1154 /// these keys.
1155 ///
1156 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1157 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
1158 pub meta: Option<Meta>,
1159}
1160
1161impl WaitForTerminalExitResponse {
1162 #[must_use]
1163 pub fn new(exit_status: TerminalExitStatus) -> Self {
1164 Self {
1165 exit_status,
1166 meta: None,
1167 }
1168 }
1169
1170 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1171 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1172 /// these keys.
1173 ///
1174 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1175 #[must_use]
1176 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1177 self.meta = meta.into_option();
1178 self
1179 }
1180}
1181
1182/// Exit status of a terminal command.
1183#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1184#[serde(rename_all = "camelCase")]
1185#[non_exhaustive]
1186pub struct TerminalExitStatus {
1187 /// The process exit code (may be null if terminated by signal).
1188 pub exit_code: Option<u32>,
1189 /// The signal that terminated the process (may be null if exited normally).
1190 pub signal: Option<String>,
1191 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1192 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1193 /// these keys.
1194 ///
1195 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1196 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
1197 pub meta: Option<Meta>,
1198}
1199
1200impl TerminalExitStatus {
1201 #[must_use]
1202 pub fn new() -> Self {
1203 Self::default()
1204 }
1205
1206 /// The process exit code (may be null if terminated by signal).
1207 #[must_use]
1208 pub fn exit_code(mut self, exit_code: impl IntoOption<u32>) -> Self {
1209 self.exit_code = exit_code.into_option();
1210 self
1211 }
1212
1213 /// The signal that terminated the process (may be null if exited normally).
1214 #[must_use]
1215 pub fn signal(mut self, signal: impl IntoOption<String>) -> Self {
1216 self.signal = signal.into_option();
1217 self
1218 }
1219
1220 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1221 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1222 /// these keys.
1223 ///
1224 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1225 #[must_use]
1226 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1227 self.meta = meta.into_option();
1228 self
1229 }
1230}
1231
1232// Capabilities
1233
1234/// Capabilities supported by the client.
1235///
1236/// Advertised during initialization to inform the agent about
1237/// available features and methods.
1238///
1239/// See protocol docs: [Client Capabilities](https://agentclientprotocol.com/protocol/initialization#client-capabilities)
1240#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1241#[serde(rename_all = "camelCase")]
1242#[non_exhaustive]
1243pub struct ClientCapabilities {
1244 /// File system capabilities supported by the client.
1245 /// Determines which file operations the agent can request.
1246 #[serde(default)]
1247 pub fs: FileSystemCapability,
1248 /// Whether the Client support all `terminal/*` methods.
1249 #[serde(default)]
1250 pub terminal: bool,
1251 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1252 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1253 /// these keys.
1254 ///
1255 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1256 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
1257 pub meta: Option<Meta>,
1258}
1259
1260impl ClientCapabilities {
1261 #[must_use]
1262 pub fn new() -> Self {
1263 Self::default()
1264 }
1265
1266 /// File system capabilities supported by the client.
1267 /// Determines which file operations the agent can request.
1268 #[must_use]
1269 pub fn fs(mut self, fs: FileSystemCapability) -> Self {
1270 self.fs = fs;
1271 self
1272 }
1273
1274 /// Whether the Client support all `terminal/*` methods.
1275 #[must_use]
1276 pub fn terminal(mut self, terminal: bool) -> Self {
1277 self.terminal = terminal;
1278 self
1279 }
1280
1281 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1282 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1283 /// these keys.
1284 ///
1285 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1286 #[must_use]
1287 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1288 self.meta = meta.into_option();
1289 self
1290 }
1291}
1292
1293/// Filesystem capabilities supported by the client.
1294/// File system capabilities that a client may support.
1295///
1296/// See protocol docs: [FileSystem](https://agentclientprotocol.com/protocol/initialization#filesystem)
1297#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1298#[serde(rename_all = "camelCase")]
1299#[non_exhaustive]
1300pub struct FileSystemCapability {
1301 /// Whether the Client supports `fs/read_text_file` requests.
1302 #[serde(default)]
1303 pub read_text_file: bool,
1304 /// Whether the Client supports `fs/write_text_file` requests.
1305 #[serde(default)]
1306 pub write_text_file: bool,
1307 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1308 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1309 /// these keys.
1310 ///
1311 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1312 #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
1313 pub meta: Option<Meta>,
1314}
1315
1316impl FileSystemCapability {
1317 #[must_use]
1318 pub fn new() -> Self {
1319 Self::default()
1320 }
1321
1322 /// Whether the Client supports `fs/read_text_file` requests.
1323 #[must_use]
1324 pub fn read_text_file(mut self, read_text_file: bool) -> Self {
1325 self.read_text_file = read_text_file;
1326 self
1327 }
1328
1329 /// Whether the Client supports `fs/write_text_file` requests.
1330 #[must_use]
1331 pub fn write_text_file(mut self, write_text_file: bool) -> Self {
1332 self.write_text_file = write_text_file;
1333 self
1334 }
1335
1336 /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1337 /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1338 /// these keys.
1339 ///
1340 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1341 #[must_use]
1342 pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1343 self.meta = meta.into_option();
1344 self
1345 }
1346}
1347
1348// Method schema
1349
1350/// Names of all methods that clients handle.
1351///
1352/// Provides a centralized definition of method names used in the protocol.
1353#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
1354#[non_exhaustive]
1355pub struct ClientMethodNames {
1356 /// Method for requesting permission from the user.
1357 pub session_request_permission: &'static str,
1358 /// Notification for session updates.
1359 pub session_update: &'static str,
1360 /// Method for writing text files.
1361 pub fs_write_text_file: &'static str,
1362 /// Method for reading text files.
1363 pub fs_read_text_file: &'static str,
1364 /// Method for creating new terminals.
1365 pub terminal_create: &'static str,
1366 /// Method for getting terminals output.
1367 pub terminal_output: &'static str,
1368 /// Method for releasing a terminal.
1369 pub terminal_release: &'static str,
1370 /// Method for waiting for a terminal to finish.
1371 pub terminal_wait_for_exit: &'static str,
1372 /// Method for killing a terminal.
1373 pub terminal_kill: &'static str,
1374}
1375
1376/// Constant containing all client method names.
1377pub const CLIENT_METHOD_NAMES: ClientMethodNames = ClientMethodNames {
1378 session_update: SESSION_UPDATE_NOTIFICATION,
1379 session_request_permission: SESSION_REQUEST_PERMISSION_METHOD_NAME,
1380 fs_write_text_file: FS_WRITE_TEXT_FILE_METHOD_NAME,
1381 fs_read_text_file: FS_READ_TEXT_FILE_METHOD_NAME,
1382 terminal_create: TERMINAL_CREATE_METHOD_NAME,
1383 terminal_output: TERMINAL_OUTPUT_METHOD_NAME,
1384 terminal_release: TERMINAL_RELEASE_METHOD_NAME,
1385 terminal_wait_for_exit: TERMINAL_WAIT_FOR_EXIT_METHOD_NAME,
1386 terminal_kill: TERMINAL_KILL_METHOD_NAME,
1387};
1388
1389/// Notification name for session updates.
1390pub(crate) const SESSION_UPDATE_NOTIFICATION: &str = "session/update";
1391/// Method name for requesting user permission.
1392pub(crate) const SESSION_REQUEST_PERMISSION_METHOD_NAME: &str = "session/request_permission";
1393/// Method name for writing text files.
1394pub(crate) const FS_WRITE_TEXT_FILE_METHOD_NAME: &str = "fs/write_text_file";
1395/// Method name for reading text files.
1396pub(crate) const FS_READ_TEXT_FILE_METHOD_NAME: &str = "fs/read_text_file";
1397/// Method name for creating a new terminal.
1398pub(crate) const TERMINAL_CREATE_METHOD_NAME: &str = "terminal/create";
1399/// Method for getting terminals output.
1400pub(crate) const TERMINAL_OUTPUT_METHOD_NAME: &str = "terminal/output";
1401/// Method for releasing a terminal.
1402pub(crate) const TERMINAL_RELEASE_METHOD_NAME: &str = "terminal/release";
1403/// Method for waiting for a terminal to finish.
1404pub(crate) const TERMINAL_WAIT_FOR_EXIT_METHOD_NAME: &str = "terminal/wait_for_exit";
1405/// Method for killing a terminal.
1406pub(crate) const TERMINAL_KILL_METHOD_NAME: &str = "terminal/kill";
1407
1408/// All possible requests that an agent can send to a client.
1409///
1410/// This enum is used internally for routing RPC requests. You typically won't need
1411/// to use this directly - instead, use the methods on the [`Client`] trait.
1412///
1413/// This enum encompasses all method calls from agent to client.
1414#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
1415#[serde(untagged)]
1416#[schemars(inline)]
1417#[non_exhaustive]
1418pub enum AgentRequest {
1419 /// Writes content to a text file in the client's file system.
1420 ///
1421 /// Only available if the client advertises the `fs.writeTextFile` capability.
1422 /// Allows the agent to create or modify files within the client's environment.
1423 ///
1424 /// See protocol docs: [Client](https://agentclientprotocol.com/protocol/overview#client)
1425 WriteTextFileRequest(WriteTextFileRequest),
1426 /// Reads content from a text file in the client's file system.
1427 ///
1428 /// Only available if the client advertises the `fs.readTextFile` capability.
1429 /// Allows the agent to access file contents within the client's environment.
1430 ///
1431 /// See protocol docs: [Client](https://agentclientprotocol.com/protocol/overview#client)
1432 ReadTextFileRequest(ReadTextFileRequest),
1433 /// Requests permission from the user for a tool call operation.
1434 ///
1435 /// Called by the agent when it needs user authorization before executing
1436 /// a potentially sensitive operation. The client should present the options
1437 /// to the user and return their decision.
1438 ///
1439 /// If the client cancels the prompt turn via `session/cancel`, it MUST
1440 /// respond to this request with `RequestPermissionOutcome::Cancelled`.
1441 ///
1442 /// See protocol docs: [Requesting Permission](https://agentclientprotocol.com/protocol/tool-calls#requesting-permission)
1443 RequestPermissionRequest(RequestPermissionRequest),
1444 /// Executes a command in a new terminal
1445 ///
1446 /// Only available if the `terminal` Client capability is set to `true`.
1447 ///
1448 /// Returns a `TerminalId` that can be used with other terminal methods
1449 /// to get the current output, wait for exit, and kill the command.
1450 ///
1451 /// The `TerminalId` can also be used to embed the terminal in a tool call
1452 /// by using the `ToolCallContent::Terminal` variant.
1453 ///
1454 /// The Agent is responsible for releasing the terminal by using the `terminal/release`
1455 /// method.
1456 ///
1457 /// See protocol docs: [Terminals](https://agentclientprotocol.com/protocol/terminals)
1458 CreateTerminalRequest(CreateTerminalRequest),
1459 /// Gets the terminal output and exit status
1460 ///
1461 /// Returns the current content in the terminal without waiting for the command to exit.
1462 /// If the command has already exited, the exit status is included.
1463 ///
1464 /// See protocol docs: [Terminals](https://agentclientprotocol.com/protocol/terminals)
1465 TerminalOutputRequest(TerminalOutputRequest),
1466 /// Releases a terminal
1467 ///
1468 /// The command is killed if it hasn't exited yet. Use `terminal/wait_for_exit`
1469 /// to wait for the command to exit before releasing the terminal.
1470 ///
1471 /// After release, the `TerminalId` can no longer be used with other `terminal/*` methods,
1472 /// but tool calls that already contain it, continue to display its output.
1473 ///
1474 /// The `terminal/kill` method can be used to terminate the command without releasing
1475 /// the terminal, allowing the Agent to call `terminal/output` and other methods.
1476 ///
1477 /// See protocol docs: [Terminals](https://agentclientprotocol.com/protocol/terminals)
1478 ReleaseTerminalRequest(ReleaseTerminalRequest),
1479 /// Waits for the terminal command to exit and return its exit status
1480 ///
1481 /// See protocol docs: [Terminals](https://agentclientprotocol.com/protocol/terminals)
1482 WaitForTerminalExitRequest(WaitForTerminalExitRequest),
1483 /// Kills the terminal command without releasing the terminal
1484 ///
1485 /// While `terminal/release` will also kill the command, this method will keep
1486 /// the `TerminalId` valid so it can be used with other methods.
1487 ///
1488 /// This method can be helpful when implementing command timeouts which terminate
1489 /// the command as soon as elapsed, and then get the final output so it can be sent
1490 /// to the model.
1491 ///
1492 /// Note: `terminal/release` when `TerminalId` is no longer needed.
1493 ///
1494 /// See protocol docs: [Terminals](https://agentclientprotocol.com/protocol/terminals)
1495 KillTerminalCommandRequest(KillTerminalCommandRequest),
1496 /// Handles extension method requests from the agent.
1497 ///
1498 /// Allows the Agent to send an arbitrary request that is not part of the ACP spec.
1499 /// Extension methods provide a way to add custom functionality while maintaining
1500 /// protocol compatibility.
1501 ///
1502 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1503 ExtMethodRequest(ExtRequest),
1504}
1505
1506impl AgentRequest {
1507 /// Returns the corresponding method name of the request.
1508 #[must_use]
1509 pub fn method(&self) -> &str {
1510 match self {
1511 Self::WriteTextFileRequest(_) => CLIENT_METHOD_NAMES.fs_write_text_file,
1512 Self::ReadTextFileRequest(_) => CLIENT_METHOD_NAMES.fs_read_text_file,
1513 Self::RequestPermissionRequest(_) => CLIENT_METHOD_NAMES.session_request_permission,
1514 Self::CreateTerminalRequest(_) => CLIENT_METHOD_NAMES.terminal_create,
1515 Self::TerminalOutputRequest(_) => CLIENT_METHOD_NAMES.terminal_output,
1516 Self::ReleaseTerminalRequest(_) => CLIENT_METHOD_NAMES.terminal_release,
1517 Self::WaitForTerminalExitRequest(_) => CLIENT_METHOD_NAMES.terminal_wait_for_exit,
1518 Self::KillTerminalCommandRequest(_) => CLIENT_METHOD_NAMES.terminal_kill,
1519 Self::ExtMethodRequest(ext_request) => &ext_request.method,
1520 }
1521 }
1522}
1523
1524/// All possible responses that a client can send to an agent.
1525///
1526/// This enum is used internally for routing RPC responses. You typically won't need
1527/// to use this directly - the responses are handled automatically by the connection.
1528///
1529/// These are responses to the corresponding `AgentRequest` variants.
1530#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
1531#[serde(untagged)]
1532#[schemars(inline)]
1533#[non_exhaustive]
1534pub enum ClientResponse {
1535 WriteTextFileResponse(#[serde(default)] WriteTextFileResponse),
1536 ReadTextFileResponse(ReadTextFileResponse),
1537 RequestPermissionResponse(RequestPermissionResponse),
1538 CreateTerminalResponse(CreateTerminalResponse),
1539 TerminalOutputResponse(TerminalOutputResponse),
1540 ReleaseTerminalResponse(#[serde(default)] ReleaseTerminalResponse),
1541 WaitForTerminalExitResponse(WaitForTerminalExitResponse),
1542 KillTerminalResponse(#[serde(default)] KillTerminalCommandResponse),
1543 ExtMethodResponse(ExtResponse),
1544}
1545
1546/// All possible notifications that an agent can send to a client.
1547///
1548/// This enum is used internally for routing RPC notifications. You typically won't need
1549/// to use this directly - use the notification methods on the [`Client`] trait instead.
1550///
1551/// Notifications do not expect a response.
1552#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
1553#[serde(untagged)]
1554#[expect(clippy::large_enum_variant)]
1555#[schemars(inline)]
1556#[non_exhaustive]
1557pub enum AgentNotification {
1558 /// Handles session update notifications from the agent.
1559 ///
1560 /// This is a notification endpoint (no response expected) that receives
1561 /// real-time updates about session progress, including message chunks,
1562 /// tool calls, and execution plans.
1563 ///
1564 /// Note: Clients SHOULD continue accepting tool call updates even after
1565 /// sending a `session/cancel` notification, as the agent may send final
1566 /// updates before responding with the cancelled stop reason.
1567 ///
1568 /// See protocol docs: [Agent Reports Output](https://agentclientprotocol.com/protocol/prompt-turn#3-agent-reports-output)
1569 SessionNotification(SessionNotification),
1570 /// Handles extension notifications from the agent.
1571 ///
1572 /// Allows the Agent to send an arbitrary notification that is not part of the ACP spec.
1573 /// Extension notifications provide a way to send one-way messages for custom functionality
1574 /// while maintaining protocol compatibility.
1575 ///
1576 /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1577 ExtNotification(ExtNotification),
1578}
1579
1580impl AgentNotification {
1581 /// Returns the corresponding method name of the notification.
1582 #[must_use]
1583 pub fn method(&self) -> &str {
1584 match self {
1585 Self::SessionNotification(_) => CLIENT_METHOD_NAMES.session_update,
1586 Self::ExtNotification(ext_notification) => &ext_notification.method,
1587 }
1588 }
1589}