Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/src/vs/workbench/contrib/extensions/common/searchExtensionsTool.ts
3296 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
import { CancellationToken } from '../../../../base/common/cancellation.js';
7
import { Codicon } from '../../../../base/common/codicons.js';
8
import { ThemeIcon } from '../../../../base/common/themables.js';
9
import { localize } from '../../../../nls.js';
10
import { SortBy } from '../../../../platform/extensionManagement/common/extensionManagement.js';
11
import { EXTENSION_CATEGORIES } from '../../../../platform/extensions/common/extensions.js';
12
import { CountTokensCallback, IToolData, IToolImpl, IToolInvocation, IToolResult, ToolDataSource, ToolProgress } from '../../chat/common/languageModelToolsService.js';
13
import { ExtensionState, IExtension, IExtensionsWorkbenchService } from '../common/extensions.js';
14
15
export const SearchExtensionsToolId = 'vscode_searchExtensions_internal';
16
17
export const SearchExtensionsToolData: IToolData = {
18
id: SearchExtensionsToolId,
19
toolReferenceName: 'extensions',
20
canBeReferencedInPrompt: true,
21
icon: ThemeIcon.fromId(Codicon.extensions.id),
22
displayName: localize('searchExtensionsTool.displayName', 'Search Extensions'),
23
modelDescription: localize('searchExtensionsTool.modelDescription', "This is a tool for browsing Visual Studio Code Extensions Marketplace. It allows the model to search for extensions and retrieve detailed information about them. The model should use this tool whenever it needs to discover extensions or resolve information about known ones. To use the tool, the model has to provide the category of the extensions, relevant search keywords, or known extension IDs. Note that search results may include false positives, so reviewing and filtering is recommended."),
24
userDescription: localize('searchExtensionsTool.userDescription', 'Search for VS Code extensions'),
25
source: ToolDataSource.Internal,
26
inputSchema: {
27
type: 'object',
28
properties: {
29
category: {
30
type: 'string',
31
description: 'The category of extensions to search for',
32
enum: EXTENSION_CATEGORIES,
33
},
34
keywords: {
35
type: 'array',
36
items: {
37
type: 'string',
38
},
39
description: 'The keywords to search for',
40
},
41
ids: {
42
type: 'array',
43
items: {
44
type: 'string',
45
},
46
description: 'The ids of the extensions to search for',
47
},
48
},
49
}
50
};
51
52
type InputParams = {
53
category?: string;
54
keywords?: string;
55
ids?: string[];
56
};
57
58
type ExtensionData = {
59
id: string;
60
name: string;
61
description: string;
62
installed: boolean;
63
installCount: number;
64
rating: number;
65
categories: readonly string[];
66
tags: readonly string[];
67
};
68
69
export class SearchExtensionsTool implements IToolImpl {
70
71
constructor(
72
@IExtensionsWorkbenchService private readonly extensionWorkbenchService: IExtensionsWorkbenchService,
73
) { }
74
75
async invoke(invocation: IToolInvocation, _countTokens: CountTokensCallback, _progress: ToolProgress, token: CancellationToken): Promise<IToolResult> {
76
const params = invocation.parameters as InputParams;
77
if (!params.keywords?.length && !params.category && !params.ids?.length) {
78
return {
79
content: [{
80
kind: 'text',
81
value: localize('searchExtensionsTool.noInput', 'Please provide a category or keywords or ids to search for.')
82
}]
83
};
84
}
85
86
const extensionsMap = new Map<string, ExtensionData>();
87
88
const addExtension = (extensions: IExtension[]) => {
89
for (const extension of extensions) {
90
if (extension.deprecationInfo || extension.isMalicious) {
91
continue;
92
}
93
extensionsMap.set(extension.identifier.id.toLowerCase(), {
94
id: extension.identifier.id,
95
name: extension.displayName,
96
description: extension.description,
97
installed: extension.state === ExtensionState.Installed,
98
installCount: extension.installCount ?? 0,
99
rating: extension.rating ?? 0,
100
categories: extension.categories ?? [],
101
tags: extension.gallery?.tags ?? []
102
});
103
}
104
};
105
106
const queryAndAddExtensions = async (text: string) => {
107
const extensions = await this.extensionWorkbenchService.queryGallery({
108
text,
109
pageSize: 10,
110
sortBy: SortBy.InstallCount
111
}, token);
112
if (extensions.firstPage.length) {
113
addExtension(extensions.firstPage);
114
}
115
};
116
117
// Search for extensions by their ids
118
if (params.ids?.length) {
119
const extensions = await this.extensionWorkbenchService.getExtensions(params.ids.map(id => ({ id })), token);
120
addExtension(extensions);
121
}
122
123
if (params.keywords?.length) {
124
for (const keyword of params.keywords ?? []) {
125
if (keyword === 'featured') {
126
await queryAndAddExtensions('featured');
127
} else {
128
let text = params.category ? `category:"${params.category}"` : '';
129
text = keyword ? `${text} ${keyword}`.trim() : text;
130
await queryAndAddExtensions(text);
131
}
132
}
133
} else {
134
await queryAndAddExtensions(`category:"${params.category}"`);
135
}
136
137
const result = Array.from(extensionsMap.values());
138
139
return {
140
content: [{
141
kind: 'text',
142
value: `Here are the list of extensions:\n${JSON.stringify(result)}\n. Important: Use the following format to display extensions to the user because there is a renderer available to parse these extensions in this format and display them with all details. So, do not describe about the extensions to the user.\n\`\`\`vscode-extensions\nextensionId1,extensionId2\n\`\`\`\n.`
143
}],
144
toolResultDetails: {
145
input: JSON.stringify(params),
146
output: [{ type: 'embed', isText: true, value: JSON.stringify(result.map(extension => extension.id)) }]
147
}
148
};
149
}
150
}
151
152