Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/src/vs/workbench/contrib/chat/browser/promptSyntax/promptToolsCodeLensProvider.ts
5255 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 { Disposable } from '../../../../../base/common/lifecycle.js';
8
import { generateUuid } from '../../../../../base/common/uuid.js';
9
import { CodeLens, CodeLensList, CodeLensProvider } from '../../../../../editor/common/languages.js';
10
import { isITextModel, ITextModel } from '../../../../../editor/common/model.js';
11
import { ILanguageFeaturesService } from '../../../../../editor/common/services/languageFeatures.js';
12
import { localize } from '../../../../../nls.js';
13
import { CommandsRegistry } from '../../../../../platform/commands/common/commands.js';
14
import { IInstantiationService } from '../../../../../platform/instantiation/common/instantiation.js';
15
import { showToolsPicker } from '../actions/chatToolPicker.js';
16
import { ILanguageModelToolsService } from '../../common/tools/languageModelToolsService.js';
17
import { ALL_PROMPTS_LANGUAGE_SELECTOR, getPromptsTypeForLanguageId, PromptsType } from '../../common/promptSyntax/promptTypes.js';
18
import { IPromptsService, Target } from '../../common/promptSyntax/service/promptsService.js';
19
import { registerEditorFeature } from '../../../../../editor/common/editorFeatures.js';
20
import { PromptFileRewriter } from './promptFileRewriter.js';
21
import { Range } from '../../../../../editor/common/core/range.js';
22
import { IEditorModel } from '../../../../../editor/common/editorCommon.js';
23
import { isTarget, parseCommaSeparatedList, PromptHeaderAttributes } from '../../common/promptSyntax/promptFileParser.js';
24
import { getTarget, isVSCodeOrDefaultTarget } from '../../common/promptSyntax/languageProviders/promptValidator.js';
25
import { isBoolean } from '../../../../../base/common/types.js';
26
27
class PromptToolsCodeLensProvider extends Disposable implements CodeLensProvider {
28
29
// `_`-prefix marks this as private command
30
private readonly cmdId = `_configure/${generateUuid()}`;
31
32
constructor(
33
@IPromptsService private readonly promptsService: IPromptsService,
34
@ILanguageFeaturesService private readonly languageService: ILanguageFeaturesService,
35
@ILanguageModelToolsService private readonly languageModelToolsService: ILanguageModelToolsService,
36
@IInstantiationService private readonly instantiationService: IInstantiationService,
37
) {
38
super();
39
40
41
this._register(this.languageService.codeLensProvider.register(ALL_PROMPTS_LANGUAGE_SELECTOR, this));
42
43
this._register(CommandsRegistry.registerCommand(this.cmdId, (_accessor, ...args) => {
44
const [modelArg, rangeArg, isStringArg, toolsArg, targetArg] = args;
45
const model = modelArg as IEditorModel;
46
if (isITextModel(model) && Range.isIRange(rangeArg) && isBoolean(isStringArg) && Array.isArray(toolsArg) && isTarget(targetArg)) {
47
this.updateTools(model as ITextModel, Range.lift(rangeArg), isStringArg, toolsArg, targetArg);
48
}
49
}));
50
}
51
52
async provideCodeLenses(model: ITextModel, token: CancellationToken): Promise<undefined | CodeLensList> {
53
const promptType = getPromptsTypeForLanguageId(model.getLanguageId());
54
if (!promptType || promptType === PromptsType.instructions) {
55
// if the model is not a prompt, we don't provide any code actions
56
return undefined;
57
}
58
59
const promptAST = this.promptsService.getParsedPromptFile(model);
60
const header = promptAST.header;
61
if (!header) {
62
return undefined;
63
}
64
65
const target = getTarget(promptType, header);
66
if (!isVSCodeOrDefaultTarget(target)) {
67
return undefined;
68
}
69
70
const toolsAttr = header.getAttribute(PromptHeaderAttributes.tools);
71
if (!toolsAttr) {
72
return undefined;
73
}
74
let value = toolsAttr.value;
75
if (value.type === 'string') {
76
value = parseCommaSeparatedList(value);
77
}
78
if (value.type !== 'array') {
79
return undefined;
80
}
81
const items = value.items;
82
const selectedTools = items.filter(item => item.type === 'string').map(item => item.value);
83
84
const codeLens: CodeLens = {
85
range: toolsAttr.range.collapseToStart(),
86
command: {
87
title: localize('configure-tools.capitalized.ellipsis', "Configure Tools..."),
88
id: this.cmdId,
89
arguments: [model, toolsAttr.range, toolsAttr.value.type === 'string', selectedTools, target]
90
}
91
};
92
return { lenses: [codeLens] };
93
}
94
95
private async updateTools(model: ITextModel, range: Range, isString: boolean, selectedTools: readonly string[], target: Target): Promise<void> {
96
const selectedToolsNow = () => this.languageModelToolsService.toToolAndToolSetEnablementMap(selectedTools, undefined);
97
const newSelectedAfter = await this.instantiationService.invokeFunction(showToolsPicker, localize('placeholder', "Select tools"), 'codeLens', undefined, selectedToolsNow);
98
if (!newSelectedAfter) {
99
return;
100
}
101
this.instantiationService.createInstance(PromptFileRewriter).rewriteTools(model, newSelectedAfter, range, isString);
102
}
103
}
104
105
registerEditorFeature(PromptToolsCodeLensProvider);
106
107