Path: blob/main/extensions/copilot/src/extension/byok/vscode-node/byokContribution.ts
13399 views
/*---------------------------------------------------------------------------------------------1* Copyright (c) Microsoft Corporation. All rights reserved.2* Licensed under the MIT License. See License.txt in the project root for license information.3*--------------------------------------------------------------------------------------------*/4import { LanguageModelChatInformation, LanguageModelChatProvider, lm } from 'vscode';5import { IAuthenticationService } from '../../../platform/authentication/common/authentication';6import { ICAPIClientService } from '../../../platform/endpoint/common/capiClient';7import { IVSCodeExtensionContext } from '../../../platform/extContext/common/extensionContext';8import { ILogService } from '../../../platform/log/common/logService';9import { IFetcherService } from '../../../platform/networking/common/fetcherService';10import { Disposable, DisposableStore } from '../../../util/vs/base/common/lifecycle';11import { IInstantiationService } from '../../../util/vs/platform/instantiation/common/instantiation';12import { BYOKKnownModels, isBYOKEnabled } from '../../byok/common/byokProvider';13import { IExtensionContribution } from '../../common/contributions';14import { AnthropicLMProvider } from './anthropicProvider';15import { AzureBYOKModelProvider } from './azureProvider';16import { BYOKStorageService, IBYOKStorageService } from './byokStorageService';17import { CustomOAIBYOKModelProvider } from './customOAIProvider';18import { GeminiNativeBYOKLMProvider } from './geminiNativeProvider';19import { OllamaLMProvider } from './ollamaProvider';20import { OAIBYOKLMProvider } from './openAIProvider';21import { OpenRouterLMProvider } from './openRouterProvider';22import { XAIBYOKLMProvider } from './xAIProvider';2324export class BYOKContrib extends Disposable implements IExtensionContribution {25public readonly id: string = 'byok-contribution';26private readonly _byokStorageService: IBYOKStorageService;27private readonly _providers: Map<string, LanguageModelChatProvider<LanguageModelChatInformation>> = new Map();28private readonly _byokRegistrations = this._register(new DisposableStore());29private _byokProvidersRegistered = false;3031constructor(32@IFetcherService private readonly _fetcherService: IFetcherService,33@ILogService private readonly _logService: ILogService,34@ICAPIClientService private readonly _capiClientService: ICAPIClientService,35@IVSCodeExtensionContext extensionContext: IVSCodeExtensionContext,36@IAuthenticationService authService: IAuthenticationService,37@IInstantiationService private readonly _instantiationService: IInstantiationService,38) {39super();40this._byokStorageService = new BYOKStorageService(extensionContext);41this._authChange(authService, this._instantiationService);4243this._register(authService.onDidAuthenticationChange(() => {44this._authChange(authService, this._instantiationService);45}));46}4748private async _authChange(authService: IAuthenticationService, instantiationService: IInstantiationService) {49const byokEnabled = authService.copilotToken && isBYOKEnabled(authService.copilotToken, this._capiClientService);5051if (!byokEnabled && this._byokProvidersRegistered) {52this._logService.info('BYOK: Disabling BYOK providers due to account change.');53this._byokRegistrations.clear();54this._providers.clear();55this._byokProvidersRegistered = false;56return;57}5859if (byokEnabled && !this._byokProvidersRegistered) {60this._byokProvidersRegistered = true;61// Update known models list from CDN so all providers have the same list62const knownModels = await this.fetchKnownModelList(this._fetcherService);63if (this._store.isDisposed) {64return;65}66this._providers.set(OllamaLMProvider.providerName.toLowerCase(), instantiationService.createInstance(OllamaLMProvider, this._byokStorageService));67this._providers.set(AnthropicLMProvider.providerName.toLowerCase(), instantiationService.createInstance(AnthropicLMProvider, knownModels[AnthropicLMProvider.providerName], this._byokStorageService));68this._providers.set(GeminiNativeBYOKLMProvider.providerName.toLowerCase(), instantiationService.createInstance(GeminiNativeBYOKLMProvider, knownModels[GeminiNativeBYOKLMProvider.providerName], this._byokStorageService));69this._providers.set(XAIBYOKLMProvider.providerName.toLowerCase(), instantiationService.createInstance(XAIBYOKLMProvider, knownModels[XAIBYOKLMProvider.providerName], this._byokStorageService));70this._providers.set(OAIBYOKLMProvider.providerName.toLowerCase(), instantiationService.createInstance(OAIBYOKLMProvider, knownModels[OAIBYOKLMProvider.providerName], this._byokStorageService));71this._providers.set(OpenRouterLMProvider.providerName.toLowerCase(), instantiationService.createInstance(OpenRouterLMProvider, this._byokStorageService));72this._providers.set(AzureBYOKModelProvider.providerName.toLowerCase(), instantiationService.createInstance(AzureBYOKModelProvider, this._byokStorageService));73this._providers.set(CustomOAIBYOKModelProvider.providerName.toLowerCase(), instantiationService.createInstance(CustomOAIBYOKModelProvider, this._byokStorageService));7475for (const [providerName, provider] of this._providers) {76this._byokRegistrations.add(lm.registerLanguageModelChatProvider(providerName, provider));77}78}79}80private async fetchKnownModelList(fetcherService: IFetcherService): Promise<Record<string, BYOKKnownModels>> {81const data = await (await fetcherService.fetch('https://main.vscode-cdn.net/extensions/copilotChat.json', { method: 'GET', callSite: 'byok-known-models' })).json();82// Use this for testing with changes from a local file. Don't check in83// const data = JSON.parse((await this._fileSystemService.readFile(URI.file('/Users/roblou/code/vscode-engineering/chat/copilotChat.json'))).toString());84let knownModels: Record<string, BYOKKnownModels>;85if (data.version !== 1) {86this._logService.warn('BYOK: Copilot Chat known models list is not in the expected format. Defaulting to empty list.');87knownModels = {};88} else {89knownModels = data.modelInfo;90}91this._logService.info('BYOK: Copilot Chat known models list fetched successfully.');92return knownModels;93}94}9596