mirror of
https://github.com/microsoft/vscode-extension-samples.git
synced 2026-06-13 07:10:26 +08:00
161 lines
4.7 KiB
TypeScript
161 lines
4.7 KiB
TypeScript
import * as vscode from 'vscode';
|
|
|
|
export function registerChatTools(context: vscode.ExtensionContext) {
|
|
context.subscriptions.push(vscode.lm.registerTool('chat-tools-sample_tabCount', new TabCountTool()));
|
|
context.subscriptions.push(vscode.lm.registerTool('chat-tools-sample_findFiles', new FindFilesTool()));
|
|
context.subscriptions.push(vscode.lm.registerTool('chat-tools-sample_runInTerminal', new RunInTerminalTool()));
|
|
}
|
|
|
|
interface ITabCountParameters {
|
|
tabGroup?: number;
|
|
}
|
|
|
|
export class TabCountTool implements vscode.LanguageModelTool<ITabCountParameters> {
|
|
async invoke(
|
|
options: vscode.LanguageModelToolInvocationOptions<ITabCountParameters>,
|
|
_token: vscode.CancellationToken
|
|
) {
|
|
const params = options.input;
|
|
if (typeof params.tabGroup === 'number') {
|
|
const group = vscode.window.tabGroups.all[Math.max(params.tabGroup - 1, 0)];
|
|
const nth =
|
|
params.tabGroup === 1
|
|
? '1st'
|
|
: params.tabGroup === 2
|
|
? '2nd'
|
|
: params.tabGroup === 3
|
|
? '3rd'
|
|
: `${params.tabGroup}th`;
|
|
return new vscode.LanguageModelToolResult([new vscode.LanguageModelTextPart(`There are ${group.tabs.length} tabs open in the ${nth} tab group.`)]);
|
|
} else {
|
|
const group = vscode.window.tabGroups.activeTabGroup;
|
|
return new vscode.LanguageModelToolResult([new vscode.LanguageModelTextPart(`There are ${group.tabs.length} tabs open.`)]);
|
|
}
|
|
}
|
|
|
|
async prepareInvocation(
|
|
options: vscode.LanguageModelToolInvocationPrepareOptions<ITabCountParameters>,
|
|
_token: vscode.CancellationToken
|
|
) {
|
|
const confirmationMessages = {
|
|
title: 'Count the number of open tabs',
|
|
message: new vscode.MarkdownString(
|
|
`Count the number of open tabs?` +
|
|
(options.input.tabGroup !== undefined
|
|
? ` in tab group ${options.input.tabGroup}`
|
|
: '')
|
|
),
|
|
};
|
|
|
|
return {
|
|
invocationMessage: 'Counting the number of tabs',
|
|
confirmationMessages,
|
|
};
|
|
}
|
|
}
|
|
|
|
interface IFindFilesParameters {
|
|
pattern: string;
|
|
}
|
|
|
|
export class FindFilesTool implements vscode.LanguageModelTool<IFindFilesParameters> {
|
|
async invoke(
|
|
options: vscode.LanguageModelToolInvocationOptions<IFindFilesParameters>,
|
|
token: vscode.CancellationToken
|
|
) {
|
|
const params = options.input as IFindFilesParameters;
|
|
const files = await vscode.workspace.findFiles(
|
|
params.pattern,
|
|
'**/node_modules/**',
|
|
undefined,
|
|
token
|
|
);
|
|
|
|
const strFiles = files.map((f) => f.fsPath).join('\n');
|
|
return new vscode.LanguageModelToolResult([new vscode.LanguageModelTextPart(`Found ${files.length} files matching "${params.pattern}":\n${strFiles}`)]);
|
|
}
|
|
|
|
async prepareInvocation(
|
|
options: vscode.LanguageModelToolInvocationPrepareOptions<IFindFilesParameters>,
|
|
_token: vscode.CancellationToken
|
|
) {
|
|
return {
|
|
invocationMessage: `Searching workspace for "${options.input.pattern}"`,
|
|
};
|
|
}
|
|
}
|
|
|
|
interface IRunInTerminalParameters {
|
|
command: string;
|
|
}
|
|
|
|
async function waitForShellIntegration(
|
|
terminal: vscode.Terminal,
|
|
timeout: number
|
|
): Promise<void> {
|
|
let resolve: () => void;
|
|
let reject: (e: Error) => void;
|
|
const p = new Promise<void>((_resolve, _reject) => {
|
|
resolve = _resolve;
|
|
reject = _reject;
|
|
});
|
|
|
|
const timer = setTimeout(() => reject(new Error('Could not run terminal command: shell integration is not enabled')), timeout);
|
|
|
|
const listener = vscode.window.onDidChangeTerminalShellIntegration((e) => {
|
|
if (e.terminal === terminal) {
|
|
clearTimeout(timer);
|
|
listener.dispose();
|
|
resolve();
|
|
}
|
|
});
|
|
|
|
await p;
|
|
}
|
|
|
|
export class RunInTerminalTool
|
|
implements vscode.LanguageModelTool<IRunInTerminalParameters> {
|
|
async invoke(
|
|
options: vscode.LanguageModelToolInvocationOptions<IRunInTerminalParameters>,
|
|
_token: vscode.CancellationToken
|
|
) {
|
|
const params = options.input as IRunInTerminalParameters;
|
|
|
|
const terminal = vscode.window.createTerminal('Language Model Tool User');
|
|
terminal.show();
|
|
try {
|
|
await waitForShellIntegration(terminal, 5000);
|
|
} catch (e) {
|
|
return new vscode.LanguageModelToolResult([new vscode.LanguageModelTextPart((e as Error).message)]);
|
|
}
|
|
|
|
const execution = terminal.shellIntegration!.executeCommand(params.command);
|
|
const terminalStream = execution.read();
|
|
|
|
let terminalResult = '';
|
|
for await (const chunk of terminalStream) {
|
|
terminalResult += chunk;
|
|
}
|
|
|
|
return new vscode.LanguageModelToolResult([new vscode.LanguageModelTextPart(terminalResult)]);
|
|
}
|
|
|
|
async prepareInvocation(
|
|
options: vscode.LanguageModelToolInvocationPrepareOptions<IRunInTerminalParameters>,
|
|
_token: vscode.CancellationToken
|
|
) {
|
|
const confirmationMessages = {
|
|
title: 'Run command in terminal',
|
|
message: new vscode.MarkdownString(
|
|
`Run this command in a terminal?` +
|
|
`\n\n\`\`\`\n${options.input.command}\n\`\`\`\n`
|
|
),
|
|
};
|
|
|
|
return {
|
|
invocationMessage: `Running command in terminal`,
|
|
confirmationMessages,
|
|
};
|
|
}
|
|
}
|