Skip to main content

agent_client_protocol_schema/v1/
nes.rs

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