@@ -79,8 +79,8 @@ export class CopilotCompletionContextProvider implements ContextResolver<Support
79
79
private static readonly defaultTimeBudgetMs : number = 7 ;
80
80
// Assume the cache is stale when the distance to the current caret is greater than this value.
81
81
private static readonly defaultMaxCaretDistance = 8192 ;
82
- private static readonly defaultMaxSnippetCount = 15 ;
83
- private static readonly defaultMaxSnippetLength = 10 * 1024 ; // 10KB
82
+ private static readonly defaultMaxSnippetCount = 7 ;
83
+ private static readonly defaultMaxSnippetLength = 3 * 1024 ;
84
84
private static readonly defaultDoAggregateSnippets = true ;
85
85
private completionContextCancellation = new vscode . CancellationTokenSource ( ) ;
86
86
private contextProviderDisposable : vscode . Disposable | undefined ;
@@ -152,25 +152,24 @@ export class CopilotCompletionContextProvider implements ContextResolver<Support
152
152
telemetry . addGetClientForElapsed ( getClientForDuration ) ;
153
153
if ( ! client ) { throw WellKnownErrors . clientNotFound ( ) ; }
154
154
const getCompletionContextStartTime = performance . now ( ) ;
155
-
156
155
const copilotCompletionContext : CopilotCompletionContextResult =
157
156
await client . getCompletionContext ( docUri , caretOffset , snippetsFeatureFlag , maxSnippetCount , maxSnippetLength , doAggregateSnippets , internalToken ) ;
158
157
telemetry . addRequestId ( copilotCompletionContext . requestId ) ;
159
- logMessage += `(id:${ copilotCompletionContext . requestId } ) (getClientFor elapsed:${ getClientForDuration } ms)` ;
158
+ logMessage += `(id: ${ copilotCompletionContext . requestId } )(getClientFor elapsed:${ getClientForDuration } ms)` ;
160
159
if ( ! copilotCompletionContext . areSnippetsMissing ) {
161
160
const resultMismatch = copilotCompletionContext . sourceFileUri !== docUri . toString ( ) ;
162
- if ( resultMismatch ) { logMessage += ` (mismatch TU vs result)` ; }
161
+ if ( resultMismatch ) { logMessage += `(mismatch TU vs result)` ; }
163
162
}
164
163
const cacheEntryId = randomUUID ( ) . toString ( ) ;
165
164
this . completionContextCache . set ( copilotCompletionContext . sourceFileUri , [ cacheEntryId , copilotCompletionContext ] ) ;
166
165
const duration = CopilotCompletionContextProvider . getRoundedDuration ( startTime ) ;
167
166
telemetry . addCacheComputedData ( duration , cacheEntryId ) ;
168
167
logMessage += ` cached in ${ duration } ms ${ copilotCompletionContext . traits . length } trait(s)` ;
169
- if ( copilotCompletionContext . areSnippetsMissing ) { logMessage += ` (missing code snippets) ` ; }
168
+ if ( copilotCompletionContext . areSnippetsMissing ) { logMessage += `(missing code snippets)` ; }
170
169
else {
171
170
logMessage += ` and ${ copilotCompletionContext . snippets . length } snippet(s)` ;
172
- logMessage += `, response.featureFlag:${ copilotCompletionContext . featureFlag } , \
173
- response.uri:${ copilotCompletionContext . sourceFileUri || "<not-set>" } :${ copilotCompletionContext . caretOffset } ` ;
171
+ logMessage += `( response.featureFlag:${ copilotCompletionContext . featureFlag } )` ;
172
+ logMessage += `( response.uri:${ copilotCompletionContext . sourceFileUri || "<not-set>" } :${ copilotCompletionContext . caretOffset } ) `;
174
173
}
175
174
176
175
telemetry . addResponseMetadata ( copilotCompletionContext . areSnippetsMissing , copilotCompletionContext . snippets . length ,
@@ -181,7 +180,7 @@ response.uri:${copilotCompletionContext.sourceFileUri || "<not-set>"}:${copilotC
181
180
} catch ( e : any ) {
182
181
if ( e instanceof vscode . CancellationError || e . message === CancellationError . Canceled ) {
183
182
telemetry . addInternalCanceled ( CopilotCompletionContextProvider . getRoundedDuration ( startTime ) ) ;
184
- logMessage += ` (internal cancellation) ` ;
183
+ logMessage += `(internal cancellation)` ;
185
184
throw InternalCancellationError ;
186
185
}
187
186
@@ -338,11 +337,18 @@ response.uri:${copilotCompletionContext.sourceFileUri || "<not-set>"}:${copilotC
338
337
} else { return [ defaultValue , defaultValue ? CopilotCompletionKind . GotFromCache : CopilotCompletionKind . MissingCacheMiss ] ; }
339
338
}
340
339
340
+ private static isStaleCacheHit ( caretOffset : number , cacheCaretOffset : number , maxCaretDistance : number ) : boolean {
341
+ return Math . abs ( caretOffset - caretOffset ) > maxCaretDistance ;
342
+ }
343
+
344
+ private static createContextItems ( copilotCompletionContext : CopilotCompletionContextResult | undefined ) : SupportedContextItem [ ] {
345
+ return [ ...copilotCompletionContext ?. snippets ?? [ ] , ...copilotCompletionContext ?. traits ?? [ ] ] as SupportedContextItem [ ] ;
346
+ }
347
+
341
348
public async resolve ( context : ResolveRequest , copilotCancel : vscode . CancellationToken ) : Promise < SupportedContextItem [ ] > {
342
349
const proposedEdits = context . documentContext . proposedEdits ;
343
- if ( proposedEdits ) { return [ ] ; } // Ignore the request if there are proposed edits.
344
350
const resolveStartTime = performance . now ( ) ;
345
- let logMessage = `Copilot: resolve(${ context . documentContext . uri } : ${ context . documentContext . offset } ):` ;
351
+ let logMessage = `Copilot: resolve(${ context . documentContext . uri } :${ context . documentContext . offset } ):` ;
346
352
const cppTimeBudgetMs = await this . fetchTimeBudgetMs ( context ) ;
347
353
const maxCaretDistance = await this . fetchMaxDistanceToCaret ( context ) ;
348
354
const maxSnippetCount = await this . fetchMaxSnippetCount ( context ) ;
@@ -363,37 +369,49 @@ response.uri:${copilotCompletionContext.sourceFileUri || "<not-set>"}:${copilotC
363
369
} ) ;
364
370
if ( featureFlag === undefined ) { return [ ] ; }
365
371
const cacheEntry : CacheEntry | undefined = this . completionContextCache . get ( docUri . toString ( ) ) ;
366
- const defaultValue = cacheEntry ?. [ 1 ] ;
367
- [ copilotCompletionContext , copilotCompletionContextKind ] = await this . resolveResultAndKind ( context , featureFlag ,
368
- telemetry . fork ( ) , defaultValue , resolveStartTime , cppTimeBudgetMs , maxSnippetCount , maxSnippetLength , doAggregateSnippets , copilotCancel ) ;
372
+ if ( proposedEdits ) {
373
+ const defaultValue = cacheEntry ?. [ 1 ] ;
374
+ const isStaleCache = defaultValue !== undefined ? CopilotCompletionContextProvider . isStaleCacheHit ( docOffset , defaultValue . caretOffset , maxCaretDistance ) : true ;
375
+ const contextItems = isStaleCache ? [ ] : CopilotCompletionContextProvider . createContextItems ( defaultValue ) ;
376
+ copilotCompletionContext = isStaleCache ? undefined : defaultValue ;
377
+ copilotCompletionContextKind = isStaleCache ? CopilotCompletionKind . StaleCacheHit : CopilotCompletionKind . GotFromCache ;
378
+ telemetry . addSpeculativeRequestMetadata ( proposedEdits . length ) ;
379
+ if ( cacheEntry ?. [ 0 ] ) {
380
+ telemetry . addCacheHitEntryGuid ( cacheEntry [ 0 ] ) ;
381
+ }
382
+ return contextItems ;
383
+ }
384
+ const [ resultContext , resultKind ] = await this . resolveResultAndKind ( context , featureFlag ,
385
+ telemetry . fork ( ) , cacheEntry ?. [ 1 ] , resolveStartTime , cppTimeBudgetMs , maxSnippetCount , maxSnippetLength , doAggregateSnippets , copilotCancel ) ;
386
+ copilotCompletionContext = resultContext ;
387
+ copilotCompletionContextKind = resultKind ;
388
+ logMessage += `(id: ${ copilotCompletionContext ?. requestId } )` ;
369
389
// Fix up copilotCompletionContextKind accounting for stale-cache-hits.
370
390
if ( copilotCompletionContextKind === CopilotCompletionKind . GotFromCache &&
371
391
copilotCompletionContext && cacheEntry ) {
372
392
telemetry . addCacheHitEntryGuid ( cacheEntry [ 0 ] ) ;
373
393
const cachedData = cacheEntry [ 1 ] ;
374
- if ( Math . abs ( cachedData . caretOffset - context . documentContext . offset ) > maxCaretDistance ) {
394
+ if ( CopilotCompletionContextProvider . isStaleCacheHit ( docOffset , cachedData . caretOffset , maxCaretDistance ) ) {
375
395
copilotCompletionContextKind = CopilotCompletionKind . StaleCacheHit ;
376
396
copilotCompletionContext . snippets = [ ] ;
377
397
}
378
398
}
379
- telemetry . addCompletionContextKind ( copilotCompletionContextKind ) ;
380
399
// Handle cancellation.
381
400
if ( copilotCompletionContextKind === CopilotCompletionKind . Canceled ) {
382
401
const duration : number = CopilotCompletionContextProvider . getRoundedDuration ( resolveStartTime ) ;
383
402
telemetry . addCopilotCanceled ( duration ) ;
384
403
throw new CopilotCancellationError ( ) ;
385
404
}
386
- logMessage += ` (id: ${ copilotCompletionContext ?. requestId } )` ;
387
- return [ ...copilotCompletionContext ?. snippets ?? [ ] , ...copilotCompletionContext ?. traits ?? [ ] ] as SupportedContextItem [ ] ;
405
+ return CopilotCompletionContextProvider . createContextItems ( copilotCompletionContext ) ;
388
406
} catch ( e : any ) {
389
407
if ( e instanceof CopilotCancellationError ) {
390
408
telemetry . addCopilotCanceled ( CopilotCompletionContextProvider . getRoundedDuration ( resolveStartTime ) ) ;
391
- logMessage += ` (copilot cancellation)` ;
409
+ logMessage += `(copilot cancellation)` ;
392
410
throw e ;
393
411
}
394
412
if ( e instanceof InternalCancellationError ) {
395
413
telemetry . addInternalCanceled ( CopilotCompletionContextProvider . getRoundedDuration ( resolveStartTime ) ) ;
396
- logMessage += ` (internal cancellation) ` ;
414
+ logMessage += `(internal cancellation)` ;
397
415
throw e ;
398
416
}
399
417
if ( e instanceof CancellationError ) { throw e ; }
@@ -403,13 +421,15 @@ response.uri:${copilotCompletionContext.sourceFileUri || "<not-set>"}:${copilotC
403
421
throw e ;
404
422
} finally {
405
423
const duration : number = CopilotCompletionContextProvider . getRoundedDuration ( resolveStartTime ) ;
406
- logMessage += `featureFlag:${ featureFlag ?. toString ( ) } , ` ;
424
+ logMessage += `(featureFlag:${ featureFlag ?. toString ( ) } )` ;
425
+ if ( proposedEdits ) { logMessage += `(speculative request, proposedEdits:${ proposedEdits . length } )` ; }
407
426
if ( copilotCompletionContext === undefined ) {
408
427
logMessage += `result is undefined and no code snippets provided(${ copilotCompletionContextKind . toString ( ) } ), elapsed time:${ duration } ms` ;
409
428
} else {
410
429
logMessage += `for ${ docUri } :${ docOffset } provided ${ copilotCompletionContext . snippets . length } code snippet(s)(${ copilotCompletionContextKind . toString ( ) } \
411
- ${ copilotCompletionContext ?. areSnippetsMissing ? ", missing code snippets" : "" } ) and ${ copilotCompletionContext . traits . length } trait(s), elapsed time:${ duration } ms`;
430
+ ${ copilotCompletionContext ?. areSnippetsMissing ? "( missing code snippets) " : "" } ) and ${ copilotCompletionContext . traits . length } trait(s), elapsed time:${ duration } ms`;
412
431
}
432
+ telemetry . addCompletionContextKind ( copilotCompletionContextKind ) ;
413
433
telemetry . addResponseMetadata ( copilotCompletionContext ?. areSnippetsMissing ?? true ,
414
434
copilotCompletionContext ?. snippets . length , copilotCompletionContext ?. traits . length ,
415
435
copilotCompletionContext ?. caretOffset , copilotCompletionContext ?. featureFlag ) ;
@@ -447,4 +467,3 @@ response.uri:${copilotCompletionContext.sourceFileUri || "<not-set>"}:${copilotC
447
467
}
448
468
}
449
469
}
450
-
0 commit comments