Skip to content

fix(chat): plan mode 改为有界升级,修复无限读文件循环 - #589

Merged
su-fen merged 3 commits into
mainfrom
fix/plan-mode-bounded-escalation
Aug 21, 2026
Merged

fix(chat): plan mode 改为有界升级,修复无限读文件循环#589
su-fen merged 3 commits into
mainfrom
fix/plan-mode-bounded-escalation

Conversation

@su-fen

@su-fen su-fen commented Aug 21, 2026

Copy link
Copy Markdown
Member

Fixes #588

Summary

  • 根因修复:移除 plan mode 下每轮强制 toolChoice: "any" 的无界机制(planModeForcesToolUse)。它剥夺了模型的文本收尾能力——不提交计划时每轮必须调工具,导致无限 Read/Grep 循环。

  • 有界升级架构:新增 createPlanModeRunPolicy 状态机(planModeTools.ts),终止性由四道有界防线保证,任何模型行为都在有限步内收敛到计划卡:

    1. 终止谓词——ExitPlanMode 提交即结束本轮 run(原有);
    2. 轮数熔断——研究阶段上限 32 轮,达到后当前工具批执行完优雅终止,不抛错;
    3. 补提交轮——run 以文本收尾未提交时,注入一次 wire-only 提醒(不持久化、不进 UI)并定向强制 {type:"tool", name:"ExitPlanMode"},仅升级一次(上限 4 轮);
    4. 文本兜底——仍未提交则把最后的助手文本注册为待决计划,合成 ExitPlanMode 调用对进历史,计划卡/审批短语/WebUI 链路零改动复用。
  • runner 恢复模式无关:agentRunner.ts 删除 ExitPlanMode 硬编码,新增通用参数 resolveToolChoice(round)maxRounds,plan 语义全部收敛到编排层策略。

  • 协议守卫:Anthropic extended thinking 与强制 tool_choice 互斥(400),streamByApi.ts 在该组合下自动降级为 auto,避免重试/failover 循环。

  • 防空转守卫:plan mode 下同参重复的研究调用(稳定序列化,键序无关)第 3 次起被拦截,拦截理由引导模型提交计划。

  • Prompt 收敛:<plan-mode> system 段成为规则唯一权威,toolsSuffix 压缩为一行指引并删除重复的 "## Plan Mode" 段;移除 "You MUST call … before this turn ends" 高压措辞(抬高提交门槛、诱导无限调研),改为"够用即提交、勿重读已返回 unchanged 的文件"。

  • 细节决策积极提问:<plan-mode> 权威段新增准则——属于用户的决定(范围边界、互斥方案、取舍、目标行为)在调研阶段用 AskUserQuestion 主动问清,而非猜测或把开放问题遗留在计划里(代码能回答的自己查,剩余决策合并为一次聚焦提问);toolsSuffix plan 段按工具可用性追加一行指引。AskUserQuestion 本就在 plan mode 白名单内且为 run 内挂起语义,与提交终止/有界升级无冲突。

  • 计划模式菜单项 UI 升级(GUI 与 WebUI 共享的 ChatComposerBar):去掉"开启计划模式/关闭计划模式"行内小字,改为整行可点的开关行——右侧迷你 switch 呈现状态(与计划 pill 同用 sky 色系,开启时图标同步着色),closeOnClick=false 使切换就地生效、开关动画可见,行为说明降为 hover 提示,并补齐 menuitemcheckbox + aria-checked 语义。

Test plan

  • 新增 9 个用例:策略状态机三态流转(auto → nudge → fallback)、提交成功即落定、错误结果不算提交、空文本兜底不注册、重复调用守卫(含键序无关与 ExitPlanMode 豁免)、resolveToolChoice 逐轮生效、maxRounds 优雅终止、ExitPlanMode 存在时 toolChoice 保持 auto
  • 同步三个既有测试文件的 prompt 文案断言
  • tsc --noEmitbiome check 通过
  • agent-gui 全量测试 2491 pass / 0 fail

Made with Cursor

移除对 plan mode 每轮强制 toolChoice:any 的无界机制——它剥夺了模型的
文本收尾能力,不提交计划时每轮必须调工具,导致无限 Read/Grep 循环。

改为"auto + 有界升级"四道防线,任何模型行为都在有限步内收敛到计划卡:
- 终止谓词:ExitPlanMode 提交即结束本轮 run(原有);
- 轮数熔断:runner 新增通用 maxRounds,达到上限后当前批执行完优雅终止;
- 补提交轮:run 以文本收尾未提交时,注入一次 wire-only 提醒并定向强制
  ExitPlanMode(仅一次,Anthropic thinking 下由 provider 层降级为 auto,
  避免 400 重试循环);
- 文本兜底:仍未提交则把助手文本注册为待决计划,合成 ExitPlanMode 调用
  对进历史,计划卡/审批/持久化零改动复用。

配套:runner 恢复模式无关(新增 resolveToolChoice/maxRounds 通用参数,
plan 策略收敛到 createPlanModeRunPolicy);同参重复研究调用超限即拦截;
plan mode prompt 收敛为 <plan-mode> 单一权威段并移除高压措辞。

Fixes #588

Co-authored-by: Cursor <cursoragent@cursor.com>
@StackCairn
StackCairn marked this pull request as draft August 21, 2026 19:01
@github-actions

Copy link
Copy Markdown
Contributor

PR governance checks failed — this PR has been converted to draft.

  • UI change without screenshots: this PR modifies frontend code. Please add before/after screenshots or a recording under "Screenshots / preview" in the PR body.

Fix the items above, then click Ready for review to re-run the checks.

su-fen and others added 2 commits August 22, 2026 03:05
属于用户的决定(范围边界、互斥方案、取舍、目标行为)在调研阶段就应
问清,而非猜测或把开放问题遗留在计划文本里。AskUserQuestion 本就在
plan mode 白名单内(isReadOnly)且为 run 内挂起语义——作答后本轮继
续,与提交终止、有界升级无冲突,故仅需提示词引导:

- <plan-mode> 权威段新增提问准则:代码能回答的自己查,剩余决策合并
  为一次聚焦提问;
- toolsSuffix plan 段按工具可用性追加一行指引,不可用时不产生文案。

Co-authored-by: Cursor <cursoragent@cursor.com>
"+"菜单里的计划模式项原以"计划模式 开启计划模式/关闭计划模式"的行内
小字表达状态与动作,信息重复且拥挤。改为整行可点的开关行:

- 右侧迷你 switch 呈现开/关,与计划 pill 同用 sky 色系,开启时图标同步
  着色,状态一眼可辨;
- closeOnClick=false:切换就地生效,开关动画可见,菜单不弹跳收起;
- 行为说明降为 hover 提示(新增 planModeHint 文案),行内不再挤小字;
- 语义补齐 role=menuitemcheckbox + aria-checked;
- 移除不再使用的 planModeSlashOn 文案键(planModeSlashOff 仍供 pill 用)。

ChatComposerBar 为 GUI 与 WebUI 共享组件,一处改动覆盖双端。

Co-authored-by: Cursor <cursoragent@cursor.com>
@su-fen su-fen added the governance-exempt Skip PR governance checks label Aug 21, 2026
@su-fen
su-fen marked this pull request as ready for review August 21, 2026 19:52
@su-fen
su-fen merged commit 359d36e into main Aug 21, 2026
10 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

governance-exempt Skip PR governance checks

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Plan mode 开启后模型无限读文件,turn 无法收敛

1 participant