diff --git a/src/vs/workbench/api/browser/mainThreadLanguageModels.ts b/src/vs/workbench/api/browser/mainThreadLanguageModels.ts index 964628c863a..8b9ebfcf0dc 100644 --- a/src/vs/workbench/api/browser/mainThreadLanguageModels.ts +++ b/src/vs/workbench/api/browser/mainThreadLanguageModels.ts @@ -3,7 +3,6 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { coalesce } from 'vs/base/common/arrays'; import { CancellationToken } from 'vs/base/common/cancellation'; import { Emitter, Event } from 'vs/base/common/event'; import { Disposable, DisposableMap, DisposableStore, IDisposable, toDisposable } from 'vs/base/common/lifecycle'; @@ -37,8 +36,7 @@ export class MainThreadLanguageModels implements MainThreadLanguageModelsShape { @IExtensionService private readonly _extensionService: IExtensionService ) { this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostChatProvider); - - this._proxy.$acceptChatModelMetadata({ added: coalesce(_chatProviderService.getLanguageModelIds().map(id => _chatProviderService.lookupLanguageModel(id))) }); + this._proxy.$acceptChatModelMetadata({ added: _chatProviderService.getLanguageModelIds().map(id => ({ identifier: id, metadata: _chatProviderService.lookupLanguageModel(id)! })) }); this._store.add(_chatProviderService.onDidChangeLanguageModels(this._proxy.$acceptChatModelMetadata, this._proxy)); } @@ -88,18 +86,6 @@ export class MainThreadLanguageModels implements MainThreadLanguageModelsShape { async $prepareChatAccess(extension: ExtensionIdentifier, providerId: string, justification?: string): Promise { - const activate = this._extensionService.activateByEvent(`onLanguageModelAccess:${providerId}`); - const metadata = this._chatProviderService.lookupLanguageModel(providerId); - - if (metadata) { - return metadata; - } - - await Promise.race([ - activate, - Event.toPromise(Event.filter(this._chatProviderService.onDidChangeLanguageModels, e => Boolean(e.added?.some(value => value.identifier === providerId)))) - ]); - return this._chatProviderService.lookupLanguageModel(providerId); } diff --git a/src/vs/workbench/api/common/extHost.api.impl.ts b/src/vs/workbench/api/common/extHost.api.impl.ts index f5d4f04d280..d0009f2ec1f 100644 --- a/src/vs/workbench/api/common/extHost.api.impl.ts +++ b/src/vs/workbench/api/common/extHost.api.impl.ts @@ -1430,7 +1430,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I const lm: typeof vscode.lm = { selectChatModels: (selector) => { checkProposedApiEnabled(extension, 'languageModels'); - return extHostLanguageModels.selectLanguageModels(extension, selector); + return extHostLanguageModels.selectLanguageModels(extension, selector ?? {}); }, onDidChangeChatModels: (listener, thisArgs?, disposables?) => { checkProposedApiEnabled(extension, 'languageModels'); diff --git a/src/vs/workbench/api/common/extHost.protocol.ts b/src/vs/workbench/api/common/extHost.protocol.ts index e4a7a398823..130ffae9d6e 100644 --- a/src/vs/workbench/api/common/extHost.protocol.ts +++ b/src/vs/workbench/api/common/extHost.protocol.ts @@ -54,7 +54,7 @@ import { ChatAgentLocation, IChatAgentMetadata, IChatAgentRequest, IChatAgentRes import { IChatProgressResponseContent } from 'vs/workbench/contrib/chat/common/chatModel'; import { IChatFollowup, IChatProgress, IChatResponseErrorDetails, IChatUserActionEvent, InteractiveSessionVoteDirection } from 'vs/workbench/contrib/chat/common/chatService'; import { IChatRequestVariableValue, IChatVariableData, IChatVariableResolverProgress } from 'vs/workbench/contrib/chat/common/chatVariables'; -import { IChatMessage, IChatResponseFragment, ILanguageModelChatMetadata, ILanguageModelChatSelector } from 'vs/workbench/contrib/chat/common/languageModels'; +import { IChatMessage, IChatResponseFragment, ILanguageModelChatMetadata, ILanguageModelChatSelector, ILanguageModelsChangeEvent } from 'vs/workbench/contrib/chat/common/languageModels'; import { DebugConfigurationProviderTriggerKind, IAdapterDescriptor, IConfig, IDebugSessionReplMode, IDebugVisualization, IDebugVisualizationContext, IDebugVisualizationTreeItem, MainThreadDebugVisualization } from 'vs/workbench/contrib/debug/common/debug'; import * as notebookCommon from 'vs/workbench/contrib/notebook/common/notebookCommon'; import { CellExecutionUpdateType } from 'vs/workbench/contrib/notebook/common/notebookExecutionService'; @@ -1211,7 +1211,7 @@ export interface MainThreadLanguageModelsShape extends IDisposable { } export interface ExtHostLanguageModelsShape { - $acceptChatModelMetadata(data: { added?: ILanguageModelChatMetadata[]; removed?: string[] }): void; + $acceptChatModelMetadata(data: ILanguageModelsChangeEvent): void; $updateModelAccesslist(data: { from: ExtensionIdentifier; to: ExtensionIdentifier; enabled: boolean }[]): void; $provideLanguageModelResponse(handle: number, requestId: number, from: ExtensionIdentifier, messages: IChatMessage[], options: { [name: string]: any }, token: CancellationToken): Promise; $handleResponseFragment(requestId: number, chunk: IChatResponseFragment): Promise; diff --git a/src/vs/workbench/api/common/extHostLanguageModels.ts b/src/vs/workbench/api/common/extHostLanguageModels.ts index d19e5ee4d99..53351f21ca5 100644 --- a/src/vs/workbench/api/common/extHostLanguageModels.ts +++ b/src/vs/workbench/api/common/extHostLanguageModels.ts @@ -152,9 +152,9 @@ export class ExtHostLanguageModels implements ExtHostLanguageModelsShape { accountLabel: typeof metadata.auth === 'object' ? metadata.auth.label : undefined }; } - this._proxy.$registerLanguageModelProvider(handle, identifier, { + this._proxy.$registerLanguageModelProvider(handle, `${ExtensionIdentifier.toKey(extension.identifier)}/${handle}/${identifier}`, { extension: extension.identifier, - identifier: identifier, + id: identifier, vendor: metadata.vendor ?? ExtensionIdentifier.toKey(extension.identifier), name: metadata.name ?? '', family: metadata.family ?? '', @@ -211,20 +211,16 @@ export class ExtHostLanguageModels implements ExtHostLanguageModelsShape { //#region --- making request - $acceptChatModelMetadata(data: { added?: ILanguageModelChatMetadata[] | undefined; removed?: string[] | undefined }): void { - const added: string[] = []; - const removed: string[] = []; + $acceptChatModelMetadata(data: { added?: { identifier: string; metadata: ILanguageModelChatMetadata }[] | undefined; removed?: string[] | undefined }): void { if (data.added) { - for (const metadata of data.added) { - this._allLanguageModelData.set(metadata.identifier, { metadata, apiObjects: new ExtensionIdentifierMap() }); - added.push(metadata.identifier); + for (const { identifier, metadata } of data.added) { + this._allLanguageModelData.set(identifier, { metadata, apiObjects: new ExtensionIdentifierMap() }); } } if (data.removed) { for (const id of data.removed) { // clean up this._allLanguageModelData.delete(id); - removed.push(id); // cancel pending requests for this model for (const [key, value] of this._pendingRequest) { @@ -236,10 +232,10 @@ export class ExtHostLanguageModels implements ExtHostLanguageModelsShape { } } - this._onDidChangeProviders.fire(undefined); - // TODO@jrieken@TylerLeonhardt - this is a temporary hack to populate the auth providers - data.added?.forEach(this._fakeAuthPopulate, this); + data.added?.forEach(added => this._fakeAuthPopulate(added.metadata)); + + this._onDidChangeProviders.fire(undefined); } async selectLanguageModels(extension: IExtensionDescription, selector: vscode.LanguageModelChatSelector) { @@ -433,7 +429,7 @@ export class ExtHostLanguageModels implements ExtHostLanguageModelsShape { return local.provider.provideTokenCount(value, token); } - return this._proxy.$countTokens(data.metadata.identifier, (typeof value === 'string' ? value : typeConvert.LanguageModelChatMessage.from(value)), token); + return this._proxy.$countTokens(languageModelId, (typeof value === 'string' ? value : typeConvert.LanguageModelChatMessage.from(value)), token); } $updateModelAccesslist(data: { from: ExtensionIdentifier; to: ExtensionIdentifier; enabled: boolean }[]): void { diff --git a/src/vs/workbench/contrib/chat/common/languageModels.ts b/src/vs/workbench/contrib/chat/common/languageModels.ts index b5b90dcf1c5..d0021ad3e9f 100644 --- a/src/vs/workbench/contrib/chat/common/languageModels.ts +++ b/src/vs/workbench/contrib/chat/common/languageModels.ts @@ -34,8 +34,9 @@ export interface IChatResponseFragment { export interface ILanguageModelChatMetadata { readonly extension: ExtensionIdentifier; + readonly name: string; - readonly identifier: string; + readonly id: string; readonly vendor: string; readonly version: string; readonly family: string; @@ -66,11 +67,19 @@ export interface ILanguageModelChatSelector { export const ILanguageModelsService = createDecorator('ILanguageModelsService'); +export interface ILanguageModelsChangeEvent { + added?: { + identifier: string; + metadata: ILanguageModelChatMetadata; + }[]; + removed?: string[]; +} + export interface ILanguageModelsService { readonly _serviceBrand: undefined; - onDidChangeLanguageModels: Event<{ added?: ILanguageModelChatMetadata[]; removed?: string[] }>; + onDidChangeLanguageModels: Event; getLanguageModelIds(): string[]; @@ -113,7 +122,7 @@ export const languageModelExtensionPoint = ExtensionsRegistry.registerExtensionP }, activationEventsGenerator: (contribs: IUserFriendlyLanguageModel[], result: { push(item: string): void }) => { for (const contrib of contribs) { - result.push(`onLanguageModel:${contrib.vendor}`); + result.push(`onLanguageModelChat:${contrib.vendor}`); } } }); @@ -125,8 +134,8 @@ export class LanguageModelsService implements ILanguageModelsService { private readonly _providers = new Map(); private readonly _vendors = new Set(); - private readonly _onDidChangeProviders = new Emitter<{ added?: ILanguageModelChatMetadata[]; removed?: string[] }>(); - readonly onDidChangeLanguageModels: Event<{ added?: ILanguageModelChatMetadata[]; removed?: string[] }> = this._onDidChangeProviders.event; + private readonly _onDidChangeProviders = new Emitter(); + readonly onDidChangeLanguageModels: Event = this._onDidChangeProviders.event; constructor( @IExtensionService private readonly _extensionService: IExtensionService, @@ -161,10 +170,10 @@ export class LanguageModelsService implements ILanguageModelsService { } const removed: string[] = []; - for (const [key, value] of this._providers) { + for (const [identifier, value] of this._providers) { if (!this._vendors.has(value.metadata.vendor)) { - this._providers.delete(key); - removed.push(key); + this._providers.delete(identifier); + removed.push(identifier); } } if (removed.length > 0) { @@ -199,16 +208,16 @@ export class LanguageModelsService implements ILanguageModelsService { const result: string[] = []; - for (const model of this._providers.values()) { + for (const [identifier, model] of this._providers) { if (selector.vendor !== undefined && model.metadata.vendor === selector.vendor || selector.family !== undefined && model.metadata.family === selector.family || selector.version !== undefined && model.metadata.version === selector.version - || selector.identifier !== undefined && model.metadata.identifier === selector.identifier + || selector.identifier !== undefined && model.metadata.id === selector.identifier || selector.extension !== undefined && model.metadata.targetExtensions?.some(candidate => ExtensionIdentifier.equals(candidate, selector.extension)) ) { // true selection - result.push(model.metadata.identifier); + result.push(identifier); } else if (!selector || ( selector.vendor === undefined @@ -217,7 +226,7 @@ export class LanguageModelsService implements ILanguageModelsService { && selector.identifier === undefined) ) { // no selection - result.push(model.metadata.identifier); + result.push(identifier); } } @@ -234,7 +243,7 @@ export class LanguageModelsService implements ILanguageModelsService { throw new Error(`Chat response provider with identifier ${identifier} is already registered.`); } this._providers.set(identifier, provider); - this._onDidChangeProviders.fire({ added: [provider.metadata] }); + this._onDidChangeProviders.fire({ added: [{ identifier, metadata: provider.metadata }] }); return toDisposable(() => { if (this._providers.delete(identifier)) { this._onDidChangeProviders.fire({ removed: [identifier] });