feat: register toggle-only reasoning for Qwen hybrid models - #9574
Conversation
|
✅ Qwen Triage finished — CI landed green on ✅ Qwen Triage 已完成 —— |
|
Thanks for the PR! Template looks good ✓ Problem: verified gap, not theoretical. On Direction: aligned. This is a direct continuation of #8974 (WebShell Qwen 3.8 reasoning controls, same author) and the ACP reasoning-effort work (#8526); the CHANGELOG shows this is an actively maintained product area. Registering only officially verified exact ids — and explicitly deferring DeepSeek / GLM / Kimi / Grok because the capability lookup is keyed by model id alone — is the right conservative call, and the design doc records the reasoning. Size: cross-package ( Approach: scope feels right. Every file serves the stated goal — manifest, ACP projection + handler, webui mapper, WebShell component, tests at each layer, e2e smoke, design doc — with no drive-by changes. The discriminated union (toggle-only vs tiered) is the minimal way to express the capability, and it reuses the existing Risk: Moving on to code review. 🔍 中文说明感谢贡献! 模板完整 ✓ 问题:已验证的真实缺口,不是理论问题。在 方向:对齐。这是 #8974(WebShell Qwen 3.8 推理控制,同一作者)和 ACP reasoning-effort 工作(#8526)的直接延续,CHANGELOG 表明这是产品持续投入的方向。只注册有官方证据的精确模型 ID,并明确推迟 DeepSeek / GLM / Kimi / Grok(因为能力查找只按模型 ID 匹配)——这个保守决策是对的,设计文档也记录了理由。 规模:跨包改动( 方案:范围合理。每个文件都服务于既定目标——清单、ACP 投影 + 处理器、webui 映射、WebShell 组件、各层测试、e2e smoke、设计文档——没有顺手改动。用可辨识联合(仅开关 vs 分档)表达能力是最小方案,并且复用了现有 风险: 进入代码审查 🔍 — Qwen Code · qwen3.8-max Reviewed at |
|
Code review — no blockers found. Before reading the diff my independent proposal was exactly what this PR does: a discriminated union in the manifest (toggle-only vs tiered),
The only nit, not worth blocking: the sequenceDiagram
participant P1 as User
participant P2 as ChatEditor (web-shell)
participant P3 as ACP agent (daemon)
participant P4 as Generation config
participant P5 as mapReasoningControls (webui)
P1->>P2: toggles Thinking
P2->>P3: setSessionConfigOption(reasoning_effort, none or default)
P3->>P4: reasoning = false or cleared
P3-->>P5: updated configOptions
P5-->>P2: enabled flag plus empty efforts
P2-->>P1: chip shows Thinking or Thinking Off
Files changed (9 of 9)
Testing (this is an unattended CI run — PR code is never executed here; evidence is the PR's own CI, fetched via API at review time): nothing red so far. Final CI results for
One row per check name (latest run); skipped checks omitted; failures sort first. / 每个检查名一行(取最新一次运行),省略 skipped,失败项排在最前。 Not verified: that a live DashScope-backed session on one of the five models actually advertises the toggle and honors 中文说明代码审查 —— 未发现阻塞问题。读 diff 之前我的独立方案与本 PR 完全一致:清单用可辨识联合(仅开关 vs 分档)、复用现有 ACP 的 none/default 协议、webui 映射为空强度列表、弹层条件渲染——没有更简路径被遗漏。已验证:
唯一的小瑕疵(不阻塞):处理器里 selected 的嵌套三元较密,但有测试覆盖且与周边风格一致。 时序图展示了开关切换的完整回路:用户切换 Thinking → ChatEditor 发送 none 或 default → ACP agent 清除或关闭 generation.reasoning → 更新后的 configOptions 经 webui 映射(空强度列表)回流 → 模型标签显示 Thinking 或 Thinking Off。 测试(无人值守 CI 运行——此处绝不执行 PR 代码,证据来自 PR 自身 CI 的 API 查询):目前无红色。Real daemon E2E、完整 CodeQL 矩阵、密钥扫描、依赖 CVE 审计、两个 Desktop Shell 检查在本 commit 上已通过;主单元测试与 web-shell 视觉采集仍在运行,表格会在 CI 结束后原地更新。macOS/Windows 测试、CLI 集成测试、tmux/verify 按设计跳过。无失败任务,故无日志摘录。 未验证:真实 DashScope 会话在这五个模型上是否端到端展示开关并遵守 none/default——单元测试对真实 ACP 处理器使用 mock 会话配置,浏览器 smoke 使用 mock daemon 场景。沙箱验证可以补齐: — Qwen Code · qwen3.8-max Reviewed at |
|
Confidence: 4/5 — clean review at every stage I could check; two non-blocking reservations: the main unit suite and the web-shell visuals were still running at review time (approval below is gated on them landing green), and the live-daemon round trip is substantiated only by mocked harnesses (the Stepping back: the gap was verified on The implementation matches my independent proposal; I didn't find a simpler path it missed. The union type makes invalid capability states unrepresentable, the explicit The Approval is deferred until CI lands green on 中文说明置信度:4/5 —— 各阶段检查都很干净;两个非阻塞保留项:审查时主单元测试与 web-shell 视觉采集仍在运行(下方批准以其全绿为前提),且真实 daemon 的端到端回路目前只有 mock 场景佐证(审查评论中已点名 回顾:在读任何代码之前已在 实现与我的独立方案一致,没有发现更简路径。可辨识联合让无效能力状态无法表达;显式的 toggleOnly 元数据门控让旧 daemon 与旧 ACP 客户端保持现状;none/default 回路在每一环闭合(处理器、投影、映射、开关重开、模型标签)。每个文件都服务于目标,无顺手改动;测试固定了行为,包括防止清单扩大到别名/变体的反向用例。设计文档记录了六个月后维护者会问到的决策(为什么只注册这五个精确 ID)。
批准推迟到该 commit 的 CI 全绿后执行——finalize 工作流会在所有检查通过后按已审查的 commit 提交批准;若有检查变红或 head 移动则不会批准。 — Qwen Code · qwen3.8-max Reviewed at |
🖼️ web-shell visual previewRendered against a mock daemon (no real backend): the PR base vs this PR head Screenshots · before / afterFull-resolution recordings (.webm) are attached to the workflow run. — Qwen Code · web-shell visuals |
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. |
qwen-code-ci-bot
left a comment
There was a problem hiding this comment.
LGTM, looks ready to ship — CI landed green after the review. ✅
ytahdn
left a comment
There was a problem hiding this comment.
审查结论:Approve ✅
总体评价
本 PR 将"仅开关型推理"(toggle-only reasoning)作为一等概念引入,设计清晰、跨层一致、测试充分,未发现阻塞性问题。
🎉 亮点
- 采用判别联合
ModelReasoningConfiguration将 toggle-only({thinking:true, toggleOnly:true})与 tiered({thinking:true, efforts, defaultEffort})明确区分,比在既有结构上打补丁更干净。 getModelConfiguration从硬编码modelId === 'qwen3.8-max'改为基于 manifest 的精确 id 查表(MODEL_CONFIGURATIONS),后续新增 hybrid 模型只需注册条目,无需改动逻辑代码。- 跨层一致性已在 head tree 上逐一核实:
- ACP:
setSessionConfigOption的reasoning_effort处理器对 toggle-only 模型仅接受none/default,其余值返回正确的候选列表报错;default→reasoning = undefined、none→reasoning = false映射正确。 - webui:
mapReasoningControls将 toggleOnly 映射为空efforts,ChatEditor 依据efforts.length > 0隐藏 effort 区块,chip 标签走reasoning.thinking,避开了不存在的reasoning.effort.defaultkey(中英文 i18n key 均已确认存在)。 - 生成管线:
isTieredEffortWireModel仅匹配qwen3.8-max*,toggle 模型可通过getReasoningEffortOverride门控;禁用时enable_thinking: false确实会下发到 wire。
- ACP:
- 测试覆盖到位:manifest 精确匹配的正向/负向测试、非法 effort 值的拒绝测试、mapper 单测与 e2e 均有覆盖。
🟢 Nit(不阻塞)
- configOptions 投影中
selected的计算使用较深的嵌套三元表达式,可读性一般,属纯风格问题。
💡 说明(不阻塞)
- 本 PR 的验证基于 mock harness,live DashScope 端到端往返未覆盖——属现有测试基建状况,非本 PR 引入的缺口。
Review Verdict: Approve ✅
Overall
This PR introduces toggle-only reasoning as a first-class concept with a clean design, verified cross-layer consistency, and solid test coverage. No blocking issues found.
🎉 Highlights
- The discriminated union
ModelReasoningConfigurationcleanly separates toggle-only ({thinking:true, toggleOnly:true}) from tiered ({thinking:true, efforts, defaultEffort}) configurations. getModelConfigurationmoves from a hardcodedmodelId === 'qwen3.8-max'check to a manifest-based exact-id lookup (MODEL_CONFIGURATIONS), so registering new hybrid models requires no logic changes.- Cross-layer consistency verified against the head tree:
- ACP: the
reasoning_efforthandler insetSessionConfigOptionaccepts onlynone/defaultfor toggle-only models and rejects other values with the correct choices list;default→reasoning = undefinedandnone→reasoning = falsemap correctly. - webui:
mapReasoningControlsmaps toggleOnly to emptyefforts; ChatEditor hides the effort section whenefforts.length === 0, and the chip label usesreasoning.thinking, avoiding the nonexistentreasoning.effort.defaultkey (both EN/ZH i18n keys confirmed present). - Generation pipeline:
isTieredEffortWireModelmatches onlyqwen3.8-max*, so toggle models pass thegetReasoningEffortOverridegate, andenable_thinking: falsegenuinely reaches the wire when disabled.
- ACP: the
- Good test coverage: positive and negative manifest matching tests, rejection tests for invalid effort values, mapper unit tests, and e2e coverage.
🟢 Nit (non-blocking)
- The
selectedcomputation in the configOptions projection uses a dense nested ternary; purely a readability style point.
💡 Note (non-blocking)
- Verification relies on mocked harnesses; a live DashScope end-to-end round trip is not covered — this reflects the existing test infrastructure rather than a gap introduced by this PR.
|
Released in v0.21.15. |
What this PR does
Registers accurate reasoning controls for the exact stable
qwen3.5-plus,qwen3.6-plus,qwen3.6-flash,qwen3.7-plus, andqwen3.7-maxmodel ids. These hybrid-thinking models now expose a Thinking switch without invented effort tiers, whileqwen3.8-maxkeeps its existing nativelow,medium, andxhighcontrols.Selecting Thinking off disables reasoning for the live session. Re-enabling it clears the session override and restores the existing model or provider default. The WebShell model popover hides the effort section for toggle-only models and shows
ThinkingorThinking Offon the model chip.The capability decisions and official Alibaba Cloud references are recorded in the design note. Exact-id matching remains deliberate; aliases and unverified variants are not inferred.
Why it's needed
The existing model manifest could only represent optional thinking together with discrete effort levels. Copying the Qwen 3.8 tiers to older hybrid-thinking Qwen models would advertise controls that their Chat Completions APIs do not support, while omitting them leaves valid Thinking on/off behavior unavailable in WebShell.
Parallel official-document research also covered DeepSeek, GLM, Kimi, and Grok. They remain out of scope because their reasoning wire parameters or defaults vary by provider, while the current capability lookup only has a model id. Registering them here could display a control whose selected value is not sent correctly.
Reviewer Test Plan
How to verify
Thinking.none, the switch turns off, and the chip showsThinking Off.default, the switch turns on, and no effort rows appear.qwen3.8-maxand confirm its existinglow,medium, andxhighrows still work.latest, or uppercase variant and confirm it does not receive model-specific controls.Evidence (Before & After)
Before: the five hybrid-thinking models had no model-popover Thinking control because they could not be represented without fake effort tiers.
After: the browser smoke verifies a switch-only popover and the real
nonethendefaultconfig-option payload sequence; the existing Qwen 3.8 browser scenario passes unchanged.Tested on
Environment (optional)
Node.js 22.17.0, local worktree, no sandbox. Verified with
npm run build,npm run typecheck, focused ESLint and Prettier checks, 459 CLI manifest/ACP tests, 17 WebUI mapper tests, 153 DashScope provider tests, and two Chromium reasoning smoke tests.Risk & Scope
Linked Issues
N/A
中文说明
本 PR 做了什么
为精确稳定模型 ID
qwen3.5-plus、qwen3.6-plus、qwen3.6-flash、qwen3.7-plus和qwen3.7-max注册准确的推理控制。这些混合思考模型现在只展示 Thinking 开关,不虚构强度档位;qwen3.8-max继续保留已有的原生low、medium和xhigh控制。关闭 Thinking 会在当前实时会话中禁用推理。重新开启会清除会话覆盖并恢复现有模型或 provider 默认值。WebShell 的模型弹层会为仅开关模型隐藏强度区域,并在模型标签上显示
Thinking或Thinking Off。能力决策和阿里云官方资料已记录在设计说明中。模型仍按精确 ID 匹配,不推断别名或未验证变体。
为什么需要
现有模型清单只能表达“可选思考 + 离散强度档位”。如果直接复制 Qwen 3.8 的档位,会向旧版混合思考 Qwen 模型展示其 Chat Completions API 不支持的控制;如果不注册,又会让 WebShell 无法使用真实有效的 Thinking 开关能力。
并行官方资料调研还覆盖了 DeepSeek、GLM、Kimi 和 Grok。它们暂不纳入,因为不同 provider 的推理 wire 参数或默认值存在差异,而当前能力查找只有模型 ID;在这里直接注册可能导致界面显示的控制没有被正确发送。
Reviewer 测试计划
如何验证
Thinking。none、开关关闭,且标签显示Thinking Off。default、开关开启,且仍无强度行。qwen3.8-max重复验证,确认已有low、medium、xhigh强度行保持正常。latest或大写变体,确认不会获得模型专属控制。证据(Before & After)
Before:五个混合思考模型无法在不虚构强度档位的前提下表达,因此模型弹层没有 Thinking 控制。
After:浏览器 smoke 验证了仅开关弹层以及真实的
none、default配置请求顺序;现有 Qwen 3.8 浏览器场景保持通过。测试平台
环境(可选)
Node.js 22.17.0,本地 worktree,无 sandbox。已验证
npm run build、npm run typecheck、聚焦 ESLint 和 Prettier 检查、459 个 CLI 清单/ACP 测试、17 个 WebUI mapper 测试、153 个 DashScope provider 测试,以及两条 Chromium reasoning smoke 测试。风险与范围
关联 Issue
无。