update sample to latest api (#1021)

* update sample to latest api

* Fix family

* Minor cleanup

* Add fullname

---------

Co-authored-by: Rob Lourens <roblourens@gmail.com>
This commit is contained in:
Isidor Nikolic
2024-05-15 23:36:25 +02:00
committed by GitHub
parent 209ce0e81b
commit cfec264062
6 changed files with 335 additions and 313 deletions

View File

@ -15,7 +15,7 @@
"typescript": "^4.0.3"
},
"engines": {
"vscode": "^1.86.0"
"vscode": "^1.90.0"
}
},
"node_modules/@aashutoshrathi/word-wrap": {

View File

@ -9,7 +9,7 @@
},
"version": "0.1.0",
"engines": {
"vscode": "^1.88.0"
"vscode": "^1.90.0"
},
"extensionDependencies": [
"github.copilot-chat"
@ -27,6 +27,7 @@
"chatParticipants": [
{
"id": "chat-sample.cat",
"fullName": "Cat",
"name": "cat",
"description": "Meow! What can I teach you?",
"isSticky": true,

View File

@ -9,7 +9,7 @@ interface ICatChatResult extends vscode.ChatResult {
}
}
const LANGUAGE_MODEL_ID = 'copilot-gpt-3.5-turbo'; // Use faster model. Alternative is 'copilot-gpt-4', which is slower but more powerful
const MODEL_SELECTOR: vscode.LanguageModelChatSelector = { vendor: 'copilot', family: 'gpt-3.5-turbo' };
export function activate(context: vscode.ExtensionContext) {
@ -22,11 +22,12 @@ export function activate(context: vscode.ExtensionContext) {
stream.progress('Picking the right topic to teach...');
const topic = getTopic(context.history);
const messages = [
new vscode.LanguageModelChatUserMessage('You are a cat! Your job is to explain computer science concepts in the funny manner of a cat. Always start your response by stating what concept you are explaining. Always include code samples.'),
new vscode.LanguageModelChatUserMessage(topic)
vscode.LanguageModelChatMessage.User('You are a cat! Your job is to explain computer science concepts in the funny manner of a cat. Always start your response by stating what concept you are explaining. Always include code samples.'),
vscode.LanguageModelChatMessage.User(topic)
];
const chatResponse = await vscode.lm.sendChatRequest(LANGUAGE_MODEL_ID, messages, {}, token);
for await (const fragment of chatResponse.stream) {
const [model] = await vscode.lm.selectChatModels(MODEL_SELECTOR);
const chatResponse = await model.sendRequest(messages, {}, token);
for await (const fragment of chatResponse.text) {
stream.markdown(fragment);
}
@ -39,22 +40,24 @@ export function activate(context: vscode.ExtensionContext) {
} else if (request.command == 'play') {
stream.progress('Throwing away the computer science books and preparing to play with some Python code...');
const messages = [
new vscode.LanguageModelChatUserMessage('You are a cat! Reply in the voice of a cat, using cat analogies when appropriate. Be concise to prepare for cat play time.'),
new vscode.LanguageModelChatUserMessage('Give a small random python code samples (that have cat names for variables). ' + request.prompt)
vscode.LanguageModelChatMessage.User('You are a cat! Reply in the voice of a cat, using cat analogies when appropriate. Be concise to prepare for cat play time.'),
vscode.LanguageModelChatMessage.User('Give a small random python code samples (that have cat names for variables). ' + request.prompt)
];
const chatResponse = await vscode.lm.sendChatRequest(LANGUAGE_MODEL_ID, messages, {}, token);
for await (const fragment of chatResponse.stream) {
const [model] = await vscode.lm.selectChatModels(MODEL_SELECTOR);
const chatResponse = await model.sendRequest(messages, {}, token);
for await (const fragment of chatResponse.text) {
stream.markdown(fragment);
}
return { metadata: { command: 'play' } };
} else {
const messages = [
new vscode.LanguageModelChatUserMessage(`You are a cat! Think carefully and step by step like a cat would.
vscode.LanguageModelChatMessage.User(`You are a cat! Think carefully and step by step like a cat would.
Your job is to explain computer science concepts in the funny manner of a cat, using cat metaphors. Always start your response by stating what concept you are explaining. Always include code samples.`),
new vscode.LanguageModelChatUserMessage(request.prompt)
vscode.LanguageModelChatMessage.User(request.prompt)
];
const chatResponse = await vscode.lm.sendChatRequest(LANGUAGE_MODEL_ID, messages, {}, token);
for await (const fragment of chatResponse.stream) {
const [model] = await vscode.lm.selectChatModels(MODEL_SELECTOR);
const chatResponse = await model.sendRequest(messages, {}, token);
for await (const fragment of chatResponse.text) {
// Process the output from the language model
// Replace all python function definitions with cat sounds to make the user stop looking at the code and start playing with the cat
const catFragment = fragment.replaceAll('def', 'meow');
@ -80,28 +83,6 @@ export function activate(context: vscode.ExtensionContext) {
}
};
vscode.chat.registerChatVariableResolver('cat_context', 'Describes the state of mind and version of the cat', {
resolve: (name, context, token) => {
if (name == 'cat_context') {
const mood = Math.random() > 0.5 ? 'happy' : 'grumpy';
return [
{
level: vscode.ChatVariableLevel.Short,
value: 'version 1.3 ' + mood
},
{
level: vscode.ChatVariableLevel.Medium,
value: 'I am a playful cat, version 1.3, and I am ' + mood
},
{
level: vscode.ChatVariableLevel.Full,
value: 'I am a playful cat, version 1.3, this version prefer to explain everything using mouse and tail metaphores. I am ' + mood
}
]
}
}
});
context.subscriptions.push(
cat,
// Register the command handler for the /meow followup
@ -109,14 +90,15 @@ export function activate(context: vscode.ExtensionContext) {
// Replace all variables in active editor with cat names and words
const text = textEditor.document.getText();
const messages = [
new vscode.LanguageModelChatUserMessage(`You are a cat! Think carefully and step by step like a cat would.
new vscode.LanguageModelChatMessage(vscode.LanguageModelChatMessageRole.User, `You are a cat! Think carefully and step by step like a cat would.
Your job is to replace all variable names in the following code with funny cat variable names. Be creative. IMPORTANT respond just with code. Do not use markdown!`),
new vscode.LanguageModelChatUserMessage(text)
new vscode.LanguageModelChatMessage(vscode.LanguageModelChatMessageRole.User, text)
];
let chatResponse: vscode.LanguageModelChatResponse | undefined;
try {
chatResponse = await vscode.lm.sendChatRequest(LANGUAGE_MODEL_ID, messages, {}, new vscode.CancellationTokenSource().token);
const [model] = await vscode.lm.selectChatModels({ vendor: 'copilot', family: 'gpt-3.5-turbo' });
chatResponse = await model.sendRequest(messages, {}, new vscode.CancellationTokenSource().token);
} catch (err) {
// making the chat request might fail because
@ -138,7 +120,7 @@ export function activate(context: vscode.ExtensionContext) {
// Stream the code into the editor as it is coming in from the Language Model
try {
for await (const fragment of chatResponse.stream) {
for await (const fragment of chatResponse.text) {
await textEditor.edit(edit => {
const lastLine = textEditor.document.lineAt(textEditor.document.lineCount - 1);
const position = new vscode.Position(lastLine.lineNumber, lastLine.text.length);

View File

@ -12,7 +12,7 @@ declare module 'vscode' {
/**
* 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.
@ -30,12 +30,14 @@ declare module 'vscode' {
readonly command?: string;
/**
* The variables that were referenced in this message.
* TODO@API ensure that this will be compatible with future changes to chat variables.
* 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);
}
/**
@ -62,12 +64,18 @@ declare module 'vscode' {
*/
readonly command?: string;
/**
* @hidden
*/
private constructor(response: ReadonlyArray<ChatResponseMarkdownPart | ChatResponseFileTreePart | ChatResponseAnchorPart | ChatResponseCommandButtonPart>, 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<ChatRequestTurn | ChatResponseTurn>;
}
@ -81,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.
*/
@ -229,43 +228,41 @@ declare module 'vscode' {
onDidReceiveFeedback: Event<ChatResultFeedback>;
/**
* 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 value of this reference. The `string | Uri | Location` types are used today, but this could expand in the future.
*/
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.
@ -277,17 +274,16 @@ 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.
*/
readonly variables: readonly ChatResolvedVariable[];
readonly references: readonly ChatPromptReference[];
}
/**
@ -302,48 +298,43 @@ declare module 'vscode' {
*
* @see {@link ChatResponseStream.push}
* @param value A markdown string or a string that should be interpreted as markdown. The boolean form of {@link MarkdownString.isTrusted} is NOT supported.
* @returns This stream.
*/
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
@ -353,57 +344,144 @@ declare module 'vscode' {
*
* @param value A uri or location
* @param iconPath Icon for the reference shown in UI
* @returns This stream.
*/
reference(value: Uri | Location | { variableName: string; value?: Uri | Location }, iconPath?: ThemeIcon): 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;
/**
* @param value Note: The boolean form of {@link MarkdownString.isTrusted} is NOT supported.
* 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 {
value: Uri | Location | { variableName: string; value?: Uri | Location };
iconPath?: ThemeIcon;
constructor(value: Uri | Location | { variableName: string; value?: Uri | Location }, iconPath?: ThemeIcon);
/**
* The reference target.
*/
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);
}
@ -424,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;
}
}

View File

@ -1,52 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
declare module 'vscode' {
export namespace chat {
/**
* Register a variable which can be used in a chat request to any participant.
* @param name The name of the variable, to be used in the chat input as `#name`.
* @param description A description of the variable for the chat input suggest widget.
* @param resolver Will be called to provide the chat variable's value when it is used.
*/
export function registerChatVariableResolver(name: string, description: string, resolver: ChatVariableResolver): Disposable;
}
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;
}
export interface ChatVariableContext {
/**
* The message entered by the user, which includes this variable.
*/
prompt: string;
}
export interface ChatVariableResolver {
/**
* A callback to resolve the value of a chat variable.
* @param name The name of the variable.
* @param context Contextual information about this chat request.
* @param token A cancellation token.
*/
resolve(name: string, context: ChatVariableContext, token: CancellationToken): ProviderResult<ChatVariableValue[]>;
}
}

View File

@ -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<string>;
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.
*/
content: string;
/**
* Create a new system 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.
*/
constructor(content: string);
}
static User(content: string, name?: string): LanguageModelChatMessage;
/**
* A language model message that represents a user message.
*/
export class LanguageModelChatUserMessage {
/**
* 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.
*/
static Assistant(content: string, name?: string): LanguageModelChatMessage;
/**
* The role of this message.
*/
role: LanguageModelChatMessageRole;
/**
* The content of this message.
@ -62,83 +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);
}
/**
* 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 LanguageModelChatAssistantMessage {
* Represents a language model response.
*
* @see {@link LanguageModelAccess.chatRequest}
*/
export interface LanguageModelChatResponse {
/**
* The content of this message.
*/
content: string;
/**
* The optional name of a user for this message.
*/
name: string | undefined;
/**
* Create a new assistant message.
* An async iterable that is a stream of text chunks forming the overall response.
*
* @param content The content of the message.
* @param name The optional name of a user for the message.
* *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.
*/
constructor(content: string, name?: string);
text: AsyncIterable<string>;
}
/**
* Different types of language model messages.
* Represents a language model for making chat requests.
*
* @see {@link lm.selectChatModels}
*/
export type LanguageModelChatMessage = LanguageModelChatSystemMessage | LanguageModelChatUserMessage | LanguageModelChatAssistantMessage;
/**
* Represents information about a registered language model.
*/
export interface LanguageModelInformation {
/**
* The identifier of the language model.
*/
readonly id: string;
export interface LanguageModelChat {
/**
* The human-readable name of the language model.
* Human-readable name of the language model.
*/
readonly name: string;
/**
* The version of the language model.
* Opaque identifier of the language model.
*/
readonly id: string;
/**
* 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 number of available tokens that can be used when sending requests
* to the language model.
*
* @see {@link lm.sendChatRequest}
* The maximum number of tokens that can be sent to the model in a single request.
*/
readonly tokens: number;
readonly maxInputTokens: number;
/**
* Make a chat request using a language model.
*
* *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.
*/
sendRequest(messages: LanguageModelChatMessage[], options?: LanguageModelChatRequestOptions, token?: CancellationToken): Thenable<LanguageModelChatResponse>;
/**
* 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<number>;
}
/**
* An event describing the change in the set of available language models.
* Describes how to select language models for chat requests.
*
* @see {@link lm.selectChatModels}
*/
// TODO@API use LanguageModelInformation instead of string?
export interface LanguageModelChangeEvent {
export interface LanguageModelChatSelector {
/**
* Added language models.
* A vendor of language models.
* @see {@link LanguageModelChat.vendor}
*/
readonly added: readonly string[];
vendor?: string;
/**
* Removed language models.
* A family of language models.
* @see {@link LanguageModelChat.family}
*/
readonly removed: readonly string[];
family?: string;
/**
* The version of a language model.
* @see {@link LanguageModelChat.version}
*/
version?: string;
/**
* The identifier of a language model.
* @see {@link LanguageModelChat.id}
*/
id?: string;
}
/**
@ -151,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.
*
@ -175,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 {
@ -184,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.
@ -203,58 +267,33 @@ 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.
* 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.
*
* ```ts
*
* 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
* }
* ```
*
* *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 selector A chat model selector. When omitted all chat models are returned.
* @returns An array of chat models, can be empty!
*/
export const onDidChangeLanguageModels: Event<LanguageModelChangeEvent>;
/**
* 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.
*
* - *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.
*
* 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`}
*
* @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.
*/
export function computeTokenLength(languageModel: string, text: string | LanguageModelChatMessage, token?: CancellationToken): Thenable<number>;
export function selectChatModels(selector?: LanguageModelChatSelector): Thenable<LanguageModelChat[]>;
}
/**
@ -270,13 +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;
canSendRequest(chat: LanguageModelChat): boolean | undefined;
}
export interface ExtensionContext {