Skip to main content

agent_client_protocol_schema/v2/
nes.rs

1//! Next Edit Suggestions (NES) types and constants.
2//!
3//! NES allows agents to provide predictive code edits via capability negotiation,
4//! document events, and a suggestion request/response flow. NES sessions are
5//! independent of chat sessions and have their own lifecycle.
6
7use std::{collections::BTreeMap, sync::Arc};
8
9use derive_more::{Display, From};
10#[cfg(feature = "schemars")]
11use schemars::Schema;
12use serde::{Deserialize, Serialize};
13use serde_with::{DefaultOnError, DefaultOnNull, serde_as, skip_serializing_none};
14
15use super::{Meta, SessionId};
16use crate::IntoOption;
17
18// Method name constants
19
20/// Method name for starting an NES session.
21pub(crate) const NES_START_METHOD_NAME: &str = "nes/start";
22/// Method name for requesting a suggestion.
23pub(crate) const NES_SUGGEST_METHOD_NAME: &str = "nes/suggest";
24/// Method name for accepting a suggestion.
25pub(crate) const NES_ACCEPT_METHOD_NAME: &str = "nes/accept";
26/// Method name for rejecting a suggestion.
27pub(crate) const NES_REJECT_METHOD_NAME: &str = "nes/reject";
28
29/// **UNSTABLE**
30///
31/// This capability is not part of the spec yet, and may be removed or changed at any point.
32///
33/// Unique identifier for an NES suggestion.
34#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
35#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash, Display, From)]
36#[serde(transparent)]
37#[from(forward)]
38#[non_exhaustive]
39pub struct NesSuggestionId(pub Arc<str>);
40
41impl NesSuggestionId {
42    /// Wraps a protocol string as a typed [`NesSuggestionId`].
43    #[must_use]
44    pub fn new(id: impl Into<Self>) -> Self {
45        id.into()
46    }
47}
48/// Method name for closing an NES session.
49pub(crate) const NES_CLOSE_METHOD_NAME: &str = "nes/close";
50/// Notification name for document open events.
51pub(crate) const DOCUMENT_DID_OPEN_METHOD_NAME: &str = "document/didOpen";
52/// Notification name for document change events.
53pub(crate) const DOCUMENT_DID_CHANGE_METHOD_NAME: &str = "document/didChange";
54/// Notification name for document close events.
55pub(crate) const DOCUMENT_DID_CLOSE_METHOD_NAME: &str = "document/didClose";
56/// Notification name for document save events.
57pub(crate) const DOCUMENT_DID_SAVE_METHOD_NAME: &str = "document/didSave";
58/// Notification name for document focus events.
59pub(crate) const DOCUMENT_DID_FOCUS_METHOD_NAME: &str = "document/didFocus";
60
61// Position primitives
62
63/// The encoding used for character offsets in positions.
64///
65/// Follows the same conventions as LSP 3.17. The default is UTF-16.
66#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
67#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
68#[non_exhaustive]
69pub enum PositionEncodingKind {
70    /// Character offsets count UTF-16 code units. This is the default.
71    #[serde(rename = "utf-16")]
72    Utf16,
73    /// Character offsets count Unicode code points.
74    #[serde(rename = "utf-32")]
75    Utf32,
76    /// Character offsets count UTF-8 code units (bytes).
77    #[serde(rename = "utf-8")]
78    Utf8,
79}
80
81/// A zero-based position in a text document.
82///
83/// The meaning of `character` depends on the negotiated position encoding.
84#[serde_as]
85#[skip_serializing_none]
86#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
87#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
88#[serde(rename_all = "camelCase")]
89#[non_exhaustive]
90pub struct Position {
91    /// Zero-based line number.
92    pub line: u32,
93    /// Zero-based character offset (encoding-dependent).
94    pub character: u32,
95    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
96    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
97    /// these keys.
98    ///
99    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
100    #[serde_as(deserialize_as = "DefaultOnError")]
101    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
102    #[serde(default)]
103    #[serde(rename = "_meta")]
104    pub meta: Option<Meta>,
105}
106
107impl Position {
108    /// Builds a [`Position`] from protocol coordinate values.
109    #[must_use]
110    pub fn new(line: u32, character: u32) -> Self {
111        Self {
112            line,
113            character,
114            meta: None,
115        }
116    }
117
118    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
119    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
120    /// these keys.
121    ///
122    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
123    #[must_use]
124    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
125        self.meta = meta.into_option();
126        self
127    }
128}
129
130/// A range in a text document, expressed as start and end positions.
131#[serde_as]
132#[skip_serializing_none]
133#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
134#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
135#[serde(rename_all = "camelCase")]
136#[non_exhaustive]
137pub struct Range {
138    /// The start position (inclusive).
139    pub start: Position,
140    /// The end position (exclusive).
141    pub end: Position,
142    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
143    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
144    /// these keys.
145    ///
146    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
147    #[serde_as(deserialize_as = "DefaultOnError")]
148    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
149    #[serde(default)]
150    #[serde(rename = "_meta")]
151    pub meta: Option<Meta>,
152}
153
154impl Range {
155    /// Builds a [`Range`] from protocol coordinate values.
156    #[must_use]
157    pub fn new(start: Position, end: Position) -> Self {
158        Self {
159            start,
160            end,
161            meta: None,
162        }
163    }
164
165    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
166    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
167    /// these keys.
168    ///
169    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
170    #[must_use]
171    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
172        self.meta = meta.into_option();
173        self
174    }
175}
176
177// Agent NES capabilities
178
179/// NES capabilities advertised by the agent during initialization.
180///
181/// Supplying `{}` means the agent supports the NES method surface. Omitted or
182/// `null` both mean the agent does not advertise support for `nes/*` methods.
183#[serde_as]
184#[skip_serializing_none]
185#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
186#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
187#[serde(rename_all = "camelCase")]
188#[non_exhaustive]
189pub struct NesCapabilities {
190    /// Events the agent wants to receive.
191    #[serde_as(deserialize_as = "DefaultOnError")]
192    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
193    #[serde(default)]
194    pub events: Option<NesEventCapabilities>,
195    /// Context the agent wants attached to each suggestion request.
196    #[serde_as(deserialize_as = "DefaultOnError")]
197    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
198    #[serde(default)]
199    pub context: Option<NesContextCapabilities>,
200    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
201    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
202    /// these keys.
203    ///
204    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
205    #[serde_as(deserialize_as = "DefaultOnError")]
206    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
207    #[serde(default)]
208    #[serde(rename = "_meta")]
209    pub meta: Option<Meta>,
210}
211
212impl NesCapabilities {
213    /// Builds an empty [`NesCapabilities`]; use builder methods to advertise supported sub-capabilities.
214    #[must_use]
215    pub fn new() -> Self {
216        Self::default()
217    }
218
219    /// Sets or clears the optional `events` field.
220    #[must_use]
221    pub fn events(mut self, events: impl IntoOption<NesEventCapabilities>) -> Self {
222        self.events = events.into_option();
223        self
224    }
225
226    /// Sets or clears the optional `context` field.
227    #[must_use]
228    pub fn context(mut self, context: impl IntoOption<NesContextCapabilities>) -> Self {
229        self.context = context.into_option();
230        self
231    }
232
233    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
234    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
235    /// these keys.
236    ///
237    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
238    #[must_use]
239    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
240        self.meta = meta.into_option();
241        self
242    }
243}
244
245/// Event capabilities the agent can consume.
246#[serde_as]
247#[skip_serializing_none]
248#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
249#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
250#[serde(rename_all = "camelCase")]
251#[non_exhaustive]
252pub struct NesEventCapabilities {
253    /// Document event capabilities.
254    #[serde_as(deserialize_as = "DefaultOnError")]
255    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
256    #[serde(default)]
257    pub document: Option<NesDocumentEventCapabilities>,
258    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
259    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
260    /// these keys.
261    ///
262    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
263    #[serde_as(deserialize_as = "DefaultOnError")]
264    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
265    #[serde(default)]
266    #[serde(rename = "_meta")]
267    pub meta: Option<Meta>,
268}
269
270impl NesEventCapabilities {
271    /// Builds an empty [`NesEventCapabilities`]; use builder methods to advertise supported sub-capabilities.
272    #[must_use]
273    pub fn new() -> Self {
274        Self::default()
275    }
276
277    /// Sets or clears the optional `document` field.
278    #[must_use]
279    pub fn document(mut self, document: impl IntoOption<NesDocumentEventCapabilities>) -> Self {
280        self.document = document.into_option();
281        self
282    }
283
284    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
285    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
286    /// these keys.
287    ///
288    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
289    #[must_use]
290    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
291        self.meta = meta.into_option();
292        self
293    }
294}
295
296/// Document event capabilities the agent wants to receive.
297#[serde_as]
298#[skip_serializing_none]
299#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
300#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
301#[serde(rename_all = "camelCase")]
302#[non_exhaustive]
303pub struct NesDocumentEventCapabilities {
304    /// Whether the agent wants `document/didOpen` events.
305    #[serde_as(deserialize_as = "DefaultOnError")]
306    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
307    #[serde(default)]
308    pub did_open: Option<NesDocumentDidOpenCapabilities>,
309    /// Whether the agent wants `document/didChange` events, and the sync kind.
310    #[serde_as(deserialize_as = "DefaultOnError")]
311    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
312    #[serde(default)]
313    pub did_change: Option<NesDocumentDidChangeCapabilities>,
314    /// Whether the agent wants `document/didClose` events.
315    #[serde_as(deserialize_as = "DefaultOnError")]
316    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
317    #[serde(default)]
318    pub did_close: Option<NesDocumentDidCloseCapabilities>,
319    /// Whether the agent wants `document/didSave` events.
320    #[serde_as(deserialize_as = "DefaultOnError")]
321    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
322    #[serde(default)]
323    pub did_save: Option<NesDocumentDidSaveCapabilities>,
324    /// Whether the agent wants `document/didFocus` events.
325    #[serde_as(deserialize_as = "DefaultOnError")]
326    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
327    #[serde(default)]
328    pub did_focus: Option<NesDocumentDidFocusCapabilities>,
329    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
330    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
331    /// these keys.
332    ///
333    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
334    #[serde_as(deserialize_as = "DefaultOnError")]
335    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
336    #[serde(default)]
337    #[serde(rename = "_meta")]
338    pub meta: Option<Meta>,
339}
340
341impl NesDocumentEventCapabilities {
342    /// Builds an empty [`NesDocumentEventCapabilities`]; use builder methods to advertise supported sub-capabilities.
343    #[must_use]
344    pub fn new() -> Self {
345        Self::default()
346    }
347
348    /// Sets or clears the optional `didOpen` field.
349    #[must_use]
350    pub fn did_open(mut self, did_open: impl IntoOption<NesDocumentDidOpenCapabilities>) -> Self {
351        self.did_open = did_open.into_option();
352        self
353    }
354
355    /// Sets or clears the optional `didChange` field.
356    #[must_use]
357    pub fn did_change(
358        mut self,
359        did_change: impl IntoOption<NesDocumentDidChangeCapabilities>,
360    ) -> Self {
361        self.did_change = did_change.into_option();
362        self
363    }
364
365    /// Sets or clears the optional `didClose` field.
366    #[must_use]
367    pub fn did_close(
368        mut self,
369        did_close: impl IntoOption<NesDocumentDidCloseCapabilities>,
370    ) -> Self {
371        self.did_close = did_close.into_option();
372        self
373    }
374
375    /// Sets or clears the optional `didSave` field.
376    #[must_use]
377    pub fn did_save(mut self, did_save: impl IntoOption<NesDocumentDidSaveCapabilities>) -> Self {
378        self.did_save = did_save.into_option();
379        self
380    }
381
382    /// Sets or clears the optional `didFocus` field.
383    #[must_use]
384    pub fn did_focus(
385        mut self,
386        did_focus: impl IntoOption<NesDocumentDidFocusCapabilities>,
387    ) -> Self {
388        self.did_focus = did_focus.into_option();
389        self
390    }
391
392    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
393    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
394    /// these keys.
395    ///
396    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
397    #[must_use]
398    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
399        self.meta = meta.into_option();
400        self
401    }
402}
403
404/// Marker for `document/didOpen` capability support.
405#[serde_as]
406#[skip_serializing_none]
407#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
408#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
409#[serde(rename_all = "camelCase")]
410#[non_exhaustive]
411pub struct NesDocumentDidOpenCapabilities {
412    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
413    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
414    /// these keys.
415    ///
416    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
417    #[serde_as(deserialize_as = "DefaultOnError")]
418    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
419    #[serde(default)]
420    #[serde(rename = "_meta")]
421    pub meta: Option<Meta>,
422}
423
424impl NesDocumentDidOpenCapabilities {
425    /// Builds an empty [`NesDocumentDidOpenCapabilities`]; use builder methods to advertise supported sub-capabilities.
426    #[must_use]
427    pub fn new() -> Self {
428        Self::default()
429    }
430}
431
432/// Capabilities for `document/didChange` events.
433#[serde_as]
434#[skip_serializing_none]
435#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
436#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
437#[serde(rename_all = "camelCase")]
438#[non_exhaustive]
439pub struct NesDocumentDidChangeCapabilities {
440    /// The sync kind the agent wants: `"full"` or `"incremental"`.
441    pub sync_kind: TextDocumentSyncKind,
442    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
443    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
444    /// these keys.
445    ///
446    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
447    #[serde_as(deserialize_as = "DefaultOnError")]
448    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
449    #[serde(default)]
450    #[serde(rename = "_meta")]
451    pub meta: Option<Meta>,
452}
453
454impl NesDocumentDidChangeCapabilities {
455    /// Builds an empty [`NesDocumentDidChangeCapabilities`]; use builder methods to advertise supported sub-capabilities.
456    #[must_use]
457    pub fn new(sync_kind: TextDocumentSyncKind) -> Self {
458        Self {
459            sync_kind,
460            meta: None,
461        }
462    }
463
464    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
465    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
466    /// these keys.
467    ///
468    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
469    #[must_use]
470    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
471        self.meta = meta.into_option();
472        self
473    }
474}
475
476/// How the agent wants document changes delivered.
477#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
478#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
479#[non_exhaustive]
480pub enum TextDocumentSyncKind {
481    /// Client sends the entire file content on each change.
482    #[serde(rename = "full")]
483    Full,
484    /// Client sends only the changed ranges.
485    #[serde(rename = "incremental")]
486    Incremental,
487}
488
489/// Marker for `document/didClose` capability support.
490#[serde_as]
491#[skip_serializing_none]
492#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
493#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
494#[serde(rename_all = "camelCase")]
495#[non_exhaustive]
496pub struct NesDocumentDidCloseCapabilities {
497    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
498    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
499    /// these keys.
500    ///
501    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
502    #[serde_as(deserialize_as = "DefaultOnError")]
503    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
504    #[serde(default)]
505    #[serde(rename = "_meta")]
506    pub meta: Option<Meta>,
507}
508
509impl NesDocumentDidCloseCapabilities {
510    /// Builds an empty [`NesDocumentDidCloseCapabilities`]; use builder methods to advertise supported sub-capabilities.
511    #[must_use]
512    pub fn new() -> Self {
513        Self::default()
514    }
515}
516
517/// Marker for `document/didSave` capability support.
518#[serde_as]
519#[skip_serializing_none]
520#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
521#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
522#[serde(rename_all = "camelCase")]
523#[non_exhaustive]
524pub struct NesDocumentDidSaveCapabilities {
525    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
526    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
527    /// these keys.
528    ///
529    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
530    #[serde_as(deserialize_as = "DefaultOnError")]
531    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
532    #[serde(default)]
533    #[serde(rename = "_meta")]
534    pub meta: Option<Meta>,
535}
536
537impl NesDocumentDidSaveCapabilities {
538    /// Builds an empty [`NesDocumentDidSaveCapabilities`]; use builder methods to advertise supported sub-capabilities.
539    #[must_use]
540    pub fn new() -> Self {
541        Self::default()
542    }
543}
544
545/// Marker for `document/didFocus` capability support.
546#[serde_as]
547#[skip_serializing_none]
548#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
549#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
550#[serde(rename_all = "camelCase")]
551#[non_exhaustive]
552pub struct NesDocumentDidFocusCapabilities {
553    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
554    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
555    /// these keys.
556    ///
557    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
558    #[serde_as(deserialize_as = "DefaultOnError")]
559    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
560    #[serde(default)]
561    #[serde(rename = "_meta")]
562    pub meta: Option<Meta>,
563}
564
565impl NesDocumentDidFocusCapabilities {
566    /// Builds an empty [`NesDocumentDidFocusCapabilities`]; use builder methods to advertise supported sub-capabilities.
567    #[must_use]
568    pub fn new() -> Self {
569        Self::default()
570    }
571}
572
573/// Context capabilities the agent wants attached to each suggestion request.
574#[serde_as]
575#[skip_serializing_none]
576#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
577#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
578#[serde(rename_all = "camelCase")]
579#[non_exhaustive]
580pub struct NesContextCapabilities {
581    /// Whether the agent wants recent files context.
582    #[serde_as(deserialize_as = "DefaultOnError")]
583    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
584    #[serde(default)]
585    pub recent_files: Option<NesRecentFilesCapabilities>,
586    /// Whether the agent wants related snippets context.
587    #[serde_as(deserialize_as = "DefaultOnError")]
588    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
589    #[serde(default)]
590    pub related_snippets: Option<NesRelatedSnippetsCapabilities>,
591    /// Whether the agent wants edit history context.
592    #[serde_as(deserialize_as = "DefaultOnError")]
593    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
594    #[serde(default)]
595    pub edit_history: Option<NesEditHistoryCapabilities>,
596    /// Whether the agent wants user actions context.
597    #[serde_as(deserialize_as = "DefaultOnError")]
598    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
599    #[serde(default)]
600    pub user_actions: Option<NesUserActionsCapabilities>,
601    /// Whether the agent wants open files context.
602    #[serde_as(deserialize_as = "DefaultOnError")]
603    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
604    #[serde(default)]
605    pub open_files: Option<NesOpenFilesCapabilities>,
606    /// Whether the agent wants diagnostics context.
607    #[serde_as(deserialize_as = "DefaultOnError")]
608    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
609    #[serde(default)]
610    pub diagnostics: Option<NesDiagnosticsCapabilities>,
611    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
612    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
613    /// these keys.
614    ///
615    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
616    #[serde_as(deserialize_as = "DefaultOnError")]
617    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
618    #[serde(default)]
619    #[serde(rename = "_meta")]
620    pub meta: Option<Meta>,
621}
622
623impl NesContextCapabilities {
624    /// Builds an empty [`NesContextCapabilities`]; use builder methods to advertise supported sub-capabilities.
625    #[must_use]
626    pub fn new() -> Self {
627        Self::default()
628    }
629
630    /// Sets or clears the optional `recentFiles` field.
631    #[must_use]
632    pub fn recent_files(
633        mut self,
634        recent_files: impl IntoOption<NesRecentFilesCapabilities>,
635    ) -> Self {
636        self.recent_files = recent_files.into_option();
637        self
638    }
639
640    /// Sets or clears the optional `relatedSnippets` field.
641    #[must_use]
642    pub fn related_snippets(
643        mut self,
644        related_snippets: impl IntoOption<NesRelatedSnippetsCapabilities>,
645    ) -> Self {
646        self.related_snippets = related_snippets.into_option();
647        self
648    }
649
650    /// Sets or clears the optional `editHistory` field.
651    #[must_use]
652    pub fn edit_history(
653        mut self,
654        edit_history: impl IntoOption<NesEditHistoryCapabilities>,
655    ) -> Self {
656        self.edit_history = edit_history.into_option();
657        self
658    }
659
660    /// Sets or clears the optional `userActions` field.
661    #[must_use]
662    pub fn user_actions(
663        mut self,
664        user_actions: impl IntoOption<NesUserActionsCapabilities>,
665    ) -> Self {
666        self.user_actions = user_actions.into_option();
667        self
668    }
669
670    /// Sets or clears the optional `openFiles` field.
671    #[must_use]
672    pub fn open_files(mut self, open_files: impl IntoOption<NesOpenFilesCapabilities>) -> Self {
673        self.open_files = open_files.into_option();
674        self
675    }
676
677    /// Sets or clears the optional `diagnostics` field.
678    #[must_use]
679    pub fn diagnostics(mut self, diagnostics: impl IntoOption<NesDiagnosticsCapabilities>) -> Self {
680        self.diagnostics = diagnostics.into_option();
681        self
682    }
683
684    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
685    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
686    /// these keys.
687    ///
688    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
689    #[must_use]
690    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
691        self.meta = meta.into_option();
692        self
693    }
694}
695
696/// Capabilities for recent files context.
697#[serde_as]
698#[skip_serializing_none]
699#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
700#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
701#[serde(rename_all = "camelCase")]
702#[non_exhaustive]
703pub struct NesRecentFilesCapabilities {
704    /// Maximum number of recent files the agent can use.
705    #[serde_as(deserialize_as = "DefaultOnError")]
706    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
707    #[serde(default)]
708    pub max_count: Option<u32>,
709    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
710    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
711    /// these keys.
712    ///
713    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
714    #[serde_as(deserialize_as = "DefaultOnError")]
715    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
716    #[serde(default)]
717    #[serde(rename = "_meta")]
718    pub meta: Option<Meta>,
719}
720
721impl NesRecentFilesCapabilities {
722    /// Builds an empty [`NesRecentFilesCapabilities`]; use builder methods to advertise supported sub-capabilities.
723    #[must_use]
724    pub fn new() -> Self {
725        Self::default()
726    }
727}
728
729/// Capabilities for related snippets context.
730#[serde_as]
731#[skip_serializing_none]
732#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
733#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
734#[serde(rename_all = "camelCase")]
735#[non_exhaustive]
736pub struct NesRelatedSnippetsCapabilities {
737    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
738    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
739    /// these keys.
740    ///
741    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
742    #[serde_as(deserialize_as = "DefaultOnError")]
743    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
744    #[serde(default)]
745    #[serde(rename = "_meta")]
746    pub meta: Option<Meta>,
747}
748
749impl NesRelatedSnippetsCapabilities {
750    /// Builds an empty [`NesRelatedSnippetsCapabilities`]; use builder methods to advertise supported sub-capabilities.
751    #[must_use]
752    pub fn new() -> Self {
753        Self::default()
754    }
755}
756
757/// Capabilities for edit history context.
758#[serde_as]
759#[skip_serializing_none]
760#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
761#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
762#[serde(rename_all = "camelCase")]
763#[non_exhaustive]
764pub struct NesEditHistoryCapabilities {
765    /// Maximum number of edit history entries the agent can use.
766    #[serde_as(deserialize_as = "DefaultOnError")]
767    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
768    #[serde(default)]
769    pub max_count: Option<u32>,
770    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
771    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
772    /// these keys.
773    ///
774    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
775    #[serde_as(deserialize_as = "DefaultOnError")]
776    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
777    #[serde(default)]
778    #[serde(rename = "_meta")]
779    pub meta: Option<Meta>,
780}
781
782impl NesEditHistoryCapabilities {
783    /// Builds an empty [`NesEditHistoryCapabilities`]; use builder methods to advertise supported sub-capabilities.
784    #[must_use]
785    pub fn new() -> Self {
786        Self::default()
787    }
788}
789
790/// Capabilities for user actions context.
791#[serde_as]
792#[skip_serializing_none]
793#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
794#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
795#[serde(rename_all = "camelCase")]
796#[non_exhaustive]
797pub struct NesUserActionsCapabilities {
798    /// Maximum number of user actions the agent can use.
799    #[serde_as(deserialize_as = "DefaultOnError")]
800    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
801    #[serde(default)]
802    pub max_count: Option<u32>,
803    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
804    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
805    /// these keys.
806    ///
807    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
808    #[serde_as(deserialize_as = "DefaultOnError")]
809    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
810    #[serde(default)]
811    #[serde(rename = "_meta")]
812    pub meta: Option<Meta>,
813}
814
815impl NesUserActionsCapabilities {
816    /// Builds an empty [`NesUserActionsCapabilities`]; use builder methods to advertise supported sub-capabilities.
817    #[must_use]
818    pub fn new() -> Self {
819        Self::default()
820    }
821}
822
823/// Capabilities for open files context.
824#[serde_as]
825#[skip_serializing_none]
826#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
827#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
828#[serde(rename_all = "camelCase")]
829#[non_exhaustive]
830pub struct NesOpenFilesCapabilities {
831    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
832    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
833    /// these keys.
834    ///
835    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
836    #[serde_as(deserialize_as = "DefaultOnError")]
837    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
838    #[serde(default)]
839    #[serde(rename = "_meta")]
840    pub meta: Option<Meta>,
841}
842
843impl NesOpenFilesCapabilities {
844    /// Builds an empty [`NesOpenFilesCapabilities`]; use builder methods to advertise supported sub-capabilities.
845    #[must_use]
846    pub fn new() -> Self {
847        Self::default()
848    }
849}
850
851/// Capabilities for diagnostics context.
852#[serde_as]
853#[skip_serializing_none]
854#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
855#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
856#[serde(rename_all = "camelCase")]
857#[non_exhaustive]
858pub struct NesDiagnosticsCapabilities {
859    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
860    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
861    /// these keys.
862    ///
863    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
864    #[serde_as(deserialize_as = "DefaultOnError")]
865    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
866    #[serde(default)]
867    #[serde(rename = "_meta")]
868    pub meta: Option<Meta>,
869}
870
871impl NesDiagnosticsCapabilities {
872    /// Builds an empty [`NesDiagnosticsCapabilities`]; use builder methods to advertise supported sub-capabilities.
873    #[must_use]
874    pub fn new() -> Self {
875        Self::default()
876    }
877}
878
879// Client NES capabilities
880
881/// NES capabilities advertised by the client during initialization.
882#[serde_as]
883#[skip_serializing_none]
884#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
885#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
886#[serde(rename_all = "camelCase")]
887#[non_exhaustive]
888pub struct ClientNesCapabilities {
889    /// Whether the client supports the `jump` suggestion kind.
890    #[serde_as(deserialize_as = "DefaultOnError")]
891    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
892    #[serde(default)]
893    pub jump: Option<NesJumpCapabilities>,
894    /// Whether the client supports the `rename` suggestion kind.
895    #[serde_as(deserialize_as = "DefaultOnError")]
896    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
897    #[serde(default)]
898    pub rename: Option<NesRenameCapabilities>,
899    /// Whether the client supports the `searchAndReplace` suggestion kind.
900    #[serde_as(deserialize_as = "DefaultOnError")]
901    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
902    #[serde(default)]
903    pub search_and_replace: Option<NesSearchAndReplaceCapabilities>,
904    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
905    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
906    /// these keys.
907    ///
908    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
909    #[serde_as(deserialize_as = "DefaultOnError")]
910    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
911    #[serde(default)]
912    #[serde(rename = "_meta")]
913    pub meta: Option<Meta>,
914}
915
916impl ClientNesCapabilities {
917    /// Builds an empty [`ClientNesCapabilities`]; use builder methods to advertise supported sub-capabilities.
918    #[must_use]
919    pub fn new() -> Self {
920        Self::default()
921    }
922
923    /// Sets or clears the optional `jump` field.
924    #[must_use]
925    pub fn jump(mut self, jump: impl IntoOption<NesJumpCapabilities>) -> Self {
926        self.jump = jump.into_option();
927        self
928    }
929
930    /// Sets or clears the optional `rename` field.
931    #[must_use]
932    pub fn rename(mut self, rename: impl IntoOption<NesRenameCapabilities>) -> Self {
933        self.rename = rename.into_option();
934        self
935    }
936
937    /// Sets or clears the optional `searchAndReplace` field.
938    #[must_use]
939    pub fn search_and_replace(
940        mut self,
941        search_and_replace: impl IntoOption<NesSearchAndReplaceCapabilities>,
942    ) -> Self {
943        self.search_and_replace = search_and_replace.into_option();
944        self
945    }
946
947    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
948    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
949    /// these keys.
950    ///
951    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
952    #[must_use]
953    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
954        self.meta = meta.into_option();
955        self
956    }
957}
958
959/// Marker for jump suggestion support.
960#[serde_as]
961#[skip_serializing_none]
962#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
963#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
964#[serde(rename_all = "camelCase")]
965#[non_exhaustive]
966pub struct NesJumpCapabilities {
967    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
968    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
969    /// these keys.
970    ///
971    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
972    #[serde_as(deserialize_as = "DefaultOnError")]
973    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
974    #[serde(default)]
975    #[serde(rename = "_meta")]
976    pub meta: Option<Meta>,
977}
978
979impl NesJumpCapabilities {
980    /// Builds an empty [`NesJumpCapabilities`]; use builder methods to advertise supported sub-capabilities.
981    #[must_use]
982    pub fn new() -> Self {
983        Self::default()
984    }
985}
986
987/// Marker for rename suggestion support.
988#[serde_as]
989#[skip_serializing_none]
990#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
991#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
992#[serde(rename_all = "camelCase")]
993#[non_exhaustive]
994pub struct NesRenameCapabilities {
995    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
996    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
997    /// these keys.
998    ///
999    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1000    #[serde_as(deserialize_as = "DefaultOnError")]
1001    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
1002    #[serde(default)]
1003    #[serde(rename = "_meta")]
1004    pub meta: Option<Meta>,
1005}
1006
1007impl NesRenameCapabilities {
1008    /// Builds an empty [`NesRenameCapabilities`]; use builder methods to advertise supported sub-capabilities.
1009    #[must_use]
1010    pub fn new() -> Self {
1011        Self::default()
1012    }
1013}
1014
1015/// Marker for search and replace suggestion support.
1016#[serde_as]
1017#[skip_serializing_none]
1018#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1019#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
1020#[serde(rename_all = "camelCase")]
1021#[non_exhaustive]
1022pub struct NesSearchAndReplaceCapabilities {
1023    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1024    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1025    /// these keys.
1026    ///
1027    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1028    #[serde_as(deserialize_as = "DefaultOnError")]
1029    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
1030    #[serde(default)]
1031    #[serde(rename = "_meta")]
1032    pub meta: Option<Meta>,
1033}
1034
1035impl NesSearchAndReplaceCapabilities {
1036    /// Builds an empty [`NesSearchAndReplaceCapabilities`]; use builder methods to advertise supported sub-capabilities.
1037    #[must_use]
1038    pub fn new() -> Self {
1039        Self::default()
1040    }
1041}
1042
1043// Document event notifications (client -> agent)
1044
1045/// Notification sent when a file is opened in the editor.
1046#[serde_as]
1047#[skip_serializing_none]
1048#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1049#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
1050#[cfg_attr(feature = "schemars", schemars(extend("x-side" = "agent", "x-method" = DOCUMENT_DID_OPEN_METHOD_NAME)))]
1051#[serde(rename_all = "camelCase")]
1052#[non_exhaustive]
1053pub struct DidOpenDocumentNotification {
1054    /// The session ID for this notification.
1055    pub session_id: SessionId,
1056    /// The URI of the opened document.
1057    #[cfg_attr(feature = "schemars", schemars(url))]
1058    pub uri: String,
1059    /// The language identifier of the document (e.g., "rust", "python").
1060    pub language_id: String,
1061    /// The version number of the document.
1062    pub version: i64,
1063    /// The full text content of the document.
1064    pub text: String,
1065    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1066    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1067    /// these keys.
1068    ///
1069    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1070    #[serde_as(deserialize_as = "DefaultOnError")]
1071    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
1072    #[serde(default)]
1073    #[serde(rename = "_meta")]
1074    pub meta: Option<Meta>,
1075}
1076
1077impl DidOpenDocumentNotification {
1078    /// Builds [`DidOpenDocumentNotification`] with the required notification fields set; optional fields start unset or empty.
1079    #[must_use]
1080    pub fn new(
1081        session_id: impl Into<SessionId>,
1082        uri: impl Into<String>,
1083        language_id: impl Into<String>,
1084        version: i64,
1085        text: impl Into<String>,
1086    ) -> Self {
1087        Self {
1088            session_id: session_id.into(),
1089            uri: uri.into(),
1090            language_id: language_id.into(),
1091            version,
1092            text: text.into(),
1093            meta: None,
1094        }
1095    }
1096
1097    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1098    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1099    /// these keys.
1100    ///
1101    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1102    #[must_use]
1103    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1104        self.meta = meta.into_option();
1105        self
1106    }
1107}
1108
1109/// Notification sent when a file is edited.
1110#[serde_as]
1111#[skip_serializing_none]
1112#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1113#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
1114#[cfg_attr(feature = "schemars", schemars(extend("x-side" = "agent", "x-method" = DOCUMENT_DID_CHANGE_METHOD_NAME)))]
1115#[serde(rename_all = "camelCase")]
1116#[non_exhaustive]
1117pub struct DidChangeDocumentNotification {
1118    /// The session ID for this notification.
1119    pub session_id: SessionId,
1120    /// The URI of the changed document.
1121    #[cfg_attr(feature = "schemars", schemars(url))]
1122    pub uri: String,
1123    /// The new version number of the document.
1124    pub version: i64,
1125    /// The content changes.
1126    #[serde_as(deserialize_as = "DefaultOnNull")]
1127    pub content_changes: Vec<TextDocumentContentChangeEvent>,
1128    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1129    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1130    /// these keys.
1131    ///
1132    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1133    #[serde_as(deserialize_as = "DefaultOnError")]
1134    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
1135    #[serde(default)]
1136    #[serde(rename = "_meta")]
1137    pub meta: Option<Meta>,
1138}
1139
1140impl DidChangeDocumentNotification {
1141    /// Builds [`DidChangeDocumentNotification`] with the required notification fields set; optional fields start unset or empty.
1142    #[must_use]
1143    pub fn new(
1144        session_id: impl Into<SessionId>,
1145        uri: impl Into<String>,
1146        version: i64,
1147        content_changes: Vec<TextDocumentContentChangeEvent>,
1148    ) -> Self {
1149        Self {
1150            session_id: session_id.into(),
1151            uri: uri.into(),
1152            version,
1153            content_changes,
1154            meta: None,
1155        }
1156    }
1157
1158    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1159    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1160    /// these keys.
1161    ///
1162    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1163    #[must_use]
1164    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1165        self.meta = meta.into_option();
1166        self
1167    }
1168}
1169
1170/// A content change event for a document.
1171///
1172/// When `range` is `None`, `text` is the full content of the document.
1173/// When `range` is `Some`, `text` replaces the given range.
1174#[serde_as]
1175#[skip_serializing_none]
1176#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1177#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
1178#[serde(rename_all = "camelCase")]
1179#[non_exhaustive]
1180pub struct TextDocumentContentChangeEvent {
1181    /// The range of the document that changed. If `None`, the entire content is replaced.
1182    #[serde(default)]
1183    pub range: Option<Range>,
1184    /// The new text for the range, or the full document content if `range` is `None`.
1185    pub text: String,
1186    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1187    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1188    /// these keys.
1189    ///
1190    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1191    #[serde_as(deserialize_as = "DefaultOnError")]
1192    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
1193    #[serde(default)]
1194    #[serde(rename = "_meta")]
1195    pub meta: Option<Meta>,
1196}
1197
1198impl TextDocumentContentChangeEvent {
1199    /// Builds a full-document change event that replaces the entire document text.
1200    #[must_use]
1201    pub fn full(text: impl Into<String>) -> Self {
1202        Self {
1203            range: None,
1204            text: text.into(),
1205            meta: None,
1206        }
1207    }
1208
1209    /// Builds an incremental document change event for a specific text range.
1210    #[must_use]
1211    pub fn incremental(range: Range, text: impl Into<String>) -> Self {
1212        Self {
1213            range: Some(range),
1214            text: text.into(),
1215            meta: None,
1216        }
1217    }
1218
1219    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1220    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1221    /// these keys.
1222    ///
1223    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1224    #[must_use]
1225    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1226        self.meta = meta.into_option();
1227        self
1228    }
1229}
1230
1231/// Notification sent when a file is closed.
1232#[serde_as]
1233#[skip_serializing_none]
1234#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1235#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
1236#[cfg_attr(feature = "schemars", schemars(extend("x-side" = "agent", "x-method" = DOCUMENT_DID_CLOSE_METHOD_NAME)))]
1237#[serde(rename_all = "camelCase")]
1238#[non_exhaustive]
1239pub struct DidCloseDocumentNotification {
1240    /// The session ID for this notification.
1241    pub session_id: SessionId,
1242    /// The URI of the closed document.
1243    #[cfg_attr(feature = "schemars", schemars(url))]
1244    pub uri: String,
1245    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1246    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1247    /// these keys.
1248    ///
1249    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1250    #[serde_as(deserialize_as = "DefaultOnError")]
1251    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
1252    #[serde(default)]
1253    #[serde(rename = "_meta")]
1254    pub meta: Option<Meta>,
1255}
1256
1257impl DidCloseDocumentNotification {
1258    /// Builds [`DidCloseDocumentNotification`] with the required notification fields set; optional fields start unset or empty.
1259    #[must_use]
1260    pub fn new(session_id: impl Into<SessionId>, uri: impl Into<String>) -> Self {
1261        Self {
1262            session_id: session_id.into(),
1263            uri: uri.into(),
1264            meta: None,
1265        }
1266    }
1267
1268    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1269    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1270    /// these keys.
1271    ///
1272    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1273    #[must_use]
1274    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1275        self.meta = meta.into_option();
1276        self
1277    }
1278}
1279
1280/// Notification sent when a file is saved.
1281#[serde_as]
1282#[skip_serializing_none]
1283#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1284#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
1285#[cfg_attr(feature = "schemars", schemars(extend("x-side" = "agent", "x-method" = DOCUMENT_DID_SAVE_METHOD_NAME)))]
1286#[serde(rename_all = "camelCase")]
1287#[non_exhaustive]
1288pub struct DidSaveDocumentNotification {
1289    /// The session ID for this notification.
1290    pub session_id: SessionId,
1291    /// The URI of the saved document.
1292    #[cfg_attr(feature = "schemars", schemars(url))]
1293    pub uri: String,
1294    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1295    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1296    /// these keys.
1297    ///
1298    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1299    #[serde_as(deserialize_as = "DefaultOnError")]
1300    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
1301    #[serde(default)]
1302    #[serde(rename = "_meta")]
1303    pub meta: Option<Meta>,
1304}
1305
1306impl DidSaveDocumentNotification {
1307    /// Builds [`DidSaveDocumentNotification`] with the required notification fields set; optional fields start unset or empty.
1308    #[must_use]
1309    pub fn new(session_id: impl Into<SessionId>, uri: impl Into<String>) -> Self {
1310        Self {
1311            session_id: session_id.into(),
1312            uri: uri.into(),
1313            meta: None,
1314        }
1315    }
1316
1317    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1318    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1319    /// these keys.
1320    ///
1321    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1322    #[must_use]
1323    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1324        self.meta = meta.into_option();
1325        self
1326    }
1327}
1328
1329/// Notification sent when a file becomes the active editor tab.
1330#[serde_as]
1331#[skip_serializing_none]
1332#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1333#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
1334#[cfg_attr(feature = "schemars", schemars(extend("x-side" = "agent", "x-method" = DOCUMENT_DID_FOCUS_METHOD_NAME)))]
1335#[serde(rename_all = "camelCase")]
1336#[non_exhaustive]
1337pub struct DidFocusDocumentNotification {
1338    /// The session ID for this notification.
1339    pub session_id: SessionId,
1340    /// The URI of the focused document.
1341    #[cfg_attr(feature = "schemars", schemars(url))]
1342    pub uri: String,
1343    /// The version number of the document.
1344    pub version: i64,
1345    /// The current cursor position.
1346    pub position: Position,
1347    /// The portion of the file currently visible in the editor viewport.
1348    pub visible_range: Range,
1349    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1350    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1351    /// these keys.
1352    ///
1353    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1354    #[serde_as(deserialize_as = "DefaultOnError")]
1355    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
1356    #[serde(default)]
1357    #[serde(rename = "_meta")]
1358    pub meta: Option<Meta>,
1359}
1360
1361impl DidFocusDocumentNotification {
1362    /// Builds [`DidFocusDocumentNotification`] with the required notification fields set; optional fields start unset or empty.
1363    #[must_use]
1364    pub fn new(
1365        session_id: impl Into<SessionId>,
1366        uri: impl Into<String>,
1367        version: i64,
1368        position: Position,
1369        visible_range: Range,
1370    ) -> Self {
1371        Self {
1372            session_id: session_id.into(),
1373            uri: uri.into(),
1374            version,
1375            position,
1376            visible_range,
1377            meta: None,
1378        }
1379    }
1380
1381    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1382    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1383    /// these keys.
1384    ///
1385    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1386    #[must_use]
1387    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1388        self.meta = meta.into_option();
1389        self
1390    }
1391}
1392
1393// NES session start
1394
1395crate::serde_util::default_on_null! {
1396    /// Request to start an NES session.
1397    #[serde_as]
1398    #[skip_serializing_none]
1399    #[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1400    #[derive(Debug, Clone, Serialize, PartialEq, Eq)]
1401    #[cfg_attr(feature = "schemars", schemars(extend("x-side" = "agent", "x-method" = NES_START_METHOD_NAME)))]
1402    #[serde(rename_all = "camelCase")]
1403    #[non_exhaustive]
1404    pub struct StartNesRequest {
1405        /// The root URI of the workspace.
1406        #[serde_as(deserialize_as = "DefaultOnError")]
1407        #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
1408        #[cfg_attr(feature = "schemars", schemars(url))]
1409        #[serde(default)]
1410        pub workspace_uri: Option<String>,
1411        /// The workspace folders.
1412        #[serde(default)]
1413        pub workspace_folders: Option<Vec<WorkspaceFolder>>,
1414        /// Repository metadata, if the workspace is a git repository.
1415        #[serde_as(deserialize_as = "DefaultOnError")]
1416        #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
1417        #[serde(default)]
1418        pub repository: Option<NesRepository>,
1419        /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1420        /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1421        /// these keys.
1422        ///
1423        /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1424        #[serde_as(deserialize_as = "DefaultOnError")]
1425        #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
1426        #[serde(default)]
1427        #[serde(rename = "_meta")]
1428        pub meta: Option<Meta>,
1429    }
1430}
1431
1432impl StartNesRequest {
1433    /// Builds [`StartNesRequest`] with the required request fields set; optional fields start unset or empty.
1434    #[must_use]
1435    pub fn new() -> Self {
1436        Self {
1437            workspace_uri: None,
1438            workspace_folders: None,
1439            repository: None,
1440            meta: None,
1441        }
1442    }
1443
1444    /// Sets or clears the optional `workspaceUri` field.
1445    #[must_use]
1446    pub fn workspace_uri(mut self, workspace_uri: impl IntoOption<String>) -> Self {
1447        self.workspace_uri = workspace_uri.into_option();
1448        self
1449    }
1450
1451    /// Sets or clears the optional `workspaceFolders` field.
1452    #[must_use]
1453    pub fn workspace_folders(
1454        mut self,
1455        workspace_folders: impl IntoOption<Vec<WorkspaceFolder>>,
1456    ) -> Self {
1457        self.workspace_folders = workspace_folders.into_option();
1458        self
1459    }
1460
1461    /// Sets or clears the optional `repository` field.
1462    #[must_use]
1463    pub fn repository(mut self, repository: impl IntoOption<NesRepository>) -> Self {
1464        self.repository = repository.into_option();
1465        self
1466    }
1467
1468    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1469    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1470    /// these keys.
1471    ///
1472    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1473    #[must_use]
1474    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1475        self.meta = meta.into_option();
1476        self
1477    }
1478}
1479
1480impl Default for StartNesRequest {
1481    fn default() -> Self {
1482        Self::new()
1483    }
1484}
1485
1486/// A workspace folder.
1487#[serde_as]
1488#[skip_serializing_none]
1489#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1490#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
1491#[serde(rename_all = "camelCase")]
1492#[non_exhaustive]
1493pub struct WorkspaceFolder {
1494    /// The URI of the folder.
1495    #[cfg_attr(feature = "schemars", schemars(url))]
1496    pub uri: String,
1497    /// The display name of the folder.
1498    pub name: String,
1499    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1500    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1501    /// these keys.
1502    ///
1503    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1504    #[serde_as(deserialize_as = "DefaultOnError")]
1505    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
1506    #[serde(default)]
1507    #[serde(rename = "_meta")]
1508    pub meta: Option<Meta>,
1509}
1510
1511impl WorkspaceFolder {
1512    /// Builds [`WorkspaceFolder`] with the required fields set; optional fields start unset or empty.
1513    #[must_use]
1514    pub fn new(uri: impl Into<String>, name: impl Into<String>) -> Self {
1515        Self {
1516            uri: uri.into(),
1517            name: name.into(),
1518            meta: None,
1519        }
1520    }
1521
1522    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1523    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1524    /// these keys.
1525    ///
1526    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1527    #[must_use]
1528    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1529        self.meta = meta.into_option();
1530        self
1531    }
1532}
1533
1534/// Repository metadata for an NES session.
1535#[serde_as]
1536#[skip_serializing_none]
1537#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1538#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
1539#[serde(rename_all = "camelCase")]
1540#[non_exhaustive]
1541pub struct NesRepository {
1542    /// The repository name.
1543    pub name: String,
1544    /// The repository owner.
1545    pub owner: String,
1546    /// The remote URL of the repository.
1547    pub remote_url: String,
1548    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1549    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1550    /// these keys.
1551    ///
1552    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1553    #[serde_as(deserialize_as = "DefaultOnError")]
1554    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
1555    #[serde(default)]
1556    #[serde(rename = "_meta")]
1557    pub meta: Option<Meta>,
1558}
1559
1560impl NesRepository {
1561    /// Builds [`NesRepository`] with the required fields set; optional fields start unset or empty.
1562    #[must_use]
1563    pub fn new(
1564        name: impl Into<String>,
1565        owner: impl Into<String>,
1566        remote_url: impl Into<String>,
1567    ) -> Self {
1568        Self {
1569            name: name.into(),
1570            owner: owner.into(),
1571            remote_url: remote_url.into(),
1572            meta: None,
1573        }
1574    }
1575
1576    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1577    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1578    /// these keys.
1579    ///
1580    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1581    #[must_use]
1582    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1583        self.meta = meta.into_option();
1584        self
1585    }
1586}
1587
1588/// Response to `nes/start`.
1589#[serde_as]
1590#[skip_serializing_none]
1591#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1592#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
1593#[cfg_attr(feature = "schemars", schemars(extend("x-side" = "agent", "x-method" = NES_START_METHOD_NAME)))]
1594#[serde(rename_all = "camelCase")]
1595#[non_exhaustive]
1596pub struct StartNesResponse {
1597    /// The session ID for the newly started NES session.
1598    pub session_id: SessionId,
1599    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1600    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1601    /// these keys.
1602    ///
1603    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1604    #[serde_as(deserialize_as = "DefaultOnError")]
1605    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
1606    #[serde(default)]
1607    #[serde(rename = "_meta")]
1608    pub meta: Option<Meta>,
1609}
1610
1611impl StartNesResponse {
1612    /// Builds [`StartNesResponse`] with the required response fields set; optional fields start unset or empty.
1613    #[must_use]
1614    pub fn new(session_id: impl Into<SessionId>) -> Self {
1615        Self {
1616            session_id: session_id.into(),
1617            meta: None,
1618        }
1619    }
1620
1621    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1622    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1623    /// these keys.
1624    ///
1625    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1626    #[must_use]
1627    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1628        self.meta = meta.into_option();
1629        self
1630    }
1631}
1632
1633// NES session close
1634
1635/// Request to close an NES session.
1636///
1637/// The agent **must** cancel any ongoing work related to the NES session
1638/// and then free up any resources associated with the session.
1639#[serde_as]
1640#[skip_serializing_none]
1641#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1642#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
1643#[cfg_attr(feature = "schemars", schemars(extend("x-side" = "agent", "x-method" = NES_CLOSE_METHOD_NAME)))]
1644#[serde(rename_all = "camelCase")]
1645#[non_exhaustive]
1646pub struct CloseNesRequest {
1647    /// The ID of the NES session to close.
1648    pub session_id: SessionId,
1649    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1650    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1651    /// these keys.
1652    ///
1653    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1654    #[serde_as(deserialize_as = "DefaultOnError")]
1655    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
1656    #[serde(default)]
1657    #[serde(rename = "_meta")]
1658    pub meta: Option<Meta>,
1659}
1660
1661impl CloseNesRequest {
1662    /// Builds [`CloseNesRequest`] with the required request fields set; optional fields start unset or empty.
1663    #[must_use]
1664    pub fn new(session_id: impl Into<SessionId>) -> Self {
1665        Self {
1666            session_id: session_id.into(),
1667            meta: None,
1668        }
1669    }
1670
1671    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1672    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1673    /// these keys.
1674    ///
1675    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1676    #[must_use]
1677    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1678        self.meta = meta.into_option();
1679        self
1680    }
1681}
1682
1683crate::serde_util::default_on_null! {
1684    /// Response from closing an NES session.
1685    #[serde_as]
1686    #[skip_serializing_none]
1687    #[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1688    #[derive(Default, Debug, Clone, Serialize, PartialEq, Eq)]
1689    #[cfg_attr(feature = "schemars", schemars(extend("x-side" = "agent", "x-method" = NES_CLOSE_METHOD_NAME)))]
1690    #[serde(rename_all = "camelCase")]
1691    #[non_exhaustive]
1692    pub struct CloseNesResponse {
1693        /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1694        /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1695        /// these keys.
1696        ///
1697        /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1698        #[serde_as(deserialize_as = "DefaultOnError")]
1699        #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
1700        #[serde(default)]
1701        #[serde(rename = "_meta")]
1702        pub meta: Option<Meta>,
1703    }
1704}
1705
1706impl CloseNesResponse {
1707    /// Builds [`CloseNesResponse`] with the required response fields set; optional fields start unset or empty.
1708    #[must_use]
1709    pub fn new() -> Self {
1710        Self::default()
1711    }
1712
1713    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1714    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1715    /// these keys.
1716    ///
1717    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1718    #[must_use]
1719    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1720        self.meta = meta.into_option();
1721        self
1722    }
1723}
1724
1725// NES suggest request
1726
1727/// What triggered the suggestion request.
1728#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1729#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
1730#[non_exhaustive]
1731pub enum NesTriggerKind {
1732    /// Triggered by user typing or cursor movement.
1733    #[serde(rename = "automatic")]
1734    Automatic,
1735    /// Triggered by a diagnostic appearing at or near the cursor.
1736    #[serde(rename = "diagnostic")]
1737    Diagnostic,
1738    /// Triggered by an explicit user action (keyboard shortcut).
1739    #[serde(rename = "manual")]
1740    Manual,
1741    /// Custom or future suggestion trigger kind.
1742    ///
1743    /// Values beginning with `_` are reserved for implementation-specific
1744    /// extensions. Unknown values that do not begin with `_` are reserved for
1745    /// future ACP variants.
1746    #[serde(untagged)]
1747    Other(String),
1748}
1749
1750/// Request for a code suggestion.
1751#[serde_as]
1752#[skip_serializing_none]
1753#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1754#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
1755#[cfg_attr(feature = "schemars", schemars(extend("x-side" = "agent", "x-method" = NES_SUGGEST_METHOD_NAME)))]
1756#[serde(rename_all = "camelCase")]
1757#[non_exhaustive]
1758pub struct SuggestNesRequest {
1759    /// The session ID for this request.
1760    pub session_id: SessionId,
1761    /// The URI of the document to suggest for.
1762    #[cfg_attr(feature = "schemars", schemars(url))]
1763    pub uri: String,
1764    /// The version number of the document.
1765    pub version: i64,
1766    /// The current cursor position.
1767    pub position: Position,
1768    /// The current text selection range, if any.
1769    #[serde(default)]
1770    pub selection: Option<Range>,
1771    /// What triggered this suggestion request.
1772    pub trigger_kind: NesTriggerKind,
1773    /// Context for the suggestion, included based on agent capabilities.
1774    #[serde(default)]
1775    pub context: Option<NesSuggestContext>,
1776    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1777    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1778    /// these keys.
1779    ///
1780    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1781    #[serde_as(deserialize_as = "DefaultOnError")]
1782    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
1783    #[serde(default)]
1784    #[serde(rename = "_meta")]
1785    pub meta: Option<Meta>,
1786}
1787
1788impl SuggestNesRequest {
1789    /// Builds [`SuggestNesRequest`] with the required request fields set; optional fields start unset or empty.
1790    #[must_use]
1791    pub fn new(
1792        session_id: impl Into<SessionId>,
1793        uri: impl Into<String>,
1794        version: i64,
1795        position: Position,
1796        trigger_kind: NesTriggerKind,
1797    ) -> Self {
1798        Self {
1799            session_id: session_id.into(),
1800            uri: uri.into(),
1801            version,
1802            position,
1803            selection: None,
1804            trigger_kind,
1805            context: None,
1806            meta: None,
1807        }
1808    }
1809
1810    /// Sets or clears the optional `selection` field.
1811    #[must_use]
1812    pub fn selection(mut self, selection: impl IntoOption<Range>) -> Self {
1813        self.selection = selection.into_option();
1814        self
1815    }
1816
1817    /// Sets or clears the optional `context` field.
1818    #[must_use]
1819    pub fn context(mut self, context: impl IntoOption<NesSuggestContext>) -> Self {
1820        self.context = context.into_option();
1821        self
1822    }
1823
1824    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1825    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1826    /// these keys.
1827    ///
1828    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1829    #[must_use]
1830    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1831        self.meta = meta.into_option();
1832        self
1833    }
1834}
1835
1836/// Context attached to a suggestion request.
1837#[serde_as]
1838#[skip_serializing_none]
1839#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1840#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
1841#[serde(rename_all = "camelCase")]
1842#[non_exhaustive]
1843pub struct NesSuggestContext {
1844    /// Recently accessed files.
1845    #[serde(default)]
1846    pub recent_files: Option<Vec<NesRecentFile>>,
1847    /// Related code snippets.
1848    #[serde(default)]
1849    pub related_snippets: Option<Vec<NesRelatedSnippet>>,
1850    /// Recent edit history.
1851    #[serde(default)]
1852    pub edit_history: Option<Vec<NesEditHistoryEntry>>,
1853    /// Recent user actions (typing, navigation, etc.).
1854    #[serde(default)]
1855    pub user_actions: Option<Vec<NesUserAction>>,
1856    /// Currently open files in the editor.
1857    #[serde(default)]
1858    pub open_files: Option<Vec<NesOpenFile>>,
1859    /// Current diagnostics (errors, warnings).
1860    #[serde(default)]
1861    pub diagnostics: Option<Vec<NesDiagnostic>>,
1862    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1863    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1864    /// these keys.
1865    ///
1866    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1867    #[serde_as(deserialize_as = "DefaultOnError")]
1868    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
1869    #[serde(default)]
1870    #[serde(rename = "_meta")]
1871    pub meta: Option<Meta>,
1872}
1873
1874impl NesSuggestContext {
1875    /// Builds [`NesSuggestContext`] with the required fields set; optional fields start unset or empty.
1876    #[must_use]
1877    pub fn new() -> Self {
1878        Self::default()
1879    }
1880
1881    /// Sets or clears the optional `recentFiles` field.
1882    #[must_use]
1883    pub fn recent_files(mut self, recent_files: impl IntoOption<Vec<NesRecentFile>>) -> Self {
1884        self.recent_files = recent_files.into_option();
1885        self
1886    }
1887
1888    /// Sets or clears the optional `relatedSnippets` field.
1889    #[must_use]
1890    pub fn related_snippets(
1891        mut self,
1892        related_snippets: impl IntoOption<Vec<NesRelatedSnippet>>,
1893    ) -> Self {
1894        self.related_snippets = related_snippets.into_option();
1895        self
1896    }
1897
1898    /// Sets or clears the optional `editHistory` field.
1899    #[must_use]
1900    pub fn edit_history(mut self, edit_history: impl IntoOption<Vec<NesEditHistoryEntry>>) -> Self {
1901        self.edit_history = edit_history.into_option();
1902        self
1903    }
1904
1905    /// Sets or clears the optional `userActions` field.
1906    #[must_use]
1907    pub fn user_actions(mut self, user_actions: impl IntoOption<Vec<NesUserAction>>) -> Self {
1908        self.user_actions = user_actions.into_option();
1909        self
1910    }
1911
1912    /// Sets or clears the optional `openFiles` field.
1913    #[must_use]
1914    pub fn open_files(mut self, open_files: impl IntoOption<Vec<NesOpenFile>>) -> Self {
1915        self.open_files = open_files.into_option();
1916        self
1917    }
1918
1919    /// Sets or clears the optional `diagnostics` field.
1920    #[must_use]
1921    pub fn diagnostics(mut self, diagnostics: impl IntoOption<Vec<NesDiagnostic>>) -> Self {
1922        self.diagnostics = diagnostics.into_option();
1923        self
1924    }
1925
1926    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1927    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1928    /// these keys.
1929    ///
1930    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1931    #[must_use]
1932    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1933        self.meta = meta.into_option();
1934        self
1935    }
1936}
1937
1938/// A recently accessed file.
1939#[serde_as]
1940#[skip_serializing_none]
1941#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1942#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
1943#[serde(rename_all = "camelCase")]
1944#[non_exhaustive]
1945pub struct NesRecentFile {
1946    /// The URI of the file.
1947    #[cfg_attr(feature = "schemars", schemars(url))]
1948    pub uri: String,
1949    /// The language identifier.
1950    pub language_id: String,
1951    /// The full text content of the file.
1952    pub text: String,
1953    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1954    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1955    /// these keys.
1956    ///
1957    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1958    #[serde_as(deserialize_as = "DefaultOnError")]
1959    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
1960    #[serde(default)]
1961    #[serde(rename = "_meta")]
1962    pub meta: Option<Meta>,
1963}
1964
1965impl NesRecentFile {
1966    /// Builds [`NesRecentFile`] with the required fields set; optional fields start unset or empty.
1967    #[must_use]
1968    pub fn new(
1969        uri: impl Into<String>,
1970        language_id: impl Into<String>,
1971        text: impl Into<String>,
1972    ) -> Self {
1973        Self {
1974            uri: uri.into(),
1975            language_id: language_id.into(),
1976            text: text.into(),
1977            meta: None,
1978        }
1979    }
1980
1981    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
1982    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
1983    /// these keys.
1984    ///
1985    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
1986    #[must_use]
1987    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
1988        self.meta = meta.into_option();
1989        self
1990    }
1991}
1992
1993/// A related code snippet from a file.
1994#[serde_as]
1995#[skip_serializing_none]
1996#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
1997#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
1998#[serde(rename_all = "camelCase")]
1999#[non_exhaustive]
2000pub struct NesRelatedSnippet {
2001    /// The URI of the file containing the snippets.
2002    #[cfg_attr(feature = "schemars", schemars(url))]
2003    pub uri: String,
2004    /// The code excerpts.
2005    pub excerpts: Vec<NesExcerpt>,
2006    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
2007    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
2008    /// these keys.
2009    ///
2010    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
2011    #[serde_as(deserialize_as = "DefaultOnError")]
2012    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
2013    #[serde(default)]
2014    #[serde(rename = "_meta")]
2015    pub meta: Option<Meta>,
2016}
2017
2018impl NesRelatedSnippet {
2019    /// Builds [`NesRelatedSnippet`] with the required fields set; optional fields start unset or empty.
2020    #[must_use]
2021    pub fn new(uri: impl Into<String>, excerpts: Vec<NesExcerpt>) -> Self {
2022        Self {
2023            uri: uri.into(),
2024            excerpts,
2025            meta: None,
2026        }
2027    }
2028
2029    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
2030    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
2031    /// these keys.
2032    ///
2033    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
2034    #[must_use]
2035    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2036        self.meta = meta.into_option();
2037        self
2038    }
2039}
2040
2041/// A code excerpt from a file.
2042#[serde_as]
2043#[skip_serializing_none]
2044#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2045#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
2046#[serde(rename_all = "camelCase")]
2047#[non_exhaustive]
2048pub struct NesExcerpt {
2049    /// The start line of the excerpt (zero-based).
2050    pub start_line: u32,
2051    /// The end line of the excerpt (zero-based).
2052    pub end_line: u32,
2053    /// The text content of the excerpt.
2054    pub text: String,
2055    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
2056    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
2057    /// these keys.
2058    ///
2059    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
2060    #[serde_as(deserialize_as = "DefaultOnError")]
2061    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
2062    #[serde(default)]
2063    #[serde(rename = "_meta")]
2064    pub meta: Option<Meta>,
2065}
2066
2067impl NesExcerpt {
2068    /// Builds [`NesExcerpt`] with the required fields set; optional fields start unset or empty.
2069    #[must_use]
2070    pub fn new(start_line: u32, end_line: u32, text: impl Into<String>) -> Self {
2071        Self {
2072            start_line,
2073            end_line,
2074            text: text.into(),
2075            meta: None,
2076        }
2077    }
2078
2079    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
2080    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
2081    /// these keys.
2082    ///
2083    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
2084    #[must_use]
2085    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2086        self.meta = meta.into_option();
2087        self
2088    }
2089}
2090
2091/// An entry in the edit history.
2092#[serde_as]
2093#[skip_serializing_none]
2094#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2095#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
2096#[serde(rename_all = "camelCase")]
2097#[non_exhaustive]
2098pub struct NesEditHistoryEntry {
2099    /// The URI of the edited file.
2100    #[cfg_attr(feature = "schemars", schemars(url))]
2101    pub uri: String,
2102    /// A diff representing the edit.
2103    pub diff: String,
2104    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
2105    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
2106    /// these keys.
2107    ///
2108    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
2109    #[serde_as(deserialize_as = "DefaultOnError")]
2110    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
2111    #[serde(default)]
2112    #[serde(rename = "_meta")]
2113    pub meta: Option<Meta>,
2114}
2115
2116impl NesEditHistoryEntry {
2117    /// Builds [`NesEditHistoryEntry`] with the required fields set; optional fields start unset or empty.
2118    #[must_use]
2119    pub fn new(uri: impl Into<String>, diff: impl Into<String>) -> Self {
2120        Self {
2121            uri: uri.into(),
2122            diff: diff.into(),
2123            meta: None,
2124        }
2125    }
2126
2127    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
2128    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
2129    /// these keys.
2130    ///
2131    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
2132    #[must_use]
2133    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2134        self.meta = meta.into_option();
2135        self
2136    }
2137}
2138
2139/// A user action (typing, cursor movement, etc.).
2140#[serde_as]
2141#[skip_serializing_none]
2142#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2143#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
2144#[serde(rename_all = "camelCase")]
2145#[non_exhaustive]
2146pub struct NesUserAction {
2147    /// The kind of action (e.g., "insertChar", "cursorMovement").
2148    pub action: String,
2149    /// The URI of the file where the action occurred.
2150    #[cfg_attr(feature = "schemars", schemars(url))]
2151    pub uri: String,
2152    /// The position where the action occurred.
2153    pub position: Position,
2154    /// Timestamp in milliseconds since epoch.
2155    pub timestamp_ms: u64,
2156    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
2157    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
2158    /// these keys.
2159    ///
2160    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
2161    #[serde_as(deserialize_as = "DefaultOnError")]
2162    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
2163    #[serde(default)]
2164    #[serde(rename = "_meta")]
2165    pub meta: Option<Meta>,
2166}
2167
2168impl NesUserAction {
2169    /// Builds [`NesUserAction`] with the required fields set; optional fields start unset or empty.
2170    #[must_use]
2171    pub fn new(
2172        action: impl Into<String>,
2173        uri: impl Into<String>,
2174        position: Position,
2175        timestamp_ms: u64,
2176    ) -> Self {
2177        Self {
2178            action: action.into(),
2179            uri: uri.into(),
2180            position,
2181            timestamp_ms,
2182            meta: None,
2183        }
2184    }
2185
2186    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
2187    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
2188    /// these keys.
2189    ///
2190    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
2191    #[must_use]
2192    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2193        self.meta = meta.into_option();
2194        self
2195    }
2196}
2197
2198/// An open file in the editor.
2199#[serde_as]
2200#[skip_serializing_none]
2201#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2202#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
2203#[serde(rename_all = "camelCase")]
2204#[non_exhaustive]
2205pub struct NesOpenFile {
2206    /// The URI of the file.
2207    #[cfg_attr(feature = "schemars", schemars(url))]
2208    pub uri: String,
2209    /// The language identifier.
2210    pub language_id: String,
2211    /// The visible range in the editor, if any.
2212    #[serde_as(deserialize_as = "DefaultOnError")]
2213    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
2214    #[serde(default)]
2215    pub visible_range: Option<Range>,
2216    /// Timestamp in milliseconds since epoch of when the file was last focused.
2217    #[serde_as(deserialize_as = "DefaultOnError")]
2218    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
2219    #[serde(default)]
2220    pub last_focused_ms: Option<u64>,
2221    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
2222    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
2223    /// these keys.
2224    ///
2225    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
2226    #[serde_as(deserialize_as = "DefaultOnError")]
2227    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
2228    #[serde(default)]
2229    #[serde(rename = "_meta")]
2230    pub meta: Option<Meta>,
2231}
2232
2233impl NesOpenFile {
2234    /// Builds [`NesOpenFile`] with the required fields set; optional fields start unset or empty.
2235    #[must_use]
2236    pub fn new(uri: impl Into<String>, language_id: impl Into<String>) -> Self {
2237        Self {
2238            uri: uri.into(),
2239            language_id: language_id.into(),
2240            visible_range: None,
2241            last_focused_ms: None,
2242            meta: None,
2243        }
2244    }
2245
2246    /// Sets or clears the optional `visibleRange` field.
2247    #[must_use]
2248    pub fn visible_range(mut self, visible_range: impl IntoOption<Range>) -> Self {
2249        self.visible_range = visible_range.into_option();
2250        self
2251    }
2252
2253    /// Sets or clears the optional `lastFocusedMs` field.
2254    #[must_use]
2255    pub fn last_focused_ms(mut self, last_focused_ms: impl IntoOption<u64>) -> Self {
2256        self.last_focused_ms = last_focused_ms.into_option();
2257        self
2258    }
2259
2260    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
2261    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
2262    /// these keys.
2263    ///
2264    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
2265    #[must_use]
2266    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2267        self.meta = meta.into_option();
2268        self
2269    }
2270}
2271
2272/// A diagnostic (error, warning, etc.).
2273#[serde_as]
2274#[skip_serializing_none]
2275#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2276#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
2277#[serde(rename_all = "camelCase")]
2278#[non_exhaustive]
2279pub struct NesDiagnostic {
2280    /// The URI of the file containing the diagnostic.
2281    #[cfg_attr(feature = "schemars", schemars(url))]
2282    pub uri: String,
2283    /// The range of the diagnostic.
2284    pub range: Range,
2285    /// The severity of the diagnostic.
2286    pub severity: NesDiagnosticSeverity,
2287    /// The diagnostic message.
2288    pub message: String,
2289    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
2290    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
2291    /// these keys.
2292    ///
2293    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
2294    #[serde_as(deserialize_as = "DefaultOnError")]
2295    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
2296    #[serde(default)]
2297    #[serde(rename = "_meta")]
2298    pub meta: Option<Meta>,
2299}
2300
2301impl NesDiagnostic {
2302    /// Builds [`NesDiagnostic`] with the required fields set; optional fields start unset or empty.
2303    #[must_use]
2304    pub fn new(
2305        uri: impl Into<String>,
2306        range: Range,
2307        severity: NesDiagnosticSeverity,
2308        message: impl Into<String>,
2309    ) -> Self {
2310        Self {
2311            uri: uri.into(),
2312            range,
2313            severity,
2314            message: message.into(),
2315            meta: None,
2316        }
2317    }
2318
2319    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
2320    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
2321    /// these keys.
2322    ///
2323    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
2324    #[must_use]
2325    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2326        self.meta = meta.into_option();
2327        self
2328    }
2329}
2330
2331/// Severity of a diagnostic.
2332#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2333#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
2334#[non_exhaustive]
2335pub enum NesDiagnosticSeverity {
2336    /// An error.
2337    #[serde(rename = "error")]
2338    Error,
2339    /// A warning.
2340    #[serde(rename = "warning")]
2341    Warning,
2342    /// An informational message.
2343    #[serde(rename = "information")]
2344    Information,
2345    /// A hint.
2346    #[serde(rename = "hint")]
2347    Hint,
2348    /// Custom or future diagnostic severity.
2349    ///
2350    /// Values beginning with `_` are reserved for implementation-specific
2351    /// extensions. Unknown values that do not begin with `_` are reserved for
2352    /// future ACP variants.
2353    #[serde(untagged)]
2354    Other(String),
2355}
2356
2357// NES suggest response
2358
2359/// Response to `nes/suggest`.
2360#[serde_as]
2361#[skip_serializing_none]
2362#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2363#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
2364#[cfg_attr(feature = "schemars", schemars(extend("x-side" = "agent", "x-method" = NES_SUGGEST_METHOD_NAME)))]
2365#[serde(rename_all = "camelCase")]
2366#[non_exhaustive]
2367pub struct SuggestNesResponse {
2368    /// The list of suggestions.
2369    pub suggestions: Vec<NesSuggestion>,
2370    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
2371    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
2372    /// these keys.
2373    ///
2374    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
2375    #[serde_as(deserialize_as = "DefaultOnError")]
2376    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
2377    #[serde(default)]
2378    #[serde(rename = "_meta")]
2379    pub meta: Option<Meta>,
2380}
2381
2382impl SuggestNesResponse {
2383    /// Builds [`SuggestNesResponse`] with the required response fields set; optional fields start unset or empty.
2384    #[must_use]
2385    pub fn new(suggestions: Vec<NesSuggestion>) -> Self {
2386        Self {
2387            suggestions,
2388            meta: None,
2389        }
2390    }
2391
2392    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
2393    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
2394    /// these keys.
2395    ///
2396    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
2397    #[must_use]
2398    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2399        self.meta = meta.into_option();
2400        self
2401    }
2402}
2403
2404/// A suggestion returned by the agent.
2405#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2406#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
2407#[serde(tag = "kind", rename_all = "camelCase")]
2408#[non_exhaustive]
2409pub enum NesSuggestion {
2410    /// A text edit suggestion.
2411    Edit(NesEditSuggestion),
2412    /// A jump-to-location suggestion.
2413    Jump(NesJumpSuggestion),
2414    /// A rename symbol suggestion.
2415    Rename(NesRenameSuggestion),
2416    /// A search-and-replace suggestion.
2417    SearchAndReplace(NesSearchAndReplaceSuggestion),
2418    /// Custom or future NES suggestion.
2419    ///
2420    /// Values beginning with `_` are reserved for implementation-specific
2421    /// extensions. Unknown values that do not begin with `_` are reserved for
2422    /// future ACP variants.
2423    ///
2424    /// Receivers that do not understand this suggestion kind should preserve
2425    /// the raw payload when storing, replaying, proxying, or forwarding
2426    /// suggestions, and otherwise ignore it or display it generically.
2427    #[serde(untagged)]
2428    Other(OtherNesSuggestion),
2429}
2430
2431/// Custom or future NES suggestion payload.
2432#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2433#[derive(Debug, Clone, Serialize, PartialEq, Eq)]
2434#[cfg_attr(feature = "schemars", schemars(inline))]
2435#[cfg_attr(feature = "schemars", schemars(transform = other_nes_suggestion_schema))]
2436#[serde(rename_all = "camelCase")]
2437#[non_exhaustive]
2438pub struct OtherNesSuggestion {
2439    /// Custom or future NES suggestion kind.
2440    ///
2441    /// Values beginning with `_` are reserved for implementation-specific
2442    /// extensions. Unknown values that do not begin with `_` are reserved for
2443    /// future ACP variants.
2444    pub kind: String,
2445    /// Unique identifier for accept/reject tracking.
2446    pub suggestion_id: NesSuggestionId,
2447    /// Additional fields from the unknown NES suggestion payload.
2448    #[serde(flatten)]
2449    pub fields: BTreeMap<String, serde_json::Value>,
2450}
2451
2452impl OtherNesSuggestion {
2453    /// Builds [`OtherNesSuggestion`] from an unknown discriminator and preserves the remaining extension fields.
2454    #[must_use]
2455    pub fn new(
2456        kind: impl Into<String>,
2457        suggestion_id: impl Into<NesSuggestionId>,
2458        mut fields: BTreeMap<String, serde_json::Value>,
2459    ) -> Self {
2460        fields.remove("kind");
2461        fields.remove("suggestionId");
2462        Self {
2463            kind: kind.into(),
2464            suggestion_id: suggestion_id.into(),
2465            fields,
2466        }
2467    }
2468}
2469
2470impl<'de> Deserialize<'de> for OtherNesSuggestion {
2471    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
2472    where
2473        D: serde::Deserializer<'de>,
2474    {
2475        let mut fields = BTreeMap::<String, serde_json::Value>::deserialize(deserializer)?;
2476        let kind = fields
2477            .remove("kind")
2478            .ok_or_else(|| serde::de::Error::missing_field("kind"))?;
2479        let serde_json::Value::String(kind) = kind else {
2480            return Err(serde::de::Error::custom("`kind` must be a string"));
2481        };
2482        let suggestion_id = fields
2483            .remove("suggestionId")
2484            .ok_or_else(|| serde::de::Error::missing_field("suggestionId"))?;
2485        let serde_json::Value::String(suggestion_id) = suggestion_id else {
2486            return Err(serde::de::Error::custom("`suggestionId` must be a string"));
2487        };
2488
2489        if is_known_nes_suggestion_kind(&kind) {
2490            return Err(serde::de::Error::custom(format!(
2491                "known NES suggestion `{kind}` did not match its schema"
2492            )));
2493        }
2494
2495        Ok(Self {
2496            kind,
2497            suggestion_id: NesSuggestionId::new(suggestion_id),
2498            fields,
2499        })
2500    }
2501}
2502
2503fn is_known_nes_suggestion_kind(kind: &str) -> bool {
2504    matches!(kind, "edit" | "jump" | "rename" | "searchAndReplace")
2505}
2506
2507#[cfg(feature = "schemars")]
2508fn other_nes_suggestion_schema(schema: &mut Schema) {
2509    super::schema_util::reject_known_string_discriminators(
2510        schema,
2511        "kind",
2512        &["edit", "jump", "rename", "searchAndReplace"],
2513    );
2514}
2515
2516/// A text edit suggestion.
2517#[serde_as]
2518#[skip_serializing_none]
2519#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2520#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
2521#[serde(rename_all = "camelCase")]
2522#[non_exhaustive]
2523pub struct NesEditSuggestion {
2524    /// Unique identifier for accept/reject tracking.
2525    pub suggestion_id: NesSuggestionId,
2526    /// The URI of the file to edit.
2527    #[cfg_attr(feature = "schemars", schemars(url))]
2528    pub uri: String,
2529    /// The text edits to apply. Must contain at least one edit.
2530    #[cfg_attr(feature = "schemars", schemars(length(min = 1)))]
2531    pub edits: Vec<NesTextEdit>,
2532    /// Optional suggested cursor position after applying edits.
2533    #[serde_as(deserialize_as = "DefaultOnError")]
2534    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
2535    #[serde(default)]
2536    pub cursor_position: Option<Position>,
2537    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
2538    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
2539    /// these keys.
2540    ///
2541    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
2542    #[serde_as(deserialize_as = "DefaultOnError")]
2543    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
2544    #[serde(default)]
2545    #[serde(rename = "_meta")]
2546    pub meta: Option<Meta>,
2547}
2548
2549impl NesEditSuggestion {
2550    /// Builds [`NesEditSuggestion`] with the required fields set; optional fields start unset or empty.
2551    #[must_use]
2552    pub fn new(
2553        suggestion_id: impl Into<NesSuggestionId>,
2554        uri: impl Into<String>,
2555        edits: Vec<NesTextEdit>,
2556    ) -> Self {
2557        Self {
2558            suggestion_id: suggestion_id.into(),
2559            uri: uri.into(),
2560            edits,
2561            cursor_position: None,
2562            meta: None,
2563        }
2564    }
2565
2566    /// Sets or clears the optional `cursorPosition` field.
2567    #[must_use]
2568    pub fn cursor_position(mut self, cursor_position: impl IntoOption<Position>) -> Self {
2569        self.cursor_position = cursor_position.into_option();
2570        self
2571    }
2572
2573    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
2574    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
2575    /// these keys.
2576    ///
2577    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
2578    #[must_use]
2579    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2580        self.meta = meta.into_option();
2581        self
2582    }
2583}
2584
2585/// A text edit within a suggestion.
2586#[serde_as]
2587#[skip_serializing_none]
2588#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2589#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
2590#[serde(rename_all = "camelCase")]
2591#[non_exhaustive]
2592pub struct NesTextEdit {
2593    /// The range to replace.
2594    pub range: Range,
2595    /// The replacement text.
2596    pub new_text: String,
2597    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
2598    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
2599    /// these keys.
2600    ///
2601    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
2602    #[serde_as(deserialize_as = "DefaultOnError")]
2603    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
2604    #[serde(default)]
2605    #[serde(rename = "_meta")]
2606    pub meta: Option<Meta>,
2607}
2608
2609impl NesTextEdit {
2610    /// Builds [`NesTextEdit`] with the required fields set; optional fields start unset or empty.
2611    #[must_use]
2612    pub fn new(range: Range, new_text: impl Into<String>) -> Self {
2613        Self {
2614            range,
2615            new_text: new_text.into(),
2616            meta: None,
2617        }
2618    }
2619
2620    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
2621    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
2622    /// these keys.
2623    ///
2624    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
2625    #[must_use]
2626    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2627        self.meta = meta.into_option();
2628        self
2629    }
2630}
2631
2632/// A jump-to-location suggestion.
2633#[serde_as]
2634#[skip_serializing_none]
2635#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2636#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
2637#[serde(rename_all = "camelCase")]
2638#[non_exhaustive]
2639pub struct NesJumpSuggestion {
2640    /// Unique identifier for accept/reject tracking.
2641    pub suggestion_id: NesSuggestionId,
2642    /// The file to navigate to.
2643    #[cfg_attr(feature = "schemars", schemars(url))]
2644    pub uri: String,
2645    /// The target position within the file.
2646    pub position: Position,
2647    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
2648    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
2649    /// these keys.
2650    ///
2651    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
2652    #[serde_as(deserialize_as = "DefaultOnError")]
2653    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
2654    #[serde(default)]
2655    #[serde(rename = "_meta")]
2656    pub meta: Option<Meta>,
2657}
2658
2659impl NesJumpSuggestion {
2660    /// Builds [`NesJumpSuggestion`] with the required fields set; optional fields start unset or empty.
2661    #[must_use]
2662    pub fn new(
2663        suggestion_id: impl Into<NesSuggestionId>,
2664        uri: impl Into<String>,
2665        position: Position,
2666    ) -> Self {
2667        Self {
2668            suggestion_id: suggestion_id.into(),
2669            uri: uri.into(),
2670            position,
2671            meta: None,
2672        }
2673    }
2674
2675    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
2676    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
2677    /// these keys.
2678    ///
2679    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
2680    #[must_use]
2681    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2682        self.meta = meta.into_option();
2683        self
2684    }
2685}
2686
2687/// A rename symbol suggestion.
2688#[serde_as]
2689#[skip_serializing_none]
2690#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2691#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
2692#[serde(rename_all = "camelCase")]
2693#[non_exhaustive]
2694pub struct NesRenameSuggestion {
2695    /// Unique identifier for accept/reject tracking.
2696    pub suggestion_id: NesSuggestionId,
2697    /// The file URI containing the symbol.
2698    #[cfg_attr(feature = "schemars", schemars(url))]
2699    pub uri: String,
2700    /// The position of the symbol to rename.
2701    pub position: Position,
2702    /// The new name for the symbol.
2703    pub new_name: String,
2704    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
2705    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
2706    /// these keys.
2707    ///
2708    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
2709    #[serde_as(deserialize_as = "DefaultOnError")]
2710    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
2711    #[serde(default)]
2712    #[serde(rename = "_meta")]
2713    pub meta: Option<Meta>,
2714}
2715
2716impl NesRenameSuggestion {
2717    /// Builds [`NesRenameSuggestion`] with the required fields set; optional fields start unset or empty.
2718    #[must_use]
2719    pub fn new(
2720        suggestion_id: impl Into<NesSuggestionId>,
2721        uri: impl Into<String>,
2722        position: Position,
2723        new_name: impl Into<String>,
2724    ) -> Self {
2725        Self {
2726            suggestion_id: suggestion_id.into(),
2727            uri: uri.into(),
2728            position,
2729            new_name: new_name.into(),
2730            meta: None,
2731        }
2732    }
2733
2734    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
2735    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
2736    /// these keys.
2737    ///
2738    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
2739    #[must_use]
2740    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2741        self.meta = meta.into_option();
2742        self
2743    }
2744}
2745
2746/// A search-and-replace suggestion.
2747#[serde_as]
2748#[skip_serializing_none]
2749#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2750#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
2751#[serde(rename_all = "camelCase")]
2752#[non_exhaustive]
2753pub struct NesSearchAndReplaceSuggestion {
2754    /// Unique identifier for accept/reject tracking.
2755    pub suggestion_id: NesSuggestionId,
2756    /// The file URI to search within.
2757    #[cfg_attr(feature = "schemars", schemars(url))]
2758    pub uri: String,
2759    /// The text or pattern to find.
2760    pub search: String,
2761    /// The replacement text.
2762    pub replace: String,
2763    /// Whether `search` is a regular expression. Defaults to `false`.
2764    #[serde(default)]
2765    pub is_regex: Option<bool>,
2766    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
2767    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
2768    /// these keys.
2769    ///
2770    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
2771    #[serde_as(deserialize_as = "DefaultOnError")]
2772    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
2773    #[serde(default)]
2774    #[serde(rename = "_meta")]
2775    pub meta: Option<Meta>,
2776}
2777
2778impl NesSearchAndReplaceSuggestion {
2779    /// Builds [`NesSearchAndReplaceSuggestion`] with the required fields set; optional fields start unset or empty.
2780    #[must_use]
2781    pub fn new(
2782        suggestion_id: impl Into<NesSuggestionId>,
2783        uri: impl Into<String>,
2784        search: impl Into<String>,
2785        replace: impl Into<String>,
2786    ) -> Self {
2787        Self {
2788            suggestion_id: suggestion_id.into(),
2789            uri: uri.into(),
2790            search: search.into(),
2791            replace: replace.into(),
2792            is_regex: None,
2793            meta: None,
2794        }
2795    }
2796
2797    /// Sets or clears the optional `isRegex` field.
2798    #[must_use]
2799    pub fn is_regex(mut self, is_regex: impl IntoOption<bool>) -> Self {
2800        self.is_regex = is_regex.into_option();
2801        self
2802    }
2803
2804    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
2805    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
2806    /// these keys.
2807    ///
2808    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
2809    #[must_use]
2810    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2811        self.meta = meta.into_option();
2812        self
2813    }
2814}
2815
2816// NES accept/reject notifications
2817
2818/// Notification sent when a suggestion is accepted.
2819#[serde_as]
2820#[skip_serializing_none]
2821#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2822#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
2823#[cfg_attr(feature = "schemars", schemars(extend("x-side" = "agent", "x-method" = NES_ACCEPT_METHOD_NAME)))]
2824#[serde(rename_all = "camelCase")]
2825#[non_exhaustive]
2826pub struct AcceptNesNotification {
2827    /// The session ID for this notification.
2828    pub session_id: SessionId,
2829    /// The ID of the accepted suggestion.
2830    pub suggestion_id: NesSuggestionId,
2831    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
2832    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
2833    /// these keys.
2834    ///
2835    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
2836    #[serde_as(deserialize_as = "DefaultOnError")]
2837    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
2838    #[serde(default)]
2839    #[serde(rename = "_meta")]
2840    pub meta: Option<Meta>,
2841}
2842
2843impl AcceptNesNotification {
2844    /// Builds [`AcceptNesNotification`] with the required notification fields set; optional fields start unset or empty.
2845    #[must_use]
2846    pub fn new(
2847        session_id: impl Into<SessionId>,
2848        suggestion_id: impl Into<NesSuggestionId>,
2849    ) -> Self {
2850        Self {
2851            session_id: session_id.into(),
2852            suggestion_id: suggestion_id.into(),
2853            meta: None,
2854        }
2855    }
2856
2857    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
2858    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
2859    /// these keys.
2860    ///
2861    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
2862    #[must_use]
2863    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2864        self.meta = meta.into_option();
2865        self
2866    }
2867}
2868
2869/// Notification sent when a suggestion is rejected.
2870#[serde_as]
2871#[skip_serializing_none]
2872#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2873#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
2874#[cfg_attr(feature = "schemars", schemars(extend("x-side" = "agent", "x-method" = NES_REJECT_METHOD_NAME)))]
2875#[serde(rename_all = "camelCase")]
2876#[non_exhaustive]
2877pub struct RejectNesNotification {
2878    /// The session ID for this notification.
2879    pub session_id: SessionId,
2880    /// The ID of the rejected suggestion.
2881    pub suggestion_id: NesSuggestionId,
2882    /// The reason for rejection.
2883    #[serde_as(deserialize_as = "DefaultOnError")]
2884    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
2885    #[serde(default)]
2886    pub reason: Option<NesRejectReason>,
2887    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
2888    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
2889    /// these keys.
2890    ///
2891    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
2892    #[serde_as(deserialize_as = "DefaultOnError")]
2893    #[cfg_attr(feature = "schemars", schemars(extend("x-deserialize-default-on-error" = true)))]
2894    #[serde(default)]
2895    #[serde(rename = "_meta")]
2896    pub meta: Option<Meta>,
2897}
2898
2899impl RejectNesNotification {
2900    /// Builds [`RejectNesNotification`] with the required notification fields set; optional fields start unset or empty.
2901    #[must_use]
2902    pub fn new(
2903        session_id: impl Into<SessionId>,
2904        suggestion_id: impl Into<NesSuggestionId>,
2905    ) -> Self {
2906        Self {
2907            session_id: session_id.into(),
2908            suggestion_id: suggestion_id.into(),
2909            reason: None,
2910            meta: None,
2911        }
2912    }
2913
2914    /// Sets or clears the optional `reason` field.
2915    #[must_use]
2916    pub fn reason(mut self, reason: impl IntoOption<NesRejectReason>) -> Self {
2917        self.reason = reason.into_option();
2918        self
2919    }
2920
2921    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
2922    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
2923    /// these keys.
2924    ///
2925    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
2926    #[must_use]
2927    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2928        self.meta = meta.into_option();
2929        self
2930    }
2931}
2932
2933/// The reason a suggestion was rejected.
2934#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
2935#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
2936#[non_exhaustive]
2937pub enum NesRejectReason {
2938    /// The user explicitly dismissed the suggestion.
2939    #[serde(rename = "rejected")]
2940    Rejected,
2941    /// The suggestion was shown but the user continued editing without interacting.
2942    #[serde(rename = "ignored")]
2943    Ignored,
2944    /// The suggestion was superseded by a newer suggestion.
2945    #[serde(rename = "replaced")]
2946    Replaced,
2947    /// The request was cancelled before the agent returned a response.
2948    #[serde(rename = "cancelled")]
2949    Cancelled,
2950    /// Custom or future rejection reason.
2951    ///
2952    /// Values beginning with `_` are reserved for implementation-specific
2953    /// extensions. Unknown values that do not begin with `_` are reserved for
2954    /// future ACP variants.
2955    #[serde(untagged)]
2956    Other(String),
2957}
2958
2959#[cfg(test)]
2960mod tests {
2961    use super::*;
2962    use serde_json::json;
2963
2964    #[test]
2965    fn test_position_encoding_kind_serialization() {
2966        assert_eq!(
2967            serde_json::to_value(&PositionEncodingKind::Utf16).unwrap(),
2968            json!("utf-16")
2969        );
2970        assert_eq!(
2971            serde_json::to_value(&PositionEncodingKind::Utf32).unwrap(),
2972            json!("utf-32")
2973        );
2974        assert_eq!(
2975            serde_json::to_value(&PositionEncodingKind::Utf8).unwrap(),
2976            json!("utf-8")
2977        );
2978
2979        assert_eq!(
2980            serde_json::from_value::<PositionEncodingKind>(json!("utf-16")).unwrap(),
2981            PositionEncodingKind::Utf16
2982        );
2983        assert_eq!(
2984            serde_json::from_value::<PositionEncodingKind>(json!("utf-32")).unwrap(),
2985            PositionEncodingKind::Utf32
2986        );
2987        assert_eq!(
2988            serde_json::from_value::<PositionEncodingKind>(json!("utf-8")).unwrap(),
2989            PositionEncodingKind::Utf8
2990        );
2991        assert!(serde_json::from_value::<PositionEncodingKind>(json!("_future")).is_err());
2992    }
2993
2994    #[test]
2995    fn test_client_capabilities_skip_unknown_position_encodings() {
2996        let caps: crate::v2::ClientCapabilities = serde_json::from_value(json!({
2997            "positionEncodings": ["_future", "utf-8", "utf-16"]
2998        }))
2999        .unwrap();
3000
3001        assert_eq!(
3002            caps.position_encodings,
3003            vec![PositionEncodingKind::Utf8, PositionEncodingKind::Utf16]
3004        );
3005    }
3006
3007    #[test]
3008    fn test_agent_nes_capabilities_serialization() {
3009        let caps = NesCapabilities::new()
3010            .events(
3011                NesEventCapabilities::new().document(
3012                    NesDocumentEventCapabilities::new()
3013                        .did_open(NesDocumentDidOpenCapabilities::default())
3014                        .did_change(NesDocumentDidChangeCapabilities::new(
3015                            TextDocumentSyncKind::Incremental,
3016                        ))
3017                        .did_close(NesDocumentDidCloseCapabilities::default())
3018                        .did_save(NesDocumentDidSaveCapabilities::default())
3019                        .did_focus(NesDocumentDidFocusCapabilities::default()),
3020                ),
3021            )
3022            .context(
3023                NesContextCapabilities::new()
3024                    .recent_files(NesRecentFilesCapabilities {
3025                        max_count: Some(10),
3026                        meta: None,
3027                    })
3028                    .related_snippets(NesRelatedSnippetsCapabilities::default())
3029                    .edit_history(NesEditHistoryCapabilities {
3030                        max_count: Some(6),
3031                        meta: None,
3032                    })
3033                    .user_actions(NesUserActionsCapabilities {
3034                        max_count: Some(16),
3035                        meta: None,
3036                    })
3037                    .open_files(NesOpenFilesCapabilities::default())
3038                    .diagnostics(NesDiagnosticsCapabilities::default()),
3039            );
3040
3041        let json = serde_json::to_value(&caps).unwrap();
3042        assert_eq!(
3043            json,
3044            json!({
3045                "events": {
3046                    "document": {
3047                        "didOpen": {},
3048                        "didChange": {
3049                            "syncKind": "incremental"
3050                        },
3051                        "didClose": {},
3052                        "didSave": {},
3053                        "didFocus": {}
3054                    }
3055                },
3056                "context": {
3057                    "recentFiles": {
3058                        "maxCount": 10
3059                    },
3060                    "relatedSnippets": {},
3061                    "editHistory": {
3062                        "maxCount": 6
3063                    },
3064                    "userActions": {
3065                        "maxCount": 16
3066                    },
3067                    "openFiles": {},
3068                    "diagnostics": {}
3069                }
3070            })
3071        );
3072
3073        // Round-trip
3074        let deserialized: NesCapabilities = serde_json::from_value(json).unwrap();
3075        assert_eq!(deserialized, caps);
3076    }
3077
3078    #[test]
3079    fn test_client_nes_capabilities_serialization() {
3080        let caps = ClientNesCapabilities::new()
3081            .jump(NesJumpCapabilities::default())
3082            .rename(NesRenameCapabilities::default())
3083            .search_and_replace(NesSearchAndReplaceCapabilities::default());
3084
3085        let json = serde_json::to_value(&caps).unwrap();
3086        assert_eq!(
3087            json,
3088            json!({
3089                "jump": {},
3090                "rename": {},
3091                "searchAndReplace": {}
3092            })
3093        );
3094
3095        let deserialized: ClientNesCapabilities = serde_json::from_value(json).unwrap();
3096        assert_eq!(deserialized, caps);
3097    }
3098
3099    #[test]
3100    fn test_document_did_open_serialization() {
3101        let notification = DidOpenDocumentNotification::new(
3102            "session_123",
3103            "file:///path/to/file.rs",
3104            "rust",
3105            1,
3106            "fn main() {\n    println!(\"hello\");\n}\n",
3107        );
3108
3109        let json = serde_json::to_value(&notification).unwrap();
3110        assert_eq!(
3111            json,
3112            json!({
3113                "sessionId": "session_123",
3114                "uri": "file:///path/to/file.rs",
3115                "languageId": "rust",
3116                "version": 1,
3117                "text": "fn main() {\n    println!(\"hello\");\n}\n"
3118            })
3119        );
3120
3121        let deserialized: DidOpenDocumentNotification = serde_json::from_value(json).unwrap();
3122        assert_eq!(deserialized, notification);
3123    }
3124
3125    #[test]
3126    fn test_document_did_change_incremental_serialization() {
3127        let notification = DidChangeDocumentNotification::new(
3128            "session_123",
3129            "file:///path/to/file.rs",
3130            2,
3131            vec![TextDocumentContentChangeEvent::incremental(
3132                Range::new(Position::new(1, 4), Position::new(1, 4)),
3133                "let x = 42;\n    ",
3134            )],
3135        );
3136
3137        let json = serde_json::to_value(&notification).unwrap();
3138        assert_eq!(
3139            json,
3140            json!({
3141                "sessionId": "session_123",
3142                "uri": "file:///path/to/file.rs",
3143                "version": 2,
3144                "contentChanges": [
3145                    {
3146                        "range": {
3147                            "start": { "line": 1, "character": 4 },
3148                            "end": { "line": 1, "character": 4 }
3149                        },
3150                        "text": "let x = 42;\n    "
3151                    }
3152                ]
3153            })
3154        );
3155    }
3156
3157    #[test]
3158    fn test_document_did_change_full_serialization() {
3159        let notification = DidChangeDocumentNotification::new(
3160            "session_123",
3161            "file:///path/to/file.rs",
3162            2,
3163            vec![TextDocumentContentChangeEvent::full(
3164                "fn main() {\n    let x = 42;\n    println!(\"hello\");\n}\n",
3165            )],
3166        );
3167
3168        let json = serde_json::to_value(&notification).unwrap();
3169        assert_eq!(
3170            json,
3171            json!({
3172                "sessionId": "session_123",
3173                "uri": "file:///path/to/file.rs",
3174                "version": 2,
3175                "contentChanges": [
3176                    {
3177                        "text": "fn main() {\n    let x = 42;\n    println!(\"hello\");\n}\n"
3178                    }
3179                ]
3180            })
3181        );
3182    }
3183
3184    #[test]
3185    fn test_document_did_close_serialization() {
3186        let notification =
3187            DidCloseDocumentNotification::new("session_123", "file:///path/to/file.rs");
3188        let json = serde_json::to_value(&notification).unwrap();
3189        assert_eq!(
3190            json,
3191            json!({ "sessionId": "session_123", "uri": "file:///path/to/file.rs" })
3192        );
3193    }
3194
3195    #[test]
3196    fn test_document_did_save_serialization() {
3197        let notification =
3198            DidSaveDocumentNotification::new("session_123", "file:///path/to/file.rs");
3199        let json = serde_json::to_value(&notification).unwrap();
3200        assert_eq!(
3201            json,
3202            json!({ "sessionId": "session_123", "uri": "file:///path/to/file.rs" })
3203        );
3204    }
3205
3206    #[test]
3207    fn test_document_did_focus_serialization() {
3208        let notification = DidFocusDocumentNotification::new(
3209            "session_123",
3210            "file:///path/to/file.rs",
3211            2,
3212            Position::new(5, 12),
3213            Range::new(Position::new(0, 0), Position::new(45, 0)),
3214        );
3215
3216        let json = serde_json::to_value(&notification).unwrap();
3217        assert_eq!(
3218            json,
3219            json!({
3220                "sessionId": "session_123",
3221                "uri": "file:///path/to/file.rs",
3222                "version": 2,
3223                "position": { "line": 5, "character": 12 },
3224                "visibleRange": {
3225                    "start": { "line": 0, "character": 0 },
3226                    "end": { "line": 45, "character": 0 }
3227                }
3228            })
3229        );
3230    }
3231
3232    #[test]
3233    fn test_nes_suggestion_edit_serialization() {
3234        let suggestion = NesSuggestion::Edit(
3235            NesEditSuggestion::new(
3236                "sugg_001",
3237                "file:///path/to/other_file.rs",
3238                vec![NesTextEdit::new(
3239                    Range::new(Position::new(5, 0), Position::new(5, 10)),
3240                    "let result = helper();",
3241                )],
3242            )
3243            .cursor_position(Position::new(5, 22)),
3244        );
3245
3246        let json = serde_json::to_value(&suggestion).unwrap();
3247        assert_eq!(
3248            json,
3249            json!({
3250                "kind": "edit",
3251                "suggestionId": "sugg_001",
3252                "uri": "file:///path/to/other_file.rs",
3253                "edits": [
3254                    {
3255                        "range": {
3256                            "start": { "line": 5, "character": 0 },
3257                            "end": { "line": 5, "character": 10 }
3258                        },
3259                        "newText": "let result = helper();"
3260                    }
3261                ],
3262                "cursorPosition": { "line": 5, "character": 22 }
3263            })
3264        );
3265
3266        let deserialized: NesSuggestion = serde_json::from_value(json).unwrap();
3267        assert_eq!(deserialized, suggestion);
3268    }
3269
3270    #[test]
3271    fn test_nes_suggestion_unknown_variant() {
3272        let suggestion: NesSuggestion = serde_json::from_value(json!({
3273            "kind": "_preview",
3274            "suggestionId": "sugg_001",
3275            "label": "Preview generated file"
3276        }))
3277        .unwrap();
3278
3279        let NesSuggestion::Other(unknown) = suggestion else {
3280            panic!("expected unknown NES suggestion");
3281        };
3282
3283        assert_eq!(unknown.kind, "_preview");
3284        assert_eq!(unknown.suggestion_id.to_string(), "sugg_001");
3285        assert!(!unknown.fields.contains_key("suggestionId"));
3286        assert_eq!(
3287            serde_json::to_value(NesSuggestion::Other(unknown)).unwrap(),
3288            json!({
3289                "kind": "_preview",
3290                "suggestionId": "sugg_001",
3291                "label": "Preview generated file"
3292            })
3293        );
3294    }
3295
3296    #[test]
3297    fn test_nes_suggestion_unknown_does_not_hide_malformed_known_variant() {
3298        assert!(
3299            serde_json::from_value::<NesSuggestion>(json!({
3300                "kind": "edit"
3301            }))
3302            .is_err()
3303        );
3304    }
3305
3306    #[test]
3307    fn test_nes_suggestion_jump_serialization() {
3308        let suggestion = NesSuggestion::Jump(NesJumpSuggestion::new(
3309            "sugg_002",
3310            "file:///path/to/other_file.rs",
3311            Position::new(15, 4),
3312        ));
3313
3314        let json = serde_json::to_value(&suggestion).unwrap();
3315        assert_eq!(
3316            json,
3317            json!({
3318                "kind": "jump",
3319                "suggestionId": "sugg_002",
3320                "uri": "file:///path/to/other_file.rs",
3321                "position": { "line": 15, "character": 4 }
3322            })
3323        );
3324
3325        let deserialized: NesSuggestion = serde_json::from_value(json).unwrap();
3326        assert_eq!(deserialized, suggestion);
3327    }
3328
3329    #[test]
3330    fn test_nes_suggestion_rename_serialization() {
3331        let suggestion = NesSuggestion::Rename(NesRenameSuggestion::new(
3332            "sugg_003",
3333            "file:///path/to/file.rs",
3334            Position::new(5, 10),
3335            "calculateTotal",
3336        ));
3337
3338        let json = serde_json::to_value(&suggestion).unwrap();
3339        assert_eq!(
3340            json,
3341            json!({
3342                "kind": "rename",
3343                "suggestionId": "sugg_003",
3344                "uri": "file:///path/to/file.rs",
3345                "position": { "line": 5, "character": 10 },
3346                "newName": "calculateTotal"
3347            })
3348        );
3349
3350        let deserialized: NesSuggestion = serde_json::from_value(json).unwrap();
3351        assert_eq!(deserialized, suggestion);
3352    }
3353
3354    #[test]
3355    fn test_nes_suggestion_search_and_replace_serialization() {
3356        let suggestion = NesSuggestion::SearchAndReplace(
3357            NesSearchAndReplaceSuggestion::new(
3358                "sugg_004",
3359                "file:///path/to/file.rs",
3360                "oldFunction",
3361                "newFunction",
3362            )
3363            .is_regex(false),
3364        );
3365
3366        let json = serde_json::to_value(&suggestion).unwrap();
3367        assert_eq!(
3368            json,
3369            json!({
3370                "kind": "searchAndReplace",
3371                "suggestionId": "sugg_004",
3372                "uri": "file:///path/to/file.rs",
3373                "search": "oldFunction",
3374                "replace": "newFunction",
3375                "isRegex": false
3376            })
3377        );
3378
3379        let deserialized: NesSuggestion = serde_json::from_value(json).unwrap();
3380        assert_eq!(deserialized, suggestion);
3381    }
3382
3383    #[test]
3384    fn test_nes_start_request_serialization() {
3385        let request = StartNesRequest::new()
3386            .workspace_uri("file:///Users/alice/projects/my-app")
3387            .workspace_folders(vec![WorkspaceFolder::new(
3388                "file:///Users/alice/projects/my-app",
3389                "my-app",
3390            )])
3391            .repository(NesRepository::new(
3392                "my-app",
3393                "alice",
3394                "https://github.com/alice/my-app.git",
3395            ));
3396
3397        let json = serde_json::to_value(&request).unwrap();
3398        assert_eq!(
3399            json,
3400            json!({
3401                "workspaceUri": "file:///Users/alice/projects/my-app",
3402                "workspaceFolders": [
3403                    {
3404                        "uri": "file:///Users/alice/projects/my-app",
3405                        "name": "my-app"
3406                    }
3407                ],
3408                "repository": {
3409                    "name": "my-app",
3410                    "owner": "alice",
3411                    "remoteUrl": "https://github.com/alice/my-app.git"
3412                }
3413            })
3414        );
3415    }
3416
3417    #[test]
3418    fn test_nes_start_response_serialization() {
3419        let response = StartNesResponse::new("session_abc123");
3420        let json = serde_json::to_value(&response).unwrap();
3421        assert_eq!(json, json!({ "sessionId": "session_abc123" }));
3422    }
3423
3424    #[test]
3425    fn test_nes_trigger_kind_serialization() {
3426        assert_eq!(
3427            serde_json::to_value(&NesTriggerKind::Automatic).unwrap(),
3428            json!("automatic")
3429        );
3430        assert_eq!(
3431            serde_json::to_value(&NesTriggerKind::Diagnostic).unwrap(),
3432            json!("diagnostic")
3433        );
3434        assert_eq!(
3435            serde_json::to_value(&NesTriggerKind::Manual).unwrap(),
3436            json!("manual")
3437        );
3438    }
3439
3440    #[test]
3441    fn test_nes_reject_reason_serialization() {
3442        assert_eq!(
3443            serde_json::to_value(&NesRejectReason::Rejected).unwrap(),
3444            json!("rejected")
3445        );
3446        assert_eq!(
3447            serde_json::to_value(&NesRejectReason::Ignored).unwrap(),
3448            json!("ignored")
3449        );
3450        assert_eq!(
3451            serde_json::to_value(&NesRejectReason::Replaced).unwrap(),
3452            json!("replaced")
3453        );
3454        assert_eq!(
3455            serde_json::to_value(&NesRejectReason::Cancelled).unwrap(),
3456            json!("cancelled")
3457        );
3458    }
3459
3460    #[test]
3461    fn test_nes_accept_notification_serialization() {
3462        let notification = AcceptNesNotification::new("session_123", "sugg_001");
3463        let json = serde_json::to_value(&notification).unwrap();
3464        assert_eq!(
3465            json,
3466            json!({ "sessionId": "session_123", "suggestionId": "sugg_001" })
3467        );
3468    }
3469
3470    #[test]
3471    fn test_nes_reject_notification_serialization() {
3472        let notification =
3473            RejectNesNotification::new("session_123", "sugg_001").reason(NesRejectReason::Rejected);
3474        let json = serde_json::to_value(&notification).unwrap();
3475        assert_eq!(
3476            json,
3477            json!({ "sessionId": "session_123", "suggestionId": "sugg_001", "reason": "rejected" })
3478        );
3479    }
3480
3481    #[test]
3482    fn test_nes_suggest_request_with_context_serialization() {
3483        let request = SuggestNesRequest::new(
3484            "session_123",
3485            "file:///path/to/file.rs",
3486            2,
3487            Position::new(5, 12),
3488            NesTriggerKind::Automatic,
3489        )
3490        .selection(Range::new(Position::new(5, 4), Position::new(5, 12)))
3491        .context(
3492            NesSuggestContext::new()
3493                .recent_files(vec![NesRecentFile::new(
3494                    "file:///path/to/utils.rs",
3495                    "rust",
3496                    "pub fn helper() -> i32 { 42 }\n",
3497                )])
3498                .diagnostics(vec![NesDiagnostic::new(
3499                    "file:///path/to/file.rs",
3500                    Range::new(Position::new(5, 0), Position::new(5, 10)),
3501                    NesDiagnosticSeverity::Error,
3502                    "cannot find value `foo` in this scope",
3503                )]),
3504        );
3505
3506        let json = serde_json::to_value(&request).unwrap();
3507        assert_eq!(json["sessionId"], "session_123");
3508        assert_eq!(json["uri"], "file:///path/to/file.rs");
3509        assert_eq!(json["version"], 2);
3510        assert_eq!(json["triggerKind"], "automatic");
3511        assert_eq!(
3512            json["context"]["recentFiles"][0]["uri"],
3513            "file:///path/to/utils.rs"
3514        );
3515        assert_eq!(json["context"]["diagnostics"][0]["severity"], "error");
3516    }
3517
3518    #[test]
3519    fn test_text_document_sync_kind_serialization() {
3520        assert_eq!(
3521            serde_json::to_value(&TextDocumentSyncKind::Full).unwrap(),
3522            json!("full")
3523        );
3524        assert_eq!(
3525            serde_json::to_value(&TextDocumentSyncKind::Incremental).unwrap(),
3526            json!("incremental")
3527        );
3528        assert!(serde_json::from_value::<TextDocumentSyncKind>(json!("_future")).is_err());
3529    }
3530
3531    #[test]
3532    fn test_document_event_capabilities_drop_unknown_did_change_sync_kind() {
3533        let caps: NesDocumentEventCapabilities = serde_json::from_value(json!({
3534            "didChange": {
3535                "syncKind": "_future"
3536            }
3537        }))
3538        .unwrap();
3539
3540        assert_eq!(caps.did_change, None);
3541    }
3542
3543    #[test]
3544    fn test_document_did_change_capabilities_requires_sync_kind() {
3545        assert!(serde_json::from_value::<NesDocumentDidChangeCapabilities>(json!({})).is_err());
3546    }
3547
3548    #[test]
3549    fn test_nes_suggest_response_serialization() {
3550        let response = SuggestNesResponse::new(vec![
3551            NesSuggestion::Edit(NesEditSuggestion::new(
3552                "sugg_001",
3553                "file:///path/to/file.rs",
3554                vec![NesTextEdit::new(
3555                    Range::new(Position::new(5, 0), Position::new(5, 10)),
3556                    "let result = helper();",
3557                )],
3558            )),
3559            NesSuggestion::Jump(NesJumpSuggestion::new(
3560                "sugg_002",
3561                "file:///path/to/other.rs",
3562                Position::new(10, 0),
3563            )),
3564        ]);
3565
3566        let json = serde_json::to_value(&response).unwrap();
3567        assert_eq!(json["suggestions"].as_array().unwrap().len(), 2);
3568        assert_eq!(json["suggestions"][0]["kind"], "edit");
3569        assert_eq!(json["suggestions"][1]["kind"], "jump");
3570    }
3571
3572    #[test]
3573    fn did_change_document_rejects_malformed_content_changes() {
3574        let notification = |content_changes: serde_json::Value| {
3575            serde_json::from_value::<DidChangeDocumentNotification>(json!({
3576                "sessionId": "session_123",
3577                "uri": "file:///path/to/file.rs",
3578                "version": 7,
3579                "contentChanges": content_changes
3580            }))
3581        };
3582
3583        // Applying only the valid incremental edit would silently desync the
3584        // document at version 7; rejecting it leaves a detectable version gap.
3585        assert!(
3586            notification(json!([
3587                {
3588                    "range": {"start": {"line": 3, "character": 0}, "end": {"line": 3, "character": "4"}},
3589                    "text": "let"
3590                },
3591                {
3592                    "range": {"start": {"line": 9, "character": 2}, "end": {"line": 9, "character": 2}},
3593                    "text": "x"
3594                }
3595            ]))
3596            .is_err()
3597        );
3598        assert!(notification(json!("not-an-array")).is_err());
3599        assert_eq!(
3600            notification(serde_json::Value::Null)
3601                .unwrap()
3602                .content_changes,
3603            vec![]
3604        );
3605    }
3606}