Path: blob/main/src/vs/workbench/api/browser/mainThreadLanguageModelTools.ts
3296 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 { CancellationToken } from '../../../base/common/cancellation.js';6import { Disposable, DisposableMap } from '../../../base/common/lifecycle.js';7import { revive } from '../../../base/common/marshalling.js';8import { CountTokensCallback, ILanguageModelToolsService, IToolInvocation, IToolProgressStep, IToolResult, ToolProgress, toolResultHasBuffers } from '../../contrib/chat/common/languageModelToolsService.js';9import { IExtHostContext, extHostNamedCustomer } from '../../services/extensions/common/extHostCustomers.js';10import { Dto, SerializableObjectWithBuffers } from '../../services/extensions/common/proxyIdentifier.js';11import { ExtHostContext, ExtHostLanguageModelToolsShape, IToolDataDto, MainContext, MainThreadLanguageModelToolsShape } from '../common/extHost.protocol.js';1213@extHostNamedCustomer(MainContext.MainThreadLanguageModelTools)14export class MainThreadLanguageModelTools extends Disposable implements MainThreadLanguageModelToolsShape {1516private readonly _proxy: ExtHostLanguageModelToolsShape;17private readonly _tools = this._register(new DisposableMap<string>());18private readonly _runningToolCalls = new Map</* call ID */string, {19countTokens: CountTokensCallback;20progress: ToolProgress;21}>();2223constructor(24extHostContext: IExtHostContext,25@ILanguageModelToolsService private readonly _languageModelToolsService: ILanguageModelToolsService,26) {27super();28this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostLanguageModelTools);2930this._register(this._languageModelToolsService.onDidChangeTools(e => this._proxy.$onDidChangeTools(this.getToolDtos())));31}3233private getToolDtos(): IToolDataDto[] {34return Array.from(this._languageModelToolsService.getTools())35.map(tool => ({36id: tool.id,37displayName: tool.displayName,38toolReferenceName: tool.toolReferenceName,39tags: tool.tags,40userDescription: tool.userDescription,41modelDescription: tool.modelDescription,42inputSchema: tool.inputSchema,43source: tool.source,44} satisfies IToolDataDto));45}4647async $getTools(): Promise<IToolDataDto[]> {48return this.getToolDtos();49}5051async $invokeTool(dto: IToolInvocation, token?: CancellationToken): Promise<Dto<IToolResult> | SerializableObjectWithBuffers<Dto<IToolResult>>> {52const result = await this._languageModelToolsService.invokeTool(53dto,54(input, token) => this._proxy.$countTokensForInvocation(dto.callId, input, token),55token ?? CancellationToken.None,56);5758// Don't return extra metadata to EH59const out: Dto<IToolResult> = { content: result.content };60return toolResultHasBuffers(result) ? new SerializableObjectWithBuffers(out) : out;61}6263$acceptToolProgress(callId: string, progress: IToolProgressStep): void {64this._runningToolCalls.get(callId)?.progress.report(progress);65}6667$countTokensForInvocation(callId: string, input: string, token: CancellationToken): Promise<number> {68const fn = this._runningToolCalls.get(callId);69if (!fn) {70throw new Error(`Tool invocation call ${callId} not found`);71}7273return fn.countTokens(input, token);74}7576$registerTool(id: string): void {77const disposable = this._languageModelToolsService.registerToolImplementation(78id,79{80invoke: async (dto, countTokens, progress, token) => {81try {82this._runningToolCalls.set(dto.callId, { countTokens, progress });83const resultSerialized = await this._proxy.$invokeTool(dto, token);84const resultDto: Dto<IToolResult> = resultSerialized instanceof SerializableObjectWithBuffers ? resultSerialized.value : resultSerialized;85return revive<IToolResult>(resultDto);86} finally {87this._runningToolCalls.delete(dto.callId);88}89},90prepareToolInvocation: (context, token) => this._proxy.$prepareToolInvocation(id, context, token),91});92this._tools.set(id, disposable);93}9495$unregisterTool(name: string): void {96this._tools.deleteAndDispose(name);97}98}99100101