fix(prompts): dynamically list active tools in Plan Mode system prompt

- Updates `PromptProvider` to retrieve and alphabetically sort the active tools from `ToolRegistry` for the Plan Mode prompt list.
- Removes hardcoded descriptions for `write_file` and `replace` from `snippets.ts` and `snippets.legacy.ts` as they are now dynamically included.
- Modifies verbiage in Plan Mode instructions to reflect that tools may not be exclusively "read-only" when workspace policies apply overrides.
- Updates snapshot assertions and prompt test mocks to verify the correct dynamic and sorted injection of tool descriptions.
This commit is contained in:
Mahima Shanware
2026-02-24 00:07:42 +00:00
parent 3e5a250b6f
commit 2c7a62049e
5 changed files with 29 additions and 54 deletions
@@ -42,11 +42,9 @@ For example:
You are operating in **Plan Mode** - a structured planning workflow for designing implementation strategies before execution. You are operating in **Plan Mode** - a structured planning workflow for designing implementation strategies before execution.
## Available Tools ## Available Tools
The following read-only tools are available in Plan Mode: The following tools are available in Plan Mode:
<tool>\`glob\`</tool> <tool>\`glob\`</tool>
<tool>\`grep_search\`</tool> <tool>\`grep_search\`</tool>
- \`write_file\` - Save plans to the plans directory (see Plan Storage below)
- \`replace\` - Update plans in the plans directory
## Plan Storage ## Plan Storage
- Save your plans as Markdown (.md) files ONLY within: \`/tmp/plans/\` - Save your plans as Markdown (.md) files ONLY within: \`/tmp/plans/\`
@@ -174,11 +172,9 @@ For example:
You are operating in **Plan Mode** - a structured planning workflow for designing implementation strategies before execution. You are operating in **Plan Mode** - a structured planning workflow for designing implementation strategies before execution.
## Available Tools ## Available Tools
The following read-only tools are available in Plan Mode: The following tools are available in Plan Mode:
<tool>\`glob\`</tool> <tool>\`glob\`</tool>
<tool>\`grep_search\`</tool> <tool>\`grep_search\`</tool>
- \`write_file\` - Save plans to the plans directory (see Plan Storage below)
- \`replace\` - Update plans in the plans directory
## Plan Storage ## Plan Storage
- Save your plans as Markdown (.md) files ONLY within: \`/tmp/plans/\` - Save your plans as Markdown (.md) files ONLY within: \`/tmp/plans/\`
@@ -424,11 +420,9 @@ For example:
You are operating in **Plan Mode** - a structured planning workflow for designing implementation strategies before execution. You are operating in **Plan Mode** - a structured planning workflow for designing implementation strategies before execution.
## Available Tools ## Available Tools
The following read-only tools are available in Plan Mode: The following tools are available in Plan Mode:
<tool>\`glob\`</tool> <tool>\`glob\`</tool>
<tool>\`grep_search\`</tool> <tool>\`grep_search\`</tool>
- \`write_file\` - Save plans to the plans directory (see Plan Storage below)
- \`replace\` - Update plans in the plans directory
## Plan Storage ## Plan Storage
- Save your plans as Markdown (.md) files ONLY within: \`/tmp/project-temp/plans/\` - Save your plans as Markdown (.md) files ONLY within: \`/tmp/project-temp/plans/\`
+14 -20
View File
@@ -25,6 +25,7 @@ import {
} from '../config/models.js'; } from '../config/models.js';
import { ApprovalMode } from '../policy/types.js'; import { ApprovalMode } from '../policy/types.js';
import { DiscoveredMCPTool } from '../tools/mcp-tool.js'; import { DiscoveredMCPTool } from '../tools/mcp-tool.js';
import type { AnyDeclarativeTool } from '../tools/tool-registry.js';
import type { CallableTool } from '@google/genai'; import type { CallableTool } from '@google/genai';
import type { MessageBus } from '../confirmation-bus/message-bus.js'; import type { MessageBus } from '../confirmation-bus/message-bus.js';
@@ -85,6 +86,12 @@ describe('Core System Prompt (prompts.ts)', () => {
getToolRegistry: vi.fn().mockReturnValue({ getToolRegistry: vi.fn().mockReturnValue({
getAllToolNames: vi.fn().mockReturnValue(['grep_search', 'glob']), getAllToolNames: vi.fn().mockReturnValue(['grep_search', 'glob']),
getAllTools: vi.fn().mockReturnValue([]), getAllTools: vi.fn().mockReturnValue([]),
getActiveTools: vi
.fn()
.mockReturnValue([
{ name: 'grep_search' } as unknown as AnyDeclarativeTool,
{ name: 'glob' } as unknown as AnyDeclarativeTool,
]),
}), }),
getEnableShellOutputEfficiency: vi.fn().mockReturnValue(true), getEnableShellOutputEfficiency: vi.fn().mockReturnValue(true),
storage: { storage: {
@@ -452,24 +459,11 @@ describe('Core System Prompt (prompts.ts)', () => {
true, // isReadOnly true, // isReadOnly
); );
const nonReadOnlyMcpTool = new DiscoveredMCPTool( // Note: non-read-only MCP tools are implicitly filtered out by the logic
{} as CallableTool, // because they are not potentially allowed in Plan Mode by default.
'nonreadonly-server',
'non_read_static_value',
'A non-read-only tool',
{},
{} as MessageBus,
false,
false,
);
vi.mocked(mockConfig.getToolRegistry().getAllTools).mockReturnValue([ vi.mocked(mockConfig.getToolRegistry().getActiveTools).mockReturnValue([
readOnlyMcpTool, readOnlyMcpTool,
nonReadOnlyMcpTool,
]);
vi.mocked(mockConfig.getToolRegistry().getAllToolNames).mockReturnValue([
readOnlyMcpTool.name,
nonReadOnlyMcpTool.name,
]); ]);
const prompt = getCoreSystemPrompt(mockConfig); const prompt = getCoreSystemPrompt(mockConfig);
@@ -483,10 +477,10 @@ describe('Core System Prompt (prompts.ts)', () => {
it('should only list available tools in PLAN mode', () => { it('should only list available tools in PLAN mode', () => {
vi.mocked(mockConfig.getApprovalMode).mockReturnValue(ApprovalMode.PLAN); vi.mocked(mockConfig.getApprovalMode).mockReturnValue(ApprovalMode.PLAN);
// Only enable a subset of tools, including ask_user // Only enable a subset of tools, including ask_user
vi.mocked(mockConfig.getToolRegistry().getAllToolNames).mockReturnValue([ vi.mocked(mockConfig.getToolRegistry().getActiveTools).mockReturnValue([
'glob', { name: 'glob' } as unknown as AnyDeclarativeTool,
'read_file', { name: 'read_file' } as unknown as AnyDeclarativeTool,
'ask_user', { name: 'ask_user' } as unknown as AnyDeclarativeTool,
]); ]);
const prompt = getCoreSystemPrompt(mockConfig); const prompt = getCoreSystemPrompt(mockConfig);
+9 -18
View File
@@ -22,7 +22,6 @@ import {
import { CodebaseInvestigatorAgent } from '../agents/codebase-investigator.js'; import { CodebaseInvestigatorAgent } from '../agents/codebase-investigator.js';
import { isGitRepository } from '../utils/gitUtils.js'; import { isGitRepository } from '../utils/gitUtils.js';
import { import {
PLAN_MODE_TOOLS,
WRITE_TODOS_TOOL_NAME, WRITE_TODOS_TOOL_NAME,
READ_FILE_TOOL_NAME, READ_FILE_TOOL_NAME,
ENTER_PLAN_MODE_TOOL_NAME, ENTER_PLAN_MODE_TOOL_NAME,
@@ -67,25 +66,17 @@ export class PromptProvider {
const contextFilenames = getAllGeminiMdFilenames(); const contextFilenames = getAllGeminiMdFilenames();
// --- Context Gathering --- // --- Context Gathering ---
let planModeToolsList = PLAN_MODE_TOOLS.filter((t) => let planModeToolsList = '';
enabledToolNames.has(t),
)
.map((t) => ` <tool>\`${t}\`</tool>`)
.join('\n');
// Add read-only MCP tools to the list
if (isPlanMode) { if (isPlanMode) {
const allTools = config.getToolRegistry().getAllTools(); const activeTools = config.getToolRegistry().getActiveTools();
const readOnlyMcpTools = allTools.filter( activeTools.sort((a, b) => a.name.localeCompare(b.name));
(t): t is DiscoveredMCPTool => planModeToolsList = activeTools
t instanceof DiscoveredMCPTool && !!t.isReadOnly, .map((t) => {
); const serverSuffix =
if (readOnlyMcpTools.length > 0) { t instanceof DiscoveredMCPTool ? ` (${t.serverName})` : '';
const mcpToolsList = readOnlyMcpTools return ` <tool>\`${t.name}\`${serverSuffix}</tool>`;
.map((t) => ` <tool>\`${t.name}\` (${t.serverName})</tool>`) })
.join('\n'); .join('\n');
planModeToolsList += `\n${mcpToolsList}`;
}
} }
let basePrompt: string; let basePrompt: string;
+1 -3
View File
@@ -398,10 +398,8 @@ export function renderPlanningWorkflow(
You are operating in **Plan Mode** - a structured planning workflow for designing implementation strategies before execution. You are operating in **Plan Mode** - a structured planning workflow for designing implementation strategies before execution.
## Available Tools ## Available Tools
The following read-only tools are available in Plan Mode: The following tools are available in Plan Mode:
${options.planModeToolsList} ${options.planModeToolsList}
- \`${WRITE_FILE_TOOL_NAME}\` - Save plans to the plans directory (see Plan Storage below)
- \`${EDIT_TOOL_NAME}\` - Update plans in the plans directory
## Plan Storage ## Plan Storage
- Save your plans as Markdown (.md) files ONLY within: \`${options.plansDir}/\` - Save your plans as Markdown (.md) files ONLY within: \`${options.plansDir}/\`
+1 -3
View File
@@ -452,11 +452,9 @@ export function renderPlanningWorkflow(
You are operating in **Plan Mode**. Your goal is to produce a detailed implementation plan in \`${options.plansDir}/\` and get user approval before editing source code. You are operating in **Plan Mode**. Your goal is to produce a detailed implementation plan in \`${options.plansDir}/\` and get user approval before editing source code.
## Available Tools ## Available Tools
The following read-only tools are available in Plan Mode: The following tools are available in Plan Mode:
<available_tools> <available_tools>
${options.planModeToolsList} ${options.planModeToolsList}
<tool>${formatToolName(WRITE_FILE_TOOL_NAME)} - Save plans to the plans directory</tool>
<tool>${formatToolName(EDIT_TOOL_NAME)} - Update plans in the plans directory</tool>
</available_tools> </available_tools>
## Rules ## Rules