Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Determine and send inline completion session result #323

Merged
merged 5 commits into from
Jan 15, 2025
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion plugin/META-INF/MANIFEST.MF
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@ Require-Bundle: org.eclipse.core.runtime;bundle-version="3.31.0",
org.eclipse.jetty.util;bundle-version="12.0.9",
org.eclipse.core.net;bundle-version="1.5.400",
org.apache.commons.logging;bundle-version="1.2.0",
slf4j.api;bundle-version="2.0.13"
slf4j.api;bundle-version="2.0.13",
org.apache.commons.lang3;bundle-version="3.14.0"
Bundle-Classpath: target/classes/,
target/dependency/annotations-2.28.26.jar,
target/dependency/apache-client-2.28.26.jar,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ public final synchronized Object execute(final ExecutionEvent event) throws Exec
var suggestion = QInvocationSession.getInstance().getCurrentSuggestion();
var widget = QInvocationSession.getInstance().getViewer().getTextWidget();
var session = QInvocationSession.getInstance();
// mark current suggestion as accepted
session.setAccepted(suggestion.getItemId());
session.setSuggestionAccepted(true);
session.transitionToDecisionMade();
Display display = widget.getDisplay();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import software.aws.toolkits.eclipse.amazonq.lsp.model.GetConfigurationFromServerParams;
import software.aws.toolkits.eclipse.amazonq.lsp.model.InlineCompletionParams;
import software.aws.toolkits.eclipse.amazonq.lsp.model.InlineCompletionResponse;
import software.aws.toolkits.eclipse.amazonq.lsp.model.LogInlineCompletionSessionResultsParams;
import software.aws.toolkits.eclipse.amazonq.lsp.model.LspServerConfigurations;
import software.aws.toolkits.eclipse.amazonq.lsp.model.UpdateCredentialsPayload;

