mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-05-13 05:12:55 -07:00
feat(plan): conditionally add enter/exit plan mode tools based on current mode (#24378)
This commit is contained in:
@@ -26,6 +26,7 @@ import {
|
|||||||
ToolRegistry,
|
ToolRegistry,
|
||||||
COMMON_IGNORE_PATTERNS,
|
COMMON_IGNORE_PATTERNS,
|
||||||
GEMINI_IGNORE_FILE_NAME,
|
GEMINI_IGNORE_FILE_NAME,
|
||||||
|
ApprovalMode,
|
||||||
// DEFAULT_FILE_EXCLUDES,
|
// DEFAULT_FILE_EXCLUDES,
|
||||||
CoreToolCallStatus,
|
CoreToolCallStatus,
|
||||||
type Config,
|
type Config,
|
||||||
@@ -146,6 +147,7 @@ describe('handleAtCommand', () => {
|
|||||||
getClient: () => undefined,
|
getClient: () => undefined,
|
||||||
}),
|
}),
|
||||||
getMessageBus: () => mockMessageBus,
|
getMessageBus: () => mockMessageBus,
|
||||||
|
getApprovalMode: () => ApprovalMode.DEFAULT,
|
||||||
} as unknown as Config;
|
} as unknown as Config;
|
||||||
|
|
||||||
const registry = new ToolRegistry(mockConfig, mockMessageBus);
|
const registry = new ToolRegistry(mockConfig, mockMessageBus);
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ import {
|
|||||||
StandardFileSystemService,
|
StandardFileSystemService,
|
||||||
ToolRegistry,
|
ToolRegistry,
|
||||||
COMMON_IGNORE_PATTERNS,
|
COMMON_IGNORE_PATTERNS,
|
||||||
|
ApprovalMode,
|
||||||
} from '@google/gemini-cli-core';
|
} from '@google/gemini-cli-core';
|
||||||
import * as os from 'node:os';
|
import * as os from 'node:os';
|
||||||
import type { UseHistoryManagerReturn } from './useHistoryManager.js';
|
import type { UseHistoryManagerReturn } from './useHistoryManager.js';
|
||||||
@@ -136,6 +137,7 @@ describe('handleAtCommand with Agents', () => {
|
|||||||
getMessageBus: () => mockMessageBus,
|
getMessageBus: () => mockMessageBus,
|
||||||
interactive: true,
|
interactive: true,
|
||||||
getAgentRegistry: () => mockAgentRegistry,
|
getAgentRegistry: () => mockAgentRegistry,
|
||||||
|
getApprovalMode: () => ApprovalMode.DEFAULT,
|
||||||
} as unknown as Config;
|
} as unknown as Config;
|
||||||
|
|
||||||
const registry = new ToolRegistry(mockConfig, mockMessageBus);
|
const registry = new ToolRegistry(mockConfig, mockMessageBus);
|
||||||
|
|||||||
@@ -22,6 +22,8 @@ import { ToolRegistry, DiscoveredTool } from './tool-registry.js';
|
|||||||
import {
|
import {
|
||||||
DISCOVERED_TOOL_PREFIX,
|
DISCOVERED_TOOL_PREFIX,
|
||||||
UPDATE_TOPIC_TOOL_NAME,
|
UPDATE_TOPIC_TOOL_NAME,
|
||||||
|
ENTER_PLAN_MODE_TOOL_NAME,
|
||||||
|
EXIT_PLAN_MODE_TOOL_NAME,
|
||||||
} from './tool-names.js';
|
} from './tool-names.js';
|
||||||
import { DiscoveredMCPTool } from './mcp-tool.js';
|
import { DiscoveredMCPTool } from './mcp-tool.js';
|
||||||
import {
|
import {
|
||||||
@@ -833,6 +835,40 @@ describe('ToolRegistry', () => {
|
|||||||
expect(toolRegistry.getAllToolNames()).toContain(UPDATE_TOPIC_TOOL_NAME);
|
expect(toolRegistry.getAllToolNames()).toContain(UPDATE_TOPIC_TOOL_NAME);
|
||||||
expect(toolRegistry.getTool(UPDATE_TOPIC_TOOL_NAME)).toBe(topicTool);
|
expect(toolRegistry.getTool(UPDATE_TOPIC_TOOL_NAME)).toBe(topicTool);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should show enter_plan_mode only when NOT in plan mode', () => {
|
||||||
|
const enterTool = new MockTool({ name: ENTER_PLAN_MODE_TOOL_NAME });
|
||||||
|
toolRegistry.registerTool(enterTool);
|
||||||
|
|
||||||
|
// Not in plan mode
|
||||||
|
vi.spyOn(config, 'getApprovalMode').mockReturnValue(ApprovalMode.DEFAULT);
|
||||||
|
expect(toolRegistry.getAllToolNames()).toContain(
|
||||||
|
ENTER_PLAN_MODE_TOOL_NAME,
|
||||||
|
);
|
||||||
|
|
||||||
|
// In plan mode
|
||||||
|
vi.spyOn(config, 'getApprovalMode').mockReturnValue(ApprovalMode.PLAN);
|
||||||
|
expect(toolRegistry.getAllToolNames()).not.toContain(
|
||||||
|
ENTER_PLAN_MODE_TOOL_NAME,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should show exit_plan_mode only when in plan mode', () => {
|
||||||
|
const exitTool = new MockTool({ name: EXIT_PLAN_MODE_TOOL_NAME });
|
||||||
|
toolRegistry.registerTool(exitTool);
|
||||||
|
|
||||||
|
// Not in plan mode
|
||||||
|
vi.spyOn(config, 'getApprovalMode').mockReturnValue(ApprovalMode.DEFAULT);
|
||||||
|
expect(toolRegistry.getAllToolNames()).not.toContain(
|
||||||
|
EXIT_PLAN_MODE_TOOL_NAME,
|
||||||
|
);
|
||||||
|
|
||||||
|
// In plan mode
|
||||||
|
vi.spyOn(config, 'getApprovalMode').mockReturnValue(ApprovalMode.PLAN);
|
||||||
|
expect(toolRegistry.getAllToolNames()).toContain(
|
||||||
|
EXIT_PLAN_MODE_TOOL_NAME,
|
||||||
|
);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('DiscoveredToolInvocation', () => {
|
describe('DiscoveredToolInvocation', () => {
|
||||||
|
|||||||
@@ -31,6 +31,8 @@ import {
|
|||||||
WRITE_FILE_TOOL_NAME,
|
WRITE_FILE_TOOL_NAME,
|
||||||
EDIT_TOOL_NAME,
|
EDIT_TOOL_NAME,
|
||||||
UPDATE_TOPIC_TOOL_NAME,
|
UPDATE_TOPIC_TOOL_NAME,
|
||||||
|
ENTER_PLAN_MODE_TOOL_NAME,
|
||||||
|
EXIT_PLAN_MODE_TOOL_NAME,
|
||||||
} from './tool-names.js';
|
} from './tool-names.js';
|
||||||
|
|
||||||
type ToolParams = Record<string, unknown>;
|
type ToolParams = Record<string, unknown>;
|
||||||
@@ -583,6 +585,14 @@ export class ToolRegistry {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const isPlanMode = this.config.getApprovalMode() === ApprovalMode.PLAN;
|
||||||
|
if (
|
||||||
|
(tool.name === ENTER_PLAN_MODE_TOOL_NAME && isPlanMode) ||
|
||||||
|
(tool.name === EXIT_PLAN_MODE_TOOL_NAME && !isPlanMode)
|
||||||
|
) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
const normalizedClassName = tool.constructor.name.replace(/^_+/, '');
|
const normalizedClassName = tool.constructor.name.replace(/^_+/, '');
|
||||||
const possibleNames = [tool.name, normalizedClassName];
|
const possibleNames = [tool.name, normalizedClassName];
|
||||||
if (tool instanceof DiscoveredMCPTool) {
|
if (tool instanceof DiscoveredMCPTool) {
|
||||||
|
|||||||
Reference in New Issue
Block a user