api - sketch up vscode.lm.makeChatRequest alternative to requesting chat access (#206088)

re https://github.com/microsoft/vscode/issues/205800
This commit is contained in:
Johannes Rieken 2024-02-23 15:15:06 +01:00 committed by GitHub
parent 11a6b428f8
commit 529e73d71b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 77 additions and 1 deletions

View file

@ -3,7 +3,7 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { CancellationTokenSource } from 'vs/base/common/cancellation';
import { CancellationToken, 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';
@ -1436,6 +1436,20 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
onDidChangeLanguageModels: (listener, thisArgs?, disposables?) => {
checkProposedApiEnabled(extension, 'languageModels');
return extHostChatProvider.onDidChangeProviders(listener, thisArgs, disposables);
},
makeChatRequest(languageModel: string, messages: vscode.LanguageModelMessage[], optionsOrToken: { [name: string]: any } | vscode.CancellationToken, token?: vscode.CancellationToken) {
checkProposedApiEnabled(extension, 'languageModels');
let options: Record<string, any>;
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);
}
};

View file

@ -38,6 +38,10 @@ class LanguageModelResponseStream {
class LanguageModelRequest {
static fromError(err: Error): vscode.LanguageModelResponse {
return new LanguageModelRequest(Promise.reject(err), new CancellationTokenSource()).apiObject;
}
readonly apiObject: vscode.LanguageModelResponse;
private readonly _responseStreams = new Map<number, LanguageModelResponseStream>();
@ -223,6 +227,38 @@ export class ExtHostLanguageModels implements ExtHostLanguageModelsShape {
}
}
async makeChatRequest(extension: IExtensionDescription, languageModelId: string, messages: vscode.LanguageModelMessage[], options: Record<string, any>, token: CancellationToken) {
const from = extension.identifier;
// const justification = options?.justification; // TODO@jrieken
const metadata = await this._proxy.$prepareChatAccess(from, languageModelId, undefined);
if (!metadata || !this._languageModelIds.has(languageModelId)) {
return LanguageModelRequest.fromError(new Error(`Language model ${languageModelId} is unknown`));
}
if (this._isUsingAuth(from, metadata)) {
await this._getAuthAccess(extension, { identifier: metadata.extension, displayName: metadata.auth.providerLabel }, undefined);
if (!this._modelAccessList.get(from)?.has(metadata.extension)) {
return LanguageModelRequest.fromError(new Error('Access to chat has been revoked'));
}
}
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);
this._pendingRequest.set(requestId, { languageModelId, res });
requestPromise.finally(() => {
this._pendingRequest.delete(requestId);
cts.dispose();
});
return res.apiObject;
}
async requestLanguageModelAccess(extension: IExtensionDescription, languageModelId: string, options?: vscode.LanguageModelAccessOptions): Promise<vscode.LanguageModelAccess> {
const from = extension.identifier;
const justification = options?.justification;

View file

@ -171,6 +171,32 @@ declare module 'vscode' {
*/
export function requestLanguageModelAccess(id: string, options?: LanguageModelAccessOptions): Thenable<LanguageModelAccess>;
/**
* 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
*
* - 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
*/
// TODO@API refine doc
// TODO@API define specific error types?
export function makeChatRequest(languageModel: string, messages: LanguageModelMessage[], options: { [name: string]: any }, token: CancellationToken): Thenable<LanguageModelResponse>;
/**
* @see {@link makeChatRequest}
*/
export function makeChatRequest(languageModel: string, messages: LanguageModelMessage[], token: CancellationToken): Thenable<LanguageModelResponse>;
/**
* The identifiers of all language models that are currently available.
*/