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
22 changes: 16 additions & 6 deletions packages/core/src/prompts/snippets.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,16 @@ import {
SHELL_TOOL_NAME,
WRITE_FILE_TOOL_NAME,
WRITE_TODOS_TOOL_NAME,
GREP_PARAM_TOTAL_MAX_MATCHES,
GREP_PARAM_INCLUDE_PATTERN,
GREP_PARAM_EXCLUDE_PATTERN,
GREP_PARAM_CONTEXT,
GREP_PARAM_BEFORE,
GREP_PARAM_AFTER,
READ_FILE_PARAM_START_LINE,
READ_FILE_PARAM_END_LINE,
SHELL_PARAM_IS_BACKGROUND,
EDIT_PARAM_OLD_STRING,
} from '../tools/tool-names.js';
import type { HierarchicalMemory } from '../config/memory.js';
import { DEFAULT_CONTEXT_FILENAME } from '../tools/memoryTool.js';
Expand Down Expand Up @@ -183,16 +193,16 @@ Use the following guidelines to optimize your search and read patterns.
- Prefer using tools like ${GREP_TOOL_NAME} to identify points of interest instead of reading lots of files individually.
- If you need to read multiple ranges in a file, do so parallel, in as few turns as possible.
- It is more important to reduce extra turns, but please also try to minimize unnecessarily large file reads and search results, when doing so doesn't result in extra turns. Do this by always providing conservative limits and scopes to tools like ${READ_FILE_TOOL_NAME} and ${GREP_TOOL_NAME}.
- ${READ_FILE_TOOL_NAME} fails if old_string is ambiguous, causing extra turns. Take care to read enough with ${READ_FILE_TOOL_NAME} and ${GREP_TOOL_NAME} to make the edit unambiguous.
- ${READ_FILE_TOOL_NAME} fails if ${EDIT_PARAM_OLD_STRING} is ambiguous, causing extra turns. Take care to read enough with ${READ_FILE_TOOL_NAME} and ${GREP_TOOL_NAME} to make the edit unambiguous.
- You can compensate for the risk of missing results with scoped or limited searches by doing multiple searches in parallel.
- Your primary goal is still to do your best quality work. Efficiency is an important, but secondary concern.
</guidelines>

<examples>
- **Searching:** utilize search tools like ${GREP_TOOL_NAME} and ${GLOB_TOOL_NAME} with a conservative result count (\`total_max_matches\`) and a narrow scope (\`include_pattern\` and \`exclude_pattern\` parameters).
- **Searching and editing:** utilize search tools like ${GREP_TOOL_NAME} with a conservative result count and a narrow scope. Use \`context\`, \`before\`, and/or \`after\` to request enough context to avoid the need to read the file before editing matches.
- **Searching:** utilize search tools like ${GREP_TOOL_NAME} and ${GLOB_TOOL_NAME} with a conservative result count (\`${GREP_PARAM_TOTAL_MAX_MATCHES}\`) and a narrow scope (\`${GREP_PARAM_INCLUDE_PATTERN}\` and \`${GREP_PARAM_EXCLUDE_PATTERN}\` parameters).
- **Searching and editing:** utilize search tools like ${GREP_TOOL_NAME} with a conservative result count and a narrow scope. Use \`${GREP_PARAM_CONTEXT}\`, \`${GREP_PARAM_BEFORE}\`, and/or \`${GREP_PARAM_AFTER}\` to request enough context to avoid the need to read the file before editing matches.
- **Understanding:** minimize turns needed to understand a file. It's most efficient to read small files in their entirety.
- **Large files:** utilize search tools like ${GREP_TOOL_NAME} and/or ${READ_FILE_TOOL_NAME} called in parallel with 'start_line' and 'end_line' to reduce the impact on context. Minimize extra turns, unless unavoidable due to the file being too large.
- **Large files:** utilize search tools like ${GREP_TOOL_NAME} and/or ${READ_FILE_TOOL_NAME} called in parallel with '${READ_FILE_PARAM_START_LINE}' and '${READ_FILE_PARAM_END_LINE}' to reduce the impact on context. Minimize extra turns, unless unavoidable due to the file being too large.
- **Navigating:** read the minimum required to not require additional turns spent reading the file.
</examples>

Expand Down Expand Up @@ -659,11 +669,11 @@ function toolUsageInteractive(
? ' If you choose to execute an interactive command consider letting the user know they can press `ctrl + f` to focus into the shell to provide input.'
: '';
return `
- **Background Processes:** To run a command in the background, set the \`is_background\` parameter to true. If unsure, ask the user.
- **Background Processes:** To run a command in the background, set the \`${SHELL_PARAM_IS_BACKGROUND}\` parameter to true. If unsure, ask the user.
- **Interactive Commands:** Always prefer non-interactive commands (e.g., using 'run once' or 'CI' flags for test runners to avoid persistent watch modes or 'git --no-pager') unless a persistent process is specifically required; however, some commands are only interactive and expect user input during their execution (e.g. ssh, vim).${ctrlF}`;
}
return `
- **Background Processes:** To run a command in the background, set the \`is_background\` parameter to true.
- **Background Processes:** To run a command in the background, set the \`${SHELL_PARAM_IS_BACKGROUND}\` parameter to true.
- **Interactive Commands:** Always prefer non-interactive commands (e.g., using 'run once' or 'CI' flags for test runners to avoid persistent watch modes or 'git --no-pager') unless a persistent process is specifically required; however, some commands are only interactive and expect user input during their execution (e.g. ssh, vim).`;
}

