Skip to main content

agent_client_protocol_schema/v1/
nes.rs

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