tools.ts 12 KB

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