mirror of
https://github.com/RooVetGit/Roo-Code.git
synced 2026-08-28 05:27:24 +00:00
Adds subtask queue support to the new_task tool, allowing the orchestrator to define multiple subtasks that execute automatically in sequence without returning to the parent between each one. This saves LLM API calls and enables more efficient multi-agent workflows. Key changes: - SubtaskQueueItem, SubtaskResult types in packages/types/src/history.ts - task_queue parameter on new_task tool (optional JSON array) - NewTaskTool parses and validates queued subtasks, stores on parent - delegateParentAndOpenChild persists queue in parent HistoryItem - reopenParentFromDelegation auto-advances queue via advanceSubtaskQueue - formatAggregatedQueueResults aggregates all results when queue completes - 9 new tests covering queue advance, exhaustion, and result formatting - All 56 existing delegation tests continue to pass
386 lines
12 KiB
TypeScript
386 lines
12 KiB
TypeScript
import { Anthropic } from "@anthropic-ai/sdk"
|
|
|
|
import type { ClineAsk, ToolProgressStatus, ToolGroup, ToolName, GenerateImageParams } from "@roo-code/types"
|
|
|
|
export type ToolResponse = string | Array<Anthropic.TextBlockParam | Anthropic.ImageBlockParam>
|
|
|
|
export type AskApproval = (
|
|
type: ClineAsk,
|
|
partialMessage?: string,
|
|
progressStatus?: ToolProgressStatus,
|
|
forceApproval?: boolean,
|
|
) => Promise<boolean>
|
|
|
|
export type HandleError = (action: string, error: Error) => Promise<void>
|
|
|
|
export type PushToolResult = (content: ToolResponse) => void
|
|
|
|
export type AskFinishSubTaskApproval = () => Promise<boolean>
|
|
|
|
export interface TextContent {
|
|
type: "text"
|
|
content: string
|
|
partial: boolean
|
|
}
|
|
|
|
export const toolParamNames = [
|
|
"command",
|
|
"path",
|
|
"content",
|
|
"regex",
|
|
"file_pattern",
|
|
"recursive",
|
|
"action",
|
|
"url",
|
|
"coordinate",
|
|
"text",
|
|
"server_name",
|
|
"tool_name",
|
|
"arguments",
|
|
"uri",
|
|
"question",
|
|
"result",
|
|
"diff",
|
|
"mode_slug",
|
|
"reason",
|
|
"line",
|
|
"mode",
|
|
"message",
|
|
"cwd",
|
|
"follow_up",
|
|
"task",
|
|
"size",
|
|
"query",
|
|
"args",
|
|
"skill", // skill tool parameter
|
|
"start_line",
|
|
"end_line",
|
|
"todos",
|
|
"task_queue",
|
|
"prompt",
|
|
"image",
|
|
// read_file parameters (native protocol)
|
|
"operations", // search_and_replace parameter for multiple operations
|
|
"patch", // apply_patch parameter
|
|
"file_path", // search_replace and edit_file parameter
|
|
"old_string", // search_replace and edit_file parameter
|
|
"new_string", // search_replace and edit_file parameter
|
|
"replace_all", // edit tool parameter for replacing all occurrences
|
|
"expected_replacements", // edit_file parameter for multiple occurrences
|
|
"timeout", // execute_command parameter
|
|
"artifact_id", // read_command_output parameter
|
|
"search", // read_command_output parameter for grep-like search
|
|
"offset", // read_command_output and read_file parameter
|
|
"limit", // read_command_output and read_file parameter
|
|
// read_file indentation mode parameters
|
|
"indentation",
|
|
"anchor_line",
|
|
"max_levels",
|
|
"include_siblings",
|
|
"include_header",
|
|
"max_lines",
|
|
// read_file legacy format parameter (backward compatibility)
|
|
"files",
|
|
"line_ranges",
|
|
] as const
|
|
|
|
export type ToolParamName = (typeof toolParamNames)[number]
|
|
|
|
/**
|
|
* Type map defining the native (typed) argument structure for each tool.
|
|
* Tools not listed here will fall back to `any` for backward compatibility.
|
|
*/
|
|
export type NativeToolArgs = {
|
|
access_mcp_resource: { server_name: string; uri: string }
|
|
read_file: import("@roo-code/types").ReadFileToolParams
|
|
read_command_output: { artifact_id: string; search?: string; offset?: number; limit?: number }
|
|
attempt_completion: { result: string }
|
|
execute_command: { command: string; cwd?: string; timeout?: number | null }
|
|
apply_diff: { path: string; diff: string }
|
|
edit: { file_path: string; old_string: string; new_string: string; replace_all?: boolean }
|
|
search_and_replace: { file_path: string; old_string: string; new_string: string; replace_all?: boolean }
|
|
search_replace: { file_path: string; old_string: string; new_string: string }
|
|
edit_file: { file_path: string; old_string: string; new_string: string; expected_replacements?: number }
|
|
apply_patch: { patch: string }
|
|
list_files: { path: string; recursive?: boolean }
|
|
new_task: { mode: string; message: string; todos?: string; task_queue?: string }
|
|
ask_followup_question: {
|
|
question: string
|
|
follow_up: Array<{ text: string; mode?: string }>
|
|
}
|
|
codebase_search: { query: string; path?: string }
|
|
generate_image: GenerateImageParams
|
|
run_slash_command: { command: string; args?: string }
|
|
skill: { skill: string; args?: string }
|
|
search_files: { path: string; regex: string; file_pattern?: string | null }
|
|
switch_mode: { mode_slug: string; reason: string }
|
|
update_todo_list: { todos: string }
|
|
use_mcp_tool: { server_name: string; tool_name: string; arguments?: Record<string, unknown> }
|
|
write_to_file: { path: string; content: string }
|
|
// Add more tools as they are migrated to native protocol
|
|
}
|
|
|
|
/**
|
|
* Generic ToolUse interface that provides proper typing for both protocols.
|
|
*
|
|
* @template TName - The specific tool name, which determines the nativeArgs type
|
|
*/
|
|
export interface ToolUse<TName extends ToolName = ToolName> {
|
|
type: "tool_use"
|
|
id?: string // Optional ID to track tool calls
|
|
name: TName
|
|
/**
|
|
* The original tool name as called by the model (e.g. an alias like "edit_file"),
|
|
* if it differs from the canonical tool name used for execution.
|
|
* Used to preserve tool names in API conversation history.
|
|
*/
|
|
originalName?: string
|
|
// params is a partial record, allowing only some or none of the possible parameters to be used
|
|
params: Partial<Record<ToolParamName, string>>
|
|
partial: boolean
|
|
// nativeArgs is properly typed based on TName if it's in NativeToolArgs, otherwise never
|
|
nativeArgs?: TName extends keyof NativeToolArgs ? NativeToolArgs[TName] : never
|
|
/**
|
|
* Flag indicating whether the tool call used a legacy/deprecated format.
|
|
* Used to monitor migration from old formats.
|
|
*/
|
|
usedLegacyFormat?: boolean
|
|
}
|
|
|
|
/**
|
|
* Represents a native MCP tool call from the model.
|
|
* In native mode, MCP tools are called directly with their prefixed name (e.g., "mcp_serverName_toolName")
|
|
* rather than through the use_mcp_tool wrapper. This type preserves the original tool name
|
|
* so it appears correctly in API conversation history.
|
|
*/
|
|
export interface McpToolUse {
|
|
type: "mcp_tool_use"
|
|
id?: string // Tool call ID from the API
|
|
/** The original tool name from the API (e.g., "mcp_serverName_toolName") */
|
|
name: string
|
|
/** Extracted server name from the tool name */
|
|
serverName: string
|
|
/** Extracted tool name from the tool name */
|
|
toolName: string
|
|
/** Arguments passed to the MCP tool */
|
|
arguments: Record<string, unknown>
|
|
partial: boolean
|
|
}
|
|
|
|
export interface ExecuteCommandToolUse extends ToolUse<"execute_command"> {
|
|
name: "execute_command"
|
|
// Pick<Record<ToolParamName, string>, "command"> makes "command" required, but Partial<> makes it optional
|
|
params: Partial<Pick<Record<ToolParamName, string>, "command" | "cwd" | "timeout">>
|
|
}
|
|
|
|
export interface ReadFileToolUse extends ToolUse<"read_file"> {
|
|
name: "read_file"
|
|
params: Partial<
|
|
Pick<
|
|
Record<ToolParamName, string>,
|
|
| "args"
|
|
| "path"
|
|
| "start_line"
|
|
| "end_line"
|
|
| "mode"
|
|
| "offset"
|
|
| "limit"
|
|
| "indentation"
|
|
| "anchor_line"
|
|
| "max_levels"
|
|
| "include_siblings"
|
|
| "include_header"
|
|
>
|
|
>
|
|
}
|
|
|
|
export interface WriteToFileToolUse extends ToolUse<"write_to_file"> {
|
|
name: "write_to_file"
|
|
params: Partial<Pick<Record<ToolParamName, string>, "path" | "content">>
|
|
}
|
|
|
|
export interface CodebaseSearchToolUse extends ToolUse<"codebase_search"> {
|
|
name: "codebase_search"
|
|
params: Partial<Pick<Record<ToolParamName, string>, "query" | "path">>
|
|
}
|
|
|
|
export interface SearchFilesToolUse extends ToolUse<"search_files"> {
|
|
name: "search_files"
|
|
params: Partial<Pick<Record<ToolParamName, string>, "path" | "regex" | "file_pattern">>
|
|
}
|
|
|
|
export interface ListFilesToolUse extends ToolUse<"list_files"> {
|
|
name: "list_files"
|
|
params: Partial<Pick<Record<ToolParamName, string>, "path" | "recursive">>
|
|
}
|
|
|
|
export interface UseMcpToolToolUse extends ToolUse<"use_mcp_tool"> {
|
|
name: "use_mcp_tool"
|
|
params: Partial<Pick<Record<ToolParamName, string>, "server_name" | "tool_name" | "arguments">>
|
|
}
|
|
|
|
export interface AccessMcpResourceToolUse extends ToolUse<"access_mcp_resource"> {
|
|
name: "access_mcp_resource"
|
|
params: Partial<Pick<Record<ToolParamName, string>, "server_name" | "uri">>
|
|
}
|
|
|
|
export interface AskFollowupQuestionToolUse extends ToolUse<"ask_followup_question"> {
|
|
name: "ask_followup_question"
|
|
params: Partial<Pick<Record<ToolParamName, string>, "question" | "follow_up">>
|
|
}
|
|
|
|
export interface AttemptCompletionToolUse extends ToolUse<"attempt_completion"> {
|
|
name: "attempt_completion"
|
|
params: Partial<Pick<Record<ToolParamName, string>, "result">>
|
|
}
|
|
|
|
export interface SwitchModeToolUse extends ToolUse<"switch_mode"> {
|
|
name: "switch_mode"
|
|
params: Partial<Pick<Record<ToolParamName, string>, "mode_slug" | "reason">>
|
|
}
|
|
|
|
export interface NewTaskToolUse extends ToolUse<"new_task"> {
|
|
name: "new_task"
|
|
params: Partial<Pick<Record<ToolParamName, string>, "mode" | "message" | "todos" | "task_queue">>
|
|
}
|
|
|
|
export interface RunSlashCommandToolUse extends ToolUse<"run_slash_command"> {
|
|
name: "run_slash_command"
|
|
params: Partial<Pick<Record<ToolParamName, string>, "command" | "args">>
|
|
}
|
|
|
|
export interface SkillToolUse extends ToolUse<"skill"> {
|
|
name: "skill"
|
|
params: Partial<Pick<Record<ToolParamName, string>, "skill" | "args">>
|
|
}
|
|
|
|
export interface GenerateImageToolUse extends ToolUse<"generate_image"> {
|
|
name: "generate_image"
|
|
params: Partial<Pick<Record<ToolParamName, string>, "prompt" | "path" | "image">>
|
|
}
|
|
|
|
// Define tool group configuration
|
|
export type ToolGroupConfig = {
|
|
tools: readonly string[]
|
|
alwaysAvailable?: boolean // Whether this group is always available and shouldn't show in prompts view
|
|
customTools?: readonly string[] // Opt-in only tools - only available when explicitly included via model's includedTools
|
|
}
|
|
|
|
export const TOOL_DISPLAY_NAMES: Record<ToolName, string> = {
|
|
execute_command: "run commands",
|
|
read_file: "read files",
|
|
read_command_output: "read command output",
|
|
write_to_file: "write files",
|
|
apply_diff: "apply changes",
|
|
edit: "edit files",
|
|
search_and_replace: "apply changes using search and replace",
|
|
search_replace: "apply single search and replace",
|
|
edit_file: "edit files using search and replace",
|
|
apply_patch: "apply patches using codex format",
|
|
search_files: "search files",
|
|
list_files: "list files",
|
|
use_mcp_tool: "use mcp tools",
|
|
access_mcp_resource: "access mcp resources",
|
|
ask_followup_question: "ask questions",
|
|
attempt_completion: "complete tasks",
|
|
switch_mode: "switch modes",
|
|
new_task: "create new task",
|
|
codebase_search: "codebase search",
|
|
update_todo_list: "update todo list",
|
|
run_slash_command: "run slash command",
|
|
skill: "load skill",
|
|
generate_image: "generate images",
|
|
custom_tool: "use custom tools",
|
|
} as const
|
|
|
|
// Define available tool groups.
|
|
export const TOOL_GROUPS: Record<ToolGroup, ToolGroupConfig> = {
|
|
read: {
|
|
tools: ["read_file", "search_files", "list_files", "codebase_search"],
|
|
},
|
|
edit: {
|
|
tools: ["apply_diff", "write_to_file", "generate_image"],
|
|
customTools: ["edit", "search_replace", "edit_file", "apply_patch"],
|
|
},
|
|
command: {
|
|
tools: ["execute_command", "read_command_output"],
|
|
},
|
|
mcp: {
|
|
tools: ["use_mcp_tool", "access_mcp_resource"],
|
|
},
|
|
modes: {
|
|
tools: ["switch_mode", "new_task"],
|
|
alwaysAvailable: true,
|
|
},
|
|
}
|
|
|
|
// Tools that are always available to all modes.
|
|
export const ALWAYS_AVAILABLE_TOOLS: ToolName[] = [
|
|
"ask_followup_question",
|
|
"attempt_completion",
|
|
"switch_mode",
|
|
"new_task",
|
|
"update_todo_list",
|
|
"run_slash_command",
|
|
"skill",
|
|
] as const
|
|
|
|
/**
|
|
* Central registry of tool aliases.
|
|
* Maps alias name -> canonical tool name.
|
|
*
|
|
* This allows models to use alternative names for tools (e.g., "edit_file" instead of "apply_diff").
|
|
* When a model calls a tool by its alias, the system resolves it to the canonical name for execution,
|
|
* but preserves the alias in API conversation history for consistency.
|
|
*
|
|
* To add a new alias, simply add an entry here. No other files need to be modified.
|
|
*/
|
|
export const TOOL_ALIASES: Record<string, ToolName> = {
|
|
write_file: "write_to_file",
|
|
search_and_replace: "edit",
|
|
} as const
|
|
|
|
export type DiffResult =
|
|
| { success: true; content: string; failParts?: DiffResult[] }
|
|
| ({
|
|
success: false
|
|
error?: string
|
|
details?: {
|
|
similarity?: number
|
|
threshold?: number
|
|
matchedRange?: { start: number; end: number }
|
|
searchContent?: string
|
|
bestMatch?: string
|
|
}
|
|
failParts?: DiffResult[]
|
|
} & ({ error: string } | { failParts: DiffResult[] }))
|
|
|
|
export interface DiffItem {
|
|
content: string
|
|
startLine?: number
|
|
}
|
|
|
|
export interface DiffStrategy {
|
|
/**
|
|
* Get the name of this diff strategy for analytics and debugging
|
|
* @returns The name of the diff strategy
|
|
*/
|
|
getName(): string
|
|
|
|
/**
|
|
* Apply a diff to the original content
|
|
* @param originalContent The original file content
|
|
* @param diffContent The diff content in the strategy's format (string for legacy, DiffItem[] for new)
|
|
* @param startLine Optional line number where the search block starts. If not provided, searches the entire file.
|
|
* @param endLine Optional line number where the search block ends. If not provided, searches the entire file.
|
|
* @returns A DiffResult object containing either the successful result or error details
|
|
*/
|
|
applyDiff(
|
|
originalContent: string,
|
|
diffContent: string | DiffItem[],
|
|
startLine?: number,
|
|
endLine?: number,
|
|
): Promise<DiffResult>
|
|
|
|
getProgressStatus?(toolUse: ToolUse, result?: any): ToolProgressStatus
|
|
}
|