Skip to content
Draft
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
2 changes: 1 addition & 1 deletion docs/users/configuration/settings.md
Original file line number Diff line number Diff line change
Expand Up @@ -378,7 +378,7 @@ If you are experiencing performance issues with file searching (e.g., with `@` c
| `tools.workflowsEnabled` | boolean | Enable the Workflow tool, which lets the model author and run a script that orchestrates subagents in parallel. Off by default; a run can dispatch many subagents and spend tokens accordingly. | `false` | User, System, and SystemDefaults scopes only; workspace values are ignored. Requires restart: Yes. Env overrides: `QWEN_CODE_ENABLE_WORKFLOWS=1` forces on; `QWEN_CODE_DISABLE_WORKFLOWS=1` forces off (disable wins). |
| `tools.truncateToolOutputThreshold` | number | Truncate tool output if it is larger than this many characters. Applies to Shell, Grep, Glob, ReadFile and ReadManyFiles tools. | `25000` | Requires restart: Yes |
| `tools.truncateToolOutputLines` | number | Maximum lines or entries kept when truncating tool output. Applies to Shell, Grep, Glob, ReadFile and ReadManyFiles tools. | `1000` | Requires restart: Yes |
| `tools.toolSearch.enabled` | boolean | Load MCP tools on demand via ToolSearch to reduce prompt size. Disable this for models that rely on prefix-based KV caching (e.g. DeepSeek) to keep the prompt prefix stable and maximize cache hit rates. | `true` | Requires restart: Yes |
| `tools.toolSearch.enabled` | boolean | Let deferred bundled and MCP tools load on demand via ToolSearch to reduce prompt size. Disable this only when every deferred tool should be declared up front. | `true` | Requires restart: Yes |
| `tools.toolSearch.threshold` | number | Context-window percentage used as the session-start budget for preloading ordinary deferred tools (bundled built-ins and MCP alike). When their combined schemas fit within this budget, they are declared upfront instead of loaded on demand via ToolSearch. Tools demoted by `tools.eager` are excluded from this preload and stay on demand. Set `0` to always load deferred tools on demand. | `10` | Requires restart: Yes |
| `tools.listDirectory.enabled` | boolean | Enable the built-in `list_directory` tool. Disabled by default because `glob` covers directory listing in most cases; the tool is also re-enabled automatically when explicitly listed in the `coreTools` allowlist (`--core-tools` / `tools.core`). | `false` | Requires restart: Yes |

Expand Down
48 changes: 7 additions & 41 deletions packages/cli/src/config/config.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2758,53 +2758,19 @@ describe('mergeExcludeTools', () => {
expect(config.getPermissionsDeny()).toContain('tool_search');
});

it('should auto-disable tool_search for deepseek-v4 models', async () => {
process.argv = ['node', 'script.js', '--model', 'deepseek-v4-flash'];
const argv = await parseArguments();
const settings: Settings = {};
const config = await loadCliConfig(settings, argv, undefined, []);
expect(config.getPermissionsDeny()).toContain('tool_search');
});

it('should auto-disable tool_search for deepseek-v3 models', async () => {
process.argv = ['node', 'script.js', '--model', 'deepseek-v3'];
const argv = await parseArguments();
const settings: Settings = {};
const config = await loadCliConfig(settings, argv, undefined, []);
expect(config.getPermissionsDeny()).toContain('tool_search');
});

it('should auto-disable tool_search for deepseek-chat models with provider prefix', async () => {
process.argv = [
'node',
'script.js',
'--model',
'openrouter/deepseek/deepseek-chat',
];
const argv = await parseArguments();
const settings: Settings = {};
const config = await loadCliConfig(settings, argv, undefined, []);
expect(config.getPermissionsDeny()).toContain('tool_search');
});

it('should not auto-disable tool_search for non-deepseek models', async () => {
process.argv = ['node', 'script.js', '--model', 'qwen-max'];
it.each([
'deepseek-v4-flash',
'deepseek-v3',
'openrouter/deepseek/deepseek-chat',
'qwen-max',
])('should enable tool_search by default for %s', async (model) => {
process.argv = ['node', 'script.js', '--model', model];
const argv = await parseArguments();
const settings: Settings = {};
const config = await loadCliConfig(settings, argv, undefined, []);
expect(config.getPermissionsDeny()).not.toContain('tool_search');
});

it('should respect explicit enabled:true override for deepseek models', async () => {
process.argv = ['node', 'script.js', '--model', 'deepseek-v4-flash'];
const argv = await parseArguments();
const settings: Settings = {
tools: { toolSearch: { enabled: true } },
};
const config = await loadCliConfig(settings, argv, undefined, []);
expect(config.getPermissionsDeny()).not.toContain('tool_search');
});

it('should pass tools.toolSearch.threshold through to the config', async () => {
process.argv = ['node', 'script.js'];
const argv = await parseArguments();
Expand Down
17 changes: 1 addition & 16 deletions packages/cli/src/config/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1992,22 +1992,7 @@ export async function loadCliConfig(

const { model: resolvedModel } = resolvedCliConfig;

// Disable ToolSearch when explicitly configured or for models that benefit
// from prefix-based KV caching. DeepSeek models (v3, v4, deepseek-chat)
// all use prefix-based disk KV caching with heavily discounted cached
// token pricing (up to 1/120 for v4). When tool_search is in the deny
// list, client.ts eagerly reveals all deferred tools so every MCP tool
// schema is in the initial declaration list, keeping the prompt prefix
// stable and maximizing cache hit rates.
// Note: no `^` anchor — model names may include a provider prefix
// (e.g. "openrouter/deepseek/deepseek-v4-flash").
const toolSearchExplicitlyEnabled = settings.tools?.toolSearch?.enabled;
const shouldDisableToolSearch =
toolSearchExplicitlyEnabled === false ||
(toolSearchExplicitlyEnabled === undefined &&
resolvedModel !== undefined &&
/deepseek-(v3|v4|chat)/i.test(resolvedModel));
if (shouldDisableToolSearch) {
if (settings.tools?.toolSearch?.enabled === false) {
if (!mergedDeny.includes('tool_search')) {
mergedDeny.push('tool_search');
}
Expand Down
2 changes: 1 addition & 1 deletion packages/cli/src/config/settingsSchema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2629,7 +2629,7 @@ const SETTINGS_SCHEMA = {
requiresRestart: true,
default: true,
description:
'When enabled, MCP tools are loaded on-demand via ToolSearch to reduce prompt size. Disable this for models that rely on prefix-based KV caching (e.g. DeepSeek) to keep the prompt prefix stable and maximize cache hit rates.',
'When enabled, deferred bundled and MCP tools can be loaded on demand via ToolSearch to reduce prompt size. Disable this only when every deferred tool should be declared up front.',
showInDialog: true,
},
threshold: {
Expand Down
2 changes: 1 addition & 1 deletion packages/vscode-ide-companion/schemas/settings.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -1240,7 +1240,7 @@
"type": "object",
"properties": {
"enabled": {
"description": "When enabled, MCP tools are loaded on-demand via ToolSearch to reduce prompt size. Disable this for models that rely on prefix-based KV caching (e.g. DeepSeek) to keep the prompt prefix stable and maximize cache hit rates.",
"description": "When enabled, deferred bundled and MCP tools can be loaded on demand via ToolSearch to reduce prompt size. Disable this only when every deferred tool should be declared up front.",
"type": "boolean",
"default": true
},
Expand Down
2 changes: 1 addition & 1 deletion packages/web-shell/client/i18n.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6133,7 +6133,7 @@ const ZH: Messages = {
'搜索文件时启用模糊搜索。',
'settings.label.tools.toolSearch.enabled': '启用 ToolSearch',
'settings.description.tools.toolSearch.enabled':
'启用后,MCP 工具会通过 ToolSearch 按需加载,以减少提示词大小。对于依赖前缀 KV 缓存的模型(如 DeepSeek),可关闭此项来保持提示词前缀稳定并提高缓存命中率。',
'启用后,延迟加载的内置和 MCP 工具可通过 ToolSearch 按需加载,以减少提示词大小。仅当需要预先声明所有延迟工具时才关闭此项。',
'settings.label.tools.shell.enableInteractiveShell': '交互式 Shell(PTY)',
'settings.description.tools.shell.enableInteractiveShell':
'使用 node-pty 提供交互式 shell 体验。PTY 不可用时回退到 child_process。',
Expand Down
Loading