Skip to content

Commit 63fcab2

Browse files
committed
fix(amazonq): address pr feedback
1 parent be27d83 commit 63fcab2

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

@@ -56,10 +53,19 @@ export class InlineCompletionManager implements Disposable {
5653
private disposable: Disposable
5754
private inlineCompletionProvider: AmazonQInlineCompletionItemProvider
5855
private languageClient: LanguageClient
56+
private sessionManager: SessionManager
57+
private recommendationService: RecommendationService
58+
private readonly logSessionResultMessageName = 'aws/logInlineCompletionSessionResults'
5959

6060
constructor(languageClient: LanguageClient) {
6161
this.languageClient = languageClient
62-
this.inlineCompletionProvider = new AmazonQInlineCompletionItemProvider(languageClient)
62+
this.sessionManager = new SessionManager()
63+
this.recommendationService = new RecommendationService(this.sessionManager)
64+
this.inlineCompletionProvider = new AmazonQInlineCompletionItemProvider(
65+
languageClient,
66+
this.recommendationService,
67+
this.sessionManager
68+
)
6369
this.disposable = languages.registerInlineCompletionItemProvider(
6470
CodewhispererInlineCompletionLanguages,
6571
this.inlineCompletionProvider
@@ -92,16 +98,16 @@ export class InlineCompletionManager implements Disposable {
9298
totalSessionDisplayTime: Date.now() - requestStartTime,
9399
firstCompletionDisplayLatency: firstCompletionDisplayLatency,
94100
}
95-
this.languageClient.sendNotification(logInlineCompletionSessionResultsNotificationType as any, params)
101+
this.languageClient.sendNotification(this.logSessionResultMessageName, params)
96102
this.disposable.dispose()
97103
this.disposable = languages.registerInlineCompletionItemProvider(
98104
CodewhispererInlineCompletionLanguages,
99105
this.inlineCompletionProvider
100106
)
101107
}
102-
commands.registerCommand('aws.sample-vscode-ext-amazonq.accept', onInlineAcceptance)
108+
commands.registerCommand('aws.amazonq.acceptInline', onInlineAcceptance)
103109

104-
const oninlineRejection = async (sessionId: string, itemId: string) => {
110+
const onInlineRejection = async (sessionId: string, itemId: string) => {
105111
await commands.executeCommand('editor.action.inlineSuggest.hide')
106112
// TODO: also log the seen state for other suggestions in session
107113
const params: LogInlineCompletionSessionResultsParams = {
@@ -114,39 +120,49 @@ export class InlineCompletionManager implements Disposable {
114120
},
115121
},
116122
}
117-
this.languageClient.sendNotification(logInlineCompletionSessionResultsNotificationType as any, params)
123+
this.languageClient.sendNotification(this.logSessionResultMessageName, params)
118124
this.disposable.dispose()
119125
this.disposable = languages.registerInlineCompletionItemProvider(
120126
CodewhispererInlineCompletionLanguages,
121127
this.inlineCompletionProvider
122128
)
123129
}
124-
commands.registerCommand('aws.sample-vscode-ext-amazonq.reject', oninlineRejection)
130+
commands.registerCommand('aws.amazonq.rejectInline', onInlineRejection)
125131

126132
/*
127133
We have to overwrite the prev. and next. commands because the inlineCompletionProvider only contained the current item
128134
To show prev. and next. recommendation we need to re-register a new provider with the previous or next item
129135
*/
130136

131137
const prevCommandHandler = async () => {
132-
SessionManager.instance.decrementActiveIndex()
138+
this.sessionManager.decrementActiveIndex()
133139
await commands.executeCommand('editor.action.inlineSuggest.hide')
134140
this.disposable.dispose()
135141
this.disposable = languages.registerInlineCompletionItemProvider(
136142
CodewhispererInlineCompletionLanguages,
137-
new AmazonQInlineCompletionItemProvider(this.languageClient, false)
143+
new AmazonQInlineCompletionItemProvider(
144+
this.languageClient,
145+
this.recommendationService,
146+
this.sessionManager,
147+
false
148+
)
138149
)
139150
await commands.executeCommand('editor.action.inlineSuggest.trigger')
140151
}
141152
commands.registerCommand('editor.action.inlineSuggest.showPrevious', prevCommandHandler)
142153

143154
const nextCommandHandler = async () => {
144-
SessionManager.instance.incrementActiveIndex()
155+
this.sessionManager.incrementActiveIndex()
145156
await commands.executeCommand('editor.action.inlineSuggest.hide')
146157
this.disposable.dispose()
147158
this.disposable = languages.registerInlineCompletionItemProvider(
148159
CodewhispererInlineCompletionLanguages,
149-
new AmazonQInlineCompletionItemProvider(this.languageClient, false)
160+
new AmazonQInlineCompletionItemProvider(
161+
this.languageClient,
162+
this.recommendationService,
163+
this.sessionManager,
164+
false
165+
)
150166
)
151167
await commands.executeCommand('editor.action.inlineSuggest.trigger')
152168
}
@@ -157,6 +173,8 @@ export class InlineCompletionManager implements Disposable {
157173
export class AmazonQInlineCompletionItemProvider implements InlineCompletionItemProvider {
158174
constructor(
159175
private readonly languageClient: LanguageClient,
176+
private readonly recommendationService: RecommendationService,
177+
private readonly sessionManager: SessionManager,
160178
private readonly isNewSesion: boolean = true
161179
) {}
162180

@@ -168,7 +186,7 @@ export class AmazonQInlineCompletionItemProvider implements InlineCompletionItem
168186
): Promise<InlineCompletionItem[] | InlineCompletionList> {
169187
if (this.isNewSesion) {
170188
// make service requests if it's a new session
171-
await RecommendationService.instance.getAllRecommendations(
189+
await this.recommendationService.getAllRecommendations(
172190
this.languageClient,
173191
document,
174192
position,
@@ -177,6 +195,23 @@ export class AmazonQInlineCompletionItemProvider implements InlineCompletionItem
177195
)
178196
}
179197
// get active item from session for displaying
180-
return SessionManager.instance.getActiveRecommendation()
198+
const items = this.sessionManager.getActiveRecommendation()
199+
const session = this.sessionManager.getActiveSession()
200+
if (!session || !items.length) {
201+
return []
202+
}
203+
for (const item of items) {
204+
item.command = {
205+
command: 'aws.amazonq.acceptInline',
206+
title: 'On acceptance',
207+
arguments: [
208+
session.sessionId,
209+
item.itemId,
210+
session.requestStartTime,
211+
session.firstCompletionDisplayLatency,
212+
],
213+
}
214+
}
215+
return items as InlineCompletionItem[]
181216
}
182217
}

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)