1use super::*;
4
5impl BuiltinTools {
6 pub fn tool_defs(&self) -> Vec<Tool> {
9 let mut defs = vec![
10 Tool {
11 name: "read_file".to_string(),
12 description: "Read the complete contents of a file. Use this to examine existing code, configurations, or data files before making changes.".to_string(),
13 parameters: json!({
14 "type": "object",
15 "properties": {
16 "path": {
17 "type": "string",
18 "description": "Path to the file, relative to the working directory"
19 }
20 },
21 "required": ["path"]
22 }),
23 },
24 Tool {
25 name: "write_file".to_string(),
26 description: "Write content to a file, creating it (and any parent directories) if necessary. Use this to create new files or completely replace existing file content.".to_string(),
27 parameters: json!({
28 "type": "object",
29 "properties": {
30 "path": {
31 "type": "string",
32 "description": "Path to the file, relative to the working directory"
33 },
34 "content": {
35 "type": "string",
36 "description": "The full content to write to the file"
37 }
38 },
39 "required": ["path", "content"]
40 }),
41 },
42 Tool {
43 name: "edit_file".to_string(),
44 description: "Replace an exact string in an existing file. The old_str must appear exactly once in the file. Use this for targeted edits rather than rewriting entire files.".to_string(),
45 parameters: json!({
46 "type": "object",
47 "properties": {
48 "path": {
49 "type": "string",
50 "description": "Path to the file, relative to the working directory"
51 },
52 "old_str": {
53 "type": "string",
54 "description": "The exact string to replace. Must appear exactly once in the file."
55 },
56 "new_str": {
57 "type": "string",
58 "description": "The string to replace old_str with"
59 }
60 },
61 "required": ["path", "old_str", "new_str"]
62 }),
63 },
64 Tool {
65 name: "list_dir".to_string(),
66 description: "List the contents of a directory. Use this to explore the file structure before reading or writing files.".to_string(),
67 parameters: json!({
68 "type": "object",
69 "properties": {
70 "path": {
71 "type": "string",
72 "description": "Path to the directory, relative to the working directory. Defaults to the working directory root if omitted."
73 }
74 },
75 "required": []
76 }),
77 },
78 Tool {
79 name: "read_files".to_string(),
80 description: "Read multiple files at once. Returns the contents of all requested files in a single response, separated by file path headers. More efficient than calling read_file repeatedly. Use this when you need to read several files (e.g. after list_dir).".to_string(),
81 parameters: json!({
82 "type": "object",
83 "properties": {
84 "paths": {
85 "type": "array",
86 "items": { "type": "string" },
87 "description": "Array of file paths relative to the working directory"
88 }
89 },
90 "required": ["paths"]
91 }),
92 },
93 Tool {
94 name: "shell".to_string(),
95 description: "Execute a shell command in the working directory. Uses the system shell (bash/zsh on Unix, cmd on Windows). Use this for build commands, running tests, installing dependencies, or other shell operations. Has a 60-second timeout.".to_string(),
96 parameters: json!({
97 "type": "object",
98 "properties": {
99 "command": {
100 "type": "string",
101 "description": "The shell command to execute"
102 }
103 },
104 "required": ["command"]
105 }),
106 },
107 Tool {
108 name: "present_for_review".to_string(),
109 description: "Present a document, plan, or report to the user for review. The agent run will pause and the dashboard will display the document prominently. Use this when you want the user to read and approve something before you continue - for example, a technical design, an implementation plan, or a summary report. The user can provide feedback or simply acknowledge to continue.".to_string(),
110 parameters: json!({
111 "type": "object",
112 "properties": {
113 "title": {
114 "type": "string",
115 "description": "Short title for the review prompt shown to the user (e.g. 'Implementation Plan Ready for Review')"
116 },
117 "markdown": {
118 "type": "string",
119 "description": "The markdown document to present to the user. Supports headings, lists, code blocks, and mermaid diagrams."
120 }
121 },
122 "required": ["title", "markdown"]
123 }),
124 },
125 Tool {
126 name: "ask_user_text".to_string(),
127 description: "Ask the user a free-form question and wait for their written answer. The run pauses until they respond. Use this when you need clarification, missing information, or a specific detail only the user knows - decide for yourself when this is necessary; don't ask about things you can figure out on your own.".to_string(),
128 parameters: json!({
129 "type": "object",
130 "properties": {
131 "prompt": {
132 "type": "string",
133 "description": "The question to ask the user"
134 }
135 },
136 "required": ["prompt"]
137 }),
138 },
139 Tool {
140 name: "ask_user_choice".to_string(),
141 description: "Ask the user to pick one option from a list and wait for their answer. The run pauses until they respond. Use this when you have a small number of distinct paths forward and want the user to decide which one, rather than guessing yourself.".to_string(),
142 parameters: json!({
143 "type": "object",
144 "properties": {
145 "prompt": {
146 "type": "string",
147 "description": "The question to ask the user"
148 },
149 "options": {
150 "type": "array",
151 "items": { "type": "string" },
152 "description": "At least two options for the user to choose from"
153 }
154 },
155 "required": ["prompt", "options"]
156 }),
157 },
158 Tool {
159 name: "ask_user_confirm".to_string(),
160 description: "Ask the user a yes/no question and wait for their answer. The run pauses until they respond. Use this for a quick go/no-go decision before doing something significant or hard to undo.".to_string(),
161 parameters: json!({
162 "type": "object",
163 "properties": {
164 "prompt": {
165 "type": "string",
166 "description": "The yes/no question to ask the user"
167 }
168 },
169 "required": ["prompt"]
170 }),
171 },
172 Tool {
173 name: "edit_document".to_string(),
174 description: "Present a document to the user in an editable field pre-filled with its current text, and wait for them to edit it directly. The run pauses until they submit. Use this when the user wants to modify content themselves (e.g. tweak a plan or draft) rather than describe changes for you to make. Pass the current full text as `content`; the returned text is the user's edited version, which you should adopt as authoritative.".to_string(),
175 parameters: json!({
176 "type": "object",
177 "properties": {
178 "content": {
179 "type": "string",
180 "description": "The current full document text to present for editing"
181 },
182 "prompt": {
183 "type": "string",
184 "description": "Optional instruction shown above the editable field"
185 }
186 },
187 "required": ["content"]
188 }),
189 },
190 Tool {
191 name: "context_write".to_string(),
192 description: "Store or update content in a named section of your context window. This content will be included in your system prompt on subsequent turns, making it available for reference. Use this to save analysis, plans, notes, or structured information. If a key is provided and an entry with that key already exists, it will be replaced with the new content.".to_string(),
193 parameters: json!({
194 "type": "object",
195 "properties": {
196 "region": {
197 "type": "string",
198 "description": "Name of the context window section (e.g. 'architecture', 'plan')"
199 },
200 "key": {
201 "type": "string",
202 "description": "Key for the entry. Replaces existing entry with the same key."
203 },
204 "content": {
205 "type": "string",
206 "description": "Content to store"
207 }
208 },
209 "required": ["region", "content"]
210 }),
211 },
212 Tool {
213 name: "context_append".to_string(),
214 description: "Add content to an existing section of your context window without replacing what's already there.".to_string(),
215 parameters: json!({
216 "type": "object",
217 "properties": {
218 "region": {
219 "type": "string",
220 "description": "Name of the context window section"
221 },
222 "key": {
223 "type": "string",
224 "description": "Key for the entry"
225 },
226 "content": {
227 "type": "string",
228 "description": "Content to append"
229 }
230 },
231 "required": ["region", "content"]
232 }),
233 },
234 Tool {
235 name: "context_read".to_string(),
236 description: "Read what's currently stored in a section of your context window. If no key is specified and the section contains keyed entries, returns a summary of all keys and their sizes.".to_string(),
237 parameters: json!({
238 "type": "object",
239 "properties": {
240 "region": {
241 "type": "string",
242 "description": "Name of the context window section to read"
243 },
244 "key": {
245 "type": "string",
246 "description": "Key of a specific entry to read"
247 }
248 },
249 "required": ["region"]
250 }),
251 },
252 Tool {
253 name: "context_delete".to_string(),
254 description: "Remove a specific keyed entry from a section of your context window.".to_string(),
255 parameters: json!({
256 "type": "object",
257 "properties": {
258 "region": {
259 "type": "string",
260 "description": "Name of the context window section"
261 },
262 "key": {
263 "type": "string",
264 "description": "Key of the entry to remove"
265 }
266 },
267 "required": ["region", "key"]
268 }),
269 },
270 Tool {
271 name: "context_list".to_string(),
272 description: "List available sections of your context window with their current usage - section names, token counts, and number of entries. Use this to see what's available and what you've already stored.".to_string(),
273 parameters: json!({
274 "type": "object",
275 "properties": {
276 "region": {
277 "type": "string",
278 "description": "Optional region name to list keys for"
279 }
280 },
281 "required": []
282 }),
283 },
284 ];
285 defs.retain(|t| self.available(&t.name));
286 defs
287 }
288
289 pub fn subagent_tool_defs() -> Vec<Tool> {
294 vec![
295 Tool {
296 name: "spawn_agent".to_string(),
297 description: "Spawn a sub-agent from a blueprint to work on a task. Returns the new agent's ID. If wait=true, blocks until the sub-agent completes and returns its result.".to_string(),
298 parameters: json!({
299 "type": "object",
300 "properties": {
301 "blueprint": {
302 "type": "string",
303 "description": "Name of the agent blueprint to spawn"
304 },
305 "task": {
306 "type": "string",
307 "description": "Task prompt for the sub-agent"
308 },
309 "wait": {
310 "type": "boolean",
311 "description": "If true, block until the sub-agent completes and return its result. Default: false",
312 "default": false
313 },
314 "seed_context": {
315 "type": "string",
316 "description": "Optional initial context to inject into the sub-agent's first Pinned region"
317 },
318 "max_child_depth": {
319 "type": "integer",
320 "description": "Optional max depth for the sub-agent's own children"
321 }
322 },
323 "required": ["blueprint", "task"]
324 }),
325 },
326 Tool {
327 name: "check_agent".to_string(),
328 description: "Check the status of a sub-agent. Returns its current status and result if complete. Non-blocking.".to_string(),
329 parameters: json!({
330 "type": "object",
331 "properties": {
332 "agent_id": {
333 "type": "string",
334 "description": "ID of the agent to check"
335 }
336 },
337 "required": ["agent_id"]
338 }),
339 },
340 Tool {
341 name: "wait_for_agent".to_string(),
342 description: "Block until a sub-agent completes, then return its final result.".to_string(),
343 parameters: json!({
344 "type": "object",
345 "properties": {
346 "agent_id": {
347 "type": "string",
348 "description": "ID of the agent to wait for"
349 }
350 },
351 "required": ["agent_id"]
352 }),
353 },
354 Tool {
355 name: "send_to_agent".to_string(),
356 description: "Send a message to a running sub-agent's context window.".to_string(),
357 parameters: json!({
358 "type": "object",
359 "properties": {
360 "agent_id": {
361 "type": "string",
362 "description": "ID of the target agent"
363 },
364 "message": {
365 "type": "string",
366 "description": "Message content to send"
367 },
368 "target_region": {
369 "type": "string",
370 "description": "Context region to deliver to (default: conversation)"
371 }
372 },
373 "required": ["agent_id", "message"]
374 }),
375 },
376 Tool {
377 name: "kill_agent".to_string(),
378 description: "Kill a sub-agent and all its descendants. Sets their cancellation tokens and marks them as cancelled.".to_string(),
379 parameters: json!({
380 "type": "object",
381 "properties": {
382 "agent_id": {
383 "type": "string",
384 "description": "ID of the agent to kill"
385 }
386 },
387 "required": ["agent_id"]
388 }),
389 },
390 ]
391 }
392
393 pub fn subagent_tool_names() -> Vec<String> {
395 vec![
396 "spawn_agent".to_string(),
397 "check_agent".to_string(),
398 "wait_for_agent".to_string(),
399 "send_to_agent".to_string(),
400 "kill_agent".to_string(),
401 ]
402 }
403
404 pub fn names(&self) -> Vec<String> {
410 let mut names: Vec<String> = [
411 "read_file",
412 "read_files",
413 "write_file",
414 "edit_file",
415 "list_dir",
416 "shell",
417 "present_for_review",
418 "ask_user_text",
419 "ask_user_choice",
420 "ask_user_confirm",
421 "edit_document",
422 "context_write",
423 "context_append",
424 "context_read",
425 "context_delete",
426 "context_list",
427 ]
428 .iter()
429 .filter(|n| self.available(n))
433 .map(|s| s.to_string())
434 .collect();
435 names.extend(
438 TOOL_ALIASES
439 .iter()
440 .filter(|(_, canonical)| self.available(canonical))
441 .map(|(alias, _)| alias.to_string()),
442 );
443 names
444 }
445}