mirror of
https://github.com/microsoft/vscode.git
synced 2026-05-28 19:27:05 +01:00
ba56721dfa
* tools: add support for model-specific tool registration This PR goes with https://github.com/microsoft/vscode/pull/287666 This allows the registration of tools that are scoped to specific language models. These tools can be registered at runtime with definitions derived from e.g. the server. I think we should adopt this and go away from the current `alternativeDefinitions` pattern which we have used previously. Example of having tools specific for GPT 4.1 vs 4o: ```ts ToolRegistry.registerModelSpecificTool( { name: 'gpt41_get_time', inputSchema: {}, description: 'Get the current date and time (4.1)', displayName: 'Get Time (GPT 4.1)', toolReferenceName: 'get_time', source: undefined, tags: [], models: [{ id: 'gpt-4.1' }], }, class implements ICopilotTool<unknown> { invoke() { return new vscode.LanguageModelToolResult([new vscode.LanguageModelTextPart('Current year is 2041 (GPT 4.1)')]); } } ); ToolRegistry.registerModelSpecificTool( { name: 'gpt4o_get_time', inputSchema: {}, description: 'Get the current date and time (4o)', displayName: 'Get Time (GPT 4o)', toolReferenceName: 'get_time', source: undefined, tags: [], models: [{ id: 'gpt-4o' }], }, class implements ICopilotTool<unknown> { invoke() { return new vscode.LanguageModelToolResult([new vscode.LanguageModelTextPart('Current year is 2040 (GPT 4o)')]); } } ); ``` * demo * fix * overrides * add overridesTool * fix inverted logic * test fixes and back compat * make memory tool model specific * fix tests and contribute memory to the vscode toolset * verison * fix unit tests * rm config * fix missing askquestions --------- Co-authored-by: bhavyaus <bhavyau@microsoft.com>
85 lines
3.5 KiB
TypeScript
85 lines
3.5 KiB
TypeScript
/*---------------------------------------------------------------------------------------------
|
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
* Licensed under the MIT License. See License.txt in the project root for license information.
|
|
*--------------------------------------------------------------------------------------------*/
|
|
|
|
import * as l10n from '@vscode/l10n';
|
|
import type * as vscode from 'vscode';
|
|
import { count } from '../../../util/vs/base/common/strings';
|
|
import { MarkdownString } from '../../../vscodeTypes';
|
|
import { ToolName } from '../common/toolNames';
|
|
import { ToolRegistry } from '../common/toolsRegistry';
|
|
import { formatUriForFileWidget } from '../common/toolUtils';
|
|
import { AbstractReplaceStringTool, IAbstractReplaceStringInput } from './abstractReplaceStringTool';
|
|
import { resolveToolInputPath } from './toolUtils';
|
|
|
|
export interface IReplaceStringToolParams {
|
|
explanation: string;
|
|
filePath: string;
|
|
oldString: string;
|
|
newString: string;
|
|
}
|
|
|
|
export class ReplaceStringTool<T extends IReplaceStringToolParams = IReplaceStringToolParams> extends AbstractReplaceStringTool<T> {
|
|
public static toolName = ToolName.ReplaceString;
|
|
|
|
protected extractReplaceInputs(input: T): IAbstractReplaceStringInput[] {
|
|
return [{
|
|
filePath: input.filePath,
|
|
oldString: input.oldString,
|
|
newString: input.newString,
|
|
}];
|
|
}
|
|
|
|
async handleToolStream(options: vscode.LanguageModelToolInvocationStreamOptions<IReplaceStringToolParams>, _token: vscode.CancellationToken): Promise<vscode.LanguageModelToolStreamResult> {
|
|
const partialInput = options.rawInput as Partial<IReplaceStringToolParams> | undefined;
|
|
|
|
let invocationMessage: MarkdownString;
|
|
if (partialInput && typeof partialInput === 'object') {
|
|
const oldString = partialInput.oldString;
|
|
const newString = partialInput.newString;
|
|
const filePath = partialInput.filePath;
|
|
|
|
const oldLineCount = oldString !== undefined ? count(oldString, '\n') + 1 : undefined;
|
|
const newLineCount = newString !== undefined ? count(newString, '\n') + 1 : undefined;
|
|
|
|
if (filePath) {
|
|
const uri = resolveToolInputPath(filePath, this.promptPathRepresentationService);
|
|
const fileRef = formatUriForFileWidget(uri);
|
|
|
|
if (oldLineCount !== undefined && newLineCount !== undefined) {
|
|
invocationMessage = new MarkdownString(l10n.t`Replacing ${oldLineCount} lines with ${newLineCount} lines in ${fileRef}`);
|
|
} else if (oldLineCount !== undefined) {
|
|
invocationMessage = new MarkdownString(l10n.t`Replacing ${oldLineCount} lines in ${fileRef}`);
|
|
} else {
|
|
invocationMessage = new MarkdownString(l10n.t`Editing ${fileRef}`);
|
|
}
|
|
} else {
|
|
if (oldLineCount !== undefined && newLineCount !== undefined) {
|
|
invocationMessage = new MarkdownString(l10n.t`Replacing ${oldLineCount} lines with ${newLineCount} lines`);
|
|
} else if (oldLineCount !== undefined) {
|
|
invocationMessage = new MarkdownString(l10n.t`Replacing ${oldLineCount} lines`);
|
|
} else {
|
|
invocationMessage = new MarkdownString(l10n.t`Editing file`);
|
|
}
|
|
}
|
|
} else {
|
|
invocationMessage = new MarkdownString(l10n.t`Editing file`);
|
|
}
|
|
|
|
return { invocationMessage };
|
|
}
|
|
|
|
|
|
async invoke(options: vscode.LanguageModelToolInvocationOptions<T>, token: vscode.CancellationToken) {
|
|
const prepared = await this.prepareEdits(options, token);
|
|
return this.applyAllEdits(options, prepared, token);
|
|
}
|
|
|
|
protected override toolName(): ToolName {
|
|
return ReplaceStringTool.toolName;
|
|
}
|
|
}
|
|
|
|
ToolRegistry.registerTool(ReplaceStringTool);
|