tools: remove tool limit warning (#290581)

Virtual tools are pretty good now, and with the upcoming tool search tool
for Anthropic models it no longer makes sense to maintain a warning about
them.

- Remove 'too many tools enabled' warning indicator from configure tools action
- Remove tool limit validation message from tool picker
- Remove chatToolCount context key
- Remove chatToolGroupingThreshold context key
- Remove autorun that tracked enabled tool count in chat input

(Commit message generated by Copilot)
This commit is contained in:
Connor Peet
2026-01-26 15:02:20 -08:00
committed by GitHub
parent 31df641218
commit b16a2f58d6
5 changed files with 3 additions and 140 deletions

View File

@@ -7,7 +7,7 @@
{
"kind": 2,
"language": "github-issues",
"value": "// list of repos we work in\n$REPOS=repo:microsoft/lsprotocol repo:microsoft/monaco-editor repo:microsoft/vscode repo:microsoft/vscode-anycode repo:microsoft/vscode-autopep8 repo:microsoft/vscode-black-formatter repo:microsoft/vscode-copilot repo:microsoft/vscode-copilot-release repo:microsoft/vscode-dev repo:microsoft/vscode-dev-chrome-launcher repo:microsoft/vscode-emmet-helper repo:microsoft/vscode-extension-telemetry repo:microsoft/vscode-flake8 repo:microsoft/vscode-github-issue-notebooks repo:microsoft/vscode-hexeditor repo:microsoft/vscode-internalbacklog repo:microsoft/vscode-isort repo:microsoft/vscode-js-debug repo:microsoft/vscode-jupyter repo:microsoft/vscode-jupyter-internal repo:microsoft/vscode-l10n repo:microsoft/vscode-livepreview repo:microsoft/vscode-markdown-languageservice repo:microsoft/vscode-markdown-tm-grammar repo:microsoft/vscode-mypy repo:microsoft/vscode-pull-request-github repo:microsoft/vscode-pylint repo:microsoft/vscode-python repo:microsoft/vscode-python-debugger repo:microsoft/vscode-python-tools-extension-template repo:microsoft/vscode-references-view repo:microsoft/vscode-remote-release repo:microsoft/vscode-remote-repositories-github repo:microsoft/vscode-remote-tunnels repo:microsoft/vscode-remotehub repo:microsoft/vscode-settings-sync-server repo:microsoft/vscode-unpkg repo:microsoft/vscode-vsce repo:microsoft/vscode-copilot-issues repo:microsoft/vscode-extension-samples\n\n// current milestone name\n$MILESTONE=milestone:\"December 2025\"\n"
"value": "// list of repos we work in\n$REPOS=repo:microsoft/lsprotocol repo:microsoft/monaco-editor repo:microsoft/vscode repo:microsoft/vscode-anycode repo:microsoft/vscode-autopep8 repo:microsoft/vscode-black-formatter repo:microsoft/vscode-copilot repo:microsoft/vscode-copilot-release repo:microsoft/vscode-dev repo:microsoft/vscode-dev-chrome-launcher repo:microsoft/vscode-emmet-helper repo:microsoft/vscode-extension-telemetry repo:microsoft/vscode-flake8 repo:microsoft/vscode-github-issue-notebooks repo:microsoft/vscode-hexeditor repo:microsoft/vscode-internalbacklog repo:microsoft/vscode-isort repo:microsoft/vscode-js-debug repo:microsoft/vscode-jupyter repo:microsoft/vscode-jupyter-internal repo:microsoft/vscode-l10n repo:microsoft/vscode-livepreview repo:microsoft/vscode-markdown-languageservice repo:microsoft/vscode-markdown-tm-grammar repo:microsoft/vscode-mypy repo:microsoft/vscode-pull-request-github repo:microsoft/vscode-pylint repo:microsoft/vscode-python repo:microsoft/vscode-python-debugger repo:microsoft/vscode-python-tools-extension-template repo:microsoft/vscode-references-view repo:microsoft/vscode-remote-release repo:microsoft/vscode-remote-repositories-github repo:microsoft/vscode-remote-tunnels repo:microsoft/vscode-remotehub repo:microsoft/vscode-settings-sync-server repo:microsoft/vscode-unpkg repo:microsoft/vscode-vsce repo:microsoft/vscode-copilot-issues repo:microsoft/vscode-extension-samples\n\n// current milestone name\n$MILESTONE=milestone:\"January 2026\"\n"
},
{
"kind": 1,

View File

@@ -3,24 +3,18 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
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';
import { IActionViewItemService } from '../../../../../platform/actions/browser/actionViewItemService.js';
import { MenuEntryActionViewItem } from '../../../../../platform/actions/browser/menuEntryActionViewItem.js';
import { Action2, MenuId, MenuItemAction, registerAction2 } from '../../../../../platform/actions/common/actions.js';
import { Action2, MenuId, registerAction2 } from '../../../../../platform/actions/common/actions.js';
import { ContextKeyExpr } from '../../../../../platform/contextkey/common/contextkey.js';
import { IInstantiationService } from '../../../../../platform/instantiation/common/instantiation.js';
import { KeybindingWeight } from '../../../../../platform/keybinding/common/keybindingsRegistry.js';
import { ITelemetryService } from '../../../../../platform/telemetry/common/telemetry.js';
import { IWorkbenchContribution, registerWorkbenchContribution2, WorkbenchPhase } from '../../../../common/contributions.js';
import { ChatContextKeys } from '../../common/actions/chatContextKeys.js';
import { ConfirmedReason, IChatToolInvocation, ToolConfirmKind } from '../../common/chatService/chatService.js';
import { isResponseVM } from '../../common/model/chatViewModel.js';
@@ -234,80 +228,8 @@ class ConfigureToolsAction extends Action2 {
}
}
class ConfigureToolsActionRendering implements IWorkbenchContribution {
static readonly ID = 'chat.configureToolsActionRendering';
constructor(
@IActionViewItemService actionViewItemService: IActionViewItemService,
) {
const disposable = actionViewItemService.register(MenuId.ChatInput, ConfigureToolsAction.ID, (action, _opts, instantiationService) => {
if (!(action instanceof MenuItemAction)) {
return undefined;
}
return instantiationService.createInstance(class extends MenuEntryActionViewItem {
private warningElement!: HTMLElement;
override render(container: HTMLElement): void {
super.render(container);
// Add warning indicator element
this.warningElement = $(`.tool-warning-indicator${ThemeIcon.asCSSSelector(Codicon.warning)}`);
this.warningElement.style.display = 'none';
container.appendChild(this.warningElement);
container.style.position = 'relative';
// Set up context key listeners
this.updateWarningState();
this._register(this._contextKeyService.onDidChangeContext(() => {
this.updateWarningState();
}));
}
private updateWarningState(): void {
const wasShown = this.warningElement.style.display === 'block';
const shouldBeShown = this.isAboveToolLimit();
if (!wasShown && shouldBeShown) {
this.warningElement.style.display = 'block';
this.updateTooltip();
} else if (wasShown && !shouldBeShown) {
this.warningElement.style.display = 'none';
this.updateTooltip();
}
}
protected override getTooltip(): string {
if (this.isAboveToolLimit()) {
const warningMessage = localize('chatTools.tooManyEnabled', 'More than {0} tools are enabled, you may experience degraded tool calling.', this._contextKeyService.getContextKeyValue(ChatContextKeys.chatToolGroupingThreshold.key));
return `${warningMessage}`;
}
return super.getTooltip();
}
private isAboveToolLimit() {
const rawToolLimit = this._contextKeyService.getContextKeyValue(ChatContextKeys.chatToolGroupingThreshold.key);
const rawToolCount = this._contextKeyService.getContextKeyValue(ChatContextKeys.chatToolCount.key);
if (rawToolLimit === undefined || rawToolCount === undefined) {
return false;
}
const toolLimit = Number(rawToolLimit || 0);
const toolCount = Number(rawToolCount || 0);
return toolCount > toolLimit;
}
}, action, undefined);
});
// Reduces flicker a bit on reload/restart
markAsSingleton(disposable);
}
}
export function registerChatToolActions() {
registerAction2(AcceptToolConfirmation);
registerAction2(SkipToolConfirmation);
registerAction2(ConfigureToolsAction);
registerWorkbenchContribution2(ConfigureToolsActionRendering.ID, ConfigureToolsActionRendering, WorkbenchPhase.BlockRestore);
}

View File

@@ -6,14 +6,11 @@ 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';
import { DisposableStore } from '../../../../../base/common/lifecycle.js';
import Severity from '../../../../../base/common/severity.js';
import { ThemeIcon } from '../../../../../base/common/themables.js';
import { URI } from '../../../../../base/common/uri.js';
import { localize } from '../../../../../nls.js';
import { CommandsRegistry, ICommandService } from '../../../../../platform/commands/common/commands.js';
import { IContextKeyService } from '../../../../../platform/contextkey/common/contextkey.js';
import { ICommandService } from '../../../../../platform/commands/common/commands.js';
import { ExtensionIdentifier } from '../../../../../platform/extensions/common/extensions.js';
import { ServicesAccessor } from '../../../../../platform/instantiation/common/instantiation.js';
import { IQuickInputButton, IQuickInputService, IQuickPickItem, IQuickTreeItem } from '../../../../../platform/quickinput/common/quickInput.js';
@@ -24,7 +21,6 @@ import { McpCommandIds } from '../../../mcp/common/mcpCommandIds.js';
import { IMcpRegistry } from '../../../mcp/common/mcpRegistryTypes.js';
import { IMcpServer, IMcpService, IMcpWorkbenchService, McpConnectionState, McpServerCacheState, McpServerEditorTab } from '../../../mcp/common/mcpTypes.js';
import { startServerAndWaitForLiveTools } from '../../../mcp/common/mcpTypesUtils.js';
import { ChatContextKeys } from '../../common/actions/chatContextKeys.js';
import { ILanguageModelChatMetadata } from '../../common/languageModels.js';
import { ILanguageModelToolsService, IToolData, IToolSet, ToolDataSource, ToolSet } from '../../common/tools/languageModelToolsService.js';
import { ConfigureToolSets } from '../tools/toolSetsContribution.js';
@@ -210,7 +206,6 @@ export async function showToolsPicker(
const mcpWorkbenchService = accessor.get(IMcpWorkbenchService);
const toolsService = accessor.get(ILanguageModelToolsService);
const telemetryService = accessor.get(ITelemetryService);
const toolLimit = accessor.get(IContextKeyService).getContextKeyValue<number>(ChatContextKeys.chatToolGroupingThreshold.key);
const mcpServerByTool = new Map<string, IMcpServer>();
for (const server of mcpService.servers.get()) {
@@ -484,32 +479,6 @@ export async function showToolsPicker(
}
}));
const updateToolLimitMessage = () => {
if (toolLimit) {
let count = 0;
const traverse = (items: readonly AnyTreeItem[]) => {
for (const item of items) {
if (isBucketTreeItem(item) || isToolSetTreeItem(item)) {
if (item.children) {
traverse(item.children);
}
} else if (isToolTreeItem(item) && item.checked) {
count++;
}
}
};
traverse(treePicker.itemTree);
if (count > toolLimit) {
treePicker.severity = Severity.Warning;
treePicker.validationMessage = localize('toolLimitExceeded', "{0} tools are enabled. You may experience degraded tool calling above {1} tools.", count, createMarkdownCommandLink({ title: String(toolLimit), id: '_chat.toolPicker.closeAndOpenVirtualThreshold' }));
} else {
treePicker.severity = Severity.Ignore;
treePicker.validationMessage = undefined;
}
}
};
updateToolLimitMessage();
const collectResults = () => {
const result = new Map<IToolData | IToolSet, boolean>();
@@ -537,18 +506,6 @@ export async function showToolsPicker(
return result;
};
// Temporary command to close the picker and open settings, for use in the validation message
store.add(CommandsRegistry.registerCommand({
id: '_chat.toolPicker.closeAndOpenVirtualThreshold',
handler: () => {
treePicker.hide();
commandService.executeCommand('workbench.action.openSettings', 'github.copilot.chat.virtualTools.threshold');
}
}));
// Handle checkbox state changes
store.add(treePicker.onDidChangeCheckedLeafItems(() => updateToolLimitMessage()));
// Handle acceptance
let didAccept = false;
const didAcceptFinalItem = store.add(new Emitter<void>());

View File

@@ -535,20 +535,6 @@ export class ChatInputPart extends Disposable implements IHistoryNavigationWidge
}
this.chatSessionHasCustomAgentTarget = ChatContextKeys.chatSessionHasCustomAgentTarget.bindTo(contextKeyService);
const chatToolCount = ChatContextKeys.chatToolCount.bindTo(contextKeyService);
this._register(autorun(reader => {
let count = 0;
const userSelectedTools = this.selectedToolsModel.userSelectedTools.read(reader);
for (const key in userSelectedTools) {
if (userSelectedTools[key] === true) {
count++;
}
}
chatToolCount.set(count);
}));
this.history = this._register(this.instantiationService.createInstance(ChatHistoryNavigator, this.location));
this._register(this.configurationService.onDidChangeConfiguration(e => {

View File

@@ -35,8 +35,6 @@ export namespace ChatContextKeys {
export const inChatEditor = new RawContextKey<boolean>('inChatEditor', false, { type: 'boolean', description: localize('inChatEditor', "Whether focus is in a chat editor.") });
export const inChatTerminalToolOutput = new RawContextKey<boolean>('inChatTerminalToolOutput', false, { type: 'boolean', description: localize('inChatTerminalToolOutput', "True when focus is in the chat terminal output region.") });
export const chatModeKind = new RawContextKey<ChatModeKind>('chatAgentKind', ChatModeKind.Ask, { type: 'string', description: localize('agentKind', "The 'kind' of the current agent.") });
export const chatToolCount = new RawContextKey<number>('chatToolCount', 0, { type: 'number', description: localize('chatToolCount', "The number of tools available in the current agent.") });
export const chatToolGroupingThreshold = new RawContextKey<number>('chat.toolGroupingThreshold', 0, { type: 'number', description: localize('chatToolGroupingThreshold', "The number of tools at which we start doing virtual grouping.") });
export const supported = ContextKeyExpr.or(IsWebContext.negate(), RemoteNameContext.notEqualsTo(''), ContextKeyExpr.has('config.chat.experimental.serverlessWebEnabled'));
export const enabled = new RawContextKey<boolean>('chatIsEnabled', false, { type: 'boolean', description: localize('chatIsEnabled', "True when chat is enabled because a default chat participant is activated with an implementation.") });