Files
gemini-cli/packages/core/src/tools/tool-names.ts
Mahima Shanware 3e5a250b6f feat(tools): delegate Plan Mode tool filtering to PolicyEngine
- Removes hardcoded `PLAN_MODE_TOOLS` from `ToolRegistry` and delegates permission checks to the `PolicyEngine` using the new `isToolPotentiallyAllowed` method.
- Preserves Plan Mode bypass logic for read-only MCP tools while ensuring they respect explicit/wildcard policy blocks.
- Makes `getActiveTools` public with TSDoc documentation for use in prompt generation.
- Adds regression tests to `tool-registry.test.ts` to verify policy-driven tool availability.
2026-02-24 00:02:43 +00:00

164 lines
4.1 KiB
TypeScript

/**
* @license
* Copyright 2025 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
import {
GLOB_TOOL_NAME,
GREP_TOOL_NAME,
LS_TOOL_NAME,
READ_FILE_TOOL_NAME,
SHELL_TOOL_NAME,
WRITE_FILE_TOOL_NAME,
EDIT_TOOL_NAME,
WEB_SEARCH_TOOL_NAME,
WRITE_TODOS_TOOL_NAME,
WEB_FETCH_TOOL_NAME,
READ_MANY_FILES_TOOL_NAME,
MEMORY_TOOL_NAME,
GET_INTERNAL_DOCS_TOOL_NAME,
ACTIVATE_SKILL_TOOL_NAME,
ASK_USER_TOOL_NAME,
EXIT_PLAN_MODE_TOOL_NAME,
ENTER_PLAN_MODE_TOOL_NAME,
} from './definitions/coreTools.js';
export {
GLOB_TOOL_NAME,
GREP_TOOL_NAME,
LS_TOOL_NAME,
READ_FILE_TOOL_NAME,
SHELL_TOOL_NAME,
WRITE_FILE_TOOL_NAME,
EDIT_TOOL_NAME,
WEB_SEARCH_TOOL_NAME,
WRITE_TODOS_TOOL_NAME,
WEB_FETCH_TOOL_NAME,
READ_MANY_FILES_TOOL_NAME,
MEMORY_TOOL_NAME,
GET_INTERNAL_DOCS_TOOL_NAME,
ACTIVATE_SKILL_TOOL_NAME,
ASK_USER_TOOL_NAME,
EXIT_PLAN_MODE_TOOL_NAME,
ENTER_PLAN_MODE_TOOL_NAME,
};
export const LS_TOOL_NAME_LEGACY = 'list_directory'; // Just to be safe if anything used the old exported name directly
export const EDIT_TOOL_NAMES = new Set([EDIT_TOOL_NAME, WRITE_FILE_TOOL_NAME]);
// Tool Display Names
export const WRITE_FILE_DISPLAY_NAME = 'WriteFile';
export const EDIT_DISPLAY_NAME = 'Edit';
export const ASK_USER_DISPLAY_NAME = 'Ask User';
export const READ_FILE_DISPLAY_NAME = 'ReadFile';
export const GLOB_DISPLAY_NAME = 'FindFiles';
/**
* Mapping of legacy tool names to their current names.
* This ensures backward compatibility for user-defined policies, skills, and hooks.
*/
export const TOOL_LEGACY_ALIASES: Record<string, string> = {
// Add future renames here, e.g.:
search_file_content: GREP_TOOL_NAME,
};
/**
* Returns all associated names for a tool (including legacy aliases and current name).
* This ensures that if multiple legacy names point to the same tool, we consider all of them
* for policy application.
*/
export function getToolAliases(name: string): string[] {
const aliases = new Set<string>([name]);
// Determine the canonical (current) name
const canonicalName = TOOL_LEGACY_ALIASES[name] ?? name;
aliases.add(canonicalName);
// Find all other legacy aliases that point to the same canonical name
for (const [legacyName, currentName] of Object.entries(TOOL_LEGACY_ALIASES)) {
if (currentName === canonicalName) {
aliases.add(legacyName);
}
}
return Array.from(aliases);
}
/** Prefix used for tools discovered via the tool DiscoveryCommand. */
export const DISCOVERED_TOOL_PREFIX = 'discovered_tool_';
/**
* List of all built-in tool names.
*/
export const ALL_BUILTIN_TOOL_NAMES = [
GLOB_TOOL_NAME,
WRITE_TODOS_TOOL_NAME,
WRITE_FILE_TOOL_NAME,
WEB_SEARCH_TOOL_NAME,
WEB_FETCH_TOOL_NAME,
EDIT_TOOL_NAME,
SHELL_TOOL_NAME,
GREP_TOOL_NAME,
READ_MANY_FILES_TOOL_NAME,
READ_FILE_TOOL_NAME,
LS_TOOL_NAME,
MEMORY_TOOL_NAME,
ACTIVATE_SKILL_TOOL_NAME,
ASK_USER_TOOL_NAME,
GET_INTERNAL_DOCS_TOOL_NAME,
ENTER_PLAN_MODE_TOOL_NAME,
EXIT_PLAN_MODE_TOOL_NAME,
] as const;
/**
* Validates if a tool name is syntactically valid.
* Checks against built-in tools, discovered tools, and MCP naming conventions.
*/
export function isValidToolName(
name: string,
options: { allowWildcards?: boolean } = {},
): boolean {
// Built-in tools
if ((ALL_BUILTIN_TOOL_NAMES as readonly string[]).includes(name)) {
return true;
}
// Legacy aliases
if (TOOL_LEGACY_ALIASES[name]) {
return true;
}
// Discovered tools
if (name.startsWith(DISCOVERED_TOOL_PREFIX)) {
return true;
}
// Policy wildcards
if (options.allowWildcards && name === '*') {
return true;
}
// MCP tools (format: server__tool)
if (name.includes('__')) {
const parts = name.split('__');
if (parts.length !== 2 || parts[0].length === 0 || parts[1].length === 0) {
return false;
}
const server = parts[0];
const tool = parts[1];
if (tool === '*') {
return !!options.allowWildcards;
}
// Basic slug validation for server and tool names
const slugRegex = /^[a-z0-9-_]+$/i;
return slugRegex.test(server) && slugRegex.test(tool);
}
return false;
}