diff --git a/src/vs/workbench/api/browser/mainThreadLanguageModelTools.ts b/src/vs/workbench/api/browser/mainThreadLanguageModelTools.ts index 4e238f18fc0..d203c83c7e9 100644 --- a/src/vs/workbench/api/browser/mainThreadLanguageModelTools.ts +++ b/src/vs/workbench/api/browser/mainThreadLanguageModelTools.ts @@ -101,4 +101,8 @@ export class MainThreadLanguageModelTools extends Disposable implements MainThre $unregisterTool(name: string): void { this._tools.deleteAndDispose(name); } + + $supportsModel(toolId: string, modelId: string, token: CancellationToken): Promise { + return this._languageModelToolsService.supportsModel(toolId, modelId, token); + } } diff --git a/src/vs/workbench/api/common/extHost.api.impl.ts b/src/vs/workbench/api/common/extHost.api.impl.ts index a976c20189f..fe44360a8c2 100644 --- a/src/vs/workbench/api/common/extHost.api.impl.ts +++ b/src/vs/workbench/api/common/extHost.api.impl.ts @@ -1594,8 +1594,11 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I registerTool(name: string, tool: vscode.LanguageModelTool) { return extHostLanguageModelTools.registerTool(extension, name, tool); }, - invokeTool(name: string, parameters: vscode.LanguageModelToolInvocationOptions, token?: vscode.CancellationToken) { - return extHostLanguageModelTools.invokeTool(extension, name, parameters, token); + invokeTool(nameOrInfo: string | vscode.LanguageModelToolInformation, parameters: vscode.LanguageModelToolInvocationOptions, token?: vscode.CancellationToken) { + if (typeof nameOrInfo !== 'string') { + checkProposedApiEnabled(extension, 'chatParticipantAdditions'); + } + return extHostLanguageModelTools.invokeTool(extension, nameOrInfo, parameters, token); }, get tools() { return extHostLanguageModelTools.getTools(extension); diff --git a/src/vs/workbench/api/common/extHost.protocol.ts b/src/vs/workbench/api/common/extHost.protocol.ts index 7b4bf5c106d..41b78407b65 100644 --- a/src/vs/workbench/api/common/extHost.protocol.ts +++ b/src/vs/workbench/api/common/extHost.protocol.ts @@ -1463,6 +1463,7 @@ export interface MainThreadLanguageModelToolsShape extends IDisposable { $countTokensForInvocation(callId: string, input: string, token: CancellationToken): Promise; $registerTool(id: string): void; $unregisterTool(name: string): void; + $supportsModel(toolId: string, modelId: string, token: CancellationToken): Promise; } export type IChatRequestVariableValueDto = Dto; diff --git a/src/vs/workbench/api/common/extHostLanguageModelTools.ts b/src/vs/workbench/api/common/extHostLanguageModelTools.ts index 6faed42eb75..561ae1e9e6f 100644 --- a/src/vs/workbench/api/common/extHostLanguageModelTools.ts +++ b/src/vs/workbench/api/common/extHostLanguageModelTools.ts @@ -101,7 +101,8 @@ export class ExtHostLanguageModelTools implements ExtHostLanguageModelToolsShape return await fn(input, token); } - async invokeTool(extension: IExtensionDescription, toolId: string, options: vscode.LanguageModelToolInvocationOptions, token?: CancellationToken): Promise { + async invokeTool(extension: IExtensionDescription, toolIdOrInfo: string | vscode.LanguageModelToolInformation, options: vscode.LanguageModelToolInvocationOptions, token?: CancellationToken): Promise { + const toolId = typeof toolIdOrInfo === 'string' ? toolIdOrInfo : toolIdOrInfo.name; const callId = generateUuid(); if (options.tokenizationOptions) { this._tokenCountFuncs.set(callId, options.tokenizationOptions.countTokens); @@ -176,21 +177,7 @@ export class ExtHostLanguageModelTools implements ExtHostLanguageModelToolsShape * @returns `true` if supported, `false` if not, `undefined` if no supportsModel implementation (treat as supported) */ async supportsModel(toolId: string, modelId: string, token: CancellationToken): Promise { - const item = this._registeredTools.get(toolId); - if (!item) { - // Tool is not registered in this extension host, assume it supports all models - return undefined; - } - - // supportsModel is a proposed API - const supportsModelFn = item.tool.supportsModel; - if (supportsModelFn) { - const result = await supportsModelFn(modelId); - return result ?? undefined; - } - - // No supportsModel method means tool supports all models - return undefined; + return this._proxy.$supportsModel(toolId, modelId, token); } async $invokeTool(dto: Dto, token: CancellationToken): Promise | SerializableObjectWithBuffers>> { @@ -309,8 +296,7 @@ export class ExtHostLanguageModelTools implements ExtHostLanguageModelToolsShape // supportsModel is a proposed API const supportsModelFn = item.tool.supportsModel; if (supportsModelFn) { - const result = await supportsModelFn(modelId); - return result ?? undefined; + return supportsModelFn(modelId); } return undefined; diff --git a/src/vscode-dts/vscode.proposed.chatParticipantAdditions.d.ts b/src/vscode-dts/vscode.proposed.chatParticipantAdditions.d.ts index fb9bc8a83c5..038c60655e8 100644 --- a/src/vscode-dts/vscode.proposed.chatParticipantAdditions.d.ts +++ b/src/vscode-dts/vscode.proposed.chatParticipantAdditions.d.ts @@ -410,6 +410,18 @@ declare module 'vscode' { * Fired when the set of tools on a chat request changes. */ export const onDidChangeChatRequestTools: Event; + + /** + * Invoke a tool by its full information object rather than just name. + * This allows disambiguation when multiple tools have the same name + * (e.g., from different MCP servers or model-specific implementations). + * + * @param tool The tool information object, typically obtained from {@link lm.tools}. + * @param options The options to use when invoking the tool. + * @param token A cancellation token. + * @returns The result of the tool invocation. + */ + export function invokeTool(tool: LanguageModelToolInformation, options: LanguageModelToolInvocationOptions, token?: CancellationToken): Thenable; } export class LanguageModelToolExtensionSource {