@travisennis/acai 0.0.5 → 0.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (311) hide show
  1. package/README.md +4 -2
  2. package/dist/agent/index.d.ts +119 -0
  3. package/dist/agent/index.d.ts.map +1 -0
  4. package/dist/agent/index.js +406 -0
  5. package/dist/agent/manual-loop.d.ts +41 -0
  6. package/dist/agent/manual-loop.d.ts.map +1 -0
  7. package/dist/agent/manual-loop.js +278 -0
  8. package/dist/cli.d.ts +2 -0
  9. package/dist/cli.d.ts.map +1 -1
  10. package/dist/cli.js +27 -33
  11. package/dist/commands/add-directory-command.d.ts +3 -0
  12. package/dist/commands/add-directory-command.d.ts.map +1 -0
  13. package/dist/commands/add-directory-command.js +85 -0
  14. package/dist/commands/application-log-command.d.ts.map +1 -1
  15. package/dist/commands/application-log-command.js +34 -0
  16. package/dist/commands/clear-command.d.ts.map +1 -1
  17. package/dist/commands/clear-command.js +8 -0
  18. package/dist/commands/compact-command.d.ts.map +1 -1
  19. package/dist/commands/compact-command.js +15 -2
  20. package/dist/commands/context-command.d.ts +3 -0
  21. package/dist/commands/context-command.d.ts.map +1 -0
  22. package/dist/commands/context-command.js +183 -0
  23. package/dist/commands/copy-command.d.ts.map +1 -1
  24. package/dist/commands/copy-command.js +28 -0
  25. package/dist/commands/edit-command.d.ts.map +1 -1
  26. package/dist/commands/edit-command.js +33 -0
  27. package/dist/commands/edit-prompt-command.d.ts.map +1 -1
  28. package/dist/commands/edit-prompt-command.js +28 -0
  29. package/dist/commands/exit-command.d.ts.map +1 -1
  30. package/dist/commands/exit-command.js +20 -0
  31. package/dist/commands/files-command.d.ts.map +1 -1
  32. package/dist/commands/files-command.js +57 -0
  33. package/dist/commands/generate-rules-command.d.ts.map +1 -1
  34. package/dist/commands/generate-rules-command.js +311 -1
  35. package/dist/commands/handoff-command.d.ts +3 -0
  36. package/dist/commands/handoff-command.d.ts.map +1 -0
  37. package/dist/commands/handoff-command.js +202 -0
  38. package/dist/commands/health-command.d.ts.map +1 -1
  39. package/dist/commands/health-command.js +119 -2
  40. package/dist/commands/help-command.d.ts.map +1 -1
  41. package/dist/commands/help-command.js +28 -0
  42. package/dist/commands/history-command.d.ts +3 -0
  43. package/dist/commands/history-command.d.ts.map +1 -0
  44. package/dist/commands/history-command.js +534 -0
  45. package/dist/commands/init-command.d.ts +1 -1
  46. package/dist/commands/init-command.d.ts.map +1 -1
  47. package/dist/commands/init-command.js +55 -18
  48. package/dist/commands/last-log-command.d.ts.map +1 -1
  49. package/dist/commands/last-log-command.js +27 -0
  50. package/dist/commands/list-directories-command.d.ts +3 -0
  51. package/dist/commands/list-directories-command.d.ts.map +1 -0
  52. package/dist/commands/list-directories-command.js +48 -0
  53. package/dist/commands/list-tools-command.d.ts.map +1 -1
  54. package/dist/commands/list-tools-command.js +66 -3
  55. package/dist/commands/manager.d.ts +15 -3
  56. package/dist/commands/manager.d.ts.map +1 -1
  57. package/dist/commands/manager.js +86 -26
  58. package/dist/commands/model-command.d.ts +22 -0
  59. package/dist/commands/model-command.d.ts.map +1 -1
  60. package/dist/commands/model-command.js +256 -0
  61. package/dist/commands/paste-command.d.ts.map +1 -1
  62. package/dist/commands/paste-command.js +92 -0
  63. package/dist/commands/pickup-command.d.ts +3 -0
  64. package/dist/commands/pickup-command.d.ts.map +1 -0
  65. package/dist/commands/pickup-command.js +161 -0
  66. package/dist/commands/prompt-command.d.ts +1 -1
  67. package/dist/commands/prompt-command.d.ts.map +1 -1
  68. package/dist/commands/prompt-command.js +117 -2
  69. package/dist/commands/remove-directory-command.d.ts +3 -0
  70. package/dist/commands/remove-directory-command.d.ts.map +1 -0
  71. package/dist/commands/remove-directory-command.js +87 -0
  72. package/dist/commands/reset-command.d.ts +1 -1
  73. package/dist/commands/reset-command.d.ts.map +1 -1
  74. package/dist/commands/reset-command.js +13 -2
  75. package/dist/commands/rules-command.d.ts.map +1 -1
  76. package/dist/commands/rules-command.js +65 -0
  77. package/dist/commands/save-command.d.ts.map +1 -1
  78. package/dist/commands/save-command.js +12 -0
  79. package/dist/commands/shell-command.d.ts.map +1 -1
  80. package/dist/commands/shell-command.js +68 -0
  81. package/dist/commands/types.d.ts +9 -4
  82. package/dist/commands/types.d.ts.map +1 -1
  83. package/dist/commands/usage-command.d.ts.map +1 -1
  84. package/dist/commands/usage-command.js +22 -0
  85. package/dist/config.d.ts +6 -7
  86. package/dist/config.d.ts.map +1 -1
  87. package/dist/config.js +23 -29
  88. package/dist/formatting.d.ts +108 -0
  89. package/dist/formatting.d.ts.map +1 -1
  90. package/dist/formatting.js +147 -0
  91. package/dist/index.d.ts +7 -2
  92. package/dist/index.d.ts.map +1 -1
  93. package/dist/index.js +140 -38
  94. package/dist/logger.d.ts.map +1 -1
  95. package/dist/logger.js +47 -18
  96. package/dist/mentions.d.ts +2 -1
  97. package/dist/mentions.d.ts.map +1 -1
  98. package/dist/mentions.js +16 -1
  99. package/dist/messages.d.ts +8 -0
  100. package/dist/messages.d.ts.map +1 -1
  101. package/dist/messages.js +56 -19
  102. package/dist/middleware/cache.d.ts +3 -0
  103. package/dist/middleware/cache.d.ts.map +1 -0
  104. package/dist/middleware/cache.js +53 -0
  105. package/dist/middleware/index.d.ts +1 -0
  106. package/dist/middleware/index.d.ts.map +1 -1
  107. package/dist/middleware/index.js +1 -0
  108. package/dist/models/ai-config.d.ts +4 -2
  109. package/dist/models/ai-config.d.ts.map +1 -1
  110. package/dist/models/ai-config.js +12 -2
  111. package/dist/models/anthropic-provider.d.ts.map +1 -1
  112. package/dist/models/anthropic-provider.js +3 -60
  113. package/dist/models/manager.d.ts +2 -1
  114. package/dist/models/manager.d.ts.map +1 -1
  115. package/dist/models/manager.js +26 -2
  116. package/dist/models/openrouter-provider.d.ts +7 -14
  117. package/dist/models/openrouter-provider.d.ts.map +1 -1
  118. package/dist/models/openrouter-provider.js +114 -169
  119. package/dist/models/providers.d.ts +1 -1
  120. package/dist/models/providers.d.ts.map +1 -1
  121. package/dist/prompts.d.ts +1 -0
  122. package/dist/prompts.d.ts.map +1 -1
  123. package/dist/prompts.js +53 -4
  124. package/dist/repl/display-tool-messages.d.ts +1 -1
  125. package/dist/repl/display-tool-messages.d.ts.map +1 -1
  126. package/dist/repl/display-tool-messages.js +47 -44
  127. package/dist/repl/get-prompt-header.d.ts.map +1 -1
  128. package/dist/repl/get-prompt-header.js +1 -30
  129. package/dist/repl/project-status-line.d.ts +2 -0
  130. package/dist/repl/project-status-line.d.ts.map +1 -0
  131. package/dist/repl/project-status-line.js +31 -0
  132. package/dist/repl/prompt.d.ts +21 -0
  133. package/dist/repl/prompt.d.ts.map +1 -0
  134. package/dist/{repl-prompt.js → repl/prompt.js} +119 -22
  135. package/dist/repl/tool-call-repair.d.ts.map +1 -1
  136. package/dist/repl/tool-call-repair.js +8 -4
  137. package/dist/repl-new.d.ts +53 -0
  138. package/dist/repl-new.d.ts.map +1 -0
  139. package/dist/repl-new.js +374 -0
  140. package/dist/repl.d.ts +3 -5
  141. package/dist/repl.d.ts.map +1 -1
  142. package/dist/repl.js +74 -166
  143. package/dist/terminal/checkbox-prompt.d.ts.map +1 -1
  144. package/dist/terminal/checkbox-prompt.js +10 -4
  145. package/dist/terminal/index.d.ts +7 -0
  146. package/dist/terminal/index.d.ts.map +1 -1
  147. package/dist/terminal/index.js +94 -0
  148. package/dist/terminal/input-prompt.d.ts +2 -1
  149. package/dist/terminal/input-prompt.d.ts.map +1 -1
  150. package/dist/terminal/markdown.js +3 -0
  151. package/dist/terminal/search-prompt.d.ts.map +1 -1
  152. package/dist/terminal/search-prompt.js +11 -10
  153. package/dist/terminal/select-prompt.d.ts +2 -2
  154. package/dist/terminal/select-prompt.d.ts.map +1 -1
  155. package/dist/terminal/select-prompt.js +47 -39
  156. package/dist/tokens/threshold.d.ts +35 -0
  157. package/dist/tokens/threshold.d.ts.map +1 -0
  158. package/dist/tokens/threshold.js +85 -0
  159. package/dist/tools/advanced-edit-file.d.ts +69 -0
  160. package/dist/tools/advanced-edit-file.d.ts.map +1 -0
  161. package/dist/tools/advanced-edit-file.js +281 -0
  162. package/dist/tools/agent.d.ts +16 -5
  163. package/dist/tools/agent.d.ts.map +1 -1
  164. package/dist/tools/agent.js +71 -58
  165. package/dist/tools/bash-utils.d.ts +1 -1
  166. package/dist/tools/bash-utils.d.ts.map +1 -1
  167. package/dist/tools/bash-utils.js +14 -6
  168. package/dist/tools/bash.d.ts +21 -12
  169. package/dist/tools/bash.d.ts.map +1 -1
  170. package/dist/tools/bash.js +88 -135
  171. package/dist/tools/code-interpreter.d.ts +21 -9
  172. package/dist/tools/code-interpreter.d.ts.map +1 -1
  173. package/dist/tools/code-interpreter.js +138 -137
  174. package/dist/tools/delete-file.d.ts +17 -10
  175. package/dist/tools/delete-file.d.ts.map +1 -1
  176. package/dist/tools/delete-file.js +51 -95
  177. package/dist/tools/directory-tree.d.ts +17 -6
  178. package/dist/tools/directory-tree.d.ts.map +1 -1
  179. package/dist/tools/directory-tree.js +47 -49
  180. package/dist/tools/dynamic-tool-loader.d.ts +18 -8
  181. package/dist/tools/dynamic-tool-loader.d.ts.map +1 -1
  182. package/dist/tools/dynamic-tool-loader.js +121 -129
  183. package/dist/tools/dynamic-tool-parser.d.ts +1 -0
  184. package/dist/tools/dynamic-tool-parser.d.ts.map +1 -1
  185. package/dist/tools/dynamic-tool-parser.js +1 -0
  186. package/dist/tools/edit-file.d.ts +35 -15
  187. package/dist/tools/edit-file.d.ts.map +1 -1
  188. package/dist/tools/edit-file.js +112 -112
  189. package/dist/tools/filesystem-utils.d.ts +2 -1
  190. package/dist/tools/filesystem-utils.d.ts.map +1 -1
  191. package/dist/tools/filesystem-utils.js +31 -17
  192. package/dist/tools/glob.d.ts +36 -0
  193. package/dist/tools/glob.d.ts.map +1 -0
  194. package/dist/tools/glob.js +143 -0
  195. package/dist/tools/grep.d.ts +73 -12
  196. package/dist/tools/grep.d.ts.map +1 -1
  197. package/dist/tools/grep.js +413 -168
  198. package/dist/tools/index.d.ts +204 -124
  199. package/dist/tools/index.d.ts.map +1 -1
  200. package/dist/tools/index.js +242 -135
  201. package/dist/tools/llm-edit-fixer.d.ts +25 -0
  202. package/dist/tools/llm-edit-fixer.d.ts.map +1 -0
  203. package/dist/tools/llm-edit-fixer.js +150 -0
  204. package/dist/tools/move-file.d.ts +19 -7
  205. package/dist/tools/move-file.d.ts.map +1 -1
  206. package/dist/tools/move-file.js +40 -33
  207. package/dist/tools/read-file.d.ts +47 -9
  208. package/dist/tools/read-file.d.ts.map +1 -1
  209. package/dist/tools/read-file.js +74 -69
  210. package/dist/tools/read-multiple-files.d.ts +17 -6
  211. package/dist/tools/read-multiple-files.d.ts.map +1 -1
  212. package/dist/tools/read-multiple-files.js +76 -73
  213. package/dist/tools/save-file.d.ts +45 -12
  214. package/dist/tools/save-file.d.ts.map +1 -1
  215. package/dist/tools/save-file.js +58 -101
  216. package/dist/tools/think.d.ts +15 -7
  217. package/dist/tools/think.d.ts.map +1 -1
  218. package/dist/tools/think.js +30 -22
  219. package/dist/tools/types.d.ts +4 -10
  220. package/dist/tools/types.d.ts.map +1 -1
  221. package/dist/tools/types.js +9 -0
  222. package/dist/tools/utils.d.ts +14 -0
  223. package/dist/tools/utils.d.ts.map +1 -0
  224. package/dist/tools/utils.js +16 -0
  225. package/dist/tools/web-fetch.d.ts +11 -4
  226. package/dist/tools/web-fetch.d.ts.map +1 -1
  227. package/dist/tools/web-fetch.js +39 -38
  228. package/dist/tools/web-search.d.ts +15 -6
  229. package/dist/tools/web-search.d.ts.map +1 -1
  230. package/dist/tools/web-search.js +50 -32
  231. package/dist/tui/autocomplete.d.ts +44 -0
  232. package/dist/tui/autocomplete.d.ts.map +1 -0
  233. package/dist/tui/autocomplete.js +466 -0
  234. package/dist/tui/components/assistant-message.d.ts +18 -0
  235. package/dist/tui/components/assistant-message.d.ts.map +1 -0
  236. package/dist/tui/components/assistant-message.js +29 -0
  237. package/dist/tui/components/editor.d.ts +51 -0
  238. package/dist/tui/components/editor.d.ts.map +1 -0
  239. package/dist/tui/components/editor.js +758 -0
  240. package/dist/tui/components/footer.d.ts +24 -0
  241. package/dist/tui/components/footer.d.ts.map +1 -0
  242. package/dist/tui/components/footer.js +197 -0
  243. package/dist/tui/components/input.d.ts +14 -0
  244. package/dist/tui/components/input.d.ts.map +1 -0
  245. package/dist/tui/components/input.js +122 -0
  246. package/dist/tui/components/loader.d.ts +19 -0
  247. package/dist/tui/components/loader.d.ts.map +1 -0
  248. package/dist/tui/components/loader.js +45 -0
  249. package/dist/tui/components/markdown.d.ts +103 -0
  250. package/dist/tui/components/markdown.d.ts.map +1 -0
  251. package/dist/tui/components/markdown.js +533 -0
  252. package/dist/tui/components/modal.d.ts +40 -0
  253. package/dist/tui/components/modal.d.ts.map +1 -0
  254. package/dist/tui/components/modal.js +292 -0
  255. package/dist/tui/components/prompt-status.d.ts +16 -0
  256. package/dist/tui/components/prompt-status.d.ts.map +1 -0
  257. package/dist/tui/components/prompt-status.js +21 -0
  258. package/dist/tui/components/select-list.d.ts +22 -0
  259. package/dist/tui/components/select-list.d.ts.map +1 -0
  260. package/dist/tui/components/select-list.js +143 -0
  261. package/dist/tui/components/spacer.d.ts +16 -0
  262. package/dist/tui/components/spacer.d.ts.map +1 -0
  263. package/dist/tui/components/spacer.js +27 -0
  264. package/dist/tui/components/text.d.ts +26 -0
  265. package/dist/tui/components/text.d.ts.map +1 -0
  266. package/dist/tui/components/text.js +143 -0
  267. package/dist/tui/components/thinking-block.d.ts +14 -0
  268. package/dist/tui/components/thinking-block.d.ts.map +1 -0
  269. package/dist/tui/components/thinking-block.js +30 -0
  270. package/dist/tui/components/tool-execution.d.ts +17 -0
  271. package/dist/tui/components/tool-execution.d.ts.map +1 -0
  272. package/dist/tui/components/tool-execution.js +153 -0
  273. package/dist/tui/components/user-message.d.ts +9 -0
  274. package/dist/tui/components/user-message.d.ts.map +1 -0
  275. package/dist/tui/components/user-message.js +21 -0
  276. package/dist/tui/components/welcome.d.ts +6 -0
  277. package/dist/tui/components/welcome.d.ts.map +1 -0
  278. package/dist/tui/components/welcome.js +30 -0
  279. package/dist/tui/index.d.ts +14 -0
  280. package/dist/tui/index.d.ts.map +1 -0
  281. package/dist/tui/index.js +18 -0
  282. package/dist/tui/terminal.d.ts +37 -0
  283. package/dist/tui/terminal.d.ts.map +1 -0
  284. package/dist/tui/terminal.js +104 -0
  285. package/dist/tui/tui.d.ts +67 -0
  286. package/dist/tui/tui.d.ts.map +1 -0
  287. package/dist/tui/tui.js +184 -0
  288. package/dist/tui/utils.d.ts +19 -0
  289. package/dist/tui/utils.d.ts.map +1 -0
  290. package/dist/tui/utils.js +31 -0
  291. package/dist/utils/generators.d.ts +3 -0
  292. package/dist/utils/generators.d.ts.map +1 -0
  293. package/dist/utils/generators.js +25 -0
  294. package/dist/utils/iterables.d.ts +2 -0
  295. package/dist/utils/iterables.d.ts.map +1 -0
  296. package/dist/utils/iterables.js +6 -0
  297. package/package.json +16 -16
  298. package/dist/conversation-analyzer.d.ts +0 -11
  299. package/dist/conversation-analyzer.d.ts.map +0 -1
  300. package/dist/conversation-analyzer.js +0 -88
  301. package/dist/repl-prompt.d.ts +0 -15
  302. package/dist/repl-prompt.d.ts.map +0 -1
  303. package/dist/tokens/manage-output.d.ts +0 -34
  304. package/dist/tokens/manage-output.d.ts.map +0 -1
  305. package/dist/tokens/manage-output.js +0 -44
  306. package/dist/tool-executor.d.ts +0 -28
  307. package/dist/tool-executor.d.ts.map +0 -1
  308. package/dist/tool-executor.js +0 -74
  309. package/dist/tools/file-editing-utils.d.ts +0 -2
  310. package/dist/tools/file-editing-utils.d.ts.map +0 -1
  311. package/dist/tools/file-editing-utils.js +0 -135