Expand Down
92 changes: 91 additions & 1 deletion packages/core/src/tools/definitions/base-declarations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,25 +10,115 @@
*/

// ============================================================================
// TOOL NAMES
// SHARED PARAMETER NAMES (used by multiple tools)
// ============================================================================

export const PARAM_FILE_PATH = 'file_path';
export const PARAM_DIR_PATH = 'dir_path';
export const PARAM_PATTERN = 'pattern';
export const PARAM_CASE_SENSITIVE = 'case_sensitive';
export const PARAM_RESPECT_GIT_IGNORE = 'respect_git_ignore';
export const PARAM_RESPECT_GEMINI_IGNORE = 'respect_gemini_ignore';
export const PARAM_FILE_FILTERING_OPTIONS = 'file_filtering_options';
export const PARAM_DESCRIPTION = 'description';

// ============================================================================
// TOOL NAMES & TOOL-SPECIFIC PARAMETER NAMES
// ============================================================================

// -- glob --
export const GLOB_TOOL_NAME = 'glob';

// -- grep_search --
export const GREP_TOOL_NAME = 'grep_search';
export const GREP_PARAM_INCLUDE_PATTERN = 'include_pattern';
export const GREP_PARAM_EXCLUDE_PATTERN = 'exclude_pattern';
export const GREP_PARAM_NAMES_ONLY = 'names_only';
export const GREP_PARAM_MAX_MATCHES_PER_FILE = 'max_matches_per_file';
export const GREP_PARAM_TOTAL_MAX_MATCHES = 'total_max_matches';
// ripgrep only
export const GREP_PARAM_FIXED_STRINGS = 'fixed_strings';
export const GREP_PARAM_CONTEXT = 'context';
export const GREP_PARAM_AFTER = 'after';
export const GREP_PARAM_BEFORE = 'before';
export const GREP_PARAM_NO_IGNORE = 'no_ignore';

// -- list_directory --
export const LS_TOOL_NAME = 'list_directory';
export const LS_PARAM_IGNORE = 'ignore';

// -- read_file --
export const READ_FILE_TOOL_NAME = 'read_file';
export const READ_FILE_PARAM_START_LINE = 'start_line';
export const READ_FILE_PARAM_END_LINE = 'end_line';

// -- run_shell_command --
export const SHELL_TOOL_NAME = 'run_shell_command';
export const SHELL_PARAM_COMMAND = 'command';
export const SHELL_PARAM_IS_BACKGROUND = 'is_background';

// -- write_file --
export const WRITE_FILE_TOOL_NAME = 'write_file';
export const WRITE_FILE_PARAM_CONTENT = 'content';

// -- replace (edit) --
export const EDIT_TOOL_NAME = 'replace';
export const EDIT_PARAM_INSTRUCTION = 'instruction';
export const EDIT_PARAM_OLD_STRING = 'old_string';
export const EDIT_PARAM_NEW_STRING = 'new_string';
export const EDIT_PARAM_ALLOW_MULTIPLE = 'allow_multiple';

// -- google_web_search --
export const WEB_SEARCH_TOOL_NAME = 'google_web_search';
export const WEB_SEARCH_PARAM_QUERY = 'query';

// -- write_todos --
export const WRITE_TODOS_TOOL_NAME = 'write_todos';
export const TODOS_PARAM_TODOS = 'todos';
export const TODOS_ITEM_PARAM_DESCRIPTION = 'description';
export const TODOS_ITEM_PARAM_STATUS = 'status';

// -- web_fetch --
export const WEB_FETCH_TOOL_NAME = 'web_fetch';
export const WEB_FETCH_PARAM_PROMPT = 'prompt';

