Skip to content

Commit df434df

Browse files
committed
Register context provider with Copilot chat
1 parent a11b972 commit df434df

File tree

1 file changed

+92
-31
lines changed

1 file changed

+92
-31
lines changed

src/lsptoolshost/copilot/contextProviders.ts

Lines changed: 92 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,12 @@
22
* Copyright (c) Microsoft Corporation. All rights reserved.
33
* Licensed under the MIT License. See License.txt in the project root for license information.
44
*--------------------------------------------------------------------------------------------*/
5-
import { ContextProviderApiV1, ResolveRequest, SupportedContextItem } from '@github/copilot-language-server';
5+
import {
6+
ContextProviderApiV1,
7+
ResolveRequest,
8+
SupportedContextItem,
9+
type ContextProvider,
10+
} from '@github/copilot-language-server';
611
import * as vscode from 'vscode';
712
import * as lsp from 'vscode-languageserver-protocol';
813
import { RoslynLanguageServer } from '../server/roslynLanguageServer';
@@ -73,49 +78,105 @@ export function registerCopilotContextProviders(
7378

7479
devkit.activate().then(async () => {
7580
try {
76-
const copilotApi = vscode.extensions.getExtension<CopilotApi>('github.copilot');
77-
if (!copilotApi) {
81+
const copilotClientApi = await getCopilotClientApi();
82+
const copilotChatApi = await getCopilotChatApi();
83+
if (!copilotClientApi && !copilotChatApi) {
7884
channel.debug(
79-
'Failed to find compatible version of GitHub Copilot extension installed. Skip registeration of Copilot context provider.'
85+
'Failed to find compatible version of GitHub Copilot extension installed. Skip registration of Copilot context provider.'
8086
);
8187
return;
8288
}
8389

84-
const api = await copilotApi.activate();
85-
const contextProviderApi = await api.getContextProviderAPI('v1');
90+
const provider: ContextProvider<SupportedContextItem> = {
91+
id: CSharpExtensionId, // use extension id as provider id for now
92+
selector: [{ language: 'csharp' }],
93+
resolver: {
94+
resolve: async (request, token) => {
95+
const contextResolveParam = createContextResolveParam(request);
96+
if (!contextResolveParam) {
97+
return [];
98+
}
99+
const items = await languageServer.sendRequest(
100+
resolveContextRequest,
101+
contextResolveParam,
102+
token
103+
);
104+
channel.trace(`Copilot context provider resolved ${items.length} items`);
105+
return items;
106+
},
107+
},
108+
};
109+
110+
let installCount = 0;
111+
if (copilotClientApi) {
112+
const disposable = await installContextProvider(copilotClientApi, provider);
113+
if (disposable) {
114+
context.subscriptions.push(disposable);
115+
installCount++;
116+
}
117+
}
118+
if (copilotChatApi) {
119+
const disposable = await installContextProvider(copilotChatApi, provider);
120+
if (disposable) {
121+
context.subscriptions.push(disposable);
122+
installCount++;
123+
}
124+
}
86125

87-
if (!contextProviderApi) {
126+
if (installCount === 0) {
88127
channel.debug(
89-
'Incompatible GitHub Copilot extension installed. Skip registeration of C# context providers.'
128+
'Incompatible GitHub Copilot extension installed. Skip registration of C# context providers.'
90129
);
91130
return;
92131
}
93-
94-
context.subscriptions.push(
95-
contextProviderApi.registerContextProvider<SupportedContextItem>({
96-
id: CSharpExtensionId, // use extension id as provider id for now
97-
selector: [{ language: 'csharp' }],
98-
resolver: {
99-
resolve: async (request, token) => {
100-
const contextResolveParam = createContextResolveParam(request);
101-
if (!contextResolveParam) {
102-
return [];
103-
}
104-
const items = await languageServer.sendRequest(
105-
resolveContextRequest,
106-
contextResolveParam,
107-
token
108-
);
109-
channel.trace(`Copilot context provider resolved ${items.length} items`);
110-
return items;
111-
},
112-
},
113-
})
114-
);
115-
116132
channel.debug('Registration of C# context provider for GitHub Copilot extension succeeded.');
117133
} catch (error) {
118134
channel.error('Failed to register Copilot context providers', error);
119135
}
120136
});
121137
}
138+
139+
async function getCopilotClientApi(): Promise<CopilotApi | undefined> {
140+
const extension = vscode.extensions.getExtension<CopilotApi>('github.copilot');
141+
if (!extension) {
142+
return undefined;
143+
}
144+
try {
145+
return await extension.activate();
146+
} catch {
147+
return undefined;
148+
}
149+
}
150+
151+
async function getCopilotChatApi(): Promise<CopilotApi | undefined> {
152+
type CopilotChatApi = { getAPI?(version: number): CopilotApi | undefined };
153+
const extension = vscode.extensions.getExtension<CopilotChatApi>('github.copilot-chat');
154+
if (!extension) {
155+
return undefined;
156+
}
157+
158+
let exports: CopilotChatApi | undefined;
159+
try {
160+
exports = await extension.activate();
161+
} catch {
162+
return undefined;
163+
}
164+
if (!exports || typeof exports.getAPI !== 'function') {
165+
return undefined;
166+
}
167+
return exports.getAPI(1);
168+
}
169+
170+
async function installContextProvider(
171+
copilotAPI: CopilotApi,
172+
contextProvider: ContextProvider<SupportedContextItem>
173+
): Promise<vscode.Disposable | undefined> {
174+
const hasGetContextProviderAPI = typeof copilotAPI.getContextProviderAPI === 'function';
175+
if (hasGetContextProviderAPI) {
176+
const contextAPI = await copilotAPI.getContextProviderAPI('v1');
177+
if (contextAPI) {
178+
return contextAPI.registerContextProvider(contextProvider);
179+
}
180+
}
181+
return undefined;
182+
}

0 commit comments

Comments
 (0)