Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/cli/plan-mode.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
2 changes: 2 additions & 0 deletions docs/tools/planning.md
Original file line number Diff line number Diff line change
Expand Up @@ -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`
Expand Down
38 changes: 37 additions & 1 deletion packages/core/src/config/config.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1356,7 +1356,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');
Expand Down Expand Up @@ -2613,6 +2628,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());
Expand Down
15 changes: 12 additions & 3 deletions packages/core/src/config/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1737,7 +1737,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();
}
Expand All @@ -1747,8 +1751,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)) {
Expand All @@ -1761,7 +1770,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));
}
Expand Down
Loading