Skip to content

Commit 0769acb

Browse files
authored
fix(amazonq): Faster and more responsive auto trigger UX. (#7763)
## Problem 1. when intelliSense suggestion is surfaced, inline completion are not shown even if provideInlineCompletionItems have returned valid items. 2. provideInlineCompletionItems is unnecessarily debounced at 200ms which creates a user perceivable delay for inline completion UX. We already blocked concurrent API call. 3. The items returned by provideInlineCompletionItems, even though they match the typeahead of the user's current editor (they can be presented), sometimes VS Code decides to not show them to avoid interrupting user's typing flow. This not show suggestion decision is not emitted as API callback or events, causing us to report the suggestion as Rejected but it should be Discard. ## Solution 1. Force the item to render by calling `editor.action.inlineSuggest.trigger` command. <img width="589" height="374" alt="Screenshot 2025-07-24 at 7 45 12 PM" src="https://github.com/user-attachments/assets/f2723ab4-1d94-49e6-bae1-493c2af16bed" /> 3. Remove the debounce 5. Use a specific command with when clause context to detect if a suggestion is shown or not. --- - Treat all work as PUBLIC. Private `feature/x` branches will not be squash-merged at release time. - Your code changes must meet the guidelines in [CONTRIBUTING.md](https://github.com/aws/aws-toolkit-vscode/blob/master/CONTRIBUTING.md#guidelines). - License: I confirm that my contribution is made under the terms of the Apache 2.0 license.
1 parent 3084ae1 commit 0769acb

File tree

6 files changed

+47
-15
lines changed

6 files changed

+47
-15
lines changed
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"type": "Bug Fix",
3+
"description": "Faster and more responsive inline completion UX"
4+
}

