diff --git a/docs/developers/sdk-typescript.md b/docs/developers/sdk-typescript.md index 0dd66af7cb6..5139081085f 100644 --- a/docs/developers/sdk-typescript.md +++ b/docs/developers/sdk-typescript.md @@ -53,27 +53,27 @@ Creates a new query session with the Qwen Code. #### QueryOptions -| Option | Type | Default | Description | -| ------------------------ | -------------------------------------------------------------------- | ---------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `cwd` | `string` | `process.cwd()` | The working directory for the query session. Determines the context in which file operations and commands are executed. | -| `model` | `string` | - | The AI model to use (e.g., `'qwen-max'`, `'qwen-plus'`, `'qwen-turbo'`). Takes precedence over `OPENAI_MODEL` and `QWEN_MODEL` environment variables. | -| `pathToQwenExecutable` | `string` | Bundled CLI | Path to the Qwen Code executable. Supports multiple formats: `'qwen'` (native binary from PATH), `'/path/to/qwen'` (explicit path), `'/path/to/cli.js'` (Node.js bundle), `'node:/path/to/cli.js'` (force Node.js runtime), `'bun:/path/to/cli.js'` (force Bun runtime). If not provided, the SDK uses the bundled CLI included with the package. | -| `permissionMode` | `'default' \| 'plan' \| 'auto-edit' \| 'auto' \| 'yolo'` | `'default'` | Permission mode controlling tool execution approval. See [Permission Modes](#permission-modes) for details. | -| `canUseTool` | `CanUseTool` | - | Custom permission handler for tool execution approval. Invoked when a tool requires confirmation. Must respond within 60 seconds or the request will be auto-denied. See [Custom Permission Handler](#custom-permission-handler). | -| `env` | `Record` | - | Environment variables to pass to the Qwen Code process. Merged with the current process environment. | -| `systemPrompt` | `string \| QuerySystemPromptPreset` | - | System prompt configuration for the main session. Use a string to fully override the built-in Qwen Code system prompt, or a preset object to keep the built-in prompt and append extra instructions. | -| `mcpServers` | `Record` | - | MCP (Model Context Protocol) servers to connect. Supports external servers (stdio/SSE/HTTP) and SDK-embedded servers. External servers are configured with transport options like `command`, `args`, `url`, `httpUrl`, etc. SDK servers use `{ type: 'sdk', name: string, instance: Server }`. | -| `abortController` | `AbortController` | - | Controller to cancel the query session. Call `abortController.abort()` to terminate the session and cleanup resources. | -| `debug` | `boolean` | `false` | Enable debug mode for verbose logging from the CLI process. | -| `maxSessionTurns` | `number` | `-1` (unlimited) | Maximum number of conversation turns before the session automatically terminates. Must be an integer. A turn consists of a user message and an assistant response. | -| `coreTools` | `string[]` | - | Uses the legacy `coreTools` / CLI `--core-tools` allowlist semantics. If specified, only matching core tools are registered for the session. This is the only allowlist-style option that restricts built-in tool registration; a whole-tool `permissions.deny` / `excludeTools` rule (and `tools.disabled` in settings.json) also removes a tool from the registry. `permissions.allow` in settings.json is pure auto-approval and never removes, demotes, or hides a tool (#10075). To keep a tool's schema out of the initial model request, use `tools.eager` in settings.json (requires restart, #9827); to remove it entirely, use a whole-tool `excludeTools` / `permissions.deny` rule — a rule with a specifier (such as `'Bash(rm *)'`) only denies matching invocations at runtime. MCP tools are exempt from deny-based removal: hide them with the per-server `excludeTools` / `tools.disabled` filters instead (deny still blocks their calls at runtime). Example: `['read_file', 'edit', 'run_shell_command']`. | -| `excludeTools` | `string[]` | - | Equivalent to `permissions.deny` in settings.json. Excluded tools return a permission error immediately. Takes highest priority over all other permission settings. Supports tool name aliases and pattern matching: tool name (`'write_file'`), shell command prefix (`'Bash(rm *)'`), or path patterns (`'Read(.env)'`, `'Edit(/src/**)'`). | -| `allowedTools` | `string[]` | - | Equivalent to `permissions.allow` in settings.json for auto-approval. Matching tools bypass `canUseTool` callback and execute automatically. Only applies when tool requires confirmation. Like `permissions.allow`, this is pure auto-approval and never affects which tools are registered or which schemas are sent (#10075). Supports same pattern matching as `excludeTools`. Example: `['Bash(git status)', 'Bash(npm test)']`. | -| `authType` | `'openai' \| 'anthropic' \| 'qwen-oauth' \| 'gemini' \| 'vertex-ai'` | - | Authentication type for the AI service. When provided, the SDK forwards it to the CLI as `--auth-type`. | -| `agents` | `SubagentConfig[]` | - | Configuration for subagents that can be invoked during the session. Subagents are specialized AI agents for specific tasks or domains. | -| `includePartialMessages` | `boolean` | `false` | When `true`, the SDK emits incomplete messages as they are being generated, allowing real-time streaming of the AI's response. | -| `resume` | `string` | - | Resume a previous session by providing its session ID. Equivalent to CLI's `--resume` flag. | -| `sessionId` | `string` | - | Specify a session ID for the new session. Ensures SDK and CLI use the same ID without resuming history. Equivalent to CLI's `--session-id` flag. | +| Option | Type | Default | Description | +| ------------------------ | -------------------------------------------------------------------- | ---------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `cwd` | `string` | `process.cwd()` | The working directory for the query session. Determines the context in which file operations and commands are executed. | +| `model` | `string` | - | The AI model to use (e.g., `'qwen-max'`, `'qwen-plus'`, `'qwen-turbo'`). Takes precedence over `OPENAI_MODEL` and `QWEN_MODEL` environment variables. | +| `pathToQwenExecutable` | `string` | Bundled CLI | Path to the Qwen Code executable. Supports multiple formats: `'qwen'` (native binary from PATH), `'/path/to/qwen'` (explicit path), `'/path/to/cli.js'` (Node.js bundle), `'node:/path/to/cli.js'` (force Node.js runtime), `'bun:/path/to/cli.js'` (force Bun runtime). If not provided, the SDK uses the bundled CLI included with the package. | +| `permissionMode` | `'default' \| 'plan' \| 'auto-edit' \| 'auto' \| 'yolo'` | `'default'` | Permission mode controlling tool execution approval. See [Permission Modes](#permission-modes) for details. | +| `canUseTool` | `CanUseTool` | - | Custom permission handler for tool execution approval. Invoked when a tool requires confirmation. Must respond within 60 seconds or the request will be auto-denied. See [Custom Permission Handler](#custom-permission-handler). | +| `env` | `Record` | - | Environment variables to pass to the Qwen Code process. Merged with the current process environment. | +| `systemPrompt` | `string \| QuerySystemPromptPreset` | - | System prompt configuration for the main session. Use a string to fully override the built-in Qwen Code system prompt, or a preset object to keep the built-in prompt and append extra instructions. | +| `mcpServers` | `Record` | - | MCP (Model Context Protocol) servers to connect. Supports external servers (stdio/SSE/HTTP) and SDK-embedded servers. External servers are configured with transport options like `command`, `args`, `url`, `httpUrl`, etc. SDK servers use `{ type: 'sdk', name: string, instance: Server }`. | +| `abortController` | `AbortController` | - | Controller to cancel the query session. Call `abortController.abort()` to terminate the session and cleanup resources. | +| `debug` | `boolean` | `false` | Enable debug mode for verbose logging from the CLI process. | +| `maxSessionTurns` | `number` | `-1` (unlimited) | Maximum number of conversation turns before the session automatically terminates. Must be an integer. A turn consists of a user message and an assistant response. | +| `coreTools` | `string[]` | - | Uses the legacy `coreTools` / CLI `--core-tools` allowlist semantics. If specified, only matching core tools are registered for the session. This is the only allowlist-style option that restricts built-in tool registration; a whole-tool `permissions.deny` / `excludeTools` rule (and `tools.disabled` in settings.json) also removes a tool from the registry. `permissions.allow` in settings.json is pure auto-approval and never removes, demotes, or hides a tool (#10075). To keep a tool's schema out of the initial model request, use `tools.eager` in settings.json (requires restart, #9827) — `tool_search`, `structured_output`, plan-mode lifecycle tools, `task_stop`, `mcp__*` and `computer_use__*` tools are exempt from that allowlist and keep their normal loading; to remove a tool entirely, use a whole-tool `excludeTools` / `permissions.deny` rule — a rule with a specifier (such as `'Bash(rm *)'`) only denies matching invocations at runtime. MCP tools are exempt from deny-based removal: hide them with the per-server `excludeTools` / `tools.disabled` filters instead (deny still blocks their calls at runtime). Example: `['read_file', 'edit', 'run_shell_command']`. | +| `excludeTools` | `string[]` | - | Equivalent to `permissions.deny` in settings.json. Excluded tools return a permission error immediately. Takes highest priority over all other permission settings. Supports tool name aliases and pattern matching: tool name (`'write_file'`), shell command prefix (`'Bash(rm *)'`), or path patterns (`'Read(.env)'`, `'Edit(/src/**)'`). | +| `allowedTools` | `string[]` | - | Equivalent to `permissions.allow` in settings.json for auto-approval. Matching tools bypass `canUseTool` callback and execute automatically. Only applies when tool requires confirmation. Like `permissions.allow`, this is pure auto-approval and never affects which tools are registered or which schemas are sent (#10075). Supports same pattern matching as `excludeTools`. Example: `['Bash(git status)', 'Bash(npm test)']`. | +| `authType` | `'openai' \| 'anthropic' \| 'qwen-oauth' \| 'gemini' \| 'vertex-ai'` | - | Authentication type for the AI service. When provided, the SDK forwards it to the CLI as `--auth-type`. | +| `agents` | `SubagentConfig[]` | - | Configuration for subagents that can be invoked during the session. Subagents are specialized AI agents for specific tasks or domains. | +| `includePartialMessages` | `boolean` | `false` | When `true`, the SDK emits incomplete messages as they are being generated, allowing real-time streaming of the AI's response. | +| `resume` | `string` | - | Resume a previous session by providing its session ID. Equivalent to CLI's `--resume` flag. | +| `sessionId` | `string` | - | Specify a session ID for the new session. Ensures SDK and CLI use the same ID without resuming history. Equivalent to CLI's `--session-id` flag. | > [!note] > For `coreTools`, aliases like `Read`, `Edit`, and `Bash` also work, but invocation specifiers such as `Bash(git *)` are stripped. `coreTools` restricts tool registration, not invocation patterns. diff --git a/docs/users/configuration/settings.md b/docs/users/configuration/settings.md index b94cf9a40a0..50dafbd250a 100644 --- a/docs/users/configuration/settings.md +++ b/docs/users/configuration/settings.md @@ -356,30 +356,30 @@ If you are experiencing performance issues with file searching (e.g., with `@` c #### tools -| Setting | Type | Description | Default | Notes | -| ------------------------------------ | ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ----------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `tools.sandbox` | boolean or string | Sandbox execution environment (can be a boolean or a path string). | `undefined` | | -| `tools.sandboxImage` | string | Sandbox image URI used by Docker/Podman when `--sandbox-image` and `QWEN_SANDBOX_IMAGE` are not set. | `undefined` | | -| `tools.shell.enableInteractiveShell` | boolean | Use `node-pty` for an interactive shell experience. Fallback to `child_process` still applies. | `true` | | -| `tools.shell.defaultTimeoutMs` | number | Default timeout, in milliseconds, for foreground shell commands started by the agent. A per-call timeout on the shell tool overrides this. When unset, foreground commands time out after 120000 ms (2 minutes). Set to 0 to disable the timeout. | `undefined` | | -| `tools.shell.heartbeatIntervalMs` | number | Interval, in milliseconds, between liveness heartbeats emitted while a foreground shell command produces no output. Heartbeats are forwarded to ACP clients and stream-json consumers so they can tell a silent command from a dead session. When unset, heartbeats fire every 10000 ms (10 seconds). Set to 0 to disable heartbeats. | `undefined` | | -| `tools.core` | array of strings | **Deprecated.** Will be removed in next version. A non-empty list restricts the core tool set (file, shell, search and related built-ins) to an allowlist: core tools not in the list are disabled (fail-closed). Tools outside that set — dynamically discovered tools (MCP, skill) and synthetic/system built-ins such as `agent`, `list_agents`, plan-mode lifecycle tools, goal tools, `task_stop`, `send_message` and `tool_search` — bypass the allowlist by design; use `permissions.deny` to remove a tool outright. An empty list (`[]`) is treated as unset and disables nothing. `permissions.allow` cannot reproduce this restriction — it is pure auto-approval (#10075). Use `tools.eager` to restrict which eager-by-default tool schemas are sent initially (unlisted tools are deferred, not disabled — they stay loadable via `tool_search`), and `permissions.deny` to block tools outright. | `undefined` | | -| `tools.exclude` | array of strings | **Deprecated.** Use `permissions.deny` instead. Tool names to exclude from discovery. Not automatically migrated; the legacy setting remains honoured at startup. | `undefined` | | -| `tools.disabled` | array of strings | Tool names hidden from the registry entirely. Unlike `permissions.deny` (which blocks calls at runtime), disabled tools are never registered, so they do not appear in `/tools` and cannot be discovered or called by the model. For example, `["enter_plan_mode"]` prevents the model from switching into plan mode on its own. Merged as a union across scopes. | `undefined` | | -| `tools.visible` | array of strings | Deferred tool names made visible at startup without requiring `tool_search`. Listed tools appear alongside core tools in the initial session. Merged as a union across scopes. | `undefined` | | -| `tools.eager` | array of strings | Allowlist of eager-by-default built-in tool names whose schemas remain eligible for the initial model request. Unlisted non-exempt tools are deferred instead: still registered, listed in `/tools`, callable, and discoverable via `tool_search`. Tools already deferred by default stay on demand even when listed; use `tools.visible` to surface one at startup. `tool_search`, `structured_output`, plan-mode lifecycle tools, `task_stop`, MCP tools, and `computer_use__*` tools are unaffected and keep their normal loading behaviour. An explicitly empty list (`[]`) is active and defers every non-exempt eager-by-default tool; omitting the setting means no restriction. Pairs with `tool_search`: when ToolSearch is not registered — `tools.toolSearch.enabled: false`, a `tool_search` deny rule, or the automatic opt-out for DeepSeek models — the allowlist still withholds the schemas, but nothing can load them back, so the demoted tools are out of reach for that session (they stay in `/tools`, and a warning is logged). Use `permissions.deny` if you meant to remove them, or leave ToolSearch on. Unusable entries (empty or malformed) are dropped with a warning and leave the rest of the list active. Later scopes replace earlier lists. Requires restart. | `undefined` | | -| `tools.allowed` | array of strings | **Deprecated.** Use `permissions.allow` instead. Tool names that bypass the confirmation dialog. Not automatically migrated; the legacy setting remains honoured at startup. | `undefined` | | -| `tools.approvalMode` | string | Sets the default approval mode for tool usage. | `auto` | Possible values: `plan` (analyze only, do not modify files or execute commands), `default` (require approval before file edits or shell commands run), `auto-edit` (automatically approve file edits), `auto` (LLM classifier auto-approves safe actions, blocks risky ones), `yolo` (automatically approve all tool calls) | -| `tools.discoveryCommand` | string | Command to run for tool discovery. When the `tools.eager` allowlist is active, a discovered tool not named in it is registered as deferred: it stays in `/tools` and is loadable via `tool_search`, but its schema is not sent in the initial model request. | `undefined` | | -| `tools.callCommand` | string | Defines a custom shell command for calling a specific tool that was discovered using `tools.discoveryCommand`. The shell command must meet the following criteria: It must take function `name` (exactly as in [function declaration](https://ai.google.dev/gemini-api/docs/function-calling#function-declarations)) as first command line argument. It must read function arguments as JSON on `stdin`, analogous to [`functionCall.args`](https://cloud.google.com/vertex-ai/generative-ai/docs/model-reference/inference#functioncall). It must return function output as JSON on `stdout`, analogous to [`functionResponse.response.content`](https://cloud.google.com/vertex-ai/generative-ai/docs/model-reference/inference#functionresponse). | `undefined` | | -| `tools.useRipgrep` | boolean | Use ripgrep for file content search instead of the fallback implementation. Provides faster search performance. | `true` | | -| `tools.useBuiltinRipgrep` | boolean | Use the bundled ripgrep binary. When set to `false`, the system-level `rg` command will be used instead. This setting is only effective when `tools.useRipgrep` is `true`. | `true` | | -| `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.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 | +| Setting | Type | Description | Default | Notes | +| ------------------------------------ | ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ----------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `tools.sandbox` | boolean or string | Sandbox execution environment (can be a boolean or a path string). | `undefined` | | +| `tools.sandboxImage` | string | Sandbox image URI used by Docker/Podman when `--sandbox-image` and `QWEN_SANDBOX_IMAGE` are not set. | `undefined` | | +| `tools.shell.enableInteractiveShell` | boolean | Use `node-pty` for an interactive shell experience. Fallback to `child_process` still applies. | `true` | | +| `tools.shell.defaultTimeoutMs` | number | Default timeout, in milliseconds, for foreground shell commands started by the agent. A per-call timeout on the shell tool overrides this. When unset, foreground commands time out after 120000 ms (2 minutes). Set to 0 to disable the timeout. | `undefined` | | +| `tools.shell.heartbeatIntervalMs` | number | Interval, in milliseconds, between liveness heartbeats emitted while a foreground shell command produces no output. Heartbeats are forwarded to ACP clients and stream-json consumers so they can tell a silent command from a dead session. When unset, heartbeats fire every 10000 ms (10 seconds). Set to 0 to disable heartbeats. | `undefined` | | +| `tools.core` | array of strings | **Deprecated.** Will be removed in next version. A non-empty list restricts the core tool set (file, shell, search and related built-ins) to an allowlist: core tools not in the list are disabled (fail-closed). Tools outside that set — dynamically discovered tools (MCP, skill) and synthetic/system built-ins such as `agent`, `list_agents`, plan-mode lifecycle tools, goal tools, `task_stop`, `send_message` and `tool_search` — bypass the allowlist by design; use `permissions.deny` to block a tool's calls (for MCP tools it stays listed and is rejected at runtime), or `tools.disabled` / the per-server `excludeTools` filter to remove it from the registry outright. An empty list (`[]`) is treated as unset and disables nothing. `permissions.allow` cannot reproduce this restriction — it is pure auto-approval (#10075). Use `tools.eager` to restrict which eager-by-default tool schemas are sent initially (unlisted tools are deferred, not disabled — they stay loadable via `tool_search`), and `permissions.deny` to block tools outright. | `undefined` | | +| `tools.exclude` | array of strings | **Deprecated.** Use `permissions.deny` instead. Tool names to exclude from discovery. Not automatically migrated; the legacy setting remains honoured at startup. | `undefined` | | +| `tools.disabled` | array of strings | Tool names hidden from the registry entirely. Unlike `permissions.deny` (which blocks calls at runtime), disabled tools are never registered, so they do not appear in `/tools` and cannot be discovered or called by the model. For example, `["enter_plan_mode"]` prevents the model from switching into plan mode on its own. Merged as a union across scopes. | `undefined` | | +| `tools.visible` | array of strings | Deferred tool names made visible at startup without requiring `tool_search`. Listed tools appear alongside core tools in the initial session. Merged as a union across scopes. | `undefined` | | +| `tools.eager` | array of strings | Allowlist of eager-by-default built-in tool names whose schemas remain eligible for the initial model request. Unlisted non-exempt tools are deferred instead: still registered, listed in `/tools`, callable, and discoverable via `tool_search`. Tools already deferred by default stay on demand even when listed; use `tools.visible` to surface one at startup. `tool_search`, `structured_output`, plan-mode lifecycle tools, `task_stop`, MCP tools, and `computer_use__*` tools are unaffected and keep their normal loading behaviour. An explicitly empty list (`[]`) is active and defers every non-exempt eager-by-default tool; omitting the setting means no restriction. Pairs with `tool_search`: when ToolSearch is not registered — `tools.toolSearch.enabled: false`, a `tool_search` deny rule, or the automatic opt-out for DeepSeek models — the allowlist still withholds the schemas, but nothing can load them back, so the demoted tools are out of reach for that session (they stay in `/tools`, and a warning is logged). Two carve-outs: demoted tools referenced in resumed session history get their schemas re-sent without a warning, and demoted tools listed in `tools.visible` are declared up front. Use `permissions.deny` if you meant to remove them, or leave ToolSearch on. Unusable entries (empty or malformed) are dropped with a warning and leave the rest of the list active. Later scopes replace earlier lists. Requires restart. | `undefined` | | +| `tools.allowed` | array of strings | **Deprecated.** Use `permissions.allow` instead. Tool names that bypass the confirmation dialog. Not automatically migrated; the legacy setting remains honoured at startup. | `undefined` | | +| `tools.approvalMode` | string | Sets the default approval mode for tool usage. | `auto` | Possible values: `plan` (analyze only, do not modify files or execute commands), `default` (require approval before file edits or shell commands run), `auto-edit` (automatically approve file edits), `auto` (LLM classifier auto-approves safe actions, blocks risky ones), `yolo` (automatically approve all tool calls) | +| `tools.discoveryCommand` | string | Command to run for tool discovery. When the `tools.eager` allowlist is active, a discovered tool not named in it is registered as deferred: it stays in `/tools` and is loadable via `tool_search`, but its schema is not sent in the initial model request. | `undefined` | | +| `tools.callCommand` | string | Defines a custom shell command for calling a specific tool that was discovered using `tools.discoveryCommand`. The shell command must meet the following criteria: It must take function `name` (exactly as in [function declaration](https://ai.google.dev/gemini-api/docs/function-calling#function-declarations)) as first command line argument. It must read function arguments as JSON on `stdin`, analogous to [`functionCall.args`](https://cloud.google.com/vertex-ai/generative-ai/docs/model-reference/inference#functioncall). It must return function output as JSON on `stdout`, analogous to [`functionResponse.response.content`](https://cloud.google.com/vertex-ai/generative-ai/docs/model-reference/inference#functionresponse). | `undefined` | | +| `tools.useRipgrep` | boolean | Use ripgrep for file content search instead of the fallback implementation. Provides faster search performance. | `true` | | +| `tools.useBuiltinRipgrep` | boolean | Use the bundled ripgrep binary. When set to `false`, the system-level `rg` command will be used instead. This setting is only effective when `tools.useRipgrep` is `true`. | `true` | | +| `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.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 | > [!note] > @@ -484,11 +484,11 @@ Permission rules for `Read`, `Edit`, and `WebFetch` are also enforced when the a **Migrating from legacy settings:** -| Legacy setting | Equivalent `permissions` rule | Notes | -| --------------- | ------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `tools.allowed` | `permissions.allow` | Not automatically migrated; still honoured at startup | -| `tools.exclude` | `permissions.deny` | Not automatically migrated; still honoured at startup | -| `tools.core` | `tools.eager` (+ `permissions.deny`) | Not auto-migrated to `permissions.allow`, which is pure auto-approval and cannot reproduce the allowlist restriction (#10075). `tools.eager` defers unlisted eager-by-default tools (they stay loadable via `tool_search`); `permissions.deny` removes tools entirely. Neither preserves a non-empty `tools.core` allowlist's fail-closed guarantee over the core tool set: a built-in added in a future release registers until explicitly denied, so a deny list must be re-audited per release. An empty `tools.core` list is treated as unset and disables nothing. | +| Legacy setting | Equivalent `permissions` rule | Notes | +| --------------- | ------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `tools.allowed` | `permissions.allow` | Not automatically migrated; still honoured at startup | +| `tools.exclude` | `permissions.deny` | Not automatically migrated; still honoured at startup | +| `tools.core` | `tools.eager` (+ `permissions.deny`) | Not auto-migrated to `permissions.allow`, which is pure auto-approval and cannot reproduce the allowlist restriction (#10075). `tools.eager` defers unlisted eager-by-default tools (they stay loadable via `tool_search`); `permissions.deny` removes built-ins from the registry entirely (MCP tools stay listed and are rejected at runtime — use `tools.disabled` / the per-server `excludeTools` filter to remove them outright). Neither preserves a non-empty `tools.core` allowlist's fail-closed guarantee over the core tool set: a built-in added in a future release registers until explicitly denied, so a deny list must be re-audited per release. An empty `tools.core` list is treated as unset and disables nothing. | **Example configuration:** diff --git a/packages/cli/src/config/settingsSchema.ts b/packages/cli/src/config/settingsSchema.ts index 9f11c6364ce..95b4d9db5bf 100644 --- a/packages/cli/src/config/settingsSchema.ts +++ b/packages/cli/src/config/settingsSchema.ts @@ -2813,7 +2813,7 @@ const SETTINGS_SCHEMA = { requiresRestart: true, default: undefined as string[] | undefined, description: - 'Allowlist of eager-by-default built-in tool names whose schemas remain eligible for the initial model request. Unlisted non-exempt tools are deferred but stay registered, listed in /tools, callable, and discoverable via tool_search. Tools already deferred by default stay on demand even when listed; use tools.visible to surface one at startup. tool_search, structured_output, plan-mode lifecycle tools, task_stop, MCP tools, and computer_use__* tools are unaffected. An explicitly empty list ([]) defers every non-exempt eager-by-default tool; omit the setting for no restriction. Pairs with tool_search: when ToolSearch is not registered (tools.toolSearch.enabled false, a tool_search deny rule, or the automatic opt-out for DeepSeek models) the schemas are still withheld but nothing can load them back, so the demoted tools are out of reach for that session and a warning is logged. Differs from tools.disabled, which removes tools entirely, and from permissions.allow, which only auto-approves calls.', + 'Allowlist of eager-by-default built-in tool names whose schemas remain eligible for the initial model request. Unlisted non-exempt tools are deferred but stay registered, listed in /tools, callable, and discoverable via tool_search. Tools already deferred by default stay on demand even when listed; use tools.visible to surface one at startup. tool_search, structured_output, plan-mode lifecycle tools, task_stop, MCP tools, and computer_use__* tools are unaffected. An explicitly empty list ([]) defers every non-exempt eager-by-default tool; omit the setting for no restriction. Pairs with tool_search: when ToolSearch is not registered (tools.toolSearch.enabled false, a tool_search deny rule, or the automatic opt-out for DeepSeek models) the schemas are still withheld but nothing can load them back, so the demoted tools are out of reach for that session and a warning is logged. Two carve-outs: demoted tools referenced in resumed session history get their schemas re-sent without a warning, and demoted tools listed in tools.visible are declared up front. Differs from tools.disabled, which removes tools entirely, and from permissions.allow, which only auto-approves calls.', showInDialog: false, }, approvalMode: { diff --git a/packages/core/src/config/config.test.ts b/packages/core/src/config/config.test.ts index 2bbb7df3892..74a9036cc9b 100644 --- a/packages/core/src/config/config.test.ts +++ b/packages/core/src/config/config.test.ts @@ -9314,6 +9314,44 @@ describe('Server Config (config.ts)', () => { expect(deferred).toContain(ToolNames.LS); }); + it('registers an enabled LS eagerly when tools.eager covers it (#10400)', async () => { + // Third cell of the LS x tools.eager matrix: enabled AND covered by + // the allowlist (via the ListFiles alias) -> registered eagerly via + // registerFactory, not demoted to deferred. Guards against a + // registerLazy mutant that demotes LS whenever an eager list is + // active, ignoring entry coverage (#10400). + const params: ConfigParameters = { + ...baseParams, + useRipgrep: false, + coreTools: undefined, + lsToolEnabled: true, + eagerTools: ['Shell', 'ListFiles'], + }; + const config = new Config(params); + await config.initialize(); + + const { registerFactory, registerPermissionDeferredFactory } = ( + (await vi.importMock('../tools/tool-registry')) as { + ToolRegistry: { + prototype: { + registerFactory: Mock; + registerPermissionDeferredFactory: Mock; + }; + }; + } + ).ToolRegistry.prototype; + + const registered = (registerFactory as Mock).mock.calls.map( + (call) => call[0], + ) as string[]; + const deferred = ( + registerPermissionDeferredFactory as Mock + ).mock.calls.map((call) => call[0]) as string[]; + + expect(registered).toContain(ToolNames.LS); + expect(deferred).not.toContain(ToolNames.LS); + }); + it('registers the full built-in set when no permissionsAllow is set (#9827 regression guard)', async () => { const params: ConfigParameters = { ...baseParams, diff --git a/packages/core/src/permissions/permission-manager.test.ts b/packages/core/src/permissions/permission-manager.test.ts index c18afd6cdda..4cf51768103 100644 --- a/packages/core/src/permissions/permission-manager.test.ts +++ b/packages/core/src/permissions/permission-manager.test.ts @@ -96,6 +96,23 @@ describe('resolveToolName', () => { expect(resolveToolName('mcp__server__tool')).toBe('mcp__server__tool'); expect(resolveToolName('constructor')).toBe('constructor'); }); + + it('returns Object.prototype-keyed names unchanged (#10400)', async () => { + // Keys inherited from Object.prototype must never resolve to the + // prototype value (e.g. the `constructor` function): only own + // properties of the alias table are aliases (#10400). + for (const name of [ + 'toString', + 'valueOf', + 'hasOwnProperty', + 'isPrototypeOf', + 'propertyIsEnumerable', + 'toLocaleString', + '__proto__', + ]) { + expect(resolveToolName(name)).toBe(name); + } + }); }); // ─── resolveToolName exhaustiveness (#9827) ───────────────────────────────── @@ -2869,6 +2886,45 @@ describe('PermissionManager', () => { ); }); + it('tolerates Object.prototype-keyed entries without crashing (#10400)', async () => { + // Entries named after Object.prototype keys used to read the inherited + // prototype value through the plain-object alias table and surface a + // non-string toolName, crashing initialize() with + // `rule.toolName.startsWith is not a function` (CLI startup crash). + // They must behave like any other unknown canonical name: resolve to + // themselves as strings, match no registered tool, and never abort + // initialization (#10400). + pm = new PermissionManager( + makeConfig({ + eagerTools: [ + 'constructor', + 'toString', + 'valueOf', + 'hasOwnProperty', + 'isPrototypeOf', + 'propertyIsEnumerable', + 'toLocaleString', + '__proto__', + 'ReadFile', + ], + }), + ); + expect(() => pm.initialize()).not.toThrow(); + expect(pm.isEagerToolAllowListActive()).toBe(true); + // The valid entry still works and the prototype-keyed entries do not + // disturb the rest of the allowlist. + expect(await pm.getToolRegistrationStatus('read_file')).toBe( + 'registered', + ); + expect(await pm.getToolRegistrationStatus('send_message')).toBe( + 'deferred', + ); + // The lookup itself must survive a prototype-keyed tool name too. + await expect( + pm.getToolRegistrationStatus('constructor'), + ).resolves.toBeDefined(); + }); + it('malformed entries drop out but still leave the list active', async () => { // Deferring more than intended is recoverable (ToolSearch still // reaches every tool); silently ignoring a configured list would diff --git a/packages/core/src/tools/tool-registry.test.ts b/packages/core/src/tools/tool-registry.test.ts index 2efe0178fd9..aa137b022f4 100644 --- a/packages/core/src/tools/tool-registry.test.ts +++ b/packages/core/src/tools/tool-registry.test.ts @@ -930,6 +930,28 @@ describe('ToolRegistry', () => { ); }); + it('keeps the tool visible when listed in visibleTools', async () => { + const registry = new ToolRegistry( + new Config({ + ...baseConfigParams, + visibleTools: ['hidden_by_allowlist'], + }), + ); + registry.registerPermissionDeferredFactory( + 'hidden_by_allowlist', + async () => new MockTool({ name: 'hidden_by_allowlist' }), + ); + await registry.warmAll(); + + expect(registry.getFunctionDeclarations().map((d) => d.name)).toContain( + 'hidden_by_allowlist', + ); + expect(registry.isDeferredAndHidden('hidden_by_allowlist')).toBe(false); + expect(registry.getDeferredToolSummary().map((t) => t.name)).not.toContain( + 'hidden_by_allowlist', + ); + }); + it('reveals the schema once ToolSearch loads the tool', async () => { toolRegistry.registerPermissionDeferredFactory( 'hidden_by_allowlist', diff --git a/packages/sdk-typescript/README.md b/packages/sdk-typescript/README.md index 1bbb1072baf..787a5586065 100644 --- a/packages/sdk-typescript/README.md +++ b/packages/sdk-typescript/README.md @@ -52,27 +52,27 @@ Creates a new query session with the Qwen Code. #### QueryOptions -| Option | Type | Default | Description | -| ------------------------ | -------------------------------------------------------------------- | ---------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `cwd` | `string` | `process.cwd()` | The working directory for the query session. Determines the context in which file operations and commands are executed. | -| `model` | `string` | - | The AI model to use (e.g., `'qwen-max'`, `'qwen-plus'`, `'qwen-turbo'`). Takes precedence over `OPENAI_MODEL` and `QWEN_MODEL` environment variables. | -| `pathToQwenExecutable` | `string` | Bundled CLI | Path to the Qwen Code executable. Supports multiple formats: `'qwen'` (native binary from PATH), `'/path/to/qwen'` (explicit path), `'/path/to/cli.js'` (Node.js bundle), `'node:/path/to/cli.js'` (force Node.js runtime), `'bun:/path/to/cli.js'` (force Bun runtime). If not provided, the SDK uses the bundled CLI included with the package. | -| `permissionMode` | `'default' \| 'plan' \| 'auto-edit' \| 'auto' \| 'yolo'` | `'default'` | Permission mode controlling tool execution approval. See [Permission Modes](#permission-modes) for details. | -| `canUseTool` | `CanUseTool` | - | Custom permission handler for tool execution approval. Invoked when a tool requires confirmation. Must respond within 60 seconds or the request will be auto-denied. See [Custom Permission Handler](#custom-permission-handler). | -| `env` | `Record` | - | Environment variables to pass to the Qwen Code process. Merged with the current process environment. | -| `systemPrompt` | `string \| QuerySystemPromptPreset` | - | System prompt configuration for the main session. Use a string to fully override the built-in Qwen Code system prompt, or a preset object to keep the built-in prompt and append extra instructions. | -| `mcpServers` | `Record` | - | MCP (Model Context Protocol) servers to connect. Supports external servers (stdio/SSE/HTTP) and SDK-embedded servers. External servers are configured with transport options like `command`, `args`, `url`, `httpUrl`, etc. SDK servers use `{ type: 'sdk', name: string, instance: Server }`. | -| `abortController` | `AbortController` | - | Controller to cancel the query session. Call `abortController.abort()` to terminate the session and cleanup resources. | -| `debug` | `boolean` | `false` | Enable debug mode for verbose logging from the CLI process. | -| `maxSessionTurns` | `number` | `-1` (unlimited) | Maximum number of conversation turns before the session automatically terminates. Must be an integer. A turn consists of a user message and an assistant response. | -| `coreTools` | `string[]` | - | Uses the legacy `coreTools` / CLI `--core-tools` allowlist semantics. If specified, only matching core tools are registered for the session. This is the only allowlist-style option that restricts built-in tool registration; a whole-tool `permissions.deny` / `excludeTools` rule (and `tools.disabled` in settings.json) also removes a tool from the registry. `permissions.allow` in settings.json is pure auto-approval and never removes, demotes, or hides a tool (#10075). To keep a tool's schema out of the initial model request, use `tools.eager` in settings.json (requires restart, #9827); to remove it entirely, use a whole-tool `excludeTools` / `permissions.deny` rule — a rule with a specifier (such as `'Bash(rm *)'`) only denies matching invocations at runtime. MCP tools are exempt from deny-based removal: hide them with the per-server `excludeTools` / `tools.disabled` filters instead (deny still blocks their calls at runtime). Example: `['read_file', 'edit', 'run_shell_command']`. | -| `excludeTools` | `string[]` | - | Equivalent to `permissions.deny` in settings.json. Excluded tools return a permission error immediately. Takes highest priority over all other permission settings. Supports tool name aliases and pattern matching: tool name (`'write_file'`), shell command prefix (`'Bash(rm *)'`), or path patterns (`'Read(.env)'`, `'Edit(/src/**)'`). | -| `allowedTools` | `string[]` | - | Equivalent to `permissions.allow` in settings.json for auto-approval. Matching tools bypass `canUseTool` callback and execute automatically. Only applies when tool requires confirmation. Like `permissions.allow`, this is pure auto-approval and never affects which tools are registered or which schemas are sent (#10075). Supports same pattern matching as `excludeTools`. Example: `['Bash(git status)', 'Bash(npm test)']`. | -| `authType` | `'openai' \| 'anthropic' \| 'qwen-oauth' \| 'gemini' \| 'vertex-ai'` | - | Authentication type for the AI service. When provided, the SDK forwards it to the CLI as `--auth-type`. | -| `agents` | `SubagentConfig[]` | - | Configuration for subagents that can be invoked during the session. Subagents are specialized AI agents for specific tasks or domains. | -| `includePartialMessages` | `boolean` | `false` | When `true`, the SDK emits incomplete messages as they are being generated, allowing real-time streaming of the AI's response. | -| `resume` | `string` | - | Resume a previous session by providing its session ID. Equivalent to CLI's `--resume` flag. | -| `sessionId` | `string` | - | Specify a session ID for the new session. Ensures SDK and CLI use the same ID without resuming history. Equivalent to CLI's `--session-id` flag. | +| Option | Type | Default | Description | +| ------------------------ | -------------------------------------------------------------------- | ---------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `cwd` | `string` | `process.cwd()` | The working directory for the query session. Determines the context in which file operations and commands are executed. | +| `model` | `string` | - | The AI model to use (e.g., `'qwen-max'`, `'qwen-plus'`, `'qwen-turbo'`). Takes precedence over `OPENAI_MODEL` and `QWEN_MODEL` environment variables. | +| `pathToQwenExecutable` | `string` | Bundled CLI | Path to the Qwen Code executable. Supports multiple formats: `'qwen'` (native binary from PATH), `'/path/to/qwen'` (explicit path), `'/path/to/cli.js'` (Node.js bundle), `'node:/path/to/cli.js'` (force Node.js runtime), `'bun:/path/to/cli.js'` (force Bun runtime). If not provided, the SDK uses the bundled CLI included with the package. | +| `permissionMode` | `'default' \| 'plan' \| 'auto-edit' \| 'auto' \| 'yolo'` | `'default'` | Permission mode controlling tool execution approval. See [Permission Modes](#permission-modes) for details. | +| `canUseTool` | `CanUseTool` | - | Custom permission handler for tool execution approval. Invoked when a tool requires confirmation. Must respond within 60 seconds or the request will be auto-denied. See [Custom Permission Handler](#custom-permission-handler). | +| `env` | `Record` | - | Environment variables to pass to the Qwen Code process. Merged with the current process environment. | +| `systemPrompt` | `string \| QuerySystemPromptPreset` | - | System prompt configuration for the main session. Use a string to fully override the built-in Qwen Code system prompt, or a preset object to keep the built-in prompt and append extra instructions. | +| `mcpServers` | `Record` | - | MCP (Model Context Protocol) servers to connect. Supports external servers (stdio/SSE/HTTP) and SDK-embedded servers. External servers are configured with transport options like `command`, `args`, `url`, `httpUrl`, etc. SDK servers use `{ type: 'sdk', name: string, instance: Server }`. | +| `abortController` | `AbortController` | - | Controller to cancel the query session. Call `abortController.abort()` to terminate the session and cleanup resources. | +| `debug` | `boolean` | `false` | Enable debug mode for verbose logging from the CLI process. | +| `maxSessionTurns` | `number` | `-1` (unlimited) | Maximum number of conversation turns before the session automatically terminates. Must be an integer. A turn consists of a user message and an assistant response. | +| `coreTools` | `string[]` | - | Uses the legacy `coreTools` / CLI `--core-tools` allowlist semantics. If specified, only matching core tools are registered for the session. This is the only allowlist-style option that restricts built-in tool registration; a whole-tool `permissions.deny` / `excludeTools` rule (and `tools.disabled` in settings.json) also removes a tool from the registry. `permissions.allow` in settings.json is pure auto-approval and never removes, demotes, or hides a tool (#10075). To keep a tool's schema out of the initial model request, use `tools.eager` in settings.json (requires restart, #9827) — `tool_search`, `structured_output`, plan-mode lifecycle tools, `task_stop`, `mcp__*` and `computer_use__*` tools are exempt from that allowlist and keep their normal loading; to remove a tool entirely, use a whole-tool `excludeTools` / `permissions.deny` rule — a rule with a specifier (such as `'Bash(rm *)'`) only denies matching invocations at runtime. MCP tools are exempt from deny-based removal: hide them with the per-server `excludeTools` / `tools.disabled` filters instead (deny still blocks their calls at runtime). Example: `['read_file', 'edit', 'run_shell_command']`. | +| `excludeTools` | `string[]` | - | Equivalent to `permissions.deny` in settings.json. Excluded tools return a permission error immediately. Takes highest priority over all other permission settings. Supports tool name aliases and pattern matching: tool name (`'write_file'`), shell command prefix (`'Bash(rm *)'`), or path patterns (`'Read(.env)'`, `'Edit(/src/**)'`). | +| `allowedTools` | `string[]` | - | Equivalent to `permissions.allow` in settings.json for auto-approval. Matching tools bypass `canUseTool` callback and execute automatically. Only applies when tool requires confirmation. Like `permissions.allow`, this is pure auto-approval and never affects which tools are registered or which schemas are sent (#10075). Supports same pattern matching as `excludeTools`. Example: `['Bash(git status)', 'Bash(npm test)']`. | +| `authType` | `'openai' \| 'anthropic' \| 'qwen-oauth' \| 'gemini' \| 'vertex-ai'` | - | Authentication type for the AI service. When provided, the SDK forwards it to the CLI as `--auth-type`. | +| `agents` | `SubagentConfig[]` | - | Configuration for subagents that can be invoked during the session. Subagents are specialized AI agents for specific tasks or domains. | +| `includePartialMessages` | `boolean` | `false` | When `true`, the SDK emits incomplete messages as they are being generated, allowing real-time streaming of the AI's response. | +| `resume` | `string` | - | Resume a previous session by providing its session ID. Equivalent to CLI's `--resume` flag. | +| `sessionId` | `string` | - | Specify a session ID for the new session. Ensures SDK and CLI use the same ID without resuming history. Equivalent to CLI's `--session-id` flag. | > [!tip] > If you need to configure `coreTools`, `excludeTools`, or `allowedTools`, it is **strongly recommended** to read the [permissions configuration documentation](../../docs/users/configuration/settings.md#permissions) first, especially the **Tool name aliases** and **Rule syntax examples** sections. Rule patterns such as `Bash(git *)`, `Read(.env)`, and `Edit(/src/**)` apply to `excludeTools` and `allowedTools`; `coreTools` accepts aliases but strips invocation specifiers. diff --git a/packages/sdk-typescript/src/types/types.ts b/packages/sdk-typescript/src/types/types.ts index e0ba26860b0..0d90ad45ee9 100644 --- a/packages/sdk-typescript/src/types/types.ts +++ b/packages/sdk-typescript/src/types/types.ts @@ -415,7 +415,10 @@ export interface QueryOptions { * loadable via `tool_search` while ToolSearch is registered; when ToolSearch * is not registered (`tools.toolSearch.enabled: false`, a `tool_search` deny * rule, or the automatic DeepSeek opt-out) the demoted tools are out of - * reach for that session and a warning is logged. Tools already deferred by + * reach for that session and a warning is logged. Two carve-outs: demoted + * tools referenced in resumed session history get their schemas re-sent + * without a warning, and demoted tools listed in `tools.visible` are + * declared up front. Tools already deferred by * default remain on * demand even when listed; `tools.visible` surfaces one at startup. The * allowlist does not affect MCP tools, the `--json-schema` @@ -468,7 +471,9 @@ export interface QueryOptions { * `tool_search` while ToolSearch is registered; when ToolSearch is not * registered (`tools.toolSearch.enabled: false`, a `tool_search` deny * rule, or the automatic DeepSeek opt-out) the demoted tools are out of - * reach for that session and a warning is logged (#9827) + * reach for that session and a warning is logged — except demoted tools + * referenced in resumed session history (re-sent without a warning) or + * listed in `tools.visible` (declared up front) (#9827) * * **Pattern matching:** * - Tool name: `'write_file'` diff --git a/packages/vscode-ide-companion/schemas/settings.schema.json b/packages/vscode-ide-companion/schemas/settings.schema.json index e515403004a..1cdae601634 100644 --- a/packages/vscode-ide-companion/schemas/settings.schema.json +++ b/packages/vscode-ide-companion/schemas/settings.schema.json @@ -1338,7 +1338,7 @@ } }, "eager": { - "description": "Allowlist of eager-by-default built-in tool names whose schemas remain eligible for the initial model request. Unlisted non-exempt tools are deferred but stay registered, listed in /tools, callable, and discoverable via tool_search. Tools already deferred by default stay on demand even when listed; use tools.visible to surface one at startup. tool_search, structured_output, plan-mode lifecycle tools, task_stop, MCP tools, and computer_use__* tools are unaffected. An explicitly empty list ([]) defers every non-exempt eager-by-default tool; omit the setting for no restriction. Pairs with tool_search: when ToolSearch is not registered (tools.toolSearch.enabled false, a tool_search deny rule, or the automatic opt-out for DeepSeek models) the schemas are still withheld but nothing can load them back, so the demoted tools are out of reach for that session and a warning is logged. Differs from tools.disabled, which removes tools entirely, and from permissions.allow, which only auto-approves calls.", + "description": "Allowlist of eager-by-default built-in tool names whose schemas remain eligible for the initial model request. Unlisted non-exempt tools are deferred but stay registered, listed in /tools, callable, and discoverable via tool_search. Tools already deferred by default stay on demand even when listed; use tools.visible to surface one at startup. tool_search, structured_output, plan-mode lifecycle tools, task_stop, MCP tools, and computer_use__* tools are unaffected. An explicitly empty list ([]) defers every non-exempt eager-by-default tool; omit the setting for no restriction. Pairs with tool_search: when ToolSearch is not registered (tools.toolSearch.enabled false, a tool_search deny rule, or the automatic opt-out for DeepSeek models) the schemas are still withheld but nothing can load them back, so the demoted tools are out of reach for that session and a warning is logged. Two carve-outs: demoted tools referenced in resumed session history get their schemas re-sent without a warning, and demoted tools listed in tools.visible are declared up front. Differs from tools.disabled, which removes tools entirely, and from permissions.allow, which only auto-approves calls.", "type": "array", "items": { "type": "string"