Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 19 additions & 3 deletions src/vs/workbench/contrib/chat/browser/actions/chatToolActions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,12 @@
*--------------------------------------------------------------------------------------------*/

import { $ } from '../../../../../base/browser/dom.js';
import { CancellationTokenSource } from '../../../../../base/common/cancellation.js';
import { Codicon } from '../../../../../base/common/codicons.js';
import { Iterable } from '../../../../../base/common/iterator.js';
import { KeyCode, KeyMod } from '../../../../../base/common/keyCodes.js';
import { markAsSingleton } from '../../../../../base/common/lifecycle.js';
import { autorun } from '../../../../../base/common/observable.js';
import { ThemeIcon } from '../../../../../base/common/themables.js';
import { ServicesAccessor } from '../../../../../editor/browser/editorExtensions.js';
import { localize, localize2 } from '../../../../../nls.js';
Expand Down Expand Up @@ -176,9 +178,23 @@ class ConfigureToolsAction extends Action2 {

}

const result = await instaService.invokeFunction(showToolsPicker, placeholder, description, () => entriesMap.get());
if (result) {
widget.input.selectedToolsModel.set(result, false);
// Create a cancellation token that cancels when the mode changes
const cts = new CancellationTokenSource();
const initialMode = widget.input.currentModeObs.get();
const modeListener = autorun(reader => {
if (initialMode.id !== widget.input.currentModeObs.read(reader).id) {
cts.cancel();
}
});

try {
const result = await instaService.invokeFunction(showToolsPicker, placeholder, description, () => entriesMap.get(), cts.token);
if (result) {
widget.input.selectedToolsModel.set(result, false);
}
} finally {
modeListener.dispose();
cts.dispose();
}

const tools = widget.input.selectedToolsModel.entriesMap.get();
Expand Down
13 changes: 11 additions & 2 deletions src/vs/workbench/contrib/chat/browser/actions/chatToolPicker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { assertNever } from '../../../../../base/common/assert.js';
import { CancellationToken } from '../../../../../base/common/cancellation.js';
import { Codicon } from '../../../../../base/common/codicons.js';
import { Emitter, Event } from '../../../../../base/common/event.js';
import { createMarkdownCommandLink } from '../../../../../base/common/htmlContent.js';
Expand Down Expand Up @@ -183,14 +184,15 @@ function createToolSetTreeItem(toolset: ToolSet, checked: boolean, editorService
* @param placeHolder - Placeholder text shown in the picker
* @param description - Optional description text shown in the picker
* @param toolsEntries - Optional initial selection state for tools and toolsets
* @param onUpdate - Optional callback fired when the selection changes
* @param token - Optional cancellation token to close the picker when cancelled
* @returns Promise resolving to the final selection map, or undefined if cancelled
*/
export async function showToolsPicker(
accessor: ServicesAccessor,
placeHolder: string,
description?: string,
getToolsEntries?: () => ReadonlyMap<ToolSet | IToolData, boolean>
getToolsEntries?: () => ReadonlyMap<ToolSet | IToolData, boolean>,
token?: CancellationToken
): Promise<ReadonlyMap<ToolSet | IToolData, boolean> | undefined> {

const quickPickService = accessor.get(IQuickInputService);
Expand Down Expand Up @@ -584,6 +586,13 @@ export async function showToolsPicker(
treePicker.hide();
}));

// Close picker when cancelled (e.g., when mode changes)
if (token) {
store.add(token.onCancellationRequested(() => {
treePicker.hide();
}));
}

treePicker.show();

await Promise.race([Event.toPromise(Event.any(treePicker.onDidHide, didAcceptFinalItem.event), store)]);
Expand Down
Loading