feat(coding-agent): added nonAbortable option and isolated task execution
- Added nonAbortable option to AgentTool interface for ignoring abort signals during tool execution. - Added isolated option to task tool for running tasks in isolated git worktrees. - Simplified tool parameter descriptions across all coding-agent tools for better readability. - Updated find tool to always sort results by modification time and removed sortByMtime parameter. - Changed web-fetch timeout default from 20s to 45s maximum and updated bash prompt to use cwd parameter. - Removed model parameter from task and gemini-image tools to use session/provider defaults.
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -204,6 +204,8 @@ export interface AgentTool<TParameters extends TSchema = TSchema, TDetails = any
|
||||
label: string;
|
||||
/** If true, tool is excluded unless explicitly listed in --tools or agent's tools field */
|
||||
hidden?: boolean;
|
||||
/** If true, tool execution ignores abort signals (runs to completion) */
|
||||
nonAbortable?: boolean;
|
||||
execute: (
|
||||
toolCallId: string,
|
||||
params: Static<TParameters>,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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<typeof findSchema, FindToolDetails> {
|
||||
_onUpdate?: AgentToolUpdateCallback<FindToolDetails>,
|
||||
_context?: AgentToolContext,
|
||||
): Promise<AgentToolResult<FindToolDetails>> {
|
||||
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<typeof findSchema, FindToolDetails> {
|
||||
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<typeof findSchema, FindToolDetails> {
|
||||
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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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<typeof lspSchema>;
|
||||
|
||||
@@ -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 };
|
||||
|
||||
@@ -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<typeof pythonSchema>;
|
||||
|
||||
|
||||
@@ -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<typeof taskItemSchema>;
|
||||
|
||||
/** 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<typeof taskSchema>;
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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 = {
|
||||
|
||||
@@ -13,7 +13,7 @@ Do NOT use Bash for:
|
||||
</critical>
|
||||
|
||||
<instruction>
|
||||
- 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
|
||||
|
||||
@@ -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.
|
||||
|
||||
<instruction>
|
||||
- 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
|
||||
</instruction>
|
||||
|
||||
<important>
|
||||
- Empty files trigger a warning
|
||||
- Directory paths return an ls-style listing
|
||||
- Missing files return an error with closest matches (gitignore respected)
|
||||
</important>
|
||||
|
||||
<required>
|
||||
- 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)
|
||||
</required>
|
||||
- Empty files trigger a warning
|
||||
- Missing files return closest matches
|
||||
</important>
|
||||
|
||||
@@ -3,14 +3,11 @@
|
||||
Performs string replacements in files with fuzzy whitespace matching.
|
||||
|
||||
<instruction>
|
||||
- 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
|
||||
</instruction>
|
||||
|
||||
<bash_alternatives>
|
||||
|
||||
@@ -53,10 +53,9 @@ Agents with `output="structured"` have a fixed schema enforced via frontmatter;
|
||||
<parameters>
|
||||
- `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)
|
||||
|
||||
Reference in New Issue
Block a user