Skip to content

Commit 7bf4cd0

Browse files
authored
feat - Add NES-specific telemetry support (#1511)
* add nes related telemetry * resolve comments * resolve missing import
1 parent 4729341 commit 7bf4cd0

5 files changed

Lines changed: 200 additions & 33 deletions

File tree

com.microsoft.copilot.eclipse.core/src/com/microsoft/copilot/eclipse/core/lsp/CopilotLanguageServer.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import java.util.List;
44
import java.util.concurrent.CompletableFuture;
55

6+
import org.eclipse.lsp4j.jsonrpc.services.JsonNotification;
67
import org.eclipse.lsp4j.jsonrpc.services.JsonRequest;
78
import org.eclipse.lsp4j.services.LanguageServer;
89

@@ -27,6 +28,7 @@
2728
import com.microsoft.copilot.eclipse.core.lsp.protocol.ConversationTurnParams;
2829
import com.microsoft.copilot.eclipse.core.lsp.protocol.CopilotModel;
2930
import com.microsoft.copilot.eclipse.core.lsp.protocol.CopilotStatusResult;
31+
import com.microsoft.copilot.eclipse.core.lsp.protocol.DidShowInlineEditParams;
3032
import com.microsoft.copilot.eclipse.core.lsp.protocol.LanguageModelToolInformation;
3133
import com.microsoft.copilot.eclipse.core.lsp.protocol.NextEditSuggestionsParams;
3234
import com.microsoft.copilot.eclipse.core.lsp.protocol.NextEditSuggestionsResult;
@@ -261,4 +263,10 @@ public interface CopilotLanguageServer extends LanguageServer {
261263
*/
262264
@JsonRequest("githubApi/searchPR")
263265
CompletableFuture<SearchPrResponse> searchPr(SearchPrParams params);
266+
267+
/**
268+
* Notify that an inline edit was shown.
269+
*/
270+
@JsonNotification("textDocument/didShowInlineEdit")
271+
void didShowInlineEdit(DidShowInlineEditParams params);
264272
}

com.microsoft.copilot.eclipse.core/src/com/microsoft/copilot/eclipse/core/lsp/CopilotLanguageServerConnection.java

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,9 @@
1111
import org.eclipse.jface.text.IDocument;
1212
import org.eclipse.lsp4e.LSPEclipseUtils;
1313
import org.eclipse.lsp4e.LanguageServerWrapper;
14+
import org.eclipse.lsp4j.Command;
1415
import org.eclipse.lsp4j.DidChangeConfigurationParams;
16+
import org.eclipse.lsp4j.ExecuteCommandParams;
1517
import org.eclipse.lsp4j.ProgressParams;
1618
import org.eclipse.lsp4j.Range;
1719
import org.eclipse.lsp4j.TextDocumentIdentifier;
@@ -44,6 +46,7 @@
4446
import com.microsoft.copilot.eclipse.core.lsp.protocol.CopilotModel;
4547
import com.microsoft.copilot.eclipse.core.lsp.protocol.CopilotStatusResult;
4648
import com.microsoft.copilot.eclipse.core.lsp.protocol.DidChangeCopilotWatchedFilesParams;
49+
import com.microsoft.copilot.eclipse.core.lsp.protocol.DidShowInlineEditParams;
4750
import com.microsoft.copilot.eclipse.core.lsp.protocol.LanguageModelToolInformation;
4851
import com.microsoft.copilot.eclipse.core.lsp.protocol.NextEditSuggestionsParams;
4952
import com.microsoft.copilot.eclipse.core.lsp.protocol.NextEditSuggestionsResult;
@@ -633,6 +636,32 @@ public CompletableFuture<SearchPrResponse> searchPr(SearchPrParams params) {
633636
return this.languageServerWrapper.execute(fn);
634637
}
635638

639+
640+
/**
641+
* Notify that an inline edit was shown.
642+
*/
643+
public void didShowInlineEdit(DidShowInlineEditParams params) {
644+
this.languageServerWrapper.sendNotification(server -> ((CopilotLanguageServer) server).didShowInlineEdit(params));
645+
}
646+
647+
/**
648+
* Accept the next edit suggestion (inline edit).
649+
*/
650+
public CompletableFuture<Object> acceptNextEditSuggestion(Command command) {
651+
if (command == null) {
652+
return CompletableFuture.completedFuture(null);
653+
}
654+
ExecuteCommandParams params = new ExecuteCommandParams();
655+
params.setCommand("github.copilot.didAcceptNextEditSuggestionItem");
656+
List<Object> arguments = command.getArguments();
657+
if (arguments != null) {
658+
params.setArguments(arguments);
659+
}
660+
Function<LanguageServer, CompletableFuture<Object>> fn = server -> server.getWorkspaceService()
661+
.executeCommand(params);
662+
return this.languageServerWrapper.execute(fn);
663+
}
664+
636665
/**
637666
* Stop the language server.
638667
*/
Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
package com.microsoft.copilot.eclipse.core.lsp.protocol;
2+
3+
import java.util.Collections;
4+
import java.util.List;
5+
import java.util.Objects;
6+
7+
import org.eclipse.lsp4j.jsonrpc.util.ToStringBuilder;
8+
import org.eclipse.lsp4j.jsonrpc.validation.NonNull;
9+
10+
/**
11+
* Params for textDocument/didShowInlineEdit notification.
12+
*/
13+
public class DidShowInlineEditParams {
14+
@NonNull
15+
private Item item;
16+
17+
/**
18+
* Creates a new DidShowInlineEditParams.
19+
*
20+
* @param item the item containing the command wrapper
21+
*/
22+
public DidShowInlineEditParams(Item item) {
23+
this.item = item;
24+
}
25+
26+
/**
27+
* Creates a DidShowInlineEditParams from a suggestion UUID.
28+
*
29+
* @param uuid the suggestion UUID
30+
* @return the params object
31+
*/
32+
public static DidShowInlineEditParams fromUuid(String uuid) {
33+
CommandWrapper cmd = new CommandWrapper(Collections.singletonList(uuid));
34+
Item item = new Item(cmd);
35+
return new DidShowInlineEditParams(item);
36+
}
37+
38+
public Item getItem() {
39+
return item;
40+
}
41+
42+
public void setItem(Item item) {
43+
this.item = item;
44+
}
45+
46+
@Override
47+
public String toString() {
48+
return new ToStringBuilder(this).add("item", item).toString();
49+
}
50+
51+
@Override
52+
public int hashCode() {
53+
return Objects.hash(item);
54+
}
55+
56+
@Override
57+
public boolean equals(Object o) {
58+
return this == o || (o instanceof DidShowInlineEditParams r && Objects.equals(item, r.item));
59+
}
60+
61+
/**
62+
* Item containing the command wrapper.
63+
*/
64+
public static class Item {
65+
@NonNull
66+
private CommandWrapper command;
67+
68+
/**
69+
* Creates a new Item.
70+
*
71+
* @param command the command wrapper
72+
*/
73+
public Item(CommandWrapper command) {
74+
this.command = command;
75+
}
76+
77+
public CommandWrapper getCommand() {
78+
return command;
79+
}
80+
81+
public void setCommand(CommandWrapper command) {
82+
this.command = command;
83+
}
84+
85+
@Override
86+
public String toString() {
87+
return new ToStringBuilder(this).add("command", command).toString();
88+
}
89+
90+
@Override
91+
public int hashCode() {
92+
return Objects.hash(command);
93+
}
94+
95+
@Override
96+
public boolean equals(Object o) {
97+
return this == o || (o instanceof Item r && Objects.equals(command, r.command));
98+
}
99+
}
100+
101+
/**
102+
* Wrapper for command arguments.
103+
*/
104+
public static class CommandWrapper {
105+
@NonNull
106+
private List<String> arguments;
107+
108+
/**
109+
* Creates a new CommandWrapper.
110+
*
111+
* @param arguments the list of command arguments
112+
*/
113+
public CommandWrapper(List<String> arguments) {
114+
this.arguments = arguments;
115+
}
116+
117+
public List<String> getArguments() {
118+
return arguments;
119+
}
120+
121+
public void setArguments(List<String> arguments) {
122+
this.arguments = arguments;
123+
}
124+
125+
@Override
126+
public String toString() {
127+
return new ToStringBuilder(this).add("arguments", arguments).toString();
128+
}
129+
130+
@Override
131+
public int hashCode() {
132+
return Objects.hash(arguments);
133+
}
134+
135+
@Override
136+
public boolean equals(Object o) {
137+
return this == o || (o instanceof CommandWrapper r && Objects.equals(arguments, r.arguments));
138+
}
139+
}
140+
}

com.microsoft.copilot.eclipse.core/src/com/microsoft/copilot/eclipse/core/lsp/protocol/NextEditSuggestionsResult.java

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import java.util.List;
44
import java.util.Objects;
55

6+
import com.google.gson.JsonPrimitive;
67
import org.apache.commons.lang3.builder.ToStringBuilder;
78
import org.eclipse.lsp4j.Command;
89
import org.eclipse.lsp4j.Range;
@@ -90,7 +91,14 @@ public String getUuid() {
9091
return null;
9192
}
9293
Object arg0 = command.getArguments().get(0);
93-
return arg0 == null ? null : arg0.toString();
94+
if (arg0 == null) {
95+
return null;
96+
}
97+
// Handle JsonPrimitive from Gson deserialization
98+
if (arg0 instanceof JsonPrimitive jsonPrimitive) {
99+
return jsonPrimitive.getAsString();
100+
}
101+
return arg0.toString();
94102
}
95103
}
96104
}

