Skip to main content

agent_client_protocol_schema/v1/
client.rs

1//! Methods and notifications the client handles/receives.
2//!
3//! This module defines the Client trait and all associated types for implementing
4//! a client that interacts with AI coding agents via the Agent Client Protocol (ACP).
5
6use std::{path::PathBuf, sync::Arc};
7
8use derive_more::{Display, From};
9use serde::{Deserialize, Serialize};
10use serde_with::{DefaultOnError, VecSkipError, serde_as, skip_serializing_none};
11
12use super::{
13    CompleteElicitationNotification, CreateElicitationRequest, CreateElicitationResponse,
14    ElicitationCapabilities,
15};
16use crate::{IntoMaybeUndefined, IntoOption, MaybeUndefined, SkipListener};
17
18use super::{
19    ContentBlock, EnvVariable, ExtNotification, ExtRequest, ExtResponse, Meta, Plan,
20    SessionConfigOption, SessionId, SessionModeId, ToolCall, ToolCallUpdate,
21};
22#[cfg(feature = "unstable_plan_operations")]
23use super::{PlanCapabilities, PlanRemoved, PlanUpdate};
24
25#[cfg(feature = "unstable_mcp_over_acp")]
26use super::mcp::{
27    ConnectMcpRequest, ConnectMcpResponse, DisconnectMcpRequest, DisconnectMcpResponse,
28    MCP_CONNECT_METHOD_NAME, MCP_DISCONNECT_METHOD_NAME, MCP_MESSAGE_METHOD_NAME,
29    MessageMcpNotification, MessageMcpRequest, MessageMcpResponse,
30};
31
32#[cfg(feature = "unstable_nes")]
33use super::{ClientNesCapabilities, PositionEncodingKind};
34
35// Session updates
36
37/// Notification containing a session update from the agent.
38///
39/// Used to stream real-time progress and results during prompt processing.
40///
41/// See protocol docs: [Agent Reports Output](https://agentclientprotocol.com/protocol/prompt-turn#3-agent-reports-output)
42#[serde_as]
43#[skip_serializing_none]
44#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
45#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
46#[cfg_attr(feature = "schemars", schemars(extend("x-side" = "client", "x-method" = SESSION_UPDATE_NOTIFICATION)))]
47#[serde(rename_all = "camelCase")]
48#[non_exhaustive]
49pub struct SessionNotification {
50    /// The ID of the session this update pertains to.
51    pub session_id: SessionId,
52    /// The actual update content.
53    pub update: SessionUpdate,
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    #[serde_as(deserialize_as = "DefaultOnError")]
60    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
61    #[serde(default)]
62    #[serde(rename = "_meta")]
63    pub meta: Option<Meta>,
64}
65
66impl SessionNotification {
67    /// Builds [`SessionNotification`] with the required notification fields set; optional fields start unset or empty.
68    #[must_use]
69    pub fn new(session_id: impl Into<SessionId>, update: SessionUpdate) -> Self {
70        Self {
71            session_id: session_id.into(),
72            update,
73            meta: None,
74        }
75    }
76
77    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
78    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
79    /// these keys.
80    ///
81    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
82    #[must_use]
83    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
84        self.meta = meta.into_option();
85        self
86    }
87}
88
89/// Different types of updates that can be sent during session processing.
90///
91/// These updates provide real-time feedback about the agent's progress.
92///
93/// See protocol docs: [Agent Reports Output](https://agentclientprotocol.com/protocol/prompt-turn#3-agent-reports-output)
94#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
95#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
96#[serde(tag = "sessionUpdate", rename_all = "snake_case")]
97#[cfg_attr(feature = "schemars", schemars(extend("discriminator" = {"propertyName": "sessionUpdate"})))]
98#[non_exhaustive]
99pub enum SessionUpdate {
100    /// A chunk of the user's message being streamed.
101    UserMessageChunk(ContentChunk),
102    /// A chunk of the agent's response being streamed.
103    AgentMessageChunk(ContentChunk),
104    /// A chunk of the agent's internal reasoning being streamed.
105    AgentThoughtChunk(ContentChunk),
106    /// Notification that a new tool call has been initiated.
107    ToolCall(ToolCall),
108    /// Update on the status or results of a tool call.
109    ToolCallUpdate(ToolCallUpdate),
110    /// The agent's execution plan for complex tasks.
111    /// See protocol docs: [Agent Plan](https://agentclientprotocol.com/protocol/agent-plan)
112    Plan(Plan),
113    /// **UNSTABLE**
114    ///
115    /// This capability is not part of the spec yet, and may be removed or changed at any point.
116    ///
117    /// A content update for a plan identified by ID.
118    #[cfg(feature = "unstable_plan_operations")]
119    PlanUpdate(PlanUpdate),
120    /// **UNSTABLE**
121    ///
122    /// This capability is not part of the spec yet, and may be removed or changed at any point.
123    ///
124    /// Removal notice for a plan identified by ID.
125    #[cfg(feature = "unstable_plan_operations")]
126    PlanRemoved(PlanRemoved),
127    /// Available commands are ready or have changed
128    AvailableCommandsUpdate(AvailableCommandsUpdate),
129    /// The current mode of the session has changed
130    ///
131    /// See protocol docs: [Session Modes](https://agentclientprotocol.com/protocol/session-modes)
132    CurrentModeUpdate(CurrentModeUpdate),
133    /// Session configuration options have been updated.
134    ConfigOptionUpdate(ConfigOptionUpdate),
135    /// Session metadata has been updated (title, timestamps, custom metadata)
136    SessionInfoUpdate(SessionInfoUpdate),
137    /// Context window and cost update for the session.
138    UsageUpdate(UsageUpdate),
139    /// **UNSTABLE**
140    ///
141    /// This capability is not part of the spec yet, and may be removed or changed at any point.
142    ///
143    /// A context compaction has been created or updated.
144    ///
145    /// Agents MUST only send this update when the Client advertised
146    /// [`ClientSessionCapabilities::compaction`].
147    #[cfg(feature = "unstable_session_compaction")]
148    CompactionUpdate(CompactionUpdate),
149    /// **UNSTABLE**
150    ///
151    /// This capability is not part of the spec yet, and may be removed or changed at any point.
152    ///
153    /// A content block appended to a context compaction's retained summary.
154    ///
155    /// Agents MUST only send this update when the Client advertised
156    /// [`ClientSessionCapabilities::compaction`].
157    #[cfg(feature = "unstable_session_compaction")]
158    CompactionSummaryChunk(CompactionSummaryChunk),
159}
160
161/// **UNSTABLE**
162///
163/// This capability is not part of the spec yet, and may be removed or changed at any point.
164///
165/// Unique identifier for a context compaction within a session.
166#[cfg(feature = "unstable_session_compaction")]
167#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
168#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash, Display, From)]
169#[serde(transparent)]
170#[from(Arc<str>, String, &'static str)]
171#[non_exhaustive]
172pub struct CompactionId(pub Arc<str>);
173
174#[cfg(feature = "unstable_session_compaction")]
175impl CompactionId {
176    /// Wraps a protocol string as a typed [`CompactionId`].
177    #[must_use]
178    pub fn new(id: impl Into<Arc<str>>) -> Self {
179        Self(id.into())
180    }
181}
182
183/// **UNSTABLE**
184///
185/// This capability is not part of the spec yet, and may be removed or changed at any point.
186///
187/// Lifecycle state of a context compaction.
188#[cfg(feature = "unstable_session_compaction")]
189#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
190#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
191#[serde(rename_all = "snake_case")]
192#[non_exhaustive]
193pub enum CompactionStatus {
194    /// Compaction has started and has not finished.
195    InProgress,
196    /// Compaction finished successfully.
197    Completed,
198    /// Compaction finished unsuccessfully.
199    Failed,
200    /// Compaction was cancelled before it finished.
201    Cancelled,
202    /// Custom or future compaction status.
203    ///
204    /// Values beginning with `_` are reserved for implementation-specific
205    /// extensions. Other unknown values are reserved for future ACP statuses.
206    #[serde(untagged)]
207    Other(String),
208}
209
210/// **UNSTABLE**
211///
212/// This capability is not part of the spec yet, and may be removed or changed at any point.
213///
214/// A context compaction upsert. The first update fixes the compaction's
215/// timeline position. Later updates with the same ID patch that entity in place.
216/// Agents MUST only send this update when the Client advertised
217/// [`ClientSessionCapabilities::compaction`].
218///
219/// `summary`, `error`, and `_meta` have patch semantics: omission leaves the
220/// stored value unchanged, `null` clears it, and a concrete value replaces it.
221/// `summary: []` also clears the retained summary. A non-empty summary is only
222/// valid with `completed`; `error` is only valid with `failed`.
223#[cfg(feature = "unstable_session_compaction")]
224#[serde_as]
225#[skip_serializing_none]
226#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
227#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
228#[serde(rename_all = "camelCase")]
229#[non_exhaustive]
230pub struct CompactionUpdate {
231    /// The Agent-owned ID of this compaction, unique within the session.
232    pub compaction_id: CompactionId,
233    /// Current lifecycle status.
234    pub status: CompactionStatus,
235    /// Complete replacement user-displayable summary retained by the compaction.
236    #[serde_as(deserialize_as = "DefaultOnError<MaybeUndefined<VecSkipError<_, SkipListener>>>")]
237    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true, "x-deserialize-skip-invalid-items" = true)))]
238    #[serde(default, skip_serializing_if = "MaybeUndefined::is_undefined")]
239    pub summary: MaybeUndefined<Vec<ContentBlock>>,
240    /// Human-readable description of why the compaction failed.
241    #[serde_as(deserialize_as = "DefaultOnError<MaybeUndefined<_>>")]
242    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
243    #[serde(default, skip_serializing_if = "MaybeUndefined::is_undefined")]
244    pub error: MaybeUndefined<String>,
245    /// Extensible metadata patch for this compaction.
246    #[serde_as(deserialize_as = "DefaultOnError<MaybeUndefined<_>>")]
247    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
248    #[serde(
249        rename = "_meta",
250        default,
251        skip_serializing_if = "MaybeUndefined::is_undefined"
252    )]
253    pub meta: MaybeUndefined<Meta>,
254}
255
256#[cfg(feature = "unstable_session_compaction")]
257impl CompactionUpdate {
258    /// Builds a compaction update with optional patch fields omitted.
259    #[must_use]
260    pub fn new(compaction_id: impl Into<CompactionId>, status: CompactionStatus) -> Self {
261        Self {
262            compaction_id: compaction_id.into(),
263            status,
264            summary: MaybeUndefined::Undefined,
265            error: MaybeUndefined::Undefined,
266            meta: MaybeUndefined::Undefined,
267        }
268    }
269
270    /// Sets, clears, or omits the complete retained summary patch.
271    #[must_use]
272    pub fn summary(mut self, summary: impl IntoMaybeUndefined<Vec<ContentBlock>>) -> Self {
273        self.summary = summary.into_maybe_undefined();
274        self
275    }
276
277    /// Sets, clears, or omits the failure description patch.
278    #[must_use]
279    pub fn error(mut self, error: impl IntoMaybeUndefined<String>) -> Self {
280        self.error = error.into_maybe_undefined();
281        self
282    }
283
284    /// Sets, clears, or omits the metadata patch.
285    #[must_use]
286    pub fn meta(mut self, meta: impl IntoMaybeUndefined<Meta>) -> Self {
287        self.meta = meta.into_maybe_undefined();
288        self
289    }
290}
291
292/// **UNSTABLE**
293///
294/// This capability is not part of the spec yet, and may be removed or changed at any point.
295///
296/// A content block appended to the retained summary of an in-progress
297/// compaction. Agents send chunks only after an `in_progress` update and before
298/// the terminal update for the same ID. Agents MUST only send this update when
299/// the Client advertised [`ClientSessionCapabilities::compaction`].
300#[cfg(feature = "unstable_session_compaction")]
301#[serde_as]
302#[skip_serializing_none]
303#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
304#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
305#[serde(rename_all = "camelCase")]
306#[non_exhaustive]
307pub struct CompactionSummaryChunk {
308    /// ID of the compaction whose summary receives this content.
309    pub compaction_id: CompactionId,
310    /// One content block to append.
311    pub content: ContentBlock,
312    /// Metadata scoped to this chunk. Omission and `null` both mean absent.
313    #[serde_as(deserialize_as = "DefaultOnError")]
314    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
315    #[serde(default, rename = "_meta")]
316    pub meta: Option<Meta>,
317}
318
319#[cfg(feature = "unstable_session_compaction")]
320impl CompactionSummaryChunk {
321    /// Builds a summary chunk without metadata.
322    #[must_use]
323    pub fn new(compaction_id: impl Into<CompactionId>, content: ContentBlock) -> Self {
324        Self {
325            compaction_id: compaction_id.into(),
326            content,
327            meta: None,
328        }
329    }
330
331    /// Sets or clears chunk-scoped metadata.
332    #[must_use]
333    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
334        self.meta = meta.into_option();
335        self
336    }
337}
338
339/// The current mode of the session has changed
340///
341/// See protocol docs: [Session Modes](https://agentclientprotocol.com/protocol/session-modes)
342#[serde_as]
343#[skip_serializing_none]
344#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
345#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
346#[serde(rename_all = "camelCase")]
347#[non_exhaustive]
348pub struct CurrentModeUpdate {
349    /// The ID of the current mode
350    pub current_mode_id: SessionModeId,
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    #[serde_as(deserialize_as = "DefaultOnError")]
357    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
358    #[serde(default)]
359    #[serde(rename = "_meta")]
360    pub meta: Option<Meta>,
361}
362
363impl CurrentModeUpdate {
364    /// Builds [`CurrentModeUpdate`] with the required fields set; optional fields start unset or empty.
365    #[must_use]
366    pub fn new(current_mode_id: impl Into<SessionModeId>) -> Self {
367        Self {
368            current_mode_id: current_mode_id.into(),
369            meta: None,
370        }
371    }
372
373    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
374    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
375    /// these keys.
376    ///
377    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
378    #[must_use]
379    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
380        self.meta = meta.into_option();
381        self
382    }
383}
384
385/// Session configuration options have been updated.
386#[serde_as]
387#[skip_serializing_none]
388#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
389#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
390#[serde(rename_all = "camelCase")]
391#[non_exhaustive]
392pub struct ConfigOptionUpdate {
393    /// The full set of configuration options and their current values.
394    #[serde_as(deserialize_as = "DefaultOnError<VecSkipError<_, SkipListener>>")]
395    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true, "x-deserialize-skip-invalid-items" = true)))]
396    pub config_options: Vec<SessionConfigOption>,
397    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
398    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
399    /// these keys.
400    ///
401    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
402    #[serde_as(deserialize_as = "DefaultOnError")]
403    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
404    #[serde(default)]
405    #[serde(rename = "_meta")]
406    pub meta: Option<Meta>,
407}
408
409impl ConfigOptionUpdate {
410    /// Builds [`ConfigOptionUpdate`] with the required fields set; optional fields start unset or empty.
411    #[must_use]
412    pub fn new(config_options: Vec<SessionConfigOption>) -> Self {
413        Self {
414            config_options,
415            meta: None,
416        }
417    }
418
419    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
420    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
421    /// these keys.
422    ///
423    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
424    #[must_use]
425    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
426        self.meta = meta.into_option();
427        self
428    }
429}
430
431/// Update to session metadata. All fields are optional to support partial updates.
432///
433/// Agents send this notification to update session information like title or custom metadata.
434/// This allows clients to display dynamic session names and track session state changes.
435#[serde_as]
436#[skip_serializing_none]
437#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
438#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
439#[serde(rename_all = "camelCase")]
440#[non_exhaustive]
441pub struct SessionInfoUpdate {
442    /// Human-readable title for the session. Set to null to clear.
443    #[serde_as(deserialize_as = "DefaultOnError")]
444    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
445    #[serde(default, skip_serializing_if = "MaybeUndefined::is_undefined")]
446    pub title: MaybeUndefined<String>,
447    /// ISO 8601 timestamp of last activity. Set to null to clear.
448    #[serde_as(deserialize_as = "DefaultOnError")]
449    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
450    #[serde(default, skip_serializing_if = "MaybeUndefined::is_undefined")]
451    pub updated_at: MaybeUndefined<String>,
452    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
453    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
454    /// these keys.
455    ///
456    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
457    #[serde_as(deserialize_as = "DefaultOnError")]
458    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
459    #[serde(default)]
460    #[serde(rename = "_meta")]
461    pub meta: Option<Meta>,
462}
463
464impl SessionInfoUpdate {
465    /// Builds [`SessionInfoUpdate`] with the required fields set; optional fields start unset or empty.
466    #[must_use]
467    pub fn new() -> Self {
468        Self::default()
469    }
470
471    /// Human-readable title for the session. Set to null to clear.
472    #[must_use]
473    pub fn title(mut self, title: impl IntoMaybeUndefined<String>) -> Self {
474        self.title = title.into_maybe_undefined();
475        self
476    }
477
478    /// ISO 8601 timestamp of last activity. Set to null to clear.
479    #[must_use]
480    pub fn updated_at(mut self, updated_at: impl IntoMaybeUndefined<String>) -> Self {
481        self.updated_at = updated_at.into_maybe_undefined();
482        self
483    }
484
485    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
486    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
487    /// these keys.
488    ///
489    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
490    #[must_use]
491    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
492        self.meta = meta.into_option();
493        self
494    }
495}
496
497/// Context window and cost update for a session.
498#[serde_as]
499#[skip_serializing_none]
500#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
501#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
502#[serde(rename_all = "camelCase")]
503#[non_exhaustive]
504pub struct UsageUpdate {
505    /// Tokens currently in context.
506    pub used: u64,
507    /// Total context window size in tokens.
508    pub size: u64,
509    /// Cumulative session cost (optional).
510    #[serde_as(deserialize_as = "DefaultOnError")]
511    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
512    #[serde(default)]
513    pub cost: Option<Cost>,
514    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
515    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
516    /// these keys.
517    ///
518    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
519    #[serde_as(deserialize_as = "DefaultOnError")]
520    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
521    #[serde(default)]
522    #[serde(rename = "_meta")]
523    pub meta: Option<Meta>,
524}
525
526impl UsageUpdate {
527    /// Builds [`UsageUpdate`] with the required fields set; optional fields start unset or empty.
528    #[must_use]
529    pub fn new(used: u64, size: u64) -> Self {
530        Self {
531            used,
532            size,
533            cost: None,
534            meta: None,
535        }
536    }
537
538    /// Cumulative session cost (optional).
539    #[must_use]
540    pub fn cost(mut self, cost: impl IntoOption<Cost>) -> Self {
541        self.cost = cost.into_option();
542        self
543    }
544
545    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
546    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
547    /// these keys.
548    ///
549    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
550    #[must_use]
551    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
552        self.meta = meta.into_option();
553        self
554    }
555}
556
557/// Cost information for a session.
558#[serde_as]
559#[skip_serializing_none]
560#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
561#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
562#[serde(rename_all = "camelCase")]
563#[non_exhaustive]
564pub struct Cost {
565    /// Total cumulative cost for session.
566    pub amount: f64,
567    /// ISO 4217 currency code (e.g., "USD", "EUR").
568    pub currency: String,
569    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
570    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
571    /// these keys.
572    ///
573    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
574    #[serde_as(deserialize_as = "DefaultOnError")]
575    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
576    #[serde(default)]
577    #[serde(rename = "_meta")]
578    pub meta: Option<Meta>,
579}
580
581impl Cost {
582    /// Builds [`Cost`] with the required fields set; optional fields start unset or empty.
583    #[must_use]
584    pub fn new(amount: f64, currency: impl Into<String>) -> Self {
585        Self {
586            amount,
587            currency: currency.into(),
588            meta: None,
589        }
590    }
591
592    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
593    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
594    /// these keys.
595    ///
596    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
597    #[must_use]
598    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
599        self.meta = meta.into_option();
600        self
601    }
602}
603
604/// A streamed item of content
605#[serde_as]
606#[skip_serializing_none]
607#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
608#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
609#[serde(rename_all = "camelCase")]
610#[non_exhaustive]
611pub struct ContentChunk {
612    /// A single item of content
613    pub content: ContentBlock,
614    /// A unique identifier for the message this chunk belongs to.
615    ///
616    /// All chunks belonging to the same message share the same `messageId`.
617    /// A change in `messageId` indicates a new message has started.
618    #[serde_as(deserialize_as = "DefaultOnError")]
619    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
620    #[serde(default)]
621    pub message_id: Option<MessageId>,
622    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
623    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
624    /// these keys.
625    ///
626    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
627    #[serde_as(deserialize_as = "DefaultOnError")]
628    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
629    #[serde(default)]
630    #[serde(rename = "_meta")]
631    pub meta: Option<Meta>,
632}
633
634impl ContentChunk {
635    /// Builds [`ContentChunk`] with the required fields set; optional fields start unset or empty.
636    #[must_use]
637    pub fn new(content: ContentBlock) -> Self {
638        Self {
639            content,
640            message_id: None,
641            meta: None,
642        }
643    }
644
645    /// A unique identifier for the message this chunk belongs to.
646    ///
647    /// All chunks belonging to the same message share the same `messageId`.
648    /// A change in `messageId` indicates a new message has started.
649    #[must_use]
650    pub fn message_id(mut self, message_id: impl IntoOption<MessageId>) -> Self {
651        self.message_id = message_id.into_option();
652        self
653    }
654
655    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
656    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
657    /// these keys.
658    ///
659    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
660    #[must_use]
661    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
662        self.meta = meta.into_option();
663        self
664    }
665}
666
667/// Unique identifier for a message within a session.
668#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
669#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash, Display, From)]
670#[serde(transparent)]
671#[from(Arc<str>, String, &'static str)]
672#[non_exhaustive]
673pub struct MessageId(pub Arc<str>);
674
675impl MessageId {
676    /// Wraps a protocol string as a typed [`MessageId`].
677    #[must_use]
678    pub fn new(id: impl Into<Arc<str>>) -> Self {
679        Self(id.into())
680    }
681}
682
683impl IntoOption<MessageId> for &str {
684    fn into_option(self) -> Option<MessageId> {
685        Some(MessageId::new(self))
686    }
687}
688
689/// Available commands are ready or have changed
690#[serde_as]
691#[skip_serializing_none]
692#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
693#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
694#[serde(rename_all = "camelCase")]
695#[non_exhaustive]
696pub struct AvailableCommandsUpdate {
697    /// Commands the agent can execute
698    #[serde_as(deserialize_as = "DefaultOnError<VecSkipError<_, SkipListener>>")]
699    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true, "x-deserialize-skip-invalid-items" = true)))]
700    pub available_commands: Vec<AvailableCommand>,
701    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
702    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
703    /// these keys.
704    ///
705    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
706    #[serde_as(deserialize_as = "DefaultOnError")]
707    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
708    #[serde(default)]
709    #[serde(rename = "_meta")]
710    pub meta: Option<Meta>,
711}
712
713impl AvailableCommandsUpdate {
714    /// Builds [`AvailableCommandsUpdate`] with the required fields set; optional fields start unset or empty.
715    #[must_use]
716    pub fn new(available_commands: Vec<AvailableCommand>) -> Self {
717        Self {
718            available_commands,
719            meta: None,
720        }
721    }
722
723    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
724    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
725    /// these keys.
726    ///
727    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
728    #[must_use]
729    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
730        self.meta = meta.into_option();
731        self
732    }
733}
734
735/// Information about a command.
736#[serde_as]
737#[skip_serializing_none]
738#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
739#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
740#[serde(rename_all = "camelCase")]
741#[non_exhaustive]
742pub struct AvailableCommand {
743    /// Command name (e.g., `create_plan`, `research_codebase`).
744    pub name: String,
745    /// Human-readable description of what the command does.
746    pub description: String,
747    /// Input for the command if required
748    #[serde_as(deserialize_as = "DefaultOnError")]
749    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
750    #[serde(default)]
751    pub input: Option<AvailableCommandInput>,
752    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
753    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
754    /// these keys.
755    ///
756    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
757    #[serde_as(deserialize_as = "DefaultOnError")]
758    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
759    #[serde(default)]
760    #[serde(rename = "_meta")]
761    pub meta: Option<Meta>,
762}
763
764impl AvailableCommand {
765    /// Builds [`AvailableCommand`] with the required fields set; optional fields start unset or empty.
766    #[must_use]
767    pub fn new(name: impl Into<String>, description: impl Into<String>) -> Self {
768        Self {
769            name: name.into(),
770            description: description.into(),
771            input: None,
772            meta: None,
773        }
774    }
775
776    /// Input for the command if required
777    #[must_use]
778    pub fn input(mut self, input: impl IntoOption<AvailableCommandInput>) -> Self {
779        self.input = input.into_option();
780        self
781    }
782
783    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
784    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
785    /// these keys.
786    ///
787    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
788    #[must_use]
789    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
790        self.meta = meta.into_option();
791        self
792    }
793}
794
795/// The input specification for a command.
796#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
797#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
798#[serde(untagged, rename_all = "camelCase")]
799#[non_exhaustive]
800pub enum AvailableCommandInput {
801    /// All text that was typed after the command name is provided as input.
802    Unstructured(UnstructuredCommandInput),
803}
804
805/// All text that was typed after the command name is provided as input.
806#[serde_as]
807#[skip_serializing_none]
808#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
809#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
810#[serde(rename_all = "camelCase")]
811#[non_exhaustive]
812pub struct UnstructuredCommandInput {
813    /// A hint to display when the input hasn't been provided yet
814    pub hint: String,
815    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
816    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
817    /// these keys.
818    ///
819    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
820    #[serde_as(deserialize_as = "DefaultOnError")]
821    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
822    #[serde(default)]
823    #[serde(rename = "_meta")]
824    pub meta: Option<Meta>,
825}
826
827impl UnstructuredCommandInput {
828    /// Builds [`UnstructuredCommandInput`] with the required fields set; optional fields start unset or empty.
829    #[must_use]
830    pub fn new(hint: impl Into<String>) -> Self {
831        Self {
832            hint: hint.into(),
833            meta: None,
834        }
835    }
836
837    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
838    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
839    /// these keys.
840    ///
841    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
842    #[must_use]
843    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
844        self.meta = meta.into_option();
845        self
846    }
847}
848
849// Permission
850
851/// Request for user permission to execute a tool call.
852///
853/// Sent when the agent needs authorization before performing a sensitive operation.
854///
855/// See protocol docs: [Requesting Permission](https://agentclientprotocol.com/protocol/tool-calls#requesting-permission)
856#[serde_as]
857#[skip_serializing_none]
858#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
859#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
860#[cfg_attr(feature = "schemars", schemars(extend("x-side" = "client", "x-method" = SESSION_REQUEST_PERMISSION_METHOD_NAME)))]
861#[serde(rename_all = "camelCase")]
862#[non_exhaustive]
863pub struct RequestPermissionRequest {
864    /// The session ID for this request.
865    pub session_id: SessionId,
866    /// Details about the tool call requiring permission.
867    pub tool_call: ToolCallUpdate,
868    /// Available permission options for the user to choose from.
869    pub options: Vec<PermissionOption>,
870    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
871    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
872    /// these keys.
873    ///
874    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
875    #[serde_as(deserialize_as = "DefaultOnError")]
876    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
877    #[serde(default)]
878    #[serde(rename = "_meta")]
879    pub meta: Option<Meta>,
880}
881
882impl RequestPermissionRequest {
883    /// Builds [`RequestPermissionRequest`] with the required request fields set; optional fields start unset or empty.
884    #[must_use]
885    pub fn new(
886        session_id: impl Into<SessionId>,
887        tool_call: ToolCallUpdate,
888        options: Vec<PermissionOption>,
889    ) -> Self {
890        Self {
891            session_id: session_id.into(),
892            tool_call,
893            options,
894            meta: None,
895        }
896    }
897
898    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
899    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
900    /// these keys.
901    ///
902    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
903    #[must_use]
904    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
905        self.meta = meta.into_option();
906        self
907    }
908}
909
910/// An option presented to the user when requesting permission.
911#[serde_as]
912#[skip_serializing_none]
913#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
914#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
915#[serde(rename_all = "camelCase")]
916#[non_exhaustive]
917pub struct PermissionOption {
918    /// Unique identifier for this permission option.
919    pub option_id: PermissionOptionId,
920    /// Human-readable label to display to the user.
921    pub name: String,
922    /// Hint about the nature of this permission option.
923    pub kind: PermissionOptionKind,
924    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
925    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
926    /// these keys.
927    ///
928    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
929    #[serde_as(deserialize_as = "DefaultOnError")]
930    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
931    #[serde(default)]
932    #[serde(rename = "_meta")]
933    pub meta: Option<Meta>,
934}
935
936impl PermissionOption {
937    /// Builds [`PermissionOption`] with the required fields set; optional fields start unset or empty.
938    #[must_use]
939    pub fn new(
940        option_id: impl Into<PermissionOptionId>,
941        name: impl Into<String>,
942        kind: PermissionOptionKind,
943    ) -> Self {
944        Self {
945            option_id: option_id.into(),
946            name: name.into(),
947            kind,
948            meta: None,
949        }
950    }
951
952    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
953    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
954    /// these keys.
955    ///
956    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
957    #[must_use]
958    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
959        self.meta = meta.into_option();
960        self
961    }
962}
963
964/// Unique identifier for a permission option.
965#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
966#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash, Display, From)]
967#[serde(transparent)]
968#[from(Arc<str>, String, &'static str)]
969#[non_exhaustive]
970pub struct PermissionOptionId(pub Arc<str>);
971
972impl PermissionOptionId {
973    /// Wraps a protocol string as a typed [`PermissionOptionId`].
974    #[must_use]
975    pub fn new(id: impl Into<Arc<str>>) -> Self {
976        Self(id.into())
977    }
978}
979
980/// The type of permission option being presented to the user.
981///
982/// Helps clients choose appropriate icons and UI treatment.
983#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
984#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
985#[serde(rename_all = "snake_case")]
986#[non_exhaustive]
987pub enum PermissionOptionKind {
988    /// Allow this operation only this time.
989    AllowOnce,
990    /// Allow this operation and remember the choice.
991    AllowAlways,
992    /// Reject this operation only this time.
993    RejectOnce,
994    /// Reject this operation and remember the choice.
995    RejectAlways,
996}
997
998/// Response to a permission request.
999#[serde_as]
1000#[skip_serializing_none]
1001#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1002#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
1003#[cfg_attr(feature = "schemars", schemars(extend("x-side" = "client", "x-method" = SESSION_REQUEST_PERMISSION_METHOD_NAME)))]
1004#[serde(rename_all = "camelCase")]
1005#[non_exhaustive]
1006pub struct RequestPermissionResponse {
1007    /// The user's decision on the permission request.
1008    // This extra-level is unfortunately needed because the output must be an object
1009    pub outcome: RequestPermissionOutcome,
1010    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1011    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1012    /// these keys.
1013    ///
1014    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1015    #[serde_as(deserialize_as = "DefaultOnError")]
1016    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
1017    #[serde(default)]
1018    #[serde(rename = "_meta")]
1019    pub meta: Option<Meta>,
1020}
1021
1022impl RequestPermissionResponse {
1023    /// Builds [`RequestPermissionResponse`] with the required response fields set; optional fields start unset or empty.
1024    #[must_use]
1025    pub fn new(outcome: RequestPermissionOutcome) -> Self {
1026        Self {
1027            outcome,
1028            meta: None,
1029        }
1030    }
1031
1032    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1033    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1034    /// these keys.
1035    ///
1036    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1037    #[must_use]
1038    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1039        self.meta = meta.into_option();
1040        self
1041    }
1042}
1043
1044/// The outcome of a permission request.
1045#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1046#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
1047#[serde(tag = "outcome", rename_all = "snake_case")]
1048#[cfg_attr(feature = "schemars", schemars(extend("discriminator" = {"propertyName": "outcome"})))]
1049#[non_exhaustive]
1050pub enum RequestPermissionOutcome {
1051    /// The prompt turn was cancelled before the user responded.
1052    ///
1053    /// When a client sends a `session/cancel` notification to cancel an ongoing
1054    /// prompt turn, it MUST respond to all pending `session/request_permission`
1055    /// requests with this `Cancelled` outcome.
1056    ///
1057    /// See protocol docs: [Cancellation](https://agentclientprotocol.com/protocol/prompt-turn#cancellation)
1058    Cancelled,
1059    /// The user selected one of the provided options.
1060    #[serde(rename_all = "camelCase")]
1061    Selected(SelectedPermissionOutcome),
1062}
1063
1064/// The user selected one of the provided options.
1065#[serde_as]
1066#[skip_serializing_none]
1067#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1068#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
1069#[serde(rename_all = "camelCase")]
1070#[non_exhaustive]
1071pub struct SelectedPermissionOutcome {
1072    /// The ID of the option the user selected.
1073    pub option_id: PermissionOptionId,
1074    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1075    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1076    /// these keys.
1077    ///
1078    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1079    #[serde_as(deserialize_as = "DefaultOnError")]
1080    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
1081    #[serde(default)]
1082    #[serde(rename = "_meta")]
1083    pub meta: Option<Meta>,
1084}
1085
1086impl SelectedPermissionOutcome {
1087    /// Builds [`SelectedPermissionOutcome`] with the required fields set; optional fields start unset or empty.
1088    #[must_use]
1089    pub fn new(option_id: impl Into<PermissionOptionId>) -> Self {
1090        Self {
1091            option_id: option_id.into(),
1092            meta: None,
1093        }
1094    }
1095
1096    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1097    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1098    /// these keys.
1099    ///
1100    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1101    #[must_use]
1102    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1103        self.meta = meta.into_option();
1104        self
1105    }
1106}
1107
1108// Write text file
1109
1110/// Request to write content to a text file.
1111///
1112/// Only available if the client supports the `fs.writeTextFile` capability.
1113#[serde_as]
1114#[skip_serializing_none]
1115#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1116#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
1117#[cfg_attr(feature = "schemars", schemars(extend("x-side" = "client", "x-method" = FS_WRITE_TEXT_FILE_METHOD_NAME)))]
1118#[serde(rename_all = "camelCase")]
1119#[non_exhaustive]
1120pub struct WriteTextFileRequest {
1121    /// The session ID for this request.
1122    pub session_id: SessionId,
1123    /// Absolute path to the file to write.
1124    pub path: PathBuf,
1125    /// The text content to write to the file.
1126    pub content: String,
1127    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1128    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1129    /// these keys.
1130    ///
1131    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1132    #[serde_as(deserialize_as = "DefaultOnError")]
1133    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
1134    #[serde(default)]
1135    #[serde(rename = "_meta")]
1136    pub meta: Option<Meta>,
1137}
1138
1139impl WriteTextFileRequest {
1140    /// Builds [`WriteTextFileRequest`] with the required request fields set; optional fields start unset or empty.
1141    #[must_use]
1142    pub fn new(
1143        session_id: impl Into<SessionId>,
1144        path: impl Into<PathBuf>,
1145        content: impl Into<String>,
1146    ) -> Self {
1147        Self {
1148            session_id: session_id.into(),
1149            path: path.into(),
1150            content: content.into(),
1151            meta: None,
1152        }
1153    }
1154
1155    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1156    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1157    /// these keys.
1158    ///
1159    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1160    #[must_use]
1161    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1162        self.meta = meta.into_option();
1163        self
1164    }
1165}
1166
1167/// Response to `fs/write_text_file`
1168#[serde_as]
1169#[skip_serializing_none]
1170#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1171#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
1172#[serde(rename_all = "camelCase")]
1173#[cfg_attr(feature = "schemars", schemars(extend("x-side" = "client", "x-method" = FS_WRITE_TEXT_FILE_METHOD_NAME)))]
1174#[non_exhaustive]
1175pub struct WriteTextFileResponse {
1176    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1177    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1178    /// these keys.
1179    ///
1180    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1181    #[serde_as(deserialize_as = "DefaultOnError")]
1182    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
1183    #[serde(default)]
1184    #[serde(rename = "_meta")]
1185    pub meta: Option<Meta>,
1186}
1187
1188impl WriteTextFileResponse {
1189    /// Builds [`WriteTextFileResponse`] with the required response fields set; optional fields start unset or empty.
1190    #[must_use]
1191    pub fn new() -> Self {
1192        Self::default()
1193    }
1194
1195    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1196    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1197    /// these keys.
1198    ///
1199    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1200    #[must_use]
1201    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1202        self.meta = meta.into_option();
1203        self
1204    }
1205}
1206
1207// Read text file
1208
1209/// Request to read content from a text file.
1210///
1211/// Only available if the client supports the `fs.readTextFile` capability.
1212#[serde_as]
1213#[skip_serializing_none]
1214#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1215#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
1216#[cfg_attr(feature = "schemars", schemars(extend("x-side" = "client", "x-method" = FS_READ_TEXT_FILE_METHOD_NAME)))]
1217#[serde(rename_all = "camelCase")]
1218#[non_exhaustive]
1219pub struct ReadTextFileRequest {
1220    /// The session ID for this request.
1221    pub session_id: SessionId,
1222    /// Absolute path to the file to read.
1223    pub path: PathBuf,
1224    /// Line number to start reading from (1-based).
1225    #[serde_as(deserialize_as = "DefaultOnError")]
1226    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
1227    #[serde(default)]
1228    pub line: Option<u32>,
1229    /// Maximum number of lines to read.
1230    #[serde_as(deserialize_as = "DefaultOnError")]
1231    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
1232    #[serde(default)]
1233    pub limit: Option<u32>,
1234    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1235    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1236    /// these keys.
1237    ///
1238    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1239    #[serde_as(deserialize_as = "DefaultOnError")]
1240    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
1241    #[serde(default)]
1242    #[serde(rename = "_meta")]
1243    pub meta: Option<Meta>,
1244}
1245
1246impl ReadTextFileRequest {
1247    /// Builds [`ReadTextFileRequest`] with the required request fields set; optional fields start unset or empty.
1248    #[must_use]
1249    pub fn new(session_id: impl Into<SessionId>, path: impl Into<PathBuf>) -> Self {
1250        Self {
1251            session_id: session_id.into(),
1252            path: path.into(),
1253            line: None,
1254            limit: None,
1255            meta: None,
1256        }
1257    }
1258
1259    /// Line number to start reading from (1-based).
1260    #[must_use]
1261    pub fn line(mut self, line: impl IntoOption<u32>) -> Self {
1262        self.line = line.into_option();
1263        self
1264    }
1265
1266    /// Maximum number of lines to read.
1267    #[must_use]
1268    pub fn limit(mut self, limit: impl IntoOption<u32>) -> Self {
1269        self.limit = limit.into_option();
1270        self
1271    }
1272
1273    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1274    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1275    /// these keys.
1276    ///
1277    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1278    #[must_use]
1279    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1280        self.meta = meta.into_option();
1281        self
1282    }
1283}
1284
1285/// Response containing the contents of a text file.
1286#[serde_as]
1287#[skip_serializing_none]
1288#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1289#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
1290#[cfg_attr(feature = "schemars", schemars(extend("x-side" = "client", "x-method" = FS_READ_TEXT_FILE_METHOD_NAME)))]
1291#[serde(rename_all = "camelCase")]
1292#[non_exhaustive]
1293pub struct ReadTextFileResponse {
1294    /// Content payload returned by this response.
1295    pub content: String,
1296    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1297    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1298    /// these keys.
1299    ///
1300    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1301    #[serde_as(deserialize_as = "DefaultOnError")]
1302    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
1303    #[serde(default)]
1304    #[serde(rename = "_meta")]
1305    pub meta: Option<Meta>,
1306}
1307
1308impl ReadTextFileResponse {
1309    /// Builds [`ReadTextFileResponse`] with the required response fields set; optional fields start unset or empty.
1310    #[must_use]
1311    pub fn new(content: impl Into<String>) -> Self {
1312        Self {
1313            content: content.into(),
1314            meta: None,
1315        }
1316    }
1317
1318    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1319    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1320    /// these keys.
1321    ///
1322    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1323    #[must_use]
1324    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1325        self.meta = meta.into_option();
1326        self
1327    }
1328}
1329
1330// Terminals
1331
1332/// Typed identifier used for terminal values on the wire.
1333#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1334#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash, Display, From)]
1335#[serde(transparent)]
1336#[from(Arc<str>, String, &'static str)]
1337#[non_exhaustive]
1338pub struct TerminalId(pub Arc<str>);
1339
1340impl TerminalId {
1341    /// Wraps a protocol string as a typed [`TerminalId`].
1342    #[must_use]
1343    pub fn new(id: impl Into<Arc<str>>) -> Self {
1344        Self(id.into())
1345    }
1346}
1347
1348/// Request to create a new terminal and execute a command.
1349#[serde_as]
1350#[skip_serializing_none]
1351#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1352#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
1353#[serde(rename_all = "camelCase")]
1354#[cfg_attr(feature = "schemars", schemars(extend("x-side" = "client", "x-method" = TERMINAL_CREATE_METHOD_NAME)))]
1355#[non_exhaustive]
1356pub struct CreateTerminalRequest {
1357    /// The session ID for this request.
1358    pub session_id: SessionId,
1359    /// The command to execute.
1360    pub command: String,
1361    /// Array of command arguments.
1362    #[serde_as(deserialize_as = "DefaultOnError<VecSkipError<_, SkipListener>>")]
1363    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true, "x-deserialize-skip-invalid-items" = true)))]
1364    #[serde(default, skip_serializing_if = "Vec::is_empty")]
1365    pub args: Vec<String>,
1366    /// Environment variables for the command.
1367    #[serde_as(deserialize_as = "DefaultOnError<VecSkipError<_, SkipListener>>")]
1368    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true, "x-deserialize-skip-invalid-items" = true)))]
1369    #[serde(default, skip_serializing_if = "Vec::is_empty")]
1370    pub env: Vec<EnvVariable>,
1371    /// Working directory for the command. Must be an absolute path.
1372    #[serde_as(deserialize_as = "DefaultOnError")]
1373    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
1374    #[serde(default)]
1375    pub cwd: Option<PathBuf>,
1376    /// Maximum number of output bytes to retain.
1377    ///
1378    /// When the limit is exceeded, the Client truncates from the beginning of the output
1379    /// to stay within the limit.
1380    ///
1381    /// The Client MUST ensure truncation happens at a character boundary to maintain valid
1382    /// string output, even if this means the retained output is slightly less than the
1383    /// specified limit.
1384    #[serde_as(deserialize_as = "DefaultOnError")]
1385    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
1386    #[serde(default)]
1387    pub output_byte_limit: Option<u64>,
1388    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1389    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1390    /// these keys.
1391    ///
1392    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1393    #[serde_as(deserialize_as = "DefaultOnError")]
1394    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
1395    #[serde(default)]
1396    #[serde(rename = "_meta")]
1397    pub meta: Option<Meta>,
1398}
1399
1400impl CreateTerminalRequest {
1401    /// Builds [`CreateTerminalRequest`] with the required request fields set; optional fields start unset or empty.
1402    #[must_use]
1403    pub fn new(session_id: impl Into<SessionId>, command: impl Into<String>) -> Self {
1404        Self {
1405            session_id: session_id.into(),
1406            command: command.into(),
1407            args: Vec::new(),
1408            env: Vec::new(),
1409            cwd: None,
1410            output_byte_limit: None,
1411            meta: None,
1412        }
1413    }
1414
1415    /// Array of command arguments.
1416    #[must_use]
1417    pub fn args(mut self, args: Vec<String>) -> Self {
1418        self.args = args;
1419        self
1420    }
1421
1422    /// Environment variables for the command.
1423    #[must_use]
1424    pub fn env(mut self, env: Vec<EnvVariable>) -> Self {
1425        self.env = env;
1426        self
1427    }
1428
1429    /// Working directory for the command. Must be an absolute path.
1430    #[must_use]
1431    pub fn cwd(mut self, cwd: impl IntoOption<PathBuf>) -> Self {
1432        self.cwd = cwd.into_option();
1433        self
1434    }
1435
1436    /// Maximum number of output bytes to retain.
1437    ///
1438    /// When the limit is exceeded, the Client truncates from the beginning of the output
1439    /// to stay within the limit.
1440    ///
1441    /// The Client MUST ensure truncation happens at a character boundary to maintain valid
1442    /// string output, even if this means the retained output is slightly less than the
1443    /// specified limit.
1444    #[must_use]
1445    pub fn output_byte_limit(mut self, output_byte_limit: impl IntoOption<u64>) -> Self {
1446        self.output_byte_limit = output_byte_limit.into_option();
1447        self
1448    }
1449
1450    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1451    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1452    /// these keys.
1453    ///
1454    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1455    #[must_use]
1456    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1457        self.meta = meta.into_option();
1458        self
1459    }
1460}
1461
1462/// Response containing the ID of the created terminal.
1463#[serde_as]
1464#[skip_serializing_none]
1465#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1466#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
1467#[serde(rename_all = "camelCase")]
1468#[cfg_attr(feature = "schemars", schemars(extend("x-side" = "client", "x-method" = TERMINAL_CREATE_METHOD_NAME)))]
1469#[non_exhaustive]
1470pub struct CreateTerminalResponse {
1471    /// The unique identifier for the created terminal.
1472    pub terminal_id: TerminalId,
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    #[serde_as(deserialize_as = "DefaultOnError")]
1479    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
1480    #[serde(default)]
1481    #[serde(rename = "_meta")]
1482    pub meta: Option<Meta>,
1483}
1484
1485impl CreateTerminalResponse {
1486    /// Builds [`CreateTerminalResponse`] with the required response fields set; optional fields start unset or empty.
1487    #[must_use]
1488    pub fn new(terminal_id: impl Into<TerminalId>) -> Self {
1489        Self {
1490            terminal_id: terminal_id.into(),
1491            meta: None,
1492        }
1493    }
1494
1495    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1496    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1497    /// these keys.
1498    ///
1499    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1500    #[must_use]
1501    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1502        self.meta = meta.into_option();
1503        self
1504    }
1505}
1506
1507/// Request to get the current output and status of a terminal.
1508#[serde_as]
1509#[skip_serializing_none]
1510#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1511#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
1512#[serde(rename_all = "camelCase")]
1513#[cfg_attr(feature = "schemars", schemars(extend("x-side" = "client", "x-method" = TERMINAL_OUTPUT_METHOD_NAME)))]
1514#[non_exhaustive]
1515pub struct TerminalOutputRequest {
1516    /// The session ID for this request.
1517    pub session_id: SessionId,
1518    /// The ID of the terminal to get output from.
1519    pub terminal_id: TerminalId,
1520    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1521    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1522    /// these keys.
1523    ///
1524    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1525    #[serde_as(deserialize_as = "DefaultOnError")]
1526    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
1527    #[serde(default)]
1528    #[serde(rename = "_meta")]
1529    pub meta: Option<Meta>,
1530}
1531
1532impl TerminalOutputRequest {
1533    /// Builds [`TerminalOutputRequest`] with the required request fields set; optional fields start unset or empty.
1534    #[must_use]
1535    pub fn new(session_id: impl Into<SessionId>, terminal_id: impl Into<TerminalId>) -> Self {
1536        Self {
1537            session_id: session_id.into(),
1538            terminal_id: terminal_id.into(),
1539            meta: None,
1540        }
1541    }
1542
1543    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1544    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1545    /// these keys.
1546    ///
1547    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1548    #[must_use]
1549    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1550        self.meta = meta.into_option();
1551        self
1552    }
1553}
1554
1555/// Response containing the terminal output and exit status.
1556#[serde_as]
1557#[skip_serializing_none]
1558#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1559#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
1560#[serde(rename_all = "camelCase")]
1561#[cfg_attr(feature = "schemars", schemars(extend("x-side" = "client", "x-method" = TERMINAL_OUTPUT_METHOD_NAME)))]
1562#[non_exhaustive]
1563pub struct TerminalOutputResponse {
1564    /// The terminal output captured so far.
1565    pub output: String,
1566    /// Whether the output was truncated due to byte limits.
1567    pub truncated: bool,
1568    /// Exit status if the command has completed.
1569    #[serde_as(deserialize_as = "DefaultOnError")]
1570    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
1571    #[serde(default)]
1572    pub exit_status: Option<TerminalExitStatus>,
1573    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1574    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1575    /// these keys.
1576    ///
1577    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1578    #[serde_as(deserialize_as = "DefaultOnError")]
1579    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
1580    #[serde(default)]
1581    #[serde(rename = "_meta")]
1582    pub meta: Option<Meta>,
1583}
1584
1585impl TerminalOutputResponse {
1586    /// Builds [`TerminalOutputResponse`] with the required response fields set; optional fields start unset or empty.
1587    #[must_use]
1588    pub fn new(output: impl Into<String>, truncated: bool) -> Self {
1589        Self {
1590            output: output.into(),
1591            truncated,
1592            exit_status: None,
1593            meta: None,
1594        }
1595    }
1596
1597    /// Exit status if the command has completed.
1598    #[must_use]
1599    pub fn exit_status(mut self, exit_status: impl IntoOption<TerminalExitStatus>) -> Self {
1600        self.exit_status = exit_status.into_option();
1601        self
1602    }
1603
1604    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1605    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1606    /// these keys.
1607    ///
1608    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1609    #[must_use]
1610    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1611        self.meta = meta.into_option();
1612        self
1613    }
1614}
1615
1616/// Request to release a terminal and free its resources.
1617#[serde_as]
1618#[skip_serializing_none]
1619#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1620#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
1621#[serde(rename_all = "camelCase")]
1622#[cfg_attr(feature = "schemars", schemars(extend("x-side" = "client", "x-method" = TERMINAL_RELEASE_METHOD_NAME)))]
1623#[non_exhaustive]
1624pub struct ReleaseTerminalRequest {
1625    /// The session ID for this request.
1626    pub session_id: SessionId,
1627    /// The ID of the terminal to release.
1628    pub terminal_id: TerminalId,
1629    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1630    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1631    /// these keys.
1632    ///
1633    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1634    #[serde_as(deserialize_as = "DefaultOnError")]
1635    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
1636    #[serde(default)]
1637    #[serde(rename = "_meta")]
1638    pub meta: Option<Meta>,
1639}
1640
1641impl ReleaseTerminalRequest {
1642    /// Builds [`ReleaseTerminalRequest`] with the required request fields set; optional fields start unset or empty.
1643    #[must_use]
1644    pub fn new(session_id: impl Into<SessionId>, terminal_id: impl Into<TerminalId>) -> Self {
1645        Self {
1646            session_id: session_id.into(),
1647            terminal_id: terminal_id.into(),
1648            meta: None,
1649        }
1650    }
1651
1652    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1653    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1654    /// these keys.
1655    ///
1656    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1657    #[must_use]
1658    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1659        self.meta = meta.into_option();
1660        self
1661    }
1662}
1663
1664/// Response to terminal/release method
1665#[serde_as]
1666#[skip_serializing_none]
1667#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1668#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
1669#[serde(rename_all = "camelCase")]
1670#[cfg_attr(feature = "schemars", schemars(extend("x-side" = "client", "x-method" = TERMINAL_RELEASE_METHOD_NAME)))]
1671#[non_exhaustive]
1672pub struct ReleaseTerminalResponse {
1673    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1674    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1675    /// these keys.
1676    ///
1677    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1678    #[serde_as(deserialize_as = "DefaultOnError")]
1679    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
1680    #[serde(default)]
1681    #[serde(rename = "_meta")]
1682    pub meta: Option<Meta>,
1683}
1684
1685impl ReleaseTerminalResponse {
1686    /// Builds [`ReleaseTerminalResponse`] with the required response fields set; optional fields start unset or empty.
1687    #[must_use]
1688    pub fn new() -> Self {
1689        Self::default()
1690    }
1691
1692    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1693    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1694    /// these keys.
1695    ///
1696    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1697    #[must_use]
1698    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1699        self.meta = meta.into_option();
1700        self
1701    }
1702}
1703
1704/// Request to kill a terminal without releasing it.
1705#[serde_as]
1706#[skip_serializing_none]
1707#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1708#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
1709#[serde(rename_all = "camelCase")]
1710#[cfg_attr(feature = "schemars", schemars(extend("x-side" = "client", "x-method" = TERMINAL_KILL_METHOD_NAME)))]
1711#[non_exhaustive]
1712pub struct KillTerminalRequest {
1713    /// The session ID for this request.
1714    pub session_id: SessionId,
1715    /// The ID of the terminal to kill.
1716    pub terminal_id: TerminalId,
1717    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1718    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1719    /// these keys.
1720    ///
1721    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1722    #[serde_as(deserialize_as = "DefaultOnError")]
1723    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
1724    #[serde(default)]
1725    #[serde(rename = "_meta")]
1726    pub meta: Option<Meta>,
1727}
1728
1729impl KillTerminalRequest {
1730    /// Builds [`KillTerminalRequest`] with the required request fields set; optional fields start unset or empty.
1731    #[must_use]
1732    pub fn new(session_id: impl Into<SessionId>, terminal_id: impl Into<TerminalId>) -> Self {
1733        Self {
1734            session_id: session_id.into(),
1735            terminal_id: terminal_id.into(),
1736            meta: None,
1737        }
1738    }
1739
1740    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1741    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1742    /// these keys.
1743    ///
1744    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1745    #[must_use]
1746    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1747        self.meta = meta.into_option();
1748        self
1749    }
1750}
1751
1752/// Response to `terminal/kill` method
1753#[serde_as]
1754#[skip_serializing_none]
1755#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1756#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
1757#[serde(rename_all = "camelCase")]
1758#[cfg_attr(feature = "schemars", schemars(extend("x-side" = "client", "x-method" = TERMINAL_KILL_METHOD_NAME)))]
1759#[non_exhaustive]
1760pub struct KillTerminalResponse {
1761    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1762    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1763    /// these keys.
1764    ///
1765    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1766    #[serde_as(deserialize_as = "DefaultOnError")]
1767    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
1768    #[serde(default)]
1769    #[serde(rename = "_meta")]
1770    pub meta: Option<Meta>,
1771}
1772
1773impl KillTerminalResponse {
1774    /// Builds [`KillTerminalResponse`] with the required response fields set; optional fields start unset or empty.
1775    #[must_use]
1776    pub fn new() -> Self {
1777        Self::default()
1778    }
1779
1780    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1781    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1782    /// these keys.
1783    ///
1784    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1785    #[must_use]
1786    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1787        self.meta = meta.into_option();
1788        self
1789    }
1790}
1791
1792/// Request to wait for a terminal command to exit.
1793#[serde_as]
1794#[skip_serializing_none]
1795#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1796#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
1797#[serde(rename_all = "camelCase")]
1798#[cfg_attr(feature = "schemars", schemars(extend("x-side" = "client", "x-method" = TERMINAL_WAIT_FOR_EXIT_METHOD_NAME)))]
1799#[non_exhaustive]
1800pub struct WaitForTerminalExitRequest {
1801    /// The session ID for this request.
1802    pub session_id: SessionId,
1803    /// The ID of the terminal to wait for.
1804    pub terminal_id: TerminalId,
1805    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1806    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1807    /// these keys.
1808    ///
1809    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1810    #[serde_as(deserialize_as = "DefaultOnError")]
1811    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
1812    #[serde(default)]
1813    #[serde(rename = "_meta")]
1814    pub meta: Option<Meta>,
1815}
1816
1817impl WaitForTerminalExitRequest {
1818    /// Builds [`WaitForTerminalExitRequest`] with the required request fields set; optional fields start unset or empty.
1819    #[must_use]
1820    pub fn new(session_id: impl Into<SessionId>, terminal_id: impl Into<TerminalId>) -> Self {
1821        Self {
1822            session_id: session_id.into(),
1823            terminal_id: terminal_id.into(),
1824            meta: None,
1825        }
1826    }
1827
1828    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1829    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1830    /// these keys.
1831    ///
1832    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1833    #[must_use]
1834    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1835        self.meta = meta.into_option();
1836        self
1837    }
1838}
1839
1840/// Response containing the exit status of a terminal command.
1841#[serde_as]
1842#[skip_serializing_none]
1843#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1844#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
1845#[serde(rename_all = "camelCase")]
1846#[cfg_attr(feature = "schemars", schemars(extend("x-side" = "client", "x-method" = TERMINAL_WAIT_FOR_EXIT_METHOD_NAME)))]
1847#[non_exhaustive]
1848pub struct WaitForTerminalExitResponse {
1849    /// The exit status of the terminal command.
1850    #[serde(flatten)]
1851    pub exit_status: TerminalExitStatus,
1852    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1853    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1854    /// these keys.
1855    ///
1856    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1857    #[serde_as(deserialize_as = "DefaultOnError")]
1858    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
1859    #[serde(default)]
1860    #[serde(rename = "_meta")]
1861    pub meta: Option<Meta>,
1862}
1863
1864impl WaitForTerminalExitResponse {
1865    /// Builds [`WaitForTerminalExitResponse`] with the required response fields set; optional fields start unset or empty.
1866    #[must_use]
1867    pub fn new(exit_status: TerminalExitStatus) -> Self {
1868        Self {
1869            exit_status,
1870            meta: None,
1871        }
1872    }
1873
1874    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1875    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1876    /// these keys.
1877    ///
1878    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1879    #[must_use]
1880    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1881        self.meta = meta.into_option();
1882        self
1883    }
1884}
1885
1886/// Exit status of a terminal command.
1887#[serde_as]
1888#[skip_serializing_none]
1889#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1890#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
1891#[serde(rename_all = "camelCase")]
1892#[non_exhaustive]
1893pub struct TerminalExitStatus {
1894    /// The process exit code (may be null if terminated by signal).
1895    #[serde_as(deserialize_as = "DefaultOnError")]
1896    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
1897    #[serde(default)]
1898    pub exit_code: Option<u32>,
1899    /// The signal that terminated the process (may be null if exited normally).
1900    #[serde_as(deserialize_as = "DefaultOnError")]
1901    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
1902    #[serde(default)]
1903    pub signal: Option<String>,
1904    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1905    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1906    /// these keys.
1907    ///
1908    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1909    #[serde_as(deserialize_as = "DefaultOnError")]
1910    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
1911    #[serde(default)]
1912    #[serde(rename = "_meta")]
1913    pub meta: Option<Meta>,
1914}
1915
1916impl TerminalExitStatus {
1917    /// Builds [`TerminalExitStatus`] with the required fields set; optional fields start unset or empty.
1918    #[must_use]
1919    pub fn new() -> Self {
1920        Self::default()
1921    }
1922
1923    /// The process exit code (may be null if terminated by signal).
1924    #[must_use]
1925    pub fn exit_code(mut self, exit_code: impl IntoOption<u32>) -> Self {
1926        self.exit_code = exit_code.into_option();
1927        self
1928    }
1929
1930    /// The signal that terminated the process (may be null if exited normally).
1931    #[must_use]
1932    pub fn signal(mut self, signal: impl IntoOption<String>) -> Self {
1933        self.signal = signal.into_option();
1934        self
1935    }
1936
1937    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1938    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1939    /// these keys.
1940    ///
1941    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1942    #[must_use]
1943    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1944        self.meta = meta.into_option();
1945        self
1946    }
1947}
1948
1949// Capabilities
1950
1951/// Capabilities supported by the client.
1952///
1953/// Advertised during initialization to inform the agent about
1954/// available features and methods.
1955///
1956/// See protocol docs: [Client Capabilities](https://agentclientprotocol.com/protocol/initialization#client-capabilities)
1957#[serde_as]
1958#[skip_serializing_none]
1959#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1960#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
1961#[serde(rename_all = "camelCase")]
1962#[non_exhaustive]
1963pub struct ClientCapabilities {
1964    /// File system capabilities supported by the client.
1965    /// Determines which file operations the agent can request.
1966    #[serde_as(deserialize_as = "DefaultOnError")]
1967    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
1968    #[serde(default)]
1969    pub fs: FileSystemCapabilities,
1970    /// Whether the Client support all `terminal/*` methods.
1971    #[serde_as(deserialize_as = "DefaultOnError")]
1972    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
1973    #[serde(default)]
1974    pub terminal: bool,
1975    /// Session-related capabilities supported by the client.
1976    ///
1977    /// Optional. Omitted or `null` both mean the client does not advertise any
1978    /// session-related extensions.
1979    #[serde_as(deserialize_as = "DefaultOnError")]
1980    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
1981    #[serde(default)]
1982    pub session: Option<ClientSessionCapabilities>,
1983    /// **UNSTABLE**
1984    ///
1985    /// This capability is not part of the spec yet, and may be removed or changed at any point.
1986    ///
1987    /// Whether the client supports `plan_update` and `plan_removed` session updates.
1988    ///
1989    /// Optional. Omitted or `null` both mean the client does not advertise support.
1990    /// Supplying `{}` means the client can receive both update types.
1991    #[cfg(feature = "unstable_plan_operations")]
1992    #[serde_as(deserialize_as = "DefaultOnError")]
1993    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
1994    #[serde(default)]
1995    pub plan: Option<PlanCapabilities>,
1996    /// Authentication capabilities supported by the client.
1997    /// Determines which authentication method types the agent may include
1998    /// in its `InitializeResponse`.
1999    #[serde_as(deserialize_as = "DefaultOnError")]
2000    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
2001    #[serde(default)]
2002    pub auth: AuthCapabilities,
2003    /// Elicitation capabilities supported by the client.
2004    /// Determines which elicitation modes the agent may use.
2005    ///
2006    /// Optional. Omitted or `null` both mean the client does not advertise
2007    /// elicitation support.
2008    #[serde_as(deserialize_as = "DefaultOnError")]
2009    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
2010    #[serde(default)]
2011    pub elicitation: Option<ElicitationCapabilities>,
2012    /// **UNSTABLE**
2013    ///
2014    /// This capability is not part of the spec yet, and may be removed or changed at any point.
2015    ///
2016    /// NES (Next Edit Suggestions) capabilities supported by the client.
2017    ///
2018    /// Optional. Omitted or `null` both mean the client does not advertise any
2019    /// NES suggestion-kind extensions.
2020    #[cfg(feature = "unstable_nes")]
2021    #[serde_as(deserialize_as = "DefaultOnError")]
2022    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
2023    #[serde(default)]
2024    pub nes: Option<ClientNesCapabilities>,
2025    /// **UNSTABLE**
2026    ///
2027    /// This capability is not part of the spec yet, and may be removed or changed at any point.
2028    ///
2029    /// The position encodings supported by the client, in order of preference.
2030    #[cfg(feature = "unstable_nes")]
2031    #[serde_as(deserialize_as = "DefaultOnError<VecSkipError<_, SkipListener>>")]
2032    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true, "x-deserialize-skip-invalid-items" = true)))]
2033    #[serde(default, skip_serializing_if = "Vec::is_empty")]
2034    pub position_encodings: Vec<PositionEncodingKind>,
2035
2036    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
2037    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
2038    /// these keys.
2039    ///
2040    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
2041    #[serde_as(deserialize_as = "DefaultOnError")]
2042    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
2043    #[serde(default)]
2044    #[serde(rename = "_meta")]
2045    pub meta: Option<Meta>,
2046}
2047
2048impl ClientCapabilities {
2049    /// Builds an empty [`ClientCapabilities`]; use builder methods to advertise supported sub-capabilities.
2050    #[must_use]
2051    pub fn new() -> Self {
2052        Self::default()
2053    }
2054
2055    /// File system capabilities supported by the client.
2056    /// Determines which file operations the agent can request.
2057    #[must_use]
2058    pub fn fs(mut self, fs: FileSystemCapabilities) -> Self {
2059        self.fs = fs;
2060        self
2061    }
2062
2063    /// Whether the Client support all `terminal/*` methods.
2064    #[must_use]
2065    pub fn terminal(mut self, terminal: bool) -> Self {
2066        self.terminal = terminal;
2067        self
2068    }
2069
2070    /// Session-related capabilities supported by the client.
2071    #[must_use]
2072    pub fn session(mut self, session: impl IntoOption<ClientSessionCapabilities>) -> Self {
2073        self.session = session.into_option();
2074        self
2075    }
2076
2077    /// **UNSTABLE**
2078    ///
2079    /// This capability is not part of the spec yet, and may be removed or changed at any point.
2080    ///
2081    /// Whether the client supports `plan_update` and `plan_removed` session updates.
2082    ///
2083    /// Omitted or `null` both mean the client does not advertise support.
2084    /// Supplying `{}` means the client can receive both update types.
2085    #[cfg(feature = "unstable_plan_operations")]
2086    #[must_use]
2087    pub fn plan(mut self, plan: impl IntoOption<PlanCapabilities>) -> Self {
2088        self.plan = plan.into_option();
2089        self
2090    }
2091
2092    /// Authentication capabilities supported by the client.
2093    /// Determines which authentication method types the agent may include
2094    /// in its `InitializeResponse`.
2095    #[must_use]
2096    pub fn auth(mut self, auth: AuthCapabilities) -> Self {
2097        self.auth = auth;
2098        self
2099    }
2100
2101    /// Elicitation capabilities supported by the client.
2102    /// Determines which elicitation modes the agent may use.
2103    #[must_use]
2104    pub fn elicitation(mut self, elicitation: impl IntoOption<ElicitationCapabilities>) -> Self {
2105        self.elicitation = elicitation.into_option();
2106        self
2107    }
2108
2109    /// **UNSTABLE**
2110    ///
2111    /// NES (Next Edit Suggestions) capabilities supported by the client.
2112    #[cfg(feature = "unstable_nes")]
2113    #[must_use]
2114    pub fn nes(mut self, nes: impl IntoOption<ClientNesCapabilities>) -> Self {
2115        self.nes = nes.into_option();
2116        self
2117    }
2118
2119    /// **UNSTABLE**
2120    ///
2121    /// The position encodings supported by the client, in order of preference.
2122    #[cfg(feature = "unstable_nes")]
2123    #[must_use]
2124    pub fn position_encodings(mut self, position_encodings: Vec<PositionEncodingKind>) -> Self {
2125        self.position_encodings = position_encodings;
2126        self
2127    }
2128
2129    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
2130    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
2131    /// these keys.
2132    ///
2133    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
2134    #[must_use]
2135    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2136        self.meta = meta.into_option();
2137        self
2138    }
2139}
2140
2141/// Session-related capabilities supported by the client.
2142#[serde_as]
2143#[skip_serializing_none]
2144#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2145#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
2146#[serde(rename_all = "camelCase")]
2147#[non_exhaustive]
2148pub struct ClientSessionCapabilities {
2149    /// **UNSTABLE**
2150    ///
2151    /// This capability is not part of the spec yet, and may be removed or changed at any point.
2152    ///
2153    /// Support for ID-addressed context compaction updates. Omitted or `null`
2154    /// means unsupported; `{}` advertises the complete compaction contract.
2155    #[cfg(feature = "unstable_session_compaction")]
2156    #[serde_as(deserialize_as = "DefaultOnError")]
2157    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
2158    #[serde(default)]
2159    pub compaction: Option<CompactionCapabilities>,
2160    /// Config option capabilities supported by the client.
2161    ///
2162    /// Omitted or `null` both mean the client does not advertise support for any
2163    /// config option extensions.
2164    #[serde_as(deserialize_as = "DefaultOnError")]
2165    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
2166    #[serde(default)]
2167    pub config_options: Option<SessionConfigOptionsCapabilities>,
2168    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
2169    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
2170    /// these keys.
2171    ///
2172    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
2173    #[serde_as(deserialize_as = "DefaultOnError")]
2174    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
2175    #[serde(default)]
2176    #[serde(rename = "_meta")]
2177    pub meta: Option<Meta>,
2178}
2179
2180impl ClientSessionCapabilities {
2181    /// Builds an empty [`ClientSessionCapabilities`]; use builder methods to advertise supported sub-capabilities.
2182    #[must_use]
2183    pub fn new() -> Self {
2184        Self::default()
2185    }
2186
2187    /// Advertises support for ID-addressed context compaction updates.
2188    #[cfg(feature = "unstable_session_compaction")]
2189    #[must_use]
2190    pub fn compaction(mut self, compaction: impl IntoOption<CompactionCapabilities>) -> Self {
2191        self.compaction = compaction.into_option();
2192        self
2193    }
2194
2195    /// Config option capabilities supported by the client.
2196    ///
2197    /// Omitted or `null` both mean the client does not advertise support for any
2198    /// config option extensions.
2199    #[must_use]
2200    pub fn config_options(
2201        mut self,
2202        config_options: impl IntoOption<SessionConfigOptionsCapabilities>,
2203    ) -> Self {
2204        self.config_options = config_options.into_option();
2205        self
2206    }
2207
2208    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
2209    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
2210    /// these keys.
2211    ///
2212    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
2213    #[must_use]
2214    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2215        self.meta = meta.into_option();
2216        self
2217    }
2218}
2219
2220/// **UNSTABLE**
2221///
2222/// This capability is not part of the spec yet, and may be removed or changed at any point.
2223///
2224/// Client support for ID-addressed context compaction updates.
2225#[cfg(feature = "unstable_session_compaction")]
2226#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2227#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
2228#[serde(rename_all = "camelCase")]
2229#[non_exhaustive]
2230pub struct CompactionCapabilities {}
2231
2232#[cfg(feature = "unstable_session_compaction")]
2233impl CompactionCapabilities {
2234    /// Advertises the complete compaction update contract.
2235    #[must_use]
2236    pub fn new() -> Self {
2237        Self {}
2238    }
2239}
2240
2241/// Session configuration option capabilities supported by the client.
2242#[serde_as]
2243#[skip_serializing_none]
2244#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2245#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
2246#[serde(rename_all = "camelCase")]
2247#[non_exhaustive]
2248pub struct SessionConfigOptionsCapabilities {
2249    /// Whether the client supports boolean session configuration options.
2250    ///
2251    /// Optional. Omitted or `null` both mean the client does not advertise support.
2252    /// Supplying `{}` means agents may include `type: "boolean"` entries in
2253    /// `configOptions`, and the client may send `session/set_config_option`
2254    /// requests with `type: "boolean"` and a boolean `value`.
2255    #[serde_as(deserialize_as = "DefaultOnError")]
2256    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
2257    #[serde(default)]
2258    pub boolean: Option<BooleanConfigOptionCapabilities>,
2259    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
2260    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
2261    /// these keys.
2262    ///
2263    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
2264    #[serde_as(deserialize_as = "DefaultOnError")]
2265    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
2266    #[serde(default)]
2267    #[serde(rename = "_meta")]
2268    pub meta: Option<Meta>,
2269}
2270
2271impl SessionConfigOptionsCapabilities {
2272    /// Builds an empty [`SessionConfigOptionsCapabilities`]; use builder methods to advertise supported sub-capabilities.
2273    #[must_use]
2274    pub fn new() -> Self {
2275        Self::default()
2276    }
2277
2278    /// Whether the client supports boolean session configuration options.
2279    ///
2280    /// Omitted or `null` both mean the client does not advertise support.
2281    /// Supplying `{}` means agents may include `type: "boolean"` entries in
2282    /// `configOptions`, and the client may send `session/set_config_option`
2283    /// requests with `type: "boolean"` and a boolean `value`.
2284    #[must_use]
2285    pub fn boolean(mut self, boolean: impl IntoOption<BooleanConfigOptionCapabilities>) -> Self {
2286        self.boolean = boolean.into_option();
2287        self
2288    }
2289
2290    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
2291    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
2292    /// these keys.
2293    ///
2294    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
2295    #[must_use]
2296    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2297        self.meta = meta.into_option();
2298        self
2299    }
2300}
2301
2302/// Capabilities for boolean session configuration options.
2303///
2304/// Supplying `{}` means the client supports boolean session configuration options.
2305#[serde_as]
2306#[skip_serializing_none]
2307#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2308#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
2309#[non_exhaustive]
2310pub struct BooleanConfigOptionCapabilities {
2311    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
2312    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
2313    /// these keys.
2314    ///
2315    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
2316    #[serde_as(deserialize_as = "DefaultOnError")]
2317    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
2318    #[serde(default)]
2319    #[serde(rename = "_meta")]
2320    pub meta: Option<Meta>,
2321}
2322
2323impl BooleanConfigOptionCapabilities {
2324    /// Builds an empty [`BooleanConfigOptionCapabilities`]; use builder methods to advertise supported sub-capabilities.
2325    #[must_use]
2326    pub fn new() -> Self {
2327        Self::default()
2328    }
2329
2330    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
2331    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
2332    /// these keys.
2333    ///
2334    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
2335    #[must_use]
2336    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2337        self.meta = meta.into_option();
2338        self
2339    }
2340}
2341
2342/// Authentication capabilities supported by the client.
2343///
2344/// Advertised during initialization to inform the agent which authentication
2345/// method types the client can handle. This governs opt-in types that require
2346/// additional client-side support.
2347#[serde_as]
2348#[skip_serializing_none]
2349#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2350#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
2351#[serde(rename_all = "camelCase")]
2352#[non_exhaustive]
2353pub struct AuthCapabilities {
2354    /// Whether the client supports `terminal` authentication methods.
2355    ///
2356    /// The client should set this to `true` only when it can reproduce the
2357    /// configured agent invocation in an interactive terminal. When `true`, the
2358    /// agent may include `terminal` entries in its authentication methods.
2359    #[serde_as(deserialize_as = "DefaultOnError")]
2360    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
2361    #[serde(default)]
2362    pub terminal: bool,
2363    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
2364    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
2365    /// these keys.
2366    ///
2367    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
2368    #[serde_as(deserialize_as = "DefaultOnError")]
2369    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
2370    #[serde(default)]
2371    #[serde(rename = "_meta")]
2372    pub meta: Option<Meta>,
2373}
2374
2375impl AuthCapabilities {
2376    /// Builds an empty [`AuthCapabilities`]; use builder methods to advertise supported sub-capabilities.
2377    #[must_use]
2378    pub fn new() -> Self {
2379        Self::default()
2380    }
2381
2382    /// Whether the client supports `terminal` authentication methods.
2383    ///
2384    /// The client should set this to `true` only when it can reproduce the
2385    /// configured agent invocation in an interactive terminal. When `true`, the
2386    /// agent may include `AuthMethod::Terminal` entries in its authentication
2387    /// methods.
2388    #[must_use]
2389    pub fn terminal(mut self, terminal: bool) -> Self {
2390        self.terminal = terminal;
2391        self
2392    }
2393
2394    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
2395    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
2396    /// these keys.
2397    ///
2398    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
2399    #[must_use]
2400    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2401        self.meta = meta.into_option();
2402        self
2403    }
2404}
2405
2406/// File system capabilities that a client may support.
2407///
2408/// See protocol docs: [FileSystem](https://agentclientprotocol.com/protocol/initialization#filesystem)
2409#[serde_as]
2410#[skip_serializing_none]
2411#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2412#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
2413#[serde(rename_all = "camelCase")]
2414#[non_exhaustive]
2415pub struct FileSystemCapabilities {
2416    /// Whether the Client supports `fs/read_text_file` requests.
2417    #[serde_as(deserialize_as = "DefaultOnError")]
2418    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
2419    #[serde(default)]
2420    pub read_text_file: bool,
2421    /// Whether the Client supports `fs/write_text_file` requests.
2422    #[serde_as(deserialize_as = "DefaultOnError")]
2423    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
2424    #[serde(default)]
2425    pub write_text_file: bool,
2426    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
2427    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
2428    /// these keys.
2429    ///
2430    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
2431    #[serde_as(deserialize_as = "DefaultOnError")]
2432    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
2433    #[serde(default)]
2434    #[serde(rename = "_meta")]
2435    pub meta: Option<Meta>,
2436}
2437
2438impl FileSystemCapabilities {
2439    /// Builds an empty [`FileSystemCapabilities`]; use builder methods to advertise supported sub-capabilities.
2440    #[must_use]
2441    pub fn new() -> Self {
2442        Self::default()
2443    }
2444
2445    /// Whether the Client supports `fs/read_text_file` requests.
2446    #[must_use]
2447    pub fn read_text_file(mut self, read_text_file: bool) -> Self {
2448        self.read_text_file = read_text_file;
2449        self
2450    }
2451
2452    /// Whether the Client supports `fs/write_text_file` requests.
2453    #[must_use]
2454    pub fn write_text_file(mut self, write_text_file: bool) -> Self {
2455        self.write_text_file = write_text_file;
2456        self
2457    }
2458
2459    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
2460    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
2461    /// these keys.
2462    ///
2463    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
2464    #[must_use]
2465    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2466        self.meta = meta.into_option();
2467        self
2468    }
2469}
2470
2471// Method schema
2472
2473/// Names of all methods that clients handle.
2474///
2475/// Provides a centralized definition of method names used in the protocol.
2476#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
2477#[non_exhaustive]
2478pub struct ClientMethodNames {
2479    /// Method for requesting permission from the user.
2480    pub session_request_permission: &'static str,
2481    /// Notification for session updates.
2482    pub session_update: &'static str,
2483    /// Method for writing text files.
2484    pub fs_write_text_file: &'static str,
2485    /// Method for reading text files.
2486    pub fs_read_text_file: &'static str,
2487    /// Method for creating new terminals.
2488    pub terminal_create: &'static str,
2489    /// Method for getting terminals output.
2490    pub terminal_output: &'static str,
2491    /// Method for releasing a terminal.
2492    pub terminal_release: &'static str,
2493    /// Method for waiting for a terminal to finish.
2494    pub terminal_wait_for_exit: &'static str,
2495    /// Method for killing a terminal.
2496    pub terminal_kill: &'static str,
2497    /// Method for opening an MCP-over-ACP connection.
2498    #[cfg(feature = "unstable_mcp_over_acp")]
2499    pub mcp_connect: &'static str,
2500    /// Method for exchanging MCP-over-ACP messages.
2501    #[cfg(feature = "unstable_mcp_over_acp")]
2502    pub mcp_message: &'static str,
2503    /// Method for closing an MCP-over-ACP connection.
2504    #[cfg(feature = "unstable_mcp_over_acp")]
2505    pub mcp_disconnect: &'static str,
2506    /// Method for elicitation.
2507    pub elicitation_create: &'static str,
2508    /// Notification for elicitation completion.
2509    pub elicitation_complete: &'static str,
2510}
2511
2512/// Constant containing all client method names.
2513pub const CLIENT_METHOD_NAMES: ClientMethodNames = ClientMethodNames {
2514    session_update: SESSION_UPDATE_NOTIFICATION,
2515    session_request_permission: SESSION_REQUEST_PERMISSION_METHOD_NAME,
2516    fs_write_text_file: FS_WRITE_TEXT_FILE_METHOD_NAME,
2517    fs_read_text_file: FS_READ_TEXT_FILE_METHOD_NAME,
2518    terminal_create: TERMINAL_CREATE_METHOD_NAME,
2519    terminal_output: TERMINAL_OUTPUT_METHOD_NAME,
2520    terminal_release: TERMINAL_RELEASE_METHOD_NAME,
2521    terminal_wait_for_exit: TERMINAL_WAIT_FOR_EXIT_METHOD_NAME,
2522    terminal_kill: TERMINAL_KILL_METHOD_NAME,
2523    #[cfg(feature = "unstable_mcp_over_acp")]
2524    mcp_connect: MCP_CONNECT_METHOD_NAME,
2525    #[cfg(feature = "unstable_mcp_over_acp")]
2526    mcp_message: MCP_MESSAGE_METHOD_NAME,
2527    #[cfg(feature = "unstable_mcp_over_acp")]
2528    mcp_disconnect: MCP_DISCONNECT_METHOD_NAME,
2529    elicitation_create: ELICITATION_CREATE_METHOD_NAME,
2530    elicitation_complete: ELICITATION_COMPLETE_NOTIFICATION,
2531};
2532
2533/// Notification name for session updates.
2534pub(crate) const SESSION_UPDATE_NOTIFICATION: &str = "session/update";
2535/// Method name for requesting user permission.
2536pub(crate) const SESSION_REQUEST_PERMISSION_METHOD_NAME: &str = "session/request_permission";
2537/// Method name for writing text files.
2538pub(crate) const FS_WRITE_TEXT_FILE_METHOD_NAME: &str = "fs/write_text_file";
2539/// Method name for reading text files.
2540pub(crate) const FS_READ_TEXT_FILE_METHOD_NAME: &str = "fs/read_text_file";
2541/// Method name for creating a new terminal.
2542pub(crate) const TERMINAL_CREATE_METHOD_NAME: &str = "terminal/create";
2543/// Method for getting terminals output.
2544pub(crate) const TERMINAL_OUTPUT_METHOD_NAME: &str = "terminal/output";
2545/// Method for releasing a terminal.
2546pub(crate) const TERMINAL_RELEASE_METHOD_NAME: &str = "terminal/release";
2547/// Method for waiting for a terminal to finish.
2548pub(crate) const TERMINAL_WAIT_FOR_EXIT_METHOD_NAME: &str = "terminal/wait_for_exit";
2549/// Method for killing a terminal.
2550pub(crate) const TERMINAL_KILL_METHOD_NAME: &str = "terminal/kill";
2551/// Method name for elicitation.
2552pub(crate) const ELICITATION_CREATE_METHOD_NAME: &str = "elicitation/create";
2553/// Notification name for elicitation completion.
2554pub(crate) const ELICITATION_COMPLETE_NOTIFICATION: &str = "elicitation/complete";
2555
2556/// All possible requests that an agent can send to a client.
2557///
2558/// This enum is used internally for routing RPC requests. You typically won't need
2559/// to use this directly.
2560///
2561/// This enum encompasses all method calls from agent to client.
2562#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2563#[derive(Clone, Debug, Serialize, Deserialize)]
2564#[serde(untagged)]
2565#[cfg_attr(feature = "schemars", schemars(inline))]
2566#[non_exhaustive]
2567#[allow(clippy::large_enum_variant)]
2568pub enum AgentRequest {
2569    /// Writes content to a text file in the client's file system.
2570    ///
2571    /// Only available if the client advertises the `fs.writeTextFile` capability.
2572    /// Allows the agent to create or modify files within the client's environment.
2573    ///
2574    /// See protocol docs: [Client](https://agentclientprotocol.com/protocol/overview#client)
2575    WriteTextFileRequest(WriteTextFileRequest),
2576    /// Reads content from a text file in the client's file system.
2577    ///
2578    /// Only available if the client advertises the `fs.readTextFile` capability.
2579    /// Allows the agent to access file contents within the client's environment.
2580    ///
2581    /// See protocol docs: [Client](https://agentclientprotocol.com/protocol/overview#client)
2582    ReadTextFileRequest(ReadTextFileRequest),
2583    /// Requests permission from the user for a tool call operation.
2584    ///
2585    /// Called by the agent when it needs user authorization before executing
2586    /// a potentially sensitive operation. The client should present the options
2587    /// to the user and return their decision.
2588    ///
2589    /// If the client cancels the prompt turn via `session/cancel`, it MUST
2590    /// respond to this request with `RequestPermissionOutcome::Cancelled`.
2591    ///
2592    /// See protocol docs: [Requesting Permission](https://agentclientprotocol.com/protocol/tool-calls#requesting-permission)
2593    RequestPermissionRequest(RequestPermissionRequest),
2594    /// Executes a command in a new terminal
2595    ///
2596    /// Only available if the `terminal` Client capability is set to `true`.
2597    ///
2598    /// Returns a `TerminalId` that can be used with other terminal methods
2599    /// to get the current output, wait for exit, and kill the command.
2600    ///
2601    /// The `TerminalId` can also be used to embed the terminal in a tool call
2602    /// by using the `ToolCallContent::Terminal` variant.
2603    ///
2604    /// The Agent is responsible for releasing the terminal by using the `terminal/release`
2605    /// method.
2606    ///
2607    /// See protocol docs: [Terminals](https://agentclientprotocol.com/protocol/terminals)
2608    CreateTerminalRequest(CreateTerminalRequest),
2609    /// Gets the terminal output and exit status
2610    ///
2611    /// Returns the current content in the terminal without waiting for the command to exit.
2612    /// If the command has already exited, the exit status is included.
2613    ///
2614    /// See protocol docs: [Terminals](https://agentclientprotocol.com/protocol/terminals)
2615    TerminalOutputRequest(TerminalOutputRequest),
2616    /// Releases a terminal
2617    ///
2618    /// The command is killed if it hasn't exited yet. Use `terminal/wait_for_exit`
2619    /// to wait for the command to exit before releasing the terminal.
2620    ///
2621    /// After release, the `TerminalId` can no longer be used with other `terminal/*` methods,
2622    /// but tool calls that already contain it, continue to display its output.
2623    ///
2624    /// The `terminal/kill` method can be used to terminate the command without releasing
2625    /// the terminal, allowing the Agent to call `terminal/output` and other methods.
2626    ///
2627    /// See protocol docs: [Terminals](https://agentclientprotocol.com/protocol/terminals)
2628    ReleaseTerminalRequest(ReleaseTerminalRequest),
2629    /// Waits for the terminal command to exit and return its exit status
2630    ///
2631    /// See protocol docs: [Terminals](https://agentclientprotocol.com/protocol/terminals)
2632    WaitForTerminalExitRequest(WaitForTerminalExitRequest),
2633    /// Kills the terminal command without releasing the terminal
2634    ///
2635    /// While `terminal/release` will also kill the command, this method will keep
2636    /// the `TerminalId` valid so it can be used with other methods.
2637    ///
2638    /// This method can be helpful when implementing command timeouts which terminate
2639    /// the command as soon as elapsed, and then get the final output so it can be sent
2640    /// to the model.
2641    ///
2642    /// Note: Call `terminal/release` when `TerminalId` is no longer needed.
2643    ///
2644    /// See protocol docs: [Terminals](https://agentclientprotocol.com/protocol/terminals)
2645    KillTerminalRequest(KillTerminalRequest),
2646    /// Requests structured user input via a form or URL.
2647    ///
2648    /// See protocol docs: [Elicitation](https://agentclientprotocol.com/protocol/elicitation)
2649    CreateElicitationRequest(CreateElicitationRequest),
2650    /// **UNSTABLE**
2651    ///
2652    /// This capability is not part of the spec yet, and may be removed or changed at any point.
2653    ///
2654    /// Opens an MCP-over-ACP connection.
2655    #[cfg(feature = "unstable_mcp_over_acp")]
2656    ConnectMcpRequest(ConnectMcpRequest),
2657    /// **UNSTABLE**
2658    ///
2659    /// This capability is not part of the spec yet, and may be removed or changed at any point.
2660    ///
2661    /// Exchanges an MCP-over-ACP message.
2662    #[cfg(feature = "unstable_mcp_over_acp")]
2663    MessageMcpRequest(MessageMcpRequest),
2664    /// **UNSTABLE**
2665    ///
2666    /// This capability is not part of the spec yet, and may be removed or changed at any point.
2667    ///
2668    /// Closes an MCP-over-ACP connection.
2669    #[cfg(feature = "unstable_mcp_over_acp")]
2670    DisconnectMcpRequest(DisconnectMcpRequest),
2671    /// Handles extension method requests from the agent.
2672    ///
2673    /// Allows the Agent to send an arbitrary request that is not part of the ACP spec.
2674    /// Extension methods provide a way to add custom functionality while maintaining
2675    /// protocol compatibility.
2676    ///
2677    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
2678    ExtMethodRequest(ExtRequest),
2679}
2680
2681impl AgentRequest {
2682    /// Returns the corresponding method name of the request.
2683    #[must_use]
2684    pub fn method(&self) -> &str {
2685        match self {
2686            Self::WriteTextFileRequest(_) => CLIENT_METHOD_NAMES.fs_write_text_file,
2687            Self::ReadTextFileRequest(_) => CLIENT_METHOD_NAMES.fs_read_text_file,
2688            Self::RequestPermissionRequest(_) => CLIENT_METHOD_NAMES.session_request_permission,
2689            Self::CreateTerminalRequest(_) => CLIENT_METHOD_NAMES.terminal_create,
2690            Self::TerminalOutputRequest(_) => CLIENT_METHOD_NAMES.terminal_output,
2691            Self::ReleaseTerminalRequest(_) => CLIENT_METHOD_NAMES.terminal_release,
2692            Self::WaitForTerminalExitRequest(_) => CLIENT_METHOD_NAMES.terminal_wait_for_exit,
2693            Self::KillTerminalRequest(_) => CLIENT_METHOD_NAMES.terminal_kill,
2694            Self::CreateElicitationRequest(_) => CLIENT_METHOD_NAMES.elicitation_create,
2695            #[cfg(feature = "unstable_mcp_over_acp")]
2696            Self::ConnectMcpRequest(_) => CLIENT_METHOD_NAMES.mcp_connect,
2697            #[cfg(feature = "unstable_mcp_over_acp")]
2698            Self::MessageMcpRequest(_) => CLIENT_METHOD_NAMES.mcp_message,
2699            #[cfg(feature = "unstable_mcp_over_acp")]
2700            Self::DisconnectMcpRequest(_) => CLIENT_METHOD_NAMES.mcp_disconnect,
2701            Self::ExtMethodRequest(ext_request) => &ext_request.method,
2702        }
2703    }
2704}
2705
2706/// All possible responses that a client can send to an agent.
2707///
2708/// This enum is used internally for routing RPC responses. You typically won't need
2709/// to use this directly - the responses are handled automatically by the connection.
2710///
2711/// These are responses to the corresponding `AgentRequest` variants.
2712#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2713#[derive(Clone, Debug, Serialize, Deserialize)]
2714#[serde(untagged)]
2715#[cfg_attr(feature = "schemars", schemars(inline))]
2716#[non_exhaustive]
2717pub enum ClientResponse {
2718    /// Successful result returned for a `fs/write_text_file` request.
2719    WriteTextFileResponse(#[serde(default)] WriteTextFileResponse),
2720    /// Successful result returned for a `fs/read_text_file` request.
2721    ReadTextFileResponse(ReadTextFileResponse),
2722    /// Successful result returned for a `session/request_permission` request.
2723    RequestPermissionResponse(RequestPermissionResponse),
2724    /// Successful result returned for a `terminal/create` request.
2725    CreateTerminalResponse(CreateTerminalResponse),
2726    /// Successful result returned for a `terminal/output` request.
2727    TerminalOutputResponse(TerminalOutputResponse),
2728    /// Successful result returned for a `terminal/release` request.
2729    ReleaseTerminalResponse(#[serde(default)] ReleaseTerminalResponse),
2730    /// Successful result returned for a `terminal/wait_for_exit` request.
2731    WaitForTerminalExitResponse(WaitForTerminalExitResponse),
2732    /// Successful result returned for a `terminal/kill` request.
2733    KillTerminalResponse(#[serde(default)] KillTerminalResponse),
2734    /// Successful result returned for a `elicitation/create` request.
2735    CreateElicitationResponse(CreateElicitationResponse),
2736    /// Successful result returned for a `mcp/connect` request.
2737    #[cfg(feature = "unstable_mcp_over_acp")]
2738    ConnectMcpResponse(ConnectMcpResponse),
2739    /// Successful result returned for a `mcp/disconnect` request.
2740    #[cfg(feature = "unstable_mcp_over_acp")]
2741    DisconnectMcpResponse(#[serde(default)] DisconnectMcpResponse),
2742    /// Successful result returned by an MCP-over-ACP `mcp/message` request.
2743    #[cfg(feature = "unstable_mcp_over_acp")]
2744    MessageMcpResponse(MessageMcpResponse),
2745    /// Successful result returned by an extension method outside the core ACP method set.
2746    ExtMethodResponse(ExtResponse),
2747}
2748
2749/// All possible notifications that an agent can send to a client.
2750///
2751/// This enum is used internally for routing RPC notifications. You typically won't need
2752/// to use this directly.
2753///
2754/// Notifications do not expect a response.
2755#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2756#[derive(Clone, Debug, Serialize, Deserialize)]
2757#[serde(untagged)]
2758#[expect(clippy::large_enum_variant)]
2759#[cfg_attr(feature = "schemars", schemars(inline))]
2760#[non_exhaustive]
2761pub enum AgentNotification {
2762    /// Handles session update notifications from the agent.
2763    ///
2764    /// This is a notification endpoint (no response expected) that receives
2765    /// real-time updates about session progress, including message chunks,
2766    /// tool calls, and execution plans.
2767    ///
2768    /// Note: Clients SHOULD continue accepting tool call updates even after
2769    /// sending a `session/cancel` notification, as the agent may send final
2770    /// updates before responding with the cancelled stop reason.
2771    ///
2772    /// See protocol docs: [Agent Reports Output](https://agentclientprotocol.com/protocol/prompt-turn#3-agent-reports-output)
2773    SessionNotification(SessionNotification),
2774    /// Notification that a URL-based elicitation has completed.
2775    ///
2776    /// See protocol docs: [Elicitation](https://agentclientprotocol.com/protocol/elicitation#url-completion)
2777    CompleteElicitationNotification(CompleteElicitationNotification),
2778    /// **UNSTABLE**
2779    ///
2780    /// This capability is not part of the spec yet, and may be removed or changed at any point.
2781    ///
2782    /// Receives an MCP-over-ACP notification.
2783    #[cfg(feature = "unstable_mcp_over_acp")]
2784    MessageMcpNotification(MessageMcpNotification),
2785    /// Handles extension notifications from the agent.
2786    ///
2787    /// Allows the Agent to send an arbitrary notification that is not part of the ACP spec.
2788    /// Extension notifications provide a way to send one-way messages for custom functionality
2789    /// while maintaining protocol compatibility.
2790    ///
2791    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
2792    ExtNotification(ExtNotification),
2793}
2794
2795impl AgentNotification {
2796    /// Returns the corresponding method name of the notification.
2797    #[must_use]
2798    pub fn method(&self) -> &str {
2799        match self {
2800            Self::SessionNotification(_) => CLIENT_METHOD_NAMES.session_update,
2801            Self::CompleteElicitationNotification(_) => CLIENT_METHOD_NAMES.elicitation_complete,
2802            #[cfg(feature = "unstable_mcp_over_acp")]
2803            Self::MessageMcpNotification(_) => CLIENT_METHOD_NAMES.mcp_message,
2804            Self::ExtNotification(ext_notification) => &ext_notification.method,
2805        }
2806    }
2807}
2808
2809#[cfg(test)]
2810mod tests {
2811    use super::*;
2812
2813    #[cfg(feature = "unstable_session_compaction")]
2814    #[test]
2815    fn compaction_updates_preserve_patch_and_open_status_semantics() {
2816        use serde_json::json;
2817
2818        assert_eq!(
2819            serde_json::to_value(SessionUpdate::CompactionUpdate(CompactionUpdate::new(
2820                "cmp_001",
2821                CompactionStatus::InProgress,
2822            )))
2823            .unwrap(),
2824            json!({
2825                "sessionUpdate": "compaction_update",
2826                "compactionId": "cmp_001",
2827                "status": "in_progress"
2828            })
2829        );
2830
2831        let SessionUpdate::CompactionUpdate(update) = serde_json::from_value(json!({
2832            "sessionUpdate": "compaction_update",
2833            "compactionId": "cmp_001",
2834            "status": "paused",
2835            "summary": null,
2836            "error": "waiting"
2837        }))
2838        .unwrap() else {
2839            panic!("expected compaction update");
2840        };
2841        assert_eq!(update.status, CompactionStatus::Other("paused".into()));
2842        assert!(update.summary.is_null());
2843        assert_eq!(update.error.value().map(String::as_str), Some("waiting"));
2844        assert!(update.meta.is_undefined());
2845    }
2846
2847    #[cfg(feature = "unstable_session_compaction")]
2848    #[test]
2849    fn compaction_chunk_and_v1_capability_serialize() {
2850        use serde_json::json;
2851
2852        assert_eq!(
2853            serde_json::to_value(SessionUpdate::CompactionSummaryChunk(
2854                CompactionSummaryChunk::new(
2855                    "cmp_001",
2856                    ContentBlock::Text(crate::v1::TextContent::new("retained")),
2857                ),
2858            ))
2859            .unwrap(),
2860            json!({
2861                "sessionUpdate": "compaction_summary_chunk",
2862                "compactionId": "cmp_001",
2863                "content": { "type": "text", "text": "retained" }
2864            })
2865        );
2866        assert_eq!(
2867            serde_json::to_value(
2868                ClientSessionCapabilities::new().compaction(CompactionCapabilities::new())
2869            )
2870            .unwrap(),
2871            json!({ "compaction": {} })
2872        );
2873        let absent: ClientSessionCapabilities = serde_json::from_value(json!({})).unwrap();
2874        let null: ClientSessionCapabilities =
2875            serde_json::from_value(json!({ "compaction": null })).unwrap();
2876        assert!(absent.compaction.is_none());
2877        assert!(null.compaction.is_none());
2878    }
2879
2880    #[test]
2881    fn test_elicitation_capability_semantics() {
2882        use serde_json::json;
2883
2884        let unsupported: ClientCapabilities = serde_json::from_value(json!({})).unwrap();
2885        assert!(unsupported.elicitation.is_none());
2886
2887        let null: ClientCapabilities =
2888            serde_json::from_value(json!({ "elicitation": null })).unwrap();
2889        assert!(null.elicitation.is_none());
2890
2891        let malformed: ClientCapabilities =
2892            serde_json::from_value(json!({ "elicitation": false })).unwrap();
2893        assert!(malformed.elicitation.is_none());
2894
2895        let empty: ClientCapabilities =
2896            serde_json::from_value(json!({ "elicitation": {} })).unwrap();
2897        let empty = empty.elicitation.expect("present capability");
2898        assert!(!empty.supports_form());
2899        assert!(!empty.supports_url());
2900
2901        let form_only: ClientCapabilities = serde_json::from_value(json!({
2902            "elicitation": { "form": {} }
2903        }))
2904        .unwrap();
2905        let form_only = form_only.elicitation.expect("advertised capability");
2906        assert!(form_only.supports_form());
2907        assert!(!form_only.supports_url());
2908
2909        let url_only: ClientCapabilities = serde_json::from_value(json!({
2910            "elicitation": { "url": {} }
2911        }))
2912        .unwrap();
2913        let url_only = url_only.elicitation.expect("advertised capability");
2914        assert!(!url_only.supports_form());
2915        assert!(url_only.supports_url());
2916
2917        let both: ClientCapabilities = serde_json::from_value(json!({
2918            "elicitation": { "form": {}, "url": {} }
2919        }))
2920        .unwrap();
2921        let both = both.elicitation.expect("advertised capability");
2922        assert!(both.supports_form());
2923        assert!(both.supports_url());
2924    }
2925
2926    #[test]
2927    fn test_elicitation_method_routing_and_envelopes() {
2928        use serde_json::json;
2929
2930        assert_eq!(CLIENT_METHOD_NAMES.elicitation_create, "elicitation/create");
2931        assert_eq!(
2932            CLIENT_METHOD_NAMES.elicitation_complete,
2933            "elicitation/complete"
2934        );
2935
2936        let request = AgentRequest::CreateElicitationRequest(CreateElicitationRequest::new(
2937            crate::v1::ElicitationFormMode::new(
2938                crate::v1::ElicitationSessionScope::new("sess_1"),
2939                crate::v1::ElicitationSchema::new(),
2940            ),
2941            "Choose a value",
2942        ));
2943        assert_eq!(request.method(), "elicitation/create");
2944        let method = Arc::from(request.method());
2945        let request = crate::v1::JsonRpcMessage::wrap(crate::v1::Request {
2946            id: crate::v1::RequestId::Number(7),
2947            method,
2948            params: Some(request),
2949        });
2950        assert_eq!(
2951            serde_json::to_value(request).unwrap(),
2952            json!({
2953                "jsonrpc": "2.0",
2954                "id": 7,
2955                "method": "elicitation/create",
2956                "params": {
2957                    "mode": "form",
2958                    "sessionId": "sess_1",
2959                    "message": "Choose a value",
2960                    "requestedSchema": { "type": "object", "properties": {} }
2961                }
2962            })
2963        );
2964
2965        let notification = AgentNotification::CompleteElicitationNotification(
2966            CompleteElicitationNotification::new("elic_1"),
2967        );
2968        assert_eq!(notification.method(), "elicitation/complete");
2969        let method = Arc::from(notification.method());
2970        let notification = crate::v1::JsonRpcMessage::wrap(crate::v1::Notification {
2971            method,
2972            params: Some(notification),
2973        });
2974        assert_eq!(
2975            serde_json::to_value(notification).unwrap(),
2976            json!({
2977                "jsonrpc": "2.0",
2978                "method": "elicitation/complete",
2979                "params": { "elicitationId": "elic_1" }
2980            })
2981        );
2982    }
2983
2984    #[test]
2985    fn test_client_capabilities_default_on_malformed_values() {
2986        use serde_json::json;
2987
2988        let capabilities: ClientCapabilities = serde_json::from_value(json!({
2989            "fs": {
2990                "readTextFile": "yes",
2991                "writeTextFile": true
2992            },
2993            "terminal": {}
2994        }))
2995        .unwrap();
2996
2997        assert!(!capabilities.fs.read_text_file);
2998        assert!(capabilities.fs.write_text_file);
2999        assert!(!capabilities.terminal);
3000
3001        let capabilities: ClientCapabilities = serde_json::from_value(json!({
3002            "fs": false
3003        }))
3004        .unwrap();
3005        assert_eq!(capabilities.fs, FileSystemCapabilities::default());
3006
3007        {
3008            let capabilities: ClientCapabilities = serde_json::from_value(json!({
3009                "auth": false
3010            }))
3011            .unwrap();
3012            assert_eq!(capabilities.auth, AuthCapabilities::default());
3013
3014            let capabilities: AuthCapabilities = serde_json::from_value(json!({
3015                "terminal": {}
3016            }))
3017            .unwrap();
3018            assert!(!capabilities.terminal);
3019        }
3020    }
3021
3022    #[test]
3023    fn test_serialization_behavior() {
3024        use serde_json::json;
3025
3026        assert_eq!(
3027            serde_json::from_value::<SessionInfoUpdate>(json!({})).unwrap(),
3028            SessionInfoUpdate {
3029                title: MaybeUndefined::Undefined,
3030                updated_at: MaybeUndefined::Undefined,
3031                meta: None
3032            }
3033        );
3034        assert_eq!(
3035            serde_json::from_value::<SessionInfoUpdate>(json!({"title": null, "updatedAt": null}))
3036                .unwrap(),
3037            SessionInfoUpdate {
3038                title: MaybeUndefined::Null,
3039                updated_at: MaybeUndefined::Null,
3040                meta: None
3041            }
3042        );
3043        assert_eq!(
3044            serde_json::from_value::<SessionInfoUpdate>(
3045                json!({"title": "title", "updatedAt": "timestamp"})
3046            )
3047            .unwrap(),
3048            SessionInfoUpdate {
3049                title: MaybeUndefined::Value("title".to_string()),
3050                updated_at: MaybeUndefined::Value("timestamp".to_string()),
3051                meta: None
3052            }
3053        );
3054
3055        assert_eq!(
3056            serde_json::to_value(SessionInfoUpdate::new()).unwrap(),
3057            json!({})
3058        );
3059        assert_eq!(
3060            serde_json::to_value(SessionInfoUpdate::new().title("title")).unwrap(),
3061            json!({"title": "title"})
3062        );
3063        assert_eq!(
3064            serde_json::to_value(SessionInfoUpdate::new().title(None)).unwrap(),
3065            json!({"title": null})
3066        );
3067        assert_eq!(
3068            serde_json::to_value(
3069                SessionInfoUpdate::new()
3070                    .title("title")
3071                    .title(MaybeUndefined::Undefined)
3072            )
3073            .unwrap(),
3074            json!({})
3075        );
3076    }
3077
3078    #[test]
3079    fn test_content_chunk_message_id_serialization() {
3080        use serde_json::json;
3081
3082        assert_eq!(
3083            serde_json::to_value(SessionUpdate::AgentMessageChunk(ContentChunk::new(
3084                ContentBlock::Text(crate::v1::TextContent::new("Hello"))
3085            )))
3086            .unwrap(),
3087            json!({
3088                "sessionUpdate": "agent_message_chunk",
3089                "content": {
3090                    "type": "text",
3091                    "text": "Hello"
3092                }
3093            })
3094        );
3095
3096        assert_eq!(
3097            serde_json::to_value(SessionUpdate::AgentMessageChunk(
3098                ContentChunk::new(ContentBlock::Text(crate::v1::TextContent::new("Hello")))
3099                    .message_id("msg_agent_c42b9")
3100            ))
3101            .unwrap(),
3102            json!({
3103                "sessionUpdate": "agent_message_chunk",
3104                "messageId": "msg_agent_c42b9",
3105                "content": {
3106                    "type": "text",
3107                    "text": "Hello"
3108                }
3109            })
3110        );
3111
3112        let SessionUpdate::AgentMessageChunk(chunk) = serde_json::from_value(json!({
3113            "sessionUpdate": "agent_message_chunk",
3114            "messageId": null,
3115            "content": {
3116                "type": "text",
3117                "text": "Hello"
3118            }
3119        }))
3120        .unwrap() else {
3121            panic!("expected agent message chunk");
3122        };
3123
3124        assert_eq!(chunk.message_id, None);
3125    }
3126
3127    #[test]
3128    fn test_usage_update_serialization() {
3129        use serde_json::json;
3130
3131        assert_eq!(
3132            serde_json::to_value(SessionUpdate::UsageUpdate(UsageUpdate::new(
3133                53_000, 200_000
3134            )))
3135            .unwrap(),
3136            json!({
3137                "sessionUpdate": "usage_update",
3138                "used": 53000,
3139                "size": 200_000
3140            })
3141        );
3142
3143        assert_eq!(
3144            serde_json::to_value(SessionUpdate::UsageUpdate(
3145                UsageUpdate::new(53_000, 200_000).cost(Cost::new(0.045, "USD"))
3146            ))
3147            .unwrap(),
3148            json!({
3149                "sessionUpdate": "usage_update",
3150                "used": 53000,
3151                "size": 200_000,
3152                "cost": {
3153                    "amount": 0.045,
3154                    "currency": "USD"
3155                }
3156            })
3157        );
3158
3159        let SessionUpdate::UsageUpdate(update) = serde_json::from_value(json!({
3160            "sessionUpdate": "usage_update",
3161            "used": 53000,
3162            "size": 200_000,
3163            "cost": null
3164        }))
3165        .unwrap() else {
3166            panic!("expected usage update");
3167        };
3168
3169        assert_eq!(update.cost, None);
3170    }
3171
3172    #[cfg(feature = "unstable_nes")]
3173    #[test]
3174    fn test_client_capabilities_position_encodings_serialization() {
3175        use serde_json::json;
3176
3177        let capabilities = ClientCapabilities::new().position_encodings(vec![
3178            PositionEncodingKind::Utf32,
3179            PositionEncodingKind::Utf16,
3180        ]);
3181        let json = serde_json::to_value(&capabilities).unwrap();
3182
3183        assert_eq!(json["positionEncodings"], json!(["utf-32", "utf-16"]));
3184    }
3185
3186    #[test]
3187    fn test_client_capabilities_boolean_config_options_serialization() {
3188        use serde_json::json;
3189
3190        let capabilities = ClientCapabilities::new().session(
3191            ClientSessionCapabilities::new().config_options(
3192                SessionConfigOptionsCapabilities::new()
3193                    .boolean(BooleanConfigOptionCapabilities::new()),
3194            ),
3195        );
3196        let json = serde_json::to_value(&capabilities).unwrap();
3197
3198        assert_eq!(json["session"]["configOptions"]["boolean"], json!({}));
3199
3200        let omitted: ClientCapabilities = serde_json::from_value(json!({})).unwrap();
3201        assert!(omitted.session.is_none());
3202
3203        let null_session: ClientCapabilities = serde_json::from_value(json!({
3204            "session": null
3205        }))
3206        .unwrap();
3207        assert!(null_session.session.is_none());
3208
3209        let null_config_options: ClientCapabilities = serde_json::from_value(json!({
3210            "session": {
3211                "configOptions": null
3212            }
3213        }))
3214        .unwrap();
3215        assert!(
3216            null_config_options
3217                .session
3218                .and_then(|session| session.config_options)
3219                .is_none()
3220        );
3221
3222        let null_boolean: ClientCapabilities = serde_json::from_value(json!({
3223            "session": {
3224                "configOptions": {
3225                    "boolean": null
3226                }
3227            }
3228        }))
3229        .unwrap();
3230        assert!(
3231            null_boolean
3232                .session
3233                .and_then(|session| session.config_options)
3234                .and_then(|config_options| config_options.boolean)
3235                .is_none()
3236        );
3237    }
3238
3239    #[cfg(feature = "unstable_plan_operations")]
3240    #[test]
3241    fn test_plan_operations_serialization() {
3242        use serde_json::json;
3243
3244        use crate::v1::{PlanEntry, PlanEntryPriority, PlanEntryStatus, PlanUpdateContent};
3245
3246        let plan_update = SessionUpdate::PlanUpdate(PlanUpdate::new(PlanUpdateContent::items(
3247            "plan-1",
3248            vec![PlanEntry::new(
3249                "Step 1",
3250                PlanEntryPriority::High,
3251                PlanEntryStatus::Pending,
3252            )],
3253        )));
3254
3255        assert_eq!(
3256            serde_json::to_value(plan_update).unwrap(),
3257            json!({
3258                "sessionUpdate": "plan_update",
3259                "plan": {
3260                    "type": "items",
3261                    "planId": "plan-1",
3262                    "entries": [
3263                        {
3264                            "content": "Step 1",
3265                            "priority": "high",
3266                            "status": "pending"
3267                        }
3268                    ]
3269                }
3270            })
3271        );
3272
3273        assert_eq!(
3274            serde_json::to_value(SessionUpdate::PlanRemoved(PlanRemoved::new("plan-1"))).unwrap(),
3275            json!({
3276                "sessionUpdate": "plan_removed",
3277                "planId": "plan-1"
3278            })
3279        );
3280
3281        let capabilities = ClientCapabilities::new().plan(PlanCapabilities::new());
3282        let json = serde_json::to_value(&capabilities).unwrap();
3283        assert_eq!(json["plan"], json!({}));
3284
3285        assert_eq!(
3286            serde_json::from_value::<ClientCapabilities>(json!({ "plan": null }))
3287                .unwrap()
3288                .plan,
3289            None
3290        );
3291    }
3292
3293    #[cfg(feature = "unstable_mcp_over_acp")]
3294    #[test]
3295    fn test_agent_mcp_request_method_names() {
3296        use serde_json::json;
3297
3298        let params: serde_json::Map<String, serde_json::Value> =
3299            [("cursor".to_string(), json!("abc"))].into_iter().collect();
3300
3301        assert_eq!(CLIENT_METHOD_NAMES.mcp_connect, "mcp/connect");
3302        assert_eq!(CLIENT_METHOD_NAMES.mcp_message, "mcp/message");
3303        assert_eq!(CLIENT_METHOD_NAMES.mcp_disconnect, "mcp/disconnect");
3304
3305        assert_eq!(
3306            AgentRequest::ConnectMcpRequest(ConnectMcpRequest::new("server-1")).method(),
3307            "mcp/connect"
3308        );
3309        assert_eq!(
3310            AgentRequest::MessageMcpRequest(MessageMcpRequest::new("conn-1", "tools/list"))
3311                .method(),
3312            "mcp/message"
3313        );
3314        assert_eq!(
3315            AgentRequest::DisconnectMcpRequest(DisconnectMcpRequest::new("conn-1")).method(),
3316            "mcp/disconnect"
3317        );
3318        assert_eq!(
3319            AgentNotification::MessageMcpNotification(MessageMcpNotification::new(
3320                "conn-1",
3321                "notifications/progress"
3322            ))
3323            .method(),
3324            "mcp/message"
3325        );
3326
3327        assert_eq!(
3328            serde_json::to_value(ConnectMcpRequest::new("server-1")).unwrap(),
3329            json!({ "serverId": "server-1" })
3330        );
3331        assert_eq!(
3332            serde_json::to_value(ConnectMcpResponse::new("conn-1")).unwrap(),
3333            json!({ "connectionId": "conn-1" })
3334        );
3335        assert_eq!(
3336            serde_json::to_value(MessageMcpRequest::new("conn-1", "tools/list").params(params))
3337                .unwrap(),
3338            json!({
3339                "connectionId": "conn-1",
3340                "method": "tools/list",
3341                "params": { "cursor": "abc" }
3342            })
3343        );
3344        assert_eq!(
3345            serde_json::to_value(DisconnectMcpRequest::new("conn-1")).unwrap(),
3346            json!({ "connectionId": "conn-1" })
3347        );
3348        assert_eq!(
3349            serde_json::to_value(MessageMcpNotification::new(
3350                "conn-1",
3351                "notifications/progress"
3352            ))
3353            .unwrap(),
3354            json!({
3355                "connectionId": "conn-1",
3356                "method": "notifications/progress"
3357            })
3358        );
3359
3360        let request_with_null_params: MessageMcpRequest = serde_json::from_value(json!({
3361            "connectionId": "conn-1",
3362            "method": "tools/list",
3363            "params": null
3364        }))
3365        .unwrap();
3366        assert_eq!(request_with_null_params.params, None);
3367    }
3368
3369    #[test]
3370    fn request_permission_request_rejects_malformed_options() {
3371        use serde_json::json;
3372
3373        assert!(
3374            serde_json::from_value::<RequestPermissionRequest>(json!({
3375                "sessionId": "sess-1",
3376                "toolCall": {"toolCallId": "tc-1"},
3377                "options": "not-an-array"
3378            }))
3379            .is_err()
3380        );
3381        assert!(
3382            serde_json::from_value::<RequestPermissionRequest>(json!({
3383                "sessionId": "sess-1",
3384                "toolCall": {"toolCallId": "tc-1"},
3385                "options": [{"optionId": "allow"}]
3386            }))
3387            .is_err()
3388        );
3389    }
3390}