diff --git a/packages/agent/CHANGELOG.md b/packages/agent/CHANGELOG.md index 133e3ea6d..1b5106dc9 100644 --- a/packages/agent/CHANGELOG.md +++ b/packages/agent/CHANGELOG.md @@ -1,6 +1,9 @@ # Changelog ## [Unreleased] +### Added + +- Added `nonAbortable` option to tools to ignore abort signals during execution ## [6.8.0] - 2026-01-20 ### Changed diff --git a/packages/agent/src/agent-loop.ts b/packages/agent/src/agent-loop.ts index d2c53c7d1..f112661cc 100644 --- a/packages/agent/src/agent-loop.ts +++ b/packages/agent/src/agent-loop.ts @@ -410,7 +410,7 @@ async function executeToolCalls( result = await tool.execute( toolCall.id, validatedArgs, - signal, + tool.nonAbortable ? undefined : signal, (partialResult) => { stream.push({ type: "tool_execution_update", diff --git a/packages/agent/src/types.ts b/packages/agent/src/types.ts index f7f1b3a67..083115840 100644 --- a/packages/agent/src/types.ts +++ b/packages/agent/src/types.ts @@ -204,6 +204,8 @@ export interface AgentTool, diff --git a/packages/coding-agent/CHANGELOG.md b/packages/coding-agent/CHANGELOG.md index be657d395..81003838a 100644 --- a/packages/coding-agent/CHANGELOG.md +++ b/packages/coding-agent/CHANGELOG.md @@ -1,7 +1,6 @@ # Changelog ## [Unreleased] - ### Added - Added `isolated` option to run tasks in isolated git worktrees @@ -10,6 +9,11 @@ ### Changed +- Simplified tool parameter descriptions across all tools for brevity +- Updated find tool to always sort results by modification time +- Changed web-fetch timeout default from 20s to 45s maximum +- Updated bash prompt to use `cwd` parameter instead of `workdir` +- Simplified tool prompt documentation for better readability - Removed model parameter from task tool to use session model by default - Removed model parameter from gemini-image tool to use provider defaults - Improved variable display in task output with humanized keys for single variables diff --git a/packages/coding-agent/src/core/tools/ask.ts b/packages/coding-agent/src/core/tools/ask.ts index 5e851d002..1ed8ca459 100644 --- a/packages/coding-agent/src/core/tools/ask.ts +++ b/packages/coding-agent/src/core/tools/ask.ts @@ -31,29 +31,21 @@ import { ToolUIKit } from "./render-utils"; // ============================================================================= const OptionItem = Type.Object({ - label: Type.String({ description: "Display label for this option" }), + label: Type.String({ description: "Display label" }), }); const QuestionItem = Type.Object({ - id: Type.String({ description: "Short identifier for this question (e.g., 'auth', 'cache')" }), - question: Type.String({ description: "The question text" }), - options: Type.Array(OptionItem, { description: "Options for this question" }), - multi: Type.Optional(Type.Boolean({ description: "Allow multiple selections for this question" })), + id: Type.String({ description: "Question ID, e.g. 'auth', 'cache'" }), + question: Type.String({ description: "Question text" }), + options: Type.Array(OptionItem, { description: "Available options" }), + multi: Type.Optional(Type.Boolean({ description: "Allow multiple selections" })), }); const askSchema = Type.Object({ - question: Type.Optional(Type.String({ description: "The question to ask the user" })), - options: Type.Optional(Type.Array(OptionItem, { description: "Available options for the user to choose from." })), - multi: Type.Optional( - Type.Boolean({ - description: "Allow multiple options to be selected (default: false)", - }), - ), - questions: Type.Optional( - Type.Array(QuestionItem, { - description: "Multiple questions to ask in sequence, each with their own options", - }), - ), + question: Type.Optional(Type.String({ description: "Question to ask" })), + options: Type.Optional(Type.Array(OptionItem, { description: "Available options" })), + multi: Type.Optional(Type.Boolean({ description: "Allow multiple selections (default: false)" })), + questions: Type.Optional(Type.Array(QuestionItem, { description: "Multiple questions in sequence" })), }); /** Result for a single question */ diff --git a/packages/coding-agent/src/core/tools/bash.ts b/packages/coding-agent/src/core/tools/bash.ts index 8a5e2050d..60d628aca 100644 --- a/packages/coding-agent/src/core/tools/bash.ts +++ b/packages/coding-agent/src/core/tools/bash.ts @@ -18,9 +18,9 @@ import { formatTailTruncationNotice, type TruncationResult, truncateTail } from export const BASH_DEFAULT_PREVIEW_LINES = 10; const bashSchema = Type.Object({ - command: Type.String({ description: "Bash command to execute" }), - timeout: Type.Optional(Type.Number({ description: "Timeout in seconds (optional, no default timeout)" })), - cwd: Type.Optional(Type.String({ description: "Working directory for the command (default: current directory)" })), + command: Type.String({ description: "Command to execute" }), + timeout: Type.Optional(Type.Number({ description: "Timeout in seconds" })), + cwd: Type.Optional(Type.String({ description: "Working directory (default: cwd)" })), }); export interface BashToolDetails { diff --git a/packages/coding-agent/src/core/tools/find.ts b/packages/coding-agent/src/core/tools/find.ts index 92d27e971..b567e14dc 100644 --- a/packages/coding-agent/src/core/tools/find.ts +++ b/packages/coding-agent/src/core/tools/find.ts @@ -17,19 +17,13 @@ import { PREVIEW_LIMITS, ToolUIKit } from "./render-utils"; import { DEFAULT_MAX_BYTES, formatSize, type TruncationResult, truncateHead } from "./truncate"; const findSchema = Type.Object({ - pattern: Type.String({ - description: "Glob pattern to match files, e.g. '*.ts', '**/*.json', or 'src/**/*.spec.ts'", - }), - path: Type.Optional(Type.String({ description: "Directory to search in (default: current directory)" })), - limit: Type.Optional(Type.Number({ description: "Maximum number of results (default: 1000)" })), + pattern: Type.String({ description: "Glob pattern, e.g. '*.ts', '**/*.json'" }), + path: Type.Optional(Type.String({ description: "Directory to search (default: cwd)" })), + limit: Type.Optional(Type.Number({ description: "Max results (default: 1000)" })), hidden: Type.Optional(Type.Boolean({ description: "Include hidden files (default: true)" })), - sortByMtime: Type.Optional( - Type.Boolean({ description: "Sort results by modification time, most recent first (default: false)" }), - ), type: Type.Optional( StringEnum(["file", "dir", "all"], { - description: - "Filter by type: 'file' for files only, 'dir' for directories only, 'all' for both (default: 'all')", + description: "Filter: file, dir, or all (default: all)", }), ), }); @@ -128,7 +122,7 @@ export class FindTool implements AgentTool { _onUpdate?: AgentToolUpdateCallback, _context?: AgentToolContext, ): Promise> { - const { pattern, path: searchDir, limit, hidden, sortByMtime, type } = params; + const { pattern, path: searchDir, limit, hidden, type } = params; return untilAborted(signal, async () => { const searchPath = resolveToCwd(searchDir || ".", this.session.cwd); @@ -139,7 +133,6 @@ export class FindTool implements AgentTool { const effectiveLimit = limit ?? DEFAULT_LIMIT; const effectiveType = type ?? "all"; const includeHidden = hidden ?? true; - const shouldSortByMtime = sortByMtime ?? false; // If custom operations provided with glob, use that instead of fd if (this.customOps?.glob) { @@ -318,24 +311,20 @@ export class FindTool implements AgentTool { relativePath += "/"; } - // When sorting by mtime, keep files that fail to stat with mtime 0 - if (shouldSortByMtime) { - try { - const fullPath = path.join(searchPath, relativePath); - const stat = await Bun.file(fullPath).stat(); - relativized.push(relativePath); - mtimes.push(stat.mtimeMs); - } catch { - relativized.push(relativePath); - mtimes.push(0); - } - } else { + // Get mtime for sorting (files that fail to stat get mtime 0) + try { + const fullPath = path.join(searchPath, relativePath); + const stat = await Bun.file(fullPath).stat(); relativized.push(relativePath); + mtimes.push(stat.mtimeMs); + } catch { + relativized.push(relativePath); + mtimes.push(0); } } - // Sort by mtime if requested (most recent first) - if (shouldSortByMtime && relativized.length > 0) { + // Sort by mtime (most recent first) + if (relativized.length > 0) { const indexed = relativized.map((path, idx) => ({ path, mtime: mtimes[idx] })); indexed.sort((a, b) => b.mtime - a.mtime); relativized.length = 0; diff --git a/packages/coding-agent/src/core/tools/grep.ts b/packages/coding-agent/src/core/tools/grep.ts index 56a89174c..a0653ac12 100644 --- a/packages/coding-agent/src/core/tools/grep.ts +++ b/packages/coding-agent/src/core/tools/grep.ts @@ -25,34 +25,23 @@ import { } from "./truncate"; const grepSchema = Type.Object({ - pattern: Type.String({ description: "Search pattern (regex or literal string)" }), - path: Type.Optional(Type.String({ description: "Directory or file to search (default: current directory)" })), - glob: Type.Optional(Type.String({ description: "Filter files by glob pattern, e.g. '*.ts' or '**/*.spec.ts'" })), - type: Type.Optional(Type.String({ description: "File type filter (e.g., 'ts', 'rust', 'py')" })), - ignoreCase: Type.Optional( - Type.Boolean({ description: "Force case-insensitive search (default: false, uses smart-case otherwise)" }), - ), - caseSensitive: Type.Optional( - Type.Boolean({ description: "Force case-sensitive search (default: false, disables smart-case)" }), - ), - literal: Type.Optional( - Type.Boolean({ description: "Treat pattern as literal string instead of regex (default: false)" }), - ), - multiline: Type.Optional( - Type.Boolean({ description: "Enable multiline matching for cross-line patterns (default: false)" }), - ), - context: Type.Optional( - Type.Number({ description: "Number of lines to show before and after each match (default: 0)" }), - ), - limit: Type.Optional(Type.Number({ description: "Maximum number of matches to return (default: 100)" })), + pattern: Type.String({ description: "Search pattern (regex)" }), + path: Type.Optional(Type.String({ description: "Directory or file to search (default: cwd)" })), + glob: Type.Optional(Type.String({ description: "Glob filter, e.g. '*.ts', '**/*.spec.ts'" })), + type: Type.Optional(Type.String({ description: "File type filter, e.g. 'ts', 'py', 'rust'" })), + ignoreCase: Type.Optional(Type.Boolean({ description: "Force case-insensitive (default: smart-case)" })), + caseSensitive: Type.Optional(Type.Boolean({ description: "Force case-sensitive (default: smart-case)" })), + literal: Type.Optional(Type.Boolean({ description: "Treat pattern as literal, not regex (default: false)" })), + multiline: Type.Optional(Type.Boolean({ description: "Match across line boundaries (default: false)" })), + context: Type.Optional(Type.Number({ description: "Lines of context before/after match (default: 0)" })), + limit: Type.Optional(Type.Number({ description: "Max matches to return (default: 100)" })), outputMode: Type.Optional( StringEnum(["content", "files_with_matches", "count"], { - description: - "Output mode: 'content' shows matching lines, 'files_with_matches' shows only file paths, 'count' shows match counts per file (default: 'content')", + description: "Output format (default: content)", }), ), - headLimit: Type.Optional(Type.Number({ description: "Limit output to first N results (default: unlimited)" })), - offset: Type.Optional(Type.Number({ description: "Skip first N results before applying headLimit (default: 0)" })), + headLimit: Type.Optional(Type.Number({ description: "Truncate output to first N results" })), + offset: Type.Optional(Type.Number({ description: "Skip first N results (default: 0)" })), }); const DEFAULT_LIMIT = 100; diff --git a/packages/coding-agent/src/core/tools/lsp/types.ts b/packages/coding-agent/src/core/tools/lsp/types.ts index ca4fa7589..c56ba1a51 100644 --- a/packages/coding-agent/src/core/tools/lsp/types.ts +++ b/packages/coding-agent/src/core/tools/lsp/types.ts @@ -30,23 +30,21 @@ export const lspSchema = Type.Object({ "related_tests", "reload_workspace", ], - { description: "LSP action to perform" }, - ), - files: Type.Optional(Type.Array(Type.String({ description: "File paths for diagnostics" }))), - file: Type.Optional(Type.String({ description: "File path for file-specific actions" })), - line: Type.Optional(Type.Number({ description: "1-based line number" })), - column: Type.Optional(Type.Number({ description: "1-based column number" })), - end_line: Type.Optional(Type.Number({ description: "1-based end line number for ranges" })), - end_character: Type.Optional(Type.Number({ description: "1-based end column number for ranges" })), - query: Type.Optional(Type.String({ description: "Search query for symbols/SSR pattern" })), - new_name: Type.Optional(Type.String({ description: "New name for rename action" })), - replacement: Type.Optional(Type.String({ description: "Replacement for SSR action" })), - kind: Type.Optional(Type.String({ description: "Code action kind filter (quickfix, refactor, source)" })), - apply: Type.Optional(Type.Boolean({ description: "Apply edits instead of preview (default: true)" })), - action_index: Type.Optional(Type.Number({ description: "Index of code action to apply" })), - include_declaration: Type.Optional( - Type.Boolean({ description: "Include declaration in references (default: true)" }), + { description: "LSP operation" }, ), + files: Type.Optional(Type.Array(Type.String({ description: "File path" }))), + file: Type.Optional(Type.String({ description: "File path" })), + line: Type.Optional(Type.Number({ description: "Line number (1-indexed)" })), + column: Type.Optional(Type.Number({ description: "Column number (1-indexed)" })), + end_line: Type.Optional(Type.Number({ description: "End line for range (1-indexed)" })), + end_character: Type.Optional(Type.Number({ description: "End column for range (1-indexed)" })), + query: Type.Optional(Type.String({ description: "Search query or SSR pattern" })), + new_name: Type.Optional(Type.String({ description: "New name for rename" })), + replacement: Type.Optional(Type.String({ description: "Replacement text for SSR" })), + kind: Type.Optional(Type.String({ description: "Action kind: quickfix, refactor, source" })), + apply: Type.Optional(Type.Boolean({ description: "Apply edits (default: true)" })), + action_index: Type.Optional(Type.Number({ description: "Index of action to apply" })), + include_declaration: Type.Optional(Type.Boolean({ description: "Include declaration in refs (default: true)" })), }); export type LspParams = Static; diff --git a/packages/coding-agent/src/core/tools/patch/index.ts b/packages/coding-agent/src/core/tools/patch/index.ts index 406ee5c74..35ff6e557 100644 --- a/packages/coding-agent/src/core/tools/patch/index.ts +++ b/packages/coding-agent/src/core/tools/patch/index.ts @@ -90,27 +90,21 @@ export { ApplyPatchError, EditMatchError, ParseError } from "./types"; // ═══════════════════════════════════════════════════════════════════════════ const replaceEditSchema = Type.Object({ - path: Type.String({ description: "Path to the file to edit (relative or absolute)" }), - oldText: Type.String({ - description: "Text to find and replace (high-confidence fuzzy matching for whitespace/indentation is always on)", - }), - newText: Type.String({ description: "New text to replace the old text with" }), - all: Type.Optional(Type.Boolean({ description: "Replace all occurrences instead of requiring unique match" })), + path: Type.String({ description: "File path (relative or absolute)" }), + oldText: Type.String({ description: "Text to find (fuzzy whitespace matching enabled)" }), + newText: Type.String({ description: "Replacement text" }), + all: Type.Optional(Type.Boolean({ description: "Replace all occurrences (default: unique match required)" })), }); const patchEditSchema = Type.Object({ - path: Type.String({ description: "Path to the file" }), + path: Type.String({ description: "File path" }), op: Type.Optional( StringEnum(["create", "delete", "update"], { - description: "The operation to perform (Defaults to 'update')", - }), - ), - rename: Type.Optional(Type.String({ description: "New path, if moving" })), - diff: Type.Optional( - Type.String({ - description: "Diff hunk(s) for update. Full content for create.", + description: "Operation (default: update)", }), ), + rename: Type.Optional(Type.String({ description: "New path for move" })), + diff: Type.Optional(Type.String({ description: "Diff hunks (update) or full content (create)" })), }); export type ReplaceParams = { path: string; oldText: string; newText: string; all?: boolean }; diff --git a/packages/coding-agent/src/core/tools/python.ts b/packages/coding-agent/src/core/tools/python.ts index 5170c3972..2a323a607 100644 --- a/packages/coding-agent/src/core/tools/python.ts +++ b/packages/coding-agent/src/core/tools/python.ts @@ -41,22 +41,14 @@ function groupPreludeHelpers(helpers: PreludeHelper[]): PreludeCategory[] { export const pythonSchema = Type.Object({ cells: Type.Array( Type.Object({ - code: Type.String({ - description: - "Python code for this cell. Keep it focused (imports, helper, test, use). No narrative text—put explanations in the assistant message or in the cell title.", - }), - title: Type.Optional( - Type.String({ description: "Short label for the cell (e.g., 'imports', 'parse helper')." }), - ), + code: Type.String({ description: "Python code to execute" }), + title: Type.Optional(Type.String({ description: "Cell label, e.g. 'imports', 'helper'" })), }), - { - description: - "Python cells to execute sequentially. Each cell runs in the same kernel—imports and variables persist. Keep cells small: one logical step each (import, define, test, use). If a cell fails, fix only that cell; earlier cells' state remains.", - }, + { description: "Cells to execute sequentially in persistent kernel" }, ), - timeoutMs: Type.Optional(Type.Number({ description: "Timeout in milliseconds (default: 30000)" })), - cwd: Type.Optional(Type.String({ description: "Working directory for the command (default: current directory)" })), - reset: Type.Optional(Type.Boolean({ description: "Restart the kernel before executing this code" })), + timeoutMs: Type.Optional(Type.Number({ description: "Timeout in ms (default: 30000)" })), + cwd: Type.Optional(Type.String({ description: "Working directory (default: cwd)" })), + reset: Type.Optional(Type.Boolean({ description: "Restart kernel before execution" })), }); export type PythonToolParams = Static; diff --git a/packages/coding-agent/src/core/tools/task/types.ts b/packages/coding-agent/src/core/tools/task/types.ts index f2dae1a57..0a3354b78 100644 --- a/packages/coding-agent/src/core/tools/task/types.ts +++ b/packages/coding-agent/src/core/tools/task/types.ts @@ -40,12 +40,12 @@ export const TASK_SUBAGENT_PROGRESS_CHANNEL = "task:subagent:progress"; /** Single task item for parallel execution */ export const taskItemSchema = Type.Object({ id: Type.String({ - description: "Short task identifier for display (max 32 chars, CamelCase, e.g. 'SessionStore', 'WebFetchFix')", + description: "Task ID, CamelCase, max 32 chars", maxLength: 32, }), - description: Type.String({ description: "Short description for UI display" }), + description: Type.String({ description: "Short description for display" }), vars: Type.Record(Type.String(), Type.String(), { - description: "Template variables to fill {{placeholders}} in context", + description: "Variables to fill {{placeholders}} in context", }), }); @@ -53,22 +53,13 @@ export type TaskItem = Static; /** Task tool parameters */ export const taskSchema = Type.Object({ - agent: Type.String({ description: "Agent type to use for all tasks" }), - context: Type.String({ description: "Template with {{placeholders}} filled by task vars" }), - isolated: Type.Optional( - Type.Boolean({ - description: "Run each task in an isolated git worktree", - }), - ), + agent: Type.String({ description: "Agent type for all tasks" }), + context: Type.String({ description: "Template with {{placeholders}} for vars" }), + isolated: Type.Optional(Type.Boolean({ description: "Run in isolated git worktree" })), output: Type.Optional( - Type.Record(Type.String(), Type.Unknown(), { - description: "JTD schema for structured subagent output", - }), + Type.Record(Type.String(), Type.Unknown(), { description: "JTD schema for structured output" }), ), - tasks: Type.Array(taskItemSchema, { - description: "Tasks to run in parallel", - maxItems: MAX_PARALLEL_TASKS, - }), + tasks: Type.Array(taskItemSchema, { description: "Tasks to run in parallel", maxItems: MAX_PARALLEL_TASKS }), }); export type TaskParams = Static; diff --git a/packages/coding-agent/src/core/tools/web-fetch.ts b/packages/coding-agent/src/core/tools/web-fetch.ts index 2cbefca33..68906fbac 100644 --- a/packages/coding-agent/src/core/tools/web-fetch.ts +++ b/packages/coding-agent/src/core/tools/web-fetch.ts @@ -872,11 +872,9 @@ async function renderUrl( // ============================================================================= const webFetchSchema = Type.Object({ - url: Type.String({ description: "The URL to fetch and render" }), - timeout: Type.Optional(Type.Number({ description: "Timeout in seconds (default: 20, max: 120)" })), - raw: Type.Optional( - Type.Boolean({ description: "Return raw content without site-specific rendering or LLM-friendly transforms" }), - ), + url: Type.String({ description: "URL to fetch" }), + timeout: Type.Optional(Type.Number({ description: "Timeout in seconds (default: 20, max: 45)" })), + raw: Type.Optional(Type.Boolean({ description: "Return raw HTML without transforms" })), }); export interface WebFetchToolDetails { diff --git a/packages/coding-agent/src/core/tools/web-search/index.ts b/packages/coding-agent/src/core/tools/web-search/index.ts index 77e3e55fb..8e3e8d075 100644 --- a/packages/coding-agent/src/core/tools/web-search/index.ts +++ b/packages/coding-agent/src/core/tools/web-search/index.ts @@ -38,20 +38,16 @@ export const webSearchSchema = Type.Object({ query: Type.String({ description: "Search query" }), provider: Type.Optional( StringEnum(["auto", "exa", "anthropic", "perplexity"], { - description: "Search provider (auto-detected if omitted or set to auto)", + description: "Search provider (default: auto)", }), ), - num_results: Type.Optional(Type.Number({ description: "Maximum number of results to return" })), + num_results: Type.Optional(Type.Number({ description: "Max results to return" })), // Common (Anthropic & Perplexity) - system_prompt: Type.Optional( - Type.String({ - description: "System prompt to guide response style", - }), - ), + system_prompt: Type.Optional(Type.String({ description: "System prompt for response style" })), max_tokens: Type.Optional( Type.Number({ - description: "Maximum tokens in response, 1-16384, default 4096 (Anthropic only)", + description: "Max tokens, 1-16384 (default: 4096, Anthropic only)", minimum: 1, maximum: 16384, }), @@ -60,29 +56,21 @@ export const webSearchSchema = Type.Object({ // Perplexity-specific model: Type.Optional( StringEnum(["sonar", "sonar-pro"], { - description: "Perplexity model - sonar (fast) or sonar-pro (comprehensive research)", + description: "Perplexity model: sonar or sonar-pro", }), ), search_recency_filter: Type.Optional( StringEnum(["day", "week", "month", "year"], { - description: "Filter results by recency (Perplexity only)", + description: "Recency filter (Perplexity)", }), ), search_domain_filter: Type.Optional( - Type.Array(Type.String(), { - description: "Domain filter - include domains, prefix with - to exclude (Perplexity only)", - }), + Type.Array(Type.String(), { description: "Domain filter, prefix - to exclude (Perplexity)" }), ), search_context_size: Type.Optional( - StringEnum(["low", "medium", "high"], { - description: "Context size for cost control (Perplexity only)", - }), - ), - return_related_questions: Type.Optional( - Type.Boolean({ - description: "Include follow-up question suggestions, default true (Perplexity only)", - }), + StringEnum(["low", "medium", "high"], { description: "Context size (Perplexity)" }), ), + return_related_questions: Type.Optional(Type.Boolean({ description: "Include related questions (Perplexity)" })), }); export type WebSearchParams = { diff --git a/packages/coding-agent/src/prompts/tools/bash.md b/packages/coding-agent/src/prompts/tools/bash.md index 28af5124a..ae9062d98 100644 --- a/packages/coding-agent/src/prompts/tools/bash.md +++ b/packages/coding-agent/src/prompts/tools/bash.md @@ -13,7 +13,7 @@ Do NOT use Bash for: -- Use `workdir` parameter to run commands in a specific directory instead of `cd dir && ...` +- Use `cwd` parameter to set working directory instead of `cd dir && ...` - Paths with spaces must use double quotes: `cd "/path/with spaces"` - For sequential dependent operations, chain with `&&`: `mkdir foo && cd foo && touch bar` - For parallel independent operations, make multiple tool calls in one message diff --git a/packages/coding-agent/src/prompts/tools/read.md b/packages/coding-agent/src/prompts/tools/read.md index 33f366b31..0ae3f8b73 100644 --- a/packages/coding-agent/src/prompts/tools/read.md +++ b/packages/coding-agent/src/prompts/tools/read.md @@ -1,32 +1,18 @@ # Read -Reads a file from the local filesystem. You can access any file directly by using this tool. -Assume this tool is able to read all files on the machine. If the User provides a path to a file assume that path is valid. It is okay to read a file that does not exist; an error will be returned. +Reads a file from the local filesystem. -- By default, it reads up to {{DEFAULT_MAX_LINES}} lines starting from the beginning of the file -- You can optionally specify a line offset and limit (especially handy for long files), but it's recommended to read the whole file by not providing these parameters -- Any lines longer than 500 characters will be truncated -- By default, results omit line numbers. Use `lines: true` to include them -- This tool allows Claude Code to read images (eg PNG, JPG, etc). When reading an image file the contents are presented visually as Claude Code is a multimodal LLM. -- This tool can read PDF files (.pdf). PDFs are processed page by page, extracting both text and visual content for analysis. -- This tool can read Jupyter notebooks (.ipynb files) and returns all cells with their outputs, combining code, text, and visualizations. -- This tool can only read files, not directories. To read a directory, use the ls tool. -- You can call multiple tools in a single response. It is always better to speculatively read multiple potentially useful files in parallel. -- You will regularly be asked to read screenshots. If the user provides a path to a screenshot, ALWAYS use this tool to view the file at the path. This tool will work with all temporary file paths. -- If you read a file that exists but has empty contents you will receive a system reminder warning in place of file contents. +- Reads up to {{DEFAULT_MAX_LINES}} lines by default +- Use `offset` and `limit` for large files +- Use `lines: true` to include line numbers +- Supports images (PNG, JPG), PDFs, and Jupyter notebooks +- For directories, use the ls tool instead +- Parallelize reads when exploring related files -- Empty files trigger a warning -- Directory paths return an ls-style listing -- Missing files return an error with closest matches (gitignore respected) - - - -- Parallelize reads when exploring related files - Read before editing (required in current session) -- Trust user-provided paths; attempt the read -- Screenshots: Read tool renders images visually -- Skip re-reading after edits (Edit/Write report errors) - +- Empty files trigger a warning +- Missing files return closest matches + diff --git a/packages/coding-agent/src/prompts/tools/replace.md b/packages/coding-agent/src/prompts/tools/replace.md index 61b0d801b..0dc5bdba1 100644 --- a/packages/coding-agent/src/prompts/tools/replace.md +++ b/packages/coding-agent/src/prompts/tools/replace.md @@ -3,14 +3,11 @@ Performs string replacements in files with fuzzy whitespace matching. -- Use the smallest edit that uniquely identifies the change. To toggle a checkbox: `- [ ] Task` → `- [x] Task`, not the entire line. -- If the old text is not unique, expand the replacement to a larger block (function/class/section) so it is unique. +- Use the smallest edit that uniquely identifies the change +- If `oldText` is not unique, expand to include more context or use `all: true` to replace all occurrences - You must use your read tool at least once in the conversation before editing. This tool will error if you attempt an edit without reading the file. -- Fuzzy matching handles minor whitespace/indentation differences automatically - you don't need to match indentation exactly. -- ALWAYS prefer editing existing files in the codebase. NEVER write new files unless explicitly required. -- Only use emojis if the user explicitly requests it. Avoid adding emojis to files unless asked. -- The edit will FAIL if old_string is not unique in the file. Either provide a larger string with more surrounding context to make it unique or use replace_all to change every instance of old_string. -- Use replace_all for replacing and renaming strings across the file. This parameter is useful if you want to rename a variable for instance. +- Fuzzy matching handles minor whitespace/indentation differences automatically +- Prefer editing existing files over creating new ones diff --git a/packages/coding-agent/src/prompts/tools/task.md b/packages/coding-agent/src/prompts/tools/task.md index 9fc57cc1a..fd0a53d90 100644 --- a/packages/coding-agent/src/prompts/tools/task.md +++ b/packages/coding-agent/src/prompts/tools/task.md @@ -53,10 +53,9 @@ Agents with `output="structured"` have a fixed schema enforced via frontmatter; - `agent`: Agent type to use for all tasks - `context`: Template with `{{placeholders}}` for multi-task. Each placeholder is filled from task vars. -- `model`: (optional) Model override for all tasks (fuzzy matching, e.g., "sonnet", "opus") - `isolated`: (optional) Run each task in its own git worktree and return patches; patches are applied only if all apply cleanly. -- `tasks`: Array of `{id, description, vars}` - tasks to run in parallel (max {{MAX_PARALLEL_TASKS}}, {{MAX_CONCURRENCY}} concurrent) - - `id`: Short CamelCase identifier for display (max 20 chars, e.g., "SessionStore", "LspRefactor") +- `tasks`: Array of `{id, description, vars}` - tasks to run in parallel + - `id`: Short CamelCase identifier (max 32 chars, e.g., "SessionStore", "LspRefactor") - `description`: Short human-readable description of what the task does - `vars`: Object with keys matching `{{placeholders}}` in context - `output`: (optional) JTD schema for structured subagent output (used by the complete tool)