diff --git a/src/vs/workbench/api/common/extHost.api.impl.ts b/src/vs/workbench/api/common/extHost.api.impl.ts index 20b128c9af4..1b9c7eb2b08 100644 --- a/src/vs/workbench/api/common/extHost.api.impl.ts +++ b/src/vs/workbench/api/common/extHost.api.impl.ts @@ -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'; @@ -1431,10 +1431,6 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I // namespace: lm const lm: typeof vscode.lm = { - requestLanguageModelAccess(id, options) { - checkProposedApiEnabled(extension, 'languageModels'); - return extHostChatProvider.requestLanguageModelAccess(extension, id, options); - }, get languageModels() { checkProposedApiEnabled(extension, 'languageModels'); return extHostChatProvider.getLanguageModelIds(); @@ -1443,19 +1439,9 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I checkProposedApiEnabled(extension, 'languageModels'); return extHostChatProvider.onDidChangeProviders(listener, thisArgs, disposables); }, - chatRequest(languageModel: string, messages: vscode.LanguageModelMessage[], optionsOrToken: { [name: string]: any } | vscode.CancellationToken, token?: vscode.CancellationToken) { + sendChatRequest(languageModel: string, messages: vscode.LanguageModelChatMessage[], options: vscode.LanguageModelChatRequestOptions, token: vscode.CancellationToken) { checkProposedApiEnabled(extension, 'languageModels'); - let options: Record; - if (CancellationToken.isCancellationToken(optionsOrToken)) { - options = {}; - token = optionsOrToken; - } else if (CancellationToken.isCancellationToken(token)) { - options = optionsOrToken; - token = token; - } else { - throw new Error('Invalid arguments'); - } - return extHostChatProvider.makeChatRequest(extension, languageModel, messages, options, token); + return extHostChatProvider.sendChatRequest(extension, languageModel, messages, options, token); } }; @@ -1699,9 +1685,12 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I ChatResponseCommandButtonPart: extHostTypes.ChatResponseCommandButtonPart, ChatRequestTurn: extHostTypes.ChatRequestTurn, ChatResponseTurn: extHostTypes.ChatResponseTurn, - LanguageModelSystemMessage: extHostTypes.LanguageModelSystemMessage, - LanguageModelUserMessage: extHostTypes.LanguageModelUserMessage, - LanguageModelAssistantMessage: extHostTypes.LanguageModelAssistantMessage, + LanguageModelChatSystemMessage: extHostTypes.LanguageModelChatSystemMessage, + LanguageModelChatUserMessage: extHostTypes.LanguageModelChatUserMessage, + LanguageModelChatAssistantMessage: extHostTypes.LanguageModelChatAssistantMessage, + LanguageModelSystemMessage: extHostTypes.LanguageModelChatSystemMessage, + LanguageModelUserMessage: extHostTypes.LanguageModelChatUserMessage, + LanguageModelAssistantMessage: extHostTypes.LanguageModelChatAssistantMessage, NewSymbolName: extHostTypes.NewSymbolName, NewSymbolNameTag: extHostTypes.NewSymbolNameTag, InlineEdit: extHostTypes.InlineEdit, diff --git a/src/vs/workbench/api/common/extHostLanguageModels.ts b/src/vs/workbench/api/common/extHostLanguageModels.ts index aa45f8f58aa..e51c875984d 100644 --- a/src/vs/workbench/api/common/extHostLanguageModels.ts +++ b/src/vs/workbench/api/common/extHostLanguageModels.ts @@ -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 { CancellationToken } from 'vs/base/common/cancellation'; import { IDisposable, toDisposable } from 'vs/base/common/lifecycle'; import { ILogService } from 'vs/platform/log/common/log'; import { ExtHostLanguageModelsShape, IMainContext, MainContext, MainThreadLanguageModelsShape } from 'vs/workbench/api/common/extHost.protocol'; @@ -12,12 +12,12 @@ 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 } from 'vs/base/common/async'; -import { Emitter, Event } from 'vs/base/common/event'; +import { AsyncIterableSource, Barrier } from 'vs/base/common/async'; +import { Emitter } from 'vs/base/common/event'; import { ExtHostAuthentication } from 'vs/workbench/api/common/extHostAuthentication'; import { localize } from 'vs/nls'; import { INTERNAL_AUTH_PROVIDER_PREFIX } from 'vs/workbench/services/authentication/common/authentication'; -import { toErrorMessage } from 'vs/base/common/errorMessage'; +import { CancellationError } from 'vs/base/common/errors'; type LanguageModelData = { readonly extension: ExtensionIdentifier; @@ -36,43 +36,23 @@ class LanguageModelResponseStream { } } -class LanguageModelRequest { +class LanguageModelResponse { - static fromError(err: Error): vscode.LanguageModelResponse { - return new LanguageModelRequest(Promise.reject(err), new CancellationTokenSource()).apiObject; - } - - readonly apiObject: vscode.LanguageModelResponse; + readonly apiObject: vscode.LanguageModelChatResponse; private readonly _responseStreams = new Map(); private readonly _defaultStream = new AsyncIterableSource(); private _isDone: boolean = false; + private _isStreaming: boolean = false; + + constructor() { - constructor( - promise: Promise, - readonly cts: CancellationTokenSource - ) { const that = this; this.apiObject = { - result: promise, + // result: promise, stream: that._defaultStream.asyncIterable, - // responses: AsyncIterable[] // FUTURE responses per N + // streams: AsyncIterable[] // FUTURE responses per N }; - - promise.then(() => { - for (const stream of this._streams()) { - stream.resolve(); - } - }).catch(err => { - if (!(err instanceof Error)) { - err = new Error(toErrorMessage(err), { cause: err }); - } - for (const stream of this._streams()) { - stream.reject(err); - } - }).finally(() => { - this._isDone = true; - }); } private * _streams() { @@ -89,6 +69,7 @@ class LanguageModelRequest { if (this._isDone) { return; } + this._isStreaming = true; let res = this._responseStreams.get(fragment.index); if (!res) { if (this._responseStreams.size === 0) { @@ -102,6 +83,24 @@ class LanguageModelRequest { res.stream.emitOne(fragment.part); } + get isStreaming(): boolean { + return this._isStreaming; + } + + reject(err: Error): void { + this._isDone = true; + for (const stream of this._streams()) { + stream.reject(err); + } + } + + resolve(): void { + this._isDone = true; + for (const stream of this._streams()) { + stream.resolve(); + } + } + } export class ExtHostLanguageModels implements ExtHostLanguageModelsShape { @@ -116,7 +115,7 @@ export class ExtHostLanguageModels implements ExtHostLanguageModelsShape { private readonly _languageModels = new Map(); private readonly _languageModelIds = new Set(); // these are ALL models, not just the one in this EH private readonly _modelAccessList = new ExtensionIdentifierMap(); - private readonly _pendingRequest = new Map(); + private readonly _pendingRequest = new Map(); constructor( @@ -191,7 +190,7 @@ export class ExtHostLanguageModels implements ExtHostLanguageModelsShape { // cancel pending requests for this model for (const [key, value] of this._pendingRequest) { if (value.languageModelId === id) { - value.res.cts.cancel(); + value.res.reject(new CancellationError()); this._pendingRequest.delete(key); } } @@ -227,88 +226,56 @@ export class ExtHostLanguageModels implements ExtHostLanguageModelsShape { } } - async makeChatRequest(extension: IExtensionDescription, languageModelId: string, messages: vscode.LanguageModelMessage[], options: Record, token: CancellationToken) { + async sendChatRequest(extension: IExtensionDescription, languageModelId: string, messages: vscode.LanguageModelChatMessage[], options: vscode.LanguageModelChatRequestOptions, token: CancellationToken) { const from = extension.identifier; - // const justification = options?.justification; // TODO@jrieken - const metadata = await this._proxy.$prepareChatAccess(from, languageModelId, undefined); + const metadata = await this._proxy.$prepareChatAccess(from, languageModelId, options.justification); if (!metadata || !this._languageModelIds.has(languageModelId)) { - return LanguageModelRequest.fromError(new Error(`Language model ${languageModelId} is unknown`)); + throw new Error(`Language model '${languageModelId}' is unknown.`); } if (this._isUsingAuth(from, metadata)) { - await this._getAuthAccess(extension, { identifier: metadata.extension, displayName: metadata.auth.providerLabel }, undefined); + const success = await this._getAuthAccess(extension, { identifier: metadata.extension, displayName: metadata.auth.providerLabel }, options.justification, options.silent); - if (!this._modelAccessList.get(from)?.has(metadata.extension)) { - return LanguageModelRequest.fromError(new Error('Access to chat has been revoked')); + if (!success || !this._modelAccessList.get(from)?.has(metadata.extension)) { + throw new Error(`Language model '${languageModelId}' cannot be used by '${from.value}'.`); } } - const cts = new CancellationTokenSource(token); const requestId = (Math.random() * 1e6) | 0; - const requestPromise = this._proxy.$fetchResponse(from, languageModelId, requestId, messages.map(typeConvert.LanguageModelMessage.from), options ?? {}, cts.token); - const res = new LanguageModelRequest(requestPromise, cts); + const requestPromise = this._proxy.$fetchResponse(from, languageModelId, requestId, messages.map(typeConvert.LanguageModelMessage.from), options.modelOptions ?? {}, token); + + const barrier = new Barrier(); + + const res = new LanguageModelResponse(); this._pendingRequest.set(requestId, { languageModelId, res }); - requestPromise.finally(() => { + let error: Error | undefined; + + requestPromise.catch(err => { + if (barrier.isOpen()) { + // we received an error while streaming. this means we need to reject the "stream" + // because we have already returned the request object + res.reject(err); + } else { + error = err; + } + }).finally(() => { this._pendingRequest.delete(requestId); - cts.dispose(); + res.resolve(); + barrier.open(); }); + await barrier.wait(); + + if (error) { + throw new Error(`Language model '${languageModelId}' errored, check cause for more details`, { cause: error }); + } + return res.apiObject; } - async requestLanguageModelAccess(extension: IExtensionDescription, languageModelId: string, options?: vscode.LanguageModelAccessOptions): Promise { - const from = extension.identifier; - const justification = options?.justification; - const metadata = await this._proxy.$prepareChatAccess(from, languageModelId, justification); - - if (!metadata) { - throw new Error(`Language model '${languageModelId}' NOT found`); - } - - if (this._isUsingAuth(from, metadata)) { - await this._getAuthAccess(extension, { identifier: metadata.extension, displayName: metadata.auth.providerLabel }, justification); - } - - const that = this; - - return { - get model() { - return metadata.model; - }, - get isRevoked() { - return (that._isUsingAuth(from, metadata) && !that._modelAccessList.get(from)?.has(metadata.extension)) || !that._languageModelIds.has(languageModelId); - }, - get onDidChangeAccess() { - const onDidRemoveLM = Event.filter(that._onDidChangeProviders.event, e => e.removed.includes(languageModelId)); - const onDidChangeModelAccess = Event.filter(that._onDidChangeModelAccess.event, e => ExtensionIdentifier.equals(e.from, from) && ExtensionIdentifier.equals(e.to, metadata.extension)); - return Event.signal(Event.any(onDidRemoveLM, onDidChangeModelAccess)); - }, - makeChatRequest(messages, options, token) { - if (that._isUsingAuth(from, metadata) && !that._modelAccessList.get(from)?.has(metadata.extension)) { - throw new Error('Access to chat has been revoked'); - } - if (!that._languageModelIds.has(languageModelId)) { - throw new Error('Language Model has been removed'); - } - const cts = new CancellationTokenSource(token); - const requestId = (Math.random() * 1e6) | 0; - const requestPromise = that._proxy.$fetchResponse(from, languageModelId, requestId, messages.map(typeConvert.LanguageModelMessage.from), options ?? {}, cts.token); - const res = new LanguageModelRequest(requestPromise, cts); - that._pendingRequest.set(requestId, { languageModelId, res }); - - requestPromise.finally(() => { - that._pendingRequest.delete(requestId); - cts.dispose(); - }); - - return res.apiObject; - }, - }; - } - async $handleResponseFragment(requestId: number, chunk: IChatResponseFragment): Promise { const data = this._pendingRequest.get(requestId);//.report(chunk); if (data) { @@ -317,22 +284,32 @@ export class ExtHostLanguageModels implements ExtHostLanguageModelsShape { } // BIG HACK: Using AuthenticationProviders to check access to Language Models - private async _getAuthAccess(from: IExtensionDescription, to: { identifier: ExtensionIdentifier; displayName: string }, justification?: string): Promise { + private async _getAuthAccess(from: IExtensionDescription, to: { identifier: ExtensionIdentifier; displayName: string }, justification: string | undefined, silent: boolean | undefined): Promise { // This needs to be done in both MainThread & ExtHost ChatProvider const providerId = INTERNAL_AUTH_PROVIDER_PREFIX + to.identifier.value; const session = await this._extHostAuthentication.getSession(from, providerId, [], { silent: true }); - if (!session) { - try { - const detail = justification - ? localize('chatAccessWithJustification', "To allow access to the language models provided by {0}. Justification:\n\n{1}", to.displayName, justification) - : localize('chatAccess', "To allow access to the language models provided by {0}", to.displayName); - await this._extHostAuthentication.getSession(from, providerId, [], { forceNewSession: { detail } }); - } catch (err) { - throw new Error('Access to language models has not been granted'); - } + + if (session) { + this.$updateModelAccesslist([{ from: from.identifier, to: to.identifier, enabled: true }]); + return true; } - this.$updateModelAccesslist([{ from: from.identifier, to: to.identifier, enabled: true }]); + if (silent) { + return false; + } + + try { + const detail = justification + ? localize('chatAccessWithJustification', "To allow access to the language models provided by {0}. Justification:\n\n{1}", to.displayName, justification) + : localize('chatAccess', "To allow access to the language models provided by {0}", to.displayName); + await this._extHostAuthentication.getSession(from, providerId, [], { forceNewSession: { detail } }); + this.$updateModelAccesslist([{ from: from.identifier, to: to.identifier, enabled: true }]); + return true; + + } catch (err) { + // ignore + return false; + } } private _isUsingAuth(from: ExtensionIdentifier, toMetadata: ILanguageModelChatMetadata): toMetadata is ILanguageModelChatMetadata & { auth: NonNullable } { diff --git a/src/vs/workbench/api/common/extHostTypeConverters.ts b/src/vs/workbench/api/common/extHostTypeConverters.ts index 816f0227361..68cbe330492 100644 --- a/src/vs/workbench/api/common/extHostTypeConverters.ts +++ b/src/vs/workbench/api/common/extHostTypeConverters.ts @@ -2239,20 +2239,20 @@ export namespace ChatInlineFollowup { export namespace LanguageModelMessage { - export function to(message: chatProvider.IChatMessage): vscode.LanguageModelMessage { + export function to(message: chatProvider.IChatMessage): vscode.LanguageModelChatMessage { switch (message.role) { - case chatProvider.ChatMessageRole.System: return new types.LanguageModelSystemMessage(message.content); - case chatProvider.ChatMessageRole.User: return new types.LanguageModelUserMessage(message.content); - case chatProvider.ChatMessageRole.Assistant: return new types.LanguageModelAssistantMessage(message.content); + case chatProvider.ChatMessageRole.System: return new types.LanguageModelChatSystemMessage(message.content); + case chatProvider.ChatMessageRole.User: return new types.LanguageModelChatUserMessage(message.content); + case chatProvider.ChatMessageRole.Assistant: return new types.LanguageModelChatAssistantMessage(message.content); } } - export function from(message: vscode.LanguageModelMessage): chatProvider.IChatMessage { - if (message instanceof types.LanguageModelSystemMessage) { + export function from(message: vscode.LanguageModelChatMessage): chatProvider.IChatMessage { + if (message instanceof types.LanguageModelChatSystemMessage) { return { role: chatProvider.ChatMessageRole.System, content: message.content }; - } else if (message instanceof types.LanguageModelUserMessage) { + } else if (message instanceof types.LanguageModelChatUserMessage) { return { role: chatProvider.ChatMessageRole.User, content: message.content }; - } else if (message instanceof types.LanguageModelAssistantMessage) { + } else if (message instanceof types.LanguageModelChatAssistantMessage) { return { role: chatProvider.ChatMessageRole.Assistant, content: message.content }; } else { throw new Error('Invalid LanguageModelMessage'); diff --git a/src/vs/workbench/api/common/extHostTypes.ts b/src/vs/workbench/api/common/extHostTypes.ts index 4fb94e3f1c8..4eec0964cd2 100644 --- a/src/vs/workbench/api/common/extHostTypes.ts +++ b/src/vs/workbench/api/common/extHostTypes.ts @@ -4271,7 +4271,7 @@ export class ChatResponseTurn implements vscode.ChatResponseTurn { ) { } } -export class LanguageModelSystemMessage { +export class LanguageModelChatSystemMessage { content: string; constructor(content: string) { @@ -4279,7 +4279,7 @@ export class LanguageModelSystemMessage { } } -export class LanguageModelUserMessage { +export class LanguageModelChatUserMessage { content: string; name: string | undefined; @@ -4289,7 +4289,7 @@ export class LanguageModelUserMessage { } } -export class LanguageModelAssistantMessage { +export class LanguageModelChatAssistantMessage { content: string; constructor(content: string) { diff --git a/src/vscode-dts/vscode.proposed.chatProvider.d.ts b/src/vscode-dts/vscode.proposed.chatProvider.d.ts index 7a9e140b5a5..b6aa1ffdadf 100644 --- a/src/vscode-dts/vscode.proposed.chatProvider.d.ts +++ b/src/vscode-dts/vscode.proposed.chatProvider.d.ts @@ -16,7 +16,7 @@ declare module 'vscode' { * Represents a large language model that accepts ChatML messages and produces a streaming response */ export interface ChatResponseProvider { - provideLanguageModelResponse2(messages: LanguageModelMessage[], options: { [name: string]: any }, extensionId: string, progress: Progress, token: CancellationToken): Thenable; + provideLanguageModelResponse2(messages: LanguageModelChatMessage[], options: { [name: string]: any }, extensionId: string, progress: Progress, token: CancellationToken): Thenable; } export interface ChatResponseProviderMetadata { diff --git a/src/vscode-dts/vscode.proposed.languageModels.d.ts b/src/vscode-dts/vscode.proposed.languageModels.d.ts index 258a5bf18e9..59b053f149d 100644 --- a/src/vscode-dts/vscode.proposed.languageModels.d.ts +++ b/src/vscode-dts/vscode.proposed.languageModels.d.ts @@ -8,20 +8,14 @@ declare module 'vscode' { /** * Represents a language model response. * - * @see {@link LanguageModelAccess.makeChatRequest} + * @see {@link LanguageModelAccess.chatRequest} */ - export interface LanguageModelResponse { - - /** - * The overall result of the request which represents failure or success - * but. The concrete value is not specified and depends on the selected language model. - * - * *Note* that the actual response represented by the {@link LanguageModelResponse.stream `stream`}-property - */ - result: Thenable; + export interface LanguageModelChatResponse { /** * An async iterable that is a stream of text chunks forming the overall response. + * + * *Note* that this stream will error when during receiving an error occurrs. */ stream: AsyncIterable; } @@ -35,7 +29,7 @@ declare module 'vscode' { * *Note* that a language model may choose to add additional system messages to the ones * provided by extensions. */ - export class LanguageModelSystemMessage { + export class LanguageModelChatSystemMessage { /** * The content of this message. @@ -53,7 +47,7 @@ declare module 'vscode' { /** * A language model message that represents a user message. */ - export class LanguageModelUserMessage { + export class LanguageModelChatUserMessage { /** * The content of this message. @@ -78,7 +72,7 @@ declare module 'vscode' { * A language model message that represents an assistant message, usually in response to a user message * or as a sample response/reply-pair. */ - export class LanguageModelAssistantMessage { + export class LanguageModelChatAssistantMessage { /** * The content of this message. @@ -93,50 +87,8 @@ declare module 'vscode' { constructor(content: string); } - export type LanguageModelMessage = LanguageModelSystemMessage | LanguageModelUserMessage | LanguageModelAssistantMessage; + export type LanguageModelChatMessage = LanguageModelChatSystemMessage | LanguageModelChatUserMessage | LanguageModelChatAssistantMessage; - /** - * Represents access to using a language model. Access can be revoked at any time and extension - * must check if the access is {@link LanguageModelAccess.isRevoked still valid} before using it. - */ - export interface LanguageModelAccess { - - /** - * Whether the access to the language model has been revoked. - */ - readonly isRevoked: boolean; - - /** - * An event that is fired when the access the language model has has been revoked or re-granted. - */ - // TODO@API NAME? - readonly onDidChangeAccess: Event; - - /** - * The name of the model. - * - * It is expected that the model name can be used to lookup properties like token limits or what - * `options` are available. - */ - readonly model: string; - - /** - * Make a request to the language model. - * - * *Note:* This will throw an error if access has been revoked. - * - * @param messages - * @param options - */ - makeChatRequest(messages: LanguageModelMessage[], options: { [name: string]: any }, token: CancellationToken): LanguageModelResponse; - } - - export interface LanguageModelAccessOptions { - /** - * A human-readable message that explains why access to a language model is needed and what feature is enabled by it. - */ - justification?: string; - } /** * An event describing the change in the set of available language models. @@ -152,57 +104,61 @@ declare module 'vscode' { readonly removed: readonly string[]; } + /** + * Options for making a chat request using a language model. + * + * @see {@link lm.chatRequest} + */ + export interface LanguageModelChatRequestOptions { + + /** + * A human-readable message that explains why access to a language model is needed and what feature is enabled by it. + */ + justification?: string; + + /** + * Do not show the consent UI if the user has not yet granted access to the language model but fail the request instead. + */ + // TODO@API refine/define + silent?: boolean; + + /** + * A set of options that control the behavior of the language model. These options are specific to the language model + * and need to be lookup in the respective documentation. + */ + modelOptions?: { [name: string]: any }; + } + /** * Namespace for language model related functionality. */ export namespace lm { - /** - * Request access to a language model. - * - * - *Note 1:* This function will throw an error when the user didn't grant access or when the - * requested language model is not available. - * - * - *Note 2:* It is OK to hold on to the returned access object and use it later, but extensions - * should check {@link LanguageModelAccess.isRevoked} before using it. - * - * @param id The id of the language model, see {@link languageModels} for valid values. - * @returns A thenable that resolves to a language model access object, rejects if access wasn't granted - */ - export function requestLanguageModelAccess(id: string, options?: LanguageModelAccessOptions): Thenable; - - - /** * Make a chat request using a language model. * - * *Note* that language model use may be subject to access restrictions and user consent. This function always returns a response-object - * but its {@link LanguageModelResponse.result `result`}-property may indicate failure, e.g. due to + * *Note* that language model use may be subject to access restrictions and user consent. This function will return a rejected promise + * if access to the language model is not possible. Reasons for this can be: * * - user consent not given * - quote limits exceeded * - model does not exist * * @param languageModel A language model identifier. See {@link languageModels} for aviailable values. - * @param messages - * @param options - * @param token + * @param messages An array of message instances. + * @param options Objects 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 making the request failed. */ // TODO@API refine doc // TODO@API define specific error types? - // TODO@API NAME: chatRequest - // TODO@API NAME: ChatRequestXYZMessage - // TODO@API NAME: ChatRequestResponse - export function chatRequest(languageModel: string, messages: LanguageModelMessage[], options: { [name: string]: any }, token: CancellationToken): Thenable; - - /** - * @see {@link chatRequest} - */ - export function chatRequest(languageModel: string, messages: LanguageModelMessage[], token: CancellationToken): Thenable; - - // TODO@API probe on having access - // TODO@API, BETTER?: ExtensionContext.permissions.languageModels: Record; - // export function canMakeChatRequest(languageModel: string): Thenable; + // TODO@API NAME: sendChatRequest, fetchChatResponse, makeChatRequest, chat, chatRequest sendChatRequest + // TODO@API ExtensionContext#permission#languageModels: { languageModel: string: LanguageModelAccessInformation} + // TODO@API ✅ NAME: LanguageModelChatXYZMessage + // TODO@API ✅ errors on everything that prevents us to make the actual request + // TODO@API ✅ double auth + // TODO@API ✅ NAME: LanguageModelChatResponse, ChatResponse, ChatRequestResponse + export function sendChatRequest(languageModel: string, messages: LanguageModelChatMessage[], options: LanguageModelChatRequestOptions, token: CancellationToken): Thenable; /** * The identifiers of all language models that are currently available. @@ -214,4 +170,12 @@ declare module 'vscode' { */ export const onDidChangeLanguageModels: Event; } + + // export function chatRequest2(languageModel: string, callback: (request: LanguageModelRequest) => R): Thenable; + + // interface LanguageModelRequest { + // readonly quota: any; + // readonly permissions: any; + // makeRequest(messages: LanguageModelChatMessage[], options: { [name: string]: any }, token: CancellationToken): LanguageModelChatResponse; + // } }