tools.ts 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401
  1. import { Anthropic } from "@anthropic-ai/sdk"
  2. import type {
  3. ClineAsk,
  4. ToolProgressStatus,
  5. ToolGroup,
  6. ToolName,
  7. BrowserActionParams,
  8. GenerateImageParams,
  9. } from "@roo-code/types"
  10. export type ToolResponse = string | Array<Anthropic.TextBlockParam | Anthropic.ImageBlockParam>
  11. export type AskApproval = (
  12. type: ClineAsk,
  13. partialMessage?: string,
  14. progressStatus?: ToolProgressStatus,
  15. forceApproval?: boolean,
  16. ) => Promise<boolean>
  17. export type HandleError = (action: string, error: Error) => Promise<void>
  18. export type PushToolResult = (content: ToolResponse) => void
  19. export type AskFinishSubTaskApproval = () => Promise<boolean>
  20. export interface TextContent {
  21. type: "text"
  22. content: string
  23. partial: boolean
  24. }
  25. export const toolParamNames = [
  26. "command",
  27. "path",
  28. "content",
  29. "regex",
  30. "file_pattern",
  31. "recursive",
  32. "action",
  33. "url",
  34. "coordinate",
  35. "text",
  36. "server_name",
  37. "tool_name",
  38. "arguments",
  39. "uri",
  40. "question",
  41. "result",
  42. "diff",
  43. "mode_slug",
  44. "reason",
  45. "line",
  46. "mode",
  47. "message",
  48. "cwd",
  49. "follow_up",
  50. "task",
  51. "size",
  52. "query",
  53. "args",
  54. "skill", // skill tool parameter
  55. "start_line",
  56. "end_line",
  57. "todos",
  58. "prompt",
  59. "image",
  60. // read_file parameters (native protocol)
  61. "operations", // search_and_replace parameter for multiple operations
  62. "patch", // apply_patch parameter
  63. "file_path", // search_replace and edit_file parameter
  64. "old_string", // search_replace and edit_file parameter
  65. "new_string", // search_replace and edit_file parameter
  66. "replace_all", // edit tool parameter for replacing all occurrences
  67. "expected_replacements", // edit_file parameter for multiple occurrences
  68. "artifact_id", // read_command_output parameter
  69. "search", // read_command_output parameter for grep-like search
  70. "offset", // read_command_output and read_file parameter
  71. "limit", // read_command_output and read_file parameter
  72. // read_file indentation mode parameters
  73. "indentation",
  74. "anchor_line",
  75. "max_levels",
  76. "include_siblings",
  77. "include_header",
  78. "max_lines",
  79. // read_file legacy format parameter (backward compatibility)
  80. "files",
  81. "line_ranges",
  82. ] as const
  83. export type ToolParamName = (typeof toolParamNames)[number]
  84. /**
  85. * Type map defining the native (typed) argument structure for each tool.
  86. * Tools not listed here will fall back to `any` for backward compatibility.
  87. */
  88. export type NativeToolArgs = {
  89. access_mcp_resource: { server_name: string; uri: string }
  90. read_file: import("@roo-code/types").ReadFileToolParams
  91. read_command_output: { artifact_id: string; search?: string; offset?: number; limit?: number }
  92. attempt_completion: { result: string }
  93. execute_command: { command: string; cwd?: string }
  94. apply_diff: { path: string; diff: string }
  95. edit: { file_path: string; old_string: string; new_string: string; replace_all?: boolean }
  96. search_and_replace: { file_path: string; old_string: string; new_string: string; replace_all?: boolean }
  97. search_replace: { file_path: string; old_string: string; new_string: string }
  98. edit_file: { file_path: string; old_string: string; new_string: string; expected_replacements?: number }
  99. apply_patch: { patch: string }
  100. list_files: { path: string; recursive?: boolean }
  101. new_task: { mode: string; message: string; todos?: string }
  102. ask_followup_question: {
  103. question: string
  104. follow_up: Array<{ text: string; mode?: string }>
  105. }
  106. browser_action: BrowserActionParams
  107. codebase_search: { query: string; path?: string }
  108. generate_image: GenerateImageParams
  109. run_slash_command: { command: string; args?: string }
  110. skill: { skill: string; args?: string }
  111. search_files: { path: string; regex: string; file_pattern?: string | null }
  112. switch_mode: { mode_slug: string; reason: string }
  113. update_todo_list: { todos: string }
  114. use_mcp_tool: { server_name: string; tool_name: string; arguments?: Record<string, unknown> }
  115. write_to_file: { path: string; content: string }
  116. // Add more tools as they are migrated to native protocol
  117. }
  118. /**
  119. * Generic ToolUse interface that provides proper typing for both protocols.
  120. *
  121. * @template TName - The specific tool name, which determines the nativeArgs type
  122. */
  123. export interface ToolUse<TName extends ToolName = ToolName> {
  124. type: "tool_use"
  125. id?: string // Optional ID to track tool calls
  126. name: TName
  127. /**
  128. * The original tool name as called by the model (e.g. an alias like "edit_file"),
  129. * if it differs from the canonical tool name used for execution.
  130. * Used to preserve tool names in API conversation history.
  131. */
  132. originalName?: string
  133. // params is a partial record, allowing only some or none of the possible parameters to be used
  134. params: Partial<Record<ToolParamName, string>>
  135. partial: boolean
  136. // nativeArgs is properly typed based on TName if it's in NativeToolArgs, otherwise never
  137. nativeArgs?: TName extends keyof NativeToolArgs ? NativeToolArgs[TName] : never
  138. /**
  139. * Flag indicating whether the tool call used a legacy/deprecated format.
  140. * Used for telemetry tracking to monitor migration from old formats.
  141. */
  142. usedLegacyFormat?: boolean
  143. }
  144. /**
  145. * Represents a native MCP tool call from the model.
  146. * In native mode, MCP tools are called directly with their prefixed name (e.g., "mcp_serverName_toolName")
  147. * rather than through the use_mcp_tool wrapper. This type preserves the original tool name
  148. * so it appears correctly in API conversation history.
  149. */
  150. export interface McpToolUse {
  151. type: "mcp_tool_use"
  152. id?: string // Tool call ID from the API
  153. /** The original tool name from the API (e.g., "mcp_serverName_toolName") */
  154. name: string
  155. /** Extracted server name from the tool name */
  156. serverName: string
  157. /** Extracted tool name from the tool name */
  158. toolName: string
  159. /** Arguments passed to the MCP tool */
  160. arguments: Record<string, unknown>
  161. partial: boolean
  162. }
  163. export interface ExecuteCommandToolUse extends ToolUse<"execute_command"> {
  164. name: "execute_command"
  165. // Pick<Record<ToolParamName, string>, "command"> makes "command" required, but Partial<> makes it optional
  166. params: Partial<Pick<Record<ToolParamName, string>, "command" | "cwd">>
  167. }
  168. export interface ReadFileToolUse extends ToolUse<"read_file"> {
  169. name: "read_file"
  170. params: Partial<
  171. Pick<
  172. Record<ToolParamName, string>,
  173. | "args"
  174. | "path"
  175. | "start_line"
  176. | "end_line"
  177. | "mode"
  178. | "offset"
  179. | "limit"
  180. | "indentation"
  181. | "anchor_line"
  182. | "max_levels"
  183. | "include_siblings"
  184. | "include_header"
  185. >
  186. >
  187. }
  188. export interface WriteToFileToolUse extends ToolUse<"write_to_file"> {
  189. name: "write_to_file"
  190. params: Partial<Pick<Record<ToolParamName, string>, "path" | "content">>
  191. }
  192. export interface CodebaseSearchToolUse extends ToolUse<"codebase_search"> {
  193. name: "codebase_search"
  194. params: Partial<Pick<Record<ToolParamName, string>, "query" | "path">>
  195. }
  196. export interface SearchFilesToolUse extends ToolUse<"search_files"> {
  197. name: "search_files"
  198. params: Partial<Pick<Record<ToolParamName, string>, "path" | "regex" | "file_pattern">>
  199. }
  200. export interface ListFilesToolUse extends ToolUse<"list_files"> {
  201. name: "list_files"
  202. params: Partial<Pick<Record<ToolParamName, string>, "path" | "recursive">>
  203. }
  204. export interface BrowserActionToolUse extends ToolUse<"browser_action"> {
  205. name: "browser_action"
  206. params: Partial<Pick<Record<ToolParamName, string>, "action" | "url" | "coordinate" | "text" | "size" | "path">>
  207. }
  208. export interface UseMcpToolToolUse extends ToolUse<"use_mcp_tool"> {
  209. name: "use_mcp_tool"
  210. params: Partial<Pick<Record<ToolParamName, string>, "server_name" | "tool_name" | "arguments">>
  211. }
  212. export interface AccessMcpResourceToolUse extends ToolUse<"access_mcp_resource"> {
  213. name: "access_mcp_resource"
  214. params: Partial<Pick<Record<ToolParamName, string>, "server_name" | "uri">>
  215. }
  216. export interface AskFollowupQuestionToolUse extends ToolUse<"ask_followup_question"> {
  217. name: "ask_followup_question"
  218. params: Partial<Pick<Record<ToolParamName, string>, "question" | "follow_up">>
  219. }
  220. export interface AttemptCompletionToolUse extends ToolUse<"attempt_completion"> {
  221. name: "attempt_completion"
  222. params: Partial<Pick<Record<ToolParamName, string>, "result">>
  223. }
  224. export interface SwitchModeToolUse extends ToolUse<"switch_mode"> {
  225. name: "switch_mode"
  226. params: Partial<Pick<Record<ToolParamName, string>, "mode_slug" | "reason">>
  227. }
  228. export interface NewTaskToolUse extends ToolUse<"new_task"> {
  229. name: "new_task"
  230. params: Partial<Pick<Record<ToolParamName, string>, "mode" | "message" | "todos">>
  231. }
  232. export interface RunSlashCommandToolUse extends ToolUse<"run_slash_command"> {
  233. name: "run_slash_command"
  234. params: Partial<Pick<Record<ToolParamName, string>, "command" | "args">>
  235. }
  236. export interface SkillToolUse extends ToolUse<"skill"> {
  237. name: "skill"
  238. params: Partial<Pick<Record<ToolParamName, string>, "skill" | "args">>
  239. }
  240. export interface GenerateImageToolUse extends ToolUse<"generate_image"> {
  241. name: "generate_image"
  242. params: Partial<Pick<Record<ToolParamName, string>, "prompt" | "path" | "image">>
  243. }
  244. // Define tool group configuration
  245. export type ToolGroupConfig = {
  246. tools: readonly string[]
  247. alwaysAvailable?: boolean // Whether this group is always available and shouldn't show in prompts view
  248. customTools?: readonly string[] // Opt-in only tools - only available when explicitly included via model's includedTools
  249. }
  250. export const TOOL_DISPLAY_NAMES: Record<ToolName, string> = {
  251. execute_command: "run commands",
  252. read_file: "read files",
  253. read_command_output: "read command output",
  254. write_to_file: "write files",
  255. apply_diff: "apply changes",
  256. edit: "edit files",
  257. search_and_replace: "apply changes using search and replace",
  258. search_replace: "apply single search and replace",
  259. edit_file: "edit files using search and replace",
  260. apply_patch: "apply patches using codex format",
  261. search_files: "search files",
  262. list_files: "list files",
  263. browser_action: "use a browser",
  264. use_mcp_tool: "use mcp tools",
  265. access_mcp_resource: "access mcp resources",
  266. ask_followup_question: "ask questions",
  267. attempt_completion: "complete tasks",
  268. switch_mode: "switch modes",
  269. new_task: "create new task",
  270. codebase_search: "codebase search",
  271. update_todo_list: "update todo list",
  272. run_slash_command: "run slash command",
  273. skill: "load skill",
  274. generate_image: "generate images",
  275. custom_tool: "use custom tools",
  276. } as const
  277. // Define available tool groups.
  278. export const TOOL_GROUPS: Record<ToolGroup, ToolGroupConfig> = {
  279. read: {
  280. tools: ["read_file", "search_files", "list_files", "codebase_search"],
  281. },
  282. edit: {
  283. tools: ["apply_diff", "write_to_file", "generate_image"],
  284. customTools: ["edit", "search_replace", "edit_file", "apply_patch"],
  285. },
  286. browser: {
  287. tools: ["browser_action"],
  288. },
  289. command: {
  290. tools: ["execute_command", "read_command_output"],
  291. },
  292. mcp: {
  293. tools: ["use_mcp_tool", "access_mcp_resource"],
  294. },
  295. modes: {
  296. tools: ["switch_mode", "new_task"],
  297. alwaysAvailable: true,
  298. },
  299. }
  300. // Tools that are always available to all modes.
  301. export const ALWAYS_AVAILABLE_TOOLS: ToolName[] = [
  302. "ask_followup_question",
  303. "attempt_completion",
  304. "switch_mode",
  305. "new_task",
  306. "update_todo_list",
  307. "run_slash_command",
  308. "skill",
  309. ] as const
  310. /**
  311. * Central registry of tool aliases.
  312. * Maps alias name -> canonical tool name.
  313. *
  314. * This allows models to use alternative names for tools (e.g., "edit_file" instead of "apply_diff").
  315. * When a model calls a tool by its alias, the system resolves it to the canonical name for execution,
  316. * but preserves the alias in API conversation history for consistency.
  317. *
  318. * To add a new alias, simply add an entry here. No other files need to be modified.
  319. */
  320. export const TOOL_ALIASES: Record<string, ToolName> = {
  321. write_file: "write_to_file",
  322. search_and_replace: "edit",
  323. } as const
  324. export type DiffResult =
  325. | { success: true; content: string; failParts?: DiffResult[] }
  326. | ({
  327. success: false
  328. error?: string
  329. details?: {
  330. similarity?: number
  331. threshold?: number
  332. matchedRange?: { start: number; end: number }
  333. searchContent?: string
  334. bestMatch?: string
  335. }
  336. failParts?: DiffResult[]
  337. } & ({ error: string } | { failParts: DiffResult[] }))
  338. export interface DiffItem {
  339. content: string
  340. startLine?: number
  341. }
  342. export interface DiffStrategy {
  343. /**
  344. * Get the name of this diff strategy for analytics and debugging
  345. * @returns The name of the diff strategy
  346. */
  347. getName(): string
  348. /**
  349. * Apply a diff to the original content
  350. * @param originalContent The original file content
  351. * @param diffContent The diff content in the strategy's format (string for legacy, DiffItem[] for new)
  352. * @param startLine Optional line number where the search block starts. If not provided, searches the entire file.
  353. * @param endLine Optional line number where the search block ends. If not provided, searches the entire file.
  354. * @returns A DiffResult object containing either the successful result or error details
  355. */
  356. applyDiff(
  357. originalContent: string,
  358. diffContent: string | DiffItem[],
  359. startLine?: number,
  360. endLine?: number,
  361. ): Promise<DiffResult>
  362. getProgressStatus?(toolUse: ToolUse, result?: any): ToolProgressStatus
  363. }