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}