From 46d1ebdc693ff8082dbce243552480a2954c3170 Mon Sep 17 00:00:00 2001 From: Boyu Wang Date: Thu, 9 Oct 2025 10:10:56 -0700 Subject: [PATCH] fix(amazonq): prevent race condition in inline completion provider --- packages/amazonq/src/app/inline/completion.ts | 44 +++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/packages/amazonq/src/app/inline/completion.ts b/packages/amazonq/src/app/inline/completion.ts index 9c4f8e3ad20..c113d3cd2fb 100644 --- a/packages/amazonq/src/app/inline/completion.ts +++ b/packages/amazonq/src/app/inline/completion.ts @@ -213,6 +213,8 @@ export class InlineCompletionManager implements Disposable { export class AmazonQInlineCompletionItemProvider implements InlineCompletionItemProvider { private logger = getLogger() + private pendingRequest: Promise | undefined + constructor( private readonly languageClient: LanguageClient, private readonly recommendationService: RecommendationService, @@ -300,6 +302,48 @@ export class AmazonQInlineCompletionItemProvider implements InlineCompletionItem options: JSON.stringify(getAllRecommendationsOptions), }) + // If there's already a pending request, wait for it to complete instead of starting a new one + // This prevents race conditions where multiple concurrent calls cause the later (empty) response + // to override the earlier (valid) response + if (this.pendingRequest) { + getLogger().info('Reusing pending inline completion request to avoid race condition') + try { + const result = await this.pendingRequest + // Check if THIS call's token was cancelled (not the original call's token) + if (token.isCancellationRequested) { + getLogger().info('Reused request completed but this call was cancelled') + return [] + } + return result + } catch (e) { + // If the pending request failed, continue with a new request + getLogger().info('Pending request failed, starting new request: %O', e) + } + } + + // Start a new request and track it + this.pendingRequest = this._provideInlineCompletionItemsImpl( + document, + position, + context, + token, + getAllRecommendationsOptions + ) + + try { + return await this.pendingRequest + } finally { + this.pendingRequest = undefined + } + } + + private async _provideInlineCompletionItemsImpl( + document: TextDocument, + position: Position, + context: InlineCompletionContext, + token: CancellationToken, + getAllRecommendationsOptions?: GetAllRecommendationsOptions + ): Promise { if (vsCodeState.isCodeWhispererEditing) { getLogger().info('Q is editing, returning empty') return []