fix(cli): fail non-interactive runs on loop detection - #5564
Conversation
|
@qwen-code /triage |
wenshao
left a comment
There was a problem hiding this comment.
No issues found. LGTM! ✅
— qwen3.7-max via Qwen Code /review
|
Thanks for the PR, @cyphercodes! Template looks good ✓ — all required sections present, bilingual body, linked issue #5554. On direction: This is a clear-cut fix for a real automation bug. Issue #5554 provides excellent evidence — a CI triage run hit loop detection, printed the warning, then exited 0 and reported success. GitHub Actions showed green while the task silently failed. This is exactly the kind of silent failure that erodes trust in CI pipelines. Solidly within scope. Claude Code CHANGELOG has no direct precedent for loop-detection exit semantics, but the area is clearly relevant — they've shipped multiple fixes around loop detection, stop hooks, and On approach: The scope is tight — two files, one concern. The strategy is sound: extract message formatting into The one thing worth noting: Moving on to code review. 🔍 中文说明感谢 PR,@cyphercodes! 模板完整 ✓ — 所有必填部分齐全,双语正文,关联 issue #5554。 方向: 这是一个明确的自动化 bug 修复。Issue #5554 提供了充分的证据 — CI triage 运行触发了循环检测,打印了警告,但以 0 退出并报告成功。GitHub Actions 显示绿色,而任务实际失败了。这正是侵蚀 CI 管线信任的那种静默失败。完全在范围内。 Claude Code CHANGELOG 没有循环检测退出语义的直接先例,但该领域明显相关 — 他们在循环检测、停止钩子和 方案: 范围紧凑 — 两个文件,一个关注点。策略合理:将消息格式化提取到 值得注意的一点: 进入代码审查 🔍 — Qwen Code · qwen3.7-max |
Code ReviewIndependent proposal (before reading the diff): Given the bug — loop detection exits 0 in non-interactive mode — I would: (1) add a Comparison with the diff: The PR's approach matches my proposal and is well-executed. A few specifics:
No critical blockers found. No security holes, no regressions, no AGENTS.md violations. Reuse check: The new logic doesn't duplicate anything already available elsewhere in the codebase. The Lint & formatting: ESLint and Prettier both pass on the changed files. ✓ Test ResultsUnit Tests (tmux capture)Before (main branch — no loop detection tests)Note: no loop detection tests exist on main. The two tests added by this PR are absent. After (this PR — 2 new loop detection tests added, both pass)Both new tests pass:
All 51 pre-existing tests continue to pass — no regressions. 中文说明代码审查独立方案(阅读 diff 前):鉴于这个 bug — 循环检测在非交互模式下以 0 退出 — 我会:(1) 在事件处理作用域添加 与 diff 的比较: PR 的方案与我的独立方案一致,执行良好。具体细节:
未发现关键阻塞问题。 无安全漏洞、无回归、无 AGENTS.md 违规。 测试结果单元测试修改前(main 分支): 52 个测试,51 通过,1 跳过。无循环检测测试。 修改后(本 PR): 54 个测试,53 通过,1 跳过。两个新测试均通过:
所有 51 个既有测试继续通过 — 无回归。 — Qwen Code · qwen3.7-max |
ReflectionStepping back: this PR fixes exactly what issue #5554 describes — a silent CI failure mode where loop detection prints a warning but the process exits successfully. The kind of bug that nobody notices until they're debugging why a workflow "passed" but produced no output. The implementation is straightforward and correct. My independent proposal matched the PR's approach, and after reading the code in detail, I don't see a materially simpler path. The The code is clean, well-tested, and does one thing. The two regression tests directly validate the fix: exit code 1 on loop detection, JSON The minor duplication between Verdict: Ships the fix cleanly, tests confirm it works, no regressions. Approving. ✅ 中文说明反思退一步看:这个 PR 修复的正是 issue #5554 描述的问题 — 一种静默的 CI 失败模式,循环检测打印了警告但进程以成功退出。这种 bug 在有人调试为什么 workflow "通过" 了却没有产出之前,没人会注意到。 实现直接且正确。我的独立方案与 PR 的方案一致,仔细阅读代码后,我没有看到更简单的路径。 代码干净、测试充分、只做一件事。两个回归测试直接验证了修复:循环检测时退出码 1,JSON
结论: 干净地修复了问题,测试确认有效,无回归。批准。 ✅ — Qwen Code · qwen3.7-max |
qwen-code-ci-bot
left a comment
There was a problem hiding this comment.
LGTM, looks ready to ship. ✅
✅ Local verification — real CLI E2E (tmux), LGTMI verified this PR locally by building the real CLI bundle and driving it end-to-end against a mock OpenAI server that trips the Environment
1) Unit testsBoth new tests pass by name:
Non-vacuous check: reverting only 2) End-to-end before/after (real CLI, same loop scenario)
PR The BASE column is the bug exactly as described in #5554: a loop-halted run reports 3) Happy-path control (no regression)Same PR build against a normal completion (no loop): The new failure path is scoped strictly to loop detection; successful runs still exit 0. 4) Static checks
Note on the PR description's typecheck/build caveatThe description says VerdictLGTM — fixes #5554 correctly and minimally, regression tests are real, no happy-path regression, static checks green. 👍 中文版本(点击展开)✅ 本地真实验证 —— 真实 CLI 端到端(tmux),建议合并我在本地构建了真实的 CLI bundle,并用一个 mock OpenAI server 驱动它端到端运行,触发 环境
1)单元测试两个新增测试按名称通过:
非空验证: 仅把 2)端到端修改前后对比(真实 CLI,相同循环场景)
PR 在 BASE 那一列正是 #5554 描述的 bug:被循环中止的运行却报告 3)正常路径对照(无回归)同一个 PR build,针对正常完成(无循环): 新增的失败路径严格限定在循环检测;成功运行仍然以 0 退出。 4)静态检查
关于 PR 描述里 typecheck/build 失败的说明描述提到 结论LGTM —— 正确且最小化地修复了 #5554,回归测试真实有效,无正常路径回归,静态检查全绿。👍 |
What this PR does
This makes non-interactive CLI runs treat loop detection as a failure instead of a successful completion. When the model emits a loop-detected event, pending tool calls are skipped, text output still shows the loop message, and JSON output is marked as an error.
Why it's needed
In CI/non-interactive mode, loop detection means the run could not complete the requested task. Exiting with status 0 and publishing a successful JSON result can make automation report false success.
Reviewer Test Plan
How to verify
Run the focused CLI regression test and confirm loop detection exits with code 1 and does not execute queued tool calls.
Evidence (Before & After)
Before: a loop-detected non-interactive run could exit 0 and JSON output could report
isError: false.After: the new regression covers loop detection returning exit code 1, skipping pending tool calls, and setting
isError: true/is_error: truein JSON output.Commands run locally:
npm run typecheck --workspace=packages/cliandnpm run buildcurrently fail in this checkout on existing Ink import/type errors inpackages/cli/src/ui/components/shared/BaseTextInput.tsx(ink/dom,ink/components/CursorContext, andcursorCtxunknown); this PR does not touch that surface.Tested on
Environment (optional)
Linux cron container, Node/npm from the repository environment.
Risk & Scope
BaseTextInput.tsxwere not changed here.Linked Issues
Fixes #5554
中文说明
此 PR 做了什么
此 PR 让非交互式 CLI 在检测到循环时按失败处理,而不是成功完成。模型发出循环检测事件后,会跳过待执行的工具调用,文本输出仍显示循环提示,并且 JSON 输出会标记为错误。
为什么需要
在 CI/非交互模式下,循环检测表示本次任务没有完成。如果仍以状态码 0 退出并发布成功的 JSON 结果,自动化流程会误报成功。
Reviewer Test Plan
如何验证
运行聚焦的 CLI 回归测试,确认循环检测会返回退出码 1,并且不会执行排队中的工具调用。
证据(修改前后)
修改前:检测到循环的非交互式运行可能以 0 退出,并且 JSON 输出可能报告
isError: false。修改后:新增回归测试覆盖循环检测返回退出码 1、跳过待执行工具调用,并在 JSON 输出中设置
isError: true/is_error: true。本地运行命令:见英文部分命令列表。
npm run typecheck --workspace=packages/cli和npm run build当前在此检出中因为packages/cli/src/ui/components/shared/BaseTextInput.tsx里既有的 Ink 导入/类型错误失败(ink/dom、ink/components/CursorContext、以及cursorCtx为 unknown);此 PR 不修改该范围。测试平台
Linux 已测试;macOS 和 Windows 未本地测试。
环境(可选)
Linux cron 容器,使用仓库环境中的 Node/npm。
风险与范围
BaseTextInput.tsx类型检查/构建失败。关联 Issue
Fixes #5554