Skip to main content

agent_client_protocol_schema/v2/
nes.rs

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