@johpaz/hive-sdk 0.1.4 → 0.1.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 (278) hide show
  1. package/CHANGELOG.md +129 -0
  2. package/README.md +78 -23
  3. package/bun.lock +55 -29
  4. package/bunfig.toml +4 -2
  5. package/docs/API-AGENTS.md +78 -27
  6. package/docs/API-CONTEXT-COMPILER.md +31 -34
  7. package/docs/API-TOOLS-SKILLS-CHANNELS.md +58 -22
  8. package/docs/HIVE-HARNESS.md +1 -1
  9. package/docs/INDEX.md +4 -4
  10. package/docs/TEMPLATE-HIVE-APP.md +10 -10
  11. package/package.json +17 -12
  12. package/packages/cli/package.json +2 -2
  13. package/packages/cli/src/commands/create-app.test.ts +36 -7
  14. package/packages/cli/src/commands/init.ts +3 -3
  15. package/packages/cli/src/commands/run.ts +1 -1
  16. package/packages/cli/src/commands/test.ts +37 -25
  17. package/packages/cli/src/commands/trace.ts +30 -28
  18. package/packages/cli/templates/hive-app/.env.example +10 -2
  19. package/packages/cli/templates/hive-app/README.md +103 -0
  20. package/packages/cli/templates/hive-app/hive.config.ts +9 -3
  21. package/packages/cli/templates/hive-app/src/agents/coordinator.ts +8 -1
  22. package/packages/cli/templates/hive-app/src/main.ts +12 -19
  23. package/packages/core/package.json +13 -12
  24. package/packages/core/src/agent/acceptance-checks.ts +172 -0
  25. package/packages/core/src/agent/agent-catalog.ts +348 -0
  26. package/packages/core/src/agent/agent-loop.ts +1373 -0
  27. package/packages/core/src/agent/capability-search.ts +186 -0
  28. package/packages/core/src/agent/catalog-selector.ts +103 -0
  29. package/packages/core/src/agent/{Compaction.ts → compaction.ts} +86 -63
  30. package/packages/core/src/agent/context-compiler.ts +689 -0
  31. package/packages/core/src/agent/conversation-store.ts +381 -0
  32. package/packages/core/src/agent/curator.ts +276 -0
  33. package/packages/core/src/agent/delegation-runtime.ts +241 -0
  34. package/packages/core/src/agent/goal-runner.ts +323 -0
  35. package/packages/core/src/agent/index.ts +17 -12
  36. package/packages/core/src/agent/llm-client.ts +266 -0
  37. package/packages/core/src/agent/llm-providers/anthropic.ts +264 -0
  38. package/packages/core/src/agent/llm-providers/deepseek.ts +8 -0
  39. package/packages/core/src/agent/{providers → llm-providers}/gemini.ts +98 -60
  40. package/packages/core/src/agent/llm-providers/groq.ts +5 -0
  41. package/packages/core/src/agent/llm-providers/hiveagents.ts +253 -0
  42. package/packages/core/src/agent/{providers → llm-providers}/interface.ts +73 -13
  43. package/packages/core/src/agent/llm-providers/kimi.ts +8 -0
  44. package/packages/core/src/agent/llm-providers/minimax.ts +13 -0
  45. package/packages/core/src/agent/llm-providers/mistral.ts +5 -0
  46. package/packages/core/src/agent/llm-providers/modelscope.ts +5 -0
  47. package/packages/core/src/agent/llm-providers/nvidia.ts +5 -0
  48. package/packages/core/src/agent/{providers → llm-providers}/ollama.ts +31 -5
  49. package/packages/core/src/agent/llm-providers/openai-compat-base.ts +418 -0
  50. package/packages/core/src/agent/llm-providers/openai.ts +5 -0
  51. package/packages/core/src/agent/llm-providers/opencode-go.ts +9 -0
  52. package/packages/core/src/agent/llm-providers/openrouter.ts +5 -0
  53. package/packages/core/src/agent/llm-providers/qwen.ts +5 -0
  54. package/packages/core/src/agent/llm-providers/z-ai.ts +5 -0
  55. package/packages/core/src/agent/minimal-loadout.ts +47 -0
  56. package/packages/core/src/agent/playbook-selector.ts +119 -0
  57. package/packages/core/src/agent/{PromptBuilder.ts → prompt-builder.ts} +21 -22
  58. package/packages/core/src/{harness → agent}/proof-packet.ts +16 -21
  59. package/packages/core/src/agent/providers/index.ts +35 -16
  60. package/packages/core/src/agent/reflector.ts +320 -0
  61. package/packages/core/src/agent/routing-intent.ts +22 -0
  62. package/packages/core/src/{harness → agent}/run-epoch.ts +4 -3
  63. package/packages/core/src/{harness → agent}/run-store.ts +142 -81
  64. package/packages/core/src/agent/{Service.ts → service.ts} +37 -26
  65. package/packages/core/src/agent/skill-selector.ts +374 -0
  66. package/packages/core/src/agent/stuck-loop.ts +209 -0
  67. package/packages/core/src/agent/{selectors/ToolSelector.ts → tool-selector.ts} +188 -178
  68. package/packages/core/src/{ace/Tracer.ts → agent/tracer.ts} +37 -27
  69. package/packages/core/src/api/createAgent.test.ts +139 -27
  70. package/packages/core/src/api/createAgent.ts +232 -44
  71. package/packages/core/src/artifacts/store.ts +162 -0
  72. package/packages/core/src/canvas/canvas-manager.ts +161 -0
  73. package/packages/core/src/canvas/canvas.test.ts +8 -4
  74. package/packages/core/src/canvas/emitter.ts +131 -80
  75. package/packages/core/src/canvas/index.ts +1 -3
  76. package/packages/core/src/channels/base.ts +9 -1
  77. package/packages/core/src/channels/discord.ts +5 -4
  78. package/packages/core/src/channels/manager.ts +122 -30
  79. package/packages/core/src/channels/slack.ts +5 -4
  80. package/packages/core/src/channels/telegram.ts +36 -6
  81. package/packages/core/src/channels/webchat.ts +11 -10
  82. package/packages/core/src/channels/whatsapp.ts +23 -7
  83. package/packages/core/src/config/index.ts +13 -2
  84. package/packages/core/src/config/loader.ts +76 -29
  85. package/packages/core/src/ethics/EthicsGuard.test.ts +90 -36
  86. package/packages/core/src/ethics/EthicsGuard.ts +51 -47
  87. package/packages/core/src/events/agent-bus.ts +44 -68
  88. package/packages/core/src/events/channel-narration.ts +150 -0
  89. package/packages/core/src/events/narration.ts +82 -0
  90. package/packages/core/src/events/tool-narration.ts +62 -0
  91. package/packages/core/src/gateway/delegation-groups.ts +258 -0
  92. package/packages/core/src/{harness → gateway}/durable-queue.ts +102 -42
  93. package/packages/core/src/{harness → gateway}/job-store.ts +85 -48
  94. package/packages/core/src/gateway/lane-queue.ts +173 -0
  95. package/packages/core/src/gateway/notification-inbox.ts +57 -0
  96. package/packages/core/src/gateway/server.ts +1 -1
  97. package/packages/core/src/harness/index.ts +46 -27
  98. package/packages/core/src/index.ts +33 -27
  99. package/packages/core/src/mcp/hot-reload.ts +32 -23
  100. package/packages/core/src/mcp/index.ts +6 -3
  101. package/packages/core/src/mcp/singleton.ts +1 -4
  102. package/packages/core/src/mcp/tool-sync.ts +138 -0
  103. package/packages/core/src/memory/Scratchpad.test.ts +39 -20
  104. package/packages/core/src/memory/Scratchpad.ts +27 -34
  105. package/packages/core/src/multimodal/vision-service.ts +44 -38
  106. package/packages/core/src/resilience/retry.ts +95 -0
  107. package/packages/core/src/scheduler/CronScheduler.ts +334 -287
  108. package/packages/core/src/scheduler/index.ts +9 -7
  109. package/packages/core/src/scheduler/integration.ts +46 -26
  110. package/packages/core/src/scheduler/scheduler.test.ts +9 -13
  111. package/packages/core/src/scheduler/types.ts +7 -2
  112. package/packages/core/src/security/Pairing.ts +1 -1
  113. package/packages/core/src/skills/bundled/a2ui/a2ui_dashboard/SKILL.md +176 -0
  114. package/packages/core/src/skills/bundled/a2ui/a2ui_form/SKILL.md +202 -0
  115. package/packages/core/src/skills/bundled/a2ui/a2ui_interactive/SKILL.md +206 -0
  116. package/packages/core/src/skills/bundled/agents/agent_spawner/SKILL.md +173 -0
  117. package/packages/core/src/skills/bundled/agents/memory_manager/SKILL.md +143 -0
  118. package/packages/core/src/skills/bundled/agents/research_and_remember/SKILL.md +139 -0
  119. package/packages/core/src/skills/bundled/agents/task_orchestrator/SKILL.md +98 -0
  120. package/packages/core/src/skills/bundled/api/api_client/SKILL.md +132 -0
  121. package/packages/core/src/skills/bundled/cli/cli_pipeline/SKILL.md +135 -0
  122. package/packages/core/src/skills/bundled/cli/cli_safe_exec/SKILL.md +125 -0
  123. package/packages/core/src/skills/bundled/cli/software_engineering/SKILL.md +23 -0
  124. package/packages/core/src/skills/bundled/cron_manager/SKILL.md +188 -0
  125. package/packages/core/src/skills/bundled/cron_reminder/SKILL.md +112 -0
  126. package/packages/core/src/skills/bundled/filesystem/file_manager/SKILL.md +118 -0
  127. package/packages/core/src/skills/bundled/filesystem/file_read_and_summarize/SKILL.md +109 -0
  128. package/packages/core/src/skills/bundled/filesystem/file_writer/SKILL.md +129 -0
  129. package/packages/core/src/skills/bundled/filesystem/workspace_file_operator/SKILL.md +22 -0
  130. package/packages/core/src/skills/bundled/office/office_document_manager/SKILL.md +262 -0
  131. package/packages/core/src/skills/bundled/search_knowledge/capability_discovery/SKILL.md +75 -0
  132. package/packages/core/src/skills/bundled/web/browser_automate/SKILL.md +120 -0
  133. package/packages/core/src/skills/bundled/web/browser_scrape/SKILL.md +109 -0
  134. package/packages/core/src/skills/bundled/web/web_monitor/SKILL.md +127 -0
  135. package/packages/core/src/skills/bundled/web/web_research/SKILL.md +119 -0
  136. package/packages/core/src/skills/bundled-data.generated.ts +731 -2678
  137. package/packages/core/src/skills/skills.test.ts +52 -11
  138. package/packages/core/src/{harness → storage}/boot-id.ts +5 -2
  139. package/packages/core/src/storage/bootstrap.ts +151 -0
  140. package/packages/core/src/storage/causal-events.ts +84 -0
  141. package/packages/core/src/storage/collections.ts +680 -0
  142. package/packages/core/src/storage/crypto.ts +205 -74
  143. package/packages/core/src/{harness/db-helpers.ts → storage/hive.ts} +63 -7
  144. package/packages/core/src/storage/hivedb.ts +61 -0
  145. package/packages/core/src/storage/index.ts +111 -18
  146. package/packages/core/src/storage/model-id.ts +53 -0
  147. package/packages/core/src/storage/onboarding.ts +540 -972
  148. package/packages/core/src/storage/reconcile.ts +238 -0
  149. package/packages/core/src/storage/seed.ts +572 -406
  150. package/packages/core/src/storage/usage.ts +285 -225
  151. package/packages/core/src/storage/user-email.ts +11 -0
  152. package/packages/core/src/swarm/AgentExecutor.ts +1 -1
  153. package/packages/core/src/swarm/EventBridge.ts +1 -1
  154. package/packages/core/src/swarm/index.ts +12 -9
  155. package/packages/core/src/tool-runtime/index.ts +146 -23
  156. package/packages/core/src/tool-runtime/tool-worker.ts +2 -2
  157. package/packages/core/src/tool-runtime/worker-tools.ts +27 -0
  158. package/packages/core/src/{canvas/a2ui-tools.ts → tools/a2ui/index.ts} +17 -8
  159. package/packages/core/src/tools/agents/get-available-models.ts +36 -54
  160. package/packages/core/src/tools/agents/index.ts +784 -292
  161. package/packages/core/src/tools/api/api-request.test.ts +164 -0
  162. package/packages/core/src/tools/api/api-request.ts +174 -0
  163. package/packages/core/src/tools/api/index.ts +16 -0
  164. package/packages/core/src/tools/cli/index.ts +4 -0
  165. package/packages/core/src/tools/core/index.ts +281 -112
  166. package/packages/core/src/tools/cron/index.ts +121 -124
  167. package/packages/core/src/tools/index.ts +63 -78
  168. package/packages/core/src/tools/office/office-escribir-xlsx.ts +3 -1
  169. package/packages/core/src/tools/types.ts +3 -1
  170. package/packages/core/src/tools/web/artifact-inspect.ts +23 -0
  171. package/packages/core/src/tools/web/browser-backend.ts +129 -0
  172. package/packages/core/src/tools/web/browser-screenshot.ts +26 -5
  173. package/packages/core/src/tools/web/browser-service.ts +80 -35
  174. package/packages/core/src/tools/web/browser-type.ts +3 -8
  175. package/packages/core/src/tools/web/index.ts +4 -4
  176. package/packages/core/src/tools/web/webview-backend.ts +412 -0
  177. package/packages/core/src/voice/index.ts +89 -63
  178. package/packages/core/src/workers/agent.worker.ts +2 -2
  179. package/packages/core/src/workers/workers.test.ts +3 -10
  180. package/scripts/bump-version.ts +248 -0
  181. package/scripts/generate-skill-bundle.ts +108 -0
  182. package/test/acceptance-checks.test.ts +403 -0
  183. package/test/agent-loop-terminal-synthesis.test.ts +32 -0
  184. package/test/browser-backend.test.ts +308 -0
  185. package/test/catalog-agents-stay-enabled.test.ts +117 -0
  186. package/test/causal-events.test.ts +117 -0
  187. package/test/compaction.test.ts +105 -0
  188. package/test/context-compiler.test.ts +269 -0
  189. package/test/curator.test.ts +130 -0
  190. package/test/durable-queue.test.ts +114 -0
  191. package/test/harness-barrel.test.ts +64 -0
  192. package/test/hive-helpers.test.ts +130 -0
  193. package/test/hivedb-search.test.ts +189 -0
  194. package/test/internal-turns.test.ts +166 -0
  195. package/test/job-idempotency.test.ts +68 -0
  196. package/test/job-retry-backoff.test.ts +184 -0
  197. package/test/job-store.test.ts +381 -0
  198. package/test/llm-retry.test.ts +97 -0
  199. package/test/memory-perf.test.ts +774 -0
  200. package/test/minimal-loadout.test.ts +78 -0
  201. package/test/model-catalog.test.ts +105 -0
  202. package/test/preload.ts +12 -0
  203. package/test/reflector.test.ts +320 -0
  204. package/test/retention-cap.test.ts +91 -0
  205. package/test/retired-capabilities-pruned.test.ts +192 -0
  206. package/test/run-store.test.ts +355 -0
  207. package/test/scratchpad.test.ts +74 -0
  208. package/test/secrets-durability.test.ts +119 -0
  209. package/test/seed-model-reseed.test.ts +155 -0
  210. package/test/setup-agent-seed.test.ts +264 -0
  211. package/test/tool-inventory.test.ts +65 -0
  212. package/test/tool-runtime.test.ts +258 -0
  213. package/test/tool-selector-runtime-tools.test.ts +117 -0
  214. package/test/toon.test.ts +429 -0
  215. package/tsconfig.json +2 -0
  216. package/packages/core/src/ace/Curator.ts +0 -158
  217. package/packages/core/src/ace/Reflector.ts +0 -200
  218. package/packages/core/src/ace/index.ts +0 -4
  219. package/packages/core/src/agent/AgentRunner.ts +0 -711
  220. package/packages/core/src/agent/ContextCompiler.ts +0 -567
  221. package/packages/core/src/agent/ContextGuard.ts +0 -91
  222. package/packages/core/src/agent/ConversationStore.ts +0 -254
  223. package/packages/core/src/agent/Hooks.ts +0 -166
  224. package/packages/core/src/agent/StuckLoop.ts +0 -133
  225. package/packages/core/src/agent/providers/LLMClient.ts +0 -149
  226. package/packages/core/src/agent/providers/anthropic.ts +0 -212
  227. package/packages/core/src/agent/providers/openai-compat.ts +0 -231
  228. package/packages/core/src/agent/selectors/PlaybookSelector.ts +0 -121
  229. package/packages/core/src/agent/selectors/SkillSelector.ts +0 -322
  230. package/packages/core/src/agent/selectors/index.ts +0 -6
  231. package/packages/core/src/auth/auth.ts +0 -121
  232. package/packages/core/src/auth/index.ts +0 -1
  233. package/packages/core/src/canvas/CanvasManager.ts +0 -390
  234. package/packages/core/src/canvas/canvas-tools.ts +0 -448
  235. package/packages/core/src/harness/collections.ts +0 -98
  236. package/packages/core/src/harness/goal-verifier.ts +0 -141
  237. package/packages/core/src/harness/harness.test.ts +0 -236
  238. package/packages/core/src/harness/reconcile.ts +0 -149
  239. package/packages/core/src/mcp/MCPToolAdapter.ts +0 -176
  240. package/packages/core/src/multimodal/VisionService.ts +0 -293
  241. package/packages/core/src/scheduler/dag/AgentExecutor.ts +0 -53
  242. package/packages/core/src/scheduler/dag/DAGScheduler.ts +0 -250
  243. package/packages/core/src/scheduler/dag/EventBridge.ts +0 -122
  244. package/packages/core/src/scheduler/dag/TaskGraph.ts +0 -192
  245. package/packages/core/src/scheduler/dag/TaskNode.ts +0 -97
  246. package/packages/core/src/scheduler/dag/TaskResult.ts +0 -22
  247. package/packages/core/src/scheduler/dag/errors.ts +0 -37
  248. package/packages/core/src/scheduler/dag/index.ts +0 -26
  249. package/packages/core/src/scheduler/dag/presets/ResearchPreset.ts +0 -97
  250. package/packages/core/src/scheduler/dag/strategies/ParallelStrategy.ts +0 -21
  251. package/packages/core/src/scheduler/dag/strategies/PriorityStrategy.ts +0 -46
  252. package/packages/core/src/storage/HiveDBStorage.ts +0 -64
  253. package/packages/core/src/storage/SQLiteStorage.ts +0 -414
  254. package/packages/core/src/storage/hiveSeed.ts +0 -308
  255. package/packages/core/src/storage/hiveStorage.test.ts +0 -38
  256. package/packages/core/src/storage/schema.ts +0 -689
  257. package/packages/core/src/storage/storage.test.ts +0 -37
  258. package/packages/core/src/swarm/AgentBus.ts +0 -460
  259. package/packages/core/src/swarm/EventBus.ts +0 -169
  260. package/packages/core/src/swarm/WorkerPool.ts +0 -236
  261. package/packages/core/src/tools/bridge-events.ts +0 -26
  262. package/packages/core/src/tools/canvas/index.ts +0 -375
  263. package/packages/core/src/tools/codebridge/index.ts +0 -342
  264. package/packages/core/src/tools/meeting/index.ts +0 -353
  265. package/packages/core/src/tools/projects/index.ts +0 -37
  266. package/packages/core/src/tools/projects/project-create.ts +0 -94
  267. package/packages/core/src/tools/projects/project-done.ts +0 -66
  268. package/packages/core/src/tools/projects/project-fail.ts +0 -66
  269. package/packages/core/src/tools/projects/project-list.ts +0 -96
  270. package/packages/core/src/tools/projects/project-update.ts +0 -72
  271. package/packages/core/src/tools/projects/task-create.ts +0 -68
  272. package/packages/core/src/tools/projects/task-evaluate.ts +0 -93
  273. package/packages/core/src/tools/projects/task-update.ts +0 -93
  274. package/packages/core/src/tools/voice/index.ts +0 -104
  275. package/packages/core/src/tools/web/api-request.test.ts +0 -170
  276. package/packages/core/src/tools/web/api-request.ts +0 -239
  277. package/test/setup-db.ts +0 -216
  278. /package/packages/core/src/agent/{NativeTools.ts → native-tools.ts} +0 -0
