mirror of
https://github.com/Microsoft/vscode
synced 2024-10-01 08:50:48 +00:00
Tools API tweaks, merge into lmTools (#216750)
* Tools API tweaks, merge into lmTools * Rename more id -> name * Fix * Add lmTools API version
This commit is contained in:
parent
5f330d3864
commit
ee173b0e65
|
@ -53,7 +53,8 @@
|
|||
"treeViewActiveItem",
|
||||
"treeViewReveal",
|
||||
"workspaceTrust",
|
||||
"telemetry"
|
||||
"telemetry",
|
||||
"lmTools"
|
||||
],
|
||||
"private": true,
|
||||
"activationEvents": [],
|
||||
|
|
|
@ -42,9 +42,6 @@ const _allApiProposals = {
|
|||
chatTab: {
|
||||
proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.chatTab.d.ts',
|
||||
},
|
||||
chatTools: {
|
||||
proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.chatTools.d.ts',
|
||||
},
|
||||
chatVariableResolver: {
|
||||
proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.chatVariableResolver.d.ts',
|
||||
},
|
||||
|
@ -227,6 +224,7 @@ const _allApiProposals = {
|
|||
},
|
||||
lmTools: {
|
||||
proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.lmTools.d.ts',
|
||||
version: 2
|
||||
},
|
||||
mappedEditsProvider: {
|
||||
proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.mappedEditsProvider.d.ts',
|
||||
|
|
|
@ -33,18 +33,18 @@ export class MainThreadLanguageModelTools extends Disposable implements MainThre
|
|||
return this._languageModelToolsService.invokeTool(name, parameters, token);
|
||||
}
|
||||
|
||||
$registerTool(id: string): void {
|
||||
$registerTool(name: string): void {
|
||||
const disposable = this._languageModelToolsService.registerToolImplementation(
|
||||
id,
|
||||
name,
|
||||
{
|
||||
invoke: async (parameters, token) => {
|
||||
return await this._proxy.$invokeTool(id, parameters, token);
|
||||
return await this._proxy.$invokeTool(name, parameters, token);
|
||||
},
|
||||
});
|
||||
this._tools.set(id, disposable);
|
||||
this._tools.set(name, disposable);
|
||||
}
|
||||
|
||||
$unregisterTool(id: string): void {
|
||||
this._tools.deleteAndDispose(id);
|
||||
$unregisterTool(name: string): void {
|
||||
this._tools.deleteAndDispose(name);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1483,15 +1483,15 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
|
|||
}
|
||||
},
|
||||
registerTool(toolId: string, tool: vscode.LanguageModelTool) {
|
||||
checkProposedApiEnabled(extension, 'chatVariableResolver');
|
||||
checkProposedApiEnabled(extension, 'lmTools');
|
||||
return extHostLanguageModelTools.registerTool(extension, toolId, tool);
|
||||
},
|
||||
invokeTool(toolId: string, parameters: Object, token: vscode.CancellationToken) {
|
||||
checkProposedApiEnabled(extension, 'chatVariableResolver');
|
||||
checkProposedApiEnabled(extension, 'lmTools');
|
||||
return extHostLanguageModelTools.invokeTool(toolId, parameters, token);
|
||||
},
|
||||
get tools() {
|
||||
checkProposedApiEnabled(extension, 'chatVariableResolver');
|
||||
checkProposedApiEnabled(extension, 'lmTools');
|
||||
return extHostLanguageModelTools.tools;
|
||||
},
|
||||
};
|
||||
|
|
|
@ -22,7 +22,7 @@ import { CommandsConverter, ExtHostCommands } from 'vs/workbench/api/common/extH
|
|||
import * as typeConvert from 'vs/workbench/api/common/extHostTypeConverters';
|
||||
import * as extHostTypes from 'vs/workbench/api/common/extHostTypes';
|
||||
import { ChatAgentLocation, IChatAgentRequest, IChatAgentResult } from 'vs/workbench/contrib/chat/common/chatAgents';
|
||||
import { IChatContentReference, IChatFollowup, IChatUserActionEvent, ChatAgentVoteDirection, IChatResponseErrorDetails } from 'vs/workbench/contrib/chat/common/chatService';
|
||||
import { ChatAgentVoteDirection, IChatContentReference, IChatFollowup, IChatResponseErrorDetails, IChatUserActionEvent } from 'vs/workbench/contrib/chat/common/chatService';
|
||||
import { checkProposedApiEnabled, isProposedApiEnabled } from 'vs/workbench/services/extensions/common/extensions';
|
||||
import { Dto } from 'vs/workbench/services/extensions/common/proxyIdentifier';
|
||||
import type * as vscode from 'vscode';
|
||||
|
|
|
@ -7,6 +7,7 @@ import { CancellationToken } from 'vs/base/common/cancellation';
|
|||
import { IDisposable, toDisposable } from 'vs/base/common/lifecycle';
|
||||
import { IExtensionDescription } from 'vs/platform/extensions/common/extensions';
|
||||
import { ExtHostLanguageModelToolsShape, IMainContext, MainContext, MainThreadLanguageModelToolsShape } from 'vs/workbench/api/common/extHost.protocol';
|
||||
import * as typeConvert from 'vs/workbench/api/common/extHostTypeConverters';
|
||||
import { IToolData, IToolDelta } from 'vs/workbench/contrib/chat/common/languageModelToolsService';
|
||||
import type * as vscode from 'vscode';
|
||||
|
||||
|
@ -23,7 +24,7 @@ export class ExtHostLanguageModelTools implements ExtHostLanguageModelToolsShape
|
|||
|
||||
this._proxy.$getTools().then(tools => {
|
||||
for (const tool of tools) {
|
||||
this._allTools.set(tool.id, tool);
|
||||
this._allTools.set(tool.name, tool);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -35,7 +36,7 @@ export class ExtHostLanguageModelTools implements ExtHostLanguageModelToolsShape
|
|||
|
||||
async $acceptToolDelta(delta: IToolDelta): Promise<void> {
|
||||
if (delta.added) {
|
||||
this._allTools.set(delta.added.id, delta.added);
|
||||
this._allTools.set(delta.added.name, delta.added);
|
||||
}
|
||||
|
||||
if (delta.removed) {
|
||||
|
@ -44,25 +45,26 @@ export class ExtHostLanguageModelTools implements ExtHostLanguageModelToolsShape
|
|||
}
|
||||
|
||||
get tools(): vscode.LanguageModelToolDescription[] {
|
||||
return Array.from(this._allTools.values());
|
||||
return Array.from(this._allTools.values())
|
||||
.map(tool => typeConvert.LanguageModelToolDescription.to(tool));
|
||||
}
|
||||
|
||||
async $invokeTool(id: string, parameters: any, token: CancellationToken): Promise<string> {
|
||||
const item = this._registeredTools.get(id);
|
||||
async $invokeTool(name: string, parameters: any, token: CancellationToken): Promise<string> {
|
||||
const item = this._registeredTools.get(name);
|
||||
if (!item) {
|
||||
throw new Error(`Unknown tool ${id}`);
|
||||
throw new Error(`Unknown tool ${name}`);
|
||||
}
|
||||
|
||||
return await item.tool.invoke(parameters, token);
|
||||
}
|
||||
|
||||
registerTool(extension: IExtensionDescription, id: string, tool: vscode.LanguageModelTool): IDisposable {
|
||||
this._registeredTools.set(id, { extension, tool });
|
||||
this._proxy.$registerTool(id);
|
||||
registerTool(extension: IExtensionDescription, name: string, tool: vscode.LanguageModelTool): IDisposable {
|
||||
this._registeredTools.set(name, { extension, tool });
|
||||
this._proxy.$registerTool(name);
|
||||
|
||||
return toDisposable(() => {
|
||||
this._registeredTools.delete(id);
|
||||
this._proxy.$unregisterTool(id);
|
||||
this._registeredTools.delete(name);
|
||||
this._proxy.$unregisterTool(name);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -53,6 +53,7 @@ import { ACTIVE_GROUP, SIDE_GROUP } from 'vs/workbench/services/editor/common/ed
|
|||
import { Dto } from 'vs/workbench/services/extensions/common/proxyIdentifier';
|
||||
import type * as vscode from 'vscode';
|
||||
import * as types from './extHostTypes';
|
||||
import { IToolData } from 'vs/workbench/contrib/chat/common/languageModelToolsService';
|
||||
|
||||
export namespace Command {
|
||||
|
||||
|
@ -2743,3 +2744,13 @@ export namespace DebugTreeItem {
|
|||
};
|
||||
}
|
||||
}
|
||||
|
||||
export namespace LanguageModelToolDescription {
|
||||
export function to(item: IToolData): vscode.LanguageModelToolDescription {
|
||||
return {
|
||||
name: item.name,
|
||||
description: item.description,
|
||||
parametersSchema: item.parametersSchema,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,7 +11,7 @@ import { Iterable } from 'vs/base/common/iterator';
|
|||
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
|
||||
|
||||
export interface IToolData {
|
||||
id: string;
|
||||
name: string;
|
||||
displayName?: string;
|
||||
description: string;
|
||||
parametersSchema?: Object;
|
||||
|
@ -37,7 +37,7 @@ export interface ILanguageModelToolsService {
|
|||
_serviceBrand: undefined;
|
||||
onDidChangeTools: Event<IToolDelta>;
|
||||
registerToolData(toolData: IToolData): IDisposable;
|
||||
registerToolImplementation(id: string, tool: IToolImpl): IDisposable;
|
||||
registerToolImplementation(name: string, tool: IToolImpl): IDisposable;
|
||||
getTools(): Iterable<Readonly<IToolData>>;
|
||||
invokeTool(name: string, parameters: any, token: CancellationToken): Promise<string>;
|
||||
}
|
||||
|
@ -55,28 +55,28 @@ export class LanguageModelToolsService implements ILanguageModelToolsService {
|
|||
) { }
|
||||
|
||||
registerToolData(toolData: IToolData): IDisposable {
|
||||
if (this._tools.has(toolData.id)) {
|
||||
throw new Error(`Tool "${toolData.id}" is already registered.`);
|
||||
if (this._tools.has(toolData.name)) {
|
||||
throw new Error(`Tool "${toolData.name}" is already registered.`);
|
||||
}
|
||||
|
||||
this._tools.set(toolData.id, { data: toolData });
|
||||
this._tools.set(toolData.name, { data: toolData });
|
||||
this._onDidChangeTools.fire({ added: toolData });
|
||||
|
||||
return toDisposable(() => {
|
||||
this._tools.delete(toolData.id);
|
||||
this._onDidChangeTools.fire({ removed: toolData.id });
|
||||
this._tools.delete(toolData.name);
|
||||
this._onDidChangeTools.fire({ removed: toolData.name });
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
registerToolImplementation(id: string, tool: IToolImpl): IDisposable {
|
||||
const entry = this._tools.get(id);
|
||||
registerToolImplementation(name: string, tool: IToolImpl): IDisposable {
|
||||
const entry = this._tools.get(name);
|
||||
if (!entry) {
|
||||
throw new Error(`Tool "${id}" was not contributed.`);
|
||||
throw new Error(`Tool "${name}" was not contributed.`);
|
||||
}
|
||||
|
||||
if (entry.impl) {
|
||||
throw new Error(`Tool "${id}" already has an implementation.`);
|
||||
throw new Error(`Tool "${name}" already has an implementation.`);
|
||||
}
|
||||
|
||||
entry.impl = tool;
|
||||
|
|
|
@ -8,12 +8,13 @@ import { IJSONSchema } from 'vs/base/common/jsonSchema';
|
|||
import { DisposableMap } from 'vs/base/common/lifecycle';
|
||||
import { localize } from 'vs/nls';
|
||||
import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions';
|
||||
import { ILogService } from 'vs/platform/log/common/log';
|
||||
import { IWorkbenchContribution } from 'vs/workbench/common/contributions';
|
||||
import { ILanguageModelToolsService } from 'vs/workbench/contrib/chat/common/languageModelToolsService';
|
||||
import * as extensionsRegistry from 'vs/workbench/services/extensions/common/extensionsRegistry';
|
||||
|
||||
interface IRawToolContribution {
|
||||
id: string;
|
||||
name: string;
|
||||
displayName?: string;
|
||||
description: string;
|
||||
parametersSchema?: IJSONSchema;
|
||||
|
@ -23,7 +24,7 @@ const languageModelToolsExtensionPoint = extensionsRegistry.ExtensionsRegistry.r
|
|||
extensionPoint: 'languageModelTools',
|
||||
activationEventsGenerator: (contributions: IRawToolContribution[], result) => {
|
||||
for (const contrib of contributions) {
|
||||
result.push(`onLanguageModelTool:${contrib.id}`);
|
||||
result.push(`onLanguageModelTool:${contrib.name}`);
|
||||
}
|
||||
},
|
||||
jsonSchema: {
|
||||
|
@ -32,11 +33,11 @@ const languageModelToolsExtensionPoint = extensionsRegistry.ExtensionsRegistry.r
|
|||
items: {
|
||||
additionalProperties: false,
|
||||
type: 'object',
|
||||
defaultSnippets: [{ body: { id: '', description: '' } }],
|
||||
required: ['id', 'description'],
|
||||
defaultSnippets: [{ body: { name: '', description: '' } }],
|
||||
required: ['name', 'description'],
|
||||
properties: {
|
||||
id: {
|
||||
description: localize('toolId', "A unique id for this tool."),
|
||||
name: {
|
||||
description: localize('toolname', "A name for this tool which must be unique across all tools."),
|
||||
type: 'string'
|
||||
},
|
||||
description: {
|
||||
|
@ -57,8 +58,8 @@ const languageModelToolsExtensionPoint = extensionsRegistry.ExtensionsRegistry.r
|
|||
}
|
||||
});
|
||||
|
||||
function toToolKey(extensionIdentifier: ExtensionIdentifier, toolId: string) {
|
||||
return `${extensionIdentifier.value}/${toolId}`;
|
||||
function toToolKey(extensionIdentifier: ExtensionIdentifier, toolName: string) {
|
||||
return `${extensionIdentifier.value}/${toolName}`;
|
||||
}
|
||||
|
||||
export class LanguageModelToolsExtensionPointHandler implements IWorkbenchContribution {
|
||||
|
@ -67,19 +68,25 @@ export class LanguageModelToolsExtensionPointHandler implements IWorkbenchContri
|
|||
private _registrationDisposables = new DisposableMap<string>();
|
||||
|
||||
constructor(
|
||||
@ILanguageModelToolsService languageModelToolsService: ILanguageModelToolsService
|
||||
@ILanguageModelToolsService languageModelToolsService: ILanguageModelToolsService,
|
||||
@ILogService logService: ILogService,
|
||||
) {
|
||||
languageModelToolsExtensionPoint.setHandler((extensions, delta) => {
|
||||
for (const extension of delta.added) {
|
||||
for (const tool of extension.value) {
|
||||
if (!tool.name || !tool.description) {
|
||||
logService.warn(`Invalid tool contribution from ${extension.description.identifier.value}: ${JSON.stringify(tool)}`);
|
||||
continue;
|
||||
}
|
||||
|
||||
const disposable = languageModelToolsService.registerToolData(tool);
|
||||
this._registrationDisposables.set(toToolKey(extension.description.identifier, tool.id), disposable);
|
||||
this._registrationDisposables.set(toToolKey(extension.description.identifier, tool.name), disposable);
|
||||
}
|
||||
}
|
||||
|
||||
for (const extension of delta.removed) {
|
||||
for (const tool of extension.value) {
|
||||
this._registrationDisposables.deleteAndDispose(toToolKey(extension.description.identifier, tool.id));
|
||||
this._registrationDisposables.deleteAndDispose(toToolKey(extension.description.identifier, tool.name));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
35
src/vscode-dts/vscode.proposed.chatTools.d.ts
vendored
35
src/vscode-dts/vscode.proposed.chatTools.d.ts
vendored
|
@ -1,35 +0,0 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
declare module 'vscode' {
|
||||
|
||||
export namespace lm {
|
||||
/**
|
||||
* Register a LanguageModelTool. The tool must also be registered in the package.json `languageModelTools` contribution point.
|
||||
*/
|
||||
export function registerTool(toolId: string, tool: LanguageModelTool): Disposable;
|
||||
|
||||
/**
|
||||
* A list of all available tools.
|
||||
*/
|
||||
export const tools: ReadonlyArray<LanguageModelToolDescription>;
|
||||
|
||||
/**
|
||||
* Invoke a tool with the given parameters.
|
||||
*/
|
||||
export function invokeTool(toolId: string, parameters: Object, token: CancellationToken): Thenable<string>;
|
||||
}
|
||||
|
||||
export interface LanguageModelToolDescription {
|
||||
id: string;
|
||||
description: string;
|
||||
parametersSchema?: JSONSchema;
|
||||
displayName?: string;
|
||||
}
|
||||
|
||||
export interface LanguageModelTool {
|
||||
invoke(parameters: any, token: CancellationToken): Thenable<string>;
|
||||
}
|
||||
}
|
34
src/vscode-dts/vscode.proposed.lmTools.d.ts
vendored
34
src/vscode-dts/vscode.proposed.lmTools.d.ts
vendored
|
@ -3,6 +3,8 @@
|
|||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
// version: 2
|
||||
|
||||
declare module 'vscode' {
|
||||
|
||||
// TODO@API capabilities
|
||||
|
@ -13,7 +15,7 @@ declare module 'vscode' {
|
|||
export interface LanguageModelChatFunction {
|
||||
name: string;
|
||||
description: string;
|
||||
parametersSchema: JSONSchema;
|
||||
parametersSchema?: JSONSchema;
|
||||
}
|
||||
|
||||
// API -> LM: add tools as request option
|
||||
|
@ -55,4 +57,34 @@ declare module 'vscode' {
|
|||
export interface LanguageModelChatMessage {
|
||||
content2: string | LanguageModelChatMessageFunctionResultPart;
|
||||
}
|
||||
|
||||
// Tool registration/invoking between extensions
|
||||
|
||||
export namespace lm {
|
||||
/**
|
||||
* Register a LanguageModelTool. The tool must also be registered in the package.json `languageModelTools` contribution point.
|
||||
*/
|
||||
export function registerTool(name: string, tool: LanguageModelTool): Disposable;
|
||||
|
||||
/**
|
||||
* A list of all available tools.
|
||||
*/
|
||||
export const tools: ReadonlyArray<LanguageModelToolDescription>;
|
||||
|
||||
/**
|
||||
* Invoke a tool with the given parameters.
|
||||
*/
|
||||
export function invokeTool(name: string, parameters: Object, token: CancellationToken): Thenable<string>;
|
||||
}
|
||||
|
||||
// Is the same as LanguageModelChatFunction now, but could have more details in the future
|
||||
export interface LanguageModelToolDescription {
|
||||
name: string;
|
||||
description: string;
|
||||
parametersSchema?: JSONSchema;
|
||||
}
|
||||
|
||||
export interface LanguageModelTool {
|
||||
invoke(parameters: any, token: CancellationToken): Thenable<string>;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue