Skip to content

Commit 6bffcf0

Browse files
authored
fix enablement of mcp tool sets and tools (microsoft#255739)
1 parent b4d1fec commit 6bffcf0

File tree

3 files changed

+46
-24
lines changed

3 files changed

+46
-24
lines changed

src/vs/workbench/contrib/chat/browser/actions/chatToolPicker.ts

Lines changed: 21 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,9 @@ export async function showToolsPicker(
109109
if (!toolsEntries) {
110110
const defaultEntries = new Map();
111111
for (const tool of toolsService.getTools()) {
112-
defaultEntries.set(tool, false);
112+
if (tool.canBeReferencedInPrompt) {
113+
defaultEntries.set(tool, false);
114+
}
113115
}
114116
for (const toolSet of toolsService.toolSets.get()) {
115117
defaultEntries.set(toolSet, false);
@@ -210,8 +212,8 @@ export async function showToolsPicker(
210212
} else {
211213
// stash the MCP toolset into the bucket item
212214
bucket.toolset = toolSetOrTool;
215+
bucket.picked = picked;
213216
}
214-
215217
} else if (toolSetOrTool.canBeReferencedInPrompt) {
216218
bucket.children.push({
217219
parent: bucket,
@@ -223,10 +225,6 @@ export async function showToolsPicker(
223225
indented: true,
224226
});
225227
}
226-
227-
if (picked) {
228-
bucket.picked = true;
229-
}
230228
}
231229

232230
for (const bucket of [builtinBucket, userBucket]) {
@@ -235,6 +233,21 @@ export async function showToolsPicker(
235233
}
236234
}
237235

236+
// set the checkmarks in the UI:
237+
// bucket is checked if at least one of the children is checked
238+
// tool is checked if the bucket is checked or the tool itself is checked
239+
for (const bucket of toolBuckets.values()) {
240+
if (bucket.picked) {
241+
// check all children if the bucket is checked
242+
for (const child of bucket.children) {
243+
child.picked = true;
244+
}
245+
} else {
246+
// check the bucket if one of the children is checked
247+
bucket.picked = bucket.children.some(child => child.picked);
248+
}
249+
}
250+
238251
const store = new DisposableStore();
239252

240253
const picks: (AnyPick | IQuickPickSeparator)[] = [];
@@ -393,23 +406,12 @@ export async function showToolsPicker(
393406

394407
store.dispose();
395408

396-
const mcpToolSets = new Set<ToolSet>();
397-
409+
// in the result, a MCP toolset is only enabled if all tools in the toolset are enabled
398410
for (const item of toolsService.toolSets.get()) {
399411
if (item.source.type === 'mcp') {
400-
mcpToolSets.add(item);
401-
402412
const toolsInSet = Array.from(item.getTools());
403-
if (toolsInSet.length && toolsInSet.every(tool => result.get(tool))) {
404-
// ALL tools from the MCP tool set are here, replace them with just the toolset
405-
// but only when computing the final result
406-
for (const tool of toolsInSet) {
407-
result.delete(tool);
408-
}
409-
result.set(item, true);
410-
}
413+
result.set(item, toolsInSet.every(tool => result.get(tool)));
411414
}
412415
}
413-
414416
return didAccept ? result : undefined;
415417
}

src/vs/workbench/contrib/chat/browser/languageModelToolsService.ts

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -492,11 +492,23 @@ export class LanguageModelToolsService extends Disposable implements ILanguageMo
492492
toToolAndToolSetEnablementMap(enabledToolOrToolSetNames: readonly string[] | undefined): Map<ToolSet | IToolData, boolean> {
493493
const toolOrToolSetNames = enabledToolOrToolSetNames ? new Set(enabledToolOrToolSetNames) : undefined;
494494
const result = new Map<ToolSet | IToolData, boolean>();
495-
for (const tool of this._tools.values()) {
496-
result.set(tool.data, tool.data.toolReferenceName !== undefined && (toolOrToolSetNames === undefined || toolOrToolSetNames.has(tool.data.toolReferenceName)));
495+
for (const tool of this.getTools()) {
496+
if (tool.canBeReferencedInPrompt) {
497+
result.set(tool, toolOrToolSetNames === undefined || toolOrToolSetNames.has(tool.toolReferenceName ?? tool.displayName));
498+
}
497499
}
498500
for (const toolSet of this._toolSets) {
499-
result.set(toolSet, (toolOrToolSetNames === undefined || toolOrToolSetNames.has(toolSet.referenceName)));
501+
const enabled = toolOrToolSetNames === undefined || toolOrToolSetNames.has(toolSet.referenceName);
502+
result.set(toolSet, enabled);
503+
504+
// if a mcp toolset is enabled, all tools in it are enabled
505+
if (enabled && toolSet.source.type === 'mcp') {
506+
for (const tool of toolSet.getTools()) {
507+
if (tool.canBeReferencedInPrompt) {
508+
result.set(tool, enabled);
509+
}
510+
}
511+
}
500512
}
501513
return result;
502514
}

src/vs/workbench/contrib/chat/browser/promptSyntax/promptFileRewriter.ts

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import { ICodeEditorService } from '../../../../../editor/browser/services/codeE
99
import { EditOperation } from '../../../../../editor/common/core/editOperation.js';
1010
import { Range } from '../../../../../editor/common/core/range.js';
1111
import { ITextModel } from '../../../../../editor/common/model.js';
12-
import { IToolAndToolSetEnablementMap, ToolSet } from '../../common/languageModelToolsService.js';
12+
import { IToolAndToolSetEnablementMap, IToolData, ToolSet } from '../../common/languageModelToolsService.js';
1313
import { IPromptsService } from '../../common/promptSyntax/service/promptsService.js';
1414

1515
export class PromptFileRewriter {
@@ -59,11 +59,19 @@ export class PromptFileRewriter {
5959
model.pushStackElement();
6060
return;
6161
}
62+
const toolsCoveredBySets = new Set<IToolData>();
63+
for (const [item, picked] of newTools) {
64+
if (picked && item instanceof ToolSet) {
65+
for (const tool of item.getTools()) {
66+
toolsCoveredBySets.add(tool);
67+
}
68+
}
69+
}
6270
for (const [item, picked] of newTools) {
6371
if (picked) {
6472
if (item instanceof ToolSet) {
6573
newToolNames.push(item.referenceName);
66-
} else {
74+
} else if (!toolsCoveredBySets.has(item)) {
6775
newToolNames.push(item.toolReferenceName ?? item.displayName);
6876
}
6977
}

0 commit comments

Comments
 (0)