From 8e1dc6494b51b55ac4b769425e520408e3c38085 Mon Sep 17 00:00:00 2001 From: Joyce Er Date: Wed, 15 May 2024 10:18:54 -0700 Subject: [PATCH] chore: update to latest APIs (#26) --- package-lock.json | 4 +- package.json | 2 +- src/base/index.ts | 6 +- src/base/tokenizer/tokenizer.ts | 25 -- src/base/vscode.proposed.chatParticipant.d.ts | 268 +++++++++-------- src/base/vscode.proposed.languageModel.d.ts | 270 ++++++++++++------ 6 files changed, 328 insertions(+), 247 deletions(-) diff --git a/package-lock.json b/package-lock.json index 9ebf598..07e122c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@vscode/prompt-tsx", - "version": "0.1.5-alpha", + "version": "0.1.7-alpha", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@vscode/prompt-tsx", - "version": "0.1.5-alpha", + "version": "0.1.7-alpha", "license": "SEE LICENSE IN LICENSE", "dependencies": { "@microsoft/tiktokenizer": "^1.0.6" diff --git a/package.json b/package.json index deac2c8..aa94fd9 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@vscode/prompt-tsx", - "version": "0.1.6-alpha", + "version": "0.1.7-alpha", "description": "Declare LLM prompts with TSX", "main": "./dist/base/index.js", "types": "./dist/base/index.d.ts", diff --git a/src/base/index.ts b/src/base/index.ts index a94ec9b..f1511b9 100644 --- a/src/base/index.ts +++ b/src/base/index.ts @@ -95,12 +95,10 @@ export function toVsCodeChatMessages(messages: ChatMessage[]) { const vscode = require('vscode'); return messages.map((m) => { switch (m.role) { - case ChatRole.System: - return new vscode.LanguageModelChatSystemMessage(m.content); case ChatRole.Assistant: - return new vscode.LanguageModelChatAssistantMessage(m.content, m.name); + return vscode.LanguageModelChatMessage.Assistant(m.content, m.name); case ChatRole.User: - return new vscode.LanguageModelChatUserMessage(m.content, m.name); + return vscode.LanguageModelChatMessage.User(m.content, m.name); } }); } diff --git a/src/base/tokenizer/tokenizer.ts b/src/base/tokenizer/tokenizer.ts index ca34061..c9c9698 100644 --- a/src/base/tokenizer/tokenizer.ts +++ b/src/base/tokenizer/tokenizer.ts @@ -25,18 +25,6 @@ export interface ITokenizer { */ tokenLength(text: string): number; - /** - * Returns the tokens created from tokenizing `text`. - * @param text The text to tokenize - */ - tokenize(text: string): number[]; - - /** - * This function returns the substring such that the return string has maxTokenCount tokens when encoded. - * If the input text has more than maxTokenCount tokens, the return string will be the first maxTokenCount tokens. - */ - encodeTrimSuffix(text: string, maxTokenCount: number): string; - countMessageTokens(message: ChatMessage): number; } @@ -69,19 +57,6 @@ export class Cl100KBaseTokenizer implements ITokenizer { return this._cl100kTokenizer.encode(text); } - /** - * Encodes the given text and trims the suffix to the specified maximum token count. - * @param text The text to encode and trim. - * @param maxTokenCount The maximum number of tokens to include in the trimmed text. - * @returns The encoded and trimmed text. - */ - encodeTrimSuffix(text: string, maxTokenCount: number): string { - if (!this._cl100kTokenizer) { - this._cl100kTokenizer = this.initTokenizer(); - } - return this._cl100kTokenizer.encodeTrimSuffix(text, maxTokenCount, []).text; - } - /** * Calculates the token length of the given text. * @param text The text to calculate the token length for. diff --git a/src/base/vscode.proposed.chatParticipant.d.ts b/src/base/vscode.proposed.chatParticipant.d.ts index 2862413..9ace1a0 100644 --- a/src/base/vscode.proposed.chatParticipant.d.ts +++ b/src/base/vscode.proposed.chatParticipant.d.ts @@ -9,11 +9,10 @@ declare module 'vscode' { * Represents a user request in chat history. */ export class ChatRequestTurn { - /** * The prompt as entered by the user. * - * Information about variables used in this request is stored in {@link ChatRequestTurn.variables}. + * Information about references used in this request is stored in {@link ChatRequestTurn.references}. * * *Note* that the {@link ChatParticipant.name name} of the participant and the {@link ChatCommand.name command} * are not part of the prompt. @@ -21,7 +20,7 @@ declare module 'vscode' { readonly prompt: string; /** - * The id of the chat participant and contributing extension to which this request was directed. + * The id of the chat participant to which this request was directed. */ readonly participant: string; @@ -31,20 +30,22 @@ declare module 'vscode' { readonly command?: string; /** - * The variables that were referenced in this message. + * The references that were used in this message. */ - readonly variables: ChatResolvedVariable[]; + readonly references: ChatPromptReference[]; - private constructor(prompt: string, command: string | undefined, variables: ChatResolvedVariable[], participant: string); + /** + * @hidden + */ + private constructor(prompt: string, command: string | undefined, references: ChatPromptReference[], participant: string); } /** * Represents a chat participant's response in chat history. */ export class ChatResponseTurn { - /** - * The content that was received from the chat participant. Only the stream parts that represent actual content (not metadata) are represented. + * The content that was received from the chat participant. Only the stream parts that represent actual content (not metadata) are represented. */ readonly response: ReadonlyArray; @@ -54,7 +55,7 @@ declare module 'vscode' { readonly result: ChatResult; /** - * The id of the chat participant and contributing extension that this response came from. + * The id of the chat participant that this response came from. */ readonly participant: string; @@ -63,12 +64,18 @@ declare module 'vscode' { */ readonly command?: string; + /** + * @hidden + */ private constructor(response: ReadonlyArray, result: ChatResult, participant: string); } + /** + * Extra context passed to a participant. + */ export interface ChatContext { /** - * All of the chat messages so far in the current chat session. + * All of the chat messages so far in the current chat session. Currently, only chat messages for the current participant are included. */ readonly history: ReadonlyArray; } @@ -82,15 +89,6 @@ declare module 'vscode' { */ message: string; - /** - * If partial markdown content was sent over the {@link ChatRequestHandler handler}'s response stream before the response terminated, then this flag - * can be set to true and it will be rendered with incomplete markdown features patched up. - * - * For example, if the response terminated after sending part of a triple-backtick code block, then the editor will - * render it as a complete code block. - */ - responseIsIncomplete?: boolean; - /** * If set to true, the response will be partly blurred out. */ @@ -132,8 +130,8 @@ declare module 'vscode' { */ export interface ChatResultFeedback { /** - * The ChatResult that the user is providing feedback for. - * This instance has the same properties as the result returned from the participant callback, including `metadata`, but is not the same instance. + * The ChatResult for which the user is providing feedback. + * This object has the same properties as the result returned from the participant callback, including `metadata`, but is not the same instance. */ readonly result: ChatResult; @@ -175,7 +173,7 @@ declare module 'vscode' { export interface ChatFollowupProvider { /** * Provide followups for the given result. - * @param result This instance has the same properties as the result returned from the participant callback, including `metadata`, but is not the same instance. + * @param result This object has the same properties as the result returned from the participant callback, including `metadata`, but is not the same instance. * @param token A cancellation token. */ provideFollowups(result: ChatResult, context: ChatContext, token: CancellationToken): ProviderResult; @@ -184,7 +182,7 @@ declare module 'vscode' { /** * A chat request handler is a callback that will be invoked when a request is made to a chat participant. */ - export type ChatRequestHandler = (request: ChatRequest, context: ChatContext, response: ChatResponseStream, token: CancellationToken) => ProviderResult; + export type ChatRequestHandler = (request: ChatRequest, context: ChatContext, response: ChatResponseStream, token: CancellationToken) => ProviderResult; /** * A chat participant can be invoked by the user in a chat session, using the `@` prefix. When it is invoked, it handles the chat request and is solely @@ -197,7 +195,7 @@ declare module 'vscode' { readonly id: string; /** - * Icon for the participant shown in UI. + * An icon for the participant shown in UI. */ iconPath?: Uri | { /** @@ -220,16 +218,6 @@ declare module 'vscode' { */ followupProvider?: ChatFollowupProvider; - /** - * When the user clicks this participant in `/help`, this text will be submitted to this participant. - */ - sampleRequest?: string; - - /** - * Whether invoking the participant puts the chat into a persistent mode, where the participant is automatically added to the chat input for the next message. - */ - isSticky?: boolean; - /** * An event that fires whenever feedback for a result is received, e.g. when a user up- or down-votes * a result. @@ -240,61 +228,41 @@ declare module 'vscode' { onDidReceiveFeedback: Event; /** - * Dispose this participant and free resources + * Dispose this participant and free resources. */ dispose(): void; } - /** - * A resolved variable value is a name-value pair as well as the range in the prompt where a variable was used. - */ - export interface ChatResolvedVariable { + export interface ChatPromptReference { /** - * The name of the variable. - * - * *Note* that the name doesn't include the leading `#`-character, - * e.g `selection` for `#selection`. + * A unique identifier for this kind of reference. */ - readonly name: string; + readonly id: string; /** - * The start and end index of the variable in the {@link ChatRequest.prompt prompt}. + * The start and end index of the reference in the {@link ChatRequest.prompt prompt}. When undefined, the reference was not part of the prompt text. * * *Note* that the indices take the leading `#`-character into account which means they can * used to modify the prompt as-is. */ readonly range?: [start: number, end: number]; - // TODO@API decouple of resolve API, use `value: string | Uri | (maybe) unknown?` /** - * The values of the variable. Can be an empty array if the variable doesn't currently have a value. + * A description of this value that could be used in an LLM prompt. */ - readonly values: ChatVariableValue[]; - } + readonly modelDescription?: string; - /** - * The location at which the chat is happening. - */ - export enum ChatLocation { /** - * The chat panel + * The value of this reference. The `string | Uri | Location` types are used today, but this could expand in the future. */ - Panel = 1, - /** - * Terminal inline chat - */ - Terminal = 2, - /** - * Notebook inline chat - */ - Notebook = 3 + readonly value: string | Uri | Location | unknown; } export interface ChatRequest { /** * The prompt as entered by the user. * - * Information about variables used in this request is stored in {@link ChatRequest.variables}. + * Information about references used in this request is stored in {@link ChatRequest.references}. * * *Note* that the {@link ChatParticipant.name name} of the participant and the {@link ChatCommand.name command} * are not part of the prompt. @@ -307,21 +275,15 @@ declare module 'vscode' { readonly command: string | undefined; /** - * The list of variables and their values that are referenced in the prompt. + * The list of references and their values that are referenced in the prompt. * - * *Note* that the prompt contains varibale references as authored and that it is up to the participant - * to further modify the prompt, for instance by inlining variable values or creating links to - * headings which contain the resolved values. Variables are sorted in reverse by their range - * in the prompt. That means the last variable in the prompt is the first in this list. This simplifies + * *Note* that the prompt contains references as authored and that it is up to the participant + * to further modify the prompt, for instance by inlining reference values or creating links to + * headings which contain the resolved values. References are sorted in reverse by their range + * in the prompt. That means the last reference in the prompt is the first in this list. This simplifies * string-manipulation of the prompt. */ - // TODO@API Q? are there implicit variables that are not part of the prompt? - readonly variables: readonly ChatResolvedVariable[]; - - /** - * The location at which the chat is happening. This will always be one of the supported values - */ - readonly location: ChatLocation; + readonly references: readonly ChatPromptReference[]; } /** @@ -335,49 +297,44 @@ declare module 'vscode' { * `push(new ChatResponseMarkdownPart(value))`. * * @see {@link ChatResponseStream.push} - * @param value A markdown string or a string that should be interpreted as markdown. - * @returns This stream. + * @param value A markdown string or a string that should be interpreted as markdown. The boolean form of {@link MarkdownString.isTrusted} is NOT supported. */ - markdown(value: string | MarkdownString): ChatResponseStream; + markdown(value: string | MarkdownString): void; /** * Push an anchor part to this stream. Short-hand for * `push(new ChatResponseAnchorPart(value, title))`. * An anchor is an inline reference to some type of resource. * - * @param value A uri or location - * @param title An optional title that is rendered with value - * @returns This stream. + * @param value A uri, location, or symbol information. + * @param title An optional title that is rendered with value. */ - anchor(value: Uri | Location, title?: string): ChatResponseStream; + anchor(value: Uri | Location, title?: string): void; /** * Push a command button part to this stream. Short-hand for * `push(new ChatResponseCommandButtonPart(value, title))`. * * @param command A Command that will be executed when the button is clicked. - * @returns This stream. */ - button(command: Command): ChatResponseStream; + button(command: Command): void; /** * Push a filetree part to this stream. Short-hand for * `push(new ChatResponseFileTreePart(value))`. * * @param value File tree data. - * @param baseUri The base uri to which this file tree is relative to. - * @returns This stream. + * @param baseUri The base uri to which this file tree is relative. */ - filetree(value: ChatResponseFileTree[], baseUri: Uri): ChatResponseStream; + filetree(value: ChatResponseFileTree[], baseUri: Uri): void; /** * Push a progress part to this stream. Short-hand for * `push(new ChatResponseProgressPart(value))`. * * @param value A progress message - * @returns This stream. */ - progress(value: string): ChatResponseStream; + progress(value: string): void; /** * Push a reference to this stream. Short-hand for @@ -386,52 +343,145 @@ declare module 'vscode' { * *Note* that the reference is not rendered inline with the response. * * @param value A uri or location - * @returns This stream. + * @param iconPath Icon for the reference shown in UI */ - reference(value: Uri | Location): ChatResponseStream; + reference(value: Uri | Location, iconPath?: Uri | ThemeIcon | { light: Uri; dark: Uri }): void; /** * Pushes a part to this stream. * * @param part A response part, rendered or metadata */ - push(part: ChatResponsePart): ChatResponseStream; + push(part: ChatResponsePart): void; } + /** + * Represents a part of a chat response that is formatted as Markdown. + */ export class ChatResponseMarkdownPart { + /** + * A markdown string or a string that should be interpreted as markdown. + */ value: MarkdownString; + + /** + * Create a new ChatResponseMarkdownPart. + * + * @param value A markdown string or a string that should be interpreted as markdown. The boolean form of {@link MarkdownString.isTrusted} is NOT supported. + */ constructor(value: string | MarkdownString); } + /** + * Represents a file tree structure in a chat response. + */ export interface ChatResponseFileTree { + /** + * The name of the file or directory. + */ name: string; + + /** + * An array of child file trees, if the current file tree is a directory. + */ children?: ChatResponseFileTree[]; } + /** + * Represents a part of a chat response that is a file tree. + */ export class ChatResponseFileTreePart { + /** + * File tree data. + */ value: ChatResponseFileTree[]; + + /** + * The base uri to which this file tree is relative + */ baseUri: Uri; + + /** + * Create a new ChatResponseFileTreePart. + * @param value File tree data. + * @param baseUri The base uri to which this file tree is relative. + */ constructor(value: ChatResponseFileTree[], baseUri: Uri); } + /** + * Represents a part of a chat response that is an anchor, that is rendered as a link to a target. + */ export class ChatResponseAnchorPart { - value: Uri | Location | SymbolInformation; + /** + * The target of this anchor. + */ + value: Uri | Location; + + /** + * An optional title that is rendered with value. + */ title?: string; - constructor(value: Uri | Location | SymbolInformation, title?: string); + + /** + * Create a new ChatResponseAnchorPart. + * @param value A uri or location. + * @param title An optional title that is rendered with value. + */ + constructor(value: Uri | Location, title?: string); } + /** + * Represents a part of a chat response that is a progress message. + */ export class ChatResponseProgressPart { + /** + * The progress message + */ value: string; + + /** + * Create a new ChatResponseProgressPart. + * @param value A progress message + */ constructor(value: string); } + /** + * Represents a part of a chat response that is a reference, rendered separately from the content. + */ export class ChatResponseReferencePart { + /** + * The reference target. + */ value: Uri | Location; - constructor(value: Uri | Location); + + /** + * The icon for the reference. + */ + iconPath?: Uri | ThemeIcon | { light: Uri; dark: Uri }; + + /** + * Create a new ChatResponseReferencePart. + * @param value A uri or location + * @param iconPath Icon for the reference shown in UI + */ + constructor(value: Uri | Location, iconPath?: Uri | ThemeIcon | { light: Uri; dark: Uri }); } + /** + * Represents a part of a chat response that is a button that executes a command. + */ export class ChatResponseCommandButtonPart { + /** + * The command that will be executed when the button is clicked. + */ value: Command; + + /** + * Create a new ChatResponseCommandButtonPart. + * @param value A Command that will be executed when the button is clicked. + */ constructor(value: Command); } @@ -452,30 +502,4 @@ declare module 'vscode' { */ export function createChatParticipant(id: string, handler: ChatRequestHandler): ChatParticipant; } - - /** - * The detail level of this chat variable value. - */ - export enum ChatVariableLevel { - Short = 1, - Medium = 2, - Full = 3 - } - - export interface ChatVariableValue { - /** - * The detail level of this chat variable value. If possible, variable resolvers should try to offer shorter values that will consume fewer tokens in an LLM prompt. - */ - level: ChatVariableLevel; - - /** - * The variable's value, which can be included in an LLM prompt as-is, or the chat participant may decide to read the value and do something else with it. - */ - value: string | Uri; - - /** - * A description of this value, which could be provided to the LLM as a hint. - */ - description?: string; - } } diff --git a/src/base/vscode.proposed.languageModel.d.ts b/src/base/vscode.proposed.languageModel.d.ts index 98a61ec..2024eb9 100644 --- a/src/base/vscode.proposed.languageModel.d.ts +++ b/src/base/vscode.proposed.languageModel.d.ts @@ -5,49 +5,48 @@ declare module 'vscode' { + // https://github.com/microsoft/vscode/issues/206265 + /** - * Represents a language model response. - * - * @see {@link LanguageModelAccess.chatRequest} + * Represents the role of a chat message. This is either the user or the assistant. */ - export interface LanguageModelChatResponse { + export enum LanguageModelChatMessageRole { + /** + * The user role, e.g the human interacting with a language model. + */ + User = 1, /** - * An async iterable that is a stream of text chunks forming the overall response. - * - * *Note* that this stream will error when during data receiving an error occurrs. + * The assistant role, e.g. the language model generating responses. */ - stream: AsyncIterable; + Assistant = 2 } /** - * A language model message that represents a system message. - * - * System messages provide instructions to the language model that define the context in - * which user messages are interpreted. - * - * *Note* that a language model may choose to add additional system messages to the ones - * provided by extensions. + * Represents a message in a chat. Can assume different roles, like user or assistant. */ - export class LanguageModelChatSystemMessage { + export class LanguageModelChatMessage { /** - * The content of this message. + * Utility to create a new user message. + * + * @param content The content of the message. + * @param name The optional name of a user for the message. */ - content: string; + static User(content: string, name?: string): LanguageModelChatMessage; /** - * Create a new system message. + * Utility to create a new assistant message. * * @param content The content of the message. + * @param name The optional name of a user for the message. */ - constructor(content: string); - } + static Assistant(content: string, name?: string): LanguageModelChatMessage; - /** - * A language model message that represents a user message. - */ - export class LanguageModelChatUserMessage { + /** + * The role of this message. + */ + role: LanguageModelChatMessageRole; /** * The content of this message. @@ -62,54 +61,149 @@ declare module 'vscode' { /** * Create a new user message. * + * @param role The role of the message. * @param content The content of the message. * @param name The optional name of a user for the message. */ - constructor(content: string, name?: string); + constructor(role: LanguageModelChatMessageRole, content: string, name?: string); + } + + /** + * Represents a language model response. + * + * @see {@link LanguageModelAccess.chatRequest} + */ + 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 data receiving an error occurs. Consumers of + * the stream should handle the errors accordingly. + * + * @example + * ```ts + * try { + * // consume stream + * for await (const chunk of response.stream) { + * console.log(chunk); + * } + * + * } catch(e) { + * // stream ended with an error + * console.error(e); + * } + * ``` + * + * To cancel the stream, the consumer can {@link CancellationTokenSource.cancel cancel} the token that was used to make the request + * or break from the for-loop. + */ + text: AsyncIterable; } /** - * A language model message that represents an assistant message, usually in response to a user message - * or as a sample response/reply-pair. + * Represents a language model for making chat requests. + * + * @see {@link lm.selectChatModels} */ - export class LanguageModelChatAssistantMessage { + export interface LanguageModelChat { /** - * The content of this message. + * Human-readable name of the language model. */ - content: string; + readonly name: string; /** - * The optional name of a user for this message. + * Opaque identifier of the language model. */ - name: string | undefined; + readonly id: string; /** - * Create a new assistant message. + * A well-know identifier of the vendor of the language model, a sample is `copilot`, but + * values are defined by extensions contributing chat models and need to be looked up with them. + */ + readonly vendor: 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. + */ + readonly version: string; + + /** + * The maximum number of tokens that can be sent to the model in a single request. + */ + readonly maxInputTokens: number; + + /** + * Make a chat request using a language model. * - * @param content The content of the message. - * @param name The optional name of a user for the message. + * *Note* that 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. + * + * 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. */ - constructor(content: string, name?: string); + sendRequest(messages: LanguageModelChatMessage[], options?: LanguageModelChatRequestOptions, token?: CancellationToken): Thenable; + + /** + * Count the number of tokens in a message using the model specific tokenizer-logic. + + * @param text A string or a message instance. + * @param token Optional cancellation token. See {@link CancellationTokenSource} for how to create one. + * @returns A thenable that resolves to the number of tokens. + */ + countTokens(text: string | LanguageModelChatMessage, token?: CancellationToken): Thenable; } /** - * Different types of language model messages. + * Describes how to select language models for chat requests. + * + * @see {@link lm.selectChatModels} */ - export type LanguageModelChatMessage = LanguageModelChatSystemMessage | LanguageModelChatUserMessage | LanguageModelChatAssistantMessage; + export interface LanguageModelChatSelector { + + /** + * A vendor of language models. + * @see {@link LanguageModelChat.vendor} + */ + vendor?: string; + + /** + * A family of language models. + * @see {@link LanguageModelChat.family} + */ + family?: string; - /** - * An event describing the change in the set of available language models. - */ - export interface LanguageModelChangeEvent { /** - * Added language models. + * The version of a language model. + * @see {@link LanguageModelChat.version} */ - readonly added: readonly string[]; + version?: string; + /** - * Removed language models. + * The identifier of a language model. + * @see {@link LanguageModelChat.id} */ - readonly removed: readonly string[]; + id?: string; } /** @@ -122,17 +216,22 @@ declare module 'vscode' { */ export class LanguageModelError extends Error { - /** - * The language model does not exist. - */ - static NotFound(message?: string): LanguageModelError; - /** * The requestor does not have permissions to use this * language model */ static NoPermissions(message?: string): LanguageModelError; + /** + * The requestor is blocked from using this language model. + */ + static Blocked(message?: string): LanguageModelError; + + /** + * The language model does not exist. + */ + static NotFound(message?: string): LanguageModelError; + /** * A code that identifies this error. * @@ -146,7 +245,7 @@ declare module 'vscode' { /** * Options for making a chat request using a language model. * - * @see {@link lm.chatRequest} + * @see {@link LanguageModelChat.sendRequest} */ export interface LanguageModelChatRequestOptions { @@ -155,12 +254,6 @@ declare module 'vscode' { */ 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 Revisit this, how do you do the first request? - 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. @@ -174,38 +267,33 @@ declare module 'vscode' { export namespace lm { /** - * Make a chat request using a language model. + * An event that is fired when the set of available chat models changes. + */ + export const onDidChangeChatModels: Event; + + /** + * Select chat models by a {@link LanguageModelChatSelector selector}. This can yield in multiple or no chat models and + * extensions must handle these cases, esp. when no chat model exists, gracefully. * - * - *Note 1:* language model use may be subject to access restrictions and user consent. + * ```ts * - * - *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 aviailable values and handle missing language models gracefully. + * const models = await vscode.lm.selectChatModels({family: 'gpt-3.5-turbo'})!; + * if (models.length > 0) { + * const [first] = models; + * const response = await first.sendRequest(...) + * // ... + * } else { + * // NO chat models available + * } + * ``` * - * 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.cause `LanguageModelError.cause`} + * *Note* that extensions can hold-on to the results returned by this function and use them later. However, when the + * {@link onDidChangeChatModels}-event is fired the list of chat models might have changed and extensions should re-query. * - * @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. + * @param selector A chat model selector. When omitted all chat models are returned. + * @returns An array of chat models, can be empty! */ - export function sendChatRequest(languageModel: string, messages: LanguageModelChatMessage[], options: LanguageModelChatRequestOptions, token: CancellationToken): Thenable; - - /** - * The identifiers of all language models that are currently available. - */ - export const languageModels: readonly string[]; - - /** - * An event that is fired when the set of available language models changes. - */ - export const onDidChangeLanguageModels: Event; + export function selectChatModels(selector?: LanguageModelChatSelector): Thenable; } /** @@ -221,17 +309,13 @@ declare module 'vscode' { /** * Checks if a request can be made to a language model. * - * *Note* that calling this function will not trigger a consent UI but just checks. + * *Note* that calling this function will not trigger a consent UI but just checks for a persisted state. * - * @param languageModelId A language model identifier. + * @param chat A language model chat object. * @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. */ - canSendRequest(languageModelId: string): boolean | undefined; - - // TODO@API SYNC or ASYNC? - // TODO@API future - // retrieveQuota(languageModelId: string): { remaining: number; resets: Date }; + canSendRequest(chat: LanguageModelChat): boolean | undefined; } export interface ExtensionContext {