// -- read_many_files --
export const READ_MANY_FILES_TOOL_NAME = 'read_many_files';
export const READ_MANY_PARAM_INCLUDE = 'include';
export const READ_MANY_PARAM_EXCLUDE = 'exclude';
export const READ_MANY_PARAM_RECURSIVE = 'recursive';
export const READ_MANY_PARAM_USE_DEFAULT_EXCLUDES = 'useDefaultExcludes';

// -- save_memory --
export const MEMORY_TOOL_NAME = 'save_memory';
export const MEMORY_PARAM_FACT = 'fact';

// -- get_internal_docs --
export const GET_INTERNAL_DOCS_TOOL_NAME = 'get_internal_docs';
export const DOCS_PARAM_PATH = 'path';

// -- activate_skill --
export const ACTIVATE_SKILL_TOOL_NAME = 'activate_skill';
export const SKILL_PARAM_NAME = 'name';

// -- ask_user --
export const ASK_USER_TOOL_NAME = 'ask_user';
export const ASK_USER_PARAM_QUESTIONS = 'questions';
// ask_user question item params
export const ASK_USER_QUESTION_PARAM_QUESTION = 'question';
export const ASK_USER_QUESTION_PARAM_HEADER = 'header';
export const ASK_USER_QUESTION_PARAM_TYPE = 'type';
export const ASK_USER_QUESTION_PARAM_OPTIONS = 'options';
export const ASK_USER_QUESTION_PARAM_MULTI_SELECT = 'multiSelect';
export const ASK_USER_QUESTION_PARAM_PLACEHOLDER = 'placeholder';
// ask_user option item params
export const ASK_USER_OPTION_PARAM_LABEL = 'label';
export const ASK_USER_OPTION_PARAM_DESCRIPTION = 'description';

// -- exit_plan_mode --
export const EXIT_PLAN_MODE_TOOL_NAME = 'exit_plan_mode';
export const EXIT_PLAN_PARAM_PLAN_PATH = 'plan_path';

// -- enter_plan_mode --
export const ENTER_PLAN_MODE_TOOL_NAME = 'enter_plan_mode';
export const PLAN_MODE_PARAM_REASON = 'reason';
53 changes: 53 additions & 0 deletions packages/core/src/tools/definitions/coreTools.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,59 @@ export {
ASK_USER_TOOL_NAME,
EXIT_PLAN_MODE_TOOL_NAME,
ENTER_PLAN_MODE_TOOL_NAME,
// Shared parameter names
PARAM_FILE_PATH,
PARAM_DIR_PATH,
PARAM_PATTERN,
PARAM_CASE_SENSITIVE,
PARAM_RESPECT_GIT_IGNORE,
PARAM_RESPECT_GEMINI_IGNORE,
PARAM_FILE_FILTERING_OPTIONS,
PARAM_DESCRIPTION,
// Tool-specific parameter names
READ_FILE_PARAM_START_LINE,
READ_FILE_PARAM_END_LINE,
WRITE_FILE_PARAM_CONTENT,
GREP_PARAM_INCLUDE_PATTERN,
GREP_PARAM_EXCLUDE_PATTERN,
GREP_PARAM_NAMES_ONLY,
GREP_PARAM_MAX_MATCHES_PER_FILE,
GREP_PARAM_TOTAL_MAX_MATCHES,
GREP_PARAM_FIXED_STRINGS,
GREP_PARAM_CONTEXT,
GREP_PARAM_AFTER,
GREP_PARAM_BEFORE,
GREP_PARAM_NO_IGNORE,
EDIT_PARAM_INSTRUCTION,
EDIT_PARAM_OLD_STRING,
EDIT_PARAM_NEW_STRING,
EDIT_PARAM_ALLOW_MULTIPLE,
LS_PARAM_IGNORE,
SHELL_PARAM_COMMAND,
SHELL_PARAM_IS_BACKGROUND,
WEB_SEARCH_PARAM_QUERY,
WEB_FETCH_PARAM_PROMPT,
READ_MANY_PARAM_INCLUDE,
READ_MANY_PARAM_EXCLUDE,
READ_MANY_PARAM_RECURSIVE,
READ_MANY_PARAM_USE_DEFAULT_EXCLUDES,
MEMORY_PARAM_FACT,
TODOS_PARAM_TODOS,
TODOS_ITEM_PARAM_DESCRIPTION,
TODOS_ITEM_PARAM_STATUS,
DOCS_PARAM_PATH,
ASK_USER_PARAM_QUESTIONS,
ASK_USER_QUESTION_PARAM_QUESTION,
ASK_USER_QUESTION_PARAM_HEADER,
ASK_USER_QUESTION_PARAM_TYPE,
ASK_USER_QUESTION_PARAM_OPTIONS,
ASK_USER_QUESTION_PARAM_MULTI_SELECT,
ASK_USER_QUESTION_PARAM_PLACEHOLDER,
ASK_USER_OPTION_PARAM_LABEL,
ASK_USER_OPTION_PARAM_DESCRIPTION,
PLAN_MODE_PARAM_REASON,
EXIT_PLAN_PARAM_PLAN_PATH,
SKILL_PARAM_NAME,
} from './base-declarations.js';

