fix(plan): exclude EnterPlanMode tool from YOLO mode (#19570)

This commit is contained in:
Adib234
2026-02-19 20:53:12 -05:00
committed by GitHub
parent cbfb2a4e26
commit 5fd557347e
4 changed files with 52 additions and 4 deletions

View File

@@ -69,6 +69,7 @@ You can enter Plan Mode in three ways:
2. **Command:** Type `/plan` in the input box.
3. **Natural Language:** Ask the agent to "start a plan for...". The agent will
then call the [`enter_plan_mode`] tool to switch modes.
- **Note:** This tool is not available when the CLI is in YOLO mode.
### The Planning Workflow

View File

@@ -11,6 +11,8 @@ by the agent when you ask it to "start a plan" using natural language. In this
mode, the agent is restricted to read-only tools to allow for safe exploration
and planning.
> **Note:** This tool is not available when the CLI is in YOLO mode.
- **Tool name:** `enter_plan_mode`
- **Display name:** Enter Plan Mode
- **File:** `enter-plan-mode.ts`

View File

@@ -1392,7 +1392,22 @@ describe('setApprovalMode with folder trust', () => {
expect(updateSpy).toHaveBeenCalled();
});
it('should not update system instruction when switching between non-Plan modes', () => {
it('should update system instruction when entering YOLO mode', () => {
const config = new Config(baseParams);
vi.spyOn(config, 'isTrustedFolder').mockReturnValue(true);
vi.spyOn(config, 'getToolRegistry').mockReturnValue({
getTool: vi.fn().mockReturnValue(undefined),
unregisterTool: vi.fn(),
registerTool: vi.fn(),
} as Partial<ToolRegistry> as ToolRegistry);
const updateSpy = vi.spyOn(config, 'updateSystemInstructionIfInitialized');
config.setApprovalMode(ApprovalMode.YOLO);
expect(updateSpy).toHaveBeenCalled();
});
it('should not update system instruction when switching between non-Plan/non-YOLO modes', () => {
const config = new Config(baseParams);
vi.spyOn(config, 'isTrustedFolder').mockReturnValue(true);
const updateSpy = vi.spyOn(config, 'updateSystemInstructionIfInitialized');
@@ -2649,6 +2664,27 @@ describe('syncPlanModeTools', () => {
expect(registeredTool).toBeUndefined();
});
it('should NOT register EnterPlanModeTool when in YOLO mode, even if plan is enabled', async () => {
const config = new Config({
...baseParams,
approvalMode: ApprovalMode.YOLO,
plan: true,
});
const registry = new ToolRegistry(config, config.getMessageBus());
vi.spyOn(config, 'getToolRegistry').mockReturnValue(registry);
const registerSpy = vi.spyOn(registry, 'registerTool');
vi.spyOn(registry, 'getTool').mockReturnValue(undefined);
config.syncPlanModeTools();
const { EnterPlanModeTool } = await import('../tools/enter-plan-mode.js');
const registeredTool = registerSpy.mock.calls.find(
(call) => call[0] instanceof EnterPlanModeTool,
);
expect(registeredTool).toBeUndefined();
});
it('should call geminiClient.setTools if initialized', async () => {
const config = new Config(baseParams);
const registry = new ToolRegistry(config, config.getMessageBus());

View File

@@ -1793,7 +1793,11 @@ export class Config {
const isPlanModeTransition =
currentMode !== mode &&
(currentMode === ApprovalMode.PLAN || mode === ApprovalMode.PLAN);
if (isPlanModeTransition) {
const isYoloModeTransition =
currentMode !== mode &&
(currentMode === ApprovalMode.YOLO || mode === ApprovalMode.YOLO);
if (isPlanModeTransition || isYoloModeTransition) {
this.syncPlanModeTools();
this.updateSystemInstructionIfInitialized();
}
@@ -1803,8 +1807,13 @@ export class Config {
* Synchronizes enter/exit plan mode tools based on current mode.
*/
syncPlanModeTools(): void {
const isPlanMode = this.getApprovalMode() === ApprovalMode.PLAN;
const registry = this.getToolRegistry();
if (!registry) {
return;
}
const approvalMode = this.getApprovalMode();
const isPlanMode = approvalMode === ApprovalMode.PLAN;
const isYoloMode = approvalMode === ApprovalMode.YOLO;
if (isPlanMode) {
if (registry.getTool(ENTER_PLAN_MODE_TOOL_NAME)) {
@@ -1817,7 +1826,7 @@ export class Config {
if (registry.getTool(EXIT_PLAN_MODE_TOOL_NAME)) {
registry.unregisterTool(EXIT_PLAN_MODE_TOOL_NAME);
}
if (this.planEnabled) {
if (this.planEnabled && !isYoloMode) {
if (!registry.getTool(ENTER_PLAN_MODE_TOOL_NAME)) {
registry.registerTool(new EnterPlanModeTool(this, this.messageBus));
}