Expand All @@ -30,6 +31,9 @@ public interface AmazonQLspServer extends LanguageServer {
@JsonRequest("aws/textDocument/inlineCompletionWithReferences")
CompletableFuture<InlineCompletionResponse> inlineCompletionWithReferences(InlineCompletionParams params);

@JsonNotification("aws/logInlineCompletionSessionResults")
void logInlineCompletionSessionResult(LogInlineCompletionSessionResultsParams params);

@JsonRequest("aws/chat/sendChatPrompt")
CompletableFuture<String> sendChatPrompt(EncryptedChatParams encryptedChatRequestParams);

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
// Copyright 2024 Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

package software.aws.toolkits.eclipse.amazonq.lsp.model;

public final class InlineCompletionStates {
// Indicates if suggestion has been seen by the user in the UI
private boolean seen;
// Indicates if suggestion accepted
private boolean accepted;
// Indicates if suggestion was filtered out on the client-side and marked as
// discarded.
private boolean discarded;

public boolean isSeen() {
return seen;
}

public void setSeen(final boolean seen) {
this.seen = seen;
}

public boolean isAccepted() {
return accepted;
}

public void setAccepted(final boolean accepted) {
this.accepted = accepted;
}

public boolean isDiscarded() {
return discarded;
}

public void setDiscarded(final boolean discarded) {
this.discarded = discarded;
}

@Override
public String toString() {
return String.format("{accepted=%b, seen=%b, discarded=%b}", accepted, seen, discarded);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
// Copyright 2024 Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

package software.aws.toolkits.eclipse.amazonq.lsp.model;

import java.util.concurrent.ConcurrentHashMap;

import com.fasterxml.jackson.annotation.JsonInclude;

public final class LogInlineCompletionSessionResultsParams {
// Session Id attached to get completion items response
private final String sessionId;
// Map with results of interaction with completion items/suggestions in the UI
private final ConcurrentHashMap<String, InlineCompletionStates> completionSessionResult;

// Total time when items from this suggestion session were visible in UI
@JsonInclude(JsonInclude.Include.NON_NULL)
private Long totalSessionDisplayTime;
// Time from request invocation start to rendering of the first suggestion in the UI.
@JsonInclude(JsonInclude.Include.NON_NULL)
private Long firstCompletionDisplayLatency;
// Length of additional characters inputed by user from when the trigger happens to when the first suggestion is about to be shown in UI
@JsonInclude(JsonInclude.Include.NON_NULL)
private Integer typeaheadLength;

public LogInlineCompletionSessionResultsParams(final String sessionId, final ConcurrentHashMap<String, InlineCompletionStates> completionSessionResult) {
this.sessionId = sessionId;
this.completionSessionResult = completionSessionResult;
}

public Long getTotalSessionDisplayTime() {
return totalSessionDisplayTime;
}

public void setTotalSessionDisplayTime(final Long totalSessionDisplayTime) {
this.totalSessionDisplayTime = totalSessionDisplayTime;
}

public Long getFirstCompletionDisplayLatency() {
return firstCompletionDisplayLatency;
}

public void setFirstCompletionDisplayLatency(final Long firstCompletionDisplayLatency) {
this.firstCompletionDisplayLatency = firstCompletionDisplayLatency;
}

public Integer getTypeaheadLength() {
return typeaheadLength;
}

public void setTypeaheadLength(final Integer typeaheadLength) {
this.typeaheadLength = typeaheadLength;
}

public ConcurrentHashMap<String, InlineCompletionStates> getCompletionSessionResult() {
return completionSessionResult;
}

public String getSessionId() {
return sessionId;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -274,18 +274,35 @@ public void documentChanged(final DocumentEvent event) {
}
String currentSuggestion = session.getCurrentSuggestion().getInsertText();
int currentOffset = widget.getCaretOffset();

if (input.isEmpty()) {
Activator.getLogger().info("distance traversed is 1:" + distanceTraversed);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure if we want to keep this in. This would get logged every time backspace is hit during a typeahead.
Same with the logging call made below.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

updated forgot to remove it

if (distanceTraversed <= 0) {
// discard all suggestions as caret position is less than request invocation position
session.updateCompletionStates(new ArrayList<String>());
session.transitionToDecisionMade();
session.end();
return;
}
distanceTraversed = typeaheadProcessor.getNewDistanceTraversedOnDeleteAndUpdateBracketState(
event.getLength(), distanceTraversed, brackets);
Activator.getLogger().info("distance traversed is" + distanceTraversed);
if (distanceTraversed < 0) {
// discard all suggestions as caret position is less than request invocation position
session.updateCompletionStates(new ArrayList<String>());
session.transitionToDecisionMade();
session.end();
}

// note: distanceTraversed as 0 is currently understood to be when a user presses BS removing any typeahead
if (distanceTraversed == 0) {
// reset completion states for all suggestions when user reverts to request
// invocation state
session.resetCompletionStates();
// mark currently displayed suggestion as seen
session.markSuggestionAsSeen();
}

return;
}

Expand Down Expand Up @@ -328,12 +345,19 @@ public void documentChanged(final DocumentEvent event) {
session.transitionToDecisionMade(lineToUnsetIndent);
Display.getCurrent().asyncExec(() -> {
if (session.isActive()) {
session.end();
// discard suggestions and end immediately as typeahead does not match
session.updateCompletionStates(new ArrayList<String>());
session.endImmediately();
}
});
return;
}

// discard all other suggestions except for current one as typeahead matches it
// also mark current one as seen as it continues to be displayed
session.updateCompletionStates(List.of(session.getCurrentSuggestion().getItemId()));
session.markSuggestionAsSeen();
Comment on lines +356 to +357
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When these two lines get run, it means that the user has typed ahead with a character that matches.
This means updateCompletionStates and markSuggestionAsSeen are going to be called for every correct character typed in a typeahead session, with the same suggestion.

Should we perhaps wrap them in a check to see if the user has just started the typeahead?

if (!session.hasBeenTypedahead()) {
    session.updateCompletionStates(List.of(session.getCurrentSuggestion().getItemId()));
    session.markSuggestionAsSeen();
}

Copy link
Contributor Author

@shruti0085 shruti0085 Jan 15, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this line would do the opposite of what we want to do here which is to mark when suggestions have been filtered because typeahead matches.
The above logic would do the opposite because it says if there is no typeahead then consider suggsestions as filtered and discard other suggestions except for current one as being filtered out.
Also wouldn't this always return true if we hit this line of code in this block(L349) session.hasBeenTypedahead() since this would only process when there is A typeahead?

are going to be called for every correct character typed in a typeahead session, with the same suggestion.

That is correct. Since this documentChange event is raised for any update, based on user's actions it could have been a backspace marking things not-discarded unseen in the previous stroke or any of the other checks before this line. Ideally the whole list of suggestions should be filtered down to match the typeahead prefix. However due to limitations in the current filtering logic we only show the current suggestion instead of other valid suggestions from the list. I think it still makes sense to have this because unless we can retain the information of the typedPrefix among other stuff this class does it is hard to know if typeahead actually diverged or not.


// Here we perform "post closing bracket insertion caret correction", which
// consists of the following:
// - Check if the input is a closing bracket
Expand Down Expand Up @@ -398,7 +422,7 @@ public void mouseDown(final MouseEvent e) {
int currentOffset = invocationOffset + distanceTraversed;
int lastKnownLine = widget.getLineAtOffset(currentOffset);
qInvocationSessionInstance.transitionToDecisionMade(lastKnownLine + 1);
qInvocationSessionInstance.end();
qInvocationSessionInstance.endImmediately();
return;
}

Expand Down
Loading
Loading