mirror of
https://github.com/Microsoft/vscode
synced 2024-09-13 13:46:13 +00:00
add LanguageModelChat
as explict object and add a select-function as the only way of getting to them
This commit is contained in:
parent
3ec5b4a291
commit
0d55bb645f
|
@ -38,8 +38,8 @@ export class MainThreadLanguageModels implements MainThreadLanguageModelsShape {
|
|||
) {
|
||||
this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostChatProvider);
|
||||
|
||||
this._proxy.$updateLanguageModels({ added: coalesce(_chatProviderService.getLanguageModelIds().map(id => _chatProviderService.lookupLanguageModel(id))) });
|
||||
this._store.add(_chatProviderService.onDidChangeLanguageModels(this._proxy.$updateLanguageModels, this._proxy));
|
||||
this._proxy.$acceptChatModelMetadata({ added: coalesce(_chatProviderService.getLanguageModelIds().map(id => _chatProviderService.lookupLanguageModel(id))) });
|
||||
this._store.add(_chatProviderService.onDidChangeLanguageModels(this._proxy.$acceptChatModelMetadata, this._proxy));
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
|
@ -78,6 +78,10 @@ export class MainThreadLanguageModels implements MainThreadLanguageModelsShape {
|
|||
this._providerRegistrations.deleteAndDispose(handle);
|
||||
}
|
||||
|
||||
$selectChatModels(selector: Partial<ILanguageModelChatMetadata>): Promise<string[]> {
|
||||
return this._chatProviderService.selectLanguageModels(selector);
|
||||
}
|
||||
|
||||
$whenLanguageModelChatRequestMade(identifier: string, extensionId: ExtensionIdentifier, participant?: string | undefined, tokenCount?: number | undefined): void {
|
||||
this._languageModelStatsService.update(identifier, extensionId, participant, tokenCount);
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { CancellationToken, CancellationTokenSource } from 'vs/base/common/cancellation';
|
||||
import { CancellationTokenSource } from 'vs/base/common/cancellation';
|
||||
import * as errors from 'vs/base/common/errors';
|
||||
import { Emitter, Event } from 'vs/base/common/event';
|
||||
import { combinedDisposable } from 'vs/base/common/lifecycle';
|
||||
|
@ -1428,29 +1428,14 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
|
|||
|
||||
// namespace: lm
|
||||
const lm: typeof vscode.lm = {
|
||||
get languageModels() {
|
||||
selectLanguageModels: (selector) => {
|
||||
checkProposedApiEnabled(extension, 'languageModels');
|
||||
return extHostLanguageModels.getLanguageModelIds();
|
||||
return extHostLanguageModels.selectLanguageModels(extension, selector);
|
||||
},
|
||||
onDidChangeLanguageModels: (listener, thisArgs?, disposables?) => {
|
||||
onDidChangeChatModels: (listener, thisArgs?, disposables?) => {
|
||||
checkProposedApiEnabled(extension, 'languageModels');
|
||||
return extHostLanguageModels.onDidChangeProviders(listener, thisArgs, disposables);
|
||||
},
|
||||
sendChatRequest(languageModel: string, messages: (vscode.LanguageModelChatMessage | vscode.LanguageModelChatMessage2)[], options?: vscode.LanguageModelChatRequestOptions, token?: vscode.CancellationToken) {
|
||||
checkProposedApiEnabled(extension, 'languageModels');
|
||||
token ??= CancellationToken.None;
|
||||
options ??= {};
|
||||
return extHostLanguageModels.sendChatRequest(extension, languageModel, messages, options, token);
|
||||
},
|
||||
computeTokenLength(languageModel: string, text: string | vscode.LanguageModelChatMessage, token?: vscode.CancellationToken) {
|
||||
checkProposedApiEnabled(extension, 'languageModels');
|
||||
token ??= CancellationToken.None;
|
||||
return extHostLanguageModels.computeTokenLength(languageModel, text, token);
|
||||
},
|
||||
getLanguageModelInformation(languageModel: string) {
|
||||
checkProposedApiEnabled(extension, 'languageModels');
|
||||
return extHostLanguageModels.getLanguageModelInfo(languageModel);
|
||||
},
|
||||
// --- embeddings
|
||||
get embeddingModels() {
|
||||
checkProposedApiEnabled(extension, 'embeddings');
|
||||
|
|
|
@ -1201,6 +1201,8 @@ export interface MainThreadLanguageModelsShape extends IDisposable {
|
|||
$unregisterProvider(handle: number): void;
|
||||
$handleProgressChunk(requestId: number, chunk: IChatResponseFragment): Promise<void>;
|
||||
|
||||
$selectChatModels(selector: Partial<ILanguageModelChatMetadata>): Promise<string[]>;
|
||||
|
||||
$prepareChatAccess(extension: ExtensionIdentifier, providerId: string, justification?: string): Promise<ILanguageModelChatMetadata | undefined>;
|
||||
$fetchResponse(extension: ExtensionIdentifier, provider: string, requestId: number, messages: IChatMessage[], options: {}, token: CancellationToken): Promise<any>;
|
||||
|
||||
|
@ -1209,7 +1211,7 @@ export interface MainThreadLanguageModelsShape extends IDisposable {
|
|||
}
|
||||
|
||||
export interface ExtHostLanguageModelsShape {
|
||||
$updateLanguageModels(data: { added?: ILanguageModelChatMetadata[]; removed?: string[] }): void;
|
||||
$acceptChatModelMetadata(data: { added?: ILanguageModelChatMetadata[]; removed?: string[] }): 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<any>;
|
||||
$handleResponseFragment(requestId: number, chunk: IChatResponseFragment): Promise<void>;
|
||||
|
|
|
@ -3,26 +3,26 @@
|
|||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { AsyncIterableSource, Barrier } from 'vs/base/common/async';
|
||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
import { CancellationError } from 'vs/base/common/errors';
|
||||
import { Emitter, Event } from 'vs/base/common/event';
|
||||
import { Iterable } from 'vs/base/common/iterator';
|
||||
import { IDisposable, toDisposable } from 'vs/base/common/lifecycle';
|
||||
import { localize } from 'vs/nls';
|
||||
import { ExtensionIdentifier, ExtensionIdentifierMap, ExtensionIdentifierSet, IExtensionDescription } from 'vs/platform/extensions/common/extensions';
|
||||
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { ILogService } from 'vs/platform/log/common/log';
|
||||
import { Progress } from 'vs/platform/progress/common/progress';
|
||||
import { ExtHostLanguageModelsShape, MainContext, MainThreadLanguageModelsShape } from 'vs/workbench/api/common/extHost.protocol';
|
||||
import { IExtHostAuthentication } from 'vs/workbench/api/common/extHostAuthentication';
|
||||
import { IExtHostRpcService } from 'vs/workbench/api/common/extHostRpcService';
|
||||
import * as typeConvert from 'vs/workbench/api/common/extHostTypeConverters';
|
||||
import * as extHostTypes from 'vs/workbench/api/common/extHostTypes';
|
||||
import type * as vscode from 'vscode';
|
||||
import { Progress } from 'vs/platform/progress/common/progress';
|
||||
import { IChatMessage, IChatResponseFragment, ILanguageModelChatMetadata } from 'vs/workbench/contrib/chat/common/languageModels';
|
||||
import { ExtensionIdentifier, ExtensionIdentifierMap, ExtensionIdentifierSet, IExtensionDescription } from 'vs/platform/extensions/common/extensions';
|
||||
import { AsyncIterableSource, Barrier } from 'vs/base/common/async';
|
||||
import { Emitter, Event } from 'vs/base/common/event';
|
||||
import { localize } from 'vs/nls';
|
||||
import { INTERNAL_AUTH_PROVIDER_PREFIX } from 'vs/workbench/services/authentication/common/authentication';
|
||||
import { CancellationError } from 'vs/base/common/errors';
|
||||
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { IExtHostRpcService } from 'vs/workbench/api/common/extHostRpcService';
|
||||
import { IExtHostAuthentication } from 'vs/workbench/api/common/extHostAuthentication';
|
||||
import { ILogService } from 'vs/platform/log/common/log';
|
||||
import { Iterable } from 'vs/base/common/iterator';
|
||||
import { checkProposedApiEnabled } from 'vs/workbench/services/extensions/common/extensions';
|
||||
import type * as vscode from 'vscode';
|
||||
|
||||
export interface IExtHostLanguageModels extends ExtHostLanguageModels { }
|
||||
|
||||
|
@ -110,7 +110,6 @@ class LanguageModelResponse {
|
|||
stream.resolve();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export class ExtHostLanguageModels implements ExtHostLanguageModelsShape {
|
||||
|
@ -121,11 +120,11 @@ export class ExtHostLanguageModels implements ExtHostLanguageModelsShape {
|
|||
|
||||
private readonly _proxy: MainThreadLanguageModelsShape;
|
||||
private readonly _onDidChangeModelAccess = new Emitter<{ from: ExtensionIdentifier; to: ExtensionIdentifier }>();
|
||||
private readonly _onDidChangeProviders = new Emitter<vscode.LanguageModelChangeEvent>();
|
||||
private readonly _onDidChangeProviders = new Emitter<void>();
|
||||
readonly onDidChangeProviders = this._onDidChangeProviders.event;
|
||||
|
||||
private readonly _languageModels = new Map<number, LanguageModelData>();
|
||||
private readonly _allLanguageModelData = new Map<string, ILanguageModelChatMetadata>(); // these are ALL models, not just the one in this EH
|
||||
private readonly _allLanguageModelData = new Map<string, { metadata: ILanguageModelChatMetadata; apiObjects: ExtensionIdentifierMap<vscode.LanguageModelChat> }>(); // these are ALL models, not just the one in this EH
|
||||
private readonly _modelAccessList = new ExtensionIdentifierMap<ExtensionIdentifierSet>();
|
||||
private readonly _pendingRequest = new Map<number, { languageModelId: string; res: LanguageModelResponse }>();
|
||||
|
||||
|
@ -156,7 +155,9 @@ export class ExtHostLanguageModels implements ExtHostLanguageModelsShape {
|
|||
this._proxy.$registerLanguageModelProvider(handle, identifier, {
|
||||
extension: extension.identifier,
|
||||
identifier: identifier,
|
||||
vendor: metadata.vendor ?? ExtensionIdentifier.toKey(extension.identifier),
|
||||
name: metadata.name ?? '',
|
||||
family: metadata.family ?? '',
|
||||
version: metadata.version,
|
||||
tokens: metadata.tokens,
|
||||
auth
|
||||
|
@ -209,12 +210,12 @@ export class ExtHostLanguageModels implements ExtHostLanguageModelsShape {
|
|||
|
||||
//#region --- making request
|
||||
|
||||
$updateLanguageModels(data: { added?: ILanguageModelChatMetadata[] | undefined; removed?: string[] | undefined }): void {
|
||||
$acceptChatModelMetadata(data: { added?: ILanguageModelChatMetadata[] | undefined; removed?: string[] | undefined }): void {
|
||||
const added: string[] = [];
|
||||
const removed: string[] = [];
|
||||
if (data.added) {
|
||||
for (const metadata of data.added) {
|
||||
this._allLanguageModelData.set(metadata.identifier, metadata);
|
||||
this._allLanguageModelData.set(metadata.identifier, { metadata, apiObjects: new ExtensionIdentifierMap() });
|
||||
added.push(metadata.identifier);
|
||||
}
|
||||
}
|
||||
|
@ -234,39 +235,65 @@ export class ExtHostLanguageModels implements ExtHostLanguageModelsShape {
|
|||
}
|
||||
}
|
||||
|
||||
this._onDidChangeProviders.fire(Object.freeze({
|
||||
added: Object.freeze(added),
|
||||
removed: Object.freeze(removed)
|
||||
}));
|
||||
this._onDidChangeProviders.fire(undefined);
|
||||
|
||||
// TODO@jrieken@TylerLeonhardt - this is a temporary hack to populate the auth providers
|
||||
data.added?.forEach(this._fakeAuthPopulate, this);
|
||||
}
|
||||
|
||||
getLanguageModelIds(): string[] {
|
||||
return Array.from(this._allLanguageModelData.keys());
|
||||
}
|
||||
async selectLanguageModels(extension: IExtensionDescription, selector: vscode.LanguageModelChatSelector) {
|
||||
|
||||
$updateModelAccesslist(data: { from: ExtensionIdentifier; to: ExtensionIdentifier; enabled: boolean }[]): void {
|
||||
const updated = new Array<{ from: ExtensionIdentifier; to: ExtensionIdentifier }>();
|
||||
for (const { from, to, enabled } of data) {
|
||||
const set = this._modelAccessList.get(from) ?? new ExtensionIdentifierSet();
|
||||
const oldValue = set.has(to);
|
||||
if (oldValue !== enabled) {
|
||||
if (enabled) {
|
||||
set.add(to);
|
||||
} else {
|
||||
set.delete(to);
|
||||
}
|
||||
this._modelAccessList.set(from, set);
|
||||
const newItem = { from, to };
|
||||
updated.push(newItem);
|
||||
this._onDidChangeModelAccess.fire(newItem);
|
||||
// this triggers extension activation
|
||||
const models = await this._proxy.$selectChatModels(selector);
|
||||
|
||||
const result: vscode.LanguageModelChat[] = [];
|
||||
const that = this;
|
||||
for (const identifier of models) {
|
||||
const data = this._allLanguageModelData.get(identifier);
|
||||
if (!data) {
|
||||
// model gone? is this an error on us?
|
||||
continue;
|
||||
}
|
||||
|
||||
let apiObject = data.apiObjects.get(extension.identifier);
|
||||
|
||||
if (!apiObject) {
|
||||
apiObject = {
|
||||
id: identifier,
|
||||
vendor: data.metadata.vendor,
|
||||
family: data.metadata.family,
|
||||
version: data.metadata.version,
|
||||
name: data.metadata.name,
|
||||
contextSize: data.metadata.tokens,
|
||||
computeTokenLength(text, token) {
|
||||
if (!that._allLanguageModelData.has(identifier)) {
|
||||
throw extHostTypes.LanguageModelError.NotFound(identifier);
|
||||
}
|
||||
return that._computeTokenLength(identifier, text, token ?? CancellationToken.None);
|
||||
},
|
||||
sendRequest(messages, options, token) {
|
||||
if (!that._allLanguageModelData.has(identifier)) {
|
||||
throw extHostTypes.LanguageModelError.NotFound(identifier);
|
||||
}
|
||||
return that._sendChatRequest(extension, identifier, messages, options ?? {}, token ?? CancellationToken.None);
|
||||
}
|
||||
};
|
||||
|
||||
Object.freeze(apiObject);
|
||||
data.apiObjects.set(extension.identifier, apiObject);
|
||||
}
|
||||
|
||||
result.push(apiObject);
|
||||
}
|
||||
|
||||
if (result.length === 0) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
async sendChatRequest(extension: IExtensionDescription, languageModelId: string, messages: (vscode.LanguageModelChatMessage | vscode.LanguageModelChatMessage2)[], options: vscode.LanguageModelChatRequestOptions, token: CancellationToken) {
|
||||
private async _sendChatRequest(extension: IExtensionDescription, languageModelId: string, messages: vscode.LanguageModelChatMessage[], options: vscode.LanguageModelChatRequestOptions, token: CancellationToken) {
|
||||
|
||||
const internalMessages: IChatMessage[] = this._convertMessages(extension, messages);
|
||||
|
||||
|
@ -329,17 +356,10 @@ export class ExtHostLanguageModels implements ExtHostLanguageModelsShape {
|
|||
private _convertMessages(extension: IExtensionDescription, messages: vscode.LanguageModelChatMessage[]) {
|
||||
const internalMessages: IChatMessage[] = [];
|
||||
for (const message of messages) {
|
||||
if (message instanceof extHostTypes.LanguageModelChatMessage) {
|
||||
if (message.role as number === extHostTypes.LanguageModelChatMessageRole.System) {
|
||||
checkProposedApiEnabled(extension, 'languageModelSystem');
|
||||
}
|
||||
internalMessages.push(typeConvert.LanguageModelChatMessage.from(message));
|
||||
} else {
|
||||
if (message instanceof extHostTypes.LanguageModelChatSystemMessage) {
|
||||
checkProposedApiEnabled(extension, 'languageModelSystem');
|
||||
}
|
||||
internalMessages.push(typeConvert.LanguageModelChatMessage.from(message));
|
||||
if (message.role as number === extHostTypes.LanguageModelChatMessageRole.System) {
|
||||
checkProposedApiEnabled(extension, 'languageModelSystem');
|
||||
}
|
||||
internalMessages.push(typeConvert.LanguageModelChatMessage.from(message));
|
||||
}
|
||||
return internalMessages;
|
||||
}
|
||||
|
@ -399,7 +419,7 @@ export class ExtHostLanguageModels implements ExtHostLanguageModelsShape {
|
|||
}
|
||||
}
|
||||
|
||||
async computeTokenLength(languageModelId: string, value: string | vscode.LanguageModelChatMessage, token: vscode.CancellationToken): Promise<number> {
|
||||
private async _computeTokenLength(languageModelId: string, value: string | vscode.LanguageModelChatMessage, token: vscode.CancellationToken): Promise<number> {
|
||||
|
||||
const data = this._allLanguageModelData.get(languageModelId);
|
||||
if (!data) {
|
||||
|
@ -412,21 +432,26 @@ export class ExtHostLanguageModels implements ExtHostLanguageModelsShape {
|
|||
return local.provider.provideTokenCount(value, token);
|
||||
}
|
||||
|
||||
return this._proxy.$countTokens(data.identifier, (typeof value === 'string' ? value : typeConvert.LanguageModelChatMessage.from(value)), token);
|
||||
return this._proxy.$countTokens(data.metadata.identifier, (typeof value === 'string' ? value : typeConvert.LanguageModelChatMessage.from(value)), token);
|
||||
}
|
||||
|
||||
getLanguageModelInfo(languageModelId: string): vscode.LanguageModelInformation | undefined {
|
||||
const data = this._allLanguageModelData.get(languageModelId);
|
||||
if (!data) {
|
||||
return undefined;
|
||||
$updateModelAccesslist(data: { from: ExtensionIdentifier; to: ExtensionIdentifier; enabled: boolean }[]): void {
|
||||
const updated = new Array<{ from: ExtensionIdentifier; to: ExtensionIdentifier }>();
|
||||
for (const { from, to, enabled } of data) {
|
||||
const set = this._modelAccessList.get(from) ?? new ExtensionIdentifierSet();
|
||||
const oldValue = set.has(to);
|
||||
if (oldValue !== enabled) {
|
||||
if (enabled) {
|
||||
set.add(to);
|
||||
} else {
|
||||
set.delete(to);
|
||||
}
|
||||
this._modelAccessList.set(from, set);
|
||||
const newItem = { from, to };
|
||||
updated.push(newItem);
|
||||
this._onDidChangeModelAccess.fire(newItem);
|
||||
}
|
||||
}
|
||||
|
||||
return Object.freeze({
|
||||
id: data.identifier,
|
||||
name: data.name,
|
||||
version: data.version,
|
||||
contextLength: data.tokens,
|
||||
});
|
||||
}
|
||||
|
||||
private readonly _languageAccessInformationExtensions = new Set<Readonly<IExtensionDescription>>();
|
||||
|
@ -449,7 +474,7 @@ export class ExtHostLanguageModels implements ExtHostLanguageModelsShape {
|
|||
if (!data) {
|
||||
return undefined;
|
||||
}
|
||||
if (!that._isUsingAuth(from.identifier, data)) {
|
||||
if (!that._isUsingAuth(from.identifier, data.metadata)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -457,7 +482,7 @@ export class ExtHostLanguageModels implements ExtHostLanguageModelsShape {
|
|||
if (!list) {
|
||||
return undefined;
|
||||
}
|
||||
return list.has(data.extension);
|
||||
return list.has(data.metadata.extension);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -2242,7 +2242,7 @@ export namespace ChatFollowup {
|
|||
|
||||
export namespace LanguageModelChatMessage {
|
||||
|
||||
export function to(message: chatProvider.IChatMessage): vscode.LanguageModelChatMessage2 {
|
||||
export function to(message: chatProvider.IChatMessage): vscode.LanguageModelChatMessage {
|
||||
switch (message.role) {
|
||||
case chatProvider.ChatMessageRole.System: return new types.LanguageModelChatMessage(<number>types.LanguageModelChatMessageRole.System, message.content);
|
||||
case chatProvider.ChatMessageRole.User: return new types.LanguageModelChatMessage(<number>types.LanguageModelChatMessageRole.User, message.content);
|
||||
|
@ -2250,7 +2250,7 @@ export namespace LanguageModelChatMessage {
|
|||
}
|
||||
}
|
||||
|
||||
export function from(message: vscode.LanguageModelChatMessage2): chatProvider.IChatMessage {
|
||||
export function from(message: vscode.LanguageModelChatMessage): chatProvider.IChatMessage {
|
||||
switch (message.role as types.LanguageModelChatMessageRole) {
|
||||
case types.LanguageModelChatMessageRole.System: return { role: chatProvider.ChatMessageRole.System, content: message.content };
|
||||
case types.LanguageModelChatMessageRole.User: return { role: chatProvider.ChatMessageRole.User, content: message.content };
|
||||
|
|
|
@ -6,9 +6,11 @@
|
|||
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
import { Emitter, Event } from 'vs/base/common/event';
|
||||
import { IDisposable, toDisposable } from 'vs/base/common/lifecycle';
|
||||
import { isEmptyObject } from 'vs/base/common/types';
|
||||
import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions';
|
||||
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { IProgress } from 'vs/platform/progress/common/progress';
|
||||
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
|
||||
|
||||
export const enum ChatMessageRole {
|
||||
System,
|
||||
|
@ -28,9 +30,11 @@ export interface IChatResponseFragment {
|
|||
|
||||
export interface ILanguageModelChatMetadata {
|
||||
readonly extension: ExtensionIdentifier;
|
||||
readonly identifier: string;
|
||||
readonly name: string;
|
||||
readonly identifier: string;
|
||||
readonly vendor: string;
|
||||
readonly version: string;
|
||||
readonly family: string;
|
||||
readonly tokens: number;
|
||||
|
||||
readonly auth?: {
|
||||
|
@ -57,6 +61,8 @@ export interface ILanguageModelsService {
|
|||
|
||||
lookupLanguageModel(identifier: string): ILanguageModelChatMetadata | undefined;
|
||||
|
||||
selectLanguageModels(selector: Partial<ILanguageModelChatMetadata>): Promise<string[]>;
|
||||
|
||||
registerLanguageModelChat(identifier: string, provider: ILanguageModelChat): IDisposable;
|
||||
|
||||
makeLanguageModelChatRequest(identifier: string, from: ExtensionIdentifier, messages: IChatMessage[], options: { [name: string]: any }, progress: IProgress<IChatResponseFragment>, token: CancellationToken): Promise<any>;
|
||||
|
@ -72,6 +78,10 @@ export class LanguageModelsService implements ILanguageModelsService {
|
|||
private readonly _onDidChangeProviders = new Emitter<{ added?: ILanguageModelChatMetadata[]; removed?: string[] }>();
|
||||
readonly onDidChangeLanguageModels: Event<{ added?: ILanguageModelChatMetadata[]; removed?: string[] }> = this._onDidChangeProviders.event;
|
||||
|
||||
constructor(
|
||||
@IExtensionService private readonly _extensionService: IExtensionService,
|
||||
) { }
|
||||
|
||||
dispose() {
|
||||
this._onDidChangeProviders.dispose();
|
||||
this._providers.clear();
|
||||
|
@ -85,6 +95,29 @@ export class LanguageModelsService implements ILanguageModelsService {
|
|||
return this._providers.get(identifier)?.metadata;
|
||||
}
|
||||
|
||||
async selectLanguageModels(selector: Partial<ILanguageModelChatMetadata>): Promise<string[]> {
|
||||
await this._extensionService.activateByEvent(`onLanguageModelChat:${selector.vendor ?? '*'}}`);
|
||||
|
||||
const result: string[] = [];
|
||||
|
||||
for (const model of this._providers.values()) {
|
||||
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
|
||||
) {
|
||||
// true selection
|
||||
result.push(model.metadata.identifier);
|
||||
|
||||
} else if (!selector || isEmptyObject(selector)) {
|
||||
// no selection
|
||||
result.push(model.metadata.identifier);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
registerLanguageModelChat(identifier: string, provider: ILanguageModelChat): IDisposable {
|
||||
if (this._providers.has(identifier)) {
|
||||
throw new Error(`Chat response provider with identifier ${identifier} is already registered.`);
|
||||
|
|
26
src/vscode-dts/vscode.proposed.chatProvider.d.ts
vendored
26
src/vscode-dts/vscode.proposed.chatProvider.d.ts
vendored
|
@ -19,20 +19,30 @@ declare module 'vscode' {
|
|||
|
||||
onDidReceiveLanguageModelResponse2?: Event<{ readonly extensionId: string; readonly participant?: string; readonly tokenCount?: number }>;
|
||||
|
||||
provideLanguageModelResponse(messages: LanguageModelChatMessage2[], options: { [name: string]: any }, extensionId: string, progress: Progress<ChatResponseFragment>, token: CancellationToken): Thenable<any>;
|
||||
provideLanguageModelResponse(messages: LanguageModelChatMessage[], options: { [name: string]: any }, extensionId: string, progress: Progress<ChatResponseFragment>, token: CancellationToken): Thenable<any>;
|
||||
|
||||
provideTokenCount(text: string | LanguageModelChatMessage, token: CancellationToken): Thenable<number>;
|
||||
}
|
||||
|
||||
export interface ChatResponseProviderMetadata {
|
||||
/**
|
||||
* The name of the model that is used for this chat access. It is expected that the model name can
|
||||
* be used to lookup properties like token limits and ChatML support
|
||||
*/
|
||||
// TODO@API rename to model
|
||||
name: string;
|
||||
|
||||
version: string;
|
||||
readonly vendor: string;
|
||||
|
||||
/**
|
||||
* Human-readable name of the language model.
|
||||
*/
|
||||
readonly name: string;
|
||||
/**
|
||||
* Opaque family-name of the language model. Values might be `gpt-3.5-turbo`, `gpt4`, `phi2`, or `llama`
|
||||
* but they are defined by extensions contributing languages and subject to change.
|
||||
*/
|
||||
readonly family: string;
|
||||
|
||||
/**
|
||||
* Opaque version string of the model. This is defined by the extension contributing the language model
|
||||
* and subject to change while the identifier is stable.
|
||||
*/
|
||||
readonly version: string;
|
||||
|
||||
tokens: number;
|
||||
|
||||
|
|
323
src/vscode-dts/vscode.proposed.languageModels.d.ts
vendored
323
src/vscode-dts/vscode.proposed.languageModels.d.ts
vendored
|
@ -66,12 +66,6 @@ declare module 'vscode' {
|
|||
Assistant = 2
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
// TODO@API remove
|
||||
export type LanguageModelChatMessage2 = LanguageModelChatMessage;
|
||||
|
||||
/**
|
||||
* Represents a message in a chat. Can assume different roles, like user or assistant.
|
||||
*/
|
||||
|
@ -101,179 +95,89 @@ declare module 'vscode' {
|
|||
constructor(role: LanguageModelChatMessageRole, content: string, name?: string);
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents information about a registered language model.
|
||||
*/
|
||||
export interface LanguageModelInformation {
|
||||
// ---------------------------
|
||||
// Language Model Object (V2)
|
||||
// (+) can pick by id or family
|
||||
// (++) makes it harder to hardcode an identifier of a model in source code
|
||||
|
||||
|
||||
// TODO@API name LanguageModelChatEndpoint
|
||||
export interface LanguageModelChat {
|
||||
/**
|
||||
* The identifier of the language model.
|
||||
* Opaque identifier of the language model.
|
||||
*/
|
||||
readonly id: string;
|
||||
|
||||
/**
|
||||
* The human-readable name of the language model.
|
||||
* A well-know identifier of the vendor of the language model, a sample is `copilot`, but
|
||||
* values are defined by extensions contributing chat model and need to be looked up with them.
|
||||
*/
|
||||
readonly vendor: string;
|
||||
/**
|
||||
* Human-readable name of the language model.
|
||||
*/
|
||||
readonly name: string;
|
||||
|
||||
/**
|
||||
* Opaque family-name of the language model. Values might be `gpt-3.5-turbo`, `gpt4`, `phi2`, or `llama`
|
||||
* but they are defined by extensions contributing languages and subject to change.
|
||||
*/
|
||||
readonly family: string;
|
||||
/**
|
||||
* Opaque version string of the model. This is defined by the extension contributing the language model
|
||||
* and subject to change while the identifier is stable.
|
||||
*/
|
||||
readonly version: string;
|
||||
|
||||
/**
|
||||
* Opaque family-name of the language model. Values might be `gpt-3.5-turbe`, `gpt4`, `phi2`, or `llama`
|
||||
* but they are defined by extensions contributing languages and subject to change.
|
||||
*/
|
||||
family: string;
|
||||
|
||||
/**
|
||||
* The number of available tokens that can be used when sending requests
|
||||
* to the language model.
|
||||
*
|
||||
* _Note_ that input- and output-tokens count towards this limit.
|
||||
*
|
||||
* @see {@link lm.sendChatRequest}
|
||||
*/
|
||||
// TODO@API CAPI only defines prompt_token_count which IMO is just input-tokens
|
||||
readonly contextLength: number;
|
||||
}
|
||||
|
||||
// ---------------------------
|
||||
// Language Model Object (V1)
|
||||
|
||||
export interface LanguageModelInformation2 {
|
||||
/**
|
||||
* Human-readable name of the language model.
|
||||
*/
|
||||
name: string;
|
||||
/**
|
||||
* Opaque family-name of the language model. Values might be `gpt-3.5-turbe`, `gpt4`, `phi2`, or `llama`
|
||||
* but they are defined by extensions contributing languages and subject to change.
|
||||
*/
|
||||
family: string;
|
||||
/**
|
||||
* Opaque version string of the model. This is defined by the extension contributing the language model
|
||||
* and subject to change while the identifier is stable.
|
||||
*/
|
||||
version: string;
|
||||
}
|
||||
|
||||
export interface LanguageModel {
|
||||
|
||||
// TODO@API no id-property needed
|
||||
readonly id: string;
|
||||
|
||||
readonly info: LanguageModelInformation2;
|
||||
|
||||
sendChatRequest(messages: LanguageModelChatMessage[], options?: LanguageModelChatRequestOptions, token?: CancellationToken): Thenable<LanguageModelChatResponse>;
|
||||
|
||||
// maybe optional
|
||||
computeTokenLength(text: string | LanguageModelChatMessage, token?: CancellationToken): Thenable<number | undefined>;
|
||||
}
|
||||
|
||||
export namespace lm {
|
||||
|
||||
// TODO@API cannot enforce unique language model families, e.g how do we tell `openai.gpt4` apart from `copilot.gpt4`
|
||||
export function getLanguageModel(family: string): LanguageModel[] | undefined;
|
||||
|
||||
export const languageModels2: LanguageModel[];
|
||||
}
|
||||
// ---------------------------
|
||||
|
||||
|
||||
// ---------------------------
|
||||
// Language Model Object (V2)
|
||||
// (+) can pick by id or family
|
||||
// (++) makes it harder to hardcode an identifier of a model in source code
|
||||
|
||||
export interface LanguageModelInformation2 {
|
||||
/**
|
||||
* Opaque identifier of the language model.
|
||||
*/
|
||||
readonly id: string;
|
||||
/**
|
||||
* Human-readable name of the language model.
|
||||
*/
|
||||
name: string;
|
||||
/**
|
||||
* Opaque family-name of the language model. Values might be `gpt-3.5-turbo`, `gpt4`, `phi2`, or `llama`
|
||||
* but they are defined by extensions contributing languages and subject to change.
|
||||
*/
|
||||
family: string;
|
||||
/**
|
||||
* Opaque version string of the model. This is defined by the extension contributing the language model
|
||||
* and subject to change while the identifier is stable.
|
||||
*/
|
||||
version: string;
|
||||
}
|
||||
|
||||
export interface LanguageModel3 {
|
||||
/**
|
||||
* Opaque identifier of the language model.
|
||||
*/
|
||||
readonly id: string;
|
||||
vendor?: string;
|
||||
/**
|
||||
* Human-readable name of the language model.
|
||||
*/
|
||||
name: string;
|
||||
/**
|
||||
* Opaque family-name of the language model. Values might be `gpt-3.5-turbo`, `gpt4`, `phi2`, or `llama`
|
||||
* but they are defined by extensions contributing languages and subject to change.
|
||||
*/
|
||||
family: string;
|
||||
/**
|
||||
* Opaque version string of the model. This is defined by the extension contributing the language model
|
||||
* and subject to change while the identifier is stable.
|
||||
*/
|
||||
version: string;
|
||||
|
||||
|
||||
// TODO@API
|
||||
// max_prompt_tokens vs output_tokens vs context_size
|
||||
contextSize: number;
|
||||
readonly contextSize: number;
|
||||
|
||||
sendChatRequest2(messages: LanguageModelChatMessage[], options?: LanguageModelChatRequestOptions, token?: CancellationToken): Thenable<LanguageModelChatResponse>;
|
||||
/**
|
||||
* Make a chat request using a language model.
|
||||
*
|
||||
* - *Note 1:* language model use may be subject to access restrictions and user consent. Calling this function
|
||||
* for the first time (for a extension) will show a consent dialog to the user and because of that this function
|
||||
* must _only be called in response to a user action!_ Extension can use {@link LanguageModelAccessInformation.canSendRequest}
|
||||
* to check if they have the necessary permissions to make a request.
|
||||
*
|
||||
* - *Note 2:* language models are contributed by other extensions and as they evolve and change,
|
||||
* the set of available language models may change over time. Therefore it is strongly recommend to check
|
||||
* {@link languageModels} for available values and handle missing language models gracefully.
|
||||
*
|
||||
* This function will return a rejected promise if making a request to the language model is not
|
||||
* possible. Reasons for this can be:
|
||||
*
|
||||
* - user consent not given, see {@link LanguageModelError.NoPermissions `NoPermissions`}
|
||||
* - model does not exist anymore, see {@link LanguageModelError.NotFound `NotFound`}
|
||||
* - quota limits exceeded, see {@link LanguageModelError.Blocked `Blocked`}
|
||||
* - other issues in which case extension must check {@link LanguageModelError.cause `LanguageModelError.cause`}
|
||||
*
|
||||
* @param messages An array of message instances.
|
||||
* @param options Options that control the request.
|
||||
* @param token A cancellation token which controls the request. See {@link CancellationTokenSource} for how to create one.
|
||||
* @returns A thenable that resolves to a {@link LanguageModelChatResponse}. The promise will reject when the request couldn't be made.
|
||||
*/
|
||||
sendRequest(messages: LanguageModelChatMessage[], options?: LanguageModelChatRequestOptions, token?: CancellationToken): Thenable<LanguageModelChatResponse>;
|
||||
|
||||
/**
|
||||
* Uses the model specific tokenzier and computes the length in tokens of a given message.
|
||||
*
|
||||
* @param text A string or a message instance.
|
||||
* @param token Optional cancellation token.
|
||||
* @returns A thenable that resolves to the length of the message in tokens.
|
||||
*/
|
||||
// TODO@API `undefined` when the language model does not support computing token length
|
||||
// ollama has nothing
|
||||
// anthropic suggests to count after the fact https://github.com/anthropics/anthropic-tokenizer-typescript?tab=readme-ov-file#anthropic-typescript-tokenizer
|
||||
computeTokenLength(text: string | LanguageModelChatMessage, token?: CancellationToken): Thenable<number | undefined>;
|
||||
}
|
||||
|
||||
export namespace lm {
|
||||
|
||||
// export const languageModels3: readonly LanguageModelInformation2[];
|
||||
|
||||
// export const onDidChangeLanguageModels3: Event<{ readonly added: readonly LanguageModelInformation2[]; readonly removed: readonly LanguageModelInformation2[] }>;
|
||||
|
||||
// export const onDidChangeLanguageModels3: Event<void>;
|
||||
|
||||
// (++) lazy activation
|
||||
// (++) give specific LM to some extension
|
||||
// // variant A
|
||||
// export function fetchLanguageModel(selector: { id?: string; family?: string; version?: string }): Thenable<LanguageModelInformation2[] | undefined>;
|
||||
|
||||
// // variant B
|
||||
export function fetchLanguageModel(selector: { vendor: string; family?: string; version?: string; id?: string }): Thenable<LanguageModel3[] | undefined>;
|
||||
|
||||
// export function sendChatRequest2(languageModel: LanguageModelInformation2, messages: LanguageModelChatMessage[], options?: LanguageModelChatRequestOptions, token?: CancellationToken): Thenable<LanguageModelChatResponse>;
|
||||
|
||||
// export function computeTokenLength(languageModel: LanguageModelInformation2, text: string | LanguageModelChatMessage, token?: CancellationToken): Thenable<number | undefined>;
|
||||
}
|
||||
// ---------------------------
|
||||
|
||||
/**
|
||||
* An event describing the change in the set of available language models.
|
||||
*/
|
||||
// TODO@API use LanguageModelInformation instead of string?
|
||||
export interface LanguageModelChangeEvent {
|
||||
/**
|
||||
* Added language models.
|
||||
*/
|
||||
readonly added: readonly string[];
|
||||
/**
|
||||
* Removed language models.
|
||||
*/
|
||||
readonly removed: readonly string[];
|
||||
export interface LanguageModelChatSelector {
|
||||
vendor?: string; // TODO@API make required?
|
||||
family?: string;
|
||||
version?: string;
|
||||
id?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -337,65 +241,57 @@ declare module 'vscode' {
|
|||
export namespace lm {
|
||||
|
||||
/**
|
||||
* The identifiers of all language models that are currently available.
|
||||
* An event that is fired when the set of available chat models changes.
|
||||
*/
|
||||
export const languageModels: readonly string[];
|
||||
export const onDidChangeChatModels: Event<void>;
|
||||
|
||||
/**
|
||||
* An event that is fired when the set of available language models changes.
|
||||
*/
|
||||
export const onDidChangeLanguageModels: Event<LanguageModelChangeEvent>;
|
||||
// // variant B
|
||||
// (++) lazy activation
|
||||
// (++) give specific LM to some extension
|
||||
export function selectLanguageModels(selector: LanguageModelChatSelector): Thenable<LanguageModelChat[] | undefined>;
|
||||
|
||||
/**
|
||||
* Retrieve information about a language model.
|
||||
*
|
||||
* @param languageModel A language model identifier.
|
||||
* @returns A {@link LanguageModelInformation} instance or `undefined` if the language model does not exist.
|
||||
*/
|
||||
export function getLanguageModelInformation(languageModel: string): LanguageModelInformation | undefined;
|
||||
// /**
|
||||
// * Make a chat request using a language model.
|
||||
// *
|
||||
// * - *Note 1:* language model use may be subject to access restrictions and user consent. Calling this function
|
||||
// * for the first time (for a extension) will show a consent dialog to the user and because of that this function
|
||||
// * must _only be called in response to a user action!_ Extension can use {@link LanguageModelAccessInformation.canSendRequest}
|
||||
// * to check if they have the necessary permissions to make a request.
|
||||
// *
|
||||
// * - *Note 2:* language models are contributed by other extensions and as they evolve and change,
|
||||
// * the set of available language models may change over time. Therefore it is strongly recommend to check
|
||||
// * {@link languageModels} for available values and handle missing language models gracefully.
|
||||
// *
|
||||
// * This function will return a rejected promise if making a request to the language model is not
|
||||
// * possible. Reasons for this can be:
|
||||
// *
|
||||
// * - user consent not given, see {@link LanguageModelError.NoPermissions `NoPermissions`}
|
||||
// * - model does not exist, see {@link LanguageModelError.NotFound `NotFound`}
|
||||
// * - quota limits exceeded, see {@link LanguageModelError.Blocked `Blocked`}
|
||||
// * - other issues in which case extension must check {@link LanguageModelError.cause `LanguageModelError.cause`}
|
||||
// *
|
||||
// * @param languageModel A language model identifier.
|
||||
// * @param messages An array of message instances.
|
||||
// * @param options Options that control the request.
|
||||
// * @param token A cancellation token which controls the request. See {@link CancellationTokenSource} for how to create one.
|
||||
// * @returns A thenable that resolves to a {@link LanguageModelChatResponse}. The promise will reject when the request couldn't be made.
|
||||
// */
|
||||
// export function sendChatRequest(languageModel: string, messages: LanguageModelChatMessage[], options?: LanguageModelChatRequestOptions, token?: CancellationToken): Thenable<LanguageModelChatResponse>;
|
||||
|
||||
/**
|
||||
* Make a chat request using a language model.
|
||||
*
|
||||
* - *Note 1:* language model use may be subject to access restrictions and user consent. Calling this function
|
||||
* for the first time (for a extension) will show a consent dialog to the user and because of that this function
|
||||
* must _only be called in response to a user action!_ Extension can use {@link LanguageModelAccessInformation.canSendRequest}
|
||||
* to check if they have the necessary permissions to make a request.
|
||||
*
|
||||
* - *Note 2:* language models are contributed by other extensions and as they evolve and change,
|
||||
* the set of available language models may change over time. Therefore it is strongly recommend to check
|
||||
* {@link languageModels} for available values and handle missing language models gracefully.
|
||||
*
|
||||
* This function will return a rejected promise if making a request to the language model is not
|
||||
* possible. Reasons for this can be:
|
||||
*
|
||||
* - user consent not given, see {@link LanguageModelError.NoPermissions `NoPermissions`}
|
||||
* - model does not exist, see {@link LanguageModelError.NotFound `NotFound`}
|
||||
* - quota limits exceeded, see {@link LanguageModelError.Blocked `Blocked`}
|
||||
* - other issues in which case extension must check {@link LanguageModelError.cause `LanguageModelError.cause`}
|
||||
*
|
||||
* @param languageModel A language model identifier.
|
||||
* @param messages An array of message instances.
|
||||
* @param options Options that control the request.
|
||||
* @param token A cancellation token which controls the request. See {@link CancellationTokenSource} for how to create one.
|
||||
* @returns A thenable that resolves to a {@link LanguageModelChatResponse}. The promise will reject when the request couldn't be made.
|
||||
*/
|
||||
export function sendChatRequest(languageModel: string, messages: LanguageModelChatMessage[], options?: LanguageModelChatRequestOptions, token?: CancellationToken): Thenable<LanguageModelChatResponse>;
|
||||
|
||||
/**
|
||||
* Uses the language model specific tokenzier and computes the length in token of a given message.
|
||||
*
|
||||
* *Note* that this function will throw when the language model does not exist.
|
||||
*
|
||||
* @param languageModel A language model identifier.
|
||||
* @param text A string or a message instance.
|
||||
* @param token Optional cancellation token.
|
||||
* @returns A thenable that resolves to the length of the message in tokens.
|
||||
*/
|
||||
// TODO@API `undefined` when the language model does not support computing token length
|
||||
// ollama has nothing
|
||||
// anthropic suggests to count after the fact https://github.com/anthropics/anthropic-tokenizer-typescript?tab=readme-ov-file#anthropic-typescript-tokenizer
|
||||
export function computeTokenLength(languageModel: string, text: string | LanguageModelChatMessage, token?: CancellationToken): Thenable<number | undefined>;
|
||||
// /**
|
||||
// * Uses the language model specific tokenzier and computes the length in token of a given message.
|
||||
// *
|
||||
// * *Note* that this function will throw when the language model does not exist.
|
||||
// *
|
||||
// * @param languageModel A language model identifier.
|
||||
// * @param text A string or a message instance.
|
||||
// * @param token Optional cancellation token.
|
||||
// * @returns A thenable that resolves to the length of the message in tokens.
|
||||
// */
|
||||
// // TODO@API `undefined` when the language model does not support computing token length
|
||||
// // ollama has nothing
|
||||
// // anthropic suggests to count after the fact https://github.com/anthropics/anthropic-tokenizer-typescript?tab=readme-ov-file#anthropic-typescript-tokenizer
|
||||
// export function computeTokenLength(languageModel: string, text: string | LanguageModelChatMessage, token?: CancellationToken): Thenable<number | undefined>;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -417,6 +313,7 @@ declare module 'vscode' {
|
|||
* @return `true` if a request can be made, `false` if not, `undefined` if the language
|
||||
* model does not exist or consent hasn't been asked for.
|
||||
*/
|
||||
// TODO@API applies to chat and embeddings models
|
||||
canSendRequest(languageModelId: string): boolean | undefined;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue