Skip to main content

agent_client_protocol_schema/v1/
client.rs

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