Skip to content
33 changes: 22 additions & 11 deletions packages/amazonq/src/app/inline/EditRendering/displayImage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ export class EditDecorationManager {
private currentImageDecoration: vscode.DecorationOptions | undefined
private currentRemovedCodeDecorations: vscode.DecorationOptions[] = []
private acceptHandler: (() => void) | undefined
private rejectHandler: (() => void) | undefined
private rejectHandler: ((isDiscard: boolean) => void) | undefined

constructor() {
this.registerCommandHandlers()
Expand Down Expand Up @@ -131,7 +131,7 @@ export class EditDecorationManager {
svgImage: vscode.Uri,
startLine: number,
onAccept: () => Promise<void>,
onReject: () => Promise<void>,
onReject: (isDiscard: boolean) => Promise<void>,
originalCode: string,
newCode: string,
originalCodeHighlightRanges: Array<{ line: number; start: number; end: number }>
Expand Down Expand Up @@ -185,9 +185,9 @@ export class EditDecorationManager {
})

// Register Esc key handler for rejecting suggestion
vscode.commands.registerCommand('aws.amazonq.inline.rejectEdit', () => {
vscode.commands.registerCommand('aws.amazonq.inline.rejectEdit', (isDiscard: boolean = false) => {
if (this.rejectHandler) {
this.rejectHandler()
this.rejectHandler(isDiscard)
}
})
}
Expand Down Expand Up @@ -416,20 +416,31 @@ export async function displaySvgDecoration(
// )
// }
},
async () => {
async (isDiscard: boolean) => {
// Handle reject
getLogger().info('Edit suggestion rejected')
if (isDiscard) {
getLogger().info('Edit suggestion discarded')
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: getLogger().info(Edit suggestion ${state}) where state = isDiscard?? 'discarded': 'rejected

} else {
getLogger().info('Edit suggestion rejected')
}
await decorationManager.clearDecorations(editor)
documentChangeListener.dispose()
cursorChangeListener.dispose()
const suggestionState = isDiscard
? {
seen: false,
accepted: false,
discarded: true,
}
: {
seen: true,
accepted: false,
discarded: false,
}
const params: LogInlineCompletionSessionResultsParams = {
sessionId: session.sessionId,
completionSessionResult: {
[item.itemId]: {
seen: true,
accepted: false,
discarded: false,
},
[item.itemId]: suggestionState,
},
totalSessionDisplayTime: Date.now() - session.requestStartTime,
firstCompletionDisplayLatency: session.firstCompletionDisplayLatency,
Expand Down
8 changes: 8 additions & 0 deletions packages/amazonq/src/app/inline/editSuggestionState.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,20 @@
*/
export class EditSuggestionState {
private static isEditSuggestionCurrentlyActive = false
private static displayStartTime = performance.now()

static setEditSuggestionActive(active: boolean): void {
this.isEditSuggestionCurrentlyActive = active
if (active) {
this.displayStartTime = performance.now()
}
}

static isEditSuggestionActive(): boolean {
return this.isEditSuggestionCurrentlyActive
}

static isEditSuggestionDisplayingOverOneSecond(): boolean {
return this.isEditSuggestionActive() && performance.now() - this.displayStartTime > 1000
}
}
40 changes: 37 additions & 3 deletions packages/amazonq/src/app/inline/recommendationService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,9 @@ import {
inlineCompletionWithReferencesRequestType,
TextDocumentContentChangeEvent,
editCompletionRequestType,
LogInlineCompletionSessionResultsParams,
} from '@aws/language-server-runtimes/protocol'
import { CancellationToken, InlineCompletionContext, Position, TextDocument } from 'vscode'
import { CancellationToken, InlineCompletionContext, Position, TextDocument, commands } from 'vscode'
import { LanguageClient } from 'vscode-languageclient'
import { SessionManager } from './sessionManager'
import {
Expand All @@ -24,8 +25,8 @@ import { getLogger } from 'aws-core-vscode/shared'
import { DocumentEventListener } from './documentEventListener'
import { getOpenFilesInWindow } from 'aws-core-vscode/utils'
import { asyncCallWithTimeout } from '../../util/timeoutUtil'
import { EditSuggestionState } from './editSuggestionState'
import { extractFileContextInNotebooks } from './notebookUtil'
import { EditSuggestionState } from './editSuggestionState'

export interface GetAllRecommendationsOptions {
emitTelemetry?: boolean
Expand Down Expand Up @@ -137,7 +138,7 @@ export class RecommendationService {
* Completions use PartialResultToken with single 1 call of [getAllRecommendations].
* Edits leverage partialResultToken to achieve EditStreak such that clients can pull all continuous suggestions generated by the model within 1 EOS block.
*/
if (!isTriggerByDeletion && !request.partialResultToken && !EditSuggestionState.isEditSuggestionActive()) {
if (!isTriggerByDeletion && !request.partialResultToken) {
const completionPromise: Promise<InlineCompletionListWithReferences> = languageClient.sendRequest(
inlineCompletionWithReferencesRequestType.method,
request,
Expand Down Expand Up @@ -187,6 +188,39 @@ export class RecommendationService {
})),
})

if (result.items.length > 0 && result.items[0].isInlineEdit === false) {
// Completion will not be rendered if an edit suggestion has been active for longer than 1 second
if (EditSuggestionState.isEditSuggestionDisplayingOverOneSecond()) {
const session = this.sessionManager.getActiveSession()
if (!session) {
return []
}
const params: LogInlineCompletionSessionResultsParams = {
sessionId: session.sessionId,
completionSessionResult: Object.fromEntries(
result.items.map((item) => [
item.itemId,
{
seen: false,
accepted: false,
discarded: true,
},
])
),
}
languageClient.sendNotification('aws/logInlineCompletionSessionResults', params)
this.sessionManager.clear()
getLogger().info(
'Completion discarded due to active edit suggestion displayed longer than 1 second'
)
return []
} else if (EditSuggestionState.isEditSuggestionActive()) {
// discard the current edit suggestion if its display time is less than 1 sec
await commands.executeCommand('aws.amazonq.inline.rejectEdit', true)
getLogger().info('Discarding active edit suggestion displaying less than 1 second')
}
}

TelemetryHelper.instance.setSdkApiCallEndTime()
TelemetryHelper.instance.setSessionId(result.sessionId)
if (result.items.length > 0 && result.items[0].itemId !== undefined) {
Expand Down
Loading