55'use strict' ;
66
77import * as vscode from 'vscode' ;
8+ import { localize } from 'vscode-nls' ;
89import * as util from '../common' ;
9- import { ChatContextResult , GetIncludesResult } from './client' ;
10+ import * as logger from '../logger' ;
11+ import * as telemetry from '../telemetry' ;
12+ import { GetIncludesResult } from './client' ;
1013import { getActiveClient } from './extension' ;
14+ import { getCompilerArgumentFilterMap , getProjectContext } from './lmTool' ;
1115
1216export interface CopilotTrait {
1317 name : string ;
@@ -34,35 +38,113 @@ export async function registerRelatedFilesProvider(): Promise<void> {
3438 for ( const languageId of [ 'c' , 'cpp' , 'cuda-cpp' ] ) {
3539 api . registerRelatedFilesProvider (
3640 { extensionId : util . extensionContext . extension . id , languageId } ,
37- async ( _uri : vscode . Uri , context : { flags : Record < string , unknown > } , token : vscode . CancellationToken ) => {
38-
39- const getIncludesHandler = async ( ) => ( await getIncludesWithCancellation ( 1 , token ) ) ?. includedFiles . map ( file => vscode . Uri . file ( file ) ) ?? [ ] ;
40- const getTraitsHandler = async ( ) => {
41- const chatContext : ChatContextResult | undefined = await ( getActiveClient ( ) . getChatContext ( token ) ?? undefined ) ;
42-
43- if ( ! chatContext ) {
44- return undefined ;
41+ async ( uri : vscode . Uri , context : { flags : Record < string , unknown > } , token : vscode . CancellationToken ) => {
42+ const start = performance . now ( ) ;
43+ const telemetryProperties : Record < string , string > = { } ;
44+ const telemetryMetrics : Record < string , number > = { } ;
45+ try {
46+ const getIncludesHandler = async ( ) => ( await getIncludesWithCancellation ( 1 , token ) ) ?. includedFiles . map ( file => vscode . Uri . file ( file ) ) ?? [ ] ;
47+ const getTraitsHandler = async ( ) => {
48+ const projectContext = await getProjectContext ( uri , context , token ) ;
49+
50+ if ( ! projectContext ) {
51+ return undefined ;
52+ }
53+
54+ let traits : CopilotTrait [ ] = [
55+ { name : "intelliSenseDisclaimer" , value : '' , includeInPrompt : true , promptTextOverride : `IntelliSense is currently configured with the following compiler information. It reflects the active configuration, and the project may have more configurations targeting different platforms.` } ,
56+ { name : "intelliSenseDisclaimerBeginning" , value : '' , includeInPrompt : true , promptTextOverride : `Beginning of IntelliSense information.` }
57+ ] ;
58+ if ( projectContext . language ) {
59+ traits . push ( { name : "language" , value : projectContext . language , includeInPrompt : true , promptTextOverride : `The language is ${ projectContext . language } .` } ) ;
60+ }
61+ if ( projectContext . compiler ) {
62+ traits . push ( { name : "compiler" , value : projectContext . compiler , includeInPrompt : true , promptTextOverride : `This project compiles using ${ projectContext . compiler } .` } ) ;
63+ }
64+ if ( projectContext . standardVersion ) {
65+ traits . push ( { name : "standardVersion" , value : projectContext . standardVersion , includeInPrompt : true , promptTextOverride : `This project uses the ${ projectContext . standardVersion } language standard.` } ) ;
66+ }
67+ if ( projectContext . targetPlatform ) {
68+ traits . push ( { name : "targetPlatform" , value : projectContext . targetPlatform , includeInPrompt : true , promptTextOverride : `This build targets ${ projectContext . targetPlatform } .` } ) ;
69+ }
70+ if ( projectContext . targetArchitecture ) {
71+ traits . push ( { name : "targetArchitecture" , value : projectContext . targetArchitecture , includeInPrompt : true , promptTextOverride : `This build targets ${ projectContext . targetArchitecture } .` } ) ;
72+ }
73+
74+ if ( projectContext . compiler ) {
75+ // We will process compiler arguments based on copilotcppXXXCompilerArgumentFilters and copilotcppCompilerArgumentDirectAskMap feature flags.
76+ // The copilotcppXXXCompilerArgumentFilters are maps. The keys are regex strings for filtering and the values, if not empty,
77+ // are the prompt text to use when no arguments are found.
78+ // copilotcppCompilerArgumentDirectAskMap map individual matched argument to a prompt text.
79+ // For duplicate matches, the last one will be used.
80+ const filterMap = getCompilerArgumentFilterMap ( projectContext . compiler , context ) ;
81+ if ( filterMap !== undefined ) {
82+ const directAskMap : Record < string , string > = context . flags . copilotcppCompilerArgumentDirectAskMap ? JSON . parse ( context . flags . copilotcppCompilerArgumentDirectAskMap as string ) : { } ;
83+ let directAsks : string = '' ;
84+ const remainingArguments : string [ ] = [ ] ;
85+
86+ for ( const key in filterMap ) {
87+ if ( ! key ) {
88+ continue ;
89+ }
90+
91+ const matchedArgument = projectContext . compilerArguments [ key ] as string ;
92+ if ( matchedArgument ?. length > 0 ) {
93+ if ( directAskMap [ matchedArgument ] ) {
94+ directAsks += `${ directAskMap [ matchedArgument ] } ` ;
95+ } else {
96+ remainingArguments . push ( matchedArgument ) ;
97+ }
98+ } else if ( filterMap [ key ] ) {
99+ // Use the prompt text in the absence of argument.
100+ directAsks += `${ filterMap [ key ] } ` ;
101+ }
102+ }
103+
104+ if ( remainingArguments . length > 0 ) {
105+ const compilerArgumentsValue = remainingArguments . join ( ", " ) ;
106+ traits . push ( { name : "compilerArguments" , value : compilerArgumentsValue , includeInPrompt : true , promptTextOverride : `The compiler arguments include: ${ compilerArgumentsValue } .` } ) ;
107+ }
108+
109+ if ( directAsks ) {
110+ traits . push ( { name : "directAsks" , value : directAsks , includeInPrompt : true , promptTextOverride : directAsks } ) ;
111+ }
112+ }
113+ }
114+
115+ traits . push ( { name : "intelliSenseDisclaimerEnd" , value : '' , includeInPrompt : true , promptTextOverride : `End of IntelliSense information.` } ) ;
116+
117+ const includeTraitsArray = context . flags . copilotcppIncludeTraits ? context . flags . copilotcppIncludeTraits as string [ ] : [ ] ;
118+ const includeTraits = new Set ( includeTraitsArray ) ;
119+ telemetryProperties [ "includeTraits" ] = includeTraitsArray . join ( ',' ) ;
120+
121+ // standardVersion trait is enabled by default.
122+ traits = traits . filter ( trait => includeTraits . has ( trait . name ) || trait . name === 'standardVersion' ) ;
123+
124+ telemetryProperties [ "traits" ] = traits . map ( trait => trait . name ) . join ( ',' ) ;
125+ return traits . length > 0 ? traits : undefined ;
126+ } ;
127+
128+ // Call both handlers in parallel
129+ const traitsPromise = getTraitsHandler ( ) ;
130+ const includesPromise = getIncludesHandler ( ) ;
131+
132+ return { entries : await includesPromise , traits : await traitsPromise } ;
133+ }
134+ catch ( exception ) {
135+ try {
136+ const err : Error = exception as Error ;
137+ logger . getOutputChannelLogger ( ) . appendLine ( localize ( "copilot.relatedfilesprovider.error" , "Error while retrieving result. Reason: {0}" , err . message ) ) ;
45138 }
46-
47- let traits : CopilotTrait [ ] = [
48- { name : "language" , value : chatContext . language , includeInPrompt : true , promptTextOverride : `The language is ${ chatContext . language } .` } ,
49- { name : "compiler" , value : chatContext . compiler , includeInPrompt : true , promptTextOverride : `This project compiles using ${ chatContext . compiler } .` } ,
50- { name : "standardVersion" , value : chatContext . standardVersion , includeInPrompt : true , promptTextOverride : `This project uses the ${ chatContext . standardVersion } language standard.` } ,
51- { name : "targetPlatform" , value : chatContext . targetPlatform , includeInPrompt : true , promptTextOverride : `This build targets ${ chatContext . targetPlatform } .` } ,
52- { name : "targetArchitecture" , value : chatContext . targetArchitecture , includeInPrompt : true , promptTextOverride : `This build targets ${ chatContext . targetArchitecture } .` }
53- ] ;
54-
55- const excludeTraits = context . flags . copilotcppExcludeTraits as string [ ] ?? [ ] ;
56- traits = traits . filter ( trait => ! excludeTraits . includes ( trait . name ) ) ;
57-
58- return traits . length > 0 ? traits : undefined ;
59- } ;
60-
61- // Call both handlers in parallel
62- const traitsPromise = ( ( context . flags . copilotcppTraits as boolean ) ?? false ) ? getTraitsHandler ( ) : Promise . resolve ( undefined ) ;
63- const includesPromise = getIncludesHandler ( ) ;
64-
65- return { entries : await includesPromise , traits : await traitsPromise } ;
139+ catch {
140+ // Intentionally swallow any exception.
141+ }
142+ telemetryProperties [ "error" ] = "true" ;
143+ throw exception ; // Throw the exception for auto-retry.
144+ } finally {
145+ telemetryMetrics [ 'duration' ] = performance . now ( ) - start ;
146+ telemetry . logCopilotEvent ( 'RelatedFilesProvider' , telemetryProperties , telemetryMetrics ) ;
147+ }
66148 }
67149 ) ;
68150 }
0 commit comments