Files
vscode-extension-samples/chat-sample/src/extension.ts
2024-06-19 18:44:06 -07:00

88 lines
3.6 KiB
TypeScript

import * as vscode from 'vscode';
const PARTICIPANT_ID = 'chat-sample.tools';
export function activate(context: vscode.ExtensionContext) {
const handler: vscode.ChatRequestHandler = async (request: vscode.ChatRequest, chatContext: vscode.ChatContext, stream: vscode.ChatResponseStream, token: vscode.CancellationToken) => {
const models = await vscode.lm.selectChatModels({
vendor: 'copilot',
family: 'gpt-4-turbo'
});
const chat = models[0];
if (!chat) {
console.log('NO MODELS')
return {};
}
stream.markdown(`Available tools: ${vscode.lm.tools.map(tool => tool.id).join(', ')}\n\n`);
const options: vscode.LanguageModelChatRequestOptions = {
tools: vscode.lm.tools.map((tool): vscode.LanguageModelChatFunction => {
return {
name: tool.id.replace(/\./g, '_'),
description: tool.description,
parametersSchema: tool.parametersSchema ?? {}
}
}),
justification: 'Just because!',
}
const messages = [
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 runWithFunctions = async () => {
let didReceiveFunctionUse = false;
const response = await chat.sendRequest(messages, options, token);
for await (const part of response.stream) {
if (part instanceof vscode.LanguageModelChatResponseTextPart) {
stream.markdown(part.value)
} else if (part instanceof vscode.LanguageModelChatResponseFunctionUsePart) {
const tool = vscode.lm.tools.find(tool => tool.id.replace(/\./g, '_') === part.name);
if (!tool) {
// BAD tool choice?
continue;
}
const resultPromise = vscode.lm.invokeTool(tool.id, JSON.parse(part.parameters), token);
stream.progress(`FUNCTION_CALL: ${tool.id} with \`${part.parameters}\``, async (progress) => {
await resultPromise;
});
const result = await resultPromise;
// 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.id, result)
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.id}. The user cannot see this result, so you should explain it to the user if referencing it in your answer.`))
didReceiveFunctionUse = true;
}
}
if (didReceiveFunctionUse) {
// RE-enter
return runWithFunctions();
}
};
await runWithFunctions()
};
const toolUser = vscode.chat.createChatParticipant(PARTICIPANT_ID, handler);
toolUser.iconPath = new vscode.ThemeIcon('tools');
}
export function deactivate() { }