@@ -0,0 +1,23 @@
1
+ import type { Tool } from "../types";
2
+ import { inspectArtifact } from "../../artifacts/store";
3
+
4
+ export const artifactInspectTool: Tool = {
5
+ name: "artifact_inspect",
6
+ description: "Inspect managed artifact metadata, integrity, MIME type and dimensions without returning or modifying its binary content.",
7
+ parameters: {
8
+ type: "object",
9
+ properties: {
10
+ artifactId: {
11
+ type: "string",
12
+ description: "Managed artifact identifier returned by a Hive tool.",
13
+ },
14
+ },
15
+ required: ["artifactId"],
16
+ },
17
+ execute: async (params, config) => {
18
+ const artifactId = String(params.artifactId ?? "").trim();
19
+ if (!artifactId) return { ok: false, error: "artifactId is required" };
20
+ const userId = config?.configurable?.user_id as string | undefined;
21
+ return inspectArtifact(artifactId, { userId });
22
+ },
23
+ };
@@ -0,0 +1,129 @@
1
+ /**
2
+ * BrowserBackend — el contrato que consumen las browser tools.
3
+ *
4
+ * Hay dos implementaciones con perfiles opuestos:
5
+ *
6
+ * - `AgentBrowserBackend` (browser-service.ts): habla con el CLI de
7
+ * agent-browser por subproceso. Maneja Chrome de verdad, corre headless y
8
+ * por lo tanto sirve en Docker y en un servidor sin display. El costo es
9
+ * un `Bun.spawn` por operación —medido en ~68 ms de piso— más una
10
+ * instalación diferida de ~75 MB y la descarga de Chrome.
11
+ *
12
+ * - `WebViewBackend` (webview-backend.ts): usa `Bun.WebView`, in-process.
13
+ * Sin instalación, sin subprocesos, ~0.25 ms por `evaluate`. Necesita un
14
+ * entorno gráfico (WebKitGTK en Linux, WebKit del sistema en macOS), así
15
+ * que no sirve headless.
16
+ *
17
+ * El default sigue siendo agent-browser: es el único de los dos que funciona
18
+ * donde suele correr el gateway. WebView se elige explícitamente.
19
+ */
20
+
21
+ export interface ScreenshotOptions {
22
+ encoding?: "blob" | "buffer" | "base64" | "shmem";
23
+ format?: "png" | "jpeg" | "webp";
24
+ quality?: number;
25
+ clip?: { x: number; y: number; width: number; height: number; scale: number };
26
+ }
27
+
28
+ export interface SnapshotOptions {
29
+ /** Colapsa nodos sin nombre accesible y recorta el texto largo. Default: true. */
30
+ compact?: boolean;
31
+ /** Profundidad máxima del árbol. */
32
+ depth?: number;
33
+ /** Sólo elementos accionables (links, botones, inputs...). */
34
+ interactiveOnly?: boolean;
35
+ }
36
+
37
+ /**
38
+ * La superficie que las tools de `tools/web/` realmente usan. Se mantuvo
39
+ * deliberadamente chica: cualquier método que se agregue acá hay que
40
+ * implementarlo en los dos backends.
41
+ */
42
+ export interface BrowserBackend {
43
+ readonly url: string;
44
+ readonly title: string;
45
+ readonly loading: boolean;
46
+
47
+ navigate(url: string): Promise<void>;
48
+ evaluate<T = unknown>(script: string): Promise<T>;
49
+ screenshot(options?: ScreenshotOptions): Promise<string>;
50
+ /** Árbol de accesibilidad en texto — lo que ve el modelo en vez del HTML crudo. */
51
+ snapshot(options?: SnapshotOptions): Promise<string>;
52
+ click(selector: string, options?: Record<string, unknown>): Promise<void>;
53
+ type(text: string): Promise<void>;
54
+ typeIn(selector: string, text: string): Promise<void>;
55
+ fill(selector: string, text: string): Promise<void>;
56
+ press(key: string, options?: { modifiers?: string[] }): Promise<void>;
57
+ scroll(dx: number, dy: number): Promise<void>;
58
+ scrollTo(selector: string, options?: { behavior?: "smooth" | "instant" }): Promise<void>;
59
+ back(): Promise<void>;
60
+ forward(): Promise<void>;
61
+ reload(): Promise<void>;
62
+ resize(width: number, height: number): Promise<void>;
63
+ /** Captura de un elemento puntual; el backend puede recortar sobre el viewport. */
64
+ screenshotElement(selector: string): Promise<string>;
65
+ close(): void;
66
+ }
67
+
68
+ export type BrowserBackendKind = "agent-browser" | "webview";
69
+
70
+ /** `auto` resuelve a webview si el runtime lo soporta; si no, agent-browser. */
71
+ export type BrowserBackendPreference = BrowserBackendKind | "auto";
72
+
73
+ /** Motor que usa `Bun.WebView` por debajo. */
74
+ export type WebViewEngine = "webkit" | "chrome";
75
+
76
+ const CHROME_PATHS = [
77
+ "/usr/bin/google-chrome",
78
+ "/usr/bin/google-chrome-stable",
79
+ "/usr/bin/chromium",
80
+ "/usr/bin/chromium-browser",
81
+ "/snap/bin/chromium",
82
+ "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome",
83
+ "/Applications/Chromium.app/Contents/MacOS/Chromium",
84
+ "C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe",
85
+ "C:\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe",
86
+ ];
87
+
88
+ /** Chrome instalado en el sistema — `Bun.WebView` con motor chrome lo necesita. */
89
+ export function findChrome(): string | null {
90
+ if (process.env.BUN_CHROME_PATH) return process.env.BUN_CHROME_PATH;
91
+ const { existsSync } = require("node:fs") as typeof import("node:fs");
92
+ for (const candidate of CHROME_PATHS) {
93
+ if (existsSync(candidate)) return candidate;
94
+ }
95
+ // Último recurso: lo que esté en el PATH del usuario.
96
+ const home = process.env.HOME;
97
+ if (home) {
98
+ for (const name of ["google-chrome", "chromium"]) {
99
+ const local = `${home}/.local/bin/${name}`;
100
+ if (existsSync(local)) return local;
101
+ }
102
+ }
103
+ return null;
104
+ }
105
+
106
+ /**
107
+ * Motor a usar. WebKit no tiene dependencias externas pero sólo existe en macOS;
108
+ * Chrome corre headless en cualquier lado —incluido Docker— siempre que el
109
+ * binario esté instalado.
110
+ */
111
+ export function resolveWebViewEngine(): WebViewEngine | null {
112
+ if (process.platform === "darwin") return "webkit";
113
+ return findChrome() ? "chrome" : null;
114
+ }
115
+
116
+ /** `Bun.WebView` existe desde Bun 1.3; además hace falta un motor utilizable. */
117
+ export function isWebViewSupported(): boolean {
118
+ if (typeof (globalThis as { Bun?: { WebView?: unknown } }).Bun?.WebView !== "function") return false;
119
+ return resolveWebViewEngine() !== null;
120
+ }
121
+
122
+ export function resolveBackendKind(
123
+ preference: BrowserBackendPreference | undefined,
124
+ ): BrowserBackendKind {
125
+ const wanted = process.env.HIVE_BROWSER_BACKEND ?? preference ?? "agent-browser";
126
+ if (wanted === "webview") return "webview";
127
+ if (wanted === "auto") return isWebViewSupported() ? "webview" : "agent-browser";
128
+ return "agent-browser";
129
+ }
@@ -9,6 +9,7 @@
9
9
  import type { Tool } from "../types.ts";