packages/amazonq/package.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -975,6 +975,10 @@
975975
"command": "aws.amazonq.showPrev",
976976
"when": "inlineSuggestionVisible && !editorReadonly && aws.codewhisperer.connected"
977977
},
978+
{
979+
"command": "aws.amazonq.checkInlineSuggestionVisibility",
980+
"when": "inlineSuggestionVisible && !editorReadonly && aws.codewhisperer.connected"
981+
},
978982
{
979983
"command": "aws.amazonq.inline.invokeChat",
980984
"win": "ctrl+i",

packages/amazonq/src/app/inline/completion.ts

Lines changed: 24 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
33
* SPDX-License-Identifier: Apache-2.0
44
*/
5-
5+
import * as vscode from 'vscode'
66
import {
77
CancellationToken,
88
InlineCompletionContext,
@@ -32,7 +32,6 @@ import {
3232
ImportAdderProvider,
3333
CodeSuggestionsState,
3434
vsCodeState,
35-
inlineCompletionsDebounceDelay,
3635
noInlineSuggestionsMsg,
3736
getDiagnosticsDifferences,
3837
getDiagnosticsOfCurrentFile,
@@ -42,7 +41,7 @@ import { LineTracker } from './stateTracker/lineTracker'
4241
import { InlineTutorialAnnotation } from './tutorials/inlineTutorialAnnotation'
4342
import { TelemetryHelper } from './telemetryHelper'
4443
import { Experiments, getLogger, sleep } from 'aws-core-vscode/shared'
45-
import { debounce, messageUtils } from 'aws-core-vscode/utils'
44+
import { messageUtils } from 'aws-core-vscode/utils'
4645
import { showEdits } from './EditRendering/imageRenderer'
4746
import { ICursorUpdateRecorder } from './cursorUpdateManager'
4847
import { DocumentEventListener } from './documentEventListener'
@@ -214,13 +213,23 @@ export class AmazonQInlineCompletionItemProvider implements InlineCompletionItem
214213
) {}
215214

216215
private readonly logSessionResultMessageName = 'aws/logInlineCompletionSessionResults'
217-
provideInlineCompletionItems = debounce(
218-
this._provideInlineCompletionItems.bind(this),
219-
inlineCompletionsDebounceDelay,
220-
true
221-
)
222216

223-
private async _provideInlineCompletionItems(
217+
// Ideally use this API handleDidShowCompletionItem
218+
// https://github.com/microsoft/vscode/blob/main/src/vscode-dts/vscode.proposed.inlineCompletionsAdditions.d.ts#L83
219+
// we need this because the returned items of provideInlineCompletionItems may not be actually rendered on screen
220+
// if VS Code believes the user is actively typing then it will not show such item
221+
async checkWhetherInlineCompletionWasShown() {
222+
// this line is to force VS Code to re-render the inline completion
223+
// if it decides the inline completion can be shown
224+
await vscode.commands.executeCommand('editor.action.inlineSuggest.trigger')
225+
// yield event loop to let backend state transition finish plus wait for vsc to render
226+
await sleep(10)
227+
// run the command to detect if inline suggestion is really shown or not
228+
await vscode.commands.executeCommand(`aws.amazonq.checkInlineSuggestionVisibility`)
229+
}
230+
231+
// this method is automatically invoked by VS Code as user types
232+
async provideInlineCompletionItems(
224233
document: TextDocument,
225234
position: Position,
226235
context: InlineCompletionContext,
@@ -307,17 +316,18 @@ export class AmazonQInlineCompletionItemProvider implements InlineCompletionItem
307316
if (prevItemMatchingPrefix.length > 0) {
308317
logstr += `- not call LSP and reuse previous suggestions that match user typed characters
309318
- duration between trigger to completion suggestion is displayed ${performance.now() - t0}`
319+
void this.checkWhetherInlineCompletionWasShown()
310320
return prevItemMatchingPrefix
311321
}
312-
getLogger().debug(`Auto rejecting suggestions from previous session`)
313-
// if no such suggestions, report the previous suggestion as Reject
322+
323+
// if no such suggestions, report the previous suggestion as Reject or Discarded
314324
const params: LogInlineCompletionSessionResultsParams = {
315325
sessionId: prevSessionId,
316326
completionSessionResult: {
317327
[prevItemId]: {
318-
seen: true,
328+
seen: prevSession.displayed,
319329
accepted: false,
320-
discarded: false,
330+
discarded: !prevSession.displayed,
321331
},
322332
},
323333
totalSessionDisplayTime: performance.now() - prevSession.requestStartTime,
@@ -461,6 +471,7 @@ ${itemLog}
461471
this.sessionManager.updateCodeReferenceAndImports()
462472
// suggestions returned here will be displayed on screen
463473
logstr += `- duration between trigger to completion suggestion is displayed: ${performance.now() - t0}ms`
474+
void this.checkWhetherInlineCompletionWasShown()
464475
return itemsMatchingTypeahead as InlineCompletionItem[]
465476
} catch (e) {
466477
getLogger('amazonqLsp').error('Failed to provide completion items: %O', e)

packages/amazonq/src/app/inline/sessionManager.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ export interface CodeWhispererSession {
2424
// partialResultToken for the next trigger if user accepts an EDITS suggestion
2525
editsStreakPartialResultToken?: number | string
2626
triggerOnAcceptance?: boolean
27+
// whether any suggestion in this session was displayed on screen
28+
displayed: boolean
2729
}
2830

2931
export class SessionManager {
@@ -49,6 +51,7 @@ export class SessionManager {
4951
startPosition,
5052
firstCompletionDisplayLatency,
5153
diagnosticsBeforeAccept,
54+
displayed: false,
5255
}
5356
this._currentSuggestionIndex = 0
5457
}
@@ -128,6 +131,12 @@ export class SessionManager {
128131
}
129132
}
130133

134+
public checkInlineSuggestionVisibility() {
135+
if (this.activeSession) {
136+
this.activeSession.displayed = true
137+
}
138+
}
139+
131140
private clearReferenceInlineHintsAndImportHints() {
132141
ReferenceInlineProvider.instance.removeInlineReference()
133142
ImportAdderProvider.instance.clear()

packages/amazonq/src/lsp/client.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -352,6 +352,10 @@ async function onLanguageServerReady(
352352
await vscode.commands.executeCommand('editor.action.inlineSuggest.showNext')
353353
sessionManager.onNextSuggestion()
354354
}),
355+
// this is a workaround since handleDidShowCompletionItem is not public API
356+
Commands.register('aws.amazonq.checkInlineSuggestionVisibility', async () => {
357+
sessionManager.checkInlineSuggestionVisibility()
358+
}),
355359
Commands.register({ id: 'aws.amazonq.invokeInlineCompletion', autoconnect: true }, async () => {
356360
await vscode.commands.executeCommand('editor.action.inlineSuggest.trigger')
357361
}),

packages/amazonq/test/unit/amazonq/apps/inline/completion.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -378,7 +378,7 @@ describe('InlineCompletionManager', () => {
378378
)
379379
await messageShown
380380
})
381-
describe('debounce behavior', function () {
381+
describe.skip('debounce behavior', function () {
382382
let clock: ReturnType<typeof installFakeClock>
383383

384384
beforeEach(function () {
@@ -389,7 +389,7 @@ describe('InlineCompletionManager', () => {
389389
clock.uninstall()
390390
})
391391

392-
it('should only trigger once on rapid events', async () => {
392+
it.skip('should only trigger once on rapid events', async () => {
393393
provider = new AmazonQInlineCompletionItemProvider(
394394
languageClient,
395395
recommendationService,

0 commit comments

Comments
 (0)