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    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
334    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
335    /// these keys.
336    ///
337    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
338    #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
339    pub meta: Option<Meta>,
340}
341
342impl ContentChunk {
343    #[must_use]
344    pub fn new(content: ContentBlock) -> Self {
345        Self {
346            content,
347            meta: None,
348        }
349    }
350
351    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
352    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
353    /// these keys.
354    ///
355    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
356    #[must_use]
357    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
358        self.meta = meta.into_option();
359        self
360    }
361}
362
363/// Available commands are ready or have changed
364#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
365#[serde(rename_all = "camelCase")]
366#[non_exhaustive]
367pub struct AvailableCommandsUpdate {
368    /// Commands the agent can execute
369    pub available_commands: Vec<AvailableCommand>,
370    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
371    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
372    /// these keys.
373    ///
374    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
375    #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
376    pub meta: Option<Meta>,
377}
378
379impl AvailableCommandsUpdate {
380    #[must_use]
381    pub fn new(available_commands: Vec<AvailableCommand>) -> Self {
382        Self {
383            available_commands,
384            meta: None,
385        }
386    }
387
388    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
389    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
390    /// these keys.
391    ///
392    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
393    #[must_use]
394    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
395        self.meta = meta.into_option();
396        self
397    }
398}
399
400/// Information about a command.
401#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
402#[serde(rename_all = "camelCase")]
403#[non_exhaustive]
404pub struct AvailableCommand {
405    /// Command name (e.g., `create_plan`, `research_codebase`).
406    pub name: String,
407    /// Human-readable description of what the command does.
408    pub description: String,
409    /// Input for the command if required
410    pub input: Option<AvailableCommandInput>,
411    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
412    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
413    /// these keys.
414    ///
415    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
416    #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
417    pub meta: Option<Meta>,
418}
419
420impl AvailableCommand {
421    pub fn new(name: impl Into<String>, description: impl Into<String>) -> Self {
422        Self {
423            name: name.into(),
424            description: description.into(),
425            input: None,
426            meta: None,
427        }
428    }
429
430    /// Input for the command if required
431    #[must_use]
432    pub fn input(mut self, input: impl IntoOption<AvailableCommandInput>) -> Self {
433        self.input = input.into_option();
434        self
435    }
436
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    #[must_use]
443    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
444        self.meta = meta.into_option();
445        self
446    }
447}
448
449/// The input specification for a command.
450#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
451#[serde(untagged, rename_all = "camelCase")]
452#[non_exhaustive]
453pub enum AvailableCommandInput {
454    /// All text that was typed after the command name is provided as input.
455    Unstructured(UnstructuredCommandInput),
456}
457
458/// All text that was typed after the command name is provided as input.
459#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
460#[serde(rename_all = "camelCase")]
461#[non_exhaustive]
462pub struct UnstructuredCommandInput {
463    /// A hint to display when the input hasn't been provided yet
464    pub hint: String,
465    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
466    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
467    /// these keys.
468    ///
469    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
470    #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
471    pub meta: Option<Meta>,
472}
473
474impl UnstructuredCommandInput {
475    pub fn new(hint: impl Into<String>) -> Self {
476        Self {
477            hint: hint.into(),
478            meta: None,
479        }
480    }
481
482    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
483    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
484    /// these keys.
485    ///
486    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
487    #[must_use]
488    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
489        self.meta = meta.into_option();
490        self
491    }
492}
493
494// Permission
495
496/// Request for user permission to execute a tool call.
497///
498/// Sent when the agent needs authorization before performing a sensitive operation.
499///
500/// See protocol docs: [Requesting Permission](https://agentclientprotocol.com/protocol/tool-calls#requesting-permission)
501#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq)]
502#[schemars(extend("x-side" = "client", "x-method" = SESSION_REQUEST_PERMISSION_METHOD_NAME))]
503#[serde(rename_all = "camelCase")]
504#[non_exhaustive]
505pub struct RequestPermissionRequest {
506    /// The session ID for this request.
507    pub session_id: SessionId,
508    /// Details about the tool call requiring permission.
509    pub tool_call: ToolCallUpdate,
510    /// Available permission options for the user to choose from.
511    pub options: Vec<PermissionOption>,
512    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
513    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
514    /// these keys.
515    ///
516    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
517    #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
518    pub meta: Option<Meta>,
519}
520
521impl RequestPermissionRequest {
522    #[must_use]
523    pub fn new(
524        session_id: impl Into<SessionId>,
525        tool_call: ToolCallUpdate,
526        options: Vec<PermissionOption>,
527    ) -> Self {
528        Self {
529            session_id: session_id.into(),
530            tool_call,
531            options,
532            meta: None,
533        }
534    }
535
536    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
537    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
538    /// these keys.
539    ///
540    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
541    #[must_use]
542    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
543        self.meta = meta.into_option();
544        self
545    }
546}
547
548/// An option presented to the user when requesting permission.
549#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
550#[serde(rename_all = "camelCase")]
551#[non_exhaustive]
552pub struct PermissionOption {
553    /// Unique identifier for this permission option.
554    pub option_id: PermissionOptionId,
555    /// Human-readable label to display to the user.
556    pub name: String,
557    /// Hint about the nature of this permission option.
558    pub kind: PermissionOptionKind,
559    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
560    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
561    /// these keys.
562    ///
563    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
564    #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
565    pub meta: Option<Meta>,
566}
567
568impl PermissionOption {
569    pub fn new(
570        option_id: impl Into<PermissionOptionId>,
571        name: impl Into<String>,
572        kind: PermissionOptionKind,
573    ) -> Self {
574        Self {
575            option_id: option_id.into(),
576            name: name.into(),
577            kind,
578            meta: None,
579        }
580    }
581
582    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
583    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
584    /// these keys.
585    ///
586    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
587    #[must_use]
588    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
589        self.meta = meta.into_option();
590        self
591    }
592}
593
594/// Unique identifier for a permission option.
595#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq, Hash, Display, From)]
596#[serde(transparent)]
597#[from(Arc<str>, String, &'static str)]
598#[non_exhaustive]
599pub struct PermissionOptionId(pub Arc<str>);
600
601impl PermissionOptionId {
602    pub fn new(id: impl Into<Arc<str>>) -> Self {
603        Self(id.into())
604    }
605}
606
607/// The type of permission option being presented to the user.
608///
609/// Helps clients choose appropriate icons and UI treatment.
610#[derive(Debug, Clone, Copy, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
611#[serde(rename_all = "snake_case")]
612#[non_exhaustive]
613pub enum PermissionOptionKind {
614    /// Allow this operation only this time.
615    AllowOnce,
616    /// Allow this operation and remember the choice.
617    AllowAlways,
618    /// Reject this operation only this time.
619    RejectOnce,
620    /// Reject this operation and remember the choice.
621    RejectAlways,
622}
623
624/// Response to a permission request.
625#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
626#[schemars(extend("x-side" = "client", "x-method" = SESSION_REQUEST_PERMISSION_METHOD_NAME))]
627#[serde(rename_all = "camelCase")]
628#[non_exhaustive]
629pub struct RequestPermissionResponse {
630    /// The user's decision on the permission request.
631    // This extra-level is unfortunately needed because the output must be an object
632    pub outcome: RequestPermissionOutcome,
633    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
634    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
635    /// these keys.
636    ///
637    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
638    #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
639    pub meta: Option<Meta>,
640}
641
642impl RequestPermissionResponse {
643    #[must_use]
644    pub fn new(outcome: RequestPermissionOutcome) -> Self {
645        Self {
646            outcome,
647            meta: None,
648        }
649    }
650
651    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
652    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
653    /// these keys.
654    ///
655    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
656    #[must_use]
657    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
658        self.meta = meta.into_option();
659        self
660    }
661}
662
663/// The outcome of a permission request.
664#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
665#[serde(tag = "outcome", rename_all = "snake_case")]
666#[schemars(extend("discriminator" = {"propertyName": "outcome"}))]
667#[non_exhaustive]
668pub enum RequestPermissionOutcome {
669    /// The prompt turn was cancelled before the user responded.
670    ///
671    /// When a client sends a `session/cancel` notification to cancel an ongoing
672    /// prompt turn, it MUST respond to all pending `session/request_permission`
673    /// requests with this `Cancelled` outcome.
674    ///
675    /// See protocol docs: [Cancellation](https://agentclientprotocol.com/protocol/prompt-turn#cancellation)
676    Cancelled,
677    /// The user selected one of the provided options.
678    #[serde(rename_all = "camelCase")]
679    Selected(SelectedPermissionOutcome),
680}
681
682/// The user selected one of the provided options.
683#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
684#[serde(rename_all = "camelCase")]
685#[non_exhaustive]
686pub struct SelectedPermissionOutcome {
687    /// The ID of the option the user selected.
688    pub option_id: PermissionOptionId,
689    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
690    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
691    /// these keys.
692    ///
693    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
694    #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
695    pub meta: Option<Meta>,
696}
697
698impl SelectedPermissionOutcome {
699    #[must_use]
700    pub fn new(option_id: impl Into<PermissionOptionId>) -> Self {
701        Self {
702            option_id: option_id.into(),
703            meta: None,
704        }
705    }
706
707    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
708    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
709    /// these keys.
710    ///
711    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
712    #[must_use]
713    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
714        self.meta = meta.into_option();
715        self
716    }
717}
718
719// Write text file
720
721/// Request to write content to a text file.
722///
723/// Only available if the client supports the `fs.writeTextFile` capability.
724#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
725#[schemars(extend("x-side" = "client", "x-method" = FS_WRITE_TEXT_FILE_METHOD_NAME))]
726#[serde(rename_all = "camelCase")]
727#[non_exhaustive]
728pub struct WriteTextFileRequest {
729    /// The session ID for this request.
730    pub session_id: SessionId,
731    /// Absolute path to the file to write.
732    pub path: PathBuf,
733    /// The text content to write to the file.
734    pub content: String,
735    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
736    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
737    /// these keys.
738    ///
739    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
740    #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
741    pub meta: Option<Meta>,
742}
743
744impl WriteTextFileRequest {
745    pub fn new(
746        session_id: impl Into<SessionId>,
747        path: impl Into<PathBuf>,
748        content: impl Into<String>,
749    ) -> Self {
750        Self {
751            session_id: session_id.into(),
752            path: path.into(),
753            content: content.into(),
754            meta: None,
755        }
756    }
757
758    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
759    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
760    /// these keys.
761    ///
762    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
763    #[must_use]
764    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
765        self.meta = meta.into_option();
766        self
767    }
768}
769
770/// Response to `fs/write_text_file`
771#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
772#[serde(default, rename_all = "camelCase")]
773#[schemars(extend("x-side" = "client", "x-method" = FS_WRITE_TEXT_FILE_METHOD_NAME))]
774#[non_exhaustive]
775pub struct WriteTextFileResponse {
776    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
777    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
778    /// these keys.
779    ///
780    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
781    #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
782    pub meta: Option<Meta>,
783}
784
785impl WriteTextFileResponse {
786    #[must_use]
787    pub fn new() -> Self {
788        Self::default()
789    }
790
791    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
792    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
793    /// these keys.
794    ///
795    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
796    #[must_use]
797    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
798        self.meta = meta.into_option();
799        self
800    }
801}
802
803// Read text file
804
805/// Request to read content from a text file.
806///
807/// Only available if the client supports the `fs.readTextFile` capability.
808#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
809#[schemars(extend("x-side" = "client", "x-method" = FS_READ_TEXT_FILE_METHOD_NAME))]
810#[serde(rename_all = "camelCase")]
811#[non_exhaustive]
812pub struct ReadTextFileRequest {
813    /// The session ID for this request.
814    pub session_id: SessionId,
815    /// Absolute path to the file to read.
816    pub path: PathBuf,
817    /// Line number to start reading from (1-based).
818    #[serde(skip_serializing_if = "Option::is_none")]
819    pub line: Option<u32>,
820    /// Maximum number of lines to read.
821    #[serde(skip_serializing_if = "Option::is_none")]
822    pub limit: Option<u32>,
823    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
824    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
825    /// these keys.
826    ///
827    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
828    #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
829    pub meta: Option<Meta>,
830}
831
832impl ReadTextFileRequest {
833    pub fn new(session_id: impl Into<SessionId>, path: impl Into<PathBuf>) -> Self {
834        Self {
835            session_id: session_id.into(),
836            path: path.into(),
837            line: None,
838            limit: None,
839            meta: None,
840        }
841    }
842
843    /// Line number to start reading from (1-based).
844    #[must_use]
845    pub fn line(mut self, line: impl IntoOption<u32>) -> Self {
846        self.line = line.into_option();
847        self
848    }
849
850    /// Maximum number of lines to read.
851    #[must_use]
852    pub fn limit(mut self, limit: impl IntoOption<u32>) -> Self {
853        self.limit = limit.into_option();
854        self
855    }
856
857    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
858    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
859    /// these keys.
860    ///
861    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
862    #[must_use]
863    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
864        self.meta = meta.into_option();
865        self
866    }
867}
868
869/// Response containing the contents of a text file.
870#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
871#[schemars(extend("x-side" = "client", "x-method" = FS_READ_TEXT_FILE_METHOD_NAME))]
872#[serde(rename_all = "camelCase")]
873#[non_exhaustive]
874pub struct ReadTextFileResponse {
875    pub content: String,
876    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
877    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
878    /// these keys.
879    ///
880    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
881    #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
882    pub meta: Option<Meta>,
883}
884
885impl ReadTextFileResponse {
886    pub fn new(content: impl Into<String>) -> Self {
887        Self {
888            content: content.into(),
889            meta: None,
890        }
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// Terminals
906
907#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq, Hash, Display, From)]
908#[serde(transparent)]
909#[from(Arc<str>, String, &'static str)]
910#[non_exhaustive]
911pub struct TerminalId(pub Arc<str>);
912
913impl TerminalId {
914    pub fn new(id: impl Into<Arc<str>>) -> Self {
915        Self(id.into())
916    }
917}
918
919/// Request to create a new terminal and execute a command.
920#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
921#[serde(rename_all = "camelCase")]
922#[schemars(extend("x-side" = "client", "x-method" = TERMINAL_CREATE_METHOD_NAME))]
923#[non_exhaustive]
924pub struct CreateTerminalRequest {
925    /// The session ID for this request.
926    pub session_id: SessionId,
927    /// The command to execute.
928    pub command: String,
929    /// Array of command arguments.
930    #[serde(default, skip_serializing_if = "Vec::is_empty")]
931    pub args: Vec<String>,
932    /// Environment variables for the command.
933    #[serde(default, skip_serializing_if = "Vec::is_empty")]
934    pub env: Vec<crate::EnvVariable>,
935    /// Working directory for the command (absolute path).
936    #[serde(skip_serializing_if = "Option::is_none")]
937    pub cwd: Option<PathBuf>,
938    /// Maximum number of output bytes to retain.
939    ///
940    /// When the limit is exceeded, the Client truncates from the beginning of the output
941    /// to stay within the limit.
942    ///
943    /// The Client MUST ensure truncation happens at a character boundary to maintain valid
944    /// string output, even if this means the retained output is slightly less than the
945    /// specified limit.
946    #[serde(skip_serializing_if = "Option::is_none")]
947    pub output_byte_limit: Option<u64>,
948    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
949    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
950    /// these keys.
951    ///
952    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
953    #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
954    pub meta: Option<Meta>,
955}
956
957impl CreateTerminalRequest {
958    pub fn new(session_id: impl Into<SessionId>, command: impl Into<String>) -> Self {
959        Self {
960            session_id: session_id.into(),
961            command: command.into(),
962            args: Vec::new(),
963            env: Vec::new(),
964            cwd: None,
965            output_byte_limit: None,
966            meta: None,
967        }
968    }
969
970    /// Array of command arguments.
971    #[must_use]
972    pub fn args(mut self, args: Vec<String>) -> Self {
973        self.args = args;
974        self
975    }
976
977    /// Environment variables for the command.
978    #[must_use]
979    pub fn env(mut self, env: Vec<crate::EnvVariable>) -> Self {
980        self.env = env;
981        self
982    }
983
984    /// Working directory for the command (absolute path).
985    #[must_use]
986    pub fn cwd(mut self, cwd: impl IntoOption<PathBuf>) -> Self {
987        self.cwd = cwd.into_option();
988        self
989    }
990
991    /// Maximum number of output bytes to retain.
992    ///
993    /// When the limit is exceeded, the Client truncates from the beginning of the output
994    /// to stay within the limit.
995    ///
996    /// The Client MUST ensure truncation happens at a character boundary to maintain valid
997    /// string output, even if this means the retained output is slightly less than the
998    /// specified limit.
999    #[must_use]
1000    pub fn output_byte_limit(mut self, output_byte_limit: impl IntoOption<u64>) -> Self {
1001        self.output_byte_limit = output_byte_limit.into_option();
1002        self
1003    }
1004
1005    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1006    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1007    /// these keys.
1008    ///
1009    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1010    #[must_use]
1011    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1012        self.meta = meta.into_option();
1013        self
1014    }
1015}
1016
1017/// Response containing the ID of the created terminal.
1018#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1019#[serde(rename_all = "camelCase")]
1020#[schemars(extend("x-side" = "client", "x-method" = TERMINAL_CREATE_METHOD_NAME))]
1021#[non_exhaustive]
1022pub struct CreateTerminalResponse {
1023    /// The unique identifier for the created terminal.
1024    pub terminal_id: TerminalId,
1025    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1026    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1027    /// these keys.
1028    ///
1029    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1030    #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
1031    pub meta: Option<Meta>,
1032}
1033
1034impl CreateTerminalResponse {
1035    #[must_use]
1036    pub fn new(terminal_id: impl Into<TerminalId>) -> Self {
1037        Self {
1038            terminal_id: terminal_id.into(),
1039            meta: None,
1040        }
1041    }
1042
1043    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1044    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1045    /// these keys.
1046    ///
1047    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1048    #[must_use]
1049    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1050        self.meta = meta.into_option();
1051        self
1052    }
1053}
1054
1055/// Request to get the current output and status of a terminal.
1056#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1057#[serde(rename_all = "camelCase")]
1058#[schemars(extend("x-side" = "client", "x-method" = TERMINAL_OUTPUT_METHOD_NAME))]
1059#[non_exhaustive]
1060pub struct TerminalOutputRequest {
1061    /// The session ID for this request.
1062    pub session_id: SessionId,
1063    /// The ID of the terminal to get output from.
1064    pub terminal_id: TerminalId,
1065    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1066    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1067    /// these keys.
1068    ///
1069    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1070    #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
1071    pub meta: Option<Meta>,
1072}
1073
1074impl TerminalOutputRequest {
1075    #[must_use]
1076    pub fn new(session_id: impl Into<SessionId>, terminal_id: impl Into<TerminalId>) -> Self {
1077        Self {
1078            session_id: session_id.into(),
1079            terminal_id: terminal_id.into(),
1080            meta: None,
1081        }
1082    }
1083
1084    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1085    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1086    /// these keys.
1087    ///
1088    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1089    #[must_use]
1090    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1091        self.meta = meta.into_option();
1092        self
1093    }
1094}
1095
1096/// Response containing the terminal output and exit status.
1097#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1098#[serde(rename_all = "camelCase")]
1099#[schemars(extend("x-side" = "client", "x-method" = TERMINAL_OUTPUT_METHOD_NAME))]
1100#[non_exhaustive]
1101pub struct TerminalOutputResponse {
1102    /// The terminal output captured so far.
1103    pub output: String,
1104    /// Whether the output was truncated due to byte limits.
1105    pub truncated: bool,
1106    /// Exit status if the command has completed.
1107    pub exit_status: Option<TerminalExitStatus>,
1108    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1109    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1110    /// these keys.
1111    ///
1112    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1113    #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
1114    pub meta: Option<Meta>,
1115}
1116
1117impl TerminalOutputResponse {
1118    pub fn new(output: impl Into<String>, truncated: bool) -> Self {
1119        Self {
1120            output: output.into(),
1121            truncated,
1122            exit_status: None,
1123            meta: None,
1124        }
1125    }
1126
1127    /// Exit status if the command has completed.
1128    #[must_use]
1129    pub fn exit_status(mut self, exit_status: impl IntoOption<TerminalExitStatus>) -> Self {
1130        self.exit_status = exit_status.into_option();
1131        self
1132    }
1133
1134    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1135    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1136    /// these keys.
1137    ///
1138    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1139    #[must_use]
1140    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1141        self.meta = meta.into_option();
1142        self
1143    }
1144}
1145
1146/// Request to release a terminal and free its resources.
1147#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1148#[serde(rename_all = "camelCase")]
1149#[schemars(extend("x-side" = "client", "x-method" = TERMINAL_RELEASE_METHOD_NAME))]
1150#[non_exhaustive]
1151pub struct ReleaseTerminalRequest {
1152    /// The session ID for this request.
1153    pub session_id: SessionId,
1154    /// The ID of the terminal to release.
1155    pub terminal_id: TerminalId,
1156    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1157    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1158    /// these keys.
1159    ///
1160    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1161    #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
1162    pub meta: Option<Meta>,
1163}
1164
1165impl ReleaseTerminalRequest {
1166    #[must_use]
1167    pub fn new(session_id: impl Into<SessionId>, terminal_id: impl Into<TerminalId>) -> Self {
1168        Self {
1169            session_id: session_id.into(),
1170            terminal_id: terminal_id.into(),
1171            meta: None,
1172        }
1173    }
1174
1175    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1176    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1177    /// these keys.
1178    ///
1179    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1180    #[must_use]
1181    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1182        self.meta = meta.into_option();
1183        self
1184    }
1185}
1186
1187/// Response to terminal/release method
1188#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1189#[serde(rename_all = "camelCase")]
1190#[schemars(extend("x-side" = "client", "x-method" = TERMINAL_RELEASE_METHOD_NAME))]
1191#[non_exhaustive]
1192pub struct ReleaseTerminalResponse {
1193    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1194    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1195    /// these keys.
1196    ///
1197    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1198    #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
1199    pub meta: Option<Meta>,
1200}
1201
1202impl ReleaseTerminalResponse {
1203    #[must_use]
1204    pub fn new() -> Self {
1205        Self::default()
1206    }
1207
1208    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1209    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1210    /// these keys.
1211    ///
1212    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1213    #[must_use]
1214    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1215        self.meta = meta.into_option();
1216        self
1217    }
1218}
1219
1220/// Request to kill a terminal command without releasing the terminal.
1221#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1222#[serde(rename_all = "camelCase")]
1223#[schemars(extend("x-side" = "client", "x-method" = TERMINAL_KILL_METHOD_NAME))]
1224#[non_exhaustive]
1225pub struct KillTerminalCommandRequest {
1226    /// The session ID for this request.
1227    pub session_id: SessionId,
1228    /// The ID of the terminal to kill.
1229    pub terminal_id: TerminalId,
1230    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1231    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1232    /// these keys.
1233    ///
1234    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1235    #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
1236    pub meta: Option<Meta>,
1237}
1238
1239impl KillTerminalCommandRequest {
1240    #[must_use]
1241    pub fn new(session_id: impl Into<SessionId>, terminal_id: impl Into<TerminalId>) -> Self {
1242        Self {
1243            session_id: session_id.into(),
1244            terminal_id: terminal_id.into(),
1245            meta: None,
1246        }
1247    }
1248
1249    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1250    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1251    /// these keys.
1252    ///
1253    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1254    #[must_use]
1255    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1256        self.meta = meta.into_option();
1257        self
1258    }
1259}
1260
1261/// Response to terminal/kill command method
1262#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1263#[serde(rename_all = "camelCase")]
1264#[schemars(extend("x-side" = "client", "x-method" = TERMINAL_KILL_METHOD_NAME))]
1265#[non_exhaustive]
1266pub struct KillTerminalCommandResponse {
1267    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1268    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1269    /// these keys.
1270    ///
1271    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1272    #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
1273    pub meta: Option<Meta>,
1274}
1275
1276impl KillTerminalCommandResponse {
1277    #[must_use]
1278    pub fn new() -> Self {
1279        Self::default()
1280    }
1281
1282    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1283    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1284    /// these keys.
1285    ///
1286    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1287    #[must_use]
1288    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1289        self.meta = meta.into_option();
1290        self
1291    }
1292}
1293
1294/// Request to wait for a terminal command to exit.
1295#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1296#[serde(rename_all = "camelCase")]
1297#[schemars(extend("x-side" = "client", "x-method" = TERMINAL_WAIT_FOR_EXIT_METHOD_NAME))]
1298#[non_exhaustive]
1299pub struct WaitForTerminalExitRequest {
1300    /// The session ID for this request.
1301    pub session_id: SessionId,
1302    /// The ID of the terminal to wait for.
1303    pub terminal_id: TerminalId,
1304    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1305    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1306    /// these keys.
1307    ///
1308    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1309    #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
1310    pub meta: Option<Meta>,
1311}
1312
1313impl WaitForTerminalExitRequest {
1314    #[must_use]
1315    pub fn new(session_id: impl Into<SessionId>, terminal_id: impl Into<TerminalId>) -> Self {
1316        Self {
1317            session_id: session_id.into(),
1318            terminal_id: terminal_id.into(),
1319            meta: None,
1320        }
1321    }
1322
1323    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1324    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1325    /// these keys.
1326    ///
1327    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1328    #[must_use]
1329    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1330        self.meta = meta.into_option();
1331        self
1332    }
1333}
1334
1335/// Response containing the exit status of a terminal command.
1336#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1337#[serde(rename_all = "camelCase")]
1338#[schemars(extend("x-side" = "client", "x-method" = TERMINAL_WAIT_FOR_EXIT_METHOD_NAME))]
1339#[non_exhaustive]
1340pub struct WaitForTerminalExitResponse {
1341    /// The exit status of the terminal command.
1342    #[serde(flatten)]
1343    pub exit_status: TerminalExitStatus,
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 WaitForTerminalExitResponse {
1354    #[must_use]
1355    pub fn new(exit_status: TerminalExitStatus) -> Self {
1356        Self {
1357            exit_status,
1358            meta: None,
1359        }
1360    }
1361
1362    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1363    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1364    /// these keys.
1365    ///
1366    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1367    #[must_use]
1368    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1369        self.meta = meta.into_option();
1370        self
1371    }
1372}
1373
1374/// Exit status of a terminal command.
1375#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1376#[serde(rename_all = "camelCase")]
1377#[non_exhaustive]
1378pub struct TerminalExitStatus {
1379    /// The process exit code (may be null if terminated by signal).
1380    pub exit_code: Option<u32>,
1381    /// The signal that terminated the process (may be null if exited normally).
1382    pub signal: Option<String>,
1383    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1384    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1385    /// these keys.
1386    ///
1387    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1388    #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
1389    pub meta: Option<Meta>,
1390}
1391
1392impl TerminalExitStatus {
1393    #[must_use]
1394    pub fn new() -> Self {
1395        Self::default()
1396    }
1397
1398    /// The process exit code (may be null if terminated by signal).
1399    #[must_use]
1400    pub fn exit_code(mut self, exit_code: impl IntoOption<u32>) -> Self {
1401        self.exit_code = exit_code.into_option();
1402        self
1403    }
1404
1405    /// The signal that terminated the process (may be null if exited normally).
1406    #[must_use]
1407    pub fn signal(mut self, signal: impl IntoOption<String>) -> Self {
1408        self.signal = signal.into_option();
1409        self
1410    }
1411
1412    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1413    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1414    /// these keys.
1415    ///
1416    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1417    #[must_use]
1418    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1419        self.meta = meta.into_option();
1420        self
1421    }
1422}
1423
1424// Capabilities
1425
1426/// Capabilities supported by the client.
1427///
1428/// Advertised during initialization to inform the agent about
1429/// available features and methods.
1430///
1431/// See protocol docs: [Client Capabilities](https://agentclientprotocol.com/protocol/initialization#client-capabilities)
1432#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1433#[serde(rename_all = "camelCase")]
1434#[non_exhaustive]
1435pub struct ClientCapabilities {
1436    /// File system capabilities supported by the client.
1437    /// Determines which file operations the agent can request.
1438    #[serde(default)]
1439    pub fs: FileSystemCapability,
1440    /// Whether the Client support all `terminal/*` methods.
1441    #[serde(default)]
1442    pub terminal: bool,
1443    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1444    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1445    /// these keys.
1446    ///
1447    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1448    #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
1449    pub meta: Option<Meta>,
1450}
1451
1452impl ClientCapabilities {
1453    #[must_use]
1454    pub fn new() -> Self {
1455        Self::default()
1456    }
1457
1458    /// File system capabilities supported by the client.
1459    /// Determines which file operations the agent can request.
1460    #[must_use]
1461    pub fn fs(mut self, fs: FileSystemCapability) -> Self {
1462        self.fs = fs;
1463        self
1464    }
1465
1466    /// Whether the Client support all `terminal/*` methods.
1467    #[must_use]
1468    pub fn terminal(mut self, terminal: bool) -> Self {
1469        self.terminal = terminal;
1470        self
1471    }
1472
1473    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1474    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1475    /// these keys.
1476    ///
1477    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1478    #[must_use]
1479    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1480        self.meta = meta.into_option();
1481        self
1482    }
1483}
1484
1485/// Filesystem capabilities supported by the client.
1486/// File system capabilities that a client may support.
1487///
1488/// See protocol docs: [FileSystem](https://agentclientprotocol.com/protocol/initialization#filesystem)
1489#[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
1490#[serde(rename_all = "camelCase")]
1491#[non_exhaustive]
1492pub struct FileSystemCapability {
1493    /// Whether the Client supports `fs/read_text_file` requests.
1494    #[serde(default)]
1495    pub read_text_file: bool,
1496    /// Whether the Client supports `fs/write_text_file` requests.
1497    #[serde(default)]
1498    pub write_text_file: bool,
1499    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1500    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1501    /// these keys.
1502    ///
1503    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1504    #[serde(skip_serializing_if = "Option::is_none", rename = "_meta")]
1505    pub meta: Option<Meta>,
1506}
1507
1508impl FileSystemCapability {
1509    #[must_use]
1510    pub fn new() -> Self {
1511        Self::default()
1512    }
1513
1514    /// Whether the Client supports `fs/read_text_file` requests.
1515    #[must_use]
1516    pub fn read_text_file(mut self, read_text_file: bool) -> Self {
1517        self.read_text_file = read_text_file;
1518        self
1519    }
1520
1521    /// Whether the Client supports `fs/write_text_file` requests.
1522    #[must_use]
1523    pub fn write_text_file(mut self, write_text_file: bool) -> Self {
1524        self.write_text_file = write_text_file;
1525        self
1526    }
1527
1528    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1529    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1530    /// these keys.
1531    ///
1532    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1533    #[must_use]
1534    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1535        self.meta = meta.into_option();
1536        self
1537    }
1538}
1539
1540// Method schema
1541
1542/// Names of all methods that clients handle.
1543///
1544/// Provides a centralized definition of method names used in the protocol.
1545#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
1546#[non_exhaustive]
1547pub struct ClientMethodNames {
1548    /// Method for requesting permission from the user.
1549    pub session_request_permission: &'static str,
1550    /// Notification for session updates.
1551    pub session_update: &'static str,
1552    /// Method for writing text files.
1553    pub fs_write_text_file: &'static str,
1554    /// Method for reading text files.
1555    pub fs_read_text_file: &'static str,
1556    /// Method for creating new terminals.
1557    pub terminal_create: &'static str,
1558    /// Method for getting terminals output.
1559    pub terminal_output: &'static str,
1560    /// Method for releasing a terminal.
1561    pub terminal_release: &'static str,
1562    /// Method for waiting for a terminal to finish.
1563    pub terminal_wait_for_exit: &'static str,
1564    /// Method for killing a terminal.
1565    pub terminal_kill: &'static str,
1566}
1567
1568/// Constant containing all client method names.
1569pub const CLIENT_METHOD_NAMES: ClientMethodNames = ClientMethodNames {
1570    session_update: SESSION_UPDATE_NOTIFICATION,
1571    session_request_permission: SESSION_REQUEST_PERMISSION_METHOD_NAME,
1572    fs_write_text_file: FS_WRITE_TEXT_FILE_METHOD_NAME,
1573    fs_read_text_file: FS_READ_TEXT_FILE_METHOD_NAME,
1574    terminal_create: TERMINAL_CREATE_METHOD_NAME,
1575    terminal_output: TERMINAL_OUTPUT_METHOD_NAME,
1576    terminal_release: TERMINAL_RELEASE_METHOD_NAME,
1577    terminal_wait_for_exit: TERMINAL_WAIT_FOR_EXIT_METHOD_NAME,
1578    terminal_kill: TERMINAL_KILL_METHOD_NAME,
1579};
1580
1581/// Notification name for session updates.
1582pub(crate) const SESSION_UPDATE_NOTIFICATION: &str = "session/update";
1583/// Method name for requesting user permission.
1584pub(crate) const SESSION_REQUEST_PERMISSION_METHOD_NAME: &str = "session/request_permission";
1585/// Method name for writing text files.
1586pub(crate) const FS_WRITE_TEXT_FILE_METHOD_NAME: &str = "fs/write_text_file";
1587/// Method name for reading text files.
1588pub(crate) const FS_READ_TEXT_FILE_METHOD_NAME: &str = "fs/read_text_file";
1589/// Method name for creating a new terminal.
1590pub(crate) const TERMINAL_CREATE_METHOD_NAME: &str = "terminal/create";
1591/// Method for getting terminals output.
1592pub(crate) const TERMINAL_OUTPUT_METHOD_NAME: &str = "terminal/output";
1593/// Method for releasing a terminal.
1594pub(crate) const TERMINAL_RELEASE_METHOD_NAME: &str = "terminal/release";
1595/// Method for waiting for a terminal to finish.
1596pub(crate) const TERMINAL_WAIT_FOR_EXIT_METHOD_NAME: &str = "terminal/wait_for_exit";
1597/// Method for killing a terminal.
1598pub(crate) const TERMINAL_KILL_METHOD_NAME: &str = "terminal/kill";
1599
1600/// All possible requests that an agent can send to a client.
1601///
1602/// This enum is used internally for routing RPC requests. You typically won't need
1603/// to use this directly - instead, use the methods on the [`Client`] trait.
1604///
1605/// This enum encompasses all method calls from agent to client.
1606#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
1607#[serde(untagged)]
1608#[schemars(inline)]
1609#[non_exhaustive]
1610pub enum AgentRequest {
1611    /// Writes content to a text file in the client's file system.
1612    ///
1613    /// Only available if the client advertises the `fs.writeTextFile` capability.
1614    /// Allows the agent to create or modify files within the client's environment.
1615    ///
1616    /// See protocol docs: [Client](https://agentclientprotocol.com/protocol/overview#client)
1617    WriteTextFileRequest(WriteTextFileRequest),
1618    /// Reads content from a text file in the client's file system.
1619    ///
1620    /// Only available if the client advertises the `fs.readTextFile` capability.
1621    /// Allows the agent to access file contents within the client's environment.
1622    ///
1623    /// See protocol docs: [Client](https://agentclientprotocol.com/protocol/overview#client)
1624    ReadTextFileRequest(ReadTextFileRequest),
1625    /// Requests permission from the user for a tool call operation.
1626    ///
1627    /// Called by the agent when it needs user authorization before executing
1628    /// a potentially sensitive operation. The client should present the options
1629    /// to the user and return their decision.
1630    ///
1631    /// If the client cancels the prompt turn via `session/cancel`, it MUST
1632    /// respond to this request with `RequestPermissionOutcome::Cancelled`.
1633    ///
1634    /// See protocol docs: [Requesting Permission](https://agentclientprotocol.com/protocol/tool-calls#requesting-permission)
1635    RequestPermissionRequest(RequestPermissionRequest),
1636    /// Executes a command in a new terminal
1637    ///
1638    /// Only available if the `terminal` Client capability is set to `true`.
1639    ///
1640    /// Returns a `TerminalId` that can be used with other terminal methods
1641    /// to get the current output, wait for exit, and kill the command.
1642    ///
1643    /// The `TerminalId` can also be used to embed the terminal in a tool call
1644    /// by using the `ToolCallContent::Terminal` variant.
1645    ///
1646    /// The Agent is responsible for releasing the terminal by using the `terminal/release`
1647    /// method.
1648    ///
1649    /// See protocol docs: [Terminals](https://agentclientprotocol.com/protocol/terminals)
1650    CreateTerminalRequest(CreateTerminalRequest),
1651    /// Gets the terminal output and exit status
1652    ///
1653    /// Returns the current content in the terminal without waiting for the command to exit.
1654    /// If the command has already exited, the exit status is included.
1655    ///
1656    /// See protocol docs: [Terminals](https://agentclientprotocol.com/protocol/terminals)
1657    TerminalOutputRequest(TerminalOutputRequest),
1658    /// Releases a terminal
1659    ///
1660    /// The command is killed if it hasn't exited yet. Use `terminal/wait_for_exit`
1661    /// to wait for the command to exit before releasing the terminal.
1662    ///
1663    /// After release, the `TerminalId` can no longer be used with other `terminal/*` methods,
1664    /// but tool calls that already contain it, continue to display its output.
1665    ///
1666    /// The `terminal/kill` method can be used to terminate the command without releasing
1667    /// the terminal, allowing the Agent to call `terminal/output` and other methods.
1668    ///
1669    /// See protocol docs: [Terminals](https://agentclientprotocol.com/protocol/terminals)
1670    ReleaseTerminalRequest(ReleaseTerminalRequest),
1671    /// Waits for the terminal command to exit and return its exit status
1672    ///
1673    /// See protocol docs: [Terminals](https://agentclientprotocol.com/protocol/terminals)
1674    WaitForTerminalExitRequest(WaitForTerminalExitRequest),
1675    /// Kills the terminal command without releasing the terminal
1676    ///
1677    /// While `terminal/release` will also kill the command, this method will keep
1678    /// the `TerminalId` valid so it can be used with other methods.
1679    ///
1680    /// This method can be helpful when implementing command timeouts which terminate
1681    /// the command as soon as elapsed, and then get the final output so it can be sent
1682    /// to the model.
1683    ///
1684    /// Note: `terminal/release` when `TerminalId` is no longer needed.
1685    ///
1686    /// See protocol docs: [Terminals](https://agentclientprotocol.com/protocol/terminals)
1687    KillTerminalCommandRequest(KillTerminalCommandRequest),
1688    /// Handles extension method requests from the agent.
1689    ///
1690    /// Allows the Agent to send an arbitrary request that is not part of the ACP spec.
1691    /// Extension methods provide a way to add custom functionality while maintaining
1692    /// protocol compatibility.
1693    ///
1694    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1695    ExtMethodRequest(ExtRequest),
1696}
1697
1698impl AgentRequest {
1699    /// Returns the corresponding method name of the request.
1700    #[must_use]
1701    pub fn method(&self) -> &str {
1702        match self {
1703            Self::WriteTextFileRequest(_) => CLIENT_METHOD_NAMES.fs_write_text_file,
1704            Self::ReadTextFileRequest(_) => CLIENT_METHOD_NAMES.fs_read_text_file,
1705            Self::RequestPermissionRequest(_) => CLIENT_METHOD_NAMES.session_request_permission,
1706            Self::CreateTerminalRequest(_) => CLIENT_METHOD_NAMES.terminal_create,
1707            Self::TerminalOutputRequest(_) => CLIENT_METHOD_NAMES.terminal_output,
1708            Self::ReleaseTerminalRequest(_) => CLIENT_METHOD_NAMES.terminal_release,
1709            Self::WaitForTerminalExitRequest(_) => CLIENT_METHOD_NAMES.terminal_wait_for_exit,
1710            Self::KillTerminalCommandRequest(_) => CLIENT_METHOD_NAMES.terminal_kill,
1711            Self::ExtMethodRequest(ext_request) => &ext_request.method,
1712        }
1713    }
1714}
1715
1716/// All possible responses that a client can send to an agent.
1717///
1718/// This enum is used internally for routing RPC responses. You typically won't need
1719/// to use this directly - the responses are handled automatically by the connection.
1720///
1721/// These are responses to the corresponding `AgentRequest` variants.
1722#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
1723#[serde(untagged)]
1724#[schemars(inline)]
1725#[non_exhaustive]
1726pub enum ClientResponse {
1727    WriteTextFileResponse(#[serde(default)] WriteTextFileResponse),
1728    ReadTextFileResponse(ReadTextFileResponse),
1729    RequestPermissionResponse(RequestPermissionResponse),
1730    CreateTerminalResponse(CreateTerminalResponse),
1731    TerminalOutputResponse(TerminalOutputResponse),
1732    ReleaseTerminalResponse(#[serde(default)] ReleaseTerminalResponse),
1733    WaitForTerminalExitResponse(WaitForTerminalExitResponse),
1734    KillTerminalResponse(#[serde(default)] KillTerminalCommandResponse),
1735    ExtMethodResponse(ExtResponse),
1736}
1737
1738/// All possible notifications that an agent can send to a client.
1739///
1740/// This enum is used internally for routing RPC notifications. You typically won't need
1741/// to use this directly - use the notification methods on the [`Client`] trait instead.
1742///
1743/// Notifications do not expect a response.
1744#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
1745#[serde(untagged)]
1746#[expect(clippy::large_enum_variant)]
1747#[schemars(inline)]
1748#[non_exhaustive]
1749pub enum AgentNotification {
1750    /// Handles session update notifications from the agent.
1751    ///
1752    /// This is a notification endpoint (no response expected) that receives
1753    /// real-time updates about session progress, including message chunks,
1754    /// tool calls, and execution plans.
1755    ///
1756    /// Note: Clients SHOULD continue accepting tool call updates even after
1757    /// sending a `session/cancel` notification, as the agent may send final
1758    /// updates before responding with the cancelled stop reason.
1759    ///
1760    /// See protocol docs: [Agent Reports Output](https://agentclientprotocol.com/protocol/prompt-turn#3-agent-reports-output)
1761    SessionNotification(SessionNotification),
1762    /// Handles extension notifications from the agent.
1763    ///
1764    /// Allows the Agent to send an arbitrary notification that is not part of the ACP spec.
1765    /// Extension notifications provide a way to send one-way messages for custom functionality
1766    /// while maintaining protocol compatibility.
1767    ///
1768    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1769    ExtNotification(ExtNotification),
1770}
1771
1772impl AgentNotification {
1773    /// Returns the corresponding method name of the notification.
1774    #[must_use]
1775    pub fn method(&self) -> &str {
1776        match self {
1777            Self::SessionNotification(_) => CLIENT_METHOD_NAMES.session_update,
1778            Self::ExtNotification(ext_notification) => &ext_notification.method,
1779        }
1780    }
1781}
1782
1783#[cfg(test)]
1784mod tests {
1785    use super::*;
1786
1787    #[cfg(feature = "unstable_session_info_update")]
1788    #[test]
1789    fn test_serialization_behavior() {
1790        use serde_json::json;
1791
1792        assert_eq!(
1793            serde_json::from_value::<SessionInfoUpdate>(json!({})).unwrap(),
1794            SessionInfoUpdate {
1795                title: MaybeUndefined::Undefined,
1796                updated_at: MaybeUndefined::Undefined,
1797                meta: None
1798            }
1799        );
1800        assert_eq!(
1801            serde_json::from_value::<SessionInfoUpdate>(json!({"title": null, "updatedAt": null}))
1802                .unwrap(),
1803            SessionInfoUpdate {
1804                title: MaybeUndefined::Null,
1805                updated_at: MaybeUndefined::Null,
1806                meta: None
1807            }
1808        );
1809        assert_eq!(
1810            serde_json::from_value::<SessionInfoUpdate>(
1811                json!({"title": "title", "updatedAt": "timestamp"})
1812            )
1813            .unwrap(),
1814            SessionInfoUpdate {
1815                title: MaybeUndefined::Value("title".to_string()),
1816                updated_at: MaybeUndefined::Value("timestamp".to_string()),
1817                meta: None
1818            }
1819        );
1820
1821        assert_eq!(
1822            serde_json::to_value(SessionInfoUpdate::new()).unwrap(),
1823            json!({})
1824        );
1825        assert_eq!(
1826            serde_json::to_value(SessionInfoUpdate::new().title("title")).unwrap(),
1827            json!({"title": "title"})
1828        );
1829        assert_eq!(
1830            serde_json::to_value(SessionInfoUpdate::new().title(None)).unwrap(),
1831            json!({"title": null})
1832        );
1833        assert_eq!(
1834            serde_json::to_value(
1835                SessionInfoUpdate::new()
1836                    .title("title")
1837                    .title(MaybeUndefined::Undefined)
1838            )
1839            .unwrap(),
1840            json!({})
1841        );
1842    }
1843}