2
2
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3
3
* SPDX-License-Identifier: Apache-2.0
4
4
*/
5
-
5
+ import * as vscode from 'vscode'
6
6
import {
7
7
CancellationToken ,
8
8
InlineCompletionContext ,
@@ -32,7 +32,6 @@ import {
32
32
ImportAdderProvider ,
33
33
CodeSuggestionsState ,
34
34
vsCodeState ,
35
- inlineCompletionsDebounceDelay ,
36
35
noInlineSuggestionsMsg ,
37
36
getDiagnosticsDifferences ,
38
37
getDiagnosticsOfCurrentFile ,
@@ -42,7 +41,7 @@ import { LineTracker } from './stateTracker/lineTracker'
42
41
import { InlineTutorialAnnotation } from './tutorials/inlineTutorialAnnotation'
43
42
import { TelemetryHelper } from './telemetryHelper'
44
43
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'
46
45
import { showEdits } from './EditRendering/imageRenderer'
47
46
import { ICursorUpdateRecorder } from './cursorUpdateManager'
48
47
import { DocumentEventListener } from './documentEventListener'
@@ -164,6 +163,11 @@ export class InlineCompletionManager implements Disposable {
164
163
const onInlineRejection = async ( ) => {
165
164
try {
166
165
vsCodeState . isCodeWhispererEditing = true
166
+ if ( this . sessionManager . getActiveSession ( ) === undefined ) {
167
+ return
168
+ }
169
+ const requestStartTime = this . sessionManager . getActiveSession ( ) ! . requestStartTime
170
+ const totalSessionDisplayTime = performance . now ( ) - requestStartTime
167
171
await commands . executeCommand ( 'editor.action.inlineSuggest.hide' )
168
172
// TODO: also log the seen state for other suggestions in session
169
173
this . disposable . dispose ( )
@@ -185,6 +189,7 @@ export class InlineCompletionManager implements Disposable {
185
189
discarded : false ,
186
190
} ,
187
191
} ,
192
+ totalSessionDisplayTime : totalSessionDisplayTime ,
188
193
}
189
194
this . languageClient . sendNotification ( this . logSessionResultMessageName , params )
190
195
// clear session manager states once rejected
@@ -198,7 +203,7 @@ export class InlineCompletionManager implements Disposable {
198
203
}
199
204
200
205
export class AmazonQInlineCompletionItemProvider implements InlineCompletionItemProvider {
201
- private logger = getLogger ( 'nextEditPrediction' )
206
+ private logger = getLogger ( )
202
207
constructor (
203
208
private readonly languageClient : LanguageClient ,
204
209
private readonly recommendationService : RecommendationService ,
@@ -208,13 +213,23 @@ export class AmazonQInlineCompletionItemProvider implements InlineCompletionItem
208
213
) { }
209
214
210
215
private readonly logSessionResultMessageName = 'aws/logInlineCompletionSessionResults'
211
- provideInlineCompletionItems = debounce (
212
- this . _provideInlineCompletionItems . bind ( this ) ,
213
- inlineCompletionsDebounceDelay ,
214
- true
215
- )
216
216
217
- 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 (
218
233
document : TextDocument ,
219
234
position : Position ,
220
235
context : InlineCompletionContext ,
@@ -299,26 +314,28 @@ export class AmazonQInlineCompletionItemProvider implements InlineCompletionItem
299
314
}
300
315
// re-use previous suggestions as long as new typed prefix matches
301
316
if ( prevItemMatchingPrefix . length > 0 ) {
302
- getLogger ( ) . debug ( `Re-using suggestions that match user typed characters` )
317
+ logstr += `- not call LSP and reuse previous suggestions that match user typed characters
318
+ - duration between trigger to completion suggestion is displayed ${ performance . now ( ) - t0 } `
319
+ void this . checkWhetherInlineCompletionWasShown ( )
303
320
return prevItemMatchingPrefix
304
321
}
305
- getLogger ( ) . debug ( `Auto rejecting suggestions from previous session` )
306
- // if no such suggestions, report the previous suggestion as Reject
322
+
323
+ // if no such suggestions, report the previous suggestion as Reject or Discarded
307
324
const params : LogInlineCompletionSessionResultsParams = {
308
325
sessionId : prevSessionId ,
309
326
completionSessionResult : {
310
327
[ prevItemId ] : {
311
- seen : true ,
328
+ seen : prevSession . displayed ,
312
329
accepted : false ,
313
- discarded : false ,
330
+ discarded : ! prevSession . displayed ,
314
331
} ,
315
332
} ,
333
+ totalSessionDisplayTime : performance . now ( ) - prevSession . requestStartTime ,
316
334
}
317
335
this . languageClient . sendNotification ( this . logSessionResultMessageName , params )
318
336
this . sessionManager . clear ( )
319
337
}
320
338
321
- // TODO: this line will take ~200ms each trigger, need to root cause and maybe better to disable it for now
322
339
// tell the tutorial that completions has been triggered
323
340
await this . inlineTutorialAnnotation . triggered ( context . triggerKind )
324
341
@@ -346,12 +363,13 @@ export class AmazonQInlineCompletionItemProvider implements InlineCompletionItem
346
363
347
364
const t2 = performance . now ( )
348
365
349
- logstr = logstr += `- number of suggestions: ${ items . length }
366
+ logstr += `- number of suggestions: ${ items . length }
350
367
- sessionId: ${ this . sessionManager . getActiveSession ( ) ?. sessionId }
351
368
- first suggestion content (next line):
352
369
${ itemLog }
353
- - duration since trigger to before sending Flare call: ${ t1 - t0 } ms
354
- - duration since trigger to receiving responses from Flare: ${ t2 - t0 } ms
370
+ - duration between trigger to before sending LSP call: ${ t1 - t0 } ms
371
+ - duration between trigger to after receiving LSP response: ${ t2 - t0 } ms
372
+ - duration between before sending LSP call to after receving LSP response: ${ t2 - t1 } ms
355
373
`
356
374
const session = this . sessionManager . getActiveSession ( )
357
375
@@ -361,16 +379,13 @@ ${itemLog}
361
379
}
362
380
363
381
if ( ! session || ! items . length || ! editor ) {
364
- getLogger ( ) . debug (
365
- `Failed to produce inline suggestion results. Received ${ items . length } items from service`
366
- )
382
+ logstr += `Failed to produce inline suggestion results. Received ${ items . length } items from service`
367
383
return [ ]
368
384
}
369
385
370
386
const cursorPosition = document . validatePosition ( position )
371
387
372
388
if ( position . isAfter ( editor . selection . active ) ) {
373
- getLogger ( ) . debug ( `Cursor moved behind trigger position. Discarding suggestion...` )
374
389
const params : LogInlineCompletionSessionResultsParams = {
375
390
sessionId : session . sessionId ,
376
391
completionSessionResult : {
@@ -383,6 +398,7 @@ ${itemLog}
383
398
}
384
399
this . languageClient . sendNotification ( this . logSessionResultMessageName , params )
385
400
this . sessionManager . clear ( )
401
+ logstr += `- cursor moved behind trigger position. Discarding suggestion...`
386
402
return [ ]
387
403
}
388
404
@@ -410,9 +426,7 @@ ${itemLog}
410
426
// Check if Next Edit Prediction feature flag is enabled
411
427
if ( Experiments . instance . get ( 'amazonqLSPNEP' , true ) ) {
412
428
await showEdits ( item , editor , session , this . languageClient , this )
413
- const t3 = performance . now ( )
414
- logstr = logstr + `- duration since trigger to NEP suggestion is displayed: ${ t3 - t0 } ms`
415
- this . logger . info ( logstr )
429
+ logstr += `- duration between trigger to edits suggestion is displayed: ${ performance . now ( ) - t0 } ms`
416
430
}
417
431
return [ ]
418
432
}
@@ -438,9 +452,6 @@ ${itemLog}
438
452
439
453
// report discard if none of suggestions match typeahead
440
454
if ( itemsMatchingTypeahead . length === 0 ) {
441
- getLogger ( ) . debug (
442
- `Suggestion does not match user typeahead from insertion position. Discarding suggestion...`
443
- )
444
455
const params : LogInlineCompletionSessionResultsParams = {
445
456
sessionId : session . sessionId ,
446
457
completionSessionResult : {
@@ -453,17 +464,22 @@ ${itemLog}
453
464
}
454
465
this . languageClient . sendNotification ( this . logSessionResultMessageName , params )
455
466
this . sessionManager . clear ( )
467
+ logstr += `- suggestion does not match user typeahead from insertion position. Discarding suggestion...`
456
468
return [ ]
457
469
}
458
470
459
471
this . sessionManager . updateCodeReferenceAndImports ( )
460
472
// suggestions returned here will be displayed on screen
473
+ logstr += `- duration between trigger to completion suggestion is displayed: ${ performance . now ( ) - t0 } ms`
474
+ void this . checkWhetherInlineCompletionWasShown ( )
461
475
return itemsMatchingTypeahead as InlineCompletionItem [ ]
462
476
} catch ( e ) {
463
477
getLogger ( 'amazonqLsp' ) . error ( 'Failed to provide completion items: %O' , e )
478
+ logstr += `- failed to provide completion items ${ ( e as Error ) . message } `
464
479
return [ ]
465
480
} finally {
466
481
vsCodeState . isRecommendationsActive = false
482
+ this . logger . info ( logstr )
467
483
}
468
484
}
469
485
}
0 commit comments