API update

This commit is contained in:
Rob Lourens
2024-08-13 15:24:22 -07:00
parent 443397275f
commit df946f379d
4 changed files with 81 additions and 61 deletions

View File

@ -33,9 +33,13 @@
],
"languageModelTools": [
{
"name": "chat-sample.activeTabCount",
"description": "The number of active tabs in the editor",
"displayName": "Text tab count"
"id": "chat-sample_tabCount",
"name": "tabCount",
"displayName": "Tab Count",
"modelDescription": "The number of active tabs in the editor",
"userDescription": "The number of active tabs in the editor",
"icon": "$(files)",
"canBeInvokedManually": true
}
]
},

View File

@ -6,7 +6,7 @@ export function activate(context: vscode.ExtensionContext) {
}
function registerChatTool() {
return vscode.lm.registerTool('chat-sample.activeTabCount', {
return vscode.lm.registerTool('chat-sample_tabCount', {
async invoke(parameters, token) {
return {
toString() {
@ -26,12 +26,12 @@ function registerChatParticipant() {
});
const model = models[0];
stream.markdown(`Available tools: ${vscode.lm.tools.map(tool => tool.name).join(', ')}\n\n`);
stream.markdown(`Available tools: ${vscode.lm.tools.map(tool => tool.id).join(', ')}\n\n`);
const allTools = vscode.lm.tools.map((tool): vscode.LanguageModelChatFunction => {
return {
name: tool.name.replace(/\./g, '_'),
description: tool.description,
name: tool.id,
description: tool.modelDescription,
parametersSchema: tool.parametersSchema ?? {}
};
});
@ -44,11 +44,12 @@ function registerChatParticipant() {
vscode.LanguageModelChatMessage.User(`There is a selection of tools that may give helpful context to answer the user's query. If you aren't sure which tool is relevant, you can call multiple tools.`),
vscode.LanguageModelChatMessage.User(request.prompt),
];
const toolReferences = [...request.toolReferences];
const runWithFunctions = async () => {
const requestedTool = request.requestedTools?.shift();
const requestedTool = toolReferences.shift();
if (requestedTool) {
options.toolChoice = requestedTool;
options.tools = allTools.filter(tool => tool.name === requestedTool);
options.toolChoice = requestedTool.id;
options.tools = allTools.filter(tool => tool.name === requestedTool.id);
} else {
options.toolChoice = undefined;
options.tools = allTools;
@ -62,7 +63,7 @@ function registerChatParticipant() {
if (part instanceof vscode.LanguageModelChatResponseTextPart) {
stream.markdown(part.value);
} else if (part instanceof vscode.LanguageModelChatResponseFunctionUsePart) {
const tool = vscode.lm.tools.find(tool => tool.name.replace(/\./g, '_') === part.name);
const tool = vscode.lm.tools.find(tool => tool.id === part.name);
if (!tool) {
// BAD tool choice?
continue;
@ -75,22 +76,18 @@ function registerChatParticipant() {
throw new Error(`Got invalid tool use parameters: "${part.parameters}". (${(err as Error).message})`);
}
const resultPromise = vscode.lm.invokeTool(tool.name, JSON.parse(part.parameters), token);
stream.progress(`FUNCTION_CALL: ${tool.name} with ${part.parameters}`, async () => {
await resultPromise;
});
const result = await resultPromise;
stream.progress(`Calling tool: ${tool.id} with ${part.parameters}`);
const result = await vscode.lm.invokeTool(tool.id, JSON.parse(part.parameters), token);
// NOTE that the result of calling a function is a special content type of a USER-message
let message = vscode.LanguageModelChatMessage.User('');
message.content2 = new vscode.LanguageModelChatMessageFunctionResultPart(tool.name.replace(/\./g, '_'), result.toString());
message.content2 = new vscode.LanguageModelChatMessageFunctionResultPart(tool.id.replace(/\./g, '_'), result.toString());
messages.push(message);
// IMPORTANT
// IMPORTANT working around CAPI always wanting to end with a `User`-message
// IMPORTANT
messages.push(vscode.LanguageModelChatMessage.User(`Above is the result of calling the function ${tool.name}. The user cannot see this result, so you should explain it to the user if referencing it in your answer.`));
messages.push(vscode.LanguageModelChatMessage.User(`Above is the result of calling the function ${tool.id}. The user cannot see this result, so you should explain it to the user if referencing it in your answer.`));
didReceiveFunctionUse = true;
}
}

View File

@ -188,8 +188,6 @@ declare module 'vscode' {
* The `data` for any confirmations that were rejected
*/
rejectedConfirmationData?: any[];
requestedTools?: string[];
}
// TODO@API fit this into the stream
@ -197,31 +195,6 @@ declare module 'vscode' {
documents: ChatDocumentContext[];
}
export interface ChatParticipant {
/**
* Provide a set of variables that can only be used with this participant.
*/
participantVariableProvider?: { provider: ChatParticipantCompletionItemProvider; triggerCharacters: string[] };
}
export interface ChatParticipantCompletionItemProvider {
provideCompletionItems(query: string, token: CancellationToken): ProviderResult<ChatCompletionItem[]>;
}
export class ChatCompletionItem {
id: string;
label: string | CompletionItemLabel;
values: ChatVariableValue[];
fullName?: string;
icon?: ThemeIcon;
insertText?: string;
detail?: string;
documentation?: string | MarkdownString;
command?: Command;
constructor(id: string, label: string | CompletionItemLabel, values: ChatVariableValue[]);
}
export type ChatExtendedRequestHandler = (request: ChatRequest, context: ChatContext, response: ChatResponseStream, token: CancellationToken) => ProviderResult<ChatResult | void>;
export interface ChatResult {
@ -245,14 +218,12 @@ declare module 'vscode' {
* The chat extension should not activate if it doesn't support the current version.
*/
export const _version: 1 | number;
export function registerChatParticipantDetectionProvider(participantDetectionProvider: ChatParticipantDetectionProvider): Disposable;
}
export interface ChatParticipantMetadata {
participant: string;
command?: string;
description?: string;
disambiguation: { categoryName: string; description: string; examples: string[] }[];
}
export interface ChatParticipantDetectionResult {
@ -260,10 +231,6 @@ declare module 'vscode' {
command?: string;
}
export interface ChatParticipantDetectionProvider {
provideParticipantDetection(chatRequest: ChatRequest, context: ChatContext, options: { participants?: ChatParticipantMetadata[]; location: ChatLocation }, token: CancellationToken): ProviderResult<ChatParticipantDetectionResult>;
}
/*
* User action events
*/

View File

@ -3,15 +3,13 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
// version: 3
// version: 4
// https://github.com/microsoft/vscode/issues/213274
declare module 'vscode' {
// TODO@API capabilities
export type JSONSchema = object;
// API -> LM: an tool/function that is available to the language model
export interface LanguageModelChatFunction {
name: string;
@ -91,19 +89,73 @@ declare module 'vscode' {
/**
* Invoke a tool with the given parameters.
* TODO Could request a set of contentTypes to be returned so they don't all need to be computed?
* TODO@API Could request a set of contentTypes to be returned so they don't all need to be computed?
*/
export function invokeTool(name: string, parameters: Object, token: CancellationToken): Thenable<LanguageModelToolResult>;
export function invokeTool(id: string, parameters: Object, token: CancellationToken): Thenable<LanguageModelToolResult>;
}
// Is the same as LanguageModelChatFunction now, but could have more details in the future
export type JSONSchema = object;
export interface LanguageModelToolDescription {
name: string;
description: string;
/**
* A unique identifier for the tool.
*/
id: string;
/**
* A human-readable name for this tool that may be used to describe it in the UI.
*/
displayName: string | undefined;
/**
* A description of this tool that may be passed to a language model.
*/
modelDescription: string;
/**
* A JSON schema for the parameters this tool accepts.
*/
parametersSchema?: JSONSchema;
}
export interface LanguageModelTool {
// TODO@API should it be LanguageModelToolResult | string?
invoke(parameters: any, token: CancellationToken): Thenable<LanguageModelToolResult>;
}
export interface ChatLanguageModelToolReference {
/**
* The tool's ID. Refers to a tool listed in {@link lm.tools}.
*/
readonly id: string;
/**
* 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];
}
export interface ChatRequest {
/**
* The list of tools that the user attached to their request.
*
* *Note* that if tools are referenced in the text of the prompt, using `#`, 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 toolReferences: readonly ChatLanguageModelToolReference[];
}
export interface ChatRequestTurn {
/**
* The list of tools were attached to this request.
*/
readonly toolReferences?: readonly ChatLanguageModelToolReference[];
}
}