@@ -1,126 +1,83 @@
1
1
  import fs from "node:fs/promises";
2
2
  import path from "node:path";
3
- import { tool } from "ai";
4
3
  import { z } from "zod";
5
- import { formatCodeBlock } from "../formatting.js";
6
4
  import style from "../terminal/style.js";
7
5
  import { joinWorkingDir, validatePath } from "./filesystem-utils.js";
8
6
  import { fileEncodingSchema } from "./types.js";
9
7
  export const SaveFileTool = {
10
8
  name: "saveFile",
11
9
  };
12
- export const createSaveFileTool = async ({ workingDir, terminal, sendData, toolExecutor, }) => {
13
- const allowedDirectory = workingDir;
10
+ const inputSchema = z.object({
11
+ path: z.string().describe("Absolute path to file to save to"),
12
+ content: z.string().describe("Content to save in the file"),
13
+ encoding: fileEncodingSchema.describe('Encoding format for saving the file. Use "utf-8" as default for text files'),
14
+ });
15
+ export const createSaveFileTool = async ({ workingDir, allowedDirs, }) => {
16
+ const allowedDirectory = allowedDirs ?? [workingDir];
14
17
  return {
15
- [SaveFileTool.name]: tool({
18
+ toolDef: {
16
19
  description: "Create a new file or completely overwrite an existing file with new content. " +
17
20
  "Automatically creates all missing parent directories. " +
18
21
  "Use with caution as it will overwrite existing files without warning. " +
19
22
  "Handles text content with proper encoding. Only works within allowed directories.",
20
- inputSchema: z.object({
21
- path: z.string().describe("Absolute path to file to save to"),
22
- content: z.string().describe("Content to save in the file"),
23
- encoding: fileEncodingSchema.describe('Encoding format for saving the file. Use "utf-8" as default for text files'),
24
- }),
25
- execute: async ({ path: userPath, content, encoding, }, { toolCallId, abortSignal }) => {
26
- // Check if execution has been aborted
23
+ inputSchema,
24
+ },
25
+ async *execute({ path: userPath, content, encoding }, { toolCallId, abortSignal }) {
26
+ try {
27
27
  if (abortSignal?.aborted) {
28
28
  throw new Error("File saving aborted");
29
29
  }
30
- sendData?.({
31
- id: toolCallId,
30
+ yield {
31
+ name: SaveFileTool.name,
32
32
  event: "tool-init",
33
- data: `Saving file: ${style.cyan(userPath)}`,
34
- });
33
+ id: toolCallId,
34
+ data: `${style.cyan(userPath)}`,
35
+ };
36
+ const filePath = await validatePath(joinWorkingDir(userPath, workingDir), allowedDirectory, { requireExistence: false, abortSignal });
37
+ // Check if path exists and is a directory
35
38
  try {
36
- const filePath = await validatePath(joinWorkingDir(userPath, workingDir), allowedDirectory, { requireExistence: false, abortSignal });
37
- if (terminal) {
38
- terminal.writeln(`\n${style.blue.bold("●")} Proposing file save: ${style.cyan(userPath)}`);
39
- terminal.lineBreak();
40
- terminal.writeln("Proposed file content:");
41
- terminal.hr();
42
- terminal.display(formatCodeBlock(userPath, content));
43
- terminal.hr();
44
- // Determine overwrite status for display
45
- let overwriteMessage = "";
46
- try {
47
- const stat = await fs.stat(filePath);
48
- if (stat.isFile()) {
49
- overwriteMessage = style.yellow("(Will overwrite existing file)");
50
- }
51
- }
52
- catch {
53
- overwriteMessage = style.green("(Will create new file)");
54
- }
55
- let userResponse;
56
- if (toolExecutor) {
57
- const ctx = {
58
- toolName: SaveFileTool.name,
59
- toolCallId,
60
- message: `What would you like to do with this save? ${overwriteMessage}`,
61
- choices: {
62
- accept: "Accept this save",
63
- acceptAll: "Accept all future saves (including this)",
64
- reject: "Reject this save",
65
- },
66
- };
67
- try {
68
- userResponse = await toolExecutor.ask(ctx, { abortSignal });
69
- }
70
- catch (e) {
71
- if (e.name === "AbortError") {
72
- throw new Error("File saving aborted during user input");
73
- }
74
- throw e;
75
- }
76
- }
77
- const { result: userChoice, reason } = userResponse ?? {
78
- result: "accept",
79
- };
80
- terminal.lineBreak();
81
- if (userChoice === "accept-all") {
82
- terminal.writeln(style.yellow("✓ Auto-accept mode enabled for all saves"));
83
- terminal.lineBreak();
84
- }
85
- if (userChoice === "reject") {
86
- terminal.lineBreak();
87
- const rejectionReason = reason || "No reason provided";
88
- sendData?.({
89
- id: toolCallId,
90
- event: "tool-completion",
91
- data: `Save rejected by user. Reason: ${rejectionReason}`,
92
- });
93
- return `The user rejected this save. Reason: ${rejectionReason}`;
94
- }
95
- // If accepted, proceed to write file
39
+ const stat = await fs.stat(filePath);
40
+ if (stat.isDirectory()) {
41
+ throw new Error(`Cannot save file - path is a directory: ${filePath}`);
96
42
  }
97
- // Pre-side-effect check
98
- if (abortSignal?.aborted) {
99
- throw new Error("File saving aborted before writing");
100
- }
101
- // Ensure parent directory exists (create missing parents)
102
- const parentDir = path.dirname(filePath);
103
- await fs.mkdir(parentDir, { recursive: true });
104
- await fs.writeFile(filePath, content, {
105
- encoding,
106
- signal: abortSignal,
107
- });
108
- sendData?.({
109
- id: toolCallId,
110
- event: "tool-completion",
111
- data: `File saved successfully: ${userPath}`,
112
- });
113
- return `File saved successfully: ${filePath}`;
114
43
  }
115
44
  catch (error) {
116
- sendData?.({
117
- id: toolCallId,
118
- event: "tool-error",
119
- data: `Failed to save file: ${error.message}`,
120
- });
121
- return `Failed to save file: ${error.message}`;
45
+ // Only re-throw if it's our directory error, otherwise continue (file doesn't exist)
46
+ if (error instanceof Error &&
47
+ error.message.includes("is a directory")) {
48
+ throw error;
49
+ }
122
50
  }
123
- },
124
- }),
51
+ // Pre-side-effect check
52
+ if (abortSignal?.aborted) {
53
+ throw new Error("File saving aborted before writing");
54
+ }
55
+ // Ensure parent directory exists (create missing parents)
56
+ const parentDir = path.dirname(filePath);
57
+ await fs.mkdir(parentDir, { recursive: true });
58
+ await fs.writeFile(filePath, content, {
59
+ encoding,
60
+ signal: abortSignal,
61
+ });
62
+ const lines = content.split("\n").length;
63
+ const bytes = Buffer.byteLength(content, encoding);
64
+ yield {
65
+ name: SaveFileTool.name,
66
+ event: "tool-completion",
67
+ id: toolCallId,
68
+ data: `Saved ${lines} lines, ${bytes} bytes`,
69
+ };
70
+ yield `File saved successfully: ${filePath}`;
71
+ }
72
+ catch (error) {
73
+ yield {
74
+ name: SaveFileTool.name,
75
+ event: "tool-error",
76
+ id: toolCallId,
77
+ data: error.message,
78
+ };
79
+ yield `Failed to save file: ${error.message}`;
80
+ }
81
+ },
125
82
  };
126
83
  };
@@ -1,12 +1,20 @@
1
- import type { SendData } from "./types.ts";
1
+ import type { ToolCallOptions } from "ai";
2
+ import { z } from "zod";
3
+ import type { ToolResult } from "./types.ts";
2
4
  export declare const ThinkTool: {
3
5
  name: "think";
4
6
  };
5
- export declare const createThinkTool: (options?: {
6
- sendData?: SendData | undefined;
7
- }) => {
8
- think: import("ai").Tool<{
9
- thought: string;
10
- }, string>;
7
+ declare const inputSchema: z.ZodObject<{
8
+ thought: z.ZodString;
9
+ }, z.core.$strip>;
10
+ export declare const createThinkTool: () => {
11
+ toolDef: {
12
+ description: string;
13
+ inputSchema: z.ZodObject<{
14
+ thought: z.ZodString;
15
+ }, z.core.$strip>;
16
+ };
17
+ execute({ thought }: z.infer<typeof inputSchema>, { toolCallId, abortSignal }: ToolCallOptions): AsyncGenerator<ToolResult>;
11
18
  };
19
+ export {};
12
20
  //# sourceMappingURL=think.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"think.d.ts","sourceRoot":"","sources":["../../source/tools/think.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAE3C,eAAO,MAAM,SAAS;;CAErB,CAAC;AAYF,eAAO,MAAM,eAAe,GAC1B,UAAS;IAAE,QAAQ,CAAC,EAAE,QAAQ,GAAG,SAAS,CAAA;CAAO;;;;CAmClD,CAAC"}
1
+ {"version":3,"file":"think.d.ts","sourceRoot":"","sources":["../../source/tools/think.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,IAAI,CAAC;AAC1C,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAE7C,eAAO,MAAM,SAAS;;CAErB,CAAC;AAWF,QAAA,MAAM,WAAW;;iBAEf,CAAC;AAGH,eAAO,MAAM,eAAe;;;;;;;yBAOT,CAAC,CAAC,KAAK,CAAC,OAAO,WAAW,CAAC,+BACX,eAAe,GAC3C,cAAc,CAAC,UAAU,CAAC;CAqChC,CAAC"}
@@ -1,4 +1,3 @@
1
- import { tool } from "ai";
2
1
  import { z } from "zod";
3
2
  export const ThinkTool = {
4
3
  name: "think",
@@ -11,39 +10,48 @@ Common use cases:
11
10
  4. When designing a new feature, use this tool to think through architecture decisions and implementation details
12
11
  5. When debugging a complex issue, use this tool to organize your thoughts and hypotheses
13
12
  The tool simply logs your thought process for better transparency and does not execute any code or make changes.`;
13
+ const inputSchema = z.object({
14
+ thought: z.string().describe("Your thought"),
15
+ });
14
16
  // This is a no-op tool that logs a thought. It is inspired by the tau-bench think tool.
15
- export const createThinkTool = (options = {}) => {
16
- const { sendData } = options;
17
+ export const createThinkTool = () => {
17
18
  return {
18
- [ThinkTool.name]: tool({
19
+ toolDef: {
19
20
  description: toolDescription,
20
- inputSchema: z.object({
21
- thought: z.string().describe("Your thought"),
22
- }),
23
- execute: ({ thought }, { toolCallId, abortSignal }) => {
21
+ inputSchema,
22
+ },
23
+ async *execute({ thought }, { toolCallId, abortSignal }) {
24
+ try {
24
25
  // Check if execution has been aborted
25
26
  if (abortSignal?.aborted) {
26
27
  throw new Error("Thinking process aborted");
27
28
  }
28
29
  // Replace literal '\\n' with actual newline characters
29
30
  const formattedThought = thought.replace(/\\n/g, "\n");
30
- sendData?.({
31
+ yield {
32
+ name: ThinkTool.name,
31
33
  event: "tool-init",
32
34
  id: toolCallId,
33
- data: "Logging Thought",
34
- });
35
- sendData?.({
36
- event: "tool-update",
37
- id: toolCallId,
38
- data: { primary: "Thought:", secondary: [formattedThought] },
39
- });
40
- sendData?.({
35
+ data: `\n${formattedThought}`,
36
+ };
37
+ yield {
38
+ name: ThinkTool.name,
41
39
  event: "tool-completion",
42
40
  id: toolCallId,
43
- data: "Done",
44
- });
45
- return Promise.resolve("Your thought has been logged.");
46
- },
47
- }),
41
+ data: "Thought logged",
42
+ };
43
+ yield "Your thought has been logged.";
44
+ }
45
+ catch (error) {
46
+ const errorMessage = error instanceof Error ? error.message : String(error);
47
+ yield {
48
+ name: ThinkTool.name,
49
+ event: "tool-error",
50
+ id: toolCallId,
51
+ data: errorMessage,
52
+ };
53
+ yield errorMessage;
54
+ }
55
+ },
48
56
  };
49
57
  };
@@ -12,11 +12,8 @@ export declare const fileEncodingSchema: z.ZodEnum<{
12
12
  binary: "binary";
13
13
  hex: "hex";
14
14
  }>;
15
- interface MessageData {
16
- primary: string;
17
- secondary?: string[] | undefined;
18
- }
19
15
  interface BaseMessage {
16
+ name: string;
20
17
  id: string;
21
18
  retry?: number;
22
19
  }
@@ -32,11 +29,8 @@ interface ToolCompletionMessage extends BaseMessage {
32
29
  event: "tool-completion";
33
30
  data: string;
34
31
  }
35
- interface ToolUpdateMessage extends BaseMessage {
36
- event: "tool-update";
37
- data: MessageData;
38
- }
39
- export type Message = ToolInitMessage | ToolErrorMessage | ToolCompletionMessage | ToolUpdateMessage;
40
- export type SendData = ({ data, event, id, retry, }: Message) => void | Promise<void>;
32
+ export type Message = ToolInitMessage | ToolErrorMessage | ToolCompletionMessage;
33
+ export type ToolResult = Message | string;
34
+ export declare function isToolMessage(value: unknown): value is Message;
41
35
  export {};
42
36
  //# sourceMappingURL=types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../source/tools/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,eAAO,MAAM,kBAAkB;;;;;;;;;;;;EAY7B,CAAC;AAEH,UAAU,WAAW;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,EAAE,GAAG,SAAS,CAAC;CAClC;AAED,UAAU,WAAW;IACnB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,UAAU,eAAgB,SAAQ,WAAW;IAC3C,KAAK,EAAE,WAAW,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,UAAU,gBAAiB,SAAQ,WAAW;IAC5C,KAAK,EAAE,YAAY,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,UAAU,qBAAsB,SAAQ,WAAW;IACjD,KAAK,EAAE,iBAAiB,CAAC;IACzB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,UAAU,iBAAkB,SAAQ,WAAW;IAC7C,KAAK,EAAE,aAAa,CAAC;IACrB,IAAI,EAAE,WAAW,CAAC;CACnB;AAED,MAAM,MAAM,OAAO,GACf,eAAe,GACf,gBAAgB,GAChB,qBAAqB,GACrB,iBAAiB,CAAC;AAEtB,MAAM,MAAM,QAAQ,GAAG,CAAC,EACtB,IAAI,EACJ,KAAK,EACL,EAAE,EACF,KAAK,GACN,EAAE,OAAO,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../source/tools/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,eAAO,MAAM,kBAAkB;;;;;;;;;;;;EAY7B,CAAC;AAEH,UAAU,WAAW;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,UAAU,eAAgB,SAAQ,WAAW;IAC3C,KAAK,EAAE,WAAW,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,UAAU,gBAAiB,SAAQ,WAAW;IAC5C,KAAK,EAAE,YAAY,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,UAAU,qBAAsB,SAAQ,WAAW;IACjD,KAAK,EAAE,iBAAiB,CAAC;IACzB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,MAAM,OAAO,GACf,eAAe,GACf,gBAAgB,GAChB,qBAAqB,CAAC;AAE1B,MAAM,MAAM,UAAU,GAAG,OAAO,GAAG,MAAM,CAAC;AAE1C,wBAAgB,aAAa,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,OAAO,CAc9D"}
@@ -12,3 +12,12 @@ export const fileEncodingSchema = z.enum([
12
12
  "binary",
13
13
  "hex",
14
14
  ]);
15
+ export function isToolMessage(value) {
16
+ if (!value || typeof value !== "object") {
17
+ return false;
18
+ }
19
+ const candidate = value;
20
+ return (typeof candidate.event === "string" &&
21
+ typeof candidate.id === "string" &&
22
+ ("data" in candidate || "retry" in candidate));
23
+ }
@@ -0,0 +1,14 @@
1
+ import type { Tool } from "ai";
2
+ export declare function prepareTools(tools: {
3
+ [toolName: string]: Tool;
4
+ }): {
5
+ tools: undefined | Array<{
6
+ type: "function";
7
+ function: {
8
+ name: string;
9
+ description: string | undefined;
10
+ parameters: unknown;
11
+ };
12
+ }>;
13
+ };
14
+ //# sourceMappingURL=utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../source/tools/utils.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,IAAI,CAAC;AAG/B,wBAAgB,YAAY,CAAC,KAAK,EAAE;IAAE,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,GAAG;IACjE,KAAK,EACD,SAAS,GACT,KAAK,CAAC;QACJ,IAAI,EAAE,UAAU,CAAC;QACjB,QAAQ,EAAE;YACR,IAAI,EAAE,MAAM,CAAC;YACb,WAAW,EAAE,MAAM,GAAG,SAAS,CAAC;YAChC,UAAU,EAAE,OAAO,CAAC;SACrB,CAAC;KACH,CAAC,CAAC;CACR,CAuBA"}
@@ -0,0 +1,16 @@
1
+ import z from "zod";
2
+ export function prepareTools(tools) {
3
+ const openaiCompatTools = [];
4
+ for (const tool of Object.entries(tools)) {
5
+ openaiCompatTools.push({
6
+ type: "function",
7
+ function: {
8
+ name: tool[0],
9
+ description: tool[1].description,
10
+ // biome-ignore lint/suspicious/noExplicitAny: try to figure it out for now
11
+ parameters: z.toJSONSchema(tool[1].inputSchema),
12
+ },
13
+ });
14
+ }
15
+ return { tools: openaiCompatTools };
16
+ }
@@ -1,15 +1,22 @@
1
+ import type { ToolCallOptions } from "ai";
2
+ import { z } from "zod";
1
3
  import type { TokenCounter } from "../tokens/counter.ts";
2
- import type { SendData } from "./types.ts";
4
+ import type { ToolResult } from "./types.ts";
3
5
  export declare const WebFetchTool: {
4
6
  name: "webFetch";
5
7
  };
6
8
  export declare const createWebFetchTool: (options: {
7
- sendData?: SendData | undefined;
8
9
  tokenCounter: TokenCounter;
9
10
  }) => {
10
- webFetch: import("ai").Tool<{
11
+ toolDef: {
12
+ description: string;
13
+ inputSchema: z.ZodObject<{
14
+ url: z.ZodString;
15
+ }, z.core.$strip>;
16
+ };
17
+ execute({ url }: {
11
18
  url: string;
12
- }, string>;
19
+ }, { toolCallId, abortSignal }: ToolCallOptions): AsyncGenerator<ToolResult>;
13
20
  };
14
21
  type ContentType = "text/plain" | "text/html" | "text/markdown" | "application/json" | "application/xml" | "application/pdf" | "image/png" | "image/jpeg" | "image/gif" | "image/webp" | "image/svg+xml" | "audio/mpeg" | "audio/wav" | "video/mp4" | "video/webm" | "application/zip" | "application/octet-stream";
15
22
  export type ReadUrlResult = {
@@ -1 +1 @@
1
- {"version":3,"file":"web-fetch.d.ts","sourceRoot":"","sources":["../../source/tools/web-fetch.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACzD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAE3C,eAAO,MAAM,YAAY;;CAExB,CAAC;AAEF,eAAO,MAAM,kBAAkB,GAAI,SAAS;IAC1C,QAAQ,CAAC,EAAE,QAAQ,GAAG,SAAS,CAAC;IAChC,YAAY,EAAE,YAAY,CAAC;CAC5B;;;;CAyCA,CAAC;AAEF,KAAK,WAAW,GACZ,YAAY,GACZ,WAAW,GACX,eAAe,GACf,kBAAkB,GAClB,iBAAiB,GACjB,iBAAiB,GACjB,WAAW,GACX,YAAY,GACZ,WAAW,GACX,YAAY,GACZ,eAAe,GACf,YAAY,GACZ,WAAW,GACX,WAAW,GACX,YAAY,GACZ,iBAAiB,GACjB,0BAA0B,CAAC;AAE/B,MAAM,MAAM,aAAa,GAAG;IAAE,WAAW,EAAE,WAAW,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC;AAEvE,wBAAsB,OAAO,CAC3B,GAAG,EAAE,MAAM,EACX,WAAW,CAAC,EAAE,WAAW,GAAG,SAAS,GACpC,OAAO,CAAC,aAAa,CAAC,CA6HxB;AAED,qBAAa,WAAW;IACtB,MAAM,CAAC,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,WAAW;IAIrC,OAAO,CAAC,IAAI,CAAS;IAErB,OAAO;IAIP;;;;;;OAMG;IACH,KAAK,CAAC,OAAO,CAAC,EAAE;QAAE,QAAQ,CAAC,EAAE,OAAO,CAAC;QAAC,KAAK,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,MAAM;IAuBhE;;OAEG;IACH,OAAO,CAAC,yBAAyB;IAyCjC;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAuBzB;;OAEG;IACH,OAAO,CAAC,mBAAmB;CAG5B"}
1
+ {"version":3,"file":"web-fetch.d.ts","sourceRoot":"","sources":["../../source/tools/web-fetch.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,IAAI,CAAC;AAE1C,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACzD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAE7C,eAAO,MAAM,YAAY;;CAExB,CAAC;AAMF,eAAO,MAAM,kBAAkB,GAAI,SAAS;IAAE,YAAY,EAAE,YAAY,CAAA;CAAE;;;;;;;qBAQ3D;QAAE,GAAG,EAAE,MAAM,CAAA;KAAE,+BACK,eAAe,GAC3C,cAAc,CAAC,UAAU,CAAC;CAmChC,CAAC;AAEF,KAAK,WAAW,GACZ,YAAY,GACZ,WAAW,GACX,eAAe,GACf,kBAAkB,GAClB,iBAAiB,GACjB,iBAAiB,GACjB,WAAW,GACX,YAAY,GACZ,WAAW,GACX,YAAY,GACZ,eAAe,GACf,YAAY,GACZ,WAAW,GACX,WAAW,GACX,YAAY,GACZ,iBAAiB,GACjB,0BAA0B,CAAC;AAE/B,MAAM,MAAM,aAAa,GAAG;IAAE,WAAW,EAAE,WAAW,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC;AAEvE,wBAAsB,OAAO,CAC3B,GAAG,EAAE,MAAM,EACX,WAAW,CAAC,EAAE,WAAW,GAAG,SAAS,GACpC,OAAO,CAAC,aAAa,CAAC,CA6HxB;AAED,qBAAa,WAAW;IACtB,MAAM,CAAC,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,WAAW;IAIrC,OAAO,CAAC,IAAI,CAAS;IAErB,OAAO;IAIP;;;;;;OAMG;IACH,KAAK,CAAC,OAAO,CAAC,EAAE;QAAE,QAAQ,CAAC,EAAE,OAAO,CAAC;QAAC,KAAK,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,MAAM;IAuBhE;;OAEG;IACH,OAAO,CAAC,yBAAyB;IAyCjC;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAuBzB;;OAEG;IACH,OAAO,CAAC,mBAAmB;CAG5B"}
@@ -1,4 +1,3 @@
1
- import { tool } from "ai";
2
1
  import { load } from "cheerio";
3
2
  import { z } from "zod";
4
3
  import { logger } from "../logger.js";
@@ -6,46 +5,48 @@ import style from "../terminal/style.js";
6
5
  export const WebFetchTool = {
7
6
  name: "webFetch",
8
7
  };
8
+ const inputSchema = z.object({
9
+ url: z.string().describe("The URL to fetch content from."),
10
+ });
9
11
  export const createWebFetchTool = (options) => {
10
- const { sendData } = options;
11
12
  return {
12
- [WebFetchTool.name]: tool({
13
+ toolDef: {
13
14
  description: "Fetches the content of a given URL. It intelligently handles HTML content by attempting to use a specialized service for cleaner extraction, falling back to local cleaning if needed. For non-HTML content (like plain text or markdown), it fetches the raw content directly. IMPORTANT: Does not retrieve binary files.",
14
- inputSchema: z.object({
15
- url: z.string().describe("The URL to fetch content from."),
16
- }),
17
- execute: async ({ url }, { toolCallId, abortSignal }) => {
18
- try {
19
- sendData?.({
20
- event: "tool-init",
21
- id: toolCallId,
22
- data: `Reading URL: ${style.cyan(url)}`,
23
- });
24
- logger.info(`Initiating fetch for URL: ${url}`);
25
- const result = await readUrl(url, abortSignal);
26
- const urlContent = result.data;
27
- const tokenCount = options.tokenCounter.count(urlContent);
28
- sendData?.({
29
- event: "tool-completion",
30
- id: toolCallId,
31
- data: `Read URL successfully (${tokenCount} tokens)`,
32
- });
33
- logger.info(`Successfully read URL: ${url} (${tokenCount} tokens)`);
34
- return urlContent;
35
- }
36
- catch (error) {
37
- const errorMessage = error.message;
38
- sendData?.({
39
- event: "tool-error",
40
- id: toolCallId,
41
- data: `Error reading URL ${url}: ${errorMessage}`,
42
- });
43
- logger.error(`Error reading URL ${url}: ${errorMessage}`);
44
- // Return the error message so the LLM knows the tool failed.
45
- return `Failed to read URL: ${errorMessage}`;
46
- }
47
- },
48
- }),
15
+ inputSchema,
16
+ },
17
+ async *execute({ url }, { toolCallId, abortSignal }) {
18
+ try {
19
+ yield {
20
+ name: WebFetchTool.name,
21
+ event: "tool-init",
22
+ id: toolCallId,
23
+ data: `${style.cyan(url)}`,
24
+ };
25
+ logger.info(`Initiating fetch for URL: ${url}`);
26
+ const result = await readUrl(url, abortSignal);
27
+ const urlContent = result.data;
28
+ const tokenCount = options.tokenCounter.count(urlContent);
29
+ yield {
30
+ name: WebFetchTool.name,
31
+ event: "tool-completion",
32
+ id: toolCallId,
33
+ data: `Fetched URL (${tokenCount} tokens)`,
34
+ };
35
+ logger.info(`Successfully read URL: ${url} (${tokenCount} tokens)`);
36
+ yield urlContent;
37
+ }
38
+ catch (error) {
39
+ const errorMessage = error.message;
40
+ yield {
41
+ name: WebFetchTool.name,
42
+ event: "tool-error",
43
+ id: toolCallId,
44
+ data: `${style.cyan(url)} ${errorMessage}`,
45
+ };
46
+ logger.error(`Error reading URL ${url}: ${errorMessage}`);
47
+ yield `Failed to read URL: ${errorMessage}`;
48
+ }
49
+ },
49
50
  };
50
51
  };
51
52
  export async function readUrl(url, abortSignal) {
@@ -1,14 +1,23 @@
1
+ import type { ToolCallOptions } from "ai";
2
+ import { z } from "zod";
1
3
  import type { TokenCounter } from "../tokens/counter.ts";
2
- import type { SendData } from "./types.ts";
4
+ import type { ToolResult } from "./types.ts";
3
5
  export declare const WebSearchTool: {
4
6
  name: "webSearch";
5
7
  };
6
- export declare const createWebSearchTool: ({ sendData, tokenCounter, }: {
7
- sendData?: SendData;
8
+ declare const inputSchema: z.ZodObject<{
9
+ query: z.ZodString;
10
+ }, z.core.$strip>;
11
+ export declare const createWebSearchTool: ({ tokenCounter, }: {
8
12
  tokenCounter: TokenCounter;
9
13
  }) => {
10
- webSearch: import("ai").Tool<{
11
- query: string;
12
- }, string>;
14
+ toolDef: {
15
+ description: string;
16
+ inputSchema: z.ZodObject<{
17
+ query: z.ZodString;
18
+ }, z.core.$strip>;
19
+ };
20
+ execute: ({ query }: z.infer<typeof inputSchema>, { toolCallId, abortSignal }: ToolCallOptions) => AsyncGenerator<ToolResult>;
13
21
  };
22
+ export {};
14
23
  //# sourceMappingURL=web-search.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"web-search.d.ts","sourceRoot":"","sources":["../../source/tools/web-search.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACzD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAE3C,eAAO,MAAM,aAAa;;CAEzB,CAAC;AAEF,eAAO,MAAM,mBAAmB,GAAI,6BAGjC;IACD,QAAQ,CAAC,EAAE,QAAQ,CAAC;IACpB,YAAY,EAAE,YAAY,CAAC;CAC5B;;;;CA0CA,CAAC"}
1
+ {"version":3,"file":"web-search.d.ts","sourceRoot":"","sources":["../../source/tools/web-search.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,IAAI,CAAC;AAE1C,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAEzD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAE7C,eAAO,MAAM,aAAa;;CAEzB,CAAC;AAEF,QAAA,MAAM,WAAW;;iBAEf,CAAC;AAEH,eAAO,MAAM,mBAAmB,GAAI,mBAEjC;IACD,YAAY,EAAE,YAAY,CAAC;CAC5B;;;;;;;yBAQc,CAAC,CAAC,KAAK,CAAC,OAAO,WAAW,CAAC,+BACT,eAAe,KAC3C,cAAc,CAAC,UAAU,CAAC;CA0D9B,CAAC"}
@@ -1,43 +1,61 @@
1
- import { tool } from "ai";
2
1
  import { SafeSearchType, search } from "duck-duck-scrape";
3
2
  import { z } from "zod";
4
3
  import Exa from "../api/exa/index.js";
5
4
  import style from "../terminal/style.js";
5
+ import { manageTokenLimit } from "../tokens/threshold.js";
6
6
  export const WebSearchTool = {
7
7
  name: "webSearch",
8
8
  };
9
- export const createWebSearchTool = ({ sendData, tokenCounter, }) => {
9
+ const inputSchema = z.object({
10
+ query: z.string().describe("The search query."),
11
+ });
12
+ export const createWebSearchTool = ({ tokenCounter, }) => {
13
+ const toolDef = {
14
+ description: "Searches the web and returns match documents with their title, url, and text content. The query should be formulated as a natural language question.",
15
+ inputSchema,
16
+ };
17
+ const execute = async function* ({ query }, { toolCallId, abortSignal }) {
18
+ try {
19
+ // Check if execution has been aborted
20
+ if (abortSignal?.aborted) {
21
+ throw new Error("Web search aborted");
22
+ }
23
+ yield {
24
+ name: WebSearchTool.name,
25
+ event: "tool-init",
26
+ id: toolCallId,
27
+ data: `${style.cyan(query)}`,
28
+ };
29
+ if (abortSignal?.aborted) {
30
+ throw new Error("Web search aborted before search execution");
31
+ }
32
+ const result = await performSearch(query, abortSignal);
33
+ const sources = result.results.map((source) => `## ${source.title}\nURL: ${source.url}\n\n${source.text}`);
34
+ const resultText = `# Search Results:\n\n${sources.join("\n\n")}`;
35
+ const searchResult = await manageTokenLimit(resultText, tokenCounter, "WebSearch", "Use more specific search queries or reduce number of results");
36
+ yield {
37
+ name: WebSearchTool.name,
38
+ event: "tool-completion",
39
+ id: toolCallId,
40
+ data: `Found ${result.results.length} results (${searchResult.tokenCount} tokens)`,
41
+ };
42
+ yield searchResult.content;
43
+ }
44
+ catch (error) {
45
+ const errorMessage = error instanceof Error ? error.message : String(error);
46
+ yield {
47
+ name: WebSearchTool.name,
48
+ event: "tool-error",
49
+ id: toolCallId,
50
+ data: errorMessage,
51
+ };
52
+ yield errorMessage;
53
+ }
54
+ };
10
55
  return {
11
- [WebSearchTool.name]: tool({
12
- description: "Searches the web and returns match documents with their title, url, and text content. The query should be formulated as a natural language question.",
13
- inputSchema: z.object({
14
- query: z.string().describe("The search query."),
15
- }),
16
- execute: async ({ query }, { toolCallId, abortSignal }) => {
17
- // Check if execution has been aborted
18
- if (abortSignal?.aborted) {
19
- throw new Error("Web search aborted");
20
- }
21
- sendData?.({
22
- id: toolCallId,
23
- event: "tool-init",
24
- data: `Web search: ${style.cyan(query)}`,
25
- });
26
- if (abortSignal?.aborted) {
27
- throw new Error("Web search aborted before search execution");
28
- }
29
- const result = await performSearch(query, abortSignal);
30
- const sources = result.results.map((source) => `## ${source.title}\nURL: ${source.url}\n\n${source.text}`);
31
- const resultText = `# Search Results:\n\n${sources.join("\n\n")}`;
32
- const tokenCount = tokenCounter.count(resultText);
33
- sendData?.({
34
- id: toolCallId,
35
- event: "tool-completion",
36
- data: `Found ${result.results.length} results. (${tokenCount} tokens)`,
37
- });
38
- return resultText;
39
- },
40
- }),
56
+ toolDef,
57
+ execute,
58
+ // No ask method needed for read-only tool
41
59
  };
42
60
  };
43
61
  async function performSearch(query, abortSignal) {