// Re-export sets for compatibility
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,12 @@ import {
SHELL_TOOL_NAME,
EXIT_PLAN_MODE_TOOL_NAME,
ACTIVATE_SKILL_TOOL_NAME,
SHELL_PARAM_COMMAND,
PARAM_DESCRIPTION,
PARAM_DIR_PATH,
SHELL_PARAM_IS_BACKGROUND,
EXIT_PLAN_PARAM_PLAN_PATH,
SKILL_PARAM_NAME,
} from './base-declarations.js';

/**
Expand Down Expand Up @@ -47,12 +53,12 @@ export function getShellToolDescription(

if (os.platform() === 'win32') {
const backgroundInstructions = enableInteractiveShell
? 'To run a command in the background, set the `is_background` parameter to true. Do NOT use PowerShell background constructs.'
? `To run a command in the background, set the \`${SHELL_PARAM_IS_BACKGROUND}\` parameter to true. Do NOT use PowerShell background constructs.`
: 'Command can start background processes using PowerShell constructs such as `Start-Process -NoNewWindow` or `Start-Job`.';
return `This tool executes a given shell command as \`powershell.exe -NoProfile -Command <command>\`. ${backgroundInstructions}${efficiencyGuidelines}${returnedInfo}`;
} else {
const backgroundInstructions = enableInteractiveShell
? 'To run a command in the background, set the `is_background` parameter to true. Do NOT use `&` to background commands.'
? `To run a command in the background, set the \`${SHELL_PARAM_IS_BACKGROUND}\` parameter to true. Do NOT use \`&\` to background commands.`
: 'Command can start background processes using `&`.';
return `This tool executes a given shell command as \`bash -c <command>\`. ${backgroundInstructions} Command is executed as a subprocess that leads its own process group. Command process group can be terminated as \`kill -- -PGID\` or signaled as \`kill -s SIGNAL -- -PGID\`.${efficiencyGuidelines}${returnedInfo}`;
}
Expand Down Expand Up @@ -84,27 +90,27 @@ export function getShellDeclaration(
parametersJsonSchema: {
type: 'object',
properties: {
command: {
[SHELL_PARAM_COMMAND]: {
type: 'string',
description: getCommandDescription(),
},
description: {
[PARAM_DESCRIPTION]: {
type: 'string',
description:
'Brief description of the command for the user. Be specific and concise. Ideally a single sentence. Can be up to 3 sentences for clarity. No line breaks.',
},
dir_path: {
[PARAM_DIR_PATH]: {
type: 'string',
description:
'(OPTIONAL) The path of the directory to run the command in. If not provided, the project root directory is used. Must be a directory within the workspace and must already exist.',
},
is_background: {
[SHELL_PARAM_IS_BACKGROUND]: {
type: 'boolean',
description:
'Set to true if this command should be run in the background (e.g. for long-running servers or watchers). The command will be started, allowed to run for a brief moment to check for immediate errors, and then moved to the background.',
},
},
required: ['command'],
required: [SHELL_PARAM_COMMAND],
},
};
}
Expand All @@ -121,9 +127,9 @@ export function getExitPlanModeDeclaration(
'Finalizes the planning phase and transitions to implementation by presenting the plan for user approval. This tool MUST be used to exit Plan Mode before any source code edits can be performed. Call this whenever a plan is ready or the user requests implementation.',
parametersJsonSchema: {
type: 'object',
required: ['plan_path'],
required: [EXIT_PLAN_PARAM_PLAN_PATH],
properties: {
plan_path: {
[EXIT_PLAN_PARAM_PLAN_PATH]: {
type: 'string',
description: `The file path to the finalized plan (e.g., "${plansDir}/feature-x.md"). This path MUST be within the designated plans directory: ${plansDir}/`,
},
Expand All @@ -146,11 +152,13 @@ export function getActivateSkillDeclaration(
let schema: z.ZodTypeAny;
if (skillNames.length === 0) {
schema = z.object({
name: z.string().describe('No skills are currently available.'),
[SKILL_PARAM_NAME]: z
.string()
.describe('No skills are currently available.'),
});
} else {
schema = z.object({
name: z
[SKILL_PARAM_NAME]: z
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
.enum(skillNames as [string, ...string[]])
.describe('The name of the skill to activate.'),
Expand Down
Loading
Loading