@@ -13,7 +13,6 @@ import { CopilotCompletionContextResult } from './client';
13
13
import { CopilotCompletionContextTelemetry } from './copilotCompletionContextTelemetry' ;
14
14
import { getCopilotApi } from './copilotProviders' ;
15
15
import { clients } from './extension' ;
16
- import { ProjectContext } from './lmTool' ;
17
16
import { CppSettings } from './settings' ;
18
17
19
18
class DefaultValueFallback extends Error {
@@ -82,6 +81,9 @@ export class CopilotCompletionContextProvider implements ContextResolver<Support
82
81
private completionContextCancellation = new vscode . CancellationTokenSource ( ) ;
83
82
private contextProviderDisposable : vscode . Disposable | undefined ;
84
83
84
+ constructor ( private readonly logger : Logger ) {
85
+ }
86
+
85
87
private async waitForCompletionWithTimeoutAndCancellation < T > ( promise : Promise < T > , defaultValue : T | undefined ,
86
88
timeout : number , copilotToken : vscode . CancellationToken ) : Promise < [ T | undefined , CopilotCompletionKind ] > {
87
89
const defaultValuePromise = new Promise < T > ( ( _resolve , reject ) => setTimeout ( ( ) => {
@@ -123,7 +125,7 @@ export class CopilotCompletionContextProvider implements ContextResolver<Support
123
125
// Get the completion context with a timeout and a cancellation token.
124
126
// The cancellationToken indicates that the value should not be returned nor cached.
125
127
private async getCompletionContextWithCancellation ( context : ResolveRequest , featureFlag : CopilotCompletionContextFeatures ,
126
- startTime : number , out : Logger , telemetry : CopilotCompletionContextTelemetry , internalToken : vscode . CancellationToken ) :
128
+ startTime : number , telemetry : CopilotCompletionContextTelemetry , internalToken : vscode . CancellationToken ) :
127
129
Promise < CopilotCompletionContextResult | undefined > {
128
130
const documentUri = context . documentContext . uri ;
129
131
const caretOffset = context . documentContext . offset ;
@@ -133,55 +135,42 @@ export class CopilotCompletionContextProvider implements ContextResolver<Support
133
135
telemetry . addRequestMetadata ( documentUri , caretOffset , context . completionId ,
134
136
context . documentContext . languageId , { featureFlag : snippetsFeatureFlag } ) ;
135
137
const docUri = vscode . Uri . parse ( documentUri ) ;
138
+ const getClientForTime = performance . now ( ) ;
136
139
const client = clients . getClientFor ( docUri ) ;
140
+ const getClientForDuration = CopilotCompletionContextProvider . getRoundedDuration ( getClientForTime ) ;
141
+ telemetry . addGetClientForElapsed ( getClientForDuration ) ;
137
142
if ( ! client ) { throw WellKnownErrors . clientNotFound ( ) ; }
138
143
const getCompletionContextStartTime = performance . now ( ) ;
139
144
140
- // Start collection of project traits concurrently with the completion context computation.
141
- const projectContextPromise = ( async ( ) : Promise < ProjectContext | undefined > => {
142
- const elapsedTimeMs = performance . now ( ) ;
143
- const projectContext = await client . getChatContext ( docUri , internalToken ) ;
144
- telemetry . addCppStandardVersionMetadata ( projectContext . standardVersion ,
145
- CopilotCompletionContextProvider . getRoundedDuration ( elapsedTimeMs ) ) ;
146
- return projectContext ;
147
- } ) ( ) ;
148
-
149
145
const copilotCompletionContext : CopilotCompletionContextResult =
150
146
await client . getCompletionContext ( docUri , caretOffset , snippetsFeatureFlag , internalToken ) ;
151
- copilotCompletionContext . codeSnippetsCount = copilotCompletionContext . snippets . length ;
152
147
telemetry . addRequestId ( copilotCompletionContext . requestId ) ;
153
- logMessage += ` (id:${ copilotCompletionContext . requestId } )` ;
154
- // Collect project traits and if any add them to the completion context.
155
- const projectContext = await projectContextPromise ;
156
- if ( projectContext ?. standardVersion ) {
157
- copilotCompletionContext . snippets . push ( { name : "C++ language standard version" , value : `This project uses the ${ projectContext . standardVersion } language standard version.` } ) ;
158
- copilotCompletionContext . traitsCount = 1 ;
148
+ logMessage += `(id:${ copilotCompletionContext . requestId } ) (getClientFor elapsed:${ getClientForDuration } ms)` ;
149
+ if ( ! copilotCompletionContext . areSnippetsMissing ) {
150
+ const resultMismatch = copilotCompletionContext . sourceFileUri !== docUri . toString ( ) ;
151
+ if ( resultMismatch ) { logMessage += ` (mismatch TU vs result)` ; }
159
152
}
160
-
161
- let resultMismatch = false ;
162
- if ( ! copilotCompletionContext . areCodeSnippetsMissing ) {
163
- resultMismatch = copilotCompletionContext . translationUnitUri !== docUri . toString ( ) ;
164
- const cacheEntryId = randomUUID ( ) . toString ( ) ;
165
- this . completionContextCache . set ( copilotCompletionContext . translationUnitUri , [ cacheEntryId , copilotCompletionContext ] ) ;
166
- const duration = CopilotCompletionContextProvider . getRoundedDuration ( startTime ) ;
167
- telemetry . addCacheComputedData ( duration , cacheEntryId ) ;
168
- if ( resultMismatch ) { logMessage += `, mismatch TU vs result` ; }
169
- logMessage += `, cached ${ copilotCompletionContext . snippets . length } snippets in ${ duration } ms` ;
170
- logMessage += `, response.featureFlag:${ copilotCompletionContext . featureFlag } ,\
171
- ${ copilotCompletionContext . translationUnitUri } :${ copilotCompletionContext . caretOffset } ,\
172
- snippetsCount:${ copilotCompletionContext . codeSnippetsCount } , traitsCount:${ copilotCompletionContext . traitsCount } ` ;
173
- } else {
174
- logMessage += ` (snippets are missing) ` ;
153
+ const cacheEntryId = randomUUID ( ) . toString ( ) ;
154
+ this . completionContextCache . set ( copilotCompletionContext . sourceFileUri , [ cacheEntryId , copilotCompletionContext ] ) ;
155
+ const duration = CopilotCompletionContextProvider . getRoundedDuration ( startTime ) ;
156
+ telemetry . addCacheComputedData ( duration , cacheEntryId ) ;
157
+ logMessage += ` cached in ${ duration } ms ${ copilotCompletionContext . traits . length } trait(s)` ;
158
+ if ( copilotCompletionContext . areSnippetsMissing ) { logMessage += ` (missing code-snippets) ` ; }
159
+ else {
160
+ logMessage += ` and ${ copilotCompletionContext . snippets . length } snippet(s)` ;
161
+ logMessage += `, response.featureFlag:${ copilotCompletionContext . featureFlag } , \
162
+ response.uri:${ copilotCompletionContext . sourceFileUri || "<not-set>" } :${ copilotCompletionContext . caretOffset } ` ;
175
163
}
176
- telemetry . addResponseMetadata ( copilotCompletionContext . areCodeSnippetsMissing , copilotCompletionContext . snippets . length , copilotCompletionContext . codeSnippetsCount ,
177
- copilotCompletionContext . traitsCount , copilotCompletionContext . caretOffset , copilotCompletionContext . featureFlag ) ;
164
+
165
+ telemetry . addResponseMetadata ( copilotCompletionContext . areSnippetsMissing , copilotCompletionContext . snippets . length ,
166
+ copilotCompletionContext . traits . length , copilotCompletionContext . caretOffset , copilotCompletionContext . featureFlag ) ;
178
167
telemetry . addComputeContextElapsed ( CopilotCompletionContextProvider . getRoundedDuration ( getCompletionContextStartTime ) ) ;
179
168
180
- return resultMismatch ? undefined : copilotCompletionContext ;
169
+ return copilotCompletionContext ;
181
170
} catch ( e : any ) {
182
171
if ( e instanceof vscode . CancellationError || e . message === CancellationError . Canceled ) {
183
172
telemetry . addInternalCanceled ( CopilotCompletionContextProvider . getRoundedDuration ( startTime ) ) ;
184
- logMessage += `, (internal cancellation)` ;
173
+ logMessage += ` (internal cancellation) ` ;
185
174
throw InternalCancellationError ;
186
175
}
187
176
@@ -190,14 +179,11 @@ export class CopilotCompletionContextProvider implements ContextResolver<Support
190
179
}
191
180
192
181
telemetry . addError ( ) ;
193
- if ( e . message && e . stack ) {
194
- out . appendLine ( `Copilot: getCompletionContextWithCancellation(${ documentUri } : ${ caretOffset } ): Error: '${ e . message } ', stack '${ e . stack } ` ) ;
195
- } else {
196
- out . appendLine ( `Copilot: getCompletionContextWithCancellation(${ documentUri } : ${ caretOffset } ): Error: '${ e } '` ) ;
197
- }
182
+ this . logger . appendLineAtLevel ( 7 , `Copilot: getCompletionContextWithCancellation(${ documentUri } : ${ caretOffset } ): Error: '${ e } '` ) ;
198
183
return undefined ;
199
184
} finally {
200
- out . appendLineAtLevel ( 6 , logMessage ) ;
185
+ this . logger .
186
+ appendLineAtLevel ( 7 , logMessage ) ;
201
187
telemetry . send ( "cache" ) ;
202
188
}
203
189
}
@@ -251,7 +237,7 @@ export class CopilotCompletionContextProvider implements ContextResolver<Support
251
237
}
252
238
253
239
public static async Create ( ) {
254
- const copilotCompletionProvider = new CopilotCompletionContextProvider ( ) ;
240
+ const copilotCompletionProvider = new CopilotCompletionContextProvider ( getOutputChannelLogger ( ) ) ;
255
241
await copilotCompletionProvider . registerCopilotContextProvider ( ) ;
256
242
return copilotCompletionProvider ;
257
243
}
@@ -267,26 +253,26 @@ export class CopilotCompletionContextProvider implements ContextResolver<Support
267
253
268
254
public async resolve ( context : ResolveRequest , copilotCancel : vscode . CancellationToken ) : Promise < SupportedContextItem [ ] > {
269
255
const resolveStartTime = performance . now ( ) ;
270
- const out : Logger = getOutputChannelLogger ( ) ;
271
- let logMessage = `Copilot: resolve(${ context . documentContext . uri } :${ context . documentContext . offset } ): ` ;
256
+ let logMessage = `Copilot: resolve(${ context . documentContext . uri } :${ context . documentContext . offset } ):` ;
272
257
const timeBudgetFactor = await this . fetchTimeBudgetFactor ( context ) ;
273
258
const maxCaretDistance = await this . fetchMaxDistanceToCaret ( context ) ;
274
259
const telemetry = new CopilotCompletionContextTelemetry ( ) ;
275
260
let copilotCompletionContext : CopilotCompletionContextResult | undefined ;
276
261
let copilotCompletionContextKind : CopilotCompletionKind = CopilotCompletionKind . Unknown ;
277
262
let featureFlag : CopilotCompletionContextFeatures | undefined ;
263
+ const docUri = context . documentContext . uri ;
264
+ const docOffset = context . documentContext . offset ;
278
265
try {
279
266
featureFlag = await this . getEnabledFeatureFlag ( context ) ;
280
267
telemetry . addRequestMetadata ( context . documentContext . uri , context . documentContext . offset ,
281
268
context . completionId , context . documentContext . languageId , { featureFlag, timeBudgetFactor, maxCaretDistance } ) ;
282
269
if ( featureFlag === undefined ) { return [ ] ; }
283
270
this . completionContextCancellation . cancel ( ) ;
284
271
this . completionContextCancellation = new vscode . CancellationTokenSource ( ) ;
285
- const docUri = context . documentContext . uri ;
286
272
const cacheEntry : CacheEntry | undefined = this . completionContextCache . get ( docUri . toString ( ) ) ;
287
273
const defaultValue = cacheEntry ?. [ 1 ] ;
288
274
const computeSnippetsPromise = this . getCompletionContextWithCancellation ( context , featureFlag ,
289
- resolveStartTime , out , telemetry . fork ( ) , this . completionContextCancellation . token ) ;
275
+ resolveStartTime , telemetry . fork ( ) , this . completionContextCancellation . token ) ;
290
276
[ copilotCompletionContext , copilotCompletionContextKind ] = await this . waitForCompletionWithTimeoutAndCancellation (
291
277
computeSnippetsPromise , defaultValue , context . timeBudget * timeBudgetFactor , copilotCancel ) ;
292
278
// Fix up copilotCompletionContextKind accounting for stale-cache-hits.
@@ -307,7 +293,7 @@ export class CopilotCompletionContextProvider implements ContextResolver<Support
307
293
throw new CopilotCancellationError ( ) ;
308
294
}
309
295
logMessage += ` (id:${ copilotCompletionContext ?. requestId } ) ` ;
310
- return copilotCompletionContext ?. snippets ?? [ ] ;
296
+ return [ ... copilotCompletionContext ?. snippets ?? [ ] , ... copilotCompletionContext ?. traits ?? [ ] ] as SupportedContextItem [ ] ;
311
297
} catch ( e : any ) {
312
298
if ( e instanceof CopilotCancellationError ) {
313
299
telemetry . addCopilotCanceled ( CopilotCompletionContextProvider . getRoundedDuration ( resolveStartTime ) ) ;
@@ -326,22 +312,20 @@ export class CopilotCompletionContextProvider implements ContextResolver<Support
326
312
throw e ;
327
313
} finally {
328
314
const duration : number = CopilotCompletionContextProvider . getRoundedDuration ( resolveStartTime ) ;
329
- logMessage += ` featureFlag:${ featureFlag ?. toString ( ) } ,` ;
315
+ logMessage += `featureFlag:${ featureFlag ?. toString ( ) } ,` ;
330
316
if ( copilotCompletionContext === undefined ) {
331
317
logMessage += ` result is undefined and no snippets provided (${ copilotCompletionContextKind . toString ( ) } ), elapsed time:${ duration } ms` ;
332
318
} else {
333
- const uri = copilotCompletionContext . translationUnitUri ? copilotCompletionContext . translationUnitUri : "<undefined-uri>" ;
334
- logMessage += ` for ${ uri } provided ${ copilotCompletionContext . codeSnippetsCount } code-snippets (${ copilotCompletionContextKind . toString ( ) } ,\
335
- ${ copilotCompletionContext ?. areCodeSnippetsMissing ? " missing code-snippets" : "" } ) and ${ copilotCompletionContext . traitsCount } traits, elapsed time:${ duration } ms`;
319
+ logMessage += ` for ${ docUri } :${ docOffset } provided ${ copilotCompletionContext . snippets . length } code-snippet(s) (${ copilotCompletionContextKind . toString ( ) } \
320
+ ${ copilotCompletionContext ?. areSnippetsMissing ? ", missing code-snippets" : "" } ) and ${ copilotCompletionContext . traits . length } trait(s), elapsed time:${ duration } ms`;
336
321
}
337
- telemetry . addResponseMetadata ( copilotCompletionContext ?. areCodeSnippetsMissing ?? true ,
338
- copilotCompletionContext ?. snippets ?. length ,
339
- copilotCompletionContext ?. codeSnippetsCount , copilotCompletionContext ?. traitsCount ,
322
+ telemetry . addResponseMetadata ( copilotCompletionContext ?. areSnippetsMissing ?? true ,
323
+ copilotCompletionContext ?. snippets . length , copilotCompletionContext ?. traits . length ,
340
324
copilotCompletionContext ?. caretOffset , copilotCompletionContext ?. featureFlag ) ;
341
325
telemetry . addResolvedElapsed ( duration ) ;
342
326
telemetry . addCacheSize ( this . completionContextCache . size ) ;
343
327
telemetry . send ( ) ;
344
- out . appendLineAtLevel ( 6 , logMessage ) ;
328
+ this . logger . appendLineAtLevel ( 7 , logMessage ) ;
345
329
}
346
330
}
347
331
0 commit comments