fix(interactive): configure Docker sandbox networking for protocol tag retry test - #6689
Conversation
…g retry test (#6684) The protocol-tags-interactive.test.ts started the fake OpenAI server on 127.0.0.1 without Docker-aware host options, making it unreachable from inside the Docker sandbox container. The CLI running in the container tried to connect to 127.0.0.1 which resolved to the container's own loopback, not the host where the test server listens. Bind the fake server to 0.0.0.0 and advertise host.docker.internal as the base URL host when QWEN_SANDBOX is docker or podman, matching the established pattern in tool-control.test.ts. Also set NO_PROXY to include host.docker.internal so the CLI does not route sandbox model requests through an HTTP proxy.
E2E Report — autofix/issue-6684SummaryFix for release failure v0.19.9 where the Root CauseThe FixConfigure Docker sandbox networking for the test, matching the established pattern in
Verification
Limitations
|
|
Thanks for the PR! Template looks good ✓ Problem: This is an observed bug — v0.19.9 release validation failed because Direction: Clearly aligned — this is a test-infrastructure fix to unblock the release pipeline. No user-facing code changes. Size: 0 production logic lines. 59 additions / 26 deletions, all in a single test file. Not applicable for core-module gate. Approach: Scope is minimal and correct. The fix follows the exact Moving on to code review. 🔍 中文说明感谢贡献! 模板完整 ✓ 问题:已观测到的 bug —— v0.19.9 发布验证失败, 方向:完全对齐 —— 纯测试基础设施修复,解除发布流水线阻塞。无用户侧代码变更。 规模:0 行生产逻辑。59 行新增 / 26 行删除,全部在单个测试文件中。不触及核心模块门控。 方案:范围最小且正确。修复完全复用了 进入代码审查 🔍 — Qwen Code · qwen3.7-max |
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. |
Code ReviewNo issues found. The diff is a clean, minimal port of the proven Test ResultsNon-sandbox mode (QWEN_SANDBOX=false) — PASS ✅Docker sandbox mode (QWEN_SANDBOX=docker) — NOT TESTED
|
|
This is a clean, minimal test-infrastructure fix that unblocks the release pipeline. The problem is real (v0.19.9 release failed in Approving. ✅ 中文说明这是一个干净、最小化的测试基础设施修复,解除了发布流水线的阻塞。问题是真实的(v0.19.9 发布在 批准。✅ — Qwen Code · qwen3.7-max |
qwen-code-ci-bot
left a comment
There was a problem hiding this comment.
LGTM, looks ready to ship. ✅
qwen-code-ci-bot
left a comment
There was a problem hiding this comment.
No critical issues found. The fix correctly addresses the Docker sandbox networking gap that caused the v0.19.9 release failure. LGTM! ✅
— qwen3.7-max via Qwen Code /review
Suggestions — commit
|
| File | Issue | Suggested fix |
|---|---|---|
integration-tests/interactive/protocol-tags-interactive.test.ts:15-17 |
SANDBOX_MODE/IS_CONTAINER_SANDBOX constants and NO_PROXY string are duplicated across 4 test files with 2 divergent detection strategies (strict equality vs truthiness check). Drift risk grows with each new test adopting this pattern. |
Extract a shared helper (e.g., isContainerSandbox() and containerNoProxyValue()) in test-helper.ts or a new sandbox-env.ts utility. |
— qwen3.7-max via Qwen Code /review
…g retry test (QwenLM#6684) (QwenLM#6689) The protocol-tags-interactive.test.ts started the fake OpenAI server on 127.0.0.1 without Docker-aware host options, making it unreachable from inside the Docker sandbox container. The CLI running in the container tried to connect to 127.0.0.1 which resolved to the container's own loopback, not the host where the test server listens. Bind the fake server to 0.0.0.0 and advertise host.docker.internal as the base URL host when QWEN_SANDBOX is docker or podman, matching the established pattern in tool-control.test.ts. Also set NO_PROXY to include host.docker.internal so the CLI does not route sandbox model requests through an HTTP proxy. Co-authored-by: qwen-autofix[bot] <qwen-autofix[bot]@users.noreply.github.com>
* feat(web-shell): add mobile welcome composer slots * refactor(web-shell): deduplicate MessageList JSX and remove dead CSS reference - Extract ~80 lines of duplicated MessageList rendering into shared variables with conditional props and wrapper - Remove dead chatPaneWithWelcomeMiddle className reference (CSS class never defined) - Document mobileWelcomeFooterMiddle dependency on renderWelcomeFooter in JSDoc * fix(web-shell): stabilize MessageList tree position and conditional customFooter wrapper - Use stable outer wrapper div for IIFE to prevent MessageList unmount/remount when showMobileWelcomeFooterMiddle toggles - Only wrap CustomFooter in styles.customFooter div when hasMobileComposerBottom is true, avoiding DOM depth change for non-mobile consumers * fix(release): raise package size budget to 85 MiB (QwenLM#6688) * fix(interactive): configure Docker sandbox networking for protocol tag retry test (QwenLM#6684) (QwenLM#6689) The protocol-tags-interactive.test.ts started the fake OpenAI server on 127.0.0.1 without Docker-aware host options, making it unreachable from inside the Docker sandbox container. The CLI running in the container tried to connect to 127.0.0.1 which resolved to the container's own loopback, not the host where the test server listens. Bind the fake server to 0.0.0.0 and advertise host.docker.internal as the base URL host when QWEN_SANDBOX is docker or podman, matching the established pattern in tool-control.test.ts. Also set NO_PROXY to include host.docker.internal so the CLI does not route sandbox model requests through an HTTP proxy. Co-authored-by: qwen-autofix[bot] <qwen-autofix[bot]@users.noreply.github.com> * fix(core): keep YOLO mode when the model calls enter_plan_mode (QwenLM#6630) * fix(core): keep YOLO mode when the model calls enter_plan_mode A model-initiated enter_plan_mode call from YOLO silently switched the session into the read-only Plan mode, surprising users who explicitly chose YOLO for low-friction execution and then blocking the reads/writes they expected to proceed. Genuine user-driven plan-mode entries (Shift+Tab, /plan) call setApprovalMode directly and never route through this tool, so guarding the tool only affects the model deciding to plan on its own. From YOLO the tool now keeps the current mode and returns a message telling the model to continue planning without switching. Fixes QwenLM#5970 * fix(core): gate the YOLO plan-mode guard on an explicit user request Addresses review feedback on QwenLM#6630. The previous guard suppressed every enter_plan_mode invocation while the session was in YOLO mode. That fixes the unsolicited switch reported in QwenLM#5970, but it also blocks the legitimate path: the tool description tells the model to call this tool only after the user explicitly asks, and /plan is interactive-only (supportedModes: ['interactive']) with no Shift+Tab equivalent. In a headless or ACP YOLO session the tool is the only door into plan mode, so a blanket guard made an explicit user request unreachable. Add an optional userRequested flag to the tool schema and only no-op when the entry is NOT user-requested. A user-requested entry still goes through setApprovalMode(PLAN, { enteredByModel: true }) so the Plan Approval Gate on exit continues to run for AUTO/YOLO sessions (QwenLM#5574). * fix(core): address review suggestions on the YOLO plan-mode guard - Log via debugLogger.info when the guard suppresses a model-initiated entry, so a "I asked for plan mode and nothing happened" report is diagnosable by grepping ENTER_PLAN_MODE (the other early-return paths already log). - Strengthen the userRequested:false test to assert on the returned llmContent/returnDisplay, matching the unsolicited-entry sibling test. - Add a defensive test pinning that userRequested is inert outside YOLO: DEFAULT with the flag set enters plan mode normally. --------- Co-authored-by: Shaojin Wen <shaojin.wensj@alibaba-inc.com> * feat(cli): forward ask_user_question answers from SDK can_use_tool (QwenLM#6655) * feat(cli): forward ask_user_question answers from SDK can_use_tool SDK-hosted agents could receive ask_user_question calls through the can_use_tool callback and approve them, but the user's answers never reached the tool: the CLI called onConfirm(ProceedOnce) with no payload, so the tool read an empty answers map and the model never got the decisions. Route updatedInput.answers from the SDK's allow response into the tool confirmation payload so the collected answers reach the tool. Reuses the existing updatedInput channel — no new SDK API or types. Document the pattern in the TypeScript and Python SDK READMEs. * fix(cli): forward ask_user_question answers on teammate approval path Address review feedback on QwenLM#6655: - handleTeammateApproval now mirrors the leader path and promotes the user's answers from updatedInput into the confirmation payload, so ask_user_question calls approved through a teammate no longer drop the user's choices (wenshao). - Extract a shared buildAllowConfirmationPayload helper used by both the leader and teammate paths, and only promote `answers` for ask_user_question so a same-named field on any other tool's input can't leak into the payload. - Add tests for the teammate path and the defensive guards (array updatedInput, array/null/empty answers, foreign answers field). * test(web-shell): stub Range client-rect methods to fix flaky CI CodeMirror's async measure pass (scheduled via requestAnimationFrame) calls getClientRects()/getBoundingClientRect() on a text Range. jsdom implements these on Element but not on Range, so the call throws "textRange(...).getClientRects is not a function" from a rAF callback after the test completed. Vitest surfaces it as an unhandled error and fails the whole run with exit code 1 even though every assertion passed (seen intermittently in useComposerCore.dom.test.tsx). Polyfill both methods on Range.prototype in the shared test setup, mirroring the existing ResizeObserver/scrollIntoView stubs. * refactor(cli): use ToolNames constant and broaden permission tests Address review suggestions on QwenLM#6655: - buildAllowConfirmationPayload now gates answers-promotion on the ToolNames.ASK_USER_QUESTION constant instead of a bare string literal, so a future rename of the tool name is a compile-time break rather than a silent regression. - Add an it.each case for a non-object primitive updatedInput (string) to cover the `typeof updatedInput !== 'object'` guard branch. - Assert the leader path overrides toolCall.request.args with the host's sanitized updatedInput before confirming. - Add a teammate-path test for an allow response with no updatedInput, asserting respond is called with (ProceedOnce, undefined). --------- Co-authored-by: qwen-code-dev-bot <qwen-code-dev-bot@users.noreply.github.com> * fix(cli): localize approval mode UI labels (QwenLM#6592) * fix(cli): localize approval mode UI labels * fix(cli): address approval mode i18n review * fix(cli): stabilize approval mode i18n key * test(cli): cover approval mode i18n follow-up * test(cli): cover localized auto indicator * test(cli): address approval i18n suggestions --------- Co-authored-by: Shaojin Wen <shaojin.wensj@alibaba-inc.com> * feat(dingtalk): mention response senders (QwenLM#6679) * docs: design DingTalk at-sender replies * docs: plan DingTalk at-sender replies * feat(channels): preserve session for response delivery * feat(dingtalk): optionally mention response sender * docs(dingtalk): explain response mentions * fix(dingtalk): retain queued mention targets * fix(dingtalk): bound mention target lifecycle * fix(dingtalk): clear synthetic command mention target * fix(dingtalk): clear buffered targets on session death * debug(dingtalk): log mention delivery result * fix(dingtalk): render response mentions * fix(dingtalk): send visible response mentions * feat(dingtalk): use text replies for mentions * fix(dingtalk): preserve mentioned text replies * feat(web-shell): add artifact right panel (QwenLM#6591) * feat(web-shell): add artifact right panel * fix(web-shell): address artifact panel review feedback * fix(web-shell): handle artifact panel review edge cases * fix(web-shell): tighten scheduled task parsing * fix(web-shell): address artifact panel review followups * fix(web-shell): guard large file diff stats * fix(web-shell): address review panel suggestions * test(webui): stabilize heartbeat prompt cleanup test * fix(web-shell): address artifact review refresh issues * test(web-shell): stabilize ChatPane artifact hook mock * fix(web-shell): clear stale session artifacts while loading * fix(web-shell): preserve artifact tabs during refresh * fix(web-shell): address artifact review followups * fix(web-shell): respect workspace cwd for artifact outputs * fix(web-shell): scope artifact panel actions to pane * fix(web-shell): resolve split pane merge conflict * fix(web-shell): clear stale artifact panel state * fix(web-shell): preserve leading turn outputs * fix(web-shell): tighten turn output selectors * fix(web-shell): harden artifact preview sanitizer * fix(web-shell): address artifact panel review regressions * fix(web-shell): reconcile split pane artifact snapshots * fix(web-shell): clear pane artifacts on session switch * fix(web-shell): clear stale right panel snapshots * fix(web-shell): repair scheduled task hint string --------- Co-authored-by: ytahdn <ytahdn@gmail.com> Co-authored-by: qwen-code-dev-bot <qwen-code-dev-bot@users.noreply.github.com> * feat(cli): workspace-qualified ACP transport (daemon multi-workspace phase 4) (QwenLM#6621) * docs(design): add daemon multi-workspace phase 4 (workspace-qualified ACP) design * feat(cli): add workspace-qualified ACP transport (issue QwenLM#6378 phase 4) Per-runtime ACP dispatcher at /workspaces/:workspace/acp (HTTP + WS) dispatched by URL path from the single upgrade listener; per-runtime device-flow + reverse client-MCP; owner-index via bridge lifecycle; untrusted/unknown rejected; legacy /acp unchanged; advertise workspace_qualified_acp for multi-workspace. * fix(cli): keep per-runtime device-flow registry out of serve fast-path bundle Phase 4 secondary-runtime device-flow statically imported createDeviceFlowRegistry into run-qwen-serve, pulling glob/@iarna/toml into the serve fast-path bundle and failing the closure check. Import it dynamically at the creation site; the check now passes and behavior is unchanged. * refactor(cli): drop per-runtime device-flow for secondary workspaces Follow-up to the fast-path fix: instead of dynamically importing createDeviceFlowRegistry for secondary runtimes, drop the per-runtime device-flow wiring entirely. Secondary ACP device-flow falls back to the dispatcher default, keeping the serve fast-path bundle closure clean without the dynamic-import indirection. WorkspaceRuntime.deviceFlowRegistry stays optional for a future per-runtime hook. * fix(cli): share daemon-global device-flow across ACP mounts; harden WS path parsing Secondary ACP mounts share the daemon-global device-flow registry (single instance per daemon) instead of a per-runtime one; the event sink fans out to every trusted runtime bridge so secondary ACP clients receive their own flow events, fixing the reviewer QwenLM#6621 Critical and the CI test failure. Drops WorkspaceRuntime.deviceFlowRegistry. WS upgrade path is parsed from the raw request-target instead of new URL().pathname, rejecting %2e%2e / backslash / dot-segment traversal. * refactor(cli): gate CDP claim on primary mount; return plural ACP POST promise Add a primary flag to RuntimeAcpMount so a secondary workspace's ACP connection cannot claim the CDP tunnel -- the claim is gated on activeMount.primary, matching the primary-only chrome-devtools MCP wiring. The plural /workspaces/:workspace/acp POST handler returns the dispatch promise instead of voiding it. * refactor(cli): centralize ACP-HTTP enablement in resolveAcpHttpEnabled Add resolveAcpHttpEnabled() as the single interpretation of the QWEN_SERVE_ACP_HTTP opt-out, replacing four independent env checks across mount, voice-WS advertisement, and CDP-MCP gating. Advertise workspace_qualified_acp only when the ACP HTTP surface is enabled AND multi-workspace sessions are active, so it is not announced when ACP HTTP is disabled. * feat(cli): ACP dispose 503 gate + aggregate connection snapshot across mounts After dispose() the shared ACP HTTP handlers (legacy /acp + workspace-qualified) return 503 server_disposed instead of racing torn-down registries during the shutdown drain. Add AcpHttpHandle.getSnapshot() aggregating connection and wsStream counts across the primary mount and every trusted secondary runtime, and switch the metrics sampler to it so daemon metrics report all workspaces' ACP connections rather than only the primary's. * test(cli): cover ACP dispose 503, aggregate snapshot, and raw dot-segment WS reject * docs(design): record Phase 4 ACP systematic rework (8-axis hardening) Correct the Summary (the device-flow registry stays daemon-global and shared, not per-runtime) and add a section documenting the final architecture: runtime mount factory, routing/trust isolation, raw request-target WS parsing, daemon-global device-flow with event-sink fan-out, primary-only CDP, disposed 503 gate, aggregate getSnapshot, and resolveAcpHttpEnabled-gated capability advertisement. * fix(cli): align /daemon/status ACP counts with the aggregate mount snapshot Code review found a drift: the metrics sampler switched to the aggregate AcpHttpHandle.getSnapshot() (all mounts) while /daemon/status still read the primary-only registry snapshot, so the two observability surfaces diverged under multi-workspace. Extend AcpHttpSnapshot to aggregate all transport counters (connection/session/sse/ws streams + pending client requests) and feed the /daemon/status transport summary from it; per-connection diagnostics and the connection cap stay primary-scoped. Also refresh the device-flow-registry doc comment to the daemon-global shared model. * test(cli): regression-test device-flow on a trusted secondary workspace Locks in the reviewer Critical fix: a trusted secondary workspace's ACP now shares the daemon-global device-flow registry, so device_flow/start reaches provider resolution (an unsupported-provider error here) instead of erroring 'Device flow not configured'. Wires a shared DeviceFlowRegistry into the test harness and drives initialize + device_flow/start over the secondary WebSocket. * docs(design): mark the superseded per-runtime device-flow section Address PR QwenLM#6621 review: the pre-rework 'Per-runtime device-flow registry' section contradicted Systematic rework axis 4 (daemon-global shared registry + fan-out). Flag it as superseded design-history so readers don't build the wrong mental model. * refactor(cli): mount ACP only for trusted secondary workspaces Address PR QwenLM#6621 review suggestions: (1) skip creating a dispatcher/registry/remember-lane for untrusted non-primary workspaces (they are 403-rejected before any mount lookup), so they no longer appear as always-zero entries in the aggregate getSnapshot(); (2) test that a secondary workspace cannot claim the process-wide CDP tunnel (primary-only guard); (3) test that a WS upgrade to an unknown selector is rejected 400. * test(cli): cover device-flow event fan-out across bridges Address PR QwenLM#6621 review: the resolveEventBridges fan-out (the reviewer Critical fix's core delivery path) had zero test coverage. Add unit tests that a device-flow event reaches every resolved bridge, that one bridge throwing does not block the others (best-effort), and that it falls back to the single bridge when no resolver is provided. * fix(cli): report ACP connection pressure across all mounts Address PR QwenLM#6621 review: the connection_capacity_high warning read the primary mount's snapshot only, so a saturated secondary workspace was invisible. Compute the busiest mount from the aggregate snapshot (per-mount cap is uniform, opts.maxConnections) so any mount nearing capacity triggers the warning. * test(cli): allow acp-http-enabled.ts in the serve process.env guard Fix CI failure on PR QwenLM#6621: the serve process.env guard flagged the new acp-http-enabled.ts as a direct process.env reader. It is the QWEN_SERVE_ACP_HTTP interpreter extracted from index.ts and serve-features.ts (both already allow-listed); QWEN_SERVE_ACP_HTTP is a daemon-level process-global toggle, so the file inherits their allow-list entry. * docs: harden workspace-qualified ACP design Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * docs: plan workspace-qualified ACP hardening Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * fix(cli): align workspace-qualified ACP routing Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * fix(cli): harden qualified ACP request errors Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * test(cli): cover unmarked URIError fallback Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * fix(cli): make ACP disposal terminal Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * fix(cli): aggregate ACP connection diagnostics Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * chore: remove review process artifact Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * fix(cli): address workspace ACP review feedback Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> * fix(cli): finish ACP review follow-ups Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> --------- Co-authored-by: Shaojin Wen <shaojin.wensj@alibaba-inc.com> Co-authored-by: qwen-code-dev-bot <qwen-code-dev-bot@users.noreply.github.com> Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com> --------- Co-authored-by: qwen-code-dev-bot <qwen-code-dev-bot@users.noreply.github.com> Co-authored-by: Shaojin Wen <shaojin.wensj@alibaba-inc.com> Co-authored-by: qqqys <qys177@gmail.com> Co-authored-by: qwen-code-dev-bot <qwen-code-dev@service.alibaba.com> Co-authored-by: qwen-autofix[bot] <qwen-autofix[bot]@users.noreply.github.com> Co-authored-by: nas <156536069+Nas01010101@users.noreply.github.com> Co-authored-by: Tianyuan <2720711917@qq.com> Co-authored-by: han <2992336417@qq.com> Co-authored-by: ytahdn <1294726970@qq.com> Co-authored-by: ytahdn <ytahdn@gmail.com> Co-authored-by: jinye <djy1989418@126.com> Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
What this PR does
The
protocol-tags-interactive.test.tsstarted a fake OpenAI server on127.0.0.1without Docker-aware host options. Under theintegration_dockerrelease validation job (QWEN_SANDBOX=docker), the CLI runs inside a Docker container where127.0.0.1resolves to the container's own loopback — not the host where the test server listens. Every model call failed with a connection error, making the retry-response assertion unreachable and failing the entireintegration_dockerjob. The fix binds the fake server to0.0.0.0and advertiseshost.docker.internalas the base URL host when a container sandbox is active, matching the established pattern already used bytool-control.test.ts. TheNO_PROXY/no_proxyenvironment variables are also set to includehost.docker.internalso the CLI inside the container does not route model requests through an HTTP proxy.Why it's needed
Release v0.19.9 failed because the
integration_dockerjob could not complete. The protocol tag retry guard test was introduced after v0.19.8 without Docker networking support, breaking the release validation pipeline. Without this fix, every stable release attempt will fail at the Docker integration step.Reviewer Test Plan
How to verify
Run the interactive integration tests under Docker sandbox:
QWEN_SANDBOX=docker npx vitest run --root ./integration-tests interactive. Confirm thatprotocol-tags-interactive.test.tspasses — the fake server should accept requests from inside the container and the retry assertions should fire. Compare with the non-sandbox run (cross-env QWEN_SANDBOX=false npx vitest run --root ./integration-tests interactive) to confirm both modes pass.Evidence (Before & After)
N/A — this is a test-infrastructure fix with no user-visible TUI changes.
Tested on
Environment (optional)
Verified
npm run build,npm run typecheck, andnpm run linton Linux. Docker not available in the autofix sandbox; the fix follows the exactlistenHost/baseUrlHost/NO_PROXYpattern fromtool-control.test.tswhich already passes under Docker in CI.Risk & Scope
Linked Issues
Fixes #6684
中文说明
protocol-tags-interactive.test.ts在启动 fake OpenAI 服务器时绑定了127.0.0.1,没有配置 Docker 兼容的网络选项。在integration_docker发布验证任务中(QWEN_SANDBOX=docker),CLI 在 Docker 容器内运行,127.0.0.1指向容器自身的回环地址,而非运行测试服务器的主机。所有模型调用因连接错误失败,重试断言无法触发,导致整个integration_docker任务失败,v0.19.9 发布受阻。修复方法是在容器沙箱模式下将 fake 服务器绑定到0.0.0.0并通过host.docker.internal暴露地址,与tool-control.test.ts中已有的成熟模式保持一致。同时设置NO_PROXY环境变量以避免请求被代理。