fix(computer-use): auto-approve install in auto-approve modes (YOLO/AUTO_EDIT/AUTO) - #4756
Conversation
In YOLO mode the tool scheduler auto-approves the tool call and bypasses ComputerUseTool's confirmation dialog, so the dialog's onConfirm — which records install approval — never runs. runBootstrap then reached its headless fallback (promptInstallApproval), which refuses unless QWEN_COMPUTER_USE_AUTO_APPROVE=1, and threw "Computer Use install declined by user" even though the user never declined. Thread Config into ComputerUseTool so execute() can read the approval mode and set a new BootstrapContext.autoApproveInstall flag when YOLO is active. runBootstrap honors it by skipping the prompt and persisting the approval (so later non-YOLO calls also skip it). Non-YOLO behavior is unchanged: the confirmation dialog still records approval, and headless/SDK contexts still use the QWEN_COMPUTER_USE_AUTO_APPROVE fallback. Per-action permission is untouched (getDefaultPermission still returns 'ask'). AUTO (auto-edit) mode is intentionally NOT auto-approved: unlike YOLO's explicit "approve everything", silently installing a ~50MB binary that can control the desktop should still surface the dialog.
📋 Review SummaryThis PR fixes a critical bug where Computer Use fails on first invocation in YOLO approval mode with "install declined by user" error. The fix correctly identifies that YOLO mode bypasses the confirmation dialog (whose 🔍 General Feedback
🎯 Specific Feedback🟡 High
🟢 Medium
🔵 Low
✅ Highlights
|
Code Coverage Summary
CLI Package - Full Text ReportCore Package - Full Text ReportFor detailed HTML reports, please see the 'coverage-reports-22.x-ubuntu-latest' artifact from the main CI run. |
There was a problem hiding this comment.
Pull request overview
Fixes first-use Computer Use failures in YOLO approval mode by ensuring the bootstrap install gate is auto-approved (and persisted) when the scheduler bypasses the standard confirmation dialog.
Changes:
- Thread
Config(optional) intoComputerUseTool/invocations soexecute()can detect YOLO and pass anautoApproveInstallflag into bootstrap. - Extend
runBootstrap()withBootstrapContext.autoApproveInstallto skip the headless install prompt and persist install approval under YOLO. - Add unit tests covering YOLO auto-approval behavior at both the tool and bootstrap layers.
Reviewed changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| packages/core/src/tools/computer-use/tool.ts | Passes YOLO-derived autoApproveInstall into bootstrap during execution. |
| packages/core/src/tools/computer-use/tool.test.ts | Adds an end-to-end regression test for YOLO first-use install auto-approval. |
| packages/core/src/tools/computer-use/index.ts | Forwards an optional Config into each lazily-registered Computer Use tool. |
| packages/core/src/tools/computer-use/bootstrap.ts | Adds autoApproveInstall context flag to bypass the headless install refusal path under YOLO and persist approval. |
| packages/core/src/tools/computer-use/bootstrap.test.ts | Adds coverage ensuring YOLO auto-approve skips prompting and persists approval. |
| packages/core/src/config/config.ts | Passes this into registerComputerUseTools so tools can read the active approval mode. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
The YOLO install-auto-approve fix missed two sibling scheduler paths that trigger the identical "install declined by user" error: AUTO_EDIT auto-approves info-type tools via isAutoEditApproved() (all computer_use__* tools are type 'info'), and AUTO auto-approves classifier-approved calls. Both bypass the confirmation dialog, so its onConfirm never records install approval and runBootstrap's headless fallback refuses. Broaden execute()'s autoApproveInstall to YOLO || AUTO_EDIT || AUTO and parametrize the regression test over all three modes. Also use deps.packageSpec instead of a hard-coded literal in the bootstrap test assertion (review nit).
Round 2 (f03ca1a)Broadened the install auto-approve to AUTO_EDIT and AUTO in addition to YOLO — both bypass the confirmation dialog the same way and hit the identical "install declined" error (details on the inline threads). The execute() regression test is now parametrized over all three modes, and the bootstrap test uses Declining the two remaining items from the automated Review Summary as out of scope for this bug fix:
|
| // still shows the dialog; PLAN blocks. Headless / SDK contexts (no config) | ||
| // fall back to the env-var path in bootstrap's default promptInstallApproval. | ||
| const mode = this.config?.getApprovalMode(); | ||
| const autoApproveInstall = |
There was a problem hiding this comment.
[Suggestion] The autoApproveInstall derivation hardcodes three ApprovalMode enum values — a second source of truth for "does the scheduler skip the confirmation dialog?" That question is already answered by needsConfirmation(), isAutoEditApproved(), and the AUTO classifier in coreToolScheduler.ts.
The PR's own history proves the coupling: the initial version only listed YOLO, and reviewers had to catch AUTO_EDIT and AUTO. When a new auto-approve mode is added, this file must be updated manually with no compile-time safety.
Consider extracting a shared helper (e.g., wouldSkipConfirmation(mode, type) in permissionFlow.ts) that both the scheduler and this tool call, or passing a dialogWasShown flag from the scheduler into execute().
— qwen3.7-max via Qwen Code /review
There was a problem hiding this comment.
Keeping the explicit enumeration. The duplication is intentional and fail-closed: a shared wouldSkipConfirmation(mode, type) helper (or auto-coupling install-approval to dialog-skipping) would mean any future approval mode that skips the dialog would automatically also auto-install a ~50MB desktop-control binary. With the explicit list, a new mode defaults to NOT auto-installing — the safe direction, requiring a deliberate opt-in. Threading a dialogWasShown flag from the scheduler into execute() is a cross-cutting change to tool execution, out of scope for this bug fix.
| // For headless / SDK contexts (no dialog), fall back to the env-var path | ||
| // already built into bootstrap's default promptInstallApproval. | ||
| await runBootstrap(client, { signal, updateOutput }); | ||
| // But several approval modes auto-approve the tool call and bypass that |
There was a problem hiding this comment.
[Suggestion] The same YOLO/AUTO_EDIT/AUTO-bypasses-onConfirm narrative appears in four locations: this block, BootstrapContext.autoApproveInstall JSDoc (bootstrap.ts:46-53), the inline comment inside runBootstrap (bootstrap.ts:228-232), and the registerComputerUseTools JSDoc (index.ts:36-40). When the mechanism changes, four comments need updating in lockstep.
Consider keeping the full explanation in one authoritative location (BootstrapContext.autoApproveInstall JSDoc) and replacing the other three with short references:
// See BootstrapContext.autoApproveInstall for the full rationale.— qwen3.7-max via Qwen Code /review
There was a problem hiding this comment.
Leaving the four comments as-is. They sit at four distinct layers (tool execute() / BootstrapContext type / runBootstrap impl / registration), and a short local explanation is more useful where a maintainer actually lands than a see X indirection. Out of scope for this bug fix.
…idening Add a negative test asserting execute() under ApprovalMode.DEFAULT still gates the first-use install. The it.each only covered the true-branch (YOLO/AUTO_EDIT/AUTO); this locks the false-branch so a future widening of the condition (e.g. `mode !== PLAN`) — which would silently auto-install a desktop-control binary under DEFAULT — fails CI. Verified the guard catches that exact regression before landing.
PR #4756 Local Verification ReportBranch: Changes Summary
Test Results
Pre-existing TypeCheck Errors (not from this PR)
Verdict✅ Ready to merge. All 91 unit tests pass, including parametrized coverage for YOLO/AUTO_EDIT/AUTO auto-approve and DEFAULT gate-guard. Lint clean, zero new type errors. The fix is well-scoped: only affects the install gate in modes where the scheduler already auto-approved the tool call (no per-action permission change). Verified by wenshao |
wenshao
left a comment
There was a problem hiding this comment.
No issues found. LGTM! ✅ — qwen3.7-max via Qwen Code /review
yiliang114
left a comment
There was a problem hiding this comment.
LGTM — clean fix for the approval-mode / install-gate mismatch. Config threading is backward-compatible (optional args), test coverage locks both the positive and negative boundaries, CI green across all platforms.
What this PR does
Fixes Computer Use failing with
Computer Use install declined by user. Re-invoke the tool to be prompted again.on the first call in every approval mode that auto-approves the tool call and bypasses the confirmation dialog — YOLO, AUTO_EDIT, and AUTO — even though the user never declined anything.The tool now reads the active approval mode and, in those modes, auto-approves the one-time install gate instead of falling through to a headless prompt that refuses.
DEFAULT(interactive dialog) andPLAN(blocked) are unchanged.Why it's needed
Computer Use has two independent approval gates:
ComputerUseTool.getConfirmationDetails). ItsonConfirmis what records install approval (saveInstallState).runBootstrap→promptInstallApproval), a headless fallback that only returns true whenQWEN_COMPUTER_USE_AUTO_APPROVE=1.Whenever the scheduler auto-approves the tool call, it bypasses gate 1 — so
onConfirmnever runs, install state is never written, andrunBootstraphits gate 2, finds no approval, and throwsinstall declined by userwith no dialog ever shown. This happens in three modes:needsConfirmation()returnsfalse, so the scheduler marks the callProceedAlwaysand never builds the dialog (coreToolScheduler.ts:1984).isAutoEditApproved()auto-approvestype:'info'tools, and allcomputer_use__*tools areinfo, so the schedulerProceedAlways-es without callingonConfirm(coreToolScheduler.ts:2028).ProceedAlwaysand skiponConfirm(coreToolScheduler.ts:1933).A pinned-version bump (e.g.
@0.2.2 → 0.2.3in #4726) makes it more likely, since install approval is matched on the exact package spec.Reviewer Test Plan
How to verify
Unit tests at both layers (each written test-first, confirmed RED before the fix):
tool.test.ts→execute() under %s auto-approves install ...parametrized over YOLO / AUTO_EDIT / AUTO: a config in each mode + no install state + no env var no longer throws "declined".bootstrap.test.ts→runBootstraphonorsctx.autoApproveInstall: skips the prompt and persists approval.Manual: in a YOLO / AUTO_EDIT / AUTO session with no prior install state and
QWEN_COMPUTER_USE_AUTO_APPROVEunset, invoke anycomputer_use__*tool — it proceeds instead of returning the decline error.Evidence (Before & After)
Non-TUI behavior change; evidence is the test transitions.
Before (RED):
execute() under auto-edit ...and... under auto ...both fail withComputer Use install declined by user.After (GREEN):
✓ packages/core/src/tools/computer-use/ — 90 tests passed.Tested on
tsc --noEmit(core)Environment
Unit tests only (
vitest); no live desktop /npxspawn required.Risk & Scope
ComputerUseToolholds aConfig(optional 3rd ctor arg) andregisterComputerUseToolsgains an optional 2nd arg. Both optional → backward compatible; absentconfigkeeps the existing headless behavior.DEFAULTstill shows the install dialog;PLANstill blocks. Semantically safe: in those modes the scheduler already approved the call with no dialog opportunity, so auto-approving the install aligns with the approval already granted — it does not bypass a consent step the user would otherwise see. Per-action permission is untouched (getDefaultPermissionstill returns'ask'), so this does not re-introduce the blanket-grant issue fixed in feat(computer-use): zero-config built-in via open-computer-use MCP #4590.Linked Issues
Relates to #4590 (zero-config built-in / bootstrap) and #4726 (fork repoint). No issue to auto-close.
中文说明
这个 PR 做了什么
修复在所有"自动批准工具调用并跳过确认弹窗"的审批模式(YOLO、AUTO_EDIT、AUTO)下首次调用 Computer Use 报
install declined by user的问题——尽管用户从未拒绝。现在工具读取当前审批模式,在这些模式下自动通过一次性安装闸门。DEFAULT(交互弹窗)与PLAN(阻断)不变。为什么需要
两道独立闸门:(1) 标准确认弹窗,其
onConfirm负责写入安装授权;(2) bootstrap headless 兜底(仅QWEN_COMPUTER_USE_AUTO_APPROVE=1才放行)。只要调度器自动批准了工具调用,就会跳过闸门 1 →onConfirm不执行 → 安装状态未写入 → 闸门 2 在没设环境变量时抛 "declined",且全程没有任何弹窗。命中三种模式:needsConfirmation()返回 false,直接ProceedAlways,不构建弹窗(coreToolScheduler.ts:1984)。isAutoEditApproved()自动批准type:'info'工具,而所有computer_use__*都是info,于是ProceedAlways且不调用onConfirm(coreToolScheduler.ts:2028)。ProceedAlways且跳过onConfirm(coreToolScheduler.ts:1933)。方案与范围
把
Config透传进ComputerUseTool,execute()据此在YOLO‖AUTO_EDIT‖AUTO下设置BootstrapContext.autoApproveInstall;runBootstrap据此跳过提示并持久化授权。语义安全:这些模式下调度器已经批准了调用、且根本不会弹窗,自动通过安装只是与已授予的调用批准对齐,并未绕过用户本应看到的确认步骤。逐操作权限不变(getDefaultPermission仍'ask'),不会重新引入 #4590 修过的"一次确认全量放行"。DEFAULT仍弹窗,PLAN仍阻断。测试在 tool / bootstrap 两层覆盖,execute 层参数化覆盖三种模式(均先 RED 后 GREEN),npx vitest run packages/core/src/tools/computer-use/全绿(90)。