Skip to content

Commit 10ee225

Browse files
committed
fix(amazonq): address pr feedback
1 parent c7e7406 commit 10ee225

File tree

5 files changed

+84
-45
lines changed

5 files changed

+84
-45
lines changed

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

Lines changed: 51 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,7 @@ import {
1616
Disposable,
1717
} from 'vscode'
1818
import { LanguageClient } from 'vscode-languageclient'
19-
import {
20-
logInlineCompletionSessionResultsNotificationType,
21-
LogInlineCompletionSessionResultsParams,
22-
} from '@aws/language-server-runtimes/protocol'
19+
import { LogInlineCompletionSessionResultsParams } from '@aws/language-server-runtimes/protocol'
2320
import { SessionManager } from './sessionManager'
2421
import { RecommendationService } from './recommendationService'
2522
import { CodeWhispererConstants } from 'aws-core-vscode/codewhisperer'
@@ -28,10 +25,19 @@ export class InlineCompletionManager implements Disposable {
2825
private disposable: Disposable
2926
private inlineCompletionProvider: AmazonQInlineCompletionItemProvider
3027
private languageClient: LanguageClient
28+
private sessionManager: SessionManager
29+
private recommendationService: RecommendationService
30+
private readonly logSessionResultMessageName = 'aws/logInlineCompletionSessionResults'
3131

3232
constructor(languageClient: LanguageClient) {
3333
this.languageClient = languageClient
34-
this.inlineCompletionProvider = new AmazonQInlineCompletionItemProvider(languageClient)
34+
this.sessionManager = new SessionManager()
35+
this.recommendationService = new RecommendationService(this.sessionManager)
36+
this.inlineCompletionProvider = new AmazonQInlineCompletionItemProvider(
37+
languageClient,
38+
this.recommendationService,
39+
this.sessionManager
40+
)
3541
this.disposable = languages.registerInlineCompletionItemProvider(
3642
CodeWhispererConstants.platformLanguageIds,
3743
this.inlineCompletionProvider
@@ -64,16 +70,16 @@ export class InlineCompletionManager implements Disposable {
6470
totalSessionDisplayTime: Date.now() - requestStartTime,
6571
firstCompletionDisplayLatency: firstCompletionDisplayLatency,
6672
}
67-
this.languageClient.sendNotification(logInlineCompletionSessionResultsNotificationType as any, params)
73+
this.languageClient.sendNotification(this.logSessionResultMessageName, params)
6874
this.disposable.dispose()
6975
this.disposable = languages.registerInlineCompletionItemProvider(
7076
CodeWhispererConstants.platformLanguageIds,
7177
this.inlineCompletionProvider
7278
)
7379
}
74-
commands.registerCommand('aws.sample-vscode-ext-amazonq.accept', onInlineAcceptance)
80+
commands.registerCommand('aws.amazonq.acceptInline', onInlineAcceptance)
7581

76-
const oninlineRejection = async (sessionId: string, itemId: string) => {
82+
const onInlineRejection = async (sessionId: string, itemId: string) => {
7783
await commands.executeCommand('editor.action.inlineSuggest.hide')
7884
// TODO: also log the seen state for other suggestions in session
7985
const params: LogInlineCompletionSessionResultsParams = {
@@ -86,39 +92,49 @@ export class InlineCompletionManager implements Disposable {
8692
},
8793
},
8894
}
89-
this.languageClient.sendNotification(logInlineCompletionSessionResultsNotificationType as any, params)
95+
this.languageClient.sendNotification(this.logSessionResultMessageName, params)
9096
this.disposable.dispose()
9197
this.disposable = languages.registerInlineCompletionItemProvider(
9298
CodeWhispererConstants.platformLanguageIds,
9399
this.inlineCompletionProvider
94100
)
95101
}
96-
commands.registerCommand('aws.sample-vscode-ext-amazonq.reject', oninlineRejection)
102+
commands.registerCommand('aws.amazonq.rejectInline', onInlineRejection)
97103

98104
/*
99105
We have to overwrite the prev. and next. commands because the inlineCompletionProvider only contained the current item
100106
To show prev. and next. recommendation we need to re-register a new provider with the previous or next item
101107
*/
102108

103109
const prevCommandHandler = async () => {
104-
SessionManager.instance.decrementActiveIndex()
110+
this.sessionManager.decrementActiveIndex()
105111
await commands.executeCommand('editor.action.inlineSuggest.hide')
106112
this.disposable.dispose()
107113
this.disposable = languages.registerInlineCompletionItemProvider(
108114
CodeWhispererConstants.platformLanguageIds,
109-
new AmazonQInlineCompletionItemProvider(this.languageClient, false)
115+
new AmazonQInlineCompletionItemProvider(
116+
this.languageClient,
117+
this.recommendationService,
118+
this.sessionManager,
119+
false
120+
)
110121
)
111122
await commands.executeCommand('editor.action.inlineSuggest.trigger')
112123
}
113124
commands.registerCommand('editor.action.inlineSuggest.showPrevious', prevCommandHandler)
114125

115126
const nextCommandHandler = async () => {
116-
SessionManager.instance.incrementActiveIndex()
127+
this.sessionManager.incrementActiveIndex()
117128
await commands.executeCommand('editor.action.inlineSuggest.hide')
118129
this.disposable.dispose()
119130
this.disposable = languages.registerInlineCompletionItemProvider(
120131
CodeWhispererConstants.platformLanguageIds,
121-
new AmazonQInlineCompletionItemProvider(this.languageClient, false)
132+
new AmazonQInlineCompletionItemProvider(
133+
this.languageClient,
134+
this.recommendationService,
135+
this.sessionManager,
136+
false
137+
)
122138
)
123139
await commands.executeCommand('editor.action.inlineSuggest.trigger')
124140
}
@@ -129,6 +145,8 @@ export class InlineCompletionManager implements Disposable {
129145
export class AmazonQInlineCompletionItemProvider implements InlineCompletionItemProvider {
130146
constructor(
131147
private readonly languageClient: LanguageClient,
148+
private readonly recommendationService: RecommendationService,
149+
private readonly sessionManager: SessionManager,
132150
private readonly isNewSesion: boolean = true
133151
) {}
134152

@@ -140,7 +158,7 @@ export class AmazonQInlineCompletionItemProvider implements InlineCompletionItem
140158
): Promise<InlineCompletionItem[] | InlineCompletionList> {
141159
if (this.isNewSesion) {
142160
// make service requests if it's a new session
143-
await RecommendationService.instance.getAllRecommendations(
161+
await this.recommendationService.getAllRecommendations(
144162
this.languageClient,
145163
document,
146164
position,
@@ -149,6 +167,23 @@ export class AmazonQInlineCompletionItemProvider implements InlineCompletionItem
149167
)
150168
}
151169
// get active item from session for displaying
152-
return SessionManager.instance.getActiveRecommendation()
170+
const items = this.sessionManager.getActiveRecommendation()
171+
const session = this.sessionManager.getActiveSession()
172+
if (!session || !items.length) {
173+
return []
174+
}
175+
for (const item of items) {
176+
item.command = {
177+
command: 'aws.amazonq.acceptInline',
178+
title: 'On acceptance',
179+
arguments: [
180+
session.sessionId,
181+
item.itemId,
182+
session.requestStartTime,
183+
session.firstCompletionDisplayLatency,
184+
],
185+
}
186+
}
187+
return items as InlineCompletionItem[]
153188
}
154189
}

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

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,7 @@ import { LanguageClient } from 'vscode-languageclient'
1313
import { SessionManager } from './sessionManager'
1414

1515
export class RecommendationService {
16-
static #instance: RecommendationService
17-
18-
public static get instance() {
19-
return (this.#instance ??= new this())
20-
}
16+
constructor(private readonly sessionManager: SessionManager) {}
2117

2218
async getAllRecommendations(
2319
languageClient: LanguageClient,
@@ -43,15 +39,20 @@ export class RecommendationService {
4339
)
4440

4541
const firstCompletionDisplayLatency = Date.now() - requestStartTime
46-
SessionManager.instance.startSession(firstResult.sessionId, firstResult.items, firstCompletionDisplayLatency)
42+
this.sessionManager.startSession(
43+
firstResult.sessionId,
44+
firstResult.items,
45+
requestStartTime,
46+
firstCompletionDisplayLatency
47+
)
4748

4849
if (firstResult.partialResultToken) {
4950
// If there are more results to fetch, handle them in the background
5051
this.processRemainingRequests(languageClient, request, firstResult, token).catch((error) => {
5152
languageClient.warn(`Error when getting suggestions: ${error}`)
5253
})
5354
} else {
54-
SessionManager.instance.closeSession()
55+
this.sessionManager.closeSession()
5556
}
5657
}
5758

@@ -69,9 +70,9 @@ export class RecommendationService {
6970
request,
7071
token
7172
)
72-
SessionManager.instance.updateSessionSuggestions(result.items)
73+
this.sessionManager.updateSessionSuggestions(result.items)
7374
nextToken = result.partialResultToken
7475
}
75-
SessionManager.instance.closeSession()
76+
this.sessionManager.closeSession()
7677
}
7778
}

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

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,35 +4,33 @@
44
*/
55

66
import { InlineCompletionItemWithReferences } from '@aws/language-server-runtimes-types/inlineCompletionWithReferences'
7-
import { InlineCompletionItem } from 'vscode'
87

98
// TODO: add more needed data to the session interface
109
interface CodeWhispererSession {
1110
sessionId: string
1211
suggestions: InlineCompletionItemWithReferences[]
1312
// TODO: might need to convert to enum states
1413
isRequestInProgress: boolean
14+
requestStartTime: number
1515
firstCompletionDisplayLatency?: number
1616
}
1717

1818
export class SessionManager {
19-
static #instance: SessionManager
2019
private activeSession?: CodeWhispererSession
2120
private activeIndex: number = 0
22-
23-
public static get instance() {
24-
return (this.#instance ??= new this())
25-
}
21+
constructor() {}
2622

2723
public startSession(
2824
sessionId: string,
2925
suggestions: InlineCompletionItemWithReferences[],
26+
requestStartTime: number,
3027
firstCompletionDisplayLatency?: number
3128
) {
3229
this.activeSession = {
3330
sessionId,
3431
suggestions,
3532
isRequestInProgress: true,
33+
requestStartTime,
3634
firstCompletionDisplayLatency,
3735
}
3836
this.activeIndex = 0
@@ -45,6 +43,10 @@ export class SessionManager {
4543
this.activeSession.isRequestInProgress = false
4644
}
4745

46+
public getActiveSession() {
47+
return this.activeSession
48+
}
49+
4850
public updateSessionSuggestions(suggestions: InlineCompletionItemWithReferences[]) {
4951
if (!this.activeSession) {
5052
return
@@ -69,7 +71,7 @@ export class SessionManager {
6971
In order to keep track of the right suggestion state, and for features such as reference tracker, this hack is still needed
7072
*/
7173

72-
public getActiveRecommendation(): InlineCompletionItem[] {
74+
public getActiveRecommendation(): InlineCompletionItemWithReferences[] {
7375
let suggestionCount = this.activeSession?.suggestions.length
7476
if (!suggestionCount) {
7577
return []
@@ -78,7 +80,7 @@ export class SessionManager {
7880
suggestionCount += 1
7981
}
8082

81-
const activeSuggestion = this.activeSession?.suggestions[this.activeIndex] as InlineCompletionItem
83+
const activeSuggestion = this.activeSession?.suggestions[this.activeIndex]
8284
if (!activeSuggestion) {
8385
return []
8486
}

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

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -69,16 +69,16 @@ describe('InlineCompletionManager', () => {
6969
})
7070

7171
it('should register accept and reject commands', () => {
72-
assert(registerCommandStub.calledWith('aws.sample-vscode-ext-amazonq.accept'))
73-
assert(registerCommandStub.calledWith('aws.sample-vscode-ext-amazonq.reject'))
72+
assert(registerCommandStub.calledWith('aws.amazonq.acceptInline'))
73+
assert(registerCommandStub.calledWith('aws.amazonq.rejectInline'))
7474
})
7575

7676
describe('onInlineAcceptance', () => {
7777
it('should send notification and re-register provider on acceptance', async () => {
7878
// Get the acceptance handler
7979
const acceptanceHandler = registerCommandStub
8080
.getCalls()
81-
?.find((call) => call.args[0] === 'aws.sample-vscode-ext-amazonq.accept')?.args[1]
81+
?.find((call) => call.args[0] === 'aws.amazonq.acceptInline')?.args[1]
8282

8383
const sessionId = 'test-session'
8484
const itemId = 'test-item'
@@ -90,7 +90,7 @@ describe('InlineCompletionManager', () => {
9090
assert(sendNotificationStub.calledOnce)
9191
assert(
9292
sendNotificationStub.calledWith(
93-
sinon.match.any,
93+
'aws/logInlineCompletionSessionResults',
9494
sinon.match({
9595
sessionId,
9696
completionSessionResult: {
@@ -114,7 +114,7 @@ describe('InlineCompletionManager', () => {
114114
// Get the rejection handler
115115
const rejectionHandler = registerCommandStub
116116
.getCalls()
117-
.find((call) => call.args[0] === 'aws.sample-vscode-ext-amazonq.reject')?.args[1]
117+
.find((call) => call.args[0] === 'aws.amazonq.rejectInline')?.args[1]
118118

119119
const sessionId = 'test-session'
120120
const itemId = 'test-item'
@@ -125,7 +125,7 @@ describe('InlineCompletionManager', () => {
125125
assert(sendNotificationStub.calledOnce)
126126
assert(
127127
sendNotificationStub.calledWith(
128-
sinon.match.any,
128+
'aws/logInlineCompletionSessionResults',
129129
sinon.match({
130130
sessionId,
131131
completionSessionResult: {

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

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,8 @@ describe('RecommendationService', () => {
2727
insertText: 'ItemTwo',
2828
} as InlineCompletionItem
2929
const mockPartialResultToken = 'some-random-token'
30-
const service = RecommendationService.instance
30+
const sessionManager = new SessionManager()
31+
const service = new RecommendationService(sessionManager)
3132

3233
beforeEach(() => {
3334
sandbox = sinon.createSandbox()
@@ -41,7 +42,7 @@ describe('RecommendationService', () => {
4142

4243
afterEach(() => {
4344
sandbox.restore()
44-
SessionManager.instance.clear()
45+
sessionManager.clear()
4546
})
4647

4748
describe('getAllRecommendations', () => {
@@ -68,7 +69,7 @@ describe('RecommendationService', () => {
6869
})
6970

7071
// Verify session management
71-
const items = SessionManager.instance.getActiveRecommendation()
72+
const items = sessionManager.getActiveRecommendation()
7273
assert.deepStrictEqual(items, [mockInlineCompletionItemOne])
7374
})
7475

@@ -108,10 +109,10 @@ describe('RecommendationService', () => {
108109
})
109110

110111
// Verify session management
111-
const items = SessionManager.instance.getActiveRecommendation()
112+
const items = sessionManager.getActiveRecommendation()
112113
assert.deepStrictEqual(items, [mockInlineCompletionItemOne, { insertText: '1' } as InlineCompletionItem])
113-
SessionManager.instance.incrementActiveIndex()
114-
const items2 = SessionManager.instance.getActiveRecommendation()
114+
sessionManager.incrementActiveIndex()
115+
const items2 = sessionManager.getActiveRecommendation()
115116
assert.deepStrictEqual(items2, [mockInlineCompletionItemTwo, { insertText: '1' } as InlineCompletionItem])
116117
})
117118
})

0 commit comments

Comments
 (0)