feat(core): add the output-style layer to the system prompt - #9565
Conversation
Introduces output styles: a named prompt section that changes how the agent reports its work, selected per session. This is the core half — the registry, the four built-in styles, and the prompt wiring. Nothing selects a style yet; the picker, the settings key, and the per-turn reminder follow separately. The style lands at the end of the stable `base` layer: after the mandates it refines, and still ahead of every context/volatile layer, so the prompt prefix stays cacheable for the whole session. Two precedence rules, both following what the file already does for QWEN_SYSTEM_IDENTITY_MD: - A QWEN_SYSTEM_MD override wins. That file is a full, user-owned prompt; layering our section onto it would defeat the override. - The QWEN_WRITE_SYSTEM_MD dump stays a pure base prompt. A style sits on top of a base, so baking it into the dump would apply it twice once that file is fed back through QWEN_SYSTEM_MD. `keepCodingInstructions: false` lets a style replace the base outright, for styles that are not about software engineering at all. All four built-ins keep it true — Proactive in particular changes how much you plan and ask, not what you are allowed to do, and says so in its prompt so it does not read as a second permission knob next to ApprovalMode. Subagents and arena runs deliberately do not inherit the main session's style: it would multiply Explanatory's insight blocks across every child, and skew an arena comparison that is supposed to isolate the model.
|
Re-run on head
Moving on to code review. 🔍 中文说明在 head
进入代码审查。🔍 — Qwen Code · qwen3.8-max Reviewed at |
Code review (head
|
| File | What changed |
|---|---|
packages/core/src/core/output-styles.ts |
New module: four built-in style definitions, section renderer, per-turn reminder, and the apply helper |
packages/core/src/core/prompts.ts |
New fifth outputStyle parameter; workflow section extracted; styled identity sentence; headless-Learning drop; unstyled write-dump |
packages/core/src/core/client.ts |
Shared getMainSessionBaseSystemPrompt selector used by the live system instruction and the /context estimator |
packages/core/src/config/config.ts |
outputStyle field, get/set accessors, ConfigParameters slot |
packages/core/src/agents/arena/ArenaManager.ts |
In-process worker prompts now inherit the active style |
packages/cli/src/ui/commands/contextCommand.ts |
Token estimate now built through the shared selector |
packages/core/src/index.ts |
Exports the new output-styles module |
packages/core/src/core/output-styles.test.ts |
New suite: registry shape, lookup, section rendering, reminder wording, apply identity |
packages/core/src/core/prompts.test.ts |
Layer order, override precedence, identity wording, keepCodingInstructions scope, headless/interactive/acp Learning, identity override, dump purity |
packages/core/src/core/client.test.ts |
Asserts the active style reaches getCoreSystemPrompt as its fifth argument |
packages/core/src/agents/arena/ArenaManager.test.ts |
Worker prompt carries the headless marker and the active style together |
packages/cli/src/ui/commands/contextCommand.test.ts |
Style billed into the estimate; custom-prompt estimate matches the live client |
Test evidence (the PR's own CI — per repo policy I do not run PR code)
All 39 check-runs on the reviewed commit have resolved: the Linux unit suite is green and nothing failed anywhere on this head. The skipped entries are the macOS/Windows matrix and integration jobs that gate on the Linux result — this repo's normal shape.
CI checks at the reviewed commit (Qwen Code CI run: success, Security Checks run: success):
| Check | Conclusion |
|---|---|
| Test (ubuntu-latest, Node 22.x) | ✅ success |
| web-shell E2E Smoke (ubuntu-latest, Node 22.x) | ✅ success |
| precheck-pr / precheck | ✅ success |
| Desktop Shell (ubuntu-22.04) | ✅ success |
| Desktop Shell (windows-2022) | ✅ success |
| Dependency CVE audit | ✅ success |
| Secret scan (TruffleHog) | ✅ success |
| Test (macos-latest, Node 22.x) | ⏭️ skipped (gated on Linux) |
| Test (windows-latest, Node 22.x) | ⏭️ skipped (gated on Linux) |
| Integration Tests (CLI, No Sandbox) | ⏭️ skipped (gated on Linux) |
Sandboxed verification: the previous trigger's run (run 32640968248) passed on head 90e4784e — verdict merge-ready, 52/52 scripted assertions, clean flakiness gate. The only code delta since is the two cosmetic lines above plus main merges that never touch the PR's files, so that A/B evidence still carries. The verify job launched by this trigger (inside run 32683160241) is still in progress and will post its own report here when it completes.
Real-scenario testing: N/A — this run is on the CI path, and there is nothing user-visible to drive on this commit regardless: no surface selects a style yet, so every real session renders exactly the prompt it did before. Not verified: prompt-text quality against a live model (no selection surface exists yet — explicitly out of scope per the PR body).
中文说明
代码审查(head c99e3ace)
这是本 PR 的第四轮评审,距上次深度评审的增量刻意很小,因此本轮是再确认而非首读。90e4784e 之后的变化:
- 接管机器人的四次
main合并。 其中三次完全未触碰 PR 的 12 个文件;一次(5b7a5977)带入了两处 main 侧改动——config.ts中MCPServerConfig新增的versionNegotiation参数与index.ts中的VERTEX_ADC_HINT导出——两者均不与输出风格接线发生交互。 - 一个代码 commit:
ee29373d(+2/−2)。 它把prompt字段的文档注释与渲染器实际输出的标题(# Output Style: <name>)对齐,并补全了 Concise 描述中被截断的句子("…the work stays as thorough as ever")。纯外观:description是选择器文案而目前尚无选择器,也没有任何测试逐字断言这两个字符串。
因此上一轮的实质性结论全部成立,且我在当前 head 上重新核实了每一条关键性质:
- 默认路径保持逐字节不变。
prompts.ts的相关 hunk 自上次评审以来未变;getSoftwareEngineeringTasksSection()的抽取由本 diff 未触碰的快照文件钉住——任何漂移都会使 CI 失败,而此处 CI 为绿。 - 分层、优先级、导出纯净。 风格落在稳定
base层末尾——位于# Core Mandates之后、context/append 各层之前、被缓存前缀之内;QWEN_SYSTEM_MD完全优先;QWEN_WRITE_SYSTEM_MD导出无风格 base,喂回时不会二次应用风格。均有专门测试钉住。 - 共享选择器。
/context与真实客户端都经由client.ts的getMainSessionBaseSystemPrompt;结构化Pick恰好覆盖resolveInteractionMode所读取的内容(已重新核对签名),因此 token 统计不会与真实提示词漂移。 - 调用点审计。
getCoreSystemPrompt的全部非测试消费者——client.ts、ArenaManager.ts、contextCommand.ts——都在带风格的路径上。
无关键阻塞项。上一轮的两条非阻塞观察仍然成立:预留但未接通的表面(setOutputStyle、ConfigParameters.outputStyle、turnReminder、非 built-in 的 source 变体)应真正被后续 PR 消费;headless 下按 style.name === 'Learning' 丢弃的匹配方式,在用户自定义风格出现后应改为定义上的属性。另有一条接管轮次留下的卫生提示:PR 正文的评审测试计划引用测试路径时缺少 packages/core/ 前缀且计数已过时——下次编辑正文时顺手更正即可,不阻塞合入。
(改动文件一览表见上方英文部分。)
测试证据(PR 自己的 CI——按仓库规则我不运行 PR 代码)
受审 commit 上的全部 39 个 check-run 均已落定:Linux 单测套件为绿,该 head 上没有任何失败项。被跳过的条目是等待 Linux 结果的 macOS/Windows 矩阵与集成测试,这是本仓库的正常形态。(检查明细表见上方英文部分的标记区域。)
沙箱验证:上一次触发的运行(run 32640968248)已在 head 90e4784e 上通过——判定可合入,脚本断言 52/52,抖动门干净。其后的代码增量仅为上述两行外观修复与未触碰 PR 文件的 main 合并,因此该 A/B 证据仍然有效。本次触发的验证作业(位于 run 32683160241 内)仍在运行,完成后会在此单独发布报告。
真机测试:N/A——本次运行在 CI 路径上,且该 commit 上本就没有任何用户可见面可驱动:尚无入口选择风格,每个真实会话渲染的提示词与之前完全一致。未验证:提示词文本相对真实模型的质量(尚不存在选择入口——PR 正文已明确列为范围外)。
— Qwen Code · qwen3.8-max
Reviewed at c99e3aced6f20b7bdd352462256d833404372a23 · re-run with @qwen-code /triage
|
Confidence: 4/5 — clean across every stage on the current head; the point off is the same as last time: the staged wiring stays dead until the follow-up PRs land, and the headless-Learning drop still matches on the style name. Stepping back: this re-run had little new to judge — since the last deep pass the branch merged On the evidence: the doubts that would block a merge are absent. There is still no reachable behavior change — nothing selects a style on this commit, so no existing session can regress. The default prompt is pinned byte-identical by untouched snapshots plus green CI, both overrides demonstrably win, and the prior trigger's sandboxed A/B verification passed on a head whose only delta from this one is two cosmetic lines (52/52 scripted assertions, clean flakiness gate). CI on the current head is fully settled — Linux unit suite green, zero failures, no pending PR runs — so the approval below is posted now, pinned to the exact commit reviewed. The verify job launched by this trigger is still in flight and will post its own report separately; it is additional assurance, not a precondition. The small items I am leaving named for the follow-ups, none blocking: consume the staged dead surface ( 中文说明置信度:4/5 —— 当前 head 上各阶段均干净;扣分原因与上次相同:预留接线在后续 PR 落地前仍是死的,headless 下丢弃 Learning 仍按风格名字匹配。 退一步看:这次重跑几乎没有新的判断对象——自上次深度评审以来,分支合并了四次 就证据而言:阻塞合入的疑虑都不存在。仍然没有可达的行为变化——该 commit 上尚无入口选择风格,因此不可能回归任何现有会话。默认提示词由未触碰的快照与绿色 CI 共同钉为逐字节一致,两条完整覆盖路径都明确优先,上一次触发的沙箱 A/B 验证在一个与当前仅差两行外观代码的 head 上通过(脚本断言 52/52,抖动门干净)。当前 head 的 CI 已完全落定——Linux 单测为绿、零失败、无待定的 PR 运行——因此下方的批准现已发布,并钉死在所评审的确切 commit 上。本次触发的验证作业仍在运行,将单独发布报告;它是额外保障,而非前置条件。 留给后续的非阻塞小项:真正消费预留的死代码( — Qwen Code · qwen3.8-max Reviewed at |
`keepCodingInstructions: false` replaced the whole base prompt, which
took the safety rules down with the workflow guidance: a non-coding
style lost `# Executing actions with care`, the mandates, the tool
guidance and the tone section along with the part it meant to drop.
It now omits exactly one section — the software-engineering workflow
guidance, split out as `getSoftwareEngineeringTasksSection()`. Every
other section stays under every style. A style adjusts how work is
reported; it never switches off the rules for taking risky actions.
Two smaller corrections in the same area:
The identity sentence now points at the style when one is active
("responding according to your Output Style below") instead of claiming
the agent specializes in software engineering under a style that says
otherwise. A `QWEN_SYSTEM_IDENTITY_MD` override is still inserted
verbatim — that wording is distributor-owned and not ours to rewrite.
The style section is headed `# Output Style: <name>` rather than
`# <name> Style Active`. The heading is the contract a custom style file
will rely on once user and project styles load: the file body becomes
the prompt verbatim and the heading is what names it.
The per-turn reminder is now every style's, not just the two that spell
one out. `turnReminder` overrides the generic wording rather than
deciding whether a reminder exists at all — an Explanatory session
drifts back to terse answers as readily as a Concise one does.
`getOutputStyleTurnReminder()` renders the line the injection site will
use.
Because the style now feeds the base prompt rather than only being
appended to it, the QWEN_WRITE_SYSTEM_MD dump builds its own unstyled
copy, preserving the invariant that the dump is a reusable base.
The prompts.test.ts snapshots are unchanged, which is the evidence that
a session with no style selected still gets a byte-identical prompt.
qwen-code-ci-bot
left a comment
There was a problem hiding this comment.
Partially reviewed — gaps disclosed. Suggestions are inline.
Not reviewed: build-and-test — Integration Tests (CLI, No Sandbox) was skipped in CI and its suite did not run locally.
Test Plan (not a blocker): src/core/output-styles.test.ts — no such file or directory; src/core/prompts.test.ts — no such file or directory; src/core/client.test.ts — no such file or directory; 479 tests pass — this review observed 22432, 20732, 1638, 1616, 494, 3849, 553 passed; 16 passing — this review observed 22432, 20732, 1638, 1616, 494, 3849, 553 passed.
中文说明
仅完成部分审查,审查缺口已披露。 建议见行内评论。
未审查:build-and-test — Integration Tests (CLI, No Sandbox) was skipped in CI and its suite did not run locally。
Test Plan(非阻断):src/core/output-styles.test.ts — no such file or directory; src/core/prompts.test.ts — no such file or directory; src/core/client.test.ts — no such file or directory; 479 tests pass — this review observed 22432, 20732, 1638, 1616, 494, 3849, 553 passed; 16 passing — this review observed 22432, 20732, 1638, 1616, 494, 3849, 553 passed。
— qwen3.8-max via Qwen Code /review (v0.21.14)
…unpinned Two coverage gaps from the r1 review, both confirmed by mutation probes: R1-1 (prompts.test.ts): the `QWEN_SYSTEM_IDENTITY_MD` override combined with an active output style was pinned by nothing — the identity-override tests pass no style and the `outputStyle parameter` tests never stub the override. Skipping the style append under an override kept all 105 tests green while silently dropping the user's style for every deployment shipping an identity override. The new case asserts the override text wins verbatim, the styled identity sentence is skipped, and `# Output Style: Concise` still lands. R1-2 (contextCommand.test.ts): the `config.getOutputStyle()` forwarding into `getCoreSystemPrompt` was never exercised with a style active — every config mock returned `undefined`. Deleting the argument kept the suite at 16/16 while `/context` undercounted system-prompt tokens by the style section. The new case bills a `Concise` style and asserts the estimate grows by that section. Mutation verification: skipping the style append under an identity override fails only the new prompts case (1 failed | 105 passed); deleting the `config.getOutputStyle()` argument fails only the new contextCommand case (1 failed | 16 passed).
qwen-code-ci-bot
left a comment
There was a problem hiding this comment.
Partially reviewed — gaps disclosed.
Not reviewed: build-and-test — Integration Tests (CLI, No Sandbox) was skipped in CI and its suite did not run locally.
Not reviewed: reverse audit — an auditor ran and opened its brief, but no agent was launched with the prompt the CLI built — the launch was written by hand, and what the agent was actually asked is not what this skill certifies.
Test Plan (not a blocker): src/core/output-styles.test.ts — no such file or directory; src/core/prompts.test.ts — no such file or directory; src/core/client.test.ts — no such file or directory.
Deferred under the convergence posture (round 2, not a blocker) — recorded, not requested in this round:
packages/core/src/config/config.ts:5499 — [review] No round-trip test for the real Config output-style holderpackages/core/src/core/output-styles.ts:27 — [review] Stale heading contract in prompt field docpackages/core/src/core/prompts.test.ts:600 — [probe] Tail-placement test never asserts the style lands last in the base layerpackages/core/src/core/prompts.test.ts:675 — [probe] keepCodingInstructions:false drop test leaves its borders unguardedpackages/core/src/core/output-styles.ts:44 — [review] Concise style description truncated mid-sentence
中文说明
仅完成部分审查,审查缺口已披露。
未审查:build-and-test — Integration Tests (CLI, No Sandbox) was skipped in CI and its suite did not run locally。
未审查:反向审计——有审计 agent 运行并打开了自己的 brief,但没有 agent 是用 CLI 构建的 prompt 启动的——启动 prompt 是手写的,agent 实际被要求做的并不是本 skill 所认证的内容。
Test Plan(非阻断):src/core/output-styles.test.ts — no such file or directory; src/core/prompts.test.ts — no such file or directory; src/core/client.test.ts — no such file or directory。
收敛姿态下延后(第 2 轮,非阻断)——已记录,本轮不要求修改:共 5 条(原文未翻译,列表见上方英文部分)。
— qwen3.8-max via Qwen Code /review (v0.21.14)
wenshao
left a comment
There was a problem hiding this comment.
Partially reviewed — gaps disclosed.
Not reviewed: build-and-test — Integration Tests (CLI, No Sandbox) was skipped in CI and its suite did not run locally.
Test Plan (not a blocker): src/core/output-styles.test.ts — no such file or directory; src/core/prompts.test.ts — no such file or directory; src/core/client.test.ts — no such file or directory.
中文说明
仅完成部分审查,审查缺口已披露。
未审查:build-and-test — Integration Tests (CLI, No Sandbox) was skipped in CI and its suite did not run locally。
Test Plan(非阻断):src/core/output-styles.test.ts — no such file or directory; src/core/prompts.test.ts — no such file or directory; src/core/client.test.ts — no such file or directory。
— glm-5.3 via Qwen Code /review (v0.21.14)
Superseded by subsequent commit cfdbdc5; the current head requires re-review.
qwen-code-ci-bot
left a comment
There was a problem hiding this comment.
Partially reviewed — gaps disclosed. Suggestions are inline.
Not reviewed: build-and-test — Integration Tests (CLI, No Sandbox) was skipped in CI and its suite did not run locally.
Test Plan (not a blocker): src/core/output-styles.test.ts — no such file or directory; src/core/prompts.test.ts — no such file or directory; src/core/client.test.ts — no such file or directory; 479 tests pass — this review observed 22434, 1638, 1616, 494, 3849, 553 passed; 16 passing — this review observed 22434, 1638, 1616, 494, 3849, 553 passed.
Deferred under the convergence posture (round 4, not a blocker) — recorded, not requested in this round:
packages/core/src/core/output-styles.ts:27 — [review] Stale heading contract in OutputStyleDefinition.prompt doc commentpackages/core/src/config/config.ts:2203 — [probe] No round-trip test for the real Config output-style holderpackages/core/src/core/prompts.ts:517 — [probe] Unstyled-dump comment justifies itself with an unreachable double-application hazardpackages/core/src/core/prompts.test.ts:602 — [probe] Tail-placement test pins only the lower bound; 'last in the stable layer' is unpinnedpackages/core/src/core/prompts.test.ts:670 — [probe] keepCodingInstructions:false drop test asserts only 4 of the surviving sections
Convergence: round 4 posted 2 inline comment(s), 2 of them reported for the first time. Findings keep coming back to the same files: packages/core/src/core/prompts.ts (findings in round 3; 1 more now). (Evidence: the previous round was recovered from a marker this account did not post, so those rounds may not be this account's own.) A cluster that keeps producing siblings usually means the fixes are treating instances of a shared root cause — triaging that cause before the next round, or splitting an independent cluster into its own pull request, tends to end the loop faster than fixing them one at a time. (Observation only — nothing was withheld from this review because of this observation.)
中文说明
仅完成部分审查,审查缺口已披露。 建议见行内评论。
未审查:build-and-test — Integration Tests (CLI, No Sandbox) was skipped in CI and its suite did not run locally。
Test Plan(非阻断):src/core/output-styles.test.ts — no such file or directory; src/core/prompts.test.ts — no such file or directory; src/core/client.test.ts — no such file or directory; 479 tests pass — this review observed 22434, 1638, 1616, 494, 3849, 553 passed; 16 passing — this review observed 22434, 1638, 1616, 494, 3849, 553 passed。
收敛姿态下延后(第 4 轮,非阻断)——已记录,本轮不要求修改:共 5 条(原文未翻译,列表见上方英文部分)。
收敛情况:第 4 轮发布了 2 条行内评论,其中 2 条是首次提出。发现反复回到同一批文件:packages/core/src/core/prompts.ts(第 3 轮已出过发现,本轮又有 1 条)。(证据说明:上一轮的数据来自并非本账号发布的标记,上述轮次可能不属于本账号。)一个不断再生兄弟发现的簇,通常意味着逐条修复只在处理同一根因的实例——先定位并处理该根因,或把独立的簇拆成单独的 PR,通常比逐条修复更快结束循环。(仅为观察——本轮评审未因此扣留任何内容。)
— qwen3.8-max via Qwen Code /review (v0.22.0)
qwen-code-ci-bot
left a comment
There was a problem hiding this comment.
Partially reviewed — gaps disclosed. Suggestions are inline.
Not reviewed: build-and-test — Integration Tests (CLI, No Sandbox) was skipped in CI and its suite did not run locally.
Test Plan (not a blocker): src/core/output-styles.test.ts — no such file or directory; src/core/prompts.test.ts — no such file or directory; src/core/client.test.ts — no such file or directory; 479 tests pass — this review observed 20735, 1638, 22434, 1616, 494, 3849, 553 passed; 16 passing — this review observed 20735, 1638, 22434, 1616, 494, 3849, 553 passed.
Deferred under the convergence posture (round 5, not a blocker) — recorded, not requested in this round:
packages/core/src/core/prompts.test.ts:584 — [probe] Describe-scoped ! assertions can silently disarm the headless-Learning negative test
Convergence: round 5 posted 1 inline comment(s), 1 of them reported for the first time; the previous round posted 2 (2 new). Findings keep coming back to the same files: packages/core/src/core/prompts.test.ts (findings in round 4; 1 more now). A cluster that keeps producing siblings usually means the fixes are treating instances of a shared root cause — triaging that cause before the next round, or splitting an independent cluster into its own pull request, tends to end the loop faster than fixing them one at a time. No Critical finding is open on this round, so merging and moving the remaining Suggestion threads to a follow-up issue is available as an ending — a merged pull request cannot diverge further. (Observation only — nothing was withheld from this review because of this observation.)
中文说明
仅完成部分审查,审查缺口已披露。 建议见行内评论。
未审查:build-and-test — Integration Tests (CLI, No Sandbox) was skipped in CI and its suite did not run locally。
Test Plan(非阻断):src/core/output-styles.test.ts — no such file or directory; src/core/prompts.test.ts — no such file or directory; src/core/client.test.ts — no such file or directory; 479 tests pass — this review observed 20735, 1638, 22434, 1616, 494, 3849, 553 passed; 16 passing — this review observed 20735, 1638, 22434, 1616, 494, 3849, 553 passed。
收敛姿态下延后(第 5 轮,非阻断)——已记录,本轮不要求修改:共 1 条(原文未翻译,列表见上方英文部分)。
收敛情况:第 5 轮发布了 1 条行内评论,其中 1 条是首次提出;上一轮发布了 2 条(其中 2 条首次提出)。发现反复回到同一批文件:packages/core/src/core/prompts.test.ts(第 4 轮已出过发现,本轮又有 1 条)。一个不断再生兄弟发现的簇,通常意味着逐条修复只在处理同一根因的实例——先定位并处理该根因,或把独立的簇拆成单独的 PR,通常比逐条修复更快结束循环。本轮没有未决的 Critical,因此"合入后把剩余 Suggestion 线程转到后续 issue"是一个可选的结束方式——已合入的 PR 不会继续发散。(仅为观察——本轮评审未因此扣留任何内容。)
— qwen3.8-max via Qwen Code /review (v0.22.0)
qwen-code-ci-bot
left a comment
There was a problem hiding this comment.
Partially reviewed — gaps disclosed.
Not reviewed: build-and-test — Integration Tests (CLI, No Sandbox) was skipped in CI and its suite did not run locally.
Test Plan (not a blocker): src/core/output-styles.test.ts — no such file or directory; src/core/prompts.test.ts — no such file or directory; src/core/client.test.ts — no such file or directory.
中文说明
仅完成部分审查,审查缺口已披露。
未审查:build-and-test — Integration Tests (CLI, No Sandbox) was skipped in CI and its suite did not run locally。
Test Plan(非阻断):src/core/output-styles.test.ts — no such file or directory; src/core/prompts.test.ts — no such file or directory; src/core/client.test.ts — no such file or directory。
— qwen3.8-max via Qwen Code /review (v0.22.0)
|
@qwen-code /takeover |
|
🤝 Takeover engaged: the autofix loop now manages this PR — it will address new review feedback and resolve base conflicts until the label is removed or the round cap is reached. This is a fork PR, so the first round comes from the next scheduled scan (usually within minutes). Remove the 中文说明🤝 已接管:autofix 循环现在管理此 PR —— 将持续处理新的评审反馈与 base 冲突,直到移除标签或达到轮次上限。本 PR 来自 fork,首轮处理将由下一次定时扫描执行(通常几分钟内)。移除 |
|
🤖 Reviewed the latest feedback — no changes needed. Why, point by point: · 已审阅最新反馈——无需改动。逐点说明原因如下: Autofix round: no action needed on PR #9565This round found no actionable feedback, and every previously raised finding was re-verified as already fixed in the current head ( Why no action
Re-verification of the eight findings (all resolved in code)
Environment repair (no code or lockfile change)The first local Verification
中文说明Autofix 轮次:PR #9565 无需操作本轮没有可执行的反馈,此前提出的全部发现均已重新验证为已在当前 head( 为什么无需操作
八条发现的重新验证(均已在代码中解决)
环境修复(未改动任何代码或 lockfile)首次本地 验证
Base-conflict check · 基分支冲突检查: no conflict with main. · 与 main 无冲突。 🧠 Handled by Qwen Code · model/模型 |
|
@qwen-code /triage |
qwen-code-ci-bot
left a comment
There was a problem hiding this comment.
Not reviewed: build-and-test — Integration Tests (CLI, No Sandbox) was skipped in CI and its suite did not run locally.
Test Plan (not a blocker): src/core/output-styles.test.ts — no such file or directory; src/core/prompts.test.ts — no such file or directory; src/core/client.test.ts — no such file or directory; 479 tests pass — this review observed 1685, 1653, 495, 4164, 599 passed; 16 passing — this review observed 1685, 1653, 495, 4164, 599 passed.
Deferred under the convergence posture (round 8, not a blocker) — recorded, not requested in this round:
packages/core/src/core/output-styles.ts:27 — [review] Stale heading contract in OutputStyleDefinition.prompt doc commentpackages/core/src/config/config.ts:5516 — [review] No round-trip test for the real Config output-style holder
中文说明
未审查:build-and-test — Integration Tests (CLI, No Sandbox) was skipped in CI and its suite did not run locally。
Test Plan(非阻断):src/core/output-styles.test.ts — no such file or directory; src/core/prompts.test.ts — no such file or directory; src/core/client.test.ts — no such file or directory; 479 tests pass — this review observed 1685, 1653, 495, 4164, 599 passed; 16 passing — this review observed 1685, 1653, 495, 4164, 599 passed。
收敛姿态下延后(第 8 轮,非阻断)——已记录,本轮不要求修改:共 2 条(原文未翻译,列表见上方英文部分)。
— qwen3.8-max via Qwen Code /review (v0.22.0)
|
🤖 Addressed the latest review feedback (round 3/100). What changed, and what I pushed back on: · 已处理最新评审反馈(第 3/100 轮)。改动内容与我反驳保留之处如下: Round summary — PR #9565 (address-review)One commit this round: Diagnosis of the failing Test checkTwo independent facts, each evidenced: 1. The recorded failure for the current head is a 19-second early-job failure, not a test failure. The check run for head 2. If the job runs to completion on current main, it will fail the workflow-size ratchet — a defect inherited from main. A full local reproduction of the Test job's substance (details in Verification) shows every workspace suite green (cli 875/875, core 604 passed + 1 skipped, vscode-ide-companion 54/54, web-shell 197/197, desktop 35/35, all smaller packages green). The one deterministic red is:
The one-line fix (record 42519 in Feedback dispositions
Changes
No conflicts this round ( VerificationCommands actually run this round (after the committed change unless noted):
Not run: the no-AK integration gate's vitest leg and the Chrome-extension packaging step (both only run after the unit leg in CI; the gate's tsc leg is verified above, and the unit leg is where any substantive red would surface). The PR's behavioral A/B evidence remains the sandboxed verification report (52/52 assertions, mutation matrix 8/8). 中文说明本轮摘要 — PR #9565(address-review)本轮提交一个 commit: Test 检查失败的诊断两个各自有证据支撑的事实: 1. 当前 head 上记录的这次失败是 19 秒的早期 job 失败,不是测试失败。 head 2. 若 job 在当前 main 上完整跑完,会挂在 workflow 大小 ratchet 上——这是继承自 main 的缺陷。 对 Test job 实质内容的完整本地复现(细节见 Verification)显示所有 workspace 套件全绿(cli 875/875、core 604 通过 + 1 跳过、vscode-ide-companion 54/54、web-shell 197/197、desktop 35/35,其余小包全绿)。唯一确定性红色是:
一行修复(把 反馈处置
变更内容
本轮无冲突( Verification(验证)本轮实际执行的命令(除特别注明外均在提交之后运行):
未运行:no-AK 集成门的 vitest 段与 Chrome 扩展打包步骤(两者在 CI 中都排在单元测试段之后;该门的 tsc 段已在上方验证,且任何实质红色都会出现在单元测试段)。PR 的行为级 A/B 证据仍以沙箱验证报告为准(52/52 断言、变异矩阵 8/8)。 Base-conflict check · 基分支冲突检查: no conflict with main. · 与 main 无冲突。 Re-review when you have a moment. After round 100 this bot stops and leaves the PR for a human. · 有空请复审;第 100 轮后本 bot 停止并将 PR 交给人工。 🧠 Handled by Qwen Code · model/模型 |
qwen-code-ci-bot
left a comment
There was a problem hiding this comment.
Not reviewed: build-and-test — Integration Tests (CLI, No Sandbox) was skipped in CI and its suite did not run locally.
Test Plan (not a blocker): src/core/output-styles.test.ts — no such file or directory; src/core/prompts.test.ts — no such file or directory; src/core/client.test.ts — no such file or directory; 479 tests pass — this review observed 1685, 23496, 1653, 495, 4164, 599 passed; 16 passing — this review observed 1685, 23496, 1653, 495, 4164, 599 passed.
Deferred under the convergence posture (round 9, not a blocker) — recorded, not requested in this round:
packages/core/src/config/config.ts:981 — [review] Output-style layer has no producer; present-tense doc comments overstate live behavior
中文说明
未审查:build-and-test — Integration Tests (CLI, No Sandbox) was skipped in CI and its suite did not run locally。
Test Plan(非阻断):src/core/output-styles.test.ts — no such file or directory; src/core/prompts.test.ts — no such file or directory; src/core/client.test.ts — no such file or directory; 479 tests pass — this review observed 1685, 23496, 1653, 495, 4164, 599 passed; 16 passing — this review observed 1685, 23496, 1653, 495, 4164, 599 passed。
收敛姿态下延后(第 9 轮,非阻断)——已记录,本轮不要求修改:共 1 条(原文未翻译,列表见上方英文部分)。
— qwen3.8-max via Qwen Code /review (v0.22.0)
|
🔀 Base updated: red check(s) [Test (ubuntu-latest, Node 22.x)] pass on current main — merged current main via update-branch; CI will re-run. 中文说明🔀 已更新 base:红色检查 [Test (ubuntu-latest, Node 22.x)] 在当前 main 上通过 —— 已通过 update-branch 合入当前 main,CI 将重新运行。 |
qwen-code-ci-bot
left a comment
There was a problem hiding this comment.
Not reviewed: build-and-test — Integration Tests (CLI, No Sandbox) was skipped in CI and its suite did not run locally.
Test Plan (not a blocker): src/core/output-styles.test.ts — no such file or directory; src/core/prompts.test.ts — no such file or directory; src/core/client.test.ts — no such file or directory; 479 tests pass — this review observed 23526, 21070, 1685, 1654, 495, 4190, 610 passed; 16 passing — this review observed 23526, 21070, 1685, 1654, 495, 4190, 610 passed.
Deferred under the convergence posture (round 10, not a blocker) — recorded, not requested in this round:
packages/core/src/config/config.ts:5517 — [probe] No round-trip test for the real Config output-style holderpackages/core/src/core/prompts.test.ts:603 — [probe] Tail-placement test pins only a band, not "last in the base layer"packages/core/src/core/prompts.test.ts:669 — [probe] keepCodingInstructions:false drop test leaves splice-adjacent base content unguardedpackages/core/src/core/prompts.test.ts:776 — [probe] QWEN_WRITE_SYSTEM_MD dump test discards the returned prompt; styled-return invariant unpinned
中文说明
未审查:build-and-test — Integration Tests (CLI, No Sandbox) was skipped in CI and its suite did not run locally。
Test Plan(非阻断):src/core/output-styles.test.ts — no such file or directory; src/core/prompts.test.ts — no such file or directory; src/core/client.test.ts — no such file or directory; 479 tests pass — this review observed 23526, 21070, 1685, 1654, 495, 4190, 610 passed; 16 passing — this review observed 23526, 21070, 1685, 1654, 495, 4190, 610 passed。
收敛姿态下延后(第 10 轮,非阻断)——已记录,本轮不要求修改:共 4 条(原文未翻译,列表见上方英文部分)。
— qwen3.8-max via Qwen Code /review (v0.22.0)
|
🤖 Could not produce a passing fix for this feedback (round 4/100). This item now needs a human; the loop stays engaged and still picks up new feedback and base conflicts, but will not retry this item on its own. What I found before stopping: Autofix stopped: the red Test check is caused by a broken workflow-size baseline on
|
|
🔀 Base updated: red check(s) [Test (ubuntu-latest, Node 22.x)] pass on current main — merged current main via update-branch; CI will re-run. 中文说明🔀 已更新 base:红色检查 [Test (ubuntu-latest, Node 22.x)] 在当前 main 上通过 —— 已通过 update-branch 合入当前 main,CI 将重新运行。 |
qwen-code-ci-bot
left a comment
There was a problem hiding this comment.
Partially reviewed — gaps disclosed.
Not reviewed: build-and-test — Integration Tests (CLI, No Sandbox) was skipped in CI and its suite did not run locally.
Test Plan (not a blocker): src/core/output-styles.test.ts — no such file or directory; src/core/prompts.test.ts — no such file or directory; src/core/client.test.ts — no such file or directory; 479 tests pass — this review observed 21070, 1685, 1654, 495, 4190, 610 passed; 16 passing — this review observed 21070, 1685, 1654, 495, 4190, 610 passed.
Deferred under the convergence posture (round 11, not a blocker) — recorded, not requested in this round:
packages/core/src/config/config.ts:5526 — [review] Output-style layer has no producer — the entire surface added by this PR is staged and unwiredpackages/core/src/core/output-styles.ts:161 — [review] Turn-reminder mechanism exported, tested and documented as live, but no production consumerpackages/core/src/core/output-styles.ts:12 — [review] OutputStyleSource ships three never-populated variants; docs advertise contracts to nonexistent consumerspackages/core/src/core/output-styles.test.ts:50 (+2 locations) — [review] Test text states the inverse of keepCodingInstructions semanticspackages/core/src/core/prompts.ts:517 (+2 locations) — [probe] Dump-rationale comments teach a nonexistent double-applicationpackages/core/src/core/prompts.test.ts:769 — [probe] Styled dump test discards the returned prompt; styled-return invariant unpinnedpackages/core/src/core/prompts.ts:520 — [probe] Dump bakes interaction-mode wording into a file declared reusable across modes
中文说明
仅完成部分审查,审查缺口已披露。
未审查:build-and-test — Integration Tests (CLI, No Sandbox) was skipped in CI and its suite did not run locally。
Test Plan(非阻断):src/core/output-styles.test.ts — no such file or directory; src/core/prompts.test.ts — no such file or directory; src/core/client.test.ts — no such file or directory; 479 tests pass — this review observed 21070, 1685, 1654, 495, 4190, 610 passed; 16 passing — this review observed 21070, 1685, 1654, 495, 4190, 610 passed。
收敛姿态下延后(第 11 轮,非阻断)——已记录,本轮不要求修改:共 7 条(原文未翻译,列表见上方英文部分)。
— qwen3.8-max via Qwen Code /review (v0.22.0)
|
🤖 Reviewed the latest feedback — no changes needed. Why, point by point: · 已审阅最新反馈——无需改动。逐点说明原因如下: Autofix round: no action required on PR #9565No commit was made this round. HEAD ( Why no changeNo actionable feedback arrived since the last evaluation (2026-08-23T22:07:50Z):
Points checked that needed no code change
VerificationNo verification commands were run because no code change was made; the head commit is the exact one CI already validated (all runnable checks green). 中文说明Autofix 本轮:PR #9565 无需处理本轮未产生任何提交。HEAD( 为什么没有改动自上次评估(2026-08-23T22:07:50Z)以来,没有收到任何需要处理的反馈:
已核查但无需改代码的要点
验证由于没有做任何代码改动,本轮未运行任何验证命令;头提交正是 CI 已验证过的那个提交(所有可运行的检查均为绿色)。 Base-conflict check · 基分支冲突检查: no conflict with main. · 与 main 无冲突。 🧠 Handled by Qwen Code · model/模型 |
|
@qwen-code /triage |
|
Sandboxed verification: ✅ passed — merge-ready (agent verdict) - workflow run Ran the PR in an isolated, token-free container: A/B against the base build, mock-free harness assertions, targeted gates. Advisory evidence for human reviewers — not a review, an approval, or a CI check. Scripted assertions: 114 passed · 0 failed · 114 total Flakiness gate: ✅ 5 changed test file(s) x 5 identical rounds, no divergence 中文 — 判定:✅ 通过 · 可合入(agent 判定)沙箱验证在隔离、无凭证的容器中执行了该 PR 的代码(与 base 构建 A/B 对照、无 mock harness 断言、定向门禁)。仅作为评审证据,不构成评审、批准或 CI 检查。 脚本断言:114 通过 · 0 失败 · 114 总计 抖动门:✅ 5 changed test file(s) x 5 identical rounds, no divergence Verification reportPR 9565 Deep Verification (follow-up round) — feat(core): add the output-style layer to the system promptVerdict: 中文摘要
Previous-finding status (follow-up round)
Round-1's Not covered note on this container's Central claim and A/B proofCentral claim: when a style is selected it lands at the tail of the The A/B drives the compiled
Harness: Closure audit (required before trusting a base control in a monorepo): Delta since the previous round
Mutation matrix (vacuity of the new tests)Each row reverts one guard of the PR in the head tree, runs the four
M1, M3–M7 each fail exactly the test that pins the reverted guard; M2's Targeted gates
The round-1 parallel timeout is attributed to container load, not to this FindingsNit (informational, for the follow-up wiring PR):
|
qwen-code-ci-bot
left a comment
There was a problem hiding this comment.
LGTM, looks ready to ship. ✅
|
🤖 Reviewed the latest feedback — no changes needed. Why, point by point: · 已审阅最新反馈——无需改动。逐点说明原因如下: Autofix round: no action required on PR #9565No commit was made this round. HEAD ( Why no changePoint by point, against the feedback prepared for this round:
The loop remains engaged and will pick up the verification report, any new maintainer or automated-reviewer feedback, and any future base conflict in later rounds. 中文说明Autofix 本轮:PR #9565 无需改动本轮没有产生提交。HEAD( 为什么无需改动针对本轮准备的反馈,逐点说明:
循环保持启用状态,后续轮次会处理验证报告、任何新的维护者或自动评审反馈,以及任何未来出现的 base 冲突。 Base-conflict check · 基分支冲突检查: no conflict with main. · 与 main 无冲突。 🧠 Handled by Qwen Code · model/模型 |
|
Maintainer-local verification: ✅ passed — merge-ready (agent verdict, independent round) Ran an independent local verification round on the same head the latest CI sandbox round verified ( 72 scripted assertions: 72 pass · 0 fail. Advisory evidence for human reviewers — not a review, an approval, or a CI check. 中文 — 判定:✅ 通过 · 可合入(维护者本地独立验证轮)在与最新一轮 CI 沙箱验证相同的 head( Verification reportPR 9565 Local Deep Verification (maintainer round, macOS) — feat(core): add the output-style layer to the system promptVerdict: This is an independent maintainer-local round at the same head the latest CI 中文摘要
Previous-finding status (carried from the CI round at the same head)
Central claim and A/B proofCentral claim: a selected style lands at the tail of the stable Independent harness (
The base arm's control cells (B3/B4, F1b, J1b) are what make the head cells Cross-machine corroboration: the default-prompt sha ( Mutation matrix (vacuity re-check, macOS)Each row reverts one guard in
M1–M4 re-prove on this arm the same guards the CI round's matrix covered (its GatesWitness:
Merge-forward verification (new in this round)
FindingsNone new. All 72 assertions passed; no regression reproduced; the three Not covered
MethodologyMaintainer laptop, macOS (darwin), Node v24.18.1, npm 11.16.0, machine load — Qwen Code · maintainer-local verification round Evidence images— Qwen Code · maintainer-local verification round |
|
🤖 Reviewed the latest feedback — no changes needed. Why, point by point: · 已审阅最新反馈——无需改动。逐点说明原因如下: 🤖 AutoFix review round: no code changes needed Feedback triaged this round: a single issue-level comment — a maintainer-local deep-verification report on head The carried-over items it re-lists were each probed against the code before disposition (authorship adds no credibility — only execution evidence does):
No code was changed and nothing was committed. The PR stays at 中文说明🤖 AutoFix 评审轮:无需代码改动 本轮处理的反馈: 仅一条 issue 级评论 —— 维护者在 head 报告重新列出的各项遗留发现均已先探针核实、再定处置(来源不增减可信度,只有执行证据才算数):
本轮未改动任何代码、未产生任何提交。PR 保持在 Base-conflict check · 基分支冲突检查: no conflict with main. · 与 main 无冲突。 🧠 Handled by Qwen Code · model/模型 |
|
Released in v0.22.2. |








What this PR does
This adds output styles to Qwen Code: a named block of instructions that changes how the agent reports its work, chosen once and applied for the whole session. Four styles ship built in — Concise answers first and drops preamble and narration, Proactive starts working instead of proposing and prefers a stated assumption over a question, Explanatory teaches about the codebase while it changes it, and Learning hands the user small design decisions to implement by hand and then waits for them.
This is the core half of the feature. It introduces the style registry, the four built-in definitions, the accessors on
Config, and the wiring that layers a style into the system prompt. It deliberately stops short of letting anyone pick one: there is no slash command, no settings key, and no CLI flag yet, so on this commit alone no session's prompt changes. Selection surfaces follow in separate PRs, which keeps the prompt-layering question — where the style goes and what it must not disturb — reviewable on its own.A style is appended to the end of the stable
baselayer thatassembleSystemPromptalready defines. That position matters twice over: it puts the style after the mandates it is meant to refine, and it keeps the style ahead of every context and volatile layer, so a session's prompt prefix stays cacheable for its whole life rather than being invalidated on each memory save.Two precedence rules fall out of that, and both follow what
prompts.tsalready does forQWEN_SYSTEM_IDENTITY_MD. First, aQWEN_SYSTEM_MDoverride wins outright and the style is ignored — that file is a complete, user-owned prompt, and layering our section onto it would defeat the point of the override. Second, theQWEN_WRITE_SYSTEM_MDdump stays a pure base prompt with no style baked in, because a style is meant to sit on top of a base; writing it into the dump would apply it a second time as soon as that file is fed back throughQWEN_SYSTEM_MD.The
keepCodingInstructionsflag omits exactly one section of the base prompt — the software-engineering workflow guidance, split out here asgetSoftwareEngineeringTasksSection()— for a style whose work is not coding. Nothing else is affected: identity, mandates, the# Executing actions with caresafety rules, tool guidance, and tone stay in force under every style. A style adjusts how work is reported; it never switches off the rules for taking risky actions. All four built-ins keep the flagtrueregardless.When a style is active the identity sentence points at it rather than claiming the agent specializes in software engineering, and the style section is headed
# Output Style: <name>— the heading a custom style file will rely on once user- and project-level styles load, since such a file's body becomes the prompt verbatim. AQWEN_SYSTEM_IDENTITY_MDoverride is still inserted untouched, because that wording is distributor-owned.Every active style carries a per-turn reminder; the optional
turnReminderfield replaces the generic wording rather than deciding whether a reminder exists at all. An Explanatory session drifts back to terse answers as readily as a Concise one does.getOutputStyleTurnReminder()renders the line; the injection site itself lands in a follow-up.Why it's needed
The tone and shape of the agent's responses is currently fixed. A user who wants terser output, or who wants the agent to explain its reasoning as it goes, has only
--append-system-promptandQWEN_SYSTEM_MD— one is a per-invocation flag with no persistence and no discovery, and the other is an all-or-nothing replacement of the entire prompt that the user then has to maintain by hand against every upstream change. Neither is something a user can reasonably discover or switch between.There is also an existing wire-protocol commitment with nothing behind it: the
system/initmessage declaresoutput_style?: stringin bothpackages/cli/src/nonInteractive/types.tsandpackages/sdk-typescript/src/types/protocol.ts, and no code anywhere populates it. Similarly,packages/core/src/extension/claude-converter.tsalready parses anoutputStylesfield out of converted Claude plugins and merges it as metadata that nothing consumes. This PR builds the layer those two stubs were waiting for.Finally, the interaction between a style and prompt caching is the part of this feature that is easiest to get wrong and hardest to notice: a style placed in the volatile tail would silently re-bill the entire prompt on every memory save. Landing the layering decision separately, with tests that pin the layer order, makes that reviewable before any UI depends on it.
Reviewer Test Plan
How to verify
The behaviour to confirm is that a style lands in the right place in the prompt and that the two overrides win where they should. Run
npx vitest run src/core/output-styles.test.ts src/core/prompts.test.ts src/core/client.test.tsfrompackages/core— 479 tests pass, 24 of them new. The assertion most worth reading is that akeepCodingInstructions: falsestyle drops## Software Engineering Taskswhile# Core Mandates,# Executing actions with care,## Using Your Toolsand## Tone and Styleall survive. The interesting ones are in theoutputStyle parameterblock ofprompts.test.ts: they assert the style section appears after# Core Mandatesand before both the context-files and append-prompt markers, that it disappears entirely whenQWEN_SYSTEM_MDis set, and that it never reaches the file written byQWEN_WRITE_SYSTEM_MD.For the plumbing,
client.test.tsgains a case asserting thatConfig.getOutputStyle()reachesgetCoreSystemPromptas its fifth argument, andpackages/cli'scontextCommand.test.ts(16 passing) covers the/contextestimator, which has to build the same string that is actually sent or its token accounting drifts.Reviewers should also confirm the negative: with nothing selecting a style, the default prompt is byte-identical to before. The existing
prompts.test.tssnapshot is unchanged in this diff, which is the evidence for that.Two known pre-existing failures show up when running the full suites as root, in
skill-curator.test.tsandsession-writer-lease.test.tsfor core, plus seven in cli. All were confirmed to fail identically on a cleanupstream/maincheckout with this branch's changes stashed; they are chmod-based tests that cannot fail as uid 0 and are unrelated to this change.Evidence (Before & After)
N/A — no user-visible surface in this PR. Nothing selects a style yet, so the rendered prompt is unchanged for every existing session; the UI that makes this visible lands in the follow-up.
Tested on
Environment
Linux, Node 22.23.0, npm 10.9.8. Unit tests only, plus
npm run typecheckfor@qwen-code/qwen-code-coreand@qwen-code/qwen-code, andeslintandprettier --checkover every changed file. Note that typechecking the cli package requiresnpm run build --workspace @qwen-code/qwen-code-corefirst, since the cli resolves core through its builtdistdeclarations.Risk & Scope
baselayer, which is also wheresetStaticSystemPrefixdraws the cache boundary for the Anthropic converter. Placing it there is what keeps the prefix stable across a session, but it does mean that switching styles mid-session invalidates the cached prefix once — the cost is paid on the switch, not on every turn.Config.setOutputStyledocuments that callers must follow a mid-session change withGeminiClient.refreshSystemInstruction(), since the style lives in an already-bound system instruction.output_stylefield onsystem/init, and theoutputStylesfield thatclaude-converter.tsalready parses all remain unwired. The per-turn reminder is rendered but not yet injected anywhere — that arrives with the reminder-injection PR.getCoreSystemPromptgains an optional fifth parameter andConfiggains two accessors; every existing call site and every default-path prompt is unchanged. Hand-writtenConfigmocks in tests do need the newgetOutputStyleaccessor added, which is whyclient.test.tsandcontextCommand.test.tsappear in this diff.Linked Issues
None.
中文说明
这个 PR 做了什么
本 PR 为 Qwen Code 引入 output styles(输出风格):一段具名的指令块,用来改变 agent 汇报工作的方式,选定一次后在整个会话中生效。内置四种风格 —— Concise 先给结论、去掉铺垫与过程叙述;Proactive 直接动手而不是先提方案,并且倾向于给出一个明确的假设而非发问;Explanatory 在改动代码的同时讲解这个代码库;Learning 把小的设计决策交给用户亲手实现,然后停下来等待。
这是该功能的 core 部分。它引入了风格注册表、四个内置风格定义、
Config上的读写方法,以及把风格叠进系统提示词的接线。它刻意没有提供任何选择入口:目前没有斜杠命令、没有 settings 键、也没有 CLI 参数,所以仅凭这个 commit,任何会话的提示词都不会发生变化。选择入口会在后续 PR 中加入,这样「风格放在哪一层、不能扰动什么」这个提示词分层问题就可以被单独评审。风格被追加到
assembleSystemPrompt已经定义好的稳定base层的末尾。这个位置有双重意义:它让风格排在它所要修饰的 mandates 之后,同时又让风格排在所有 context 层和 volatile 层之前,因此一个会话的提示词前缀在整个生命周期内都保持可缓存,而不会在每次保存记忆时被作废。由此引出两条优先级规则,两条都沿用
prompts.ts对QWEN_SYSTEM_IDENTITY_MD已有的处理方式。第一,QWEN_SYSTEM_MD覆盖优先级最高,此时风格被忽略 —— 那个文件是一份完整的、由用户拥有的提示词,把我们的段落叠上去会违背覆盖本身的意图。第二,QWEN_WRITE_SYSTEM_MD导出的文件保持为纯粹的 base 提示词,不烘焙进风格,因为风格本就是叠在 base 之上的;一旦写进导出文件,这份文件再被QWEN_SYSTEM_MD读回时风格就会被应用两次。keepCodingInstructions标志只会省略 base 提示词中的一节 —— 软件工程工作流指引,本 PR 中被拆分为getSoftwareEngineeringTasksSection()—— 供那些工作内容并非编码的风格使用。其余部分一律不受影响:identity、mandates、# Executing actions with care安全条款、工具指引和语气段落在任何风格下都完整生效。风格调整的是工作如何被汇报,它绝不关闭执行高风险操作的规则。四个内置风格无论如何都保持该标志为true。当有风格生效时,identity 句子会指向该风格,而不再声称 agent 专精于软件工程;风格段落的标题为
# Output Style: <name>—— 这正是将来用户级/项目级自定义风格文件所依赖的标题,因为这类文件的正文会原样成为 prompt。QWEN_SYSTEM_IDENTITY_MD覆盖仍然原封不动地插入,因为那是发行方拥有的措辞。每一个生效的风格都带有每轮提醒;可选的
turnReminder字段替换的是通用文案,而不是决定提醒是否存在。Explanatory 会话漂移回简短回答的速度,和 Concise 会话一样快。getOutputStyleTurnReminder()负责渲染这一行;注入点本身在后续 PR 中落地。为什么需要它
目前 agent 回复的语气和形态是固定的。想要更简短的输出,或者想让 agent 边做边解释思路的用户,只有
--append-system-prompt和QWEN_SYSTEM_MD两条路 —— 前者是每次调用都要带的参数,既不持久也无从发现;后者是对整个提示词的全有或全无式替换,之后用户还得自己手工跟进上游的每一次改动。两者都不是用户能合理发现或在其间切换的东西。另外还存在一处已经承诺、但背后空无一物的线协议:
system/init消息在packages/cli/src/nonInteractive/types.ts和packages/sdk-typescript/src/types/protocol.ts中都声明了output_style?: string,而全仓库没有任何代码写入它。同样地,packages/core/src/extension/claude-converter.ts已经会从转换后的 Claude 插件里解析出outputStyles字段并作为元数据合并,但没有任何消费方。本 PR 补上了这两处存根一直在等的那一层。最后,风格与提示词缓存之间的相互作用,是这个功能里最容易做错、也最难被察觉的部分:一个被放进易变尾部的风格,会在每次保存记忆时悄悄地把整个提示词重新计费。把分层决策单独落地,并用测试钉死层序,可以让这一点在任何 UI 依赖它之前就得到评审。
评审者测试计划
如何验证
需要确认的行为是:风格落在提示词的正确位置,并且两个覆盖机制在该赢的地方赢。在
packages/core下运行npx vitest run src/core/output-styles.test.ts src/core/prompts.test.ts src/core/client.test.ts—— 479 个测试通过,其中 24 个是新增的。最值得一读的断言是:keepCodingInstructions: false的风格会丢掉## Software Engineering Tasks,而# Core Mandates、# Executing actions with care、## Using Your Tools和## Tone and Style全部保留。值得关注的是prompts.test.ts里的outputStyle parameter块:它断言风格段落出现在# Core Mandates之后、且在 context-files 与 append-prompt 两个标记之前,断言设置QWEN_SYSTEM_MD时风格完全消失,以及断言风格绝不会进入QWEN_WRITE_SYSTEM_MD写出的文件。关于接线部分,
client.test.ts新增了一个用例,断言Config.getOutputStyle()会作为第五个参数抵达getCoreSystemPrompt;packages/cli的contextCommand.test.ts(16 个通过)覆盖/context估算器 —— 它必须构造出与实际发送完全相同的字符串,否则 token 统计会漂移。评审者还应确认反面情况:在没有任何东西选中风格时,默认提示词与之前逐字节一致。本 diff 中
prompts.test.ts的快照文件没有变化,这就是该结论的证据。以 root 身份运行完整测试套件时会出现若干已存在的失败:core 侧在
skill-curator.test.ts和session-writer-lease.test.ts各一个,cli 侧七个。已通过把本分支改动 stash 后在干净的upstream/main检出上复跑确认,它们以完全相同的方式失败;这些是基于 chmod 的测试,在 uid 0 下不可能失败,与本次改动无关。证据(Before & After)
N/A —— 本 PR 没有任何用户可见界面。目前没有东西会选中风格,因此对所有既有会话而言渲染出的提示词没有变化;让它变得可见的 UI 会在后续 PR 中落地。
测试环境
环境(可选)
Linux,Node 22.23.0,npm 10.9.8。仅单元测试,外加对
@qwen-code/qwen-code-core和@qwen-code/qwen-code的npm run typecheck,以及对所有改动文件的eslint与prettier --check。注意:对 cli 包做类型检查前需要先执行npm run build --workspace @qwen-code/qwen-code-core,因为 cli 是通过 core 构建出的dist声明来解析类型的。风险与影响范围
base层的尾部,而这里也正是setStaticSystemPrefix为 Anthropic 转换器划定缓存边界的位置。放在这里正是保证前缀在会话内稳定的原因,但这也意味着会话中途切换风格会使缓存前缀失效一次 —— 代价付在切换那一刻,而不是每一轮。Config.setOutputStyle已在文档中说明:会话中途修改的调用方必须随后调用GeminiClient.refreshSystemInstruction(),因为风格存在于一个已经绑定的 system instruction 之中。system/init上的output_style字段,以及claude-converter.ts已经在解析的outputStyles字段,都仍未接线。每轮提醒(turn reminder)已可渲染,但尚未注入到任何地方 —— 那部分会随提醒注入的 PR 一起到来。getCoreSystemPrompt新增一个可选的第五参数,Config新增两个方法;所有既有调用点和所有走默认路径的提示词都不受影响。测试中手写的Configmock 确实需要补上新的getOutputStyle方法,这就是client.test.ts和contextCommand.test.ts出现在本 diff 中的原因。关联 Issue
无。