Skip to main content

agent_client_protocol_schema/
client.rs

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