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(Arc<str>, String, &'static str)]
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<Arc<str>>) -> Self {
43        Self(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#[schemars(extend("discriminator" = {"propertyName": "kind"}))]
2356#[non_exhaustive]
2357pub enum NesSuggestion {
2358    /// A text edit suggestion.
2359    Edit(NesEditSuggestion),
2360    /// A jump-to-location suggestion.
2361    Jump(NesJumpSuggestion),
2362    /// A rename symbol suggestion.
2363    Rename(NesRenameSuggestion),
2364    /// A search-and-replace suggestion.
2365    SearchAndReplace(NesSearchAndReplaceSuggestion),
2366    /// Custom or future NES suggestion.
2367    ///
2368    /// Values beginning with `_` are reserved for implementation-specific
2369    /// extensions. Unknown values that do not begin with `_` are reserved for
2370    /// future ACP variants.
2371    ///
2372    /// Receivers that do not understand this suggestion kind should preserve
2373    /// the raw payload when storing, replaying, proxying, or forwarding
2374    /// suggestions, and otherwise ignore it or display it generically.
2375    #[serde(untagged)]
2376    Other(OtherNesSuggestion),
2377}
2378
2379/// Custom or future NES suggestion payload.
2380#[derive(Debug, Clone, Serialize, JsonSchema, PartialEq, Eq)]
2381#[schemars(inline)]
2382#[schemars(transform = other_nes_suggestion_schema)]
2383#[serde(rename_all = "camelCase")]
2384#[non_exhaustive]
2385pub struct OtherNesSuggestion {
2386    /// Custom or future NES suggestion kind.
2387    ///
2388    /// Values beginning with `_` are reserved for implementation-specific
2389    /// extensions. Unknown values that do not begin with `_` are reserved for
2390    /// future ACP variants.
2391    pub kind: String,
2392    /// Unique identifier for accept/reject tracking.
2393    pub suggestion_id: NesSuggestionId,
2394    /// Additional fields from the unknown NES suggestion payload.
2395    #[serde(flatten)]
2396    pub fields: BTreeMap<String, serde_json::Value>,
2397}
2398
2399impl OtherNesSuggestion {
2400    /// Builds [`OtherNesSuggestion`] from an unknown discriminator and preserves the remaining extension fields.
2401    #[must_use]
2402    pub fn new(
2403        kind: impl Into<String>,
2404        suggestion_id: impl Into<NesSuggestionId>,
2405        mut fields: BTreeMap<String, serde_json::Value>,
2406    ) -> Self {
2407        fields.remove("kind");
2408        fields.remove("suggestionId");
2409        Self {
2410            kind: kind.into(),
2411            suggestion_id: suggestion_id.into(),
2412            fields,
2413        }
2414    }
2415}
2416
2417impl<'de> Deserialize<'de> for OtherNesSuggestion {
2418    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
2419    where
2420        D: serde::Deserializer<'de>,
2421    {
2422        let mut fields = BTreeMap::<String, serde_json::Value>::deserialize(deserializer)?;
2423        let kind = fields
2424            .remove("kind")
2425            .ok_or_else(|| serde::de::Error::missing_field("kind"))?;
2426        let serde_json::Value::String(kind) = kind else {
2427            return Err(serde::de::Error::custom("`kind` must be a string"));
2428        };
2429        let suggestion_id = fields
2430            .remove("suggestionId")
2431            .ok_or_else(|| serde::de::Error::missing_field("suggestionId"))?;
2432        let serde_json::Value::String(suggestion_id) = suggestion_id else {
2433            return Err(serde::de::Error::custom("`suggestionId` must be a string"));
2434        };
2435
2436        if is_known_nes_suggestion_kind(&kind) {
2437            return Err(serde::de::Error::custom(format!(
2438                "known NES suggestion `{kind}` did not match its schema"
2439            )));
2440        }
2441
2442        Ok(Self {
2443            kind,
2444            suggestion_id: NesSuggestionId::new(suggestion_id),
2445            fields,
2446        })
2447    }
2448}
2449
2450fn is_known_nes_suggestion_kind(kind: &str) -> bool {
2451    matches!(kind, "edit" | "jump" | "rename" | "searchAndReplace")
2452}
2453
2454fn other_nes_suggestion_schema(schema: &mut Schema) {
2455    super::schema_util::reject_known_string_discriminators(
2456        schema,
2457        "kind",
2458        &["edit", "jump", "rename", "searchAndReplace"],
2459    );
2460}
2461
2462/// A text edit suggestion.
2463#[serde_as]
2464#[skip_serializing_none]
2465#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2466#[serde(rename_all = "camelCase")]
2467#[non_exhaustive]
2468pub struct NesEditSuggestion {
2469    /// Unique identifier for accept/reject tracking.
2470    pub suggestion_id: NesSuggestionId,
2471    /// The URI of the file to edit.
2472    #[schemars(url)]
2473    pub uri: String,
2474    /// The text edits to apply. Must contain at least one edit.
2475    #[schemars(length(min = 1))]
2476    pub edits: Vec<NesTextEdit>,
2477    /// Optional suggested cursor position after applying edits.
2478    #[serde_as(deserialize_as = "DefaultOnError")]
2479    #[schemars(extend("x-deserialize-default-on-error" = true))]
2480    #[serde(default)]
2481    pub cursor_position: Option<Position>,
2482    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
2483    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
2484    /// these keys.
2485    ///
2486    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
2487    #[serde_as(deserialize_as = "DefaultOnError")]
2488    #[schemars(extend("x-deserialize-default-on-error" = true))]
2489    #[serde(default)]
2490    #[serde(rename = "_meta")]
2491    pub meta: Option<Meta>,
2492}
2493
2494impl NesEditSuggestion {
2495    /// Builds [`NesEditSuggestion`] with the required fields set; optional fields start unset or empty.
2496    #[must_use]
2497    pub fn new(
2498        suggestion_id: impl Into<NesSuggestionId>,
2499        uri: impl Into<String>,
2500        edits: Vec<NesTextEdit>,
2501    ) -> Self {
2502        Self {
2503            suggestion_id: suggestion_id.into(),
2504            uri: uri.into(),
2505            edits,
2506            cursor_position: None,
2507            meta: None,
2508        }
2509    }
2510
2511    /// Sets or clears the optional `cursorPosition` field.
2512    #[must_use]
2513    pub fn cursor_position(mut self, cursor_position: impl IntoOption<Position>) -> Self {
2514        self.cursor_position = cursor_position.into_option();
2515        self
2516    }
2517
2518    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
2519    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
2520    /// these keys.
2521    ///
2522    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
2523    #[must_use]
2524    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2525        self.meta = meta.into_option();
2526        self
2527    }
2528}
2529
2530/// A text edit within a suggestion.
2531#[serde_as]
2532#[skip_serializing_none]
2533#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2534#[serde(rename_all = "camelCase")]
2535#[non_exhaustive]
2536pub struct NesTextEdit {
2537    /// The range to replace.
2538    pub range: Range,
2539    /// The replacement text.
2540    pub new_text: String,
2541    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
2542    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
2543    /// these keys.
2544    ///
2545    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
2546    #[serde_as(deserialize_as = "DefaultOnError")]
2547    #[schemars(extend("x-deserialize-default-on-error" = true))]
2548    #[serde(default)]
2549    #[serde(rename = "_meta")]
2550    pub meta: Option<Meta>,
2551}
2552
2553impl NesTextEdit {
2554    /// Builds [`NesTextEdit`] with the required fields set; optional fields start unset or empty.
2555    #[must_use]
2556    pub fn new(range: Range, new_text: impl Into<String>) -> Self {
2557        Self {
2558            range,
2559            new_text: new_text.into(),
2560            meta: None,
2561        }
2562    }
2563
2564    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
2565    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
2566    /// these keys.
2567    ///
2568    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
2569    #[must_use]
2570    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2571        self.meta = meta.into_option();
2572        self
2573    }
2574}
2575
2576/// A jump-to-location suggestion.
2577#[serde_as]
2578#[skip_serializing_none]
2579#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2580#[serde(rename_all = "camelCase")]
2581#[non_exhaustive]
2582pub struct NesJumpSuggestion {
2583    /// Unique identifier for accept/reject tracking.
2584    pub suggestion_id: NesSuggestionId,
2585    /// The file to navigate to.
2586    #[schemars(url)]
2587    pub uri: String,
2588    /// The target position within the file.
2589    pub position: Position,
2590    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
2591    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
2592    /// these keys.
2593    ///
2594    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
2595    #[serde_as(deserialize_as = "DefaultOnError")]
2596    #[schemars(extend("x-deserialize-default-on-error" = true))]
2597    #[serde(default)]
2598    #[serde(rename = "_meta")]
2599    pub meta: Option<Meta>,
2600}
2601
2602impl NesJumpSuggestion {
2603    /// Builds [`NesJumpSuggestion`] with the required fields set; optional fields start unset or empty.
2604    #[must_use]
2605    pub fn new(
2606        suggestion_id: impl Into<NesSuggestionId>,
2607        uri: impl Into<String>,
2608        position: Position,
2609    ) -> Self {
2610        Self {
2611            suggestion_id: suggestion_id.into(),
2612            uri: uri.into(),
2613            position,
2614            meta: None,
2615        }
2616    }
2617
2618    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
2619    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
2620    /// these keys.
2621    ///
2622    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
2623    #[must_use]
2624    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2625        self.meta = meta.into_option();
2626        self
2627    }
2628}
2629
2630/// A rename symbol suggestion.
2631#[serde_as]
2632#[skip_serializing_none]
2633#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2634#[serde(rename_all = "camelCase")]
2635#[non_exhaustive]
2636pub struct NesRenameSuggestion {
2637    /// Unique identifier for accept/reject tracking.
2638    pub suggestion_id: NesSuggestionId,
2639    /// The file URI containing the symbol.
2640    #[schemars(url)]
2641    pub uri: String,
2642    /// The position of the symbol to rename.
2643    pub position: Position,
2644    /// The new name for the symbol.
2645    pub new_name: String,
2646    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
2647    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
2648    /// these keys.
2649    ///
2650    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
2651    #[serde_as(deserialize_as = "DefaultOnError")]
2652    #[schemars(extend("x-deserialize-default-on-error" = true))]
2653    #[serde(default)]
2654    #[serde(rename = "_meta")]
2655    pub meta: Option<Meta>,
2656}
2657
2658impl NesRenameSuggestion {
2659    /// Builds [`NesRenameSuggestion`] with the required fields set; optional fields start unset or empty.
2660    #[must_use]
2661    pub fn new(
2662        suggestion_id: impl Into<NesSuggestionId>,
2663        uri: impl Into<String>,
2664        position: Position,
2665        new_name: impl Into<String>,
2666    ) -> Self {
2667        Self {
2668            suggestion_id: suggestion_id.into(),
2669            uri: uri.into(),
2670            position,
2671            new_name: new_name.into(),
2672            meta: None,
2673        }
2674    }
2675
2676    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
2677    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
2678    /// these keys.
2679    ///
2680    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
2681    #[must_use]
2682    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2683        self.meta = meta.into_option();
2684        self
2685    }
2686}
2687
2688/// A search-and-replace suggestion.
2689#[serde_as]
2690#[skip_serializing_none]
2691#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2692#[serde(rename_all = "camelCase")]
2693#[non_exhaustive]
2694pub struct NesSearchAndReplaceSuggestion {
2695    /// Unique identifier for accept/reject tracking.
2696    pub suggestion_id: NesSuggestionId,
2697    /// The file URI to search within.
2698    #[schemars(url)]
2699    pub uri: String,
2700    /// The text or pattern to find.
2701    pub search: String,
2702    /// The replacement text.
2703    pub replace: String,
2704    /// Whether `search` is a regular expression. Defaults to `false`.
2705    #[serde(default)]
2706    pub is_regex: Option<bool>,
2707    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
2708    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
2709    /// these keys.
2710    ///
2711    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
2712    #[serde_as(deserialize_as = "DefaultOnError")]
2713    #[schemars(extend("x-deserialize-default-on-error" = true))]
2714    #[serde(default)]
2715    #[serde(rename = "_meta")]
2716    pub meta: Option<Meta>,
2717}
2718
2719impl NesSearchAndReplaceSuggestion {
2720    /// Builds [`NesSearchAndReplaceSuggestion`] with the required fields set; optional fields start unset or empty.
2721    #[must_use]
2722    pub fn new(
2723        suggestion_id: impl Into<NesSuggestionId>,
2724        uri: impl Into<String>,
2725        search: impl Into<String>,
2726        replace: impl Into<String>,
2727    ) -> Self {
2728        Self {
2729            suggestion_id: suggestion_id.into(),
2730            uri: uri.into(),
2731            search: search.into(),
2732            replace: replace.into(),
2733            is_regex: None,
2734            meta: None,
2735        }
2736    }
2737
2738    /// Sets or clears the optional `isRegex` field.
2739    #[must_use]
2740    pub fn is_regex(mut self, is_regex: impl IntoOption<bool>) -> Self {
2741        self.is_regex = is_regex.into_option();
2742        self
2743    }
2744
2745    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
2746    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
2747    /// these keys.
2748    ///
2749    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
2750    #[must_use]
2751    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2752        self.meta = meta.into_option();
2753        self
2754    }
2755}
2756
2757// NES accept/reject notifications
2758
2759/// Notification sent when a suggestion is accepted.
2760#[serde_as]
2761#[skip_serializing_none]
2762#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2763#[schemars(extend("x-side" = "agent", "x-method" = NES_ACCEPT_METHOD_NAME))]
2764#[serde(rename_all = "camelCase")]
2765#[non_exhaustive]
2766pub struct AcceptNesNotification {
2767    /// The session ID for this notification.
2768    pub session_id: SessionId,
2769    /// The ID of the accepted suggestion.
2770    pub suggestion_id: NesSuggestionId,
2771    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
2772    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
2773    /// these keys.
2774    ///
2775    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
2776    #[serde_as(deserialize_as = "DefaultOnError")]
2777    #[schemars(extend("x-deserialize-default-on-error" = true))]
2778    #[serde(default)]
2779    #[serde(rename = "_meta")]
2780    pub meta: Option<Meta>,
2781}
2782
2783impl AcceptNesNotification {
2784    /// Builds [`AcceptNesNotification`] with the required notification fields set; optional fields start unset or empty.
2785    #[must_use]
2786    pub fn new(
2787        session_id: impl Into<SessionId>,
2788        suggestion_id: impl Into<NesSuggestionId>,
2789    ) -> Self {
2790        Self {
2791            session_id: session_id.into(),
2792            suggestion_id: suggestion_id.into(),
2793            meta: None,
2794        }
2795    }
2796
2797    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
2798    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
2799    /// these keys.
2800    ///
2801    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
2802    #[must_use]
2803    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2804        self.meta = meta.into_option();
2805        self
2806    }
2807}
2808
2809/// Notification sent when a suggestion is rejected.
2810#[serde_as]
2811#[skip_serializing_none]
2812#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2813#[schemars(extend("x-side" = "agent", "x-method" = NES_REJECT_METHOD_NAME))]
2814#[serde(rename_all = "camelCase")]
2815#[non_exhaustive]
2816pub struct RejectNesNotification {
2817    /// The session ID for this notification.
2818    pub session_id: SessionId,
2819    /// The ID of the rejected suggestion.
2820    pub suggestion_id: NesSuggestionId,
2821    /// The reason for rejection.
2822    #[serde_as(deserialize_as = "DefaultOnError")]
2823    #[schemars(extend("x-deserialize-default-on-error" = true))]
2824    #[serde(default)]
2825    pub reason: Option<NesRejectReason>,
2826    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
2827    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
2828    /// these keys.
2829    ///
2830    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
2831    #[serde_as(deserialize_as = "DefaultOnError")]
2832    #[schemars(extend("x-deserialize-default-on-error" = true))]
2833    #[serde(default)]
2834    #[serde(rename = "_meta")]
2835    pub meta: Option<Meta>,
2836}
2837
2838impl RejectNesNotification {
2839    /// Builds [`RejectNesNotification`] with the required notification fields set; optional fields start unset or empty.
2840    #[must_use]
2841    pub fn new(
2842        session_id: impl Into<SessionId>,
2843        suggestion_id: impl Into<NesSuggestionId>,
2844    ) -> Self {
2845        Self {
2846            session_id: session_id.into(),
2847            suggestion_id: suggestion_id.into(),
2848            reason: None,
2849            meta: None,
2850        }
2851    }
2852
2853    /// Sets or clears the optional `reason` field.
2854    #[must_use]
2855    pub fn reason(mut self, reason: impl IntoOption<NesRejectReason>) -> Self {
2856        self.reason = reason.into_option();
2857        self
2858    }
2859
2860    /// The _meta property is reserved by ACP to allow clients and agents to attach additional
2861    /// metadata to their interactions. Implementations MUST NOT make assumptions about values at
2862    /// these keys.
2863    ///
2864    /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)
2865    #[must_use]
2866    pub fn meta(mut self, meta: impl IntoOption<Meta>) -> Self {
2867        self.meta = meta.into_option();
2868        self
2869    }
2870}
2871
2872/// The reason a suggestion was rejected.
2873#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
2874#[non_exhaustive]
2875pub enum NesRejectReason {
2876    /// The user explicitly dismissed the suggestion.
2877    #[serde(rename = "rejected")]
2878    Rejected,
2879    /// The suggestion was shown but the user continued editing without interacting.
2880    #[serde(rename = "ignored")]
2881    Ignored,
2882    /// The suggestion was superseded by a newer suggestion.
2883    #[serde(rename = "replaced")]
2884    Replaced,
2885    /// The request was cancelled before the agent returned a response.
2886    #[serde(rename = "cancelled")]
2887    Cancelled,
2888    /// Custom or future rejection reason.
2889    ///
2890    /// Values beginning with `_` are reserved for implementation-specific
2891    /// extensions. Unknown values that do not begin with `_` are reserved for
2892    /// future ACP variants.
2893    #[serde(untagged)]
2894    Other(String),
2895}
2896
2897#[cfg(test)]
2898mod tests {
2899    use super::*;
2900    use serde_json::json;
2901
2902    #[test]
2903    fn test_position_encoding_kind_serialization() {
2904        assert_eq!(
2905            serde_json::to_value(&PositionEncodingKind::Utf16).unwrap(),
2906            json!("utf-16")
2907        );
2908        assert_eq!(
2909            serde_json::to_value(&PositionEncodingKind::Utf32).unwrap(),
2910            json!("utf-32")
2911        );
2912        assert_eq!(
2913            serde_json::to_value(&PositionEncodingKind::Utf8).unwrap(),
2914            json!("utf-8")
2915        );
2916
2917        assert_eq!(
2918            serde_json::from_value::<PositionEncodingKind>(json!("utf-16")).unwrap(),
2919            PositionEncodingKind::Utf16
2920        );
2921        assert_eq!(
2922            serde_json::from_value::<PositionEncodingKind>(json!("utf-32")).unwrap(),
2923            PositionEncodingKind::Utf32
2924        );
2925        assert_eq!(
2926            serde_json::from_value::<PositionEncodingKind>(json!("utf-8")).unwrap(),
2927            PositionEncodingKind::Utf8
2928        );
2929        assert!(serde_json::from_value::<PositionEncodingKind>(json!("_future")).is_err());
2930    }
2931
2932    #[test]
2933    fn test_client_capabilities_skip_unknown_position_encodings() {
2934        let caps: crate::v2::ClientCapabilities = serde_json::from_value(json!({
2935            "positionEncodings": ["_future", "utf-8", "utf-16"]
2936        }))
2937        .unwrap();
2938
2939        assert_eq!(
2940            caps.position_encodings,
2941            vec![PositionEncodingKind::Utf8, PositionEncodingKind::Utf16]
2942        );
2943    }
2944
2945    #[test]
2946    fn test_agent_nes_capabilities_serialization() {
2947        let caps = NesCapabilities::new()
2948            .events(
2949                NesEventCapabilities::new().document(
2950                    NesDocumentEventCapabilities::new()
2951                        .did_open(NesDocumentDidOpenCapabilities::default())
2952                        .did_change(NesDocumentDidChangeCapabilities::new(
2953                            TextDocumentSyncKind::Incremental,
2954                        ))
2955                        .did_close(NesDocumentDidCloseCapabilities::default())
2956                        .did_save(NesDocumentDidSaveCapabilities::default())
2957                        .did_focus(NesDocumentDidFocusCapabilities::default()),
2958                ),
2959            )
2960            .context(
2961                NesContextCapabilities::new()
2962                    .recent_files(NesRecentFilesCapabilities {
2963                        max_count: Some(10),
2964                        meta: None,
2965                    })
2966                    .related_snippets(NesRelatedSnippetsCapabilities::default())
2967                    .edit_history(NesEditHistoryCapabilities {
2968                        max_count: Some(6),
2969                        meta: None,
2970                    })
2971                    .user_actions(NesUserActionsCapabilities {
2972                        max_count: Some(16),
2973                        meta: None,
2974                    })
2975                    .open_files(NesOpenFilesCapabilities::default())
2976                    .diagnostics(NesDiagnosticsCapabilities::default()),
2977            );
2978
2979        let json = serde_json::to_value(&caps).unwrap();
2980        assert_eq!(
2981            json,
2982            json!({
2983                "events": {
2984                    "document": {
2985                        "didOpen": {},
2986                        "didChange": {
2987                            "syncKind": "incremental"
2988                        },
2989                        "didClose": {},
2990                        "didSave": {},
2991                        "didFocus": {}
2992                    }
2993                },
2994                "context": {
2995                    "recentFiles": {
2996                        "maxCount": 10
2997                    },
2998                    "relatedSnippets": {},
2999                    "editHistory": {
3000                        "maxCount": 6
3001                    },
3002                    "userActions": {
3003                        "maxCount": 16
3004                    },
3005                    "openFiles": {},
3006                    "diagnostics": {}
3007                }
3008            })
3009        );
3010
3011        // Round-trip
3012        let deserialized: NesCapabilities = serde_json::from_value(json).unwrap();
3013        assert_eq!(deserialized, caps);
3014    }
3015
3016    #[test]
3017    fn test_client_nes_capabilities_serialization() {
3018        let caps = ClientNesCapabilities::new()
3019            .jump(NesJumpCapabilities::default())
3020            .rename(NesRenameCapabilities::default())
3021            .search_and_replace(NesSearchAndReplaceCapabilities::default());
3022
3023        let json = serde_json::to_value(&caps).unwrap();
3024        assert_eq!(
3025            json,
3026            json!({
3027                "jump": {},
3028                "rename": {},
3029                "searchAndReplace": {}
3030            })
3031        );
3032
3033        let deserialized: ClientNesCapabilities = serde_json::from_value(json).unwrap();
3034        assert_eq!(deserialized, caps);
3035    }
3036
3037    #[test]
3038    fn test_document_did_open_serialization() {
3039        let notification = DidOpenDocumentNotification::new(
3040            "session_123",
3041            "file:///path/to/file.rs",
3042            "rust",
3043            1,
3044            "fn main() {\n    println!(\"hello\");\n}\n",
3045        );
3046
3047        let json = serde_json::to_value(&notification).unwrap();
3048        assert_eq!(
3049            json,
3050            json!({
3051                "sessionId": "session_123",
3052                "uri": "file:///path/to/file.rs",
3053                "languageId": "rust",
3054                "version": 1,
3055                "text": "fn main() {\n    println!(\"hello\");\n}\n"
3056            })
3057        );
3058
3059        let deserialized: DidOpenDocumentNotification = serde_json::from_value(json).unwrap();
3060        assert_eq!(deserialized, notification);
3061    }
3062
3063    #[test]
3064    fn test_document_did_change_incremental_serialization() {
3065        let notification = DidChangeDocumentNotification::new(
3066            "session_123",
3067            "file:///path/to/file.rs",
3068            2,
3069            vec![TextDocumentContentChangeEvent::incremental(
3070                Range::new(Position::new(1, 4), Position::new(1, 4)),
3071                "let x = 42;\n    ",
3072            )],
3073        );
3074
3075        let json = serde_json::to_value(&notification).unwrap();
3076        assert_eq!(
3077            json,
3078            json!({
3079                "sessionId": "session_123",
3080                "uri": "file:///path/to/file.rs",
3081                "version": 2,
3082                "contentChanges": [
3083                    {
3084                        "range": {
3085                            "start": { "line": 1, "character": 4 },
3086                            "end": { "line": 1, "character": 4 }
3087                        },
3088                        "text": "let x = 42;\n    "
3089                    }
3090                ]
3091            })
3092        );
3093    }
3094
3095    #[test]
3096    fn test_document_did_change_full_serialization() {
3097        let notification = DidChangeDocumentNotification::new(
3098            "session_123",
3099            "file:///path/to/file.rs",
3100            2,
3101            vec![TextDocumentContentChangeEvent::full(
3102                "fn main() {\n    let x = 42;\n    println!(\"hello\");\n}\n",
3103            )],
3104        );
3105
3106        let json = serde_json::to_value(&notification).unwrap();
3107        assert_eq!(
3108            json,
3109            json!({
3110                "sessionId": "session_123",
3111                "uri": "file:///path/to/file.rs",
3112                "version": 2,
3113                "contentChanges": [
3114                    {
3115                        "text": "fn main() {\n    let x = 42;\n    println!(\"hello\");\n}\n"
3116                    }
3117                ]
3118            })
3119        );
3120    }
3121
3122    #[test]
3123    fn test_document_did_close_serialization() {
3124        let notification =
3125            DidCloseDocumentNotification::new("session_123", "file:///path/to/file.rs");
3126        let json = serde_json::to_value(&notification).unwrap();
3127        assert_eq!(
3128            json,
3129            json!({ "sessionId": "session_123", "uri": "file:///path/to/file.rs" })
3130        );
3131    }
3132
3133    #[test]
3134    fn test_document_did_save_serialization() {
3135        let notification =
3136            DidSaveDocumentNotification::new("session_123", "file:///path/to/file.rs");
3137        let json = serde_json::to_value(&notification).unwrap();
3138        assert_eq!(
3139            json,
3140            json!({ "sessionId": "session_123", "uri": "file:///path/to/file.rs" })
3141        );
3142    }
3143
3144    #[test]
3145    fn test_document_did_focus_serialization() {
3146        let notification = DidFocusDocumentNotification::new(
3147            "session_123",
3148            "file:///path/to/file.rs",
3149            2,
3150            Position::new(5, 12),
3151            Range::new(Position::new(0, 0), Position::new(45, 0)),
3152        );
3153
3154        let json = serde_json::to_value(&notification).unwrap();
3155        assert_eq!(
3156            json,
3157            json!({
3158                "sessionId": "session_123",
3159                "uri": "file:///path/to/file.rs",
3160                "version": 2,
3161                "position": { "line": 5, "character": 12 },
3162                "visibleRange": {
3163                    "start": { "line": 0, "character": 0 },
3164                    "end": { "line": 45, "character": 0 }
3165                }
3166            })
3167        );
3168    }
3169
3170    #[test]
3171    fn test_nes_suggestion_edit_serialization() {
3172        let suggestion = NesSuggestion::Edit(
3173            NesEditSuggestion::new(
3174                "sugg_001",
3175                "file:///path/to/other_file.rs",
3176                vec![NesTextEdit::new(
3177                    Range::new(Position::new(5, 0), Position::new(5, 10)),
3178                    "let result = helper();",
3179                )],
3180            )
3181            .cursor_position(Position::new(5, 22)),
3182        );
3183
3184        let json = serde_json::to_value(&suggestion).unwrap();
3185        assert_eq!(
3186            json,
3187            json!({
3188                "kind": "edit",
3189                "suggestionId": "sugg_001",
3190                "uri": "file:///path/to/other_file.rs",
3191                "edits": [
3192                    {
3193                        "range": {
3194                            "start": { "line": 5, "character": 0 },
3195                            "end": { "line": 5, "character": 10 }
3196                        },
3197                        "newText": "let result = helper();"
3198                    }
3199                ],
3200                "cursorPosition": { "line": 5, "character": 22 }
3201            })
3202        );
3203
3204        let deserialized: NesSuggestion = serde_json::from_value(json).unwrap();
3205        assert_eq!(deserialized, suggestion);
3206    }
3207
3208    #[test]
3209    fn test_nes_suggestion_unknown_variant() {
3210        let suggestion: NesSuggestion = serde_json::from_value(json!({
3211            "kind": "_preview",
3212            "suggestionId": "sugg_001",
3213            "label": "Preview generated file"
3214        }))
3215        .unwrap();
3216
3217        let NesSuggestion::Other(unknown) = suggestion else {
3218            panic!("expected unknown NES suggestion");
3219        };
3220
3221        assert_eq!(unknown.kind, "_preview");
3222        assert_eq!(unknown.suggestion_id.to_string(), "sugg_001");
3223        assert!(!unknown.fields.contains_key("suggestionId"));
3224        assert_eq!(
3225            serde_json::to_value(NesSuggestion::Other(unknown)).unwrap(),
3226            json!({
3227                "kind": "_preview",
3228                "suggestionId": "sugg_001",
3229                "label": "Preview generated file"
3230            })
3231        );
3232    }
3233
3234    #[test]
3235    fn test_nes_suggestion_unknown_does_not_hide_malformed_known_variant() {
3236        assert!(
3237            serde_json::from_value::<NesSuggestion>(json!({
3238                "kind": "edit"
3239            }))
3240            .is_err()
3241        );
3242    }
3243
3244    #[test]
3245    fn test_nes_suggestion_jump_serialization() {
3246        let suggestion = NesSuggestion::Jump(NesJumpSuggestion::new(
3247            "sugg_002",
3248            "file:///path/to/other_file.rs",
3249            Position::new(15, 4),
3250        ));
3251
3252        let json = serde_json::to_value(&suggestion).unwrap();
3253        assert_eq!(
3254            json,
3255            json!({
3256                "kind": "jump",
3257                "suggestionId": "sugg_002",
3258                "uri": "file:///path/to/other_file.rs",
3259                "position": { "line": 15, "character": 4 }
3260            })
3261        );
3262
3263        let deserialized: NesSuggestion = serde_json::from_value(json).unwrap();
3264        assert_eq!(deserialized, suggestion);
3265    }
3266
3267    #[test]
3268    fn test_nes_suggestion_rename_serialization() {
3269        let suggestion = NesSuggestion::Rename(NesRenameSuggestion::new(
3270            "sugg_003",
3271            "file:///path/to/file.rs",
3272            Position::new(5, 10),
3273            "calculateTotal",
3274        ));
3275
3276        let json = serde_json::to_value(&suggestion).unwrap();
3277        assert_eq!(
3278            json,
3279            json!({
3280                "kind": "rename",
3281                "suggestionId": "sugg_003",
3282                "uri": "file:///path/to/file.rs",
3283                "position": { "line": 5, "character": 10 },
3284                "newName": "calculateTotal"
3285            })
3286        );
3287
3288        let deserialized: NesSuggestion = serde_json::from_value(json).unwrap();
3289        assert_eq!(deserialized, suggestion);
3290    }
3291
3292    #[test]
3293    fn test_nes_suggestion_search_and_replace_serialization() {
3294        let suggestion = NesSuggestion::SearchAndReplace(
3295            NesSearchAndReplaceSuggestion::new(
3296                "sugg_004",
3297                "file:///path/to/file.rs",
3298                "oldFunction",
3299                "newFunction",
3300            )
3301            .is_regex(false),
3302        );
3303
3304        let json = serde_json::to_value(&suggestion).unwrap();
3305        assert_eq!(
3306            json,
3307            json!({
3308                "kind": "searchAndReplace",
3309                "suggestionId": "sugg_004",
3310                "uri": "file:///path/to/file.rs",
3311                "search": "oldFunction",
3312                "replace": "newFunction",
3313                "isRegex": false
3314            })
3315        );
3316
3317        let deserialized: NesSuggestion = serde_json::from_value(json).unwrap();
3318        assert_eq!(deserialized, suggestion);
3319    }
3320
3321    #[test]
3322    fn test_nes_start_request_serialization() {
3323        let request = StartNesRequest::new()
3324            .workspace_uri("file:///Users/alice/projects/my-app")
3325            .workspace_folders(vec![WorkspaceFolder::new(
3326                "file:///Users/alice/projects/my-app",
3327                "my-app",
3328            )])
3329            .repository(NesRepository::new(
3330                "my-app",
3331                "alice",
3332                "https://github.com/alice/my-app.git",
3333            ));
3334
3335        let json = serde_json::to_value(&request).unwrap();
3336        assert_eq!(
3337            json,
3338            json!({
3339                "workspaceUri": "file:///Users/alice/projects/my-app",
3340                "workspaceFolders": [
3341                    {
3342                        "uri": "file:///Users/alice/projects/my-app",
3343                        "name": "my-app"
3344                    }
3345                ],
3346                "repository": {
3347                    "name": "my-app",
3348                    "owner": "alice",
3349                    "remoteUrl": "https://github.com/alice/my-app.git"
3350                }
3351            })
3352        );
3353    }
3354
3355    #[test]
3356    fn test_nes_start_response_serialization() {
3357        let response = StartNesResponse::new("session_abc123");
3358        let json = serde_json::to_value(&response).unwrap();
3359        assert_eq!(json, json!({ "sessionId": "session_abc123" }));
3360    }
3361
3362    #[test]
3363    fn test_nes_trigger_kind_serialization() {
3364        assert_eq!(
3365            serde_json::to_value(&NesTriggerKind::Automatic).unwrap(),
3366            json!("automatic")
3367        );
3368        assert_eq!(
3369            serde_json::to_value(&NesTriggerKind::Diagnostic).unwrap(),
3370            json!("diagnostic")
3371        );
3372        assert_eq!(
3373            serde_json::to_value(&NesTriggerKind::Manual).unwrap(),
3374            json!("manual")
3375        );
3376    }
3377
3378    #[test]
3379    fn test_nes_reject_reason_serialization() {
3380        assert_eq!(
3381            serde_json::to_value(&NesRejectReason::Rejected).unwrap(),
3382            json!("rejected")
3383        );
3384        assert_eq!(
3385            serde_json::to_value(&NesRejectReason::Ignored).unwrap(),
3386            json!("ignored")
3387        );
3388        assert_eq!(
3389            serde_json::to_value(&NesRejectReason::Replaced).unwrap(),
3390            json!("replaced")
3391        );
3392        assert_eq!(
3393            serde_json::to_value(&NesRejectReason::Cancelled).unwrap(),
3394            json!("cancelled")
3395        );
3396    }
3397
3398    #[test]
3399    fn test_nes_accept_notification_serialization() {
3400        let notification = AcceptNesNotification::new("session_123", "sugg_001");
3401        let json = serde_json::to_value(&notification).unwrap();
3402        assert_eq!(
3403            json,
3404            json!({ "sessionId": "session_123", "suggestionId": "sugg_001" })
3405        );
3406    }
3407
3408    #[test]
3409    fn test_nes_reject_notification_serialization() {
3410        let notification =
3411            RejectNesNotification::new("session_123", "sugg_001").reason(NesRejectReason::Rejected);
3412        let json = serde_json::to_value(&notification).unwrap();
3413        assert_eq!(
3414            json,
3415            json!({ "sessionId": "session_123", "suggestionId": "sugg_001", "reason": "rejected" })
3416        );
3417    }
3418
3419    #[test]
3420    fn test_nes_suggest_request_with_context_serialization() {
3421        let request = SuggestNesRequest::new(
3422            "session_123",
3423            "file:///path/to/file.rs",
3424            2,
3425            Position::new(5, 12),
3426            NesTriggerKind::Automatic,
3427        )
3428        .selection(Range::new(Position::new(5, 4), Position::new(5, 12)))
3429        .context(
3430            NesSuggestContext::new()
3431                .recent_files(vec![NesRecentFile::new(
3432                    "file:///path/to/utils.rs",
3433                    "rust",
3434                    "pub fn helper() -> i32 { 42 }\n",
3435                )])
3436                .diagnostics(vec![NesDiagnostic::new(
3437                    "file:///path/to/file.rs",
3438                    Range::new(Position::new(5, 0), Position::new(5, 10)),
3439                    NesDiagnosticSeverity::Error,
3440                    "cannot find value `foo` in this scope",
3441                )]),
3442        );
3443
3444        let json = serde_json::to_value(&request).unwrap();
3445        assert_eq!(json["sessionId"], "session_123");
3446        assert_eq!(json["uri"], "file:///path/to/file.rs");
3447        assert_eq!(json["version"], 2);
3448        assert_eq!(json["triggerKind"], "automatic");
3449        assert_eq!(
3450            json["context"]["recentFiles"][0]["uri"],
3451            "file:///path/to/utils.rs"
3452        );
3453        assert_eq!(json["context"]["diagnostics"][0]["severity"], "error");
3454    }
3455
3456    #[test]
3457    fn test_text_document_sync_kind_serialization() {
3458        assert_eq!(
3459            serde_json::to_value(&TextDocumentSyncKind::Full).unwrap(),
3460            json!("full")
3461        );
3462        assert_eq!(
3463            serde_json::to_value(&TextDocumentSyncKind::Incremental).unwrap(),
3464            json!("incremental")
3465        );
3466        assert!(serde_json::from_value::<TextDocumentSyncKind>(json!("_future")).is_err());
3467    }
3468
3469    #[test]
3470    fn test_document_event_capabilities_drop_unknown_did_change_sync_kind() {
3471        let caps: NesDocumentEventCapabilities = serde_json::from_value(json!({
3472            "didChange": {
3473                "syncKind": "_future"
3474            }
3475        }))
3476        .unwrap();
3477
3478        assert_eq!(caps.did_change, None);
3479    }
3480
3481    #[test]
3482    fn test_document_did_change_capabilities_requires_sync_kind() {
3483        assert!(serde_json::from_value::<NesDocumentDidChangeCapabilities>(json!({})).is_err());
3484    }
3485
3486    #[test]
3487    fn test_nes_suggest_response_serialization() {
3488        let response = SuggestNesResponse::new(vec![
3489            NesSuggestion::Edit(NesEditSuggestion::new(
3490                "sugg_001",
3491                "file:///path/to/file.rs",
3492                vec![NesTextEdit::new(
3493                    Range::new(Position::new(5, 0), Position::new(5, 10)),
3494                    "let result = helper();",
3495                )],
3496            )),
3497            NesSuggestion::Jump(NesJumpSuggestion::new(
3498                "sugg_002",
3499                "file:///path/to/other.rs",
3500                Position::new(10, 0),
3501            )),
3502        ]);
3503
3504        let json = serde_json::to_value(&response).unwrap();
3505        assert_eq!(json["suggestions"].as_array().unwrap().len(), 2);
3506        assert_eq!(json["suggestions"][0]["kind"], "edit");
3507        assert_eq!(json["suggestions"][1]["kind"], "jump");
3508    }
3509}