Path: blob/main/extensions/copilot/test/base/extHostContext/simulationExtHostToolsService.ts
13394 views
/*---------------------------------------------------------------------------------------------1* Copyright (c) Microsoft Corporation. All rights reserved.2* Licensed under the MIT License. See License.txt in the project root for license information.3*--------------------------------------------------------------------------------------------*/45import type { CancellationToken, ChatRequest, LanguageModelTool, LanguageModelToolInformation, LanguageModelToolInvocationOptions, LanguageModelToolResult } from 'vscode';6import { getToolName, ToolName } from '../../../src/extension/tools/common/toolNames';7import { ICopilotTool } from '../../../src/extension/tools/common/toolsRegistry';8import { BaseToolsService, IToolsService } from '../../../src/extension/tools/common/toolsService';9import { getPackagejsonToolsForTest } from '../../../src/extension/tools/node/test/testToolsService';10import { ToolsContribution } from '../../../src/extension/tools/vscode-node/tools';11import { ToolsService } from '../../../src/extension/tools/vscode-node/toolsService';12import { packageJson } from '../../../src/platform/env/common/packagejson';13import { ILogService } from '../../../src/platform/log/common/logService';14import { IChatEndpoint } from '../../../src/platform/networking/common/networking';15import { raceTimeout } from '../../../src/util/vs/base/common/async';16import { CancellationError } from '../../../src/util/vs/base/common/errors';17import { Iterable } from '../../../src/util/vs/base/common/iterator';18import { observableValue } from '../../../src/util/vs/base/common/observableInternal';19import { IInstantiationService } from '../../../src/util/vs/platform/instantiation/common/instantiation';20import { logger } from '../../simulationLogger';2122export class SimulationExtHostToolsService extends BaseToolsService implements IToolsService {23declare readonly _serviceBrand: undefined;2425private readonly _inner: IToolsService;26private readonly _overrides = new Map<ToolName | string, { info: LanguageModelToolInformation; tool: ICopilotTool<any> }>();27private _lmToolRegistration?: ToolsContribution;2829override get onWillInvokeTool() {30return this._inner.onWillInvokeTool;31}3233get tools() {34this.ensureToolsRegistered();35return [36...this._inner.tools.filter(t => !this._disabledTools.has(t.name) && !this._overrides.has(t.name)),37...Iterable.map(this._overrides.values(), i => i.info),38];39}4041get copilotTools() {42const r = new Map([43...this._inner.copilotTools,44...Iterable.map(this._overrides, ([k, v]): [ToolName, ICopilotTool<any>] => [k as ToolName, v.tool]),45]);46for (const name of this._disabledTools) {47r.delete(name as ToolName);48}49return r;50}5152constructor(53private readonly _disabledTools: Set<string>,54@ILogService logService: ILogService,55@IInstantiationService instantiationService: IInstantiationService,56) {57super(logService);58this._inner = instantiationService.createInstance(ToolsService);5960// register the contribution so that our tools are on vscode.lm.tools61setImmediate(() => this.ensureToolsRegistered());62}6364private ensureToolsRegistered() {65this._lmToolRegistration ??= new ToolsContribution(this, {} as any, { threshold: observableValue(this, 128) } as any, {} as any, {} as any, {} as any, {} as any);66}6768getCopilotTool(name: string): ICopilotTool<any> | undefined {69return this._disabledTools.has(name) ? undefined : (this._overrides.get(name)?.tool || this._inner.getCopilotTool(name));70}7172async invokeTool(name: string, options: LanguageModelToolInvocationOptions<unknown>, token: CancellationToken): Promise<LanguageModelToolResult> {73logger.debug('SimulationExtHostToolsService.invokeTool', name, JSON.stringify(options.input));74const start = Date.now();75let err: Error | undefined;76try {77const toolName = getToolName(name) as ToolName;78const tool = this._overrides.get(toolName)?.tool;79const invoke = tool?.invoke;80if (invoke) {81this._onWillInvokeTool.fire({ toolName });82const result = await invoke.call(tool, options, token);83if (!result) {84throw new CancellationError();85}8687return result;88}8990if (tool) {91throw new Error(`tool ${toolName} does not implement invoke`);92}9394const r = await raceTimeout(Promise.resolve(this._inner.invokeTool(name, options, token)), 60_000);95if (!r) {96throw new Error(`Tool call timed out after 60 seconds`);97}98return r;99} catch (e) {100err = e;101throw e;102} finally {103logger.debug(`SimulationExtHostToolsService.invokeTool ${name} done in ${Date.now() - start}ms` + (err ? ` with error: ${err.message}` : ''));104}105}106107getTool(name: string): LanguageModelToolInformation | undefined {108return this._disabledTools.has(name) ? undefined : (this._overrides.get(name)?.info || this._inner.getTool(name));109}110111getToolByToolReferenceName(toolReferenceName: string): LanguageModelToolInformation | undefined {112const contributedTool = packageJson.contributes.languageModelTools.find(tool => tool.toolReferenceName === toolReferenceName && tool.canBeReferencedInPrompt);113if (contributedTool) {114return {115name: contributedTool.name,116description: contributedTool.modelDescription,117inputSchema: contributedTool.inputSchema,118source: undefined,119tags: []120};121}122123return undefined;124}125126getEnabledTools(request: ChatRequest, endpoint: IChatEndpoint, filter?: (tool: LanguageModelToolInformation) => boolean | undefined): LanguageModelToolInformation[] {127const packageJsonTools = getPackagejsonToolsForTest();128return this.tools129.map(tool => {130// Apply model-specific alternative if available via alternativeDefinition131const owned = this.copilotTools.get(getToolName(tool.name) as ToolName);132if (owned?.alternativeDefinition) {133const alternative = owned.alternativeDefinition(tool, endpoint);134if (alternative) {135return alternative;136}137}138return tool;139})140.filter(tool => filter?.(tool) ?? (!this._disabledTools.has(getToolName(tool.name)) && packageJsonTools.has(tool.name)));141}142143addTestToolOverride(info: LanguageModelToolInformation, tool: LanguageModelTool<unknown>): void {144if (!this._disabledTools.has(info.name)) {145this._overrides.set(info.name as ToolName, { tool, info });146}147}148}149150151