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