Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/extensions/copilot/test/simulation/fixtures/edit/issue-7202/languageModelToolsContribution.ts
13405 views
1
/*---------------------------------------------------------------------------------------------
2
* Copyright (c) Microsoft Corporation. All rights reserved.
3
* Licensed under the MIT License. See License.txt in the project root for license information.
4
*--------------------------------------------------------------------------------------------*/
5
6
7
import { IJSONSchema } from 'vs/base/common/jsonSchema';
8
import { DisposableMap } from 'vs/base/common/lifecycle';
9
import { joinPath } from 'vs/base/common/resources';
10
import { ThemeIcon } from 'vs/base/common/themables';
11
import { localize } from 'vs/nls';
12
import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions';
13
import { ILogService } from 'vs/platform/log/common/log';
14
import { IWorkbenchContribution } from 'vs/workbench/common/contributions';
15
import { ILanguageModelToolsService, IToolData } from 'vs/workbench/contrib/chat/common/languageModelToolsService';
16
import * as extensionsRegistry from 'vs/workbench/services/extensions/common/extensionsRegistry';
17
18
interface IRawToolContribution {
19
id: string;
20
name?: string;
21
icon?: string | { light: string; dark: string };
22
displayName?: string;
23
description: string;
24
parametersSchema?: IJSONSchema;
25
canBeInvokedManually?: boolean;
26
}
27
28
const languageModelToolsExtensionPoint = extensionsRegistry.ExtensionsRegistry.registerExtensionPoint<IRawToolContribution[]>({
29
extensionPoint: 'languageModelTools',
30
activationEventsGenerator: (contributions: IRawToolContribution[], result) => {
31
for (const contrib of contributions) {
32
result.push(`onLanguageModelTool:${contrib.name}`);
33
}
34
},
35
jsonSchema: {
36
description: localize('vscode.extension.contributes.tools', 'Contributes a tool that can be invoked by a language model.'),
37
type: 'array',
38
items: {
39
additionalProperties: false,
40
type: 'object',
41
defaultSnippets: [{ body: { name: '', description: '' } }],
42
required: ['id', 'description'],
43
properties: {
44
id: {
45
description: localize('toolId', "A unique id for this tool."),
46
type: 'string',
47
// Borrow OpenAI's requirement for tool names
48
pattern: '^[\\w-]+$'
49
},
50
name: {
51
description: 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`'),
52
type: 'string',
53
pattern: '^[\\w-]+$'
54
},
55
displayName: {
56
description: localize('toolDisplayName', "A human-readable name for this tool that may be used to describe it in the UI."),
57
type: 'string'
58
},
59
description: {
60
description: localize('toolDescription', "A description of this tool that may be passed to a language model."),
61
type: 'string'
62
},
63
parametersSchema: {
64
description: localize('parametersSchema', "A JSON schema for the parameters this tool accepts."),
65
type: 'object',
66
$ref: 'http://json-schema.org/draft-07/schema#'
67
},
68
canBeInvokedManually: {
69
description: localize('canBeInvokedManually', "Whether this tool can be invoked manually by the user through the chat UX."),
70
type: 'boolean'
71
},
72
icon: {
73
description: localize('icon', "An icon that represents this tool. Either a file path, an object with file paths for dark and light themes, or a theme icon reference, like `\\$(zap)`"),
74
anyOf: [{
75
type: 'string'
76
},
77
{
78
type: 'object',
79
properties: {
80
light: {
81
description: localize('icon.light', 'Icon path when a light theme is used'),
82
type: 'string'
83
},
84
dark: {
85
description: localize('icon.dark', 'Icon path when a dark theme is used'),
86
type: 'string'
87
}
88
}
89
}]
90
}
91
}
92
}
93
}
94
});
95
96
function toToolKey(extensionIdentifier: ExtensionIdentifier, toolName: string) {
97
return `${extensionIdentifier.value}/${toolName}`;
98
}
99
100
export class LanguageModelToolsExtensionPointHandler implements IWorkbenchContribution {
101
static readonly ID = 'workbench.contrib.toolsExtensionPointHandler';
102
103
private _registrationDisposables = new DisposableMap<string>();
104
105
constructor(
106
@ILanguageModelToolsService languageModelToolsService: ILanguageModelToolsService,
107
@ILogService logService: ILogService,
108
) {
109
languageModelToolsExtensionPoint.setHandler((extensions, delta) => {
110
for (const extension of delta.added) {
111
for (const rawTool of extension.value) {
112
if (!rawTool.name || !rawTool.description) {
113
logService.error(`Invalid tool contribution from ${extension.description.identifier.value}: ${JSON.stringify(rawTool)}`);
114
continue;
115
}
116
117
if (!rawTool.id.match(/^[\w-]+$/)) {
118
logService.error(`Extension '${extension.description.identifier.value}' CANNOT register participant with invalid id: ${rawTool.id}. The id must match /^[\\w-]+$/.`);
119
continue;
120
}
121
122
const rawIcon = rawTool.icon;
123
let icon: IToolData['icon'] | undefined;
124
if (typeof rawIcon === 'string') {
125
icon = ThemeIcon.fromString(rawIcon) ?? {
126
dark: joinPath(extension.description.extensionLocation, rawIcon),
127
light: joinPath(extension.description.extensionLocation, rawIcon)
128
};
129
} else if (rawIcon) {
130
icon = {
131
dark: joinPath(extension.description.extensionLocation, rawIcon.dark),
132
light: joinPath(extension.description.extensionLocation, rawIcon.light)
133
};
134
}
135
136
const tool: IToolData = {
137
...rawTool,
138
icon
139
};
140
const disposable = languageModelToolsService.registerToolData(tool);
141
this._registrationDisposables.set(toToolKey(extension.description.identifier, rawTool.id), disposable);
142
}
143
}
144
145
for (const extension of delta.removed) {
146
for (const tool of extension.value) {
147
this._registrationDisposables.deleteAndDispose(toToolKey(extension.description.identifier, tool.id));
148
}
149
}
150
});
151
}
152
}
153
154