@claude-flow/cli 3.10.4 → 3.10.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 (242) hide show
  1. package/dist/src/benchmarks/capability-tasks.d.ts +126 -0
  2. package/dist/src/benchmarks/capability-tasks.d.ts.map +1 -0
  3. package/dist/src/benchmarks/capability-tasks.js +147 -0
  4. package/dist/src/benchmarks/capability-tasks.js.map +1 -0
  5. package/dist/src/benchmarks/gaia-agent-contrastive.d.ts +53 -0
  6. package/dist/src/benchmarks/gaia-agent-contrastive.d.ts.map +1 -0
  7. package/dist/src/benchmarks/gaia-agent-contrastive.js +177 -0
  8. package/dist/src/benchmarks/gaia-agent-contrastive.js.map +1 -0
  9. package/dist/src/benchmarks/gaia-agent-gemini.d.ts +51 -0
  10. package/dist/src/benchmarks/gaia-agent-gemini.d.ts.map +1 -0
  11. package/dist/src/benchmarks/gaia-agent-gemini.js +352 -0
  12. package/dist/src/benchmarks/gaia-agent-gemini.js.map +1 -0
  13. package/dist/src/benchmarks/gaia-agent-planning.smoke.d.ts +18 -0
  14. package/dist/src/benchmarks/gaia-agent-planning.smoke.d.ts.map +1 -0
  15. package/dist/src/benchmarks/gaia-agent-planning.smoke.js +253 -0
  16. package/dist/src/benchmarks/gaia-agent-planning.smoke.js.map +1 -0
  17. package/dist/src/benchmarks/gaia-agent.d.ts +198 -0
  18. package/dist/src/benchmarks/gaia-agent.d.ts.map +1 -0
  19. package/dist/src/benchmarks/gaia-agent.js +651 -0
  20. package/dist/src/benchmarks/gaia-agent.js.map +1 -0
  21. package/dist/src/benchmarks/gaia-causal-memory.d.ts +133 -0
  22. package/dist/src/benchmarks/gaia-causal-memory.d.ts.map +1 -0
  23. package/dist/src/benchmarks/gaia-causal-memory.js +281 -0
  24. package/dist/src/benchmarks/gaia-causal-memory.js.map +1 -0
  25. package/dist/src/benchmarks/gaia-causal-memory.smoke.d.ts +22 -0
  26. package/dist/src/benchmarks/gaia-causal-memory.smoke.d.ts.map +1 -0
  27. package/dist/src/benchmarks/gaia-causal-memory.smoke.js +300 -0
  28. package/dist/src/benchmarks/gaia-causal-memory.smoke.js.map +1 -0
  29. package/dist/src/benchmarks/gaia-claude-p.d.ts +105 -0
  30. package/dist/src/benchmarks/gaia-claude-p.d.ts.map +1 -0
  31. package/dist/src/benchmarks/gaia-claude-p.js +269 -0
  32. package/dist/src/benchmarks/gaia-claude-p.js.map +1 -0
  33. package/dist/src/benchmarks/gaia-claude-p.smoke.d.ts +20 -0
  34. package/dist/src/benchmarks/gaia-claude-p.smoke.d.ts.map +1 -0
  35. package/dist/src/benchmarks/gaia-claude-p.smoke.js +168 -0
  36. package/dist/src/benchmarks/gaia-claude-p.smoke.js.map +1 -0
  37. package/dist/src/benchmarks/gaia-codeagent-runner.py +556 -0
  38. package/dist/src/benchmarks/gaia-codeagent.d.ts +129 -0
  39. package/dist/src/benchmarks/gaia-codeagent.d.ts.map +1 -0
  40. package/dist/src/benchmarks/gaia-codeagent.js +590 -0
  41. package/dist/src/benchmarks/gaia-codeagent.js.map +1 -0
  42. package/dist/src/benchmarks/gaia-codeagent.smoke.d.ts +33 -0
  43. package/dist/src/benchmarks/gaia-codeagent.smoke.d.ts.map +1 -0
  44. package/dist/src/benchmarks/gaia-codeagent.smoke.js +241 -0
  45. package/dist/src/benchmarks/gaia-codeagent.smoke.js.map +1 -0
  46. package/dist/src/benchmarks/gaia-convergence.d.ts +138 -0
  47. package/dist/src/benchmarks/gaia-convergence.d.ts.map +1 -0
  48. package/dist/src/benchmarks/gaia-convergence.js +260 -0
  49. package/dist/src/benchmarks/gaia-convergence.js.map +1 -0
  50. package/dist/src/benchmarks/gaia-convergence.smoke.d.ts +19 -0
  51. package/dist/src/benchmarks/gaia-convergence.smoke.d.ts.map +1 -0
  52. package/dist/src/benchmarks/gaia-convergence.smoke.js +246 -0
  53. package/dist/src/benchmarks/gaia-convergence.smoke.js.map +1 -0
  54. package/dist/src/benchmarks/gaia-critic.d.ts +123 -0
  55. package/dist/src/benchmarks/gaia-critic.d.ts.map +1 -0
  56. package/dist/src/benchmarks/gaia-critic.js +312 -0
  57. package/dist/src/benchmarks/gaia-critic.js.map +1 -0
  58. package/dist/src/benchmarks/gaia-critic.smoke.d.ts +21 -0
  59. package/dist/src/benchmarks/gaia-critic.smoke.d.ts.map +1 -0
  60. package/dist/src/benchmarks/gaia-critic.smoke.js +327 -0
  61. package/dist/src/benchmarks/gaia-critic.smoke.js.map +1 -0
  62. package/dist/src/benchmarks/gaia-dag-pilot.d.ts +22 -0
  63. package/dist/src/benchmarks/gaia-dag-pilot.d.ts.map +1 -0
  64. package/dist/src/benchmarks/gaia-dag-pilot.js +158 -0
  65. package/dist/src/benchmarks/gaia-dag-pilot.js.map +1 -0
  66. package/dist/src/benchmarks/gaia-dag.d.ts +110 -0
  67. package/dist/src/benchmarks/gaia-dag.d.ts.map +1 -0
  68. package/dist/src/benchmarks/gaia-dag.js +658 -0
  69. package/dist/src/benchmarks/gaia-dag.js.map +1 -0
  70. package/dist/src/benchmarks/gaia-dag.smoke.d.ts +21 -0
  71. package/dist/src/benchmarks/gaia-dag.smoke.d.ts.map +1 -0
  72. package/dist/src/benchmarks/gaia-dag.smoke.js +290 -0
  73. package/dist/src/benchmarks/gaia-dag.smoke.js.map +1 -0
  74. package/dist/src/benchmarks/gaia-decomposer.d.ts +125 -0
  75. package/dist/src/benchmarks/gaia-decomposer.d.ts.map +1 -0
  76. package/dist/src/benchmarks/gaia-decomposer.js +350 -0
  77. package/dist/src/benchmarks/gaia-decomposer.js.map +1 -0
  78. package/dist/src/benchmarks/gaia-decomposer.smoke.d.ts +21 -0
  79. package/dist/src/benchmarks/gaia-decomposer.smoke.d.ts.map +1 -0
  80. package/dist/src/benchmarks/gaia-decomposer.smoke.js +228 -0
  81. package/dist/src/benchmarks/gaia-decomposer.smoke.js.map +1 -0
  82. package/dist/src/benchmarks/gaia-e2e-smoke.d.ts +27 -0
  83. package/dist/src/benchmarks/gaia-e2e-smoke.d.ts.map +1 -0
  84. package/dist/src/benchmarks/gaia-e2e-smoke.js +136 -0
  85. package/dist/src/benchmarks/gaia-e2e-smoke.js.map +1 -0
  86. package/dist/src/benchmarks/gaia-ensemble-pilot.d.ts +17 -0
  87. package/dist/src/benchmarks/gaia-ensemble-pilot.d.ts.map +1 -0
  88. package/dist/src/benchmarks/gaia-ensemble-pilot.js +106 -0
  89. package/dist/src/benchmarks/gaia-ensemble-pilot.js.map +1 -0
  90. package/dist/src/benchmarks/gaia-ensemble.d.ts +103 -0
  91. package/dist/src/benchmarks/gaia-ensemble.d.ts.map +1 -0
  92. package/dist/src/benchmarks/gaia-ensemble.js +462 -0
  93. package/dist/src/benchmarks/gaia-ensemble.js.map +1 -0
  94. package/dist/src/benchmarks/gaia-extract.smoke.d.ts +45 -0
  95. package/dist/src/benchmarks/gaia-extract.smoke.d.ts.map +1 -0
  96. package/dist/src/benchmarks/gaia-extract.smoke.js +242 -0
  97. package/dist/src/benchmarks/gaia-extract.smoke.js.map +1 -0
  98. package/dist/src/benchmarks/gaia-gemini-pilot.d.ts +17 -0
  99. package/dist/src/benchmarks/gaia-gemini-pilot.d.ts.map +1 -0
  100. package/dist/src/benchmarks/gaia-gemini-pilot.js +168 -0
  101. package/dist/src/benchmarks/gaia-gemini-pilot.js.map +1 -0
  102. package/dist/src/benchmarks/gaia-hardness/features.d.ts +46 -0
  103. package/dist/src/benchmarks/gaia-hardness/features.d.ts.map +1 -0
  104. package/dist/src/benchmarks/gaia-hardness/features.js +170 -0
  105. package/dist/src/benchmarks/gaia-hardness/features.js.map +1 -0
  106. package/dist/src/benchmarks/gaia-hardness/predictor.d.ts +105 -0
  107. package/dist/src/benchmarks/gaia-hardness/predictor.d.ts.map +1 -0
  108. package/dist/src/benchmarks/gaia-hardness/predictor.js +260 -0
  109. package/dist/src/benchmarks/gaia-hardness/predictor.js.map +1 -0
  110. package/dist/src/benchmarks/gaia-hardness/predictor.smoke.d.ts +20 -0
  111. package/dist/src/benchmarks/gaia-hardness/predictor.smoke.d.ts.map +1 -0
  112. package/dist/src/benchmarks/gaia-hardness/predictor.smoke.js +235 -0
  113. package/dist/src/benchmarks/gaia-hardness/predictor.smoke.js.map +1 -0
  114. package/dist/src/benchmarks/gaia-hardness/train-data-loader.d.ts +51 -0
  115. package/dist/src/benchmarks/gaia-hardness/train-data-loader.d.ts.map +1 -0
  116. package/dist/src/benchmarks/gaia-hardness/train-data-loader.js +179 -0
  117. package/dist/src/benchmarks/gaia-hardness/train-data-loader.js.map +1 -0
  118. package/dist/src/benchmarks/gaia-judge.d.ts +88 -0
  119. package/dist/src/benchmarks/gaia-judge.d.ts.map +1 -0
  120. package/dist/src/benchmarks/gaia-judge.js +437 -0
  121. package/dist/src/benchmarks/gaia-judge.js.map +1 -0
  122. package/dist/src/benchmarks/gaia-loader.d.ts +87 -0
  123. package/dist/src/benchmarks/gaia-loader.d.ts.map +1 -0
  124. package/dist/src/benchmarks/gaia-loader.js +326 -0
  125. package/dist/src/benchmarks/gaia-loader.js.map +1 -0
  126. package/dist/src/benchmarks/gaia-mode-router.d.ts +67 -0
  127. package/dist/src/benchmarks/gaia-mode-router.d.ts.map +1 -0
  128. package/dist/src/benchmarks/gaia-mode-router.js +126 -0
  129. package/dist/src/benchmarks/gaia-mode-router.js.map +1 -0
  130. package/dist/src/benchmarks/gaia-mode-router.smoke.d.ts +15 -0
  131. package/dist/src/benchmarks/gaia-mode-router.smoke.d.ts.map +1 -0
  132. package/dist/src/benchmarks/gaia-mode-router.smoke.js +131 -0
  133. package/dist/src/benchmarks/gaia-mode-router.smoke.js.map +1 -0
  134. package/dist/src/benchmarks/gaia-tools/file_read.d.ts +35 -0
  135. package/dist/src/benchmarks/gaia-tools/file_read.d.ts.map +1 -0
  136. package/dist/src/benchmarks/gaia-tools/file_read.js +403 -0
  137. package/dist/src/benchmarks/gaia-tools/file_read.js.map +1 -0
  138. package/dist/src/benchmarks/gaia-tools/grounded_query.d.ts +126 -0
  139. package/dist/src/benchmarks/gaia-tools/grounded_query.d.ts.map +1 -0
  140. package/dist/src/benchmarks/gaia-tools/grounded_query.js +225 -0
  141. package/dist/src/benchmarks/gaia-tools/grounded_query.js.map +1 -0
  142. package/dist/src/benchmarks/gaia-tools/grounded_query.smoke.d.ts +24 -0
  143. package/dist/src/benchmarks/gaia-tools/grounded_query.smoke.d.ts.map +1 -0
  144. package/dist/src/benchmarks/gaia-tools/grounded_query.smoke.js +276 -0
  145. package/dist/src/benchmarks/gaia-tools/grounded_query.smoke.js.map +1 -0
  146. package/dist/src/benchmarks/gaia-tools/image_describe.d.ts +45 -0
  147. package/dist/src/benchmarks/gaia-tools/image_describe.d.ts.map +1 -0
  148. package/dist/src/benchmarks/gaia-tools/image_describe.js +222 -0
  149. package/dist/src/benchmarks/gaia-tools/image_describe.js.map +1 -0
  150. package/dist/src/benchmarks/gaia-tools/image_describe.smoke.d.ts +24 -0
  151. package/dist/src/benchmarks/gaia-tools/image_describe.smoke.d.ts.map +1 -0
  152. package/dist/src/benchmarks/gaia-tools/image_describe.smoke.js +169 -0
  153. package/dist/src/benchmarks/gaia-tools/image_describe.smoke.js.map +1 -0
  154. package/dist/src/benchmarks/gaia-tools/index.d.ts +32 -0
  155. package/dist/src/benchmarks/gaia-tools/index.d.ts.map +1 -0
  156. package/dist/src/benchmarks/gaia-tools/index.js +36 -0
  157. package/dist/src/benchmarks/gaia-tools/index.js.map +1 -0
  158. package/dist/src/benchmarks/gaia-tools/pdf_read.d.ts +27 -0
  159. package/dist/src/benchmarks/gaia-tools/pdf_read.d.ts.map +1 -0
  160. package/dist/src/benchmarks/gaia-tools/pdf_read.js +226 -0
  161. package/dist/src/benchmarks/gaia-tools/pdf_read.js.map +1 -0
  162. package/dist/src/benchmarks/gaia-tools/python_exec.d.ts +31 -0
  163. package/dist/src/benchmarks/gaia-tools/python_exec.d.ts.map +1 -0
  164. package/dist/src/benchmarks/gaia-tools/python_exec.js +94 -0
  165. package/dist/src/benchmarks/gaia-tools/python_exec.js.map +1 -0
  166. package/dist/src/benchmarks/gaia-tools/python_exec.smoke.d.ts +13 -0
  167. package/dist/src/benchmarks/gaia-tools/python_exec.smoke.d.ts.map +1 -0
  168. package/dist/src/benchmarks/gaia-tools/python_exec.smoke.js +98 -0
  169. package/dist/src/benchmarks/gaia-tools/python_exec.smoke.js.map +1 -0
  170. package/dist/src/benchmarks/gaia-tools/types.d.ts +62 -0
  171. package/dist/src/benchmarks/gaia-tools/types.d.ts.map +1 -0
  172. package/dist/src/benchmarks/gaia-tools/types.js +12 -0
  173. package/dist/src/benchmarks/gaia-tools/types.js.map +1 -0
  174. package/dist/src/benchmarks/gaia-tools/visit_webpage.d.ts +52 -0
  175. package/dist/src/benchmarks/gaia-tools/visit_webpage.d.ts.map +1 -0
  176. package/dist/src/benchmarks/gaia-tools/visit_webpage.js +304 -0
  177. package/dist/src/benchmarks/gaia-tools/visit_webpage.js.map +1 -0
  178. package/dist/src/benchmarks/gaia-tools/web_browse.d.ts +61 -0
  179. package/dist/src/benchmarks/gaia-tools/web_browse.d.ts.map +1 -0
  180. package/dist/src/benchmarks/gaia-tools/web_browse.js +217 -0
  181. package/dist/src/benchmarks/gaia-tools/web_browse.js.map +1 -0
  182. package/dist/src/benchmarks/gaia-tools/web_browse.smoke.d.ts +26 -0
  183. package/dist/src/benchmarks/gaia-tools/web_browse.smoke.d.ts.map +1 -0
  184. package/dist/src/benchmarks/gaia-tools/web_browse.smoke.js +152 -0
  185. package/dist/src/benchmarks/gaia-tools/web_browse.smoke.js.map +1 -0
  186. package/dist/src/benchmarks/gaia-tools/web_search.d.ts +30 -0
  187. package/dist/src/benchmarks/gaia-tools/web_search.d.ts.map +1 -0
  188. package/dist/src/benchmarks/gaia-tools/web_search.js +210 -0
  189. package/dist/src/benchmarks/gaia-tools/web_search.js.map +1 -0
  190. package/dist/src/benchmarks/gaia-tools/web_search.smoke.d.ts +24 -0
  191. package/dist/src/benchmarks/gaia-tools/web_search.smoke.d.ts.map +1 -0
  192. package/dist/src/benchmarks/gaia-tools/web_search.smoke.js +311 -0
  193. package/dist/src/benchmarks/gaia-tools/web_search.smoke.js.map +1 -0
  194. package/dist/src/benchmarks/gaia-visit-webpage.smoke.d.ts +25 -0
  195. package/dist/src/benchmarks/gaia-visit-webpage.smoke.d.ts.map +1 -0
  196. package/dist/src/benchmarks/gaia-visit-webpage.smoke.js +304 -0
  197. package/dist/src/benchmarks/gaia-visit-webpage.smoke.js.map +1 -0
  198. package/dist/src/benchmarks/gaia-voting.d.ts +88 -0
  199. package/dist/src/benchmarks/gaia-voting.d.ts.map +1 -0
  200. package/dist/src/benchmarks/gaia-voting.js +297 -0
  201. package/dist/src/benchmarks/gaia-voting.js.map +1 -0
  202. package/dist/src/benchmarks/gaia-voting.smoke.d.ts +20 -0
  203. package/dist/src/benchmarks/gaia-voting.smoke.d.ts.map +1 -0
  204. package/dist/src/benchmarks/gaia-voting.smoke.js +332 -0
  205. package/dist/src/benchmarks/gaia-voting.smoke.js.map +1 -0
  206. package/dist/src/commands/gaia-bench.d.ts +40 -0
  207. package/dist/src/commands/gaia-bench.d.ts.map +1 -0
  208. package/dist/src/commands/gaia-bench.js +597 -0
  209. package/dist/src/commands/gaia-bench.js.map +1 -0
  210. package/dist/src/commands/index.d.ts.map +1 -1
  211. package/dist/src/commands/index.js +2 -0
  212. package/dist/src/commands/index.js.map +1 -1
  213. package/dist/src/commands/init.d.ts.map +1 -1
  214. package/dist/src/commands/init.js +41 -4
  215. package/dist/src/commands/init.js.map +1 -1
  216. package/dist/src/commands/performance-capability.d.ts +30 -0
  217. package/dist/src/commands/performance-capability.d.ts.map +1 -0
  218. package/dist/src/commands/performance-capability.js +349 -0
  219. package/dist/src/commands/performance-capability.js.map +1 -0
  220. package/dist/src/commands/route.d.ts.map +1 -1
  221. package/dist/src/commands/route.js +9 -0
  222. package/dist/src/commands/route.js.map +1 -1
  223. package/dist/src/init/executor.d.ts.map +1 -1
  224. package/dist/src/init/executor.js +25 -6
  225. package/dist/src/init/executor.js.map +1 -1
  226. package/dist/src/init/mcp-generator.d.ts.map +1 -1
  227. package/dist/src/init/mcp-generator.js +9 -4
  228. package/dist/src/init/mcp-generator.js.map +1 -1
  229. package/dist/src/init/statusline-generator.d.ts.map +1 -1
  230. package/dist/src/init/statusline-generator.js +25 -2
  231. package/dist/src/init/statusline-generator.js.map +1 -1
  232. package/dist/src/mcp-tools/agentdb-tools.d.ts.map +1 -1
  233. package/dist/src/mcp-tools/agentdb-tools.js +20 -3
  234. package/dist/src/mcp-tools/agentdb-tools.js.map +1 -1
  235. package/dist/src/mcp-tools/system-tools.d.ts.map +1 -1
  236. package/dist/src/mcp-tools/system-tools.js +12 -1
  237. package/dist/src/mcp-tools/system-tools.js.map +1 -1
  238. package/dist/src/memory/memory-bridge.d.ts.map +1 -1
  239. package/dist/src/memory/memory-bridge.js +34 -0
  240. package/dist/src/memory/memory-bridge.js.map +1 -1
  241. package/dist/tsconfig.tsbuildinfo +1 -1
  242. package/package.json +1 -1
