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