mirror of
https://github.com/microsoft/vscode-extension-samples.git
synced 2026-06-13 07:10:26 +08:00
129 lines
5.3 KiB
TypeScript
129 lines
5.3 KiB
TypeScript
import { contentType, renderElementJSON } from '@vscode/prompt-tsx';
|
|
import * as vscode from 'vscode';
|
|
import { CatToolPrompt } from './play';
|
|
|
|
export function activate(context: vscode.ExtensionContext) {
|
|
context.subscriptions.push(registerChatTool());
|
|
context.subscriptions.push(registerChatParticipant());
|
|
}
|
|
|
|
function registerChatTool() {
|
|
vscode.lm.registerTool('chat-sample_catVoice', {
|
|
async invoke(parameters, token) {
|
|
return {
|
|
[contentType]: await renderElementJSON(CatToolPrompt, {}, parameters.tokenOptions, token),
|
|
toString() {
|
|
return 'Reply in the voice of a cat! Use cat analogies when appropriate.';
|
|
},
|
|
};
|
|
},
|
|
});
|
|
|
|
return vscode.lm.registerTool('chat-sample_tabCount', {
|
|
async invoke(parameters, token) {
|
|
return {
|
|
toString() {
|
|
const activeTabCount = vscode.window.tabGroups.activeTabGroup.tabs.length;
|
|
return `There are ${activeTabCount} tabs open.`;
|
|
},
|
|
};
|
|
},
|
|
});
|
|
}
|
|
|
|
function registerChatParticipant() {
|
|
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-4o'
|
|
});
|
|
|
|
const model = models[0];
|
|
stream.markdown(`Available tools: ${vscode.lm.tools.map(tool => tool.id).join(', ')}\n\n`);
|
|
|
|
const allTools = vscode.lm.tools.map((tool): vscode.LanguageModelChatTool => {
|
|
return {
|
|
name: tool.id,
|
|
description: tool.modelDescription,
|
|
parametersSchema: tool.parametersSchema ?? {}
|
|
};
|
|
});
|
|
|
|
const options: vscode.LanguageModelChatRequestOptions = {
|
|
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 toolReferences = [...request.toolReferences];
|
|
const runWithFunctions = async () => {
|
|
const requestedTool = toolReferences.shift();
|
|
if (requestedTool) {
|
|
options.toolChoice = requestedTool.id;
|
|
options.tools = allTools.filter(tool => tool.name === requestedTool.id);
|
|
} else {
|
|
options.toolChoice = undefined;
|
|
options.tools = allTools;
|
|
}
|
|
|
|
let didReceiveFunctionUse = false;
|
|
|
|
const response = await model.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.LanguageModelChatResponseToolCallPart) {
|
|
const tool = vscode.lm.tools.find(tool => tool.id === part.name);
|
|
if (!tool) {
|
|
// BAD tool choice?
|
|
continue;
|
|
}
|
|
|
|
let parameters: any;
|
|
try {
|
|
parameters = JSON.parse(part.parameters);
|
|
} catch (err) {
|
|
throw new Error(`Got invalid tool use parameters: "${part.parameters}". (${(err as Error).message})`);
|
|
}
|
|
|
|
stream.progress(`Calling tool: ${tool.id} with ${part.parameters}`);
|
|
const result = await vscode.lm.invokeTool(tool.id, { parameters: JSON.parse(part.parameters) }, token);
|
|
|
|
let assistantMsg = vscode.LanguageModelChatMessage.Assistant('');
|
|
assistantMsg.content2 = [new vscode.LanguageModelChatResponseToolCallPart(tool.id, part.toolCallId, part.parameters)];
|
|
messages.push(assistantMsg);
|
|
|
|
// 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.LanguageModelChatMessageToolResultPart(part.toolCallId, 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.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('chat-sample.tools', handler);
|
|
toolUser.iconPath = new vscode.ThemeIcon('tools');
|
|
|
|
return toolUser;
|
|
}
|
|
|
|
|
|
export function deactivate() { }
|