com.microsoft.copilot.eclipse.ui/src/com/microsoft/copilot/eclipse/ui/nes/RenderManager.java

Lines changed: 14 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package com.microsoft.copilot.eclipse.ui.nes;
22

33
import java.net.URI;
4-
import java.util.Collections;
54

65
import org.apache.commons.lang3.StringUtils;
76
import org.eclipse.core.resources.IFile;
@@ -21,11 +20,11 @@
2120
import org.eclipse.jface.text.TextSelection;
2221
import org.eclipse.jface.text.source.IAnnotationModel;
2322
import org.eclipse.jface.text.source.IAnnotationModelListener;
24-
import org.eclipse.jface.text.source.ISourceViewer;
2523
import org.eclipse.jface.text.source.projection.ProjectionAnnotation;
2624
import org.eclipse.jface.text.source.projection.ProjectionViewer;
2725
import org.eclipse.jface.util.IPropertyChangeListener;
2826
import org.eclipse.lsp4e.LSPEclipseUtils;
27+
import org.eclipse.lsp4j.Command;
2928
import org.eclipse.lsp4j.Range;
3029
import org.eclipse.swt.SWT;
3130
import org.eclipse.swt.custom.StyledText;
@@ -36,12 +35,11 @@
3635
import com.microsoft.copilot.eclipse.core.CopilotCore;
3736
import com.microsoft.copilot.eclipse.core.events.CopilotEventConstants;
3837
import com.microsoft.copilot.eclipse.core.lsp.CopilotLanguageServerConnection;
38+
import com.microsoft.copilot.eclipse.core.lsp.protocol.DidShowInlineEditParams;
3939
import com.microsoft.copilot.eclipse.core.lsp.protocol.NextEditSuggestionsResult.CopilotInlineEdit;
40-
import com.microsoft.copilot.eclipse.core.lsp.protocol.NotifyAcceptedParams;
41-
import com.microsoft.copilot.eclipse.core.lsp.protocol.NotifyRejectedParams;
42-
import com.microsoft.copilot.eclipse.core.lsp.protocol.NotifyShownParams;
4340
import com.microsoft.copilot.eclipse.core.nes.NextEditSuggestionListener;
4441
import com.microsoft.copilot.eclipse.core.nes.NextEditSuggestionProvider;
42+
import com.microsoft.copilot.eclipse.core.utils.FileUtils;
4543
import com.microsoft.copilot.eclipse.ui.CopilotUi;
4644
import com.microsoft.copilot.eclipse.ui.utils.CompletionUtils;
4745
import com.microsoft.copilot.eclipse.ui.utils.SwtUtils;
@@ -88,6 +86,7 @@ public boolean isPureInsert() {
8886
private Range lastRange; // precise range of current suggestion
8987
private IFile lastFile; // track file for extension-based fallback
9088
private String currentSuggestionUuid; // UUID for telemetry
89+
private Command currentSuggestionCommand; // Command for acceptance
9190
private int suggestionDocumentVersion = -1; // document version when suggestion was received
9291
private Position suggestionStartPosition; // start offset of suggestion range
9392
private Position suggestionEndPosition; // end offset of suggestion range
@@ -332,6 +331,7 @@ private void clearSuggestionData() {
332331
diffModel = null;
333332
lastRange = null;
334333
currentSuggestionUuid = null;
334+
currentSuggestionCommand = null;
335335
suggestionDocumentVersion = -1;
336336
}
337337

@@ -343,8 +343,6 @@ public void clearSuggestion() {
343343
return;
344344
}
345345
nesProvider.cancelCurrentRequest();
346-
notifyRejected();
347-
348346
SwtUtils.invokeOnDisplayThread(() -> {
349347
clearSuggestionUi();
350348
clearSuggestionData();
@@ -505,6 +503,7 @@ public void onNextEditSuggestion(IFile file, CopilotInlineEdit edit) {
505503
this.lastFile = file;
506504
this.lastRange = range;
507505
this.currentSuggestionUuid = edit.getUuid();
506+
this.currentSuggestionCommand = edit.getCommand();
508507
this.suggestionDocumentVersion = edit.getTextDocument() != null && edit.getTextDocument().getVersion() != null
509508
? edit.getTextDocument().getVersion()
510509
: -1;
@@ -533,7 +532,7 @@ public void onNextEditSuggestion(IFile file, CopilotInlineEdit edit) {
533532

534533
private boolean isCurrentDocument(IDocument doc, IFile file) {
535534
URI currentDocUri = LSPEclipseUtils.toUri(doc);
536-
String fileUriString = file != null ? com.microsoft.copilot.eclipse.core.utils.FileUtils.getResourceUri(file)
535+
String fileUriString = file != null ? FileUtils.getResourceUri(file)
537536
: null;
538537
return currentDocUri != null && fileUriString != null && currentDocUri.toString().equals(fileUriString);
539538
}
@@ -769,6 +768,8 @@ public void acceptSuggestion() {
769768
diffPopup.hideAndClearIndent(text, viewer, indentLinePosition);
770769
}, text);
771770

771+
notifyAccepted();
772+
772773
// Apply replacement (document operation)
773774
String replacement = diffModel.replacement == null ? "" : diffModel.replacement;
774775
String lineDelimiter = CompletionUtils.getDocumentLineDelimiter(doc, startOff);
@@ -785,9 +786,8 @@ public void acceptSuggestion() {
785786
clearSuggestionUi();
786787
}, text);
787788

788-
// Clear data and notify (non-UI operations)
789+
// Clear data
789790
clearSuggestionData();
790-
notifyAccepted();
791791
scheduleNextSuggestionRequest(doc, currentFile, newCaretOffset);
792792

793793
} catch (BadLocationException ex) {
@@ -909,8 +909,8 @@ private void notifyShown() {
909909
return;
910910
}
911911
try {
912-
NotifyShownParams params = new NotifyShownParams(currentSuggestionUuid);
913-
lsConnection.notifyShown(params);
912+
DidShowInlineEditParams params = DidShowInlineEditParams.fromUuid(currentSuggestionUuid);
913+
lsConnection.didShowInlineEdit(params);
914914
} catch (Exception e) {
915915
CopilotCore.LOGGER.error("Failed to notify shown telemetry", e);
916916
}
@@ -920,31 +920,13 @@ private void notifyShown() {
920920
* Notify Language Server that suggestion is accepted (telemetry).
921921
*/
922922
private void notifyAccepted() {
923-
if (currentSuggestionUuid == null || lsConnection == null) {
923+
if (currentSuggestionCommand == null || lsConnection == null) {
924924
return;
925925
}
926926
try {
927-
NotifyAcceptedParams params = new NotifyAcceptedParams(currentSuggestionUuid);
928-
lsConnection.notifyAccepted(params);
929-
currentSuggestionUuid = null; // Clear after accepting
927+
lsConnection.acceptNextEditSuggestion(currentSuggestionCommand);
930928
} catch (Exception e) {
931929
CopilotCore.LOGGER.error("Failed to notify accepted telemetry", e);
932930
}
933931
}
934-
935-
/**
936-
* Notify Language Server that suggestion is rejected (telemetry).
937-
*/
938-
private void notifyRejected() {
939-
if (currentSuggestionUuid == null || lsConnection == null) {
940-
return;
941-
}
942-
try {
943-
NotifyRejectedParams params = new NotifyRejectedParams(Collections.singletonList(currentSuggestionUuid));
944-
lsConnection.notifyRejected(params);
945-
currentSuggestionUuid = null; // Clear after rejecting
946-
} catch (Exception e) {
947-
CopilotCore.LOGGER.error("Failed to notify rejected telemetry", e);
948-
}
949-
}
950932
}

0 commit comments

Comments
 (0)