10
10
  import { logger } from "../../utils/logger.ts";
11
11
  import { getBrowserService, screenshotElement } from "./browser-service.ts";
12
+ import { createArtifact } from "../../artifacts/store.ts";
12
13
 
13
14
  const log = logger.child("browser-screenshot");
14
15
 
@@ -53,7 +54,7 @@ export const browserScreenshotTool: Tool = {
53
54
  },
54
55
  required: [],
55
56
  },
56
- execute: async (params: Record<string, unknown>) => {
57
+ execute: async (params: Record<string, unknown>, config?: any) => {
57
58
  const url = params.url as string | undefined;
58
59
  const fullPage = (params.fullPage as boolean) ?? false;
59
60
  const selector = params.selector as string | undefined;
@@ -99,14 +100,34 @@ export const browserScreenshotTool: Tool = {
99
100
  }
100
101
 
101
102
  const currentUrl = view.url;
102
- log.info(`Screenshot captured: ${currentUrl} (${screenshot.length} base64 chars, ${format})`);
103
+ const bytes = Buffer.from(screenshot, "base64");
104
+ const effectiveFormat = selector ? "png" : format;
105
+ const mimeType = effectiveFormat === "png" ? "image/png" : "image/jpeg";
106
+ const configurable = config?.configurable ?? {};
107
+ const artifact = await createArtifact({
108
+ bytes,
109
+ mimeType,
110
+ kind: "browser_screenshot",
111
+ userId: String(configurable.user_id ?? ""),
112
+ runId: configurable.run_id ? String(configurable.run_id) : null,
113
+ taskId: configurable.task_id ? String(configurable.task_id) : null,
114
+ rootDir: configurable.artifact_dir ? String(configurable.artifact_dir) : undefined,
115
+ width,
116
+ height,
117
+ });
118
+ log.info(`Screenshot stored as artifact ${artifact.id} (${artifact.size} bytes, ${mimeType})`);
103
119
 
104
120
  return {
105
121
  ok: true,
106
122
  url: currentUrl,
107
- screenshot,
108
- format,
109
- encoding: "base64",
123
+ artifact_id: artifact.id,
124
+ kind: artifact.kind,
125
+ mime_type: artifact.mime_type,
126
+ size: artifact.size,
127
+ sha256: artifact.sha256,
128
+ status: artifact.status,
129
+ expires_at: artifact.expires_at,
130
+ format: effectiveFormat,
110
131
  fullPage,
111
132
  selector,
112
133
  viewport: { width, height },
@@ -1,11 +1,18 @@
1
1
  /**
2
- * BrowserService — Browser automation via agent-browser CLI (Rust).
2
+ * BrowserService — automatización de navegador, con backend intercambiable.
3
3
  *
4
- * Flujo:
4
+ * `AgentBrowserBackend` (este archivo) habla con el CLI de agent-browser por
5
+ * subproceso: maneja Chrome de verdad y corre headless, así que es el único que
6
+ * sirve en Docker o en un servidor sin display. Por eso sigue siendo el default.
7
+ *
8
+ * `WebViewBackend` (webview-backend.ts) usa `Bun.WebView` in-process — sin
9
+ * instalación ni subprocesos, mucho más rápido — pero necesita entorno gráfico.
10
+ * Se elige con `tools.browser.backend` o `HIVE_BROWSER_BACKEND`.
11
+ *
12
+ * Flujo del backend por CLI:
5
13
  * 1. Detecta si agent-browser está instalado (lazy install en primer uso).
6
14
  * 2. Ejecuta comandos via CLI con --json para output estructurado.
7
15
  * 3. El daemon de agent-browser maneja Chrome internamente via CDP.
8
- * 4. Las herramientas de browser usan AgentBrowserView (API compatible con CDPClient).
9
16
  */
10
17
 
11
18
  import { logger } from "../../utils/logger.ts";
@@ -13,6 +20,13 @@ import type { Config } from "../../config/loader.ts";
13
20
  import { existsSync, mkdirSync, readFileSync, rmSync } from "fs";
14
21
  import { homedir, tmpdir } from "os";
15
22
  import { dirname, join, resolve } from "path";
23
+ import {
24
+ resolveBackendKind,
25
+ type BrowserBackend,
26
+ type BrowserBackendKind,
27
+ type ScreenshotOptions,
28
+ type SnapshotOptions,
29
+ } from "./browser-backend.ts";
16
30
 
17
31
  const log = logger.child("browser-service");
18
32
 
@@ -117,7 +131,7 @@ async function ensureChromeInstalled(): Promise<void> {
117
131
 
118
132
  // ─── AgentBrowserView (API compatible con CDPClient) ──────────────────────────
119
133
 
120
- export class AgentBrowserView {
134
+ export class AgentBrowserView implements BrowserBackend {
121
135
  private sessionName: string;
122
136
  private _url = "";
123
137
 
@@ -162,12 +176,7 @@ export class AgentBrowserView {
162
176
  return res.data?.result as T;
163
177
  }
164
178
 
165
- async screenshot(options?: {
166
- encoding?: "blob" | "buffer" | "base64" | "shmem";
167
- format?: "png" | "jpeg" | "webp";
168
- quality?: number;
169
- clip?: { x: number; y: number; width: number; height: number; scale: number };
170
- }): Promise<string> {
179
+ async screenshot(options?: ScreenshotOptions): Promise<string> {
171
180
  // Build args
172
181
  const args: string[] = ["screenshot"];
173
182
 
@@ -178,6 +187,11 @@ export class AgentBrowserView {
178
187
  args.push("--screenshot-quality", String(options.quality));
179
188
  }
180
189
 
190
+ // If clip/selector is provided, agent-browser screenshot accepts a positional selector
191
+ // For element screenshots, we can pass a selector as first positional arg
192
+ // But we don't have selector in options here — the old CDPClient didn't use it either
193
+ // screenshotElement helper handles element-specific screenshots
194
+
181
195
  const res = await this.run(args);
182
196
  if (!res.success) throw new Error(res.error || "screenshot failed");
183
197
 
@@ -259,8 +273,21 @@ export class AgentBrowserView {
259
273
  if (!res.success) throw new Error(res.error || "resize failed");
260
274
  }
261
275
 
276
+ /** Screenshot recortado a un elemento — agent-browser acepta el selector posicional. */
277
+ async screenshotElement(selector: string): Promise<string> {
278
+ const res = await this.run(["screenshot", selector]);
279
+ if (!res.success) throw new Error(res.error || `screenshot failed: ${selector}`);
280
+
281
+ const path = res.data?.path as string;
282
+ if (!path) throw new Error("screenshot did not return a path");
283
+
284
+ const base64 = Buffer.from(readFileSync(path)).toString("base64");
285
+ try { rmSync(path); } catch { /* ignore */ }
286
+ return base64;
287
+ }
288
+
262
289
  /** Capture accessibility tree snapshot (compact, AI-optimized). ~200-600 chars vs ~3000+ innerText. */
263
- async snapshot(options?: { compact?: boolean; depth?: number; interactiveOnly?: boolean }): Promise<string> {
290
+ async snapshot(options?: SnapshotOptions): Promise<string> {
264
291
  const args = ["snapshot"];
265
292
  if (options?.compact !== false) args.push("-c");
266
293
  if (options?.depth) args.push("-d", String(options.depth));
@@ -321,11 +348,17 @@ export type LaunchSpec = { kind: "remote"; cdpUrl: string };
321
348
 
322
349
  // ─── BrowserService (singleton) ───────────────────────────────────────────────
323
350
 
324
- export type BrowserView = AgentBrowserView;
351
+ /** Alias histórico: las tools sólo dependen del contrato, no de la implementación. */
352
+ export type BrowserView = BrowserBackend;
353
+
354
+ /** Re-export para que quien importe el servicio no tenga que conocer el módulo del contrato. */
355
+ export type { BrowserBackend, BrowserBackendKind } from "./browser-backend.ts";
356
+ export { isWebViewSupported, resolveBackendKind } from "./browser-backend.ts";
325
357
 
326
- let _client: AgentBrowserView | null = null;
358
+ let _client: BrowserBackend | null = null;
327
359
  let _available = false;
328
360
  let _launching = false;
361
+ let _kind: BrowserBackendKind = "agent-browser";
329
362
 
330
363
  export class BrowserService {
331
364
  private static instance: BrowserService | null = null;
@@ -352,6 +385,17 @@ export class BrowserService {
352
385
  return false;
353
386
  }
354
387
 
388
+ _kind = resolveBackendKind(b?.backend);
389
+
390
+ if (_kind === "webview") {
391
+ // No hay nada que instalar ni que descargar: el WebView se crea al primer
392
+ // uso. Si el entorno no lo soporta, ensureView() falla ahí y el servicio
393
+ // queda no disponible, igual que cuando agent-browser no arranca.
394
+ _available = true;
395
+ log.info("✅ Backend de navegador: Bun.WebView (in-process, sin Chrome)");
396
+ return true;
397
+ }
398
+
355
399
  const installed = await isAgentBrowserInstalled();
356
400
 
357
401
  if (!installed) {
@@ -387,8 +431,13 @@ export class BrowserService {
387
431
  }
388
432
  _launching = true;
389
433
  try {
390
- const sessionName = this.config.tools?.browser?.sessionName ?? DEFAULT_SESSION_NAME;
391
- _client = new AgentBrowserView(sessionName);
434
+ if (_kind === "webview") {
435
+ const { WebViewBackend } = await import("./webview-backend.ts");
436
+ _client = new WebViewBackend({ show: this.config.tools?.browser?.headless === false });
437
+ } else {
438
+ const sessionName = this.config.tools?.browser?.sessionName ?? DEFAULT_SESSION_NAME;
439
+ _client = new AgentBrowserView(sessionName);
440
+ }
392
441
  log.info("✅ Browser abierto — el usuario verá las acciones del agente");
393
442
  return true;
394
443
  } catch (err) {
@@ -401,20 +450,25 @@ export class BrowserService {
401
450
  }
402
451
  }
403
452
 
404
- async getView(): Promise<AgentBrowserView | null> {
453
+ async getView(): Promise<BrowserBackend | null> {
405
454
  if (!_available) return null;
406
455
  await this._ensureLaunched();
407
456
  return _client;
408
457
  }
409
458
 
410
- getViewSync(): AgentBrowserView | null {
459
+ getViewSync(): BrowserBackend | null {
411
460
  return _client;
412
461
  }
413
462
 
414
- async getPage(): Promise<AgentBrowserView | null> {
463
+ async getPage(): Promise<BrowserBackend | null> {
415
464
  return this.getView();
416
465
  }
417
466
 
467
+ /** Qué backend quedó activo — lo reporta `hive doctor` y los tests. */
468
+ getBackendKind(): BrowserBackendKind {
469
+ return _kind;
470
+ }
471
+
418
472
  isAvailable(): boolean {
419
473
  return _available;
420
474
  }
@@ -423,8 +477,8 @@ export class BrowserService {
423
477
  return _available && _client !== null;
424
478
  }
425
479
 
426
- getInfo(): { running: boolean } {
427
- return { running: this.isRunning() };
480
+ getInfo(): { running: boolean; backend: BrowserBackendKind } {
481
+ return { running: this.isRunning(), backend: _kind };
428
482
  }
429
483
 
430
484
  async stop(): Promise<void> {
@@ -457,7 +511,7 @@ export function getBrowserService(): BrowserService | null {
457
511
  // ─── Helpers (misma API que antes) ───────────────────────────────────────────
458
512
 
459
513
  export async function waitForSelector(
460
- view: AgentBrowserView,
514
+ view: BrowserBackend,
461
515
  selector: string,
462
516
  timeout = 30000
463
517
  ): Promise<void> {
@@ -471,7 +525,7 @@ export async function waitForSelector(
471
525
  }
472
526
 
473
527
  export async function waitForCondition(
474
- view: AgentBrowserView,
528
+ view: BrowserBackend,
475
529
  expression: string,
476
530
  timeout = 30000
477
531
  ): Promise<void> {
@@ -485,19 +539,10 @@ export async function waitForCondition(
485
539
  }
486
540
 
487
541
  export async function screenshotElement(
488
- view: AgentBrowserView,
542
+ view: BrowserBackend,
489
543
  selector: string
490
544
  ): Promise<string> {
491
- const res = await (view as any).run(["screenshot", selector]);
492
- if (!res.success) throw new Error(res.error || `screenshot failed: ${selector}`);
493
-
494
- const path = res.data?.path as string;
495
- if (!path) throw new Error("screenshot did not return a path");
496
-
497
- const data = readFileSync(path);
498
- const base64 = Buffer.from(data).toString("base64");
499
-
500
- try { rmSync(path); } catch { /* ignore */ }
501
-
502
- return base64;
545
+ // Antes esto hacía `(view as any).run([...])`, atándose a la implementación por
546
+ // CLI: con dos backends el recorte es responsabilidad de cada uno.
547
+ return view.screenshotElement(selector);
503
548
  }
@@ -68,17 +68,12 @@ export const browserTypeTool: Tool = {
68
68
  await Bun.sleep(500);
69
69
  }
70
70
 
71
- // click(selector) waits for actionability then focuses the element
72
- await view.click(selector, { timeout });
73
-
74
71
  if (clear) {
75
- // Ctrl+A Backspace to clear existing content
76
- await view.press("a", { modifiers: ["Control"] });
77
- await view.press("Backspace");
72
+ await (view as any).fill(selector, text);
73
+ } else {
74
+ await (view as any).typeIn(selector, text);
78
75
  }
79
76
 
80
- await view.type(text);
81
-
82
77
  const currentUrl = view.url;
83
78
  log.info(`Type successful: "${text.substring(0, 50)}${text.length > 50 ? "..." : ""}" into ${selector}`);
84
79
 
@@ -1,13 +1,12 @@
1
1
  /**
2
2
  * Web Tools - Browser automation + Web utilities
3
3
  *
4
- * Browser tools use Puppeteer/Chromium (auto-managed).
4
+ * Browser tools use agent-browser (Rust CLI, auto-managed).
5
5
  */
6
6
 
7
7
  import type { Tool } from "../types.ts";
8
8
  import { webSearchTool } from "./web-search.ts";
9
9
  import { webFetchTool } from "./web-fetch.ts";
10
- import { apiRequestTool } from "./api-request.ts";
11
10
  import { browserNavigateTool } from "./browser-navigate.ts";
12
11
  import { browserScreenshotTool } from "./browser-screenshot.ts";
13
12
  import { browserClickTool } from "./browser-click.ts";
@@ -15,12 +14,12 @@ import { browserTypeTool } from "./browser-type.ts";
15
14
  import { browserExtractTool } from "./browser-extract.ts";
16
15
  import { browserScriptTool } from "./browser-script.ts";
17
16
  import { browserWaitTool } from "./browser-wait.ts";
17
+ import { artifactInspectTool } from "./artifact-inspect.ts";
18
18
 
19
19
  export function createTools(): Tool[] {
20
20
  return [
21
21
  webSearchTool,
22
22
  webFetchTool,
23
- apiRequestTool,
24
23
  browserNavigateTool,
25
24
  browserScreenshotTool,
26
25
  browserClickTool,
@@ -28,12 +27,12 @@ export function createTools(): Tool[] {
28
27
  browserExtractTool,
29
28
  browserScriptTool,
30
29
  browserWaitTool,
30
+ artifactInspectTool,
31
31
  ];
32
32
  }
33
33
 
34
34
  export * from "./web-search.ts";
35
35
  export * from "./web-fetch.ts";
36
- export * from "./api-request.ts";
37
36
  export * from "./browser-navigate.ts";
38
37
  export * from "./browser-screenshot.ts";
39
38
  export * from "./browser-click.ts";
@@ -42,3 +41,4 @@ export * from "./browser-extract.ts";
42
41
  export * from "./browser-script.ts";
43
42
  export * from "./browser-wait.ts";
44
43
  export * from "./browser-service.ts";
44
+ export * from "./artifact-inspect.ts";