refactor(goal): render Goal continuation prompts from one core renderer - #9581
Conversation
The prompt sent when `runtime.finishTurn` schedules another Goal turn was assembled independently in three hosts: the TUI's inline array in `useGeminiStream`, and a `buildGoalContinuationParts` in each of the ACP session and the non-interactive CLI. Three copies of the same four shared lines have already drifted -- the TUI carries the anti-spoofing guard lines but no objective, while ACP and non-interactive carry the runtime continuation context but no guard lines. Upcoming work adds further variants (an "objective was edited" announcement and a budget wind-down prompt). With the text living in three places, every new variant means three edits, which is precisely how the current drift was produced. This moves assembly into `packages/core/src/goals/goal-continuation-prompt.ts`, where a variant is a case in one function and the shared prefix exists once. The two `buildGoalContinuationParts` helpers keep their names and signatures and simply delegate. This is a pure refactor: no prompt text changes. Each host still emits a byte-identical string to the one it emitted before. The existing drift is preserved deliberately and is left for a separate, behavior-changing follow-up. The new unit test pins the complete rendered string for both variants with and without verifier feedback, so any future edit to a line surfaces as a test diff; the existing host tests pass unmodified. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
Re-run on an unmoved head — nothing has landed since the last pass reviewed Thanks for the PR! Template looks good ✓ Problem: real and observable in-tree, not theoretical. On Direction: aligned. Consolidating the assembly into one core renderer ahead of the announced further Goal variants is the right sequencing, and keeping the output byte-identical makes the change reviewable as a pure refactor. Reconciling the drift is correctly deferred to its own PR, since that is a model-visible behavior change. Size: 137 production lines — Session.ts 18, nonInteractiveCli.ts 18, useGeminiStream.ts 16, new core module 80, goals/index.ts 5 — plus 155 test lines and no generated/schema lines. Well under the 500-line Tier 1 threshold for core refactors, so no hard block; the Tier 2 100%-confidence bar for core changes applies and is the standard this pass held the diff to. Approach: matches the independent proposal — one renderer in Risk: Moving on to code review. 🔍 中文说明在未移动的 head 上重跑——自上次审查 感谢贡献! 模板完整 ✓ 问题:真实存在、可在代码树中直接观察到,而非理论问题。在 方向:对齐。在已预告的 Goal 新变体之前把拼装收敛到 core 的单一 renderer,时机正确;保持输出逐字节不变,使该改动可以作为纯重构来审查。统一措辞漂移正确地留到单独 PR——那是模型可见的行为变更。 规模:137 行生产代码(Session.ts 18、nonInteractiveCli.ts 18、useGeminiStream.ts 16、新 core 模块 80、goals/index.ts 5)+ 155 行测试,无生成/schema 行。远低于 core 重构 500 行的 Tier 1 阈值,不触发硬拦截;适用 Tier 2 对 core 改动的 100% 置信标准,本次也按此标准审查。 方案:与独立提案一致——在 风险: 进入代码审查。🔍 — Qwen Code · qwen3.8-max Reviewed at |
Code review — re-run on an unmoved headNothing has landed since Independent proposal first: three copies of the same prompt have drifted; the fix I'd reach for is one renderer in Byte-identity, re-checked line by line against base:
Nothing else in the diff: no export collisions (grepped core for the new symbol names), Testing evidence — the PR's own CI, read via the APIPer the unattended-run rules, no PR code is built or executed here. Check-runs below were fetched from the commits API for
The unit suite is green on this exact head, and there are no red checks — the only non-green conclusions are skips and duplicate orchestration jobs cancelled in favor of their successful twins. The macOS/Windows unit jobs and the sandboxed integration job being skipped is consistent with fork-PR runner/secret limits, not a failure signal; for a diff that is pure string assembly with no platform-specific path the coverage gap is immaterial — and it is closed by the sandboxed A/B below anyway. On the behavioural claim itself — byte-identical prompts — CI green only shows the tests pass, and this PR's static review is unusually well-placed to settle the rest: the pinned literal tests fail on any edit to any line, and I re-compared every removed expression against the base tree character by character. Independently, the thread already carries three passing sandboxed 中文说明代码审查——未移动 head 上的重跑自上次审查 独立提案:三份相同提示词已经漂移;我会采用的修法是在 逐字节一致性,已逐行对照 base 复核:
diff 中再无其他:无导出名冲突, 测试证据——PR 自身 CI,经 API 读取无人值守运行规则下,此处不构建、不执行任何 PR 代码。检查项取自 — Qwen Code · qwen3.8-max Reviewed at |
|
Confidence: 3/5 — clean re-derivation on an unmoved head; the fork-refactor approval guardrail, not any finding, caps the score and keeps the bot's approval out. Stepping back: nothing has moved since the last pass reviewed It is a fork ⏸️ Deferring to @wenshao — fork-refactor approval guardrail. The gate has no findings of its own against this head; 中文说明置信度:3/5 —— 在未移动 head 上重新推导后结论干净;压低分数、扣下机器人批准的不是任何发现,而是 fork 重构 PR 的审批护栏。 退一步看:自上次审查 这是一个 fork 的 ⏸️ 转交 @wenshao —— fork 重构审批护栏。门禁对该 head 没有任何自己的发现; — Qwen Code · qwen3.8-max Reviewed at |
qwen-code-ci-bot
left a comment
There was a problem hiding this comment.
Reviewed — no blockers. Suggestions are inline.
中文说明
已审查——无阻断问题。 建议见行内评论。
— qwen3.8-max via Qwen Code /review (v0.21.14)
qwen-code-ci-bot
left a comment
There was a problem hiding this comment.
Reviewed — no blockers. Suggestions are inline.
中文说明
已审查——无阻断问题。 建议见行内评论。
— qwen3.8-max via Qwen Code /review (v0.21.14)
qwen-code-ci-bot
left a comment
There was a problem hiding this comment.
Reviewed. Suggestions are inline.
Not explored to full depth (tool budget reached): "agent 6c": root-cause the observed one-off flake (instrument bindGoalTurnHost invocation order and goalOrigin of the first send, then repeat runs until failure to iden….
中文说明
已审查。 建议见行内评论。
未探索到全部深度(达到工具调用预算):"agent 6c":root-cause the observed one-off flake (instrument bindGoalTurnHost invocation order and goalOrigin of the first send, then repeat runs until failure to iden…。
— qwen3.8-max via Qwen Code /review (v0.21.14)
|
@qwen-code takeover |
|
@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,首轮处理将由下一次定时扫描执行(通常几分钟内)。移除 |
|
🤖 Addressed the latest review feedback (round 1/100). What changed, and what I pushed back on: · 已处理最新评审反馈(第 1/100 轮)。改动内容与我反驳保留之处如下: Autofix review-response summary — PR #9581 (round on HEAD
|
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.
中文说明
仅完成部分审查,审查缺口已披露。
未审查:build-and-test — Integration Tests (CLI, No Sandbox) was skipped in CI and its suite did not run locally。
— qwen3.8-max via Qwen Code /review (v0.22.0)
|
🤖 Reviewed the latest feedback — no changes needed. Why, point by point: · 已审阅最新反馈——无需改动。逐点说明原因如下: Autofix round: no code changesFeedback triageThis round's feedback contains a single item: review
There are no inline comments, no issue-level comments, no failed checks, and no still-red checks. Nothing requests a code change. Why the check was "skipped" in CI: the Decision: since the disclosed gap is the only actionable content, this round closes it with local evidence instead of a code change. No code was modified; HEAD remains Closing the gap locallyThe environment needed repair before the suite could run (details below), then the exact disclosed suite was run against the bundled CLI built from this PR's HEAD:
The single failure is environmental, proven by surrogate:
All Goal-related and ACP/serve/headless integration tests in the suite passed. Environment repairs performed (not code changes)
Verification
Conclusion: no action required on the code. The disclosed verification gap is closed with local evidence: the merge-queue-only integration suite passes on this PR's HEAD except for one test proven to fail solely because this self-hosted runner's 中文说明Autofix 本轮:无代码改动反馈分诊本轮反馈仅包含一条:自动审查器的评审
没有行内评论、没有 issue 级评论、没有失败检查、也没有持续失败的检查。没有任何内容要求代码改动。 该检查在 CI 中"被跳过"的原因: 决定: 由于披露的缺口是唯一可操作的内容,本轮用本地证据来弥补它,而不是做代码改动。未修改任何代码;HEAD 仍为 在本地弥补该缺口运行套件前需要先修复环境(详见下文),随后针对从本 PR HEAD 构建的捆绑 CLI 运行了被披露的那个套件:
唯一的失败是环境性的,已通过替代实验证明:
套件中所有与 Goal 相关以及 ACP/serve/headless 的集成测试均已通过。 所执行的环境修复(非代码改动)
验证
结论: 代码无需任何改动。披露的验证缺口已用本地证据弥补:仅限合并队列运行的集成套件在本 PR 的 HEAD 上全部通过,唯一例外的那个测试已被证明仅因本自托管运行器的 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: 161 passed · 0 failed · 161 total Flakiness gate: ✅ 3 changed test file(s) x 5 identical rounds, no divergence 中文 — 判定:✅ 通过 · 可合入(agent 判定)沙箱验证在隔离、无凭证的容器中执行了该 PR 的代码(与 base 构建 A/B 对照、无 mock harness 断言、定向门禁)。仅作为评审证据,不构成评审、批准或 CI 检查。 脚本断言:161 通过 · 0 失败 · 161 总计 抖动门:✅ 3 changed test file(s) x 5 identical rounds, no divergence Verification reportPR 9581 — refactor(goal): render Goal continuation prompts from one core rendererVerdict: 中文摘要
Central claim and A/BCentral claim: this is a pure refactor — each host (interactive TUI, ACP session, non-interactive CLI) sends a byte-identical Goal continuation prompt before and after; the three drifted assemblies collapse into one core renderer with two variants ( Control construction: the pre-change assemblies were extracted verbatim from
Bonus census: the two pre-change ACP/headless helpers were byte-identical to each other on all 63 cells (they were duplicate code), and a repo-wide grep census shows exactly 3 production assemblers at base → exactly 1 at head ( Secondary claimsPinned-literal tests are load-bearing. Mutation matrix (
6/6 rows as expected; source restored clean after each row. Discriminated-union contract. A Host suites are the regression check. Test-file diffs are purely additive (0 removed lines across FindingsNo blocking findings. Two description-level nits:
Not covered
MethodologyEnvironment: Flakiness gate logEvidence imagesHarness scripts and raw logs are in the workflow run artifacts (7-day retention). — Qwen Code · sandboxed verification |
|
Triage re-run completed without a new review.
The stage comments above were updated with the latest result. View workflow run. 上方各阶段评论已更新为最新结果。查看工作流运行。 |
|
🤖 AutoFix updated a stale base — the fix did not pass verification, but this PR was behind Round summary — same-run verification repair (base update)This round had one actionable item: the Same-run verification repair notice. The previous commit was rejected because the deterministic gate's Root cause (evidence-based)
Change madeOne follow-up commit, preserving all previously committed (rejected) work: `Merge remote-tracking branch 'origin/main' into goal/b1-continu Why it was not pushed: Note: the base has since been auto-updated; the verdict below predates that update, and the next round's re-measurement may charge the round. tests failed in packages/cli 中文说明🤖 AutoFix 更新了一个过期的 base —— 修复未通过验证,但本 PR 落后于 验证门的拒绝原因与日志证据见上方英文部分(gate-rejection 不翻译)。 Run log: https://github.com/QwenLM/qwen-code/actions/runs/32608884687 🧠 Handled by Qwen Code · model/模型 |
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.
中文说明
仅完成部分审查,审查缺口已披露。
未审查:build-and-test — Integration Tests (CLI, No Sandbox) was skipped in CI and its suite did not run locally。
— qwen3.8-max via Qwen Code /review (v0.22.0)
|
@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: 284 passed · 0 failed · 284 total Flakiness gate: ✅ 3 changed test file(s) x 5 identical rounds, no divergence 中文 — 判定:✅ 通过 · 可合入(agent 判定)沙箱验证在隔离、无凭证的容器中执行了该 PR 的代码(与 base 构建 A/B 对照、无 mock harness 断言、定向门禁)。仅作为评审证据,不构成评审、批准或 CI 检查。 脚本断言:284 通过 · 0 失败 · 284 总计 抖动门:✅ 3 changed test file(s) x 5 identical rounds, no divergence Verification report<!-- qwen-triage:verify --> Verdict: 中文摘要
Previous-finding status (follow-up round)
I agree with both nit classifications: neither is blocking, and both remain true. Central claim and A/BCentral claim (unchanged): pure refactor — each host (interactive TUI, ACP session, non-interactive CLI) sends a byte-identical Goal continuation prompt before and after; the three drifted assemblies collapse into one core renderer ( Control construction (re-run at the new base): the pre-change assemblers were extracted verbatim from
Assembler census: exactly 3 production assemblers at base → exactly 1 at head ( Secondary claimsPinned-literal tests are load-bearing (re-run). Mutation matrix (
12/12 matrix assertions as expected; source restored byte-identical afterwards ( Discriminated-union contract (re-run, witness Host suites are the regression check (re-run): FindingsNo new findings. The two carried nits (previous-finding table rows 1–2) stand; both are description-level and non-blocking. Not covered
MethodologyEnvironment: Flakiness gate logEvidence imagesHarness scripts and raw logs are in the workflow run artifacts (7-day retention). — Qwen Code · sandboxed verification |
|
Triage re-run completed without a new review.
The stage comments above were updated with the latest result. View workflow run. 上方各阶段评论已更新为最新结果。查看工作流运行。 |
|
🤖 Reviewed the latest feedback — no changes needed. Why, point by point: · 已审阅最新反馈——无需改动。逐点说明原因如下: Autofix round: no action requiredNo new review findings to address this round: both automated reviews in the window posted zero findings (their ledgers record Feedback triage
Gate rejection diagnosisThe rejected gate ran Two facts explain the shape of the rejection:
Evidence the failures are environmental, not caused by this PR:
There is no in-scope change to make: hardening unrelated tests would be an out-of-footprint edit, and the verification machinery itself is off-limits. The rejection note itself states the verdict predates the base auto-update; the next gate re-measurement on the updated base is the correct resolution path. VerificationCommands actually run this round at head
中文说明Autofix 轮次:无需任何改动本轮没有新的评审发现需要处理:窗口内的两条自动评审均为零发现(其 ledger 记录为 反馈分类
验证门拒绝的诊断被拒绝的门在 有两个事实解释了该拒绝的形态:
以下证据表明失败是环境问题,而非本 PR 引起:
不存在范围内的改动可做:加固无关测试属于足迹(footprint)之外的编辑,验证机制本身也不允许触碰。拒绝说明本身也已注明该判定早于 base 自动更新;在更新后的 base 上由下一次门的重新测量来解决,才是正确的路径。 验证本轮在当前 head
Base-conflict check · 基分支冲突检查: no conflict with main. · 与 main 无冲突。 🧠 Handled by Qwen Code · model/模型 |
|
✅ Verdict: merge-ready — 55/55 scripted byte-identity assertions passed, 0 unexpected failures. Verified head: 中文摘要结论:可以合并。 中央主张已通过独立 A/B:从 base 提交的三个 host 原始拼装逻辑得到的 UTF-8 字节,与 head 上新 core renderer 的输出在完整矩阵中逐字节一致,详见下方 Central claim and A/B 表及 Central claim and A/BClaim: this PR is a pure refactor: each host must emit exactly the same Goal continuation prompt bytes as the base commit for every supported input shape. The control expressions were transcribed line-for-line from the deleted assemblies at base
The empty feedback string remained omitted under the original truthiness rule. The existing host split also remained intact: TUI keeps the two synthetic-turn anti-spoofing lines, while ACP and non-interactive keep Evidence: FindingsNone. Targeted gatesAll commands ran against the exact head in a credential-free,
Evidence: Not covered
MethodologyMetadata and exact base/head OIDs were resolved outside the sandbox with |
|
🤖 Reviewed the latest feedback — no changes needed. Why, point by point: · 已审阅最新反馈——无需改动。逐点说明原因如下: Autofix round: no action requiredNo new review findings to address this round; the PR stays as-is at Feedback triageThe workflow prepared exactly one feedback item newer than the last evaluation (2026-08-23T04:23:32Z):
Checks and threads
ConclusionNothing in this round's feedback is actionable. No code changes were made and nothing was committed; the branch remains at 中文说明Autofix 本轮:无需任何操作本轮没有新的评审发现需要处理,PR 保持原样,停留在 反馈分类相对上次评估(2026-08-23T04:23:32Z),工作流只准备了一条更新的反馈:
检查与讨论串
结论本轮反馈中没有任何可操作项。未做任何代码改动,也没有提交任何内容;分支保持在 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: 234 passed · 0 failed · 234 total Flakiness gate: ✅ 3 changed test file(s) x 5 identical rounds, no divergence 中文 — 判定:✅ 通过 · 可合入(agent 判定)沙箱验证在隔离、无凭证的容器中执行了该 PR 的代码(与 base 构建 A/B 对照、无 mock harness 断言、定向门禁)。仅作为评审证据,不构成评审、批准或 CI 检查。 脚本断言:234 通过 · 0 失败 · 234 总计 抖动门:✅ 3 changed test file(s) x 5 identical rounds, no divergence Verification report<!-- qwen-triage:verify --> Verdict: 中文摘要
Previous-finding status (follow-up round)Note: this round re-ran at the same head (
Central claim and A/BCentral claim (unchanged): pure refactor — each host (interactive TUI, ACP session, non-interactive CLI) sends a byte-identical Goal continuation prompt before and after; the three drifted assemblies collapse into one core renderer ( Control construction (re-run): the pre-change assemblers were extracted verbatim from
189/189 assertions in this harness ( Secondary claimsPinned-literal tests are load-bearing (re-run). Mutation matrix (
22/22 matrix assertions as expected. Discriminated-union contract (re-run, witness Host suites are the regression check (re-run, witness FindingsNo new findings. The two carried nits (previous-finding table rows 1–2) stand; both are description-level and non-blocking. Not covered
MethodologyEnvironment: Flakiness gate logEvidence imagesHarness scripts and raw logs are in the workflow run artifacts (7-day retention). — Qwen Code · sandboxed verification |
|
🤖 Reviewed the latest feedback — no changes needed. Why, point by point: · 已审阅最新反馈——无需改动。逐点说明原因如下: 🤖 Reviewed the latest feedback — no changes needed. Why, point by point:
The working tree stays as-is; no commit was made this round. 中文说明🤖 已审阅最新反馈 —— 无需任何改动。 逐点说明:
工作区保持原样;本轮没有产生任何提交。 Base-conflict check · 基分支冲突检查: no conflict with main. · 与 main 无冲突。 🧠 Handled by Qwen Code · model/模型 |
|
Triage re-run completed without a new review.
The stage comments above were updated with the latest result. View workflow run. 上方各阶段评论已更新为最新结果。查看工作流运行。 |
|
🤖 Reviewed the latest feedback — no changes needed. Why, point by point: · 已审阅最新反馈——无需改动。逐点说明原因如下: Autofix round report — PR #9581 (no action taken)SummaryThis round's feedback contains no new findings. All six inline items are author replies ("Fixed in …") to earlier automated-reviewer findings, and the six review bodies are the empty COMMENTED vehicles carrying those replies. There are no issue-level comments and no still-red checks: the only non-success checks in the window are five No code changes were made this round. Instead, every claimed fix was re-verified source-blind against HEAD Verification of each claimed fix
All three fix commits ( Verification
中文说明Autofix 轮次报告 — PR #9581(未采取行动)摘要本轮反馈中没有新的发现项。全部六条行内条目都是作者对此前自动审查发现项的回复("Fixed in …"),六条评审主体(review body)只是承载这些回复的空 COMMENTED 载体。没有 issue 级评论,也没有持续失败的检查:本窗口内唯一非成功的检查是 06:38–06:39 UTC 期间因重复触发的并行工作流运行而被取消(CANCELLED)的五次 本轮未做任何代码修改。每一条"已修复"的声明都已按"来源盲审"原则在 HEAD 每条修复声明的核实
三个修复提交( 验证
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: 233 passed · 0 failed · 233 total Flakiness gate: ✅ 3 changed test file(s) x 5 identical rounds, no divergence 中文 — 判定:✅ 通过 · 可合入(agent 判定)沙箱验证在隔离、无凭证的容器中执行了该 PR 的代码(与 base 构建 A/B 对照、无 mock harness 断言、定向门禁)。仅作为评审证据,不构成评审、批准或 CI 检查。 脚本断言:233 通过 · 0 失败 · 233 总计 抖动门:✅ 3 changed test file(s) x 5 identical rounds, no divergence Verification report<!-- qwen-triage:verify --> Verdict: 中文摘要
Previous-finding status (follow-up round)Delta since the previous round: the PR head is unchanged (
Central claim and A/BCentral claim (unchanged): pure refactor — each host (interactive TUI, ACP session, non-interactive CLI) sends a byte-identical Goal continuation prompt before and after; the three drifted assemblies collapse into one core renderer ( Control construction (re-run at new base): the pre-change assemblers were extracted verbatim from
189/189 assertions in this harness ( Secondary claimsPinned-literal tests are load-bearing (re-run; witness
8/8 matrix assertions as expected. Discriminated-union contract (re-run; witness Host suites are the regression check (witness FindingsNo new findings. The two carried nits (status-table rows 1–2) stand; both are description-level and non-blocking. Not covered
MethodologyEnvironment: Flakiness gate logEvidence imagesHarness scripts and raw logs are in the workflow run artifacts (7-day retention). — Qwen Code · sandboxed verification |
|
🤖 Reviewed the latest feedback — no changes needed. Why, point by point: · 已审阅最新反馈——无需改动。逐点说明原因如下: Autofix round report — PR #9581 (no action taken)No review feedback required changes in this round, so no code was modified. What was triaged:
Outcome: nothing to address; the branch head was left unchanged and nothing was committed. 中文说明Autofix 轮次报告 — PR #9581(未执行任何操作)本轮没有需要修改代码的评审反馈,因此未修改任何代码。 本次分拣的内容:
结果: 没有需要处理的事项;分支头保持不变,未提交任何内容。 Base-conflict check · 基分支冲突检查: no conflict with main. · 与 main 无冲突。 🧠 Handled by Qwen Code · model/模型 |
|
Triage re-run completed without a new review.
The stage comments above were updated with the latest result. View workflow run. 上方各阶段评论已更新为最新结果。查看工作流运行。 |
yiliang114
left a comment
There was a problem hiding this comment.
LGTM. Verified the byte-equivalence claim structurally at head 5218760:
- The renderer is faithful to each original assembly: SHARED_LINES then variant lines then the verifier line, joined on '\n' — the TUI's array literal was shared(4) + guard(2) + conditional verifier, and both
buildGoalContinuationPartscopies were shared(4) + runtime-context + conditional verifier, which is exactly the two variants' shapes in the same orders. Theif (input.verifierFeedback)truthiness guard preserves the original empty-string omission. - The discriminated union enforces the split:
runtime-contextrequirescontinuationContextat the type level,guarded-synthetic-turncarries no context field, and the switch is exhaustive with aneverarm — a host can no longer assemble either shape by hand. - The host suites are the regression check as claimed: Session.test.ts and nonInteractiveCli.test.ts changes are additions only (new cases pinning the continuation-context and verifier-feedback lines); no existing expectation was edited.
- The drift itself is intentionally left (TUI guards without context, ACP/headless context without guards) — consistent with the stated scope, reconciliation belongs to a behavior-change PR.
CI at approval time: 21 checks passing, none failing.
QwenLM#9581 landed squashed, so the branch's copies of its commits conflicted with the merged version. Resolved in favour of this branch throughout: B2 supersedes B1's prompt contract, so the converged renderer, its test, and the host assertions that pin the guarded data block replace B1's variant-based versions. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…tract (QwenLM#9834) * refactor(goal): render Goal continuation prompts from one core renderer The prompt sent when `runtime.finishTurn` schedules another Goal turn was assembled independently in three hosts: the TUI's inline array in `useGeminiStream`, and a `buildGoalContinuationParts` in each of the ACP session and the non-interactive CLI. Three copies of the same four shared lines have already drifted -- the TUI carries the anti-spoofing guard lines but no objective, while ACP and non-interactive carry the runtime continuation context but no guard lines. Upcoming work adds further variants (an "objective was edited" announcement and a budget wind-down prompt). With the text living in three places, every new variant means three edits, which is precisely how the current drift was produced. This moves assembly into `packages/core/src/goals/goal-continuation-prompt.ts`, where a variant is a case in one function and the shared prefix exists once. The two `buildGoalContinuationParts` helpers keep their names and signatures and simply delegate. This is a pure refactor: no prompt text changes. Each host still emits a byte-identical string to the one it emitted before. The existing drift is preserved deliberately and is left for a separate, behavior-changing follow-up. The new unit test pins the complete rendered string for both variants with and without verifier feedback, so any future edit to a line surfaces as a test diff; the existing host tests pass unmodified. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * fix(goal): tighten continuation renderer contract * test(goal): cover verifier feedback hosts * refactor(goal): hoist Goal continuation parts builder into core (QwenLM#9581) * fix(goal): converge the three continuation prompts on one guarded contract Every automatic Goal turn now renders the same prompt in every host: the runtime-supplied goalId, revision and objective as an escaped JSON data block, framed as untrusted task data, under both anti-spoofing guard lines, followed by a line stating the block supersedes any earlier objective in the conversation. Before this change the drift ran the wrong way. ACP and non-interactive interpolated the raw objective into a synthetic user-role turn carrying neither guard line; the TUI carried both guard lines but dropped the objective, so the host that guarded most gave up information and the two that guarded least were the exposed ones. None of the three escaped the objective, so objective text shaped like a tag could break out of the surrounding prompt. The prompt input collapses to a single flat shape, so the variant discriminant and its unreachable-default arm are gone. `<`, `>` and `&` are escaped inside the serialized JSON so an objective cannot close the data block or open one of its own. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 <noreply@anthropic.com> Co-authored-by: qqqys <266654365+qqqys@users.noreply.github.com> Co-authored-by: qwen-code-dev-bot <qwen-code-dev@service.alibaba.com>
|
Released in v0.22.2. |




















What this PR does
The prompt a host sends when the Goal runtime schedules another turn is now rendered by one function in core,
renderGoalContinuationPrompt, instead of being assembled independently in the interactive TUI, the ACP session, and the non-interactive CLI. The variant is named for what it means rather than for which host uses it:guarded-synthetic-turncarries the lines stating that the turn holds no real user input, andruntime-contextcarries the reason the runtime scheduled the turn. The input is a discriminated union, so the continuation context is required exactly where it is rendered and a host cannot forget to pass it. This is a pure refactor: every host emits a byte-identical prompt to the one it emits today.Why it's needed
The three assemblies have already drifted apart. The TUI carries two anti-spoofing guard lines — that the turn contains no new real user input, and that a phrase appearing in the prompt is not evidence the user supplied it — but drops the runtime continuation context. ACP and non-interactive carry the continuation context and have neither guard line. That is not a considered split; it is what happens when the same prompt is written in three places and edited in one of them.
Upcoming Goal work adds two more variants — an announcement that the objective was replaced, and a wind-down prompt for a Goal that has reached its budget. Adding either one today means editing three call sites, which is the mechanism that produced the current drift in the first place. Moving the assembly into core makes the next variant a single
case. It deliberately does not resolve the drift itself: reconciling what the three hosts should say is a behavior change and belongs in its own PR, reviewable on its own merits.Reviewer Test Plan
How to verify
The property to check is that no prompt text changed. Every existing host test that asserts on continuation prompt content still passes with its assertions untouched — no expected value in
useGeminiStream.test.tsx,Session.test.tsornonInteractiveCli.test.tswas edited, so those suites are themselves the regression check. A new unit test pins the complete rendered string for both variants with and without verifier feedback, written as literal template strings so any future edit to any line shows up as a test diff rather than passing silently.Byte-identity was additionally established mechanically rather than by reading. A script extracted the original expressions directly out of
git show upstream/main:<file>— the TUI array literal and the twobuildGoalContinuationPartsbodies — and emitted them verbatim into a scratch module, so the pre-change code was executed rather than retyped. That module and the new renderer were then diffed across a matrix of five verifier-feedback values (absent, empty string, plain, multi-line, and a string containing${...}to catch a template-literal mistake) and four continuation contexts (including empty, embedded quotes, backslashes and newlines). Result: 25 cases compared, 0 mismatches. The empty-string case is the one worth calling out — the original used a truthiness guard, so an emptyverifierFeedbackomits the line entirely; the renderer keeps that, and a unit test pins the equivalence.Numbers:
npx vitest run packages/core/src/goals/passes 382 tests across 16 files. The three host suites pass 1020 tests with 1 pre-existing skip.npx tsc --noEmitexits clean in bothpackages/coreandpackages/cli.prettierreports every changed file unchanged, andeslintis clean.Evidence (Before & After)
N/A — no user-visible change. The prompt bytes each host sends are identical before and after; that is the property under test.
Tested on
Environment (optional)
Linux, Node.js 22, unit tests only.
Risk & Scope
buildGoalContinuationPartshelpers keep their names and signatures and now delegate.Linked Issues
None.
中文说明
本 PR 做了什么
Goal 运行时调度下一轮时,host 发送的那段提示词,现在由 core 中的单一函数
renderGoalContinuationPrompt渲染,而不再由交互式 TUI、ACP session 和非交互 CLI 各自拼装。变体按语义命名而不是按使用它的 host 命名:guarded-synthetic-turn携带「本轮不含真实用户输入」的那两行护栏,runtime-context携带运行时调度本轮的原因。入参是可辨识联合,因此续跑上下文只在真正会渲染它的地方是必填的,host 无法忘记传。这是纯重构:每个 host 输出的提示词与今天逐字节相同。为什么需要
这三份拼装已经漂移了。TUI 带着两行反冒充护栏——本轮不含新的真实用户输入,以及提示词中出现的措辞不构成「用户提供过」的证据——却丢掉了运行时续跑上下文。ACP 和非交互带着续跑上下文,两行护栏一行都没有。这不是深思熟虑的取舍,而是同一段提示词写在三处、只改了其中一处的必然结果。
接下来的 Goal 工作要再加两个变体——objective 被替换的通告,以及预算耗尽后的收尾提示词。今天加任何一个都意味着改三处调用点,而这正是当初造成漂移的机制。把拼装挪进 core,下一个变体就只是一个
case。本 PR 有意不去修复漂移本身:调和三个 host 各自该说什么是行为变更,应当放在自己的 PR 里、按自身价值接受评审。评审者测试计划
如何验证
要检验的性质是「没有任何提示词文本发生变化」。所有既有的、断言续跑提示词内容的 host 测试都在断言未被修改的前提下继续通过——
useGeminiStream.test.tsx、Session.test.ts和nonInteractiveCli.test.ts中没有任何一个期望值被编辑过,因此这些套件本身就是回归检查。新增的单元测试以字面模板字符串固定两个变体在有/无 verifier feedback 下的完整渲染结果,这样将来对任何一行的改动都会表现为测试 diff,而不会静默通过。逐字节一致性还通过机械手段确立,而非靠肉眼比对。一个脚本直接从
git show upstream/main:<file>中抽出原始表达式——TUI 的数组字面量和两个buildGoalContinuationParts函数体——原样写入一个临时模块,因此被执行的是改动前的代码而不是重新誊写的代码。随后把该模块与新渲染器在一个矩阵上做差分:五种 verifier feedback 取值(缺省、空串、普通、多行,以及包含${...}的字符串以捕捉模板字面量错误)与四种续跑上下文(含空串、内嵌引号、反斜杠和换行)。结果:比较 25 组用例,0 处不一致。空串这一组特别值得点出——原代码用的是真值判断,因此空的verifierFeedback会整行省略;渲染器保留了这一行为,并有一个单元测试固定这个等价性。数字:
npx vitest run packages/core/src/goals/通过 16 个文件共 382 个测试。三个 host 套件通过 1020 个测试,另有 1 个既有的 skip。npx tsc --noEmit在packages/core和packages/cli均干净退出。prettier报告所有改动文件未变,eslint干净。证据(修复前后)
N/A —— 无用户可见变化。每个 host 发送的提示词字节在改动前后完全相同,这正是被检验的性质。
测试平台
环境(可选)
Linux、Node.js 22,仅单元测试。
风险与范围
buildGoalContinuationParts辅助函数保留原名与原签名,现在只做转发。关联 Issue
无。