@@ -0,0 +1,217 @@
1
+ /**
2
+ * GAIA Tool: web_browse — ADR-133-PR5
3
+ *
4
+ * Opens a URL in a headless Chromium browser via Playwright and extracts
5
+ * page content (text, HTML, or screenshot). Covers the ~10-15pp of GAIA
6
+ * Level-1 questions that require navigating dynamic JS pages, video pages
7
+ * (YouTube, Vimeo), and paywalled/login-required content.
8
+ *
9
+ * ============================================================
10
+ * PLAYWRIGHT DEPENDENCY — OPT-IN INSTALL
11
+ * ============================================================
12
+ * Playwright is NOT a hard runtime dep of @claude-flow/cli. It is loaded
13
+ * lazily via a dynamic import so the package installs cleanly without it.
14
+ *
15
+ * To use web_browse, run once:
16
+ * npm install playwright
17
+ * npx playwright install chromium
18
+ *
19
+ * If Playwright is not installed, execute() returns a structured error
20
+ * message that Claude can relay to the user rather than crashing.
21
+ *
22
+ * Install size: ~80 MB for the Playwright package + Chromium binary.
23
+ * Add as a devDependency in benchmark-specific contexts to avoid bloating
24
+ * the production bundle.
25
+ *
26
+ * ============================================================
27
+ * RESOURCE CAPS
28
+ * ============================================================
29
+ * - Text/HTML extraction capped at 8 000 characters (prevents context-window
30
+ * overflow; roughly 2 000 tokens).
31
+ * - Default timeout: 30 seconds.
32
+ * - Screenshots returned as base64-encoded PNG strings.
33
+ * - Browser instance is always closed in a `finally` block.
34
+ *
35
+ * Refs: ADR-133, #2156
36
+ */
37
+ // ---------------------------------------------------------------------------
38
+ // Constants
39
+ // ---------------------------------------------------------------------------
40
+ const DEFAULT_TIMEOUT_MS = 30_000;
41
+ const MAX_CONTENT_CHARS = 8_000;
42
+ /**
43
+ * Attempt to load Playwright's `chromium` launch function.
44
+ * Returns a missing-result (with install instructions) if Playwright is not
45
+ * installed rather than throwing — callers return the reason string to Claude.
46
+ */
47
+ async function loadPlaywright() {
48
+ try {
49
+ // Dynamic import keeps Playwright out of the static dep graph.
50
+ // The string is built at runtime to prevent TS from statically resolving
51
+ // the module (which would fail with TS2307 when playwright is not installed).
52
+ const pwModuleName = 'play' + 'wright';
53
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
54
+ const pw = await import(/* @vite-ignore */ pwModuleName);
55
+ return { ok: true, chromium: pw.chromium };
56
+ }
57
+ catch {
58
+ return {
59
+ ok: false,
60
+ reason: 'Playwright is not installed. Install it with:\n' +
61
+ ' npm install playwright\n' +
62
+ ' npx playwright install chromium\n' +
63
+ 'Then retry. web_browse requires Playwright to navigate dynamic pages.',
64
+ };
65
+ }
66
+ }
67
+ // ---------------------------------------------------------------------------
68
+ // Core browse logic
69
+ // ---------------------------------------------------------------------------
70
+ async function browseUrl(input) {
71
+ const extract = input.extract ?? 'text';
72
+ const timeoutMs = Math.min(Math.max(1_000, Math.round((input.timeout_seconds ?? DEFAULT_TIMEOUT_MS / 1000) * 1000)), 120_000);
73
+ const pw = await loadPlaywright();
74
+ if (!pw.ok) {
75
+ // Return as a structured result so the agent loop can forward the error
76
+ // to Claude without crashing.
77
+ return {
78
+ content: `[web_browse error] ${pw.reason}`,
79
+ final_url: input.url,
80
+ status: 0,
81
+ };
82
+ }
83
+ const browser = await pw.chromium.launch({ headless: true });
84
+ try {
85
+ const page = await browser.newPage();
86
+ // Capture final HTTP status from the main-frame response.
87
+ let responseStatus = 200;
88
+ page.on('response', (resp) => {
89
+ if (resp.url() === page.url() || resp.url() === input.url) {
90
+ responseStatus = resp.status();
91
+ }
92
+ });
93
+ await page.goto(input.url, {
94
+ waitUntil: 'domcontentloaded',
95
+ timeout: timeoutMs,
96
+ });
97
+ if (input.wait_for_selector) {
98
+ await page.waitForSelector(input.wait_for_selector, { timeout: timeoutMs });
99
+ }
100
+ let rawContent;
101
+ if (extract === 'screenshot') {
102
+ const buf = await page.screenshot({ type: 'png', fullPage: false });
103
+ rawContent = buf.toString('base64');
104
+ }
105
+ else if (extract === 'html') {
106
+ rawContent = await page.content();
107
+ }
108
+ else {
109
+ // Default: extract visible text
110
+ // page.evaluate runs inside the browser context (Chromium's V8 runtime),
111
+ // so `document` / `window` are available there. Cast to avoid the
112
+ // TypeScript "lib does not include dom" error from the Node.js tsconfig.
113
+ rawContent = await page.evaluate(() => {
114
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
115
+ const doc = globalThis.document;
116
+ if (!doc)
117
+ return '';
118
+ doc
119
+ .querySelectorAll('script, style, noscript, [hidden], [aria-hidden="true"]')
120
+ .forEach((el) => el.remove());
121
+ return (doc.body?.innerText ?? doc.documentElement?.innerText ?? '').trim();
122
+ });
123
+ }
124
+ const finalUrl = page.url();
125
+ // Cap text/html at MAX_CONTENT_CHARS; screenshots are kept as-is (base64
126
+ // of a 1280×720 PNG ≈ 300–800 KB — large but necessary for vision pass).
127
+ let content = rawContent;
128
+ let truncated = false;
129
+ if (extract !== 'screenshot' && rawContent.length > MAX_CONTENT_CHARS) {
130
+ content = rawContent.slice(0, MAX_CONTENT_CHARS);
131
+ truncated = true;
132
+ }
133
+ return { content, final_url: finalUrl, status: responseStatus, truncated };
134
+ }
135
+ finally {
136
+ await browser.close();
137
+ }
138
+ }
139
+ // ---------------------------------------------------------------------------
140
+ // Format output for Claude
141
+ // ---------------------------------------------------------------------------
142
+ function formatBrowseResult(result, extract) {
143
+ const lines = [];
144
+ lines.push(`final_url: ${result.final_url}`);
145
+ lines.push(`status: ${result.status}`);
146
+ if (extract === 'screenshot') {
147
+ lines.push(`extract: screenshot (base64 PNG)`);
148
+ lines.push(`content:\n${result.content}`);
149
+ }
150
+ else {
151
+ lines.push(`extract: ${extract}`);
152
+ if (result.truncated) {
153
+ lines.push(`[content truncated at ${MAX_CONTENT_CHARS} characters]`);
154
+ }
155
+ lines.push(`content:\n${result.content}`);
156
+ }
157
+ return lines.join('\n');
158
+ }
159
+ // ---------------------------------------------------------------------------
160
+ // GaiaTool implementation
161
+ // ---------------------------------------------------------------------------
162
+ export class WebBrowseTool {
163
+ name = 'web_browse';
164
+ definition = {
165
+ name: 'web_browse',
166
+ description: 'Open a URL in a headless Chromium browser and extract page content. ' +
167
+ 'Use this for dynamic JavaScript pages, video pages (YouTube, Vimeo), ' +
168
+ 'or any URL that web_search cannot fetch directly. ' +
169
+ 'Returns page text by default; pass extract="html" for raw HTML or ' +
170
+ 'extract="screenshot" for a base64 PNG screenshot. ' +
171
+ 'Requires Playwright to be installed (npm install playwright && ' +
172
+ 'npx playwright install chromium).',
173
+ input_schema: {
174
+ type: 'object',
175
+ properties: {
176
+ url: {
177
+ type: 'string',
178
+ description: 'The URL to navigate to (http or https).',
179
+ },
180
+ wait_for_selector: {
181
+ type: 'string',
182
+ description: 'Optional CSS selector to wait for before extracting content. ' +
183
+ 'Useful for SPAs that render after the initial DOM load.',
184
+ },
185
+ extract: {
186
+ type: 'string',
187
+ description: 'What to extract: "text" (default, visible text), ' +
188
+ '"html" (full page HTML), or "screenshot" (base64 PNG).',
189
+ },
190
+ timeout_seconds: {
191
+ type: 'number',
192
+ description: `Navigation timeout in seconds (default: ${DEFAULT_TIMEOUT_MS / 1000}, max: 120).`,
193
+ },
194
+ },
195
+ required: ['url'],
196
+ },
197
+ };
198
+ async execute(input) {
199
+ const url = String(input['url'] ?? '').trim();
200
+ if (!url)
201
+ throw new Error('web_browse: `url` input is required and must be non-empty.');
202
+ const rawExtract = String(input['extract'] ?? 'text').toLowerCase();
203
+ const extract = rawExtract === 'html' ? 'html' : rawExtract === 'screenshot' ? 'screenshot' : 'text';
204
+ const browseInput = {
205
+ url,
206
+ wait_for_selector: input['wait_for_selector'] != null ? String(input['wait_for_selector']) : undefined,
207
+ extract,
208
+ timeout_seconds: input['timeout_seconds'] != null ? Number(input['timeout_seconds']) : undefined,
209
+ };
210
+ const result = await browseUrl(browseInput);
211
+ return formatBrowseResult(result, extract);
212
+ }
213
+ }
214
+ export function createWebBrowseTool(_opts) {
215
+ return new WebBrowseTool();
216
+ }
217
+ //# sourceMappingURL=web_browse.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"web_browse.js","sourceRoot":"","sources":["../../../../src/benchmarks/gaia-tools/web_browse.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Smoke tests for web_browse — ADR-133-PR5
3
+ *
4
+ * Run with:
5
+ * cd v3/@claude-flow/cli
6
+ * npx tsx src/benchmarks/gaia-tools/web_browse.smoke.ts
7
+ *
8
+ * Requires Playwright to be installed:
9
+ * npm install playwright
10
+ * npx playwright install chromium
11
+ *
12
+ * If Playwright is not installed, tests that require it are skipped with
13
+ * a SKIP result (not a failure) — the install instructions are printed.
14
+ *
15
+ * Tests:
16
+ * 1. Browse Wikipedia page — content contains 'Mercedes', status 200
17
+ * 2. Bad URL with short timeout — returns error message (no crash)
18
+ * 3. Screenshot mode — returns non-empty base64 string
19
+ * 4. HTML extract mode — content contains '<html' or '<HTML'
20
+ *
21
+ * Cost: $0 (all local Playwright calls — no LLM).
22
+ *
23
+ * Refs: ADR-133, #2156
24
+ */
25
+ export {};
26
+ //# sourceMappingURL=web_browse.smoke.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"web_browse.smoke.d.ts","sourceRoot":"","sources":["../../../../src/benchmarks/gaia-tools/web_browse.smoke.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG"}
@@ -0,0 +1,152 @@
1
+ /**
2
+ * Smoke tests for web_browse — ADR-133-PR5
3
+ *
4
+ * Run with:
5
+ * cd v3/@claude-flow/cli
6
+ * npx tsx src/benchmarks/gaia-tools/web_browse.smoke.ts
7
+ *
8
+ * Requires Playwright to be installed:
9
+ * npm install playwright
10
+ * npx playwright install chromium
11
+ *
12
+ * If Playwright is not installed, tests that require it are skipped with
13
+ * a SKIP result (not a failure) — the install instructions are printed.
14
+ *
15
+ * Tests:
16
+ * 1. Browse Wikipedia page — content contains 'Mercedes', status 200
17
+ * 2. Bad URL with short timeout — returns error message (no crash)
18
+ * 3. Screenshot mode — returns non-empty base64 string
19
+ * 4. HTML extract mode — content contains '<html' or '<HTML'
20
+ *
21
+ * Cost: $0 (all local Playwright calls — no LLM).
22
+ *
23
+ * Refs: ADR-133, #2156
24
+ */
25
+ import { createWebBrowseTool } from './web_browse.js';
26
+ async function runTest(name, fn) {
27
+ try {
28
+ await fn();
29
+ return { name, status: 'PASS', message: 'OK' };
30
+ }
31
+ catch (e) {
32
+ const msg = String(e);
33
+ // If Playwright isn't installed, mark as SKIP rather than FAIL.
34
+ if (msg.includes('Playwright is not installed') ||
35
+ msg.includes('Cannot find module') ||
36
+ msg.includes('playwright')) {
37
+ return { name, status: 'SKIP', message: `Playwright not installed — ${msg}` };
38
+ }
39
+ return { name, status: 'FAIL', message: msg };
40
+ }
41
+ }
42
+ function assert(condition, msg) {
43
+ if (!condition)
44
+ throw new Error(`Assertion failed: ${msg}`);
45
+ }
46
+ // ---------------------------------------------------------------------------
47
+ // Tests
48
+ // ---------------------------------------------------------------------------
49
+ const tool = createWebBrowseTool();
50
+ // Test 1: Wikipedia text extraction
51
+ async function testWikipedia() {
52
+ const out = await tool.execute({
53
+ url: 'https://en.wikipedia.org/wiki/Mercedes_Sosa',
54
+ extract: 'text',
55
+ timeout_seconds: 30,
56
+ });
57
+ // If Playwright is missing, execute() returns a structured error string.
58
+ if (out.startsWith('[web_browse error]')) {
59
+ throw new Error(out);
60
+ }
61
+ assert(out.toLowerCase().includes('mercedes') || out.toLowerCase().includes('sosa'), `Expected page text to contain "Mercedes" or "Sosa", got:\n${out.slice(0, 500)}`);
62
+ assert(out.includes('final_url:'), `Expected final_url in output, got:\n${out.slice(0, 200)}`);
63
+ }
64
+ // Test 2: Bad URL with short timeout — should return gracefully, not throw
65
+ async function testBadUrlTimeout() {
66
+ const out = await tool.execute({
67
+ url: 'https://this-domain-absolutely-does-not-exist-gaia-bench.example',
68
+ extract: 'text',
69
+ timeout_seconds: 5,
70
+ });
71
+ // Either a Playwright "not installed" error or a network error — both are
72
+ // acceptable. The tool must NOT throw; it must return a string.
73
+ assert(typeof out === 'string', 'Expected string output from bad-URL test');
74
+ }
75
+ // Test 3: Screenshot mode — returns base64 PNG
76
+ async function testScreenshotMode() {
77
+ const out = await tool.execute({
78
+ url: 'https://en.wikipedia.org/wiki/Main_Page',
79
+ extract: 'screenshot',
80
+ timeout_seconds: 30,
81
+ });
82
+ if (out.startsWith('[web_browse error]')) {
83
+ throw new Error(out);
84
+ }
85
+ assert(out.includes('content:'), `Expected "content:" in output, got:\n${out.slice(0, 200)}`);
86
+ // Extract the base64 portion after "content:\n"
87
+ const contentIdx = out.indexOf('content:\n');
88
+ if (contentIdx !== -1) {
89
+ const b64 = out.slice(contentIdx + 'content:\n'.length).trim();
90
+ assert(b64.length > 100, `Expected non-trivial base64 data, got length ${b64.length}`);
91
+ // Base64 charset only
92
+ assert(/^[A-Za-z0-9+/=]+$/.test(b64.slice(0, 100)), `Expected base64-encoded output, got:\n${b64.slice(0, 100)}`);
93
+ }
94
+ }
95
+ // Test 4: HTML extract mode
96
+ async function testHtmlExtract() {
97
+ const out = await tool.execute({
98
+ url: 'https://en.wikipedia.org/wiki/Main_Page',
99
+ extract: 'html',
100
+ timeout_seconds: 30,
101
+ });
102
+ if (out.startsWith('[web_browse error]')) {
103
+ throw new Error(out);
104
+ }
105
+ assert(out.toLowerCase().includes('<html') || out.includes('<!DOCTYPE'), `Expected HTML markup in output, got:\n${out.slice(0, 300)}`);
106
+ }
107
+ // ---------------------------------------------------------------------------
108
+ // Runner
109
+ // ---------------------------------------------------------------------------
110
+ async function main() {
111
+ console.log('web_browse smoke tests — ADR-133-PR5\n');
112
+ const tests = [
113
+ runTest('Test 1: Wikipedia text extraction (contains "Mercedes")', testWikipedia),
114
+ runTest('Test 2: Bad URL with 5s timeout — no crash', testBadUrlTimeout),
115
+ runTest('Test 3: Screenshot mode — non-empty base64', testScreenshotMode),
116
+ runTest('Test 4: HTML extract mode — markup present', testHtmlExtract),
117
+ ];
118
+ // Run sequentially to avoid spawning 4 browser instances simultaneously.
119
+ const results = [];
120
+ for (const t of tests) {
121
+ results.push(await t);
122
+ }
123
+ let passed = 0;
124
+ let failed = 0;
125
+ let skipped = 0;
126
+ for (const r of results) {
127
+ console.log(`[${r.status}] ${r.name}`);
128
+ if (r.status !== 'PASS') {
129
+ console.log(` ${r.message.slice(0, 300)}`);
130
+ }
131
+ if (r.status === 'PASS')
132
+ passed++;
133
+ else if (r.status === 'FAIL')
134
+ failed++;
135
+ else
136
+ skipped++;
137
+ }
138
+ console.log(`\nResults: ${passed} passed, ${failed} failed, ${skipped} skipped`);
139
+ if (skipped > 0) {
140
+ console.log('\nInstall Playwright to run skipped tests:');
141
+ console.log(' npm install playwright');
142
+ console.log(' npx playwright install chromium');
143
+ }
144
+ if (failed > 0) {
145
+ process.exit(1);
146
+ }
147
+ }
148
+ main().catch((e) => {
149
+ console.error('Fatal:', e);
150
+ process.exit(1);
151
+ });
152
+ //# sourceMappingURL=web_browse.smoke.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"web_browse.smoke.js","sourceRoot":"","sources":["../../../../src/benchmarks/gaia-tools/web_browse.smoke.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,30 @@
1
+ /**
2
+ * GAIA Tool: web_search — ADR-133-PR2
3
+ *
4
+ * Scrapes DuckDuckGo HTML search results for a query string and returns
5
+ * the top-N snippet titles + URLs as a plain-text block. No API key
6
+ * required; uses DDG's HTML endpoint which is publicly accessible.
7
+ *
8
+ * Design notes:
9
+ * - Uses native Node.js https/http (no external fetch polyfill).
10
+ * - Follows the DDG Lite HTML endpoint: https://html.duckduckgo.com/html/?q=…
11
+ * - Parses result titles + URLs via a simple regex (no DOM parser dependency).
12
+ * - Rate-limit aware: 1-second back-off between calls is the caller's
13
+ * responsibility (the agent loop enforces this in PR-3).
14
+ * - PDF / binary detection is handled by file_read.ts, not here.
15
+ *
16
+ * Refs: ADR-133, #2156
17
+ */
18
+ import { GaiaTool, ToolDefinition } from './types.js';
19
+ export interface SearchResult {
20
+ title: string;
21
+ url: string;
22
+ snippet: string;
23
+ }
24
+ export declare class WebSearchTool implements GaiaTool {
25
+ readonly name = "web_search";
26
+ readonly definition: ToolDefinition;
27
+ execute(input: Record<string, unknown>): Promise<string>;
28
+ }
29
+ export declare function createWebSearchTool(): WebSearchTool;
30
+ //# sourceMappingURL=web_search.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"web_search.d.ts","sourceRoot":"","sources":["../../../../src/benchmarks/gaia-tools/web_search.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAIH,OAAO,EAAE,QAAQ,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAkBtD,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,MAAM,CAAC;CACjB;AA2KD,qBAAa,aAAc,YAAW,QAAQ;IAC5C,QAAQ,CAAC,IAAI,gBAAgB;IAE7B,QAAQ,CAAC,UAAU,EAAE,cAAc,CAmBjC;IAEI,OAAO,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC;CAa/D;AAMD,wBAAgB,mBAAmB,IAAI,aAAa,CAEnD"}
@@ -0,0 +1,210 @@
1
+ /**
2
+ * GAIA Tool: web_search — ADR-133-PR2
3
+ *
4
+ * Scrapes DuckDuckGo HTML search results for a query string and returns
5
+ * the top-N snippet titles + URLs as a plain-text block. No API key
6
+ * required; uses DDG's HTML endpoint which is publicly accessible.
7
+ *
8
+ * Design notes:
9
+ * - Uses native Node.js https/http (no external fetch polyfill).
10
+ * - Follows the DDG Lite HTML endpoint: https://html.duckduckgo.com/html/?q=…
11
+ * - Parses result titles + URLs via a simple regex (no DOM parser dependency).
12
+ * - Rate-limit aware: 1-second back-off between calls is the caller's
13
+ * responsibility (the agent loop enforces this in PR-3).
14
+ * - PDF / binary detection is handled by file_read.ts, not here.
15
+ *
16
+ * Refs: ADR-133, #2156
17
+ */
18
+ import * as https from 'node:https';
19
+ // ---------------------------------------------------------------------------
20
+ // Constants
21
+ // ---------------------------------------------------------------------------
22
+ const DDG_HTML_URL = 'https://html.duckduckgo.com/html/';
23
+ const DEFAULT_MAX_RESULTS = 5;
24
+ const REQUEST_TIMEOUT_MS = 20_000;
25
+ // User-Agent that DDG accepts (plain browser UA).
26
+ const UA = 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36';
27
+ // ---------------------------------------------------------------------------
28
+ // HTML fetch helper
29
+ // ---------------------------------------------------------------------------
30
+ /**
31
+ * POST to DuckDuckGo's HTML search endpoint and return the raw HTML string.
32
+ * DDG blocks GET for automated scrapers but accepts POST form submissions.
33
+ */
34
+ async function fetchDdgHtml(query) {
35
+ const body = `q=${encodeURIComponent(query)}&b=&kl=&df=`;
36
+ const bodyBytes = Buffer.from(body, 'utf-8');
37
+ return new Promise((resolve, reject) => {
38
+ const options = {
39
+ hostname: 'html.duckduckgo.com',
40
+ path: '/html/',
41
+ method: 'POST',
42
+ headers: {
43
+ 'Content-Type': 'application/x-www-form-urlencoded',
44
+ 'Content-Length': bodyBytes.length,
45
+ 'User-Agent': UA,
46
+ Accept: 'text/html,application/xhtml+xml',
47
+ 'Accept-Language': 'en-US,en;q=0.9',
48
+ },
49
+ };
50
+ const req = https.request(options, (res) => {
51
+ // Follow a single redirect if needed (DDG occasionally redirects to /html/)
52
+ if (res.statusCode !== undefined &&
53
+ res.statusCode >= 300 &&
54
+ res.statusCode < 400 &&
55
+ res.headers.location) {
56
+ const loc = res.headers.location;
57
+ res.resume();
58
+ // Simple follow — only handle absolute https redirects
59
+ if (loc.startsWith('https://')) {
60
+ https
61
+ .get(loc, { headers: { 'User-Agent': UA } }, (r2) => {
62
+ const chunks = [];
63
+ r2.on('data', (c) => chunks.push(c));
64
+ r2.on('end', () => resolve(Buffer.concat(chunks).toString('utf-8')));
65
+ r2.on('error', reject);
66
+ })
67
+ .on('error', reject);
68
+ }
69
+ else {
70
+ reject(new Error(`Unexpected redirect target: ${loc}`));
71
+ }
72
+ return;
73
+ }
74
+ if (res.statusCode !== 200) {
75
+ res.resume();
76
+ reject(new Error(`DDG returned HTTP ${res.statusCode ?? 'unknown'}`));
77
+ return;
78
+ }
79
+ const chunks = [];
80
+ res.on('data', (c) => chunks.push(c));
81
+ res.on('end', () => resolve(Buffer.concat(chunks).toString('utf-8')));
82
+ res.on('error', reject);
83
+ });
84
+ req.on('error', reject);
85
+ req.setTimeout(REQUEST_TIMEOUT_MS, () => {
86
+ req.destroy(new Error(`web_search timeout after ${REQUEST_TIMEOUT_MS}ms`));
87
+ });
88
+ req.write(bodyBytes);
89
+ req.end();
90
+ });
91
+ }
92
+ // ---------------------------------------------------------------------------
93
+ // HTML parser (regex-based, no DOM)
94
+ // ---------------------------------------------------------------------------
95
+ /**
96
+ * Extract up to `maxResults` search results from DDG HTML.
97
+ *
98
+ * DDG's HTML result structure (stable as of 2026):
99
+ * <a class="result__a" href="URL">TITLE</a>
100
+ * <a class="result__snippet">SNIPPET</a>
101
+ *
102
+ * We parse with regex to avoid adding an htmlparser2 dependency.
103
+ */
104
+ function parseDdgHtml(html, maxResults) {
105
+ const results = [];
106
+ // Match result blocks — DDG wraps each result in <div class="result …">
107
+ // We extract title+url from the result__a anchor, and snippet from result__snippet.
108
+ const resultBlockRe = /<a[^>]+class="result__a"[^>]*href="([^"]+)"[^>]*>([\s\S]*?)<\/a>[\s\S]*?(?:<a[^>]+class="result__snippet"[^>]*>([\s\S]*?)<\/a>)?/g;
109
+ let match;
110
+ while ((match = resultBlockRe.exec(html)) !== null && results.length < maxResults) {
111
+ const rawUrl = match[1] ?? '';
112
+ const rawTitle = match[2] ?? '';
113
+ const rawSnippet = match[3] ?? '';
114
+ // DDG wraps URLs in //duckduckgo.com/l/?uddg=ENCODED_URL
115
+ const url = decodeRawUrl(rawUrl);
116
+ const title = stripHtml(rawTitle).trim();
117
+ const snippet = stripHtml(rawSnippet).trim();
118
+ if (url && title) {
119
+ results.push({ title, url, snippet });
120
+ }
121
+ }
122
+ return results;
123
+ }
124
+ /**
125
+ * Decode the DDG redirect URL back to the real URL.
126
+ * Input example: //duckduckgo.com/l/?uddg=https%3A%2F%2Fexample.com%2F&rut=…
127
+ */
128
+ function decodeRawUrl(raw) {
129
+ if (raw.startsWith('//duckduckgo.com/l/')) {
130
+ const qIdx = raw.indexOf('uddg=');
131
+ if (qIdx !== -1) {
132
+ const encoded = raw.slice(qIdx + 5).split('&')[0];
133
+ try {
134
+ return decodeURIComponent(encoded);
135
+ }
136
+ catch {
137
+ return raw;
138
+ }
139
+ }
140
+ }
141
+ // Direct URL (some results skip the redirect)
142
+ if (raw.startsWith('http://') || raw.startsWith('https://'))
143
+ return raw;
144
+ return raw;
145
+ }
146
+ /** Strip HTML tags and decode common entities. */
147
+ function stripHtml(html) {
148
+ return html
149
+ .replace(/<[^>]+>/g, '')
150
+ .replace(/&amp;/g, '&')
151
+ .replace(/&lt;/g, '<')
152
+ .replace(/&gt;/g, '>')
153
+ .replace(/&quot;/g, '"')
154
+ .replace(/&#x27;/g, "'")
155
+ .replace(/&nbsp;/g, ' ')
156
+ .replace(/\s+/g, ' ')
157
+ .trim();
158
+ }
159
+ // ---------------------------------------------------------------------------
160
+ // Format output for Claude
161
+ // ---------------------------------------------------------------------------
162
+ function formatResults(results) {
163
+ if (results.length === 0) {
164
+ return 'No results found.';
165
+ }
166
+ return results
167
+ .map((r, i) => `[${i + 1}] ${r.title}\n URL: ${r.url}${r.snippet ? '\n ' + r.snippet : ''}`)
168
+ .join('\n\n');
169
+ }
170
+ // ---------------------------------------------------------------------------
171
+ // GaiaTool implementation
172
+ // ---------------------------------------------------------------------------
173
+ export class WebSearchTool {
174
+ name = 'web_search';
175
+ definition = {
176
+ name: 'web_search',
177
+ description: 'Search the web using DuckDuckGo and return the top results (title, URL, snippet). ' +
178
+ 'Use this when you need current information, external facts, or to verify claims.',
179
+ input_schema: {
180
+ type: 'object',
181
+ properties: {
182
+ query: {
183
+ type: 'string',
184
+ description: 'The search query string.',
185
+ },
186
+ max_results: {
187
+ type: 'number',
188
+ description: `Maximum number of results to return (default: ${DEFAULT_MAX_RESULTS}, max: 10).`,
189
+ },
190
+ },
191
+ required: ['query'],
192
+ },
193
+ };
194
+ async execute(input) {
195
+ const query = String(input['query'] ?? '').trim();
196
+ if (!query)
197
+ throw new Error('web_search: `query` input is required and must be non-empty.');
198
+ const maxResults = Math.min(Math.max(1, Number(input['max_results'] ?? DEFAULT_MAX_RESULTS)), 10);
199
+ const html = await fetchDdgHtml(query);
200
+ const results = parseDdgHtml(html, maxResults);
201
+ return formatResults(results);
202
+ }
203
+ }
204
+ // ---------------------------------------------------------------------------
205
+ // Convenience factory
206
+ // ---------------------------------------------------------------------------
207
+ export function createWebSearchTool() {
208
+ return new WebSearchTool();
209
+ }
210
+ //# sourceMappingURL=web_search.js.map