Skip to main content

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