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