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