fix(chat): plan mode 改为有界升级,修复无限读文件循环 - #589
Merged
Merged
Conversation
移除对 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
marked this pull request as draft
August 21, 2026 19:01
Contributor
|
PR governance checks failed — this PR has been converted to draft.
Fix the items above, then click Ready for review to re-run the checks. |
属于用户的决定(范围边界、互斥方案、取舍、目标行为)在调研阶段就应 问清,而非猜测或把开放问题遗留在计划文本里。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>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #588
Summary
根因修复:移除 plan mode 下每轮强制
toolChoice: "any"的无界机制(planModeForcesToolUse)。它剥夺了模型的文本收尾能力——不提交计划时每轮必须调工具,导致无限 Read/Grep 循环。有界升级架构:新增
createPlanModeRunPolicy状态机(planModeTools.ts),终止性由四道有界防线保证,任何模型行为都在有限步内收敛到计划卡:ExitPlanMode提交即结束本轮 run(原有);{type:"tool", name:"ExitPlanMode"},仅升级一次(上限 4 轮);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
resolveToolChoice逐轮生效、maxRounds优雅终止、ExitPlanMode 存在时 toolChoice 保持 autotsc --noEmit与biome check通过Made with Cursor