-
Notifications
You must be signed in to change notification settings - Fork 2.7k
fix(core): tell the model when the user manually exits plan mode #7682
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -1098,6 +1098,22 @@ Your plan is ready when you have addressed all ambiguities and it covers: what t | |
| </system-reminder>`; | ||
| } | ||
|
|
||
| /** | ||
| * One-shot reminder injected on the first model-bound turn after the user | ||
| * manually exits plan mode (Shift+Tab, `/approval-mode`, `/plan`, ACP mode | ||
| * switch). While plan mode is active {@link getPlanModeSystemReminder} is | ||
| * re-injected every turn, so on a manual exit the model's most recent | ||
| * context still says "plan mode is active" — the reminder silently | ||
| * disappearing is not a signal models reliably notice (#7671). | ||
| * | ||
| * @param currentMode - The approval mode the user switched to | ||
| */ | ||
| export function getManualPlanExitSystemReminder(currentMode: string): string { | ||
| return `<system-reminder> | ||
| The user has manually switched out of plan mode (current approval mode: ${currentMode}). You are no longer in plan mode. Do NOT call ${ToolNames.EXIT_PLAN_MODE} — there is no plan approval pending. Continue working in the current mode; previous plan-mode restrictions on edits and state-modifying tools no longer apply. | ||
| </system-reminder>`; | ||
|
Comment on lines
+1111
to
+1114
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [Suggestion] No unit test in Add a — qwen3.7-max via Qwen Code /review
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Added in 18bb51b — a |
||
| } | ||
|
|
||
| /** | ||
| * Generates a system reminder about an active Arena session. | ||
| * | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -234,7 +234,9 @@ class ExitPlanModeToolInvocation extends BaseToolInvocation< | |
|
|
||
| this.savePlanBestEffort(snapshot.plan); | ||
| try { | ||
| this.config.setApprovalMode(targetMode); | ||
| this.config.setApprovalMode(targetMode, { | ||
| fromApprovedPlanExit: true, | ||
| }); | ||
| } catch (error) { | ||
| const message = error instanceof Error ? error.message : String(error); | ||
| debugLogger.error( | ||
|
|
@@ -331,7 +333,9 @@ class ExitPlanModeToolInvocation extends BaseToolInvocation< | |
|
|
||
| this.savePlanBestEffort(plan); | ||
| try { | ||
| this.config.setApprovalMode(decision.targetMode); | ||
| this.config.setApprovalMode(decision.targetMode, { | ||
| fromApprovedPlanExit: true, | ||
| }); | ||
|
Comment on lines
+336
to
+338
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [Suggestion] The leader-approval Add a happy-path test for leader approval that asserts — qwen3.7-max via Qwen Code /review
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Added in 18bb51b — new test |
||
| } catch (error) { | ||
| const message = error instanceof Error ? error.message : String(error); | ||
| return this.errorResult( | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[Suggestion] The exit notice is only consumed on
UserQuery/Cronturns (line 2425 gates the whole system-reminder block). If the user Shift+Tabs out of plan mode mid-tool-loop, the next model-bound turn is aToolResult— the flag stays pending and no exit reminder is injected. — Concrete cost: the model's most recent system reminder still says "plan mode is active"; it may callexit_plan_modeand burn a round-trip before the next user message delivers the reminder. The staleness guard inexitPlanMode.tsprevents harm, but the one wasted turn is the exact scenario this feature targets.中文说明
退出通知仅在
UserQuery/Cron轮次消费(第 2425 行的门控覆盖了整个 system-reminder 块)。如果用户在工具循环中途按 Shift+Tab 退出 plan mode,下一个发给模型的轮次是ToolResult——标志保持 pending 状态,不会注入退出提醒。具体代价: 模型最近的 system reminder 仍显示"plan mode 激活中";它可能调用
exit_plan_mode,浪费一轮交互后才能在下一条用户消息中获得提醒。exitPlanMode.ts中的过期检查防止了实际损害,但这一轮浪费正是此功能要解决的问题。— qwen3.7-max via Qwen Code /review
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Real bound, deliberately kept: the notice rides the same
UserQuery/Croncadence as the plan-mode reminder it replaces — no reminder in this assembly is injected onToolResultturns today, and giving this one reminder its own injection point outside that gate would be a new pattern for the block (with its own questions about interleaving system reminders into an active tool loop). The mid-loop window is bounded: the flag stays pending (it is only cleared by consumption or plan re-entry, never dropped), so the reminder lands on the very next user/cron turn, and a prematureexit_plan_modecall in that window is caught by the staleness/permission guard — with #7673 it additionally returns explicit guidance instead of a generic deny. If maintainers want reminders onToolResultturns, happy to do that as a follow-up gate change rather than special-casing this one reminder.中文
真实边界,且是有意保留的:通知与它所替代的 plan-mode reminder 走同一个
UserQuery/Cron注入节奏——该装配块今天没有任何 reminder 在ToolResult轮注入,为这一个 reminder 单开注入点会给这个块引入新模式(还牵出「向进行中的工具循环插入 system reminder」的问题)。循环中途的窗口是有界的:标志保持 pending(只被消费或重进 plan mode 清除,绝不丢弃),下一个 user/cron 轮必然送达;窗口内过早的exit_plan_mode调用被过期/权限守卫拦住——配合 #7673 还会返回明确指引而非泛化拒绝。如果维护者希望ToolResult轮也注入 reminder,可以作为 follow-up 改门控整体处理,而不是给单个 reminder 开特例。