From c347320c8b24fa941c73c9bb014dffff87cc2d6e Mon Sep 17 00:00:00 2001 From: Lei Gao Date: Tue, 22 Jul 2025 20:43:13 -0700 Subject: [PATCH 1/2] fix race condition when accepting inline completion --- packages/amazonq/src/app/inline/completion.ts | 35 ++++++++----------- 1 file changed, 14 insertions(+), 21 deletions(-) diff --git a/packages/amazonq/src/app/inline/completion.ts b/packages/amazonq/src/app/inline/completion.ts index 9020deac824..cf2e7f66878 100644 --- a/packages/amazonq/src/app/inline/completion.ts +++ b/packages/amazonq/src/app/inline/completion.ts @@ -34,7 +34,6 @@ import { vsCodeState, inlineCompletionsDebounceDelay, noInlineSuggestionsMsg, - ReferenceInlineProvider, getDiagnosticsDifferences, getDiagnosticsOfCurrentFile, toIdeDiagnostics, @@ -114,12 +113,7 @@ export class InlineCompletionManager implements Disposable { // TODO: also log the seen state for other suggestions in session // Calculate timing metrics before diagnostic delay const totalSessionDisplayTime = performance.now() - requestStartTime - await sleep(1000) - const diagnosticDiff = getDiagnosticsDifferences( - this.sessionManager.getActiveSession()?.diagnosticsBeforeAccept, - getDiagnosticsOfCurrentFile() - ) - const params: LogInlineCompletionSessionResultsParams = { + let params: LogInlineCompletionSessionResultsParams = { sessionId: sessionId, completionSessionResult: { [item.itemId]: { @@ -130,10 +124,9 @@ export class InlineCompletionManager implements Disposable { }, totalSessionDisplayTime: totalSessionDisplayTime, firstCompletionDisplayLatency: firstCompletionDisplayLatency, - addedDiagnostics: diagnosticDiff.added.map((it) => toIdeDiagnostics(it)), - removedDiagnostics: diagnosticDiff.removed.map((it) => toIdeDiagnostics(it)), + addedDiagnostics: [], + removedDiagnostics: [], } - this.languageClient.sendNotification(this.logSessionResultMessageName, params) this.disposable.dispose() this.disposable = languages.registerInlineCompletionItemProvider( CodeWhispererConstants.platformLanguageIds, @@ -147,23 +140,23 @@ export class InlineCompletionManager implements Disposable { ) ReferenceLogViewProvider.instance.addReferenceLog(referenceLog) ReferenceHoverProvider.instance.addCodeReferences(item.insertText as string, item.references) - - // Show codelense for 5 seconds. - ReferenceInlineProvider.instance.setInlineReference( - startLine, - item.insertText as string, - item.references - ) - setTimeout(() => { - ReferenceInlineProvider.instance.removeInlineReference() - }, 5000) } if (item.mostRelevantMissingImports?.length) { await ImportAdderProvider.instance.onAcceptRecommendation(editor, item, startLine) } this.sessionManager.incrementSuggestionCount() - // clear session manager states once accepted + // clear session manager states immediately once accepted this.sessionManager.clear() + + // compute diagnostics differences AFTER the session is cleared. + await sleep(1000) + const diagnosticDiff = getDiagnosticsDifferences( + this.sessionManager.getActiveSession()?.diagnosticsBeforeAccept, + getDiagnosticsOfCurrentFile() + ) + params.addedDiagnostics = diagnosticDiff.added.map((it) => toIdeDiagnostics(it)) + params.removedDiagnostics = diagnosticDiff.removed.map((it) => toIdeDiagnostics(it)) + this.languageClient.sendNotification(this.logSessionResultMessageName, params) } commands.registerCommand('aws.amazonq.acceptInline', onInlineAcceptance) From e0388e38bac2f2eef28d7f278c5cde21a15889a9 Mon Sep 17 00:00:00 2001 From: Lei Gao Date: Tue, 22 Jul 2025 21:33:26 -0700 Subject: [PATCH 2/2] fix race condition --- packages/amazonq/src/app/inline/completion.ts | 140 +++++++++--------- 1 file changed, 73 insertions(+), 67 deletions(-) diff --git a/packages/amazonq/src/app/inline/completion.ts b/packages/amazonq/src/app/inline/completion.ts index cf2e7f66878..595ad6d31cd 100644 --- a/packages/amazonq/src/app/inline/completion.ts +++ b/packages/amazonq/src/app/inline/completion.ts @@ -110,82 +110,88 @@ export class InlineCompletionManager implements Disposable { startLine: number, firstCompletionDisplayLatency?: number ) => { - // TODO: also log the seen state for other suggestions in session - // Calculate timing metrics before diagnostic delay - const totalSessionDisplayTime = performance.now() - requestStartTime - let params: LogInlineCompletionSessionResultsParams = { - sessionId: sessionId, - completionSessionResult: { - [item.itemId]: { - seen: true, - accepted: true, - discarded: false, + try { + vsCodeState.isCodeWhispererEditing = true + // TODO: also log the seen state for other suggestions in session + // Calculate timing metrics before diagnostic delay + const totalSessionDisplayTime = performance.now() - requestStartTime + await sleep(500) + const diagnosticDiff = getDiagnosticsDifferences( + this.sessionManager.getActiveSession()?.diagnosticsBeforeAccept, + getDiagnosticsOfCurrentFile() + ) + const params: LogInlineCompletionSessionResultsParams = { + sessionId: sessionId, + completionSessionResult: { + [item.itemId]: { + seen: true, + accepted: true, + discarded: false, + }, }, - }, - totalSessionDisplayTime: totalSessionDisplayTime, - firstCompletionDisplayLatency: firstCompletionDisplayLatency, - addedDiagnostics: [], - removedDiagnostics: [], - } - this.disposable.dispose() - this.disposable = languages.registerInlineCompletionItemProvider( - CodeWhispererConstants.platformLanguageIds, - this.inlineCompletionProvider - ) - if (item.references && item.references.length) { - const referenceLog = ReferenceLogViewProvider.getReferenceLog( - item.insertText as string, - item.references, - editor + totalSessionDisplayTime: totalSessionDisplayTime, + firstCompletionDisplayLatency: firstCompletionDisplayLatency, + addedDiagnostics: diagnosticDiff.added.map((it) => toIdeDiagnostics(it)), + removedDiagnostics: diagnosticDiff.removed.map((it) => toIdeDiagnostics(it)), + } + this.languageClient.sendNotification(this.logSessionResultMessageName, params) + this.disposable.dispose() + this.disposable = languages.registerInlineCompletionItemProvider( + CodeWhispererConstants.platformLanguageIds, + this.inlineCompletionProvider ) - ReferenceLogViewProvider.instance.addReferenceLog(referenceLog) - ReferenceHoverProvider.instance.addCodeReferences(item.insertText as string, item.references) - } - if (item.mostRelevantMissingImports?.length) { - await ImportAdderProvider.instance.onAcceptRecommendation(editor, item, startLine) + if (item.references && item.references.length) { + const referenceLog = ReferenceLogViewProvider.getReferenceLog( + item.insertText as string, + item.references, + editor + ) + ReferenceLogViewProvider.instance.addReferenceLog(referenceLog) + ReferenceHoverProvider.instance.addCodeReferences(item.insertText as string, item.references) + } + if (item.mostRelevantMissingImports?.length) { + await ImportAdderProvider.instance.onAcceptRecommendation(editor, item, startLine) + } + this.sessionManager.incrementSuggestionCount() + // clear session manager states once accepted + this.sessionManager.clear() + } finally { + vsCodeState.isCodeWhispererEditing = false } - this.sessionManager.incrementSuggestionCount() - // clear session manager states immediately once accepted - this.sessionManager.clear() - - // compute diagnostics differences AFTER the session is cleared. - await sleep(1000) - const diagnosticDiff = getDiagnosticsDifferences( - this.sessionManager.getActiveSession()?.diagnosticsBeforeAccept, - getDiagnosticsOfCurrentFile() - ) - params.addedDiagnostics = diagnosticDiff.added.map((it) => toIdeDiagnostics(it)) - params.removedDiagnostics = diagnosticDiff.removed.map((it) => toIdeDiagnostics(it)) - this.languageClient.sendNotification(this.logSessionResultMessageName, params) } commands.registerCommand('aws.amazonq.acceptInline', onInlineAcceptance) const onInlineRejection = async () => { - await commands.executeCommand('editor.action.inlineSuggest.hide') - // TODO: also log the seen state for other suggestions in session - this.disposable.dispose() - this.disposable = languages.registerInlineCompletionItemProvider( - CodeWhispererConstants.platformLanguageIds, - this.inlineCompletionProvider - ) - const sessionId = this.sessionManager.getActiveSession()?.sessionId - const itemId = this.sessionManager.getActiveRecommendation()[0]?.itemId - if (!sessionId || !itemId) { - return - } - const params: LogInlineCompletionSessionResultsParams = { - sessionId: sessionId, - completionSessionResult: { - [itemId]: { - seen: true, - accepted: false, - discarded: false, + try { + vsCodeState.isCodeWhispererEditing = true + await commands.executeCommand('editor.action.inlineSuggest.hide') + // TODO: also log the seen state for other suggestions in session + this.disposable.dispose() + this.disposable = languages.registerInlineCompletionItemProvider( + CodeWhispererConstants.platformLanguageIds, + this.inlineCompletionProvider + ) + const sessionId = this.sessionManager.getActiveSession()?.sessionId + const itemId = this.sessionManager.getActiveRecommendation()[0]?.itemId + if (!sessionId || !itemId) { + return + } + const params: LogInlineCompletionSessionResultsParams = { + sessionId: sessionId, + completionSessionResult: { + [itemId]: { + seen: true, + accepted: false, + discarded: false, + }, }, - }, + } + this.languageClient.sendNotification(this.logSessionResultMessageName, params) + // clear session manager states once rejected + this.sessionManager.clear() + } finally { + vsCodeState.isCodeWhispererEditing = false } - this.languageClient.sendNotification(this.logSessionResultMessageName, params) - // clear session manager states once rejected - this.sessionManager.clear() } commands.registerCommand('aws.amazonq.rejectCodeSuggestion', onInlineRejection) }