22 * Copyright (c) Microsoft Corporation. All Rights Reserved.
33 * See 'LICENSE' in the project root for license information.
44 * ------------------------------------------------------------------------------------------ */
5- import { ContextResolver , ResolveRequest , SupportedContextItem } from '@github/copilot-language-server' ;
5+ import { ContextResolver , ResolveRequest , SupportedContextItem , type ContextProvider } from '@github/copilot-language-server' ;
66import { randomUUID } from 'crypto' ;
77import * as vscode from 'vscode' ;
88import { DocumentSelector } from 'vscode-languageserver-protocol' ;
@@ -11,7 +11,7 @@ import { getOutputChannelLogger, Logger } from '../logger';
1111import * as telemetry from '../telemetry' ;
1212import { CopilotCompletionContextResult } from './client' ;
1313import { CopilotCompletionContextTelemetry } from './copilotCompletionContextTelemetry' ;
14- import { getCopilotApi } from './copilotProviders' ;
14+ import { getCopilotChatApi , getCopilotClientApi , type CopilotContextProviderAPI } from './copilotProviders' ;
1515import { clients } from './extension' ;
1616import { CppSettings } from './settings' ;
1717
@@ -83,7 +83,7 @@ export class CopilotCompletionContextProvider implements ContextResolver<Support
8383 private static readonly defaultMaxSnippetLength = 3 * 1024 ;
8484 private static readonly defaultDoAggregateSnippets = true ;
8585 private completionContextCancellation = new vscode . CancellationTokenSource ( ) ;
86- private contextProviderDisposable : vscode . Disposable | undefined ;
86+ private contextProviderDisposables : vscode . Disposable [ ] | undefined ;
8787 static readonly CppContextProviderEnabledFeatures = 'enabledFeatures' ;
8888 static readonly CppContextProviderTimeBudgetMs = 'timeBudgetMs' ;
8989 static readonly CppContextProviderMaxSnippetCount = 'maxSnippetCount' ;
@@ -312,7 +312,12 @@ export class CopilotCompletionContextProvider implements ContextResolver<Support
312312
313313 public dispose ( ) : void {
314314 this . completionContextCancellation . cancel ( ) ;
315- this . contextProviderDisposable ?. dispose ( ) ;
315+ if ( this . contextProviderDisposables ) {
316+ for ( const disposable of this . contextProviderDisposables ) {
317+ disposable . dispose ( ) ;
318+ }
319+ this . contextProviderDisposables = undefined ;
320+ }
316321 }
317322
318323 public removeFile ( fileUri : string ) : void {
@@ -444,18 +449,32 @@ ${copilotCompletionContext?.areSnippetsMissing ? "(missing code snippets)" : ""}
444449 const properties : Record < string , string > = { } ;
445450 const registerCopilotContextProvider = 'registerCopilotContextProvider' ;
446451 try {
447- const copilotApi = await getCopilotApi ( ) ;
448- if ( ! copilotApi ) { throw new CopilotContextProviderException ( "getCopilotApi() returned null, Copilot is missing or inactive." ) ; }
449- const hasGetContextProviderAPI = "getContextProviderAPI" in copilotApi ;
450- if ( ! hasGetContextProviderAPI ) { throw new CopilotContextProviderException ( "getContextProviderAPI() is not available." ) ; }
451- const contextAPI = await copilotApi . getContextProviderAPI ( "v1" ) ;
452- if ( ! contextAPI ) { throw new CopilotContextProviderException ( "getContextProviderAPI(v1) returned null." ) ; }
453- this . contextProviderDisposable = contextAPI . registerContextProvider ( {
452+ const copilotApi = await getCopilotClientApi ( ) ;
453+ const copilotChatApi = await getCopilotChatApi ( ) ;
454+ if ( ! copilotApi && ! copilotChatApi ) { throw new CopilotContextProviderException ( "getCopilotApi() returned null, Copilot is missing or inactive." ) ; }
455+ const contextProvider = {
454456 id : CopilotCompletionContextProvider . providerId ,
455457 selector : CopilotCompletionContextProvider . defaultCppDocumentSelector ,
456458 resolver : this
457- } ) ;
458- properties [ "cppCodeSnippetsProviderRegistered" ] = "true" ;
459+ } ;
460+ type InstallSummary = { hasGetContextProviderAPI : boolean ; hasAPI : boolean } ;
461+ const installSummary : { client ?: InstallSummary ; chat ?: InstallSummary } = { } ;
462+ if ( copilotApi ) {
463+ installSummary . client = await this . installContextProvider ( copilotApi , contextProvider ) ;
464+ }
465+ if ( copilotChatApi ) {
466+ installSummary . chat = await this . installContextProvider ( copilotChatApi , contextProvider ) ;
467+ }
468+ if ( installSummary . client ?. hasAPI || installSummary . chat ?. hasAPI ) {
469+ properties [ "cppCodeSnippetsProviderRegistered" ] = "true" ;
470+ } else {
471+ if ( installSummary . client ?. hasGetContextProviderAPI === false &&
472+ installSummary . chat ?. hasGetContextProviderAPI === false ) {
473+ throw new CopilotContextProviderException ( "getContextProviderAPI() is not available." ) ;
474+ } else {
475+ throw new CopilotContextProviderException ( "getContextProviderAPI(v1) returned null." ) ;
476+ }
477+ }
459478 } catch ( e ) {
460479 console . debug ( "Failed to register the Copilot Context Provider." ) ;
461480 properties [ "error" ] = "Failed to register the Copilot Context Provider" ;
@@ -466,4 +485,18 @@ ${copilotCompletionContext?.areSnippetsMissing ? "(missing code snippets)" : ""}
466485 telemetry . logCopilotEvent ( registerCopilotContextProvider , { ...properties } ) ;
467486 }
468487 }
488+
489+ private async installContextProvider ( copilotAPI : CopilotContextProviderAPI , contextProvider : ContextProvider < SupportedContextItem > ) : Promise < { hasGetContextProviderAPI : boolean ; hasAPI : boolean } > {
490+ const hasGetContextProviderAPI = typeof copilotAPI . getContextProviderAPI === 'function' ;
491+ if ( hasGetContextProviderAPI ) {
492+ const contextAPI = await copilotAPI . getContextProviderAPI ( "v1" ) ;
493+ if ( contextAPI ) {
494+ this . contextProviderDisposables = this . contextProviderDisposables ?? [ ] ;
495+ this . contextProviderDisposables . push ( contextAPI . registerContextProvider ( contextProvider ) ) ;
496+ }
497+ return { hasGetContextProviderAPI, hasAPI : contextAPI !== undefined } ;
498+ } else {
499+ return { hasGetContextProviderAPI : false , hasAPI : false } ;
500+ }
501+ }
469502}
0 commit comments