diff --git a/src/vs/workbench/contrib/chat/browser/actions/chatToolActions.ts b/src/vs/workbench/contrib/chat/browser/actions/chatToolActions.ts index 602f3d41beda7..9d420cfad24fb 100644 --- a/src/vs/workbench/contrib/chat/browser/actions/chatToolActions.ts +++ b/src/vs/workbench/contrib/chat/browser/actions/chatToolActions.ts @@ -143,9 +143,24 @@ export class AttachToolsAction extends Action2 { const enum BucketOrdinal { Extension, Mcp, Other } type BucketPick = IQuickPickItem & { picked: boolean; ordinal: BucketOrdinal; status?: string; children: ToolPick[]; source: ToolDataSource }; type ToolPick = IQuickPickItem & { picked: boolean; tool: IToolData; parent: BucketPick }; - type AddPick = IQuickPickItem & { add: 'server' | 'ext'; pickable: false }; + type AddPick = IQuickPickItem & { pickable: false; run: () => void }; type MyPick = ToolPick | BucketPick | AddPick; + const addMcpPick: AddPick = { type: 'item', label: localize('addServer', "Add MCP Server..."), iconClass: ThemeIcon.asClassName(Codicon.add), pickable: false, run: () => commandService.executeCommand(AddConfigurationAction.ID) }; + const addExpPick: AddPick = { type: 'item', label: localize('addExtension', "Install Extension..."), iconClass: ThemeIcon.asClassName(Codicon.add), pickable: false, run: () => extensionWorkbenchService.openSearch('@tag:language-model-tools') }; + const addPick: AddPick = { + type: 'item', label: localize('addAny', "Add More Tools..."), iconClass: ThemeIcon.asClassName(Codicon.add), pickable: false, run: async () => { + const pick = await quickPickService.pick( + [addMcpPick, addExpPick], + { + canPickMany: false, + title: localize('noTools', "Add tools to chat") + } + ); + pick?.run(); + } + }; + const defaultBucket: BucketPick = { type: 'item', children: [], @@ -225,14 +240,13 @@ export class AttachToolsAction extends Action2 { function isToolPick(obj: any): obj is ToolPick { return Boolean((obj as ToolPick).tool); } + function isAddPick(obj: any): obj is AddPick { + return Boolean((obj as AddPick).run); + } const store = new DisposableStore(); - const picker = store.add(quickPickService.createQuickPick({ useSeparators: true })); - const picks: (MyPick | IQuickPickSeparator)[] = [ - { add: 'server', type: 'item', label: localize('addServer', "Add MCP Server..."), iconClass: ThemeIcon.asClassName(Codicon.add), pickable: false }, - { add: 'ext', type: 'item', label: localize('addExtension', "Install Extension..."), iconClass: ThemeIcon.asClassName(Codicon.add), pickable: false }, - ]; + const picks: (MyPick | IQuickPickSeparator)[] = []; for (const bucket of Array.from(toolBuckets.values()).sort((a, b) => a.ordinal - b.ordinal)) { picks.push({ @@ -244,12 +258,27 @@ export class AttachToolsAction extends Action2 { picks.push(...bucket.children); } - + const picker = store.add(quickPickService.createQuickPick({ useSeparators: true })); picker.placeholder = localize('placeholder', "Select tools that are available to chat"); picker.canSelectMany = true; picker.keepScrollPosition = true; picker.matchOnDescription = true; + if (picks.length === 0) { + picker.placeholder = localize('noTools', "Add tools to chat"); + picker.canSelectMany = false; + picks.push( + addMcpPick, + addExpPick, + ); + } else { + picks.push( + { type: 'separator' }, + addPick, + ); + } + + let lastSelectedItems = new Set(); let ignoreEvent = false; @@ -287,15 +316,9 @@ export class AttachToolsAction extends Action2 { return; } - const addPick = selectedPicks.find(p => 'add' in p); + const addPick = selectedPicks.find(isAddPick); if (addPick) { - if (addPick.add === 'ext') { - extensionWorkbenchService.openSearch('@tag:language-model-tools'); - } else if (addPick.add === 'server') { - commandService.executeCommand(AddConfigurationAction.ID); - } else { - assertNever(addPick.add); - } + addPick.run(); picker.hide(); return; }