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