Skip to main content

agent_client_protocol_schema/v2/
nes.rs

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