mirror of
https://github.com/microsoft/vscode.git
synced 2026-02-15 07:28:05 +00:00
Merge pull request #231145 from microsoft/roblou/tools-api-updates
lmTools API updates
This commit is contained in:
@@ -244,7 +244,7 @@ const _allApiProposals = {
|
||||
},
|
||||
lmTools: {
|
||||
proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.lmTools.d.ts',
|
||||
version: 8
|
||||
version: 9
|
||||
},
|
||||
mappedEditsProvider: {
|
||||
proposal: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.mappedEditsProvider.d.ts',
|
||||
|
||||
@@ -59,7 +59,7 @@ export class MainThreadLanguageModelTools extends Disposable implements MainThre
|
||||
this._countTokenCallbacks.delete(dto.callId);
|
||||
}
|
||||
},
|
||||
prepareToolInvocation: (participantName, parameters, token) => this._proxy.$prepareToolInvocation(id, participantName, parameters, token),
|
||||
prepareToolInvocation: (parameters, token) => this._proxy.$prepareToolInvocation(id, parameters, token),
|
||||
});
|
||||
this._tools.set(id, disposable);
|
||||
}
|
||||
|
||||
@@ -1491,9 +1491,9 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
|
||||
return extHostEmbeddings.computeEmbeddings(embeddingsModel, input, token);
|
||||
}
|
||||
},
|
||||
registerTool<T>(toolId: string, tool: vscode.LanguageModelTool<T>) {
|
||||
registerTool<T>(name: string, tool: vscode.LanguageModelTool<T>) {
|
||||
checkProposedApiEnabled(extension, 'lmTools');
|
||||
return extHostLanguageModelTools.registerTool(extension, toolId, tool);
|
||||
return extHostLanguageModelTools.registerTool(extension, name, tool);
|
||||
},
|
||||
invokeTool<T>(toolId: string, parameters: vscode.LanguageModelToolInvocationOptions<T>, token: vscode.CancellationToken) {
|
||||
checkProposedApiEnabled(extension, 'lmTools');
|
||||
|
||||
@@ -1369,7 +1369,7 @@ export interface ExtHostLanguageModelToolsShape {
|
||||
$invokeTool(dto: IToolInvocation, token: CancellationToken): Promise<IToolResult>;
|
||||
$countTokensForInvocation(callId: string, input: string, token: CancellationToken): Promise<number>;
|
||||
|
||||
$prepareToolInvocation(toolId: string, participantName: string, parameters: any, token: CancellationToken): Promise<IPreparedToolInvocation | undefined>;
|
||||
$prepareToolInvocation(toolId: string, parameters: any, token: CancellationToken): Promise<IPreparedToolInvocation | undefined>;
|
||||
}
|
||||
|
||||
export interface MainThreadUrlsShape extends IDisposable {
|
||||
|
||||
@@ -121,7 +121,7 @@ export class ExtHostLanguageModelTools implements ExtHostLanguageModelToolsShape
|
||||
return extensionResult;
|
||||
}
|
||||
|
||||
async $prepareToolInvocation(toolId: string, participantName: string, parameters: any, token: CancellationToken): Promise<IPreparedToolInvocation | undefined> {
|
||||
async $prepareToolInvocation(toolId: string, parameters: any, token: CancellationToken): Promise<IPreparedToolInvocation | undefined> {
|
||||
const item = this._registeredTools.get(toolId);
|
||||
if (!item) {
|
||||
throw new Error(`Unknown tool ${toolId}`);
|
||||
@@ -131,7 +131,7 @@ export class ExtHostLanguageModelTools implements ExtHostLanguageModelToolsShape
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const result = await item.tool.prepareToolInvocation({ participantName, parameters }, token);
|
||||
const result = await item.tool.prepareToolInvocation({ parameters }, token);
|
||||
if (!result) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
@@ -2927,10 +2927,10 @@ export namespace DebugTreeItem {
|
||||
export namespace LanguageModelToolDescription {
|
||||
export function to(item: IToolData): vscode.LanguageModelToolDescription {
|
||||
return {
|
||||
id: item.id,
|
||||
// Note- the reason this is a unique 'name' is just to avoid confusion with the toolCallId
|
||||
name: item.id,
|
||||
description: item.modelDescription,
|
||||
parametersSchema: item.parametersSchema,
|
||||
displayName: item.displayName,
|
||||
supportedContentTypes: item.supportedContentTypes,
|
||||
tags: item.tags ?? [],
|
||||
};
|
||||
|
||||
@@ -482,23 +482,21 @@ export class AttachContextAction extends Action2 {
|
||||
}
|
||||
}
|
||||
|
||||
if (!usedAgent || usedAgent.agent.supportsToolReferences) {
|
||||
for (const tool of languageModelToolsService.getTools()) {
|
||||
if (tool.canBeInvokedManually) {
|
||||
const item: IToolQuickPickItem = {
|
||||
kind: 'tool',
|
||||
label: tool.displayName ?? tool.name ?? '',
|
||||
id: tool.id,
|
||||
icon: ThemeIcon.isThemeIcon(tool.icon) ? tool.icon : undefined // TODO need to support icon path?
|
||||
};
|
||||
if (ThemeIcon.isThemeIcon(tool.icon)) {
|
||||
item.iconClass = ThemeIcon.asClassName(tool.icon);
|
||||
} else if (tool.icon) {
|
||||
item.iconPath = tool.icon;
|
||||
}
|
||||
|
||||
quickPickItems.push(item);
|
||||
for (const tool of languageModelToolsService.getTools()) {
|
||||
if (tool.canBeReferencedInPrompt) {
|
||||
const item: IToolQuickPickItem = {
|
||||
kind: 'tool',
|
||||
label: tool.displayName ?? '',
|
||||
id: tool.id,
|
||||
icon: ThemeIcon.isThemeIcon(tool.icon) ? tool.icon : undefined // TODO need to support icon path?
|
||||
};
|
||||
if (ThemeIcon.isThemeIcon(tool.icon)) {
|
||||
item.iconClass = ThemeIcon.asClassName(tool.icon);
|
||||
} else if (tool.icon) {
|
||||
item.iconPath = tool.icon;
|
||||
}
|
||||
|
||||
quickPickItems.push(item);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -149,10 +149,6 @@ const chatParticipantExtensionPoint = extensionsRegistry.ExtensionsRegistry.regi
|
||||
}
|
||||
}
|
||||
},
|
||||
supportsToolReferences: {
|
||||
description: localize('chatParticipantSupportsToolReferences', "Whether this participant supports {0}.", 'ChatRequest#toolReferences'),
|
||||
type: 'boolean'
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -261,7 +257,6 @@ export class ChatExtensionPointHandler implements IWorkbenchContribution {
|
||||
[ChatAgentLocation.Panel],
|
||||
slashCommands: providerDescriptor.commands ?? [],
|
||||
disambiguation: coalesce(participantsAndCommandsDisambiguation.flat()),
|
||||
supportsToolReferences: providerDescriptor.supportsToolReferences,
|
||||
} satisfies IChatAgentData));
|
||||
|
||||
this._participantRegistrationDisposables.set(
|
||||
|
||||
@@ -575,22 +575,20 @@ class VariableCompletions extends Disposable {
|
||||
const usedTools = widget.parsedInput.parts.filter((p): p is ChatRequestToolPart => p instanceof ChatRequestToolPart);
|
||||
const usedToolNames = new Set(usedTools.map(v => v.toolName));
|
||||
const toolItems: CompletionItem[] = [];
|
||||
if (!usedAgent || usedAgent.agent.supportsToolReferences) {
|
||||
toolItems.push(...Array.from(toolsService.getTools())
|
||||
.filter(t => t.canBeInvokedManually)
|
||||
.filter(t => !usedToolNames.has(t.name ?? ''))
|
||||
.map((t): CompletionItem => {
|
||||
const withLeader = `${chatVariableLeader}${t.name}`;
|
||||
return {
|
||||
label: withLeader,
|
||||
range,
|
||||
insertText: withLeader + ' ',
|
||||
detail: t.userDescription,
|
||||
kind: CompletionItemKind.Text,
|
||||
sortText: 'z'
|
||||
};
|
||||
}));
|
||||
}
|
||||
toolItems.push(...Array.from(toolsService.getTools())
|
||||
.filter(t => t.canBeReferencedInPrompt)
|
||||
.filter(t => !usedToolNames.has(t.toolReferenceName ?? ''))
|
||||
.map((t): CompletionItem => {
|
||||
const withLeader = `${chatVariableLeader}${t.toolReferenceName}`;
|
||||
return {
|
||||
label: withLeader,
|
||||
range,
|
||||
insertText: withLeader + ' ',
|
||||
detail: t.userDescription,
|
||||
kind: CompletionItemKind.Text,
|
||||
sortText: 'z'
|
||||
};
|
||||
}));
|
||||
|
||||
return {
|
||||
suggestions: [...variableItems, ...toolItems]
|
||||
|
||||
@@ -112,7 +112,7 @@ export class LanguageModelToolsService extends Disposable implements ILanguageMo
|
||||
|
||||
getToolByName(name: string): IToolData | undefined {
|
||||
for (const toolData of this.getTools()) {
|
||||
if (toolData.name === name) {
|
||||
if (toolData.toolReferenceName === name) {
|
||||
return toolData;
|
||||
}
|
||||
}
|
||||
@@ -142,42 +142,31 @@ export class LanguageModelToolsService extends Disposable implements ILanguageMo
|
||||
const model = this._chatService.getSession(dto.context?.sessionId) as ChatModel;
|
||||
const request = model.getRequests().at(-1)!;
|
||||
|
||||
const participantName = request.response?.agent?.fullName ?? ''; // This should always be set in this scenario with a new live request
|
||||
|
||||
const prepared = tool.impl.prepareToolInvocation ?
|
||||
await tool.impl.prepareToolInvocation(participantName, dto.parameters, token)
|
||||
: undefined;
|
||||
const confirmationMessages = tool.data.requiresConfirmation ?
|
||||
prepared?.confirmationMessages ?? {
|
||||
title: localize('toolConfirmTitle', "Use {0}?", `"${tool.data.displayName ?? tool.data.id}"`),
|
||||
message: localize('toolConfirmMessage', "{0} will use {1}.", participantName, `"${tool.data.displayName ?? tool.data.id}"`),
|
||||
}
|
||||
await tool.impl.prepareToolInvocation(dto.parameters, token)
|
||||
: undefined;
|
||||
|
||||
const defaultMessage = localize('toolInvocationMessage', "Using {0}", `"${tool.data.displayName ?? tool.data.id}"`);
|
||||
const defaultMessage = localize('toolInvocationMessage', "Using {0}", `"${tool.data.displayName}"`);
|
||||
const invocationMessage = prepared?.invocationMessage ?? defaultMessage;
|
||||
toolInvocation = new ChatToolInvocation(invocationMessage, confirmationMessages);
|
||||
toolInvocation = new ChatToolInvocation(invocationMessage, prepared?.confirmationMessages);
|
||||
token.onCancellationRequested(() => {
|
||||
toolInvocation!.confirmed.complete(false);
|
||||
});
|
||||
model.acceptResponseProgress(request, toolInvocation);
|
||||
if (tool.data.requiresConfirmation) {
|
||||
if (prepared?.confirmationMessages) {
|
||||
const userConfirmed = await toolInvocation.confirmed.p;
|
||||
if (!userConfirmed) {
|
||||
throw new CancellationError();
|
||||
}
|
||||
}
|
||||
} else if (tool.data.requiresConfirmation) {
|
||||
} else {
|
||||
const prepared = tool.impl.prepareToolInvocation ?
|
||||
await tool.impl.prepareToolInvocation('Some Extension', dto.parameters, token)
|
||||
await tool.impl.prepareToolInvocation(dto.parameters, token)
|
||||
: undefined;
|
||||
|
||||
const confirmationMessages = prepared?.confirmationMessages ?? {
|
||||
title: localize('toolConfirmTitle', "Use {0}?", `"${tool.data.displayName ?? tool.data.id}"`),
|
||||
message: localize('toolConfirmMessage', "{0} will use {1}.", 'Some Extension', `"${tool.data.displayName ?? tool.data.id}"`),
|
||||
};
|
||||
|
||||
await this._dialogService.confirm({ message: confirmationMessages.title, detail: renderStringAsPlaintext(confirmationMessages.message) });
|
||||
if (prepared?.confirmationMessages) {
|
||||
await this._dialogService.confirm({ message: prepared.confirmationMessages.title, detail: renderStringAsPlaintext(prepared.confirmationMessages.message) });
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
|
||||
@@ -77,7 +77,6 @@ export interface IChatAgentData {
|
||||
slashCommands: IChatAgentCommand[];
|
||||
locations: ChatAgentLocation[];
|
||||
disambiguation: { category: string; description: string; examples: string[] }[];
|
||||
supportsToolReferences?: boolean;
|
||||
}
|
||||
|
||||
export interface IChatWelcomeMessageContent {
|
||||
|
||||
@@ -29,7 +29,6 @@ export interface IRawChatParticipantContribution {
|
||||
defaultImplicitVariables?: string[];
|
||||
locations?: RawChatParticipantLocation[];
|
||||
disambiguation?: { category: string; categoryName?: string /** Deprecated */; description: string; examples: string[] }[];
|
||||
supportsToolReferences?: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -159,7 +159,7 @@ export class ChatRequestParser {
|
||||
}
|
||||
|
||||
const tool = this.toolsService.getToolByName(name);
|
||||
if (tool && tool.canBeInvokedManually && (!usedAgent || usedAgent.agent.supportsToolReferences)) {
|
||||
if (tool && tool.canBeReferencedInPrompt) {
|
||||
return new ChatRequestToolPart(varRange, varEditorRange, name, tool.id, tool.displayName, tool.icon);
|
||||
}
|
||||
|
||||
|
||||
@@ -15,17 +15,16 @@ import { createDecorator } from '../../../../platform/instantiation/common/insta
|
||||
|
||||
export interface IToolData {
|
||||
id: string;
|
||||
name?: string;
|
||||
toolReferenceName?: string;
|
||||
icon?: { dark: URI; light?: URI } | ThemeIcon;
|
||||
when?: ContextKeyExpression;
|
||||
tags?: string[];
|
||||
displayName?: string;
|
||||
displayName: string;
|
||||
userDescription?: string;
|
||||
modelDescription: string;
|
||||
parametersSchema?: IJSONSchema;
|
||||
canBeInvokedManually?: boolean;
|
||||
canBeReferencedInPrompt?: boolean;
|
||||
supportedContentTypes: string[];
|
||||
requiresConfirmation?: boolean;
|
||||
}
|
||||
|
||||
export interface IToolInvocation {
|
||||
@@ -57,7 +56,7 @@ export interface IPreparedToolInvocation {
|
||||
|
||||
export interface IToolImpl {
|
||||
invoke(invocation: IToolInvocation, countTokens: CountTokensCallback, token: CancellationToken): Promise<IToolResult>;
|
||||
prepareToolInvocation?(participantName: string, parameters: any, token: CancellationToken): Promise<IPreparedToolInvocation | undefined>;
|
||||
prepareToolInvocation?(parameters: any, token: CancellationToken): Promise<IPreparedToolInvocation | undefined>;
|
||||
}
|
||||
|
||||
export const ILanguageModelToolsService = createDecorator<ILanguageModelToolsService>('ILanguageModelToolsService');
|
||||
|
||||
@@ -17,25 +17,24 @@ import { ILanguageModelToolsService, IToolData } from '../languageModelToolsServ
|
||||
import * as extensionsRegistry from '../../../../services/extensions/common/extensionsRegistry.js';
|
||||
|
||||
interface IRawToolContribution {
|
||||
id: string;
|
||||
name?: string;
|
||||
name: string;
|
||||
displayName: string;
|
||||
modelDescription: string;
|
||||
toolReferenceName?: string;
|
||||
icon?: string | { light: string; dark: string };
|
||||
when?: string;
|
||||
tags?: string[];
|
||||
displayName?: string;
|
||||
userDescription?: string;
|
||||
modelDescription: string;
|
||||
parametersSchema?: IJSONSchema;
|
||||
canBeInvokedManually?: boolean;
|
||||
canBeReferencedInPrompt?: boolean;
|
||||
supportedContentTypes?: string[];
|
||||
requiresConfirmation?: boolean;
|
||||
}
|
||||
|
||||
const languageModelToolsExtensionPoint = extensionsRegistry.ExtensionsRegistry.registerExtensionPoint<IRawToolContribution[]>({
|
||||
extensionPoint: 'languageModelTools',
|
||||
activationEventsGenerator: (contributions: IRawToolContribution[], result) => {
|
||||
for (const contrib of contributions) {
|
||||
result.push(`onLanguageModelTool:${contrib.id}`);
|
||||
result.push(`onLanguageModelTool:${contrib.name}`);
|
||||
}
|
||||
},
|
||||
jsonSchema: {
|
||||
@@ -45,16 +44,16 @@ const languageModelToolsExtensionPoint = extensionsRegistry.ExtensionsRegistry.r
|
||||
additionalProperties: false,
|
||||
type: 'object',
|
||||
defaultSnippets: [{ body: { name: '', description: '' } }],
|
||||
required: ['id', 'modelDescription'],
|
||||
required: ['name', 'displayName', 'modelDescription'],
|
||||
properties: {
|
||||
id: {
|
||||
description: localize('toolId', "A unique id for this tool."),
|
||||
name: {
|
||||
description: localize('toolName', "A unique name for this tool. This name must be a globally unique identifier, and is also used as a name when presenting this tool to a language model."),
|
||||
type: 'string',
|
||||
// Borrow OpenAI's requirement for tool names
|
||||
pattern: '^[\\w-]+$'
|
||||
},
|
||||
name: {
|
||||
markdownDescription: localize('toolName', "If {0} is enabled for this tool, the user may use '#' with this name to invoke the tool in a query. Otherwise, the name is not required. Name must not contain whitespace.", '`canBeInvokedManually`'),
|
||||
toolReferenceName: {
|
||||
markdownDescription: localize('toolName2', "If {0} is enabled for this tool, the user may use '#' with this name to invoke the tool in a query. Otherwise, the name is not required. Name must not contain whitespace.", '`canBeReferencedInPrompt`'),
|
||||
type: 'string',
|
||||
pattern: '^[\\w-]+$'
|
||||
},
|
||||
@@ -67,7 +66,7 @@ const languageModelToolsExtensionPoint = extensionsRegistry.ExtensionsRegistry.r
|
||||
type: 'string'
|
||||
},
|
||||
modelDescription: {
|
||||
description: localize('toolModelDescription', "A description of this tool that may be passed to a language model."),
|
||||
description: localize('toolModelDescription', "A description of this tool that may be used by a language model to select it."),
|
||||
type: 'string'
|
||||
},
|
||||
parametersSchema: {
|
||||
@@ -75,8 +74,8 @@ const languageModelToolsExtensionPoint = extensionsRegistry.ExtensionsRegistry.r
|
||||
type: 'object',
|
||||
$ref: 'http://json-schema.org/draft-07/schema#'
|
||||
},
|
||||
canBeInvokedManually: {
|
||||
description: localize('canBeInvokedManually', "Whether this tool can be invoked manually by the user through the chat UX."),
|
||||
canBeReferencedInPrompt: {
|
||||
markdownDescription: localize('canBeReferencedInPrompt', "If true, this tool shows up as an attachment that the user can add manually to their request. Chat participants will receive the tool in {0}.", '`ChatRequest#toolReferences`'),
|
||||
type: 'boolean'
|
||||
},
|
||||
icon: {
|
||||
@@ -109,9 +108,6 @@ const languageModelToolsExtensionPoint = extensionsRegistry.ExtensionsRegistry.r
|
||||
type: 'string'
|
||||
}
|
||||
},
|
||||
requiresConfirmation: {
|
||||
description: localize('requiresConfirmation', "Whether this tool requires user confirmation before being executed."),
|
||||
},
|
||||
tags: {
|
||||
description: localize('toolTags', "A set of tags that roughly describe the tool's capabilities. A tool user may use these to filter the set of tools to just ones that are relevant for the task at hand."),
|
||||
type: 'array',
|
||||
@@ -140,18 +136,18 @@ export class LanguageModelToolsExtensionPointHandler implements IWorkbenchContri
|
||||
languageModelToolsExtensionPoint.setHandler((extensions, delta) => {
|
||||
for (const extension of delta.added) {
|
||||
for (const rawTool of extension.value) {
|
||||
if (!rawTool.id || !rawTool.modelDescription) {
|
||||
logService.error(`Extension '${extension.description.identifier.value}' CANNOT register tool without name and modelDescription: ${JSON.stringify(rawTool)}`);
|
||||
if (!rawTool.name || !rawTool.modelDescription || !rawTool.displayName) {
|
||||
logService.error(`Extension '${extension.description.identifier.value}' CANNOT register tool without name, modelDescription, and displayName: ${JSON.stringify(rawTool)}`);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!rawTool.id.match(/^[\w-]+$/)) {
|
||||
logService.error(`Extension '${extension.description.identifier.value}' CANNOT register tool with invalid id: ${rawTool.id}. The id must match /^[\\w-]+$/.`);
|
||||
if (!rawTool.name.match(/^[\w-]+$/)) {
|
||||
logService.error(`Extension '${extension.description.identifier.value}' CANNOT register tool with invalid id: ${rawTool.name}. The id must match /^[\\w-]+$/.`);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (rawTool.canBeInvokedManually && !rawTool.name) {
|
||||
logService.error(`Extension '${extension.description.identifier.value}' CANNOT register tool with 'canBeInvokedManually' set without a name: ${JSON.stringify(rawTool)}`);
|
||||
if (rawTool.canBeReferencedInPrompt && !rawTool.toolReferenceName) {
|
||||
logService.error(`Extension '${extension.description.identifier.value}' CANNOT register tool with 'canBeReferencedInPrompt' set without a 'toolReferenceName': ${JSON.stringify(rawTool)}`);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -171,18 +167,19 @@ export class LanguageModelToolsExtensionPointHandler implements IWorkbenchContri
|
||||
|
||||
const tool: IToolData = {
|
||||
...rawTool,
|
||||
id: rawTool.name,
|
||||
icon,
|
||||
when: rawTool.when ? ContextKeyExpr.deserialize(rawTool.when) : undefined,
|
||||
supportedContentTypes: rawTool.supportedContentTypes ? rawTool.supportedContentTypes : [],
|
||||
};
|
||||
const disposable = languageModelToolsService.registerToolData(tool);
|
||||
this._registrationDisposables.set(toToolKey(extension.description.identifier, rawTool.id), disposable);
|
||||
this._registrationDisposables.set(toToolKey(extension.description.identifier, rawTool.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));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -31,7 +31,8 @@ suite('LanguageModelToolsService', () => {
|
||||
const toolData: IToolData = {
|
||||
id: 'testTool',
|
||||
modelDescription: 'Test Tool',
|
||||
supportedContentTypes: []
|
||||
supportedContentTypes: [],
|
||||
displayName: 'Test Tool'
|
||||
};
|
||||
|
||||
const disposable = service.registerToolData(toolData);
|
||||
@@ -44,7 +45,8 @@ suite('LanguageModelToolsService', () => {
|
||||
const toolData: IToolData = {
|
||||
id: 'testTool',
|
||||
modelDescription: 'Test Tool',
|
||||
supportedContentTypes: []
|
||||
supportedContentTypes: [],
|
||||
displayName: 'Test Tool'
|
||||
};
|
||||
|
||||
store.add(service.registerToolData(toolData));
|
||||
@@ -63,20 +65,23 @@ suite('LanguageModelToolsService', () => {
|
||||
id: 'testTool1',
|
||||
modelDescription: 'Test Tool 1',
|
||||
when: ContextKeyEqualsExpr.create('testKey', false),
|
||||
supportedContentTypes: []
|
||||
supportedContentTypes: [],
|
||||
displayName: 'Test Tool'
|
||||
};
|
||||
|
||||
const toolData2: IToolData = {
|
||||
id: 'testTool2',
|
||||
modelDescription: 'Test Tool 2',
|
||||
when: ContextKeyEqualsExpr.create('testKey', true),
|
||||
supportedContentTypes: []
|
||||
supportedContentTypes: [],
|
||||
displayName: 'Test Tool'
|
||||
};
|
||||
|
||||
const toolData3: IToolData = {
|
||||
id: 'testTool3',
|
||||
modelDescription: 'Test Tool 3',
|
||||
supportedContentTypes: []
|
||||
supportedContentTypes: [],
|
||||
displayName: 'Test Tool'
|
||||
};
|
||||
|
||||
store.add(service.registerToolData(toolData1));
|
||||
@@ -93,7 +98,8 @@ suite('LanguageModelToolsService', () => {
|
||||
const toolData: IToolData = {
|
||||
id: 'testTool',
|
||||
modelDescription: 'Test Tool',
|
||||
supportedContentTypes: []
|
||||
supportedContentTypes: [],
|
||||
displayName: 'Test Tool'
|
||||
};
|
||||
|
||||
store.add(service.registerToolData(toolData));
|
||||
|
||||
123
src/vscode-dts/vscode.proposed.lmTools.d.ts
vendored
123
src/vscode-dts/vscode.proposed.lmTools.d.ts
vendored
@@ -3,24 +3,38 @@
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
// version: 8
|
||||
// version: 9
|
||||
// https://github.com/microsoft/vscode/issues/213274
|
||||
|
||||
declare module 'vscode' {
|
||||
|
||||
// TODO@API capabilities
|
||||
|
||||
// API -> LM: an tool/function that is available to the language model
|
||||
/**
|
||||
* A tool that is available to the language model via {@link LanguageModelChatRequestOptions}.
|
||||
*/
|
||||
export interface LanguageModelChatTool {
|
||||
// TODO@API should use "id" here to match vscode tools, or keep name to match OpenAI? Align everything.
|
||||
/**
|
||||
* The name of the tool.
|
||||
*/
|
||||
name: string;
|
||||
|
||||
/**
|
||||
* The description of the tool.
|
||||
*/
|
||||
description: string;
|
||||
parametersSchema?: JSONSchema;
|
||||
|
||||
/**
|
||||
* A JSON schema for the parameters this tool accepts.
|
||||
*/
|
||||
parametersSchema?: object;
|
||||
}
|
||||
|
||||
// API -> LM: add tools as request option
|
||||
export interface LanguageModelChatRequestOptions {
|
||||
// TODO@API this will be a heterogeneous array of different types of tools
|
||||
/**
|
||||
* An optional list of tools that are available to the language model.
|
||||
*/
|
||||
tools?: LanguageModelChatTool[];
|
||||
|
||||
/**
|
||||
@@ -29,30 +43,62 @@ declare module 'vscode' {
|
||||
toolChoice?: string;
|
||||
}
|
||||
|
||||
// LM -> USER: function that should be used
|
||||
/**
|
||||
* A language model response part indicating a tool call, returned from a {@link LanguageModelChatResponse}, and also can be
|
||||
* included as a content part on a {@link LanguageModelChatMessage}, to represent a previous tool call in a
|
||||
* chat request.
|
||||
*/
|
||||
export class LanguageModelToolCallPart {
|
||||
/**
|
||||
* The name of the tool to call.
|
||||
*/
|
||||
name: string;
|
||||
toolCallId: string;
|
||||
parameters: any;
|
||||
|
||||
constructor(name: string, toolCallId: string, parameters: any);
|
||||
/**
|
||||
* The ID of the tool call. This is a unique identifier for the tool call within the chat request.
|
||||
*/
|
||||
toolCallId: string;
|
||||
|
||||
/**
|
||||
* The parameters with which to call the tool.
|
||||
*/
|
||||
parameters: object;
|
||||
|
||||
constructor(name: string, toolCallId: string, parameters: object);
|
||||
}
|
||||
|
||||
// LM -> USER: text chunk
|
||||
/**
|
||||
* A language model response part containing a piece of text, returned from a {@link LanguageModelChatResponse}.
|
||||
*/
|
||||
export class LanguageModelTextPart {
|
||||
/**
|
||||
* The text content of the part.
|
||||
*/
|
||||
value: string;
|
||||
|
||||
constructor(value: string);
|
||||
}
|
||||
|
||||
export interface LanguageModelChatResponse {
|
||||
/**
|
||||
* A stream of parts that make up the response. Could be extended with more types in the future.
|
||||
* TODO@API add "| unknown"?
|
||||
*/
|
||||
stream: AsyncIterable<LanguageModelTextPart | LanguageModelToolCallPart>;
|
||||
}
|
||||
|
||||
|
||||
// USER -> LM: the result of a function call
|
||||
/**
|
||||
* The result of a tool call. Can only be included in the content of a User message.
|
||||
*/
|
||||
export class LanguageModelToolResultPart {
|
||||
/**
|
||||
* The ID of the tool call.
|
||||
*/
|
||||
toolCallId: string;
|
||||
|
||||
/**
|
||||
* The content of the tool result.
|
||||
*/
|
||||
content: string;
|
||||
|
||||
constructor(toolCallId: string, content: string);
|
||||
@@ -60,12 +106,8 @@ declare module 'vscode' {
|
||||
|
||||
export interface LanguageModelChatMessage {
|
||||
/**
|
||||
* A heterogeneous array of other things that a message can contain as content.
|
||||
* Some parts would be message-type specific for some models and wouldn't go together,
|
||||
* but it's up to the chat provider to decide what to do about that.
|
||||
* Can drop parts that are not valid for the message type.
|
||||
* LanguageModelToolResultPart: only on User messages
|
||||
* LanguageModelToolCallPart: only on Assistant messages
|
||||
* A heterogeneous array of other things that a message can contain as content. Some parts may be message-type specific
|
||||
* for some models.
|
||||
*/
|
||||
content2: (string | LanguageModelToolResultPart | LanguageModelToolCallPart)[];
|
||||
}
|
||||
@@ -93,7 +135,7 @@ declare module 'vscode' {
|
||||
* point. A registered tool is available in the {@link lm.tools} list for any extension to see. But in order for it to
|
||||
* be seen by a language model, it must be passed in the list of available tools in {@link LanguageModelChatRequestOptions.tools}.
|
||||
*/
|
||||
export function registerTool<T>(id: string, tool: LanguageModelTool<T>): Disposable;
|
||||
export function registerTool<T>(name: string, tool: LanguageModelTool<T>): Disposable;
|
||||
|
||||
/**
|
||||
* A list of all available tools.
|
||||
@@ -103,7 +145,7 @@ declare module 'vscode' {
|
||||
/**
|
||||
* Invoke a tool with the given parameters.
|
||||
*/
|
||||
export function invokeTool<T>(id: string, options: LanguageModelToolInvocationOptions<T>, token: CancellationToken): Thenable<LanguageModelToolResult>;
|
||||
export function invokeTool(id: string, options: LanguageModelToolInvocationOptions<object>, token: CancellationToken): Thenable<LanguageModelToolResult>;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -120,6 +162,8 @@ declare module 'vscode' {
|
||||
* {@link ChatRequest.toolInvocationToken}. In that case, a progress bar will be automatically shown for the tool
|
||||
* invocation in the chat response view, and if the tool requires user confirmation, it will show up inline in the chat
|
||||
* view. If the tool is being invoked outside of a chat request, `undefined` should be passed instead.
|
||||
*
|
||||
* If a tool invokes another tool during its invocation, it can pass along the `toolInvocationToken` that it received.
|
||||
*/
|
||||
toolInvocationToken: ChatParticipantToolToken | undefined;
|
||||
|
||||
@@ -154,26 +198,14 @@ declare module 'vscode' {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a JSON Schema.
|
||||
* TODO@API - is this worth it?
|
||||
*/
|
||||
export type JSONSchema = Object;
|
||||
|
||||
/**
|
||||
* A description of an available tool.
|
||||
*/
|
||||
export interface LanguageModelToolDescription {
|
||||
/**
|
||||
* A unique identifier for the tool.
|
||||
* A unique name for the tool.
|
||||
*/
|
||||
readonly id: string;
|
||||
|
||||
/**
|
||||
* A human-readable name for this tool that may be used to describe it in the UI.
|
||||
* TODO@API keep?
|
||||
*/
|
||||
readonly displayName: string | undefined;
|
||||
readonly name: string;
|
||||
|
||||
/**
|
||||
* A description of this tool that may be passed to a language model.
|
||||
@@ -183,7 +215,7 @@ declare module 'vscode' {
|
||||
/**
|
||||
* A JSON schema for the parameters this tool accepts.
|
||||
*/
|
||||
readonly parametersSchema?: JSONSchema;
|
||||
readonly parametersSchema?: object;
|
||||
|
||||
/**
|
||||
* The list of content types that the tool has declared support for. See {@link LanguageModelToolResult}.
|
||||
@@ -198,8 +230,8 @@ declare module 'vscode' {
|
||||
}
|
||||
|
||||
/**
|
||||
* Messages shown in the chat view when a tool needs confirmation from the user to run. These messages will be shown with
|
||||
* buttons that say Continue and Cancel.
|
||||
* When this is returned in {@link PreparedToolInvocation}, the user will be asked to confirm before running the tool. These
|
||||
* messages will be shown with buttons that say "Continue" and "Cancel".
|
||||
*/
|
||||
export interface LanguageModelToolConfirmationMessages {
|
||||
/**
|
||||
@@ -208,10 +240,7 @@ declare module 'vscode' {
|
||||
title: string;
|
||||
|
||||
/**
|
||||
* The body of the confirmation message. This should be phrased as an action of the participant that is invoking the tool
|
||||
* from {@link LanguageModelToolInvocationPrepareOptions.participantName}. An example of a good message would be
|
||||
* `${participantName} will run the command ${echo 'hello world'} in the terminal.`
|
||||
* TODO@API keep this?
|
||||
* The body of the confirmation message.
|
||||
*/
|
||||
message: string | MarkdownString;
|
||||
}
|
||||
@@ -220,12 +249,6 @@ declare module 'vscode' {
|
||||
* Options for {@link LanguageModelTool.prepareToolInvocation}.
|
||||
*/
|
||||
export interface LanguageModelToolInvocationPrepareOptions<T> {
|
||||
/**
|
||||
* The name of the participant invoking the tool.
|
||||
* TODO@API keep this?
|
||||
*/
|
||||
participantName: string;
|
||||
|
||||
/**
|
||||
* The parameters that the tool is being invoked with.
|
||||
*/
|
||||
@@ -242,8 +265,8 @@ declare module 'vscode' {
|
||||
invoke(options: LanguageModelToolInvocationOptions<T>, token: CancellationToken): ProviderResult<LanguageModelToolResult>;
|
||||
|
||||
/**
|
||||
* Called once before a tool is invoked. May be implemented to customize the progress message that appears while the tool
|
||||
* is running, and the messages that appear when the tool needs confirmation.
|
||||
* Called once before a tool is invoked. May be implemented to signal that a tool needs user confirmation before running,
|
||||
* and to customize the progress message that appears while the tool is running.
|
||||
*/
|
||||
prepareToolInvocation?(options: LanguageModelToolInvocationPrepareOptions<T>, token: CancellationToken): ProviderResult<PreparedToolInvocation>;
|
||||
}
|
||||
@@ -258,7 +281,7 @@ declare module 'vscode' {
|
||||
invocationMessage?: string;
|
||||
|
||||
/**
|
||||
* Customized messages to show when asking for user confirmation to run the tool.
|
||||
* The presence of this property indicates that the user should be asked to confirm before running the tool.
|
||||
*/
|
||||
confirmationMessages?: LanguageModelToolConfirmationMessages;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user