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