@@ -139,6 +139,8 @@ export class InlineCompletionManager implements Disposable {
139
139
await ImportAdderProvider . instance . onAcceptRecommendation ( editor , item , startLine )
140
140
}
141
141
this . sessionManager . incrementSuggestionCount ( )
142
+ // clear session manager states once accepted
143
+ this . sessionManager . clear ( )
142
144
}
143
145
commands . registerCommand ( 'aws.amazonq.acceptInline' , onInlineAcceptance )
144
146
@@ -166,6 +168,8 @@ export class InlineCompletionManager implements Disposable {
166
168
} ,
167
169
}
168
170
this . languageClient . sendNotification ( this . logSessionResultMessageName , params )
171
+ // clear session manager states once rejected
172
+ this . sessionManager . clear ( )
169
173
}
170
174
commands . registerCommand ( 'aws.amazonq.rejectCodeSuggestion' , onInlineRejection )
171
175
}
@@ -179,6 +183,7 @@ export class AmazonQInlineCompletionItemProvider implements InlineCompletionItem
179
183
private readonly inlineTutorialAnnotation : InlineTutorialAnnotation
180
184
) { }
181
185
186
+ private readonly logSessionResultMessageName = 'aws/logInlineCompletionSessionResults'
182
187
provideInlineCompletionItems = debounce (
183
188
this . _provideInlineCompletionItems . bind ( this ) ,
184
189
inlineCompletionsDebounceDelay ,
@@ -191,6 +196,10 @@ export class AmazonQInlineCompletionItemProvider implements InlineCompletionItem
191
196
context : InlineCompletionContext ,
192
197
token : CancellationToken
193
198
) : Promise < InlineCompletionItem [ ] > {
199
+ // prevent concurrent API calls and write to shared state variables
200
+ if ( vsCodeState . isRecommendationsActive ) {
201
+ return [ ]
202
+ }
194
203
try {
195
204
vsCodeState . isRecommendationsActive = true
196
205
const isAutoTrigger = context . triggerKind === InlineCompletionTriggerKind . Automatic
@@ -199,6 +208,24 @@ export class AmazonQInlineCompletionItemProvider implements InlineCompletionItem
199
208
return [ ]
200
209
}
201
210
211
+ // report suggestion state for previous suggestions if they exist
212
+ const prevSessionId = this . sessionManager . getActiveSession ( ) ?. sessionId
213
+ const prevItemId = this . sessionManager . getActiveRecommendation ( ) ?. [ 0 ] ?. itemId
214
+ if ( prevSessionId && prevItemId ) {
215
+ const params : LogInlineCompletionSessionResultsParams = {
216
+ sessionId : prevSessionId ,
217
+ completionSessionResult : {
218
+ [ prevItemId ] : {
219
+ seen : true ,
220
+ accepted : false ,
221
+ discarded : false ,
222
+ } ,
223
+ } ,
224
+ }
225
+ this . languageClient . sendNotification ( this . logSessionResultMessageName , params )
226
+ this . sessionManager . clear ( )
227
+ }
228
+
202
229
// tell the tutorial that completions has been triggered
203
230
await this . inlineTutorialAnnotation . triggered ( context . triggerKind )
204
231
TelemetryHelper . instance . setInvokeSuggestionStartTime ( )
@@ -213,6 +240,7 @@ export class AmazonQInlineCompletionItemProvider implements InlineCompletionItem
213
240
)
214
241
// get active item from session for displaying
215
242
const items = this . sessionManager . getActiveRecommendation ( )
243
+ const itemId = this . sessionManager . getActiveRecommendation ( ) ?. [ 0 ] ?. itemId
216
244
const session = this . sessionManager . getActiveSession ( )
217
245
const editor = window . activeTextEditor
218
246
@@ -229,24 +257,72 @@ export class AmazonQInlineCompletionItemProvider implements InlineCompletionItem
229
257
}
230
258
231
259
const cursorPosition = document . validatePosition ( position )
232
- for ( const item of items ) {
233
- item . command = {
234
- command : 'aws.amazonq.acceptInline' ,
235
- title : 'On acceptance' ,
236
- arguments : [
237
- session . sessionId ,
238
- item ,
239
- editor ,
240
- session . requestStartTime ,
241
- cursorPosition . line ,
242
- session . firstCompletionDisplayLatency ,
243
- ] ,
260
+
261
+ if ( position . isAfter ( editor . selection . active ) ) {
262
+ getLogger ( ) . debug ( `Cursor moved behind trigger position. Discarding suggestion...` )
263
+ const params : LogInlineCompletionSessionResultsParams = {
264
+ sessionId : session . sessionId ,
265
+ completionSessionResult : {
266
+ [ itemId ] : {
267
+ seen : false ,
268
+ accepted : false ,
269
+ discarded : true ,
270
+ } ,
271
+ } ,
244
272
}
245
- item . range = new Range ( cursorPosition , cursorPosition )
273
+ this . languageClient . sendNotification ( this . logSessionResultMessageName , params )
274
+ this . sessionManager . clear ( )
275
+ return [ ]
276
+ }
277
+
278
+ // the user typed characters from invoking suggestion cursor position to receiving suggestion position
279
+ const typeahead = document . getText ( new Range ( position , editor . selection . active ) )
280
+
281
+ const itemsMatchingTypeahead = [ ]
282
+
283
+ for ( const item of items ) {
246
284
item . insertText = typeof item . insertText === 'string' ? item . insertText : item . insertText . value
247
- ImportAdderProvider . instance . onShowRecommendation ( document , cursorPosition . line , item )
285
+ if ( item . insertText . startsWith ( typeahead ) ) {
286
+ item . command = {
287
+ command : 'aws.amazonq.acceptInline' ,
288
+ title : 'On acceptance' ,
289
+ arguments : [
290
+ session . sessionId ,
291
+ item ,
292
+ editor ,
293
+ session . requestStartTime ,
294
+ cursorPosition . line ,
295
+ session . firstCompletionDisplayLatency ,
296
+ ] ,
297
+ }
298
+ item . range = new Range ( cursorPosition , cursorPosition )
299
+ itemsMatchingTypeahead . push ( item )
300
+ ImportAdderProvider . instance . onShowRecommendation ( document , cursorPosition . line , item )
301
+ }
302
+ }
303
+
304
+ // report discard if none of suggestions match typeahead
305
+ if ( itemsMatchingTypeahead . length === 0 ) {
306
+ getLogger ( ) . debug (
307
+ `Suggestion does not match user typeahead from insertion position. Discarding suggestion...`
308
+ )
309
+ const params : LogInlineCompletionSessionResultsParams = {
310
+ sessionId : session . sessionId ,
311
+ completionSessionResult : {
312
+ [ itemId ] : {
313
+ seen : false ,
314
+ accepted : false ,
315
+ discarded : true ,
316
+ } ,
317
+ } ,
318
+ }
319
+ this . languageClient . sendNotification ( this . logSessionResultMessageName , params )
320
+ this . sessionManager . clear ( )
321
+ return [ ]
248
322
}
249
- return items as InlineCompletionItem [ ]
323
+
324
+ // suggestions returned here will be displayed on screen
325
+ return itemsMatchingTypeahead as InlineCompletionItem [ ]
250
326
} catch ( e ) {
251
327
getLogger ( 'amazonqLsp' ) . error ( 'Failed to provide completion items: %O' , e )
252
328
return [ ]
0 commit comments