Skip to content

Commit b74f9e1

Browse files
authored
fix(amazonq): Render first response before receiving all paginated inline completion results (#7663)
## Problem Previous the pagination API call was blocking and it does not render until all pagination API calls are done. Without a force refresh of the inline ghost text, paginated response will not be rendered. ## Solution 1. Keep doing paginated API call in the background. 2. Refresh the ghost text of inline completion when user press Left or Right key to add paginated responses by calling VS Code native commands. Note that we can do such refresh below whenever the pagination session finish but that will result in inline completion flickering, hence it is better to do it on demand when Left or Right is pressed. ``` await vscode.commands.executeCommand('editor.action.inlineSuggest.hide') await vscode.commands.executeCommand('editor.action.inlineSuggest.trigger') ``` --- - 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 d17c1d7 commit b74f9e1

File tree

5 files changed

+63
-21
lines changed

5 files changed

+63
-21
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": "Render first response before receiving all paginated inline completion results"
4+
}

packages/amazonq/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -917,12 +917,12 @@
917917
},
918918
{
919919
"key": "right",
920-
"command": "editor.action.inlineSuggest.showNext",
920+
"command": "aws.amazonq.showNext",
921921
"when": "inlineSuggestionVisible && !editorReadonly && aws.codewhisperer.connected"
922922
},
923923
{
924924
"key": "left",
925-
"command": "editor.action.inlineSuggest.showPrevious",
925+
"command": "aws.amazonq.showPrev",
926926
"when": "inlineSuggestionVisible && !editorReadonly && aws.codewhisperer.connected"
927927
},
928928
{

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

Lines changed: 32 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
33
* SPDX-License-Identifier: Apache-2.0
44
*/
5-
65
import {
76
InlineCompletionListWithReferences,
87
InlineCompletionWithReferencesParams,
@@ -80,7 +79,7 @@ export class RecommendationService {
8079
nextToken: request.partialResultToken,
8180
},
8281
})
83-
let result: InlineCompletionListWithReferences = await languageClient.sendRequest(
82+
const result: InlineCompletionListWithReferences = await languageClient.sendRequest(
8483
inlineCompletionWithReferencesRequestType.method,
8584
request,
8685
token
@@ -120,18 +119,10 @@ export class RecommendationService {
120119
getLogger().info(
121120
'Suggestion type is COMPLETIONS. Start fetching for more items if partialResultToken exists.'
122121
)
123-
try {
124-
while (result.partialResultToken) {
125-
const paginatedRequest = { ...request, partialResultToken: result.partialResultToken }
126-
result = await languageClient.sendRequest(
127-
inlineCompletionWithReferencesRequestType.method,
128-
paginatedRequest,
129-
token
130-
)
131-
this.sessionManager.updateSessionSuggestions(result.items)
132-
}
133-
} catch (error) {
134-
languageClient.warn(`Error when getting suggestions: ${error}`)
122+
if (result.partialResultToken) {
123+
this.processRemainingRequests(languageClient, request, result, token).catch((error) => {
124+
languageClient.warn(`Error when getting suggestions: ${error}`)
125+
})
135126
}
136127
} else {
137128
// Skip fetching for more items if the suggesion is EDITS. If it is EDITS suggestion, only fetching for more
@@ -140,11 +131,6 @@ export class RecommendationService {
140131
getLogger().info('Suggestion type is EDITS. Skip fetching for more items.')
141132
this.sessionManager.updateActiveEditsStreakToken(result.partialResultToken)
142133
}
143-
144-
// Close session and finalize telemetry regardless of pagination path
145-
this.sessionManager.closeSession()
146-
TelemetryHelper.instance.setAllPaginationEndTime()
147-
options.emitTelemetry && TelemetryHelper.instance.tryRecordClientComponentLatency()
148134
} catch (error: any) {
149135
getLogger().error('Error getting recommendations: %O', error)
150136
// bearer token expired
@@ -167,4 +153,31 @@ export class RecommendationService {
167153
}
168154
}
169155
}
156+
157+
private async processRemainingRequests(
158+
languageClient: LanguageClient,
159+
initialRequest: InlineCompletionWithReferencesParams,
160+
firstResult: InlineCompletionListWithReferences,
161+
token: CancellationToken
162+
): Promise<void> {
163+
let nextToken = firstResult.partialResultToken
164+
while (nextToken) {
165+
const request = { ...initialRequest, partialResultToken: nextToken }
166+
167+
const result: InlineCompletionListWithReferences = await languageClient.sendRequest(
168+
inlineCompletionWithReferencesRequestType.method,
169+
request,
170+
token
171+
)
172+
this.sessionManager.updateSessionSuggestions(result.items)
173+
nextToken = result.partialResultToken
174+
}
175+
176+
this.sessionManager.closeSession()
177+
178+
// refresh inline completion items to render paginated responses
179+
// All pagination requests completed
180+
TelemetryHelper.instance.setAllPaginationEndTime()
181+
TelemetryHelper.instance.tryRecordClientComponentLatency()
182+
}
170183
}

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

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ export interface CodeWhispererSession {
2424
export class SessionManager {
2525
private activeSession?: CodeWhispererSession
2626
private _acceptedSuggestionCount: number = 0
27+
private _refreshedSessions = new Set<string>()
2728

2829
constructor() {}
2930

@@ -86,4 +87,20 @@ export class SessionManager {
8687
public clear() {
8788
this.activeSession = undefined
8889
}
90+
91+
// re-render the session ghost text to display paginated responses once per completed session
92+
public async maybeRefreshSessionUx() {
93+
if (
94+
this.activeSession &&
95+
!this.activeSession.isRequestInProgress &&
96+
!this._refreshedSessions.has(this.activeSession.sessionId)
97+
) {
98+
await vscode.commands.executeCommand('editor.action.inlineSuggest.hide')
99+
await vscode.commands.executeCommand('editor.action.inlineSuggest.trigger')
100+
if (this._refreshedSessions.size > 1000) {
101+
this._refreshedSessions.clear()
102+
}
103+
this._refreshedSessions.add(this.activeSession.sessionId)
104+
}
105+
}
89106
}

packages/amazonq/src/lsp/client.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -265,6 +265,14 @@ async function onLanguageServerReady(
265265

266266
toDispose.push(
267267
inlineManager,
268+
Commands.register('aws.amazonq.showPrev', async () => {
269+
await sessionManager.maybeRefreshSessionUx()
270+
await vscode.commands.executeCommand('editor.action.inlineSuggest.showPrevious')
271+
}),
272+
Commands.register('aws.amazonq.showNext', async () => {
273+
await sessionManager.maybeRefreshSessionUx()
274+
await vscode.commands.executeCommand('editor.action.inlineSuggest.showNext')
275+
}),
268276
Commands.register({ id: 'aws.amazonq.invokeInlineCompletion', autoconnect: true }, async () => {
269277
await vscode.commands.executeCommand('editor.action.inlineSuggest.trigger')
270278
}),

0 commit comments

Comments
 (0)