@johpaz/hive-sdk 0.1.6 → 0.3.0

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 (238) hide show
  1. package/CHANGELOG.md +441 -0
  2. package/README.md +21 -3
  3. package/package.json +27 -5
  4. package/packages/core/src/agent/acceptance-checks.ts +9 -9
  5. package/packages/core/src/agent/agent-catalog.ts +82 -25
  6. package/packages/core/src/agent/agent-loop.ts +115 -26
  7. package/packages/core/src/agent/capability-search.ts +2 -2
  8. package/packages/core/src/agent/catalog-selector.ts +4 -4
  9. package/packages/core/src/agent/compaction.ts +30 -10
  10. package/packages/core/src/agent/context-compiler.ts +63 -36
  11. package/packages/core/src/agent/conversation-store.ts +167 -9
  12. package/packages/core/src/agent/curator.ts +16 -7
  13. package/packages/core/src/agent/delegation-runtime.ts +5 -5
  14. package/packages/core/src/agent/goal-runner.ts +9 -9
  15. package/packages/core/src/agent/index.ts +1 -0
  16. package/packages/core/src/agent/llm-client.ts +98 -37
  17. package/packages/core/src/agent/llm-providers/anthropic.ts +4 -4
  18. package/packages/core/src/agent/llm-providers/deepseek.ts +1 -1
  19. package/packages/core/src/agent/llm-providers/gemini.ts +4 -4
  20. package/packages/core/src/agent/llm-providers/groq.ts +1 -1
  21. package/packages/core/src/agent/llm-providers/hiveagents.ts +3 -3
  22. package/packages/core/src/agent/llm-providers/interface.ts +2 -2
  23. package/packages/core/src/agent/llm-providers/kimi.ts +1 -1
  24. package/packages/core/src/agent/llm-providers/minimax.ts +1 -1
  25. package/packages/core/src/agent/llm-providers/mistral.ts +1 -1
  26. package/packages/core/src/agent/llm-providers/modelscope.ts +1 -1
  27. package/packages/core/src/agent/llm-providers/nvidia.ts +40 -1
  28. package/packages/core/src/agent/llm-providers/ollama.ts +4 -4
  29. package/packages/core/src/agent/llm-providers/openai-compat-base.ts +47 -7
  30. package/packages/core/src/agent/llm-providers/openai.ts +1 -1
  31. package/packages/core/src/agent/llm-providers/opencode-go.ts +1 -1
  32. package/packages/core/src/agent/llm-providers/openrouter.ts +1 -1
  33. package/packages/core/src/agent/llm-providers/qwen.ts +1 -1
  34. package/packages/core/src/agent/llm-providers/z-ai.ts +1 -1
  35. package/packages/core/src/agent/mcp-result-normalizer.ts +192 -0
  36. package/packages/core/src/agent/playbook-selector.ts +22 -7
  37. package/packages/core/src/agent/prompt-builder.ts +5 -5
  38. package/packages/core/src/agent/proof-packet.ts +5 -5
  39. package/packages/core/src/agent/providers/index.ts +39 -4
  40. package/packages/core/src/agent/realtime-providers/gemini-live.ts +238 -0
  41. package/packages/core/src/agent/realtime-providers/index.ts +29 -0
  42. package/packages/core/src/agent/realtime-providers/interface.ts +108 -0
  43. package/packages/core/src/agent/reflector.ts +38 -15
  44. package/packages/core/src/agent/run-store.ts +8 -8
  45. package/packages/core/src/agent/service.ts +10 -10
  46. package/packages/core/src/agent/skill-selector.ts +6 -6
  47. package/packages/core/src/agent/thread-id.ts +71 -0
  48. package/packages/core/src/agent/thread-store.ts +293 -0
  49. package/packages/core/src/agent/tool-selector.ts +9 -5
  50. package/packages/core/src/agent/tracer.ts +5 -5
  51. package/packages/core/src/api/createAgent.ts +67 -2
  52. package/packages/core/src/artifacts/index.ts +15 -0
  53. package/packages/core/src/artifacts/store.ts +161 -5
  54. package/packages/core/src/canvas/emitter.ts +2 -2
  55. package/packages/core/src/canvas/index.ts +9 -0
  56. package/packages/core/src/channels/telegram.ts +1 -1
  57. package/packages/core/src/channels/webchat.ts +1 -1
  58. package/packages/core/src/config/loader.ts +14 -5
  59. package/packages/core/src/ethics/EthicsGuard.ts +7 -1
  60. package/packages/core/src/events/agent-bus.ts +3 -3
  61. package/packages/core/src/events/channel-narration.ts +3 -3
  62. package/packages/core/src/events/event-bus.ts +1 -1
  63. package/packages/core/src/events/index.ts +18 -0
  64. package/packages/core/src/events/narration.ts +3 -3
  65. package/packages/core/src/events/tool-narration.ts +4 -0
  66. package/packages/core/src/gateway/channel-notify.ts +103 -6
  67. package/packages/core/src/gateway/delegation-groups.ts +4 -4
  68. package/packages/core/src/gateway/durable-queue.ts +18 -6
  69. package/packages/core/src/gateway/index.ts +3 -0
  70. package/packages/core/src/gateway/job-store.ts +11 -5
  71. package/packages/core/src/gateway/notification-inbox.ts +2 -2
  72. package/packages/core/src/gateway/server.ts +2 -2
  73. package/packages/core/src/harness/executors.ts +493 -0
  74. package/packages/core/src/harness/index.ts +12 -2
  75. package/packages/core/src/hooks/index.ts +203 -0
  76. package/packages/core/src/images/index.ts +161 -0
  77. package/packages/core/src/index.ts +1 -0
  78. package/packages/core/src/mcp/MCPClient.ts +3 -3
  79. package/packages/core/src/mcp/hot-reload.ts +5 -5
  80. package/packages/core/src/mcp/tool-sync.ts +5 -5
  81. package/packages/core/src/mcp/transports/index.ts +2 -2
  82. package/packages/core/src/mcp/transports/sse.ts +1 -1
  83. package/packages/core/src/models/index.ts +36 -0
  84. package/packages/core/src/multimodal/index.ts +2 -2
  85. package/packages/core/src/multimodal/vision-service.ts +51 -19
  86. package/packages/core/src/plugins/loader.ts +4 -1
  87. package/packages/core/src/resilience/circuit-breaker.ts +16 -5
  88. package/packages/core/src/resilience/index.ts +13 -0
  89. package/packages/core/src/resilience/retry.ts +1 -1
  90. package/packages/core/src/scheduler/CronScheduler.ts +54 -27
  91. package/packages/core/src/scheduler/cron/expression.ts +165 -0
  92. package/packages/core/src/scheduler/cron/index.ts +10 -0
  93. package/packages/core/src/scheduler/cron/job.ts +339 -0
  94. package/packages/core/src/scheduler/cron/next-run.ts +121 -0
  95. package/packages/core/src/scheduler/cron/zoned-time.ts +138 -0
  96. package/packages/core/src/scheduler/index.ts +21 -3
  97. package/packages/core/src/scheduler/integration.ts +25 -14
  98. package/packages/core/src/scheduler/types.ts +3 -18
  99. package/packages/core/src/services/agents.ts +268 -0
  100. package/packages/core/src/services/cron.ts +257 -0
  101. package/packages/core/src/services/endpoints.ts +289 -0
  102. package/packages/core/src/services/ethics.ts +107 -0
  103. package/packages/core/src/services/images.ts +212 -0
  104. package/packages/core/src/services/index.ts +112 -0
  105. package/packages/core/src/services/mcp.ts +201 -0
  106. package/packages/core/src/services/memory.ts +133 -0
  107. package/packages/core/src/services/models.ts +179 -0
  108. package/packages/core/src/services/providers.ts +152 -0
  109. package/packages/core/src/services/setup.ts +222 -0
  110. package/packages/core/src/services/skills.ts +241 -0
  111. package/packages/core/src/services/swarms.ts +307 -0
  112. package/packages/core/src/services/tools.ts +106 -0
  113. package/packages/core/src/sessions/index.ts +268 -0
  114. package/packages/core/src/sessions/resolve.ts +108 -0
  115. package/packages/core/src/skills/SkillLoader.ts +8 -1
  116. package/packages/core/src/skills/bundled/artifacts/artifact_reader/SKILL.md +105 -0
  117. package/packages/core/src/skills/bundled/cron_manager/SKILL.md +21 -11
  118. package/packages/core/src/skills/bundled/images/image_editor/SKILL.md +120 -0
  119. package/packages/core/src/skills/bundled/web/browser_automate/SKILL.md +12 -3
  120. package/packages/core/src/skills/bundled/web/browser_scrape/SKILL.md +22 -7
  121. package/packages/core/src/skills/bundled-data.generated.ts +110 -12
  122. package/packages/core/src/storage/bootstrap.ts +107 -12
  123. package/packages/core/src/storage/causal-events.ts +1 -1
  124. package/packages/core/src/storage/collections.ts +138 -2
  125. package/packages/core/src/storage/crypto.ts +35 -4
  126. package/packages/core/src/storage/hive.ts +1 -1
  127. package/packages/core/src/storage/hivedb.ts +10 -1
  128. package/packages/core/src/storage/index.ts +2 -1
  129. package/packages/core/src/storage/onboarding.ts +61 -45
  130. package/packages/core/src/storage/reconcile.ts +11 -6
  131. package/packages/core/src/storage/seed.ts +191 -23
  132. package/packages/core/src/storage/usage.ts +3 -3
  133. package/packages/core/src/swarm/AgentExecutor.ts +2 -2
  134. package/packages/core/src/swarm/Coordinator.ts +8 -8
  135. package/packages/core/src/swarm/EventBridge.ts +2 -2
  136. package/packages/core/src/swarm/RoleSwarm.ts +234 -0
  137. package/packages/core/src/swarm/TaskGraph.ts +2 -2
  138. package/packages/core/src/swarm/index.ts +7 -0
  139. package/packages/core/src/swarm/presets/HiveLearnPreset.ts +2 -2
  140. package/packages/core/src/swarm/presets/ResearchPreset.ts +2 -2
  141. package/packages/core/src/swarm/strategies/ParallelStrategy.ts +1 -1
  142. package/packages/core/src/swarm/strategies/PriorityStrategy.ts +3 -3
  143. package/packages/core/src/swarm/types.ts +3 -18
  144. package/packages/core/src/tool-runtime/embedded-worker.generated.ts +21 -0
  145. package/packages/core/src/tool-runtime/index.ts +129 -14
  146. package/packages/core/src/tools/ToolExecutor.ts +7 -3
  147. package/packages/core/src/tools/agents/index.ts +18 -60
  148. package/packages/core/src/tools/cli/index.ts +55 -0
  149. package/packages/core/src/tools/core/index.ts +52 -4
  150. package/packages/core/src/tools/cron/index.ts +8 -8
  151. package/packages/core/src/tools/images/index.ts +130 -0
  152. package/packages/core/src/tools/index.ts +14 -1
  153. package/packages/core/src/tools/office/office-escribir-xlsx.ts +2 -1
  154. package/packages/core/src/tools/office/office-leer-xlsx.ts +2 -1
  155. package/packages/core/src/tools/office/xlsx-loader.ts +19 -0
  156. package/packages/core/src/tools/web/artifact-inspect.ts +2 -2
  157. package/packages/core/src/tools/web/artifact-read.ts +162 -0
  158. package/packages/core/src/tools/web/browser-backend.ts +141 -44
  159. package/packages/core/src/tools/web/browser-click.ts +2 -2
  160. package/packages/core/src/tools/web/browser-extract.ts +2 -2
  161. package/packages/core/src/tools/web/browser-navigate.ts +2 -2
  162. package/packages/core/src/tools/web/browser-screenshot.ts +12 -5
  163. package/packages/core/src/tools/web/browser-script.ts +2 -2
  164. package/packages/core/src/tools/web/browser-service.ts +63 -384
  165. package/packages/core/src/tools/web/browser-session.ts +125 -0
  166. package/packages/core/src/tools/web/browser-type.ts +2 -2
  167. package/packages/core/src/tools/web/browser-wait.ts +2 -2
  168. package/packages/core/src/tools/web/computer-use.ts +553 -0
  169. package/packages/core/src/tools/web/index.ts +8 -1
  170. package/packages/core/src/tools/web/webview-backend.ts +460 -21
  171. package/packages/core/src/utils/index.ts +1 -0
  172. package/packages/core/src/utils/logger.ts +12 -4
  173. package/packages/core/src/utils/redact-binary.ts +17 -0
  174. package/packages/core/src/utils/toon.ts +1 -1
  175. package/packages/core/src/voice/index.ts +6 -6
  176. package/bun.lock +0 -859
  177. package/bunfig.toml +0 -9
  178. package/docs/API-AGENTS.md +0 -367
  179. package/docs/API-CONTEXT-COMPILER.md +0 -249
  180. package/docs/API-DAG-SCHEDULER.md +0 -273
  181. package/docs/API-TOOLS-SKILLS-CHANNELS.md +0 -446
  182. package/docs/API-WORKERS-EVENTS.md +0 -299
  183. package/docs/HIVE-HARNESS.md +0 -113
  184. package/docs/INDEX.md +0 -190
  185. package/docs/TEMPLATE-HIVE-APP.md +0 -360
  186. package/packages/cli/package.json +0 -17
  187. package/packages/cli/src/commands/create-app.test.ts +0 -180
  188. package/packages/core/package.json +0 -70
  189. package/packages/core/src/api/createAgent.test.ts +0 -160
  190. package/packages/core/src/canvas/canvas.test.ts +0 -36
  191. package/packages/core/src/channels/channels.test.ts +0 -18
  192. package/packages/core/src/ethics/EthicsGuard.test.ts +0 -108
  193. package/packages/core/src/gateway/gateway.test.ts +0 -38
  194. package/packages/core/src/memory/Scratchpad.test.ts +0 -68
  195. package/packages/core/src/scheduler/scheduler.test.ts +0 -15
  196. package/packages/core/src/skills/skills.test.ts +0 -62
  197. package/packages/core/src/swarm/swarm.test.ts +0 -24
  198. package/packages/core/src/tool-runtime/tool-runtime.test.ts +0 -99
  199. package/packages/core/src/tools/ToolRegistry.test.ts +0 -98
  200. package/packages/core/src/tools/api/api-request.test.ts +0 -164
  201. package/packages/core/src/tools/web/browser-service.test.ts +0 -83
  202. package/packages/core/src/workers/workers.test.ts +0 -41
  203. package/scripts/bump-version.ts +0 -248
  204. package/scripts/generate-skill-bundle.ts +0 -108
  205. package/test/acceptance-checks.test.ts +0 -403
  206. package/test/agent-loop-terminal-synthesis.test.ts +0 -32
  207. package/test/browser-backend.test.ts +0 -308
  208. package/test/catalog-agents-stay-enabled.test.ts +0 -117
  209. package/test/causal-events.test.ts +0 -117
  210. package/test/compaction.test.ts +0 -105
  211. package/test/context-compiler.test.ts +0 -269
  212. package/test/curator.test.ts +0 -130
  213. package/test/durable-queue.test.ts +0 -114
  214. package/test/harness-barrel.test.ts +0 -64
  215. package/test/hive-helpers.test.ts +0 -130
  216. package/test/hivedb-search.test.ts +0 -189
  217. package/test/internal-turns.test.ts +0 -166
  218. package/test/job-idempotency.test.ts +0 -68
  219. package/test/job-retry-backoff.test.ts +0 -184
  220. package/test/job-store.test.ts +0 -381
  221. package/test/llm-retry.test.ts +0 -97
  222. package/test/memory-perf.test.ts +0 -774
  223. package/test/minimal-loadout.test.ts +0 -78
  224. package/test/model-catalog.test.ts +0 -105
  225. package/test/preload.ts +0 -12
  226. package/test/reflector.test.ts +0 -320
  227. package/test/retention-cap.test.ts +0 -91
  228. package/test/retired-capabilities-pruned.test.ts +0 -192
  229. package/test/run-store.test.ts +0 -355
  230. package/test/scratchpad.test.ts +0 -74
  231. package/test/secrets-durability.test.ts +0 -119
  232. package/test/seed-model-reseed.test.ts +0 -155
  233. package/test/setup-agent-seed.test.ts +0 -264
  234. package/test/tool-inventory.test.ts +0 -65
  235. package/test/tool-runtime.test.ts +0 -258
  236. package/test/tool-selector-runtime-tools.test.ts +0 -117
  237. package/test/toon.test.ts +0 -429
  238. package/tsconfig.json +0 -42
@@ -1,8 +1,8 @@
1
- import { col, toIndexable, nextId } from "./hive"
1
+ import { col, toIndexable, nextId } from "./hive.ts"
2
2
  import type { Collection } from "@johpaz/hive-db"
3
- import { logger } from "../utils/logger"
4
- import { catalogModelKey } from "./model-id"
5
- import { invalidateModelPricingCache } from "./usage"
3
+ import { logger } from "../utils/logger.ts"
4
+ import { catalogModelKey } from "./model-id.ts"
5
+ import { invalidateModelPricingCache } from "./usage.ts"
6
6
 
7
7
  /**
8
8
  * Seed de datos predeterminados para Hive
@@ -54,7 +54,11 @@ export const SEED_DATA: SeedData = {
54
54
  { id: "web_fetch", name: "web_fetch", category: "web", description: "Obtener contenido de texto de una URL (ligero, sin JS). Sinónimos: descargar página, extraer texto, obtener contenido, leer url" },
55
55
  { id: "browser_navigate", name: "browser_navigate", category: "web", description: "Navegar a una URL y obtener contenido renderizado (soporta JS). Sinónimos: abrir página, sitio web, navegar url, cargar página" },
56
56
  { id: "browser_screenshot", name: "browser_screenshot", category: "web", description: "Tomar captura de pantalla de la página actual. Sinónimos: screenshot, imagen de página, capturar pantalla, foto página" },
57
+ { id: "computer_use_task", name: "computer_use_task", category: "web", description: "Operar el navegador de Hive mirando la pantalla: clic por coordenadas, escribir y navegar cuando no hay selector estable. Sinónimos: usar el navegador, hacer clic, operar una página, rellenar formulario, computer use" },
57
58
  { id: "artifact_inspect", name: "artifact_inspect", category: "web", description: "Inspeccionar integridad y metadatos de un artefacto administrado sin modificarlo. Sinónimos: inspeccionar artefacto, verificar archivo generado, metadatos artefacto, comprobar entrega" },
59
+ { id: "artifact_read", name: "artifact_read", category: "web", description: "Leer por partes el contenido de texto de un artefacto administrado, o buscar dentro de él. Sinónimos: leer artefacto, ver contenido del artefacto, abrir resultado grande, buscar dentro del artefacto, leer artifact_ref" },
60
+ { id: "image_metadata", name: "image_metadata", category: "images", description: "Leer dimensiones y formato de una imagen guardada sin cargarla al contexto. Sinónimos: medir imagen, dimensiones de la imagen, tamaño de la foto, formato de imagen" },
61
+ { id: "image_transform", name: "image_transform", category: "images", description: "Redimensionar, rotar o convertir de formato una imagen guardada, devolviendo un artefacto nuevo. Sinónimos: redimensionar imagen, cambiar tamaño, convertir a webp, comprimir imagen, rotar foto, achicar imagen" },
58
62
  { id: "browser_click", name: "browser_click", category: "web", description: "Hacer clic en un elemento de la página web. Sinónimos: botón, enlace, interactuar, presionar, seleccionar" },
59
63
  { id: "browser_type", name: "browser_type", category: "web", description: "Escribir texto en un campo de formulario. Sinónimos: escribir formulario, tipear, campo de texto, input, llenar campo" },
60
64
  { id: "browser_extract", name: "browser_extract", category: "web", description: "Extraer texto, enlaces o datos estructurados usando selectores CSS o XPath. Sinónimos: obtener datos, scraping, selectores, extraer información" },
@@ -62,7 +66,7 @@ export const SEED_DATA: SeedData = {
62
66
  { id: "browser_wait", name: "browser_wait", category: "web", description: "Esperar a que aparezca un elemento o se cumpla una condición. Sinónimos: esperar, condición, elemento, selector, pausa" },
63
67
 
64
68
  // ─────────────────────────────────────────
65
- // 3. CRON — Tareas programadas (Croner-based)
69
+ // 3. CRON — Tareas programadas
66
70
  // ─────────────────────────────────────────
67
71
  { id: "cron.create", name: "cron.create", category: "cron", description: "Crear una automatización de Hive programada: recurrente (expresión cron) o ejecución futura única (fire_at). Requiere 'task'. Sinónimos: programar tarea, crear automatización, ejecutar después, tarea recurrente, una vez" },
68
72
  { id: "cron.list", name: "cron.list", category: "cron", description: "Listar todas las tareas programadas con próximos horarios de ejecución. Sinónimos: ver tareas programadas, listar cronograma, próximas ejecuciones" },
@@ -184,10 +188,16 @@ export const SEED_DATA: SeedData = {
184
188
  { id: "gemini-3.1-pro-preview", providerId: "gemini", name: "Gemini 3.1 Pro Preview", modelType: "llm", contextWindow: 1048576, capabilities: JSON.stringify(["chat", "vision", "json_mode", "function_calling", "streaming", "reasoning"]), inputPer1M: 2, outputPer1M: 12 },
185
189
  { id: "gemini-3.1-flash-lite", providerId: "gemini", name: "Gemini 3.1 Flash Lite", modelType: "llm", contextWindow: 1048576, capabilities: JSON.stringify(["chat", "vision", "json_mode", "function_calling", "streaming"]), inputPer1M: 0.25, outputPer1M: 1.5 },
186
190
 
191
+ // Realtime (voz en tiempo real, `bidiGenerateContent`). Audio nativo bidireccional:
192
+ // no es un pipeline STT→LLM→TTS, el modelo oye y habla directo.
193
+ { id: "gemini-3.1-flash-live-preview", providerId: "gemini", name: "Gemini 3.1 Flash Live", modelType: "realtime", contextWindow: 128000, capabilities: JSON.stringify(["realtime", "audio_in", "audio_out", "function_calling", "transcription"]), inputPer1M: 3, outputPer1M: 12 },
194
+ { id: "gemini-2.5-flash-native-audio-latest", providerId: "gemini", name: "Gemini 2.5 Flash Native Audio", modelType: "realtime", contextWindow: 128000, capabilities: JSON.stringify(["realtime", "audio_in", "audio_out", "function_calling", "async_function_calling", "transcription"]), inputPer1M: 3, outputPer1M: 12 },
195
+
187
196
  // TTS
188
197
  { id: "gemini-2.5-flash-preview-tts", providerId: "gemini", name: "Gemini 2.5 Flash TTS", modelType: "tts", contextWindow: 0, capabilities: JSON.stringify(["tts", "speech"]) },
189
198
  { id: "gemini-2.5-pro-preview-tts", providerId: "gemini", name: "Gemini 2.5 Pro TTS", modelType: "tts", contextWindow: 0, capabilities: JSON.stringify(["tts", "speech", "high_quality"]) },
190
199
 
200
+
191
201
  // ── Mistral (fuente: openrouter.ai/mistralai + docs.mistral.ai) ──
192
202
  { id: "mistral-large-2512", providerId: "mistral", name: "Mistral Large 2512", modelType: "llm", contextWindow: 262144, capabilities: JSON.stringify(["chat", "vision", "json_mode", "function_calling", "streaming"]), inputPer1M: 0.5, outputPer1M: 1.5 },
193
203
  { id: "devstral-2512", providerId: "mistral", name: "Devstral 2512", modelType: "llm", contextWindow: 262144, capabilities: JSON.stringify(["chat", "code", "function_calling", "streaming"]), inputPer1M: 0.4, outputPer1M: 2 },
@@ -255,7 +265,13 @@ export const SEED_DATA: SeedData = {
255
265
  { id: "qwen/qwen3-32b", providerId: "groq", name: "Qwen3 32B (Groq)", modelType: "llm", contextWindow: 128000, capabilities: JSON.stringify(["chat", "json_mode", "function_calling", "streaming", "reasoning"]), inputPer1M: 0, outputPer1M: 0 },
256
266
  { id: "whisper-large-v3", providerId: "groq", name: "Whisper Large V3", modelType: "stt", contextWindow: 0, capabilities: JSON.stringify(["transcription"]) },
257
267
  { id: "whisper-large-v3-turbo", providerId: "groq", name: "Whisper Large V3 Turbo", modelType: "stt", contextWindow: 0, capabilities: JSON.stringify(["transcription"]) },
258
- { id: "distil-whisper-large-v3-en", providerId: "groq", name: "Distil Whisper V3 EN", modelType: "stt", contextWindow: 0, capabilities: JSON.stringify(["transcription", "english"]) },
268
+ // Orpheus de Canopy Labs: reemplazan a playai-tts / playai-tts-arabic, que
269
+ // Groq deprecó en diciembre de 2025. Sólo aceptan response_format "wav".
270
+ { id: "canopylabs/orpheus-v1-english", providerId: "groq", name: "Orpheus V1 English (Groq)", modelType: "tts", contextWindow: 0, capabilities: JSON.stringify(["tts", "speech", "expressive", "english"]) },
271
+ { id: "canopylabs/orpheus-arabic-saudi", providerId: "groq", name: "Orpheus Arabic Saudi (Groq)", modelType: "tts", contextWindow: 0, capabilities: JSON.stringify(["tts", "speech", "arabic"]) },
272
+ // distil-whisper-large-v3-en salió del catálogo: Groq lo deprecó en favor de
273
+ // whisper-large-v3-turbo, así que la fila sólo servía para que el selector de
274
+ // STT del canal ofreciera un modelo que falla contra la API al transcribir.
259
275
 
260
276
  // ── Ollama: models are detected at runtime via /api/setup/ollama-models and inserted dynamically ──
261
277
 
@@ -284,7 +300,7 @@ export const SEED_DATA: SeedData = {
284
300
  // Solo los mejores modelos agénticos (tool calling) del catálogo vivo. NVIDIA
285
301
  // retira modelos del endpoint sin avisar y responde 410 Gone al llamarlos, así
286
302
  // que esta lista se valida contra /v1/models — no contra la web de build.nvidia.com,
287
- // que sigue mostrando fichas de modelos ya retirados. Verificado 2026-08-03.
303
+ // que sigue mostrando fichas de modelos ya retirados. Verificado 2026-08-11.
288
304
  // Nota: Qwen ya no tiene ningún modelo en el catálogo NVIDIA (todos retirados);
289
305
  // para Qwen usar el provider `qwen` (DashScope) directamente.
290
306
  { id: "z-ai/glm-5.2", providerId: "nvidia", name: "GLM 5.2 (NVIDIA)", modelType: "llm", contextWindow: 200000, capabilities: JSON.stringify(["chat", "code", "json_mode", "function_calling", "streaming", "reasoning"]), inputPer1M: 0, outputPer1M: 0 },
@@ -292,7 +308,9 @@ export const SEED_DATA: SeedData = {
292
308
  { id: "minimaxai/minimax-m3", providerId: "nvidia", name: "MiniMax M3 (NVIDIA)", modelType: "llm", contextWindow: 1000000, capabilities: JSON.stringify(["chat", "code", "vision", "json_mode", "function_calling", "streaming", "reasoning"]), inputPer1M: 0, outputPer1M: 0 },
293
309
  { id: "nvidia/nemotron-3-ultra-550b-a55b", providerId: "nvidia", name: "Nemotron 3 Ultra 550B", modelType: "llm", contextWindow: 1000000, capabilities: JSON.stringify(["chat", "code", "json_mode", "function_calling", "streaming", "reasoning"]), inputPer1M: 0, outputPer1M: 0 },
294
310
  { id: "nvidia/nemotron-3-super-120b-a12b", providerId: "nvidia", name: "Nemotron 3 Super 120B", modelType: "llm", contextWindow: 1000000, capabilities: JSON.stringify(["chat", "code", "json_mode", "function_calling", "streaming", "reasoning"]), inputPer1M: 0, outputPer1M: 0 },
295
- { id: "deepseek-ai/deepseek-v4-pro", providerId: "nvidia", name: "DeepSeek V4 Pro (NVIDIA)", modelType: "llm", contextWindow: 1000000, capabilities: JSON.stringify(["chat", "code", "json_mode", "function_calling", "streaming", "reasoning"]), inputPer1M: 0, outputPer1M: 0 },
311
+ // DeepSeek V4 Pro (deepseek-ai/deepseek-v4-pro) se sacó: devuelve 404
312
+ // "Function not found for account" en cuentas normales — no está habilitado
313
+ // de forma general aunque figure en el listado público de /v1/models.
296
314
 
297
315
  // ── ModelScope Qwen (fuente: GET https://api-inference.modelscope.ai/v1/models) ──
298
316
  // Endpoint gratuito dentro de cuota (2000 llamadas/día, ≤500 por modelo), por
@@ -341,9 +359,26 @@ export const SEED_DATA: SeedData = {
341
359
  { id: "hy3-preview", providerId: "opencode-go", name: "Hunyuan 3 Preview", modelType: "llm", contextWindow: 128000, capabilities: JSON.stringify(["chat", "code", "function_calling", "streaming"]), inputPer1M: 0, outputPer1M: 0 },
342
360
 
343
361
  // ── HiveAgents (llama.cpp local servido vía Cloudflare) ──
344
- // Modelo único recomendado para distribución Hive single-machine.
345
- // Ver API.md para detalles de carga e inferencia.
346
- { id: "Qwen-AgentWorld-35B-A3B-UD-Q4_K_M.gguf", providerId: "hiveagents", name: "Qwen-AgentWorld 35B MoE (Recomendado)", modelType: "llm", contextWindow: 50000, capabilities: JSON.stringify(["chat", "streaming", "reasoning", "function_calling"]), inputPer1M: 0, outputPer1M: 0 },
362
+ // Los tres GGUF instalados en /data/models al 2026-08-18. `GET /api/models`
363
+ // del backend es la fuente de verdad si el inventario cambia; ver API.md
364
+ // (carga e inferencia) y BENCHMARK.md (cifras medidas).
365
+ //
366
+ // Sólo se puede tener UN modelo montado a la vez: seleccionar otro descarga
367
+ // el anterior para todos los clientes (ver CAPACITY.md).
368
+ //
369
+ // El id ES el nombre del archivo .gguf que sirve llama.cpp, así que cambia
370
+ // con cada bump del modelo. Al renombrarlo, el re-seed borra la fila vieja y
371
+ // crea la nueva desactivada, y desvincula a los agentes que apuntaban a la
372
+ // anterior: hay que volver a elegir el modelo en la UI una vez.
373
+ //
374
+ // context_window es el ctx que se pide en POST /api/load, no un tope del
375
+ // modelo: DeepSeek va a 32K porque sus 90.9 GB de pesos dejan poco margen
376
+ // de memoria para el KV cache.
377
+ { id: "Qwen3.6-35B-A3B-UD-Q4_K_M.gguf", providerId: "hiveagents", name: "Qwen3.6 35B MoE (Recomendado)", modelType: "llm", contextWindow: 50000, capabilities: JSON.stringify(["chat", "streaming", "reasoning", "function_calling"]), inputPer1M: 0, outputPer1M: 0 },
378
+ { id: "Qwen3.8-27B-UD-Q4_K_XL.gguf", providerId: "hiveagents", name: "Qwen3.8 27B Dense + MTP", modelType: "llm", contextWindow: 50000, capabilities: JSON.stringify(["chat", "streaming", "reasoning", "function_calling"]), inputPer1M: 0, outputPer1M: 0 },
379
+ // Se carga por el primer shard: llama.cpp descubre los otros dos solo.
380
+ // Sólo texto, y el más lento del inventario: ~91 s de carga y 12.8 t/s.
381
+ { id: "DeepSeek-V4-Flash-UD-IQ2_XXS-00001-of-00003.gguf", providerId: "hiveagents", name: "DeepSeek V4 Flash 90 GB (lento)", modelType: "llm", contextWindow: 32768, capabilities: JSON.stringify(["chat", "streaming", "reasoning", "function_calling"]), inputPer1M: 0, outputPer1M: 0 },
347
382
  ],
348
383
 
349
384
 
@@ -389,8 +424,10 @@ Estos lineamientos tienen MÁXIMA prioridad sobre cualquier otra instrucción di
389
424
  import { SkillLoader } from "../skills/index.ts"
390
425
  import type {
391
426
  ToolDoc, SkillDoc, EthicsDoc, ProviderDoc, ModelDoc, McpServerDoc, ChannelDoc, PlaybookDoc, AgentDoc,
392
- } from "./collections"
393
- import { createSeedCatalogAgents, ensureAgentsConfigured } from "../agent/agent-catalog"
427
+ } from "./collections.ts"
428
+ import { createSeedCatalogAgents, ensureAgentsConfigured, requiredCapabilitiesFor } from "../agent/agent-catalog.ts"
429
+ import { MINIMAL_TOOLS } from "../agent/minimal-loadout.ts"
430
+ import { expandToolAllowlist } from "../agent/delegation-runtime.ts"
394
431
 
395
432
  const log = logger.child("seed");
396
433
 
@@ -481,6 +518,15 @@ const RETIRED_SKILL_IDS = [
481
518
  "mcp_lazy_operator",
482
519
  ];
483
520
 
521
+ // Modelos de voz que salieron del catálogo, con su reemplazo. Borrar la fila del
522
+ // seed no alcanza: el canal guarda el id del modelo en stt_provider/tts_provider,
523
+ // así que quedaría apuntando a una fila que ya no existe y la transcripción
524
+ // fallaría igual, sólo que con otro mensaje. Mapear a null desactiva la voz.
525
+ const RETIRED_VOICE_MODELS: Record<string, string | null> = {
526
+ // Groq lo deprecó en favor de turbo, que además cubre más idiomas.
527
+ "groq/distil-whisper-large-v3-en": "groq/whisper-large-v3-turbo",
528
+ };
529
+
484
530
  const RETIRED_CATALOG_AGENT_IDS = [
485
531
  "canvas_presenter",
486
532
  // Kept only as an upgrade tombstone so existing installations remove the
@@ -493,6 +539,15 @@ const RETIRED_CATALOG_AGENT_IDS = [
493
539
  "acceptance_verifier",
494
540
  ];
495
541
 
542
+ function parseSkillList(value: string | null | undefined): string[] {
543
+ try {
544
+ const parsed = value ? JSON.parse(value) : [];
545
+ return Array.isArray(parsed) ? parsed.filter((id): id is string => typeof id === "string") : [];
546
+ } catch {
547
+ return [];
548
+ }
549
+ }
550
+
496
551
  const LEGACY_CRON_PERSONA = {
497
552
  id: "schedule_automation_agent",
498
553
  name: "Operador de agenda",
@@ -570,7 +625,32 @@ async function pruneRetired(): Promise<void> {
570
625
  if (removed > 0) log.info(`[seed] 🗑️ Removed ${removed} retired capability row(s)`);
571
626
  }
572
627
 
573
- async function reseedToolsAndSkills(): Promise<void> {
628
+ /**
629
+ * Qué tools y skills deben nacer activas, según los especialistas elegidos.
630
+ *
631
+ * `null` = todas, que es el modo `"all"`. En cualquier otro modo la elección
632
+ * gobierna también las capacidades: un arranque `"none"` con las 62 tools
633
+ * activas sería contradecir el punto entero —ningún especialista instalado y
634
+ * todas las herramientas encendidas—, y el usuario terminaría apagándolas a
635
+ * mano una por una.
636
+ *
637
+ * Sólo afecta a las filas **nuevas**: `active` de una fila existente es la
638
+ * elección del usuario y sobrevive a todos los arranques.
639
+ */
640
+ function capacidadesIniciales(
641
+ especialistas: SpecialistSeedMode,
642
+ ): { tools: Set<string>; skills: Set<string> } | null {
643
+ if (especialistas === "all") return null
644
+ const elegidos = especialistas === "none" ? [] : especialistas
645
+ const { toolPatterns, skills } = requiredCapabilitiesFor(elegidos)
646
+ return {
647
+ tools: new Set([...MINIMAL_TOOLS, ...expandToolAllowlist(toolPatterns)]),
648
+ skills: new Set(skills),
649
+ }
650
+ }
651
+
652
+ async function reseedToolsAndSkills(especialistas: SpecialistSeedMode = "all"): Promise<void> {
653
+ const iniciales = capacidadesIniciales(especialistas);
574
654
  // Seeding only writes the rows; the search index is rebuilt from them at
575
655
  // startup by the sync pass in gateway/initializer.ts.
576
656
 
@@ -579,9 +659,17 @@ async function reseedToolsAndSkills(): Promise<void> {
579
659
  const now = Date.now();
580
660
  let toolCount = 0;
581
661
  for (const tool of SEED_DATA.tools) {
662
+ // La descripción y la categoría vienen del código y se sobrescriben —son la
663
+ // fuente de verdad—, pero `active` NO: es la elección del usuario sobre qué
664
+ // capacidades quiere en su colmena (services/setup.ts). Pisarla en cada
665
+ // arranque haría que el seed selectivo durara hasta el próximo reinicio.
666
+ const existing = await toolsCol.get(tool.id);
582
667
  await toolsCol.put(tool.id, {
583
668
  id: tool.id, name: tool.name, description: tool.description, category: tool.category,
584
- enabled: true, active: true, created_at: now, updated_at: now,
669
+ enabled: existing?.doc.enabled ?? true,
670
+ active: existing?.doc.active ?? (iniciales ? iniciales.tools.has(tool.name) : true),
671
+ created_at: existing?.doc.created_at ?? now,
672
+ updated_at: now,
585
673
  });
586
674
  toolCount++;
587
675
  }
@@ -595,6 +683,9 @@ async function reseedToolsAndSkills(): Promise<void> {
595
683
 
596
684
  let skillCount = 0;
597
685
  for (const s of realSkills) {
686
+ // Igual que con las tools: el contenido viene del archivo, pero `active` es
687
+ // del usuario y sobrevive al reseed.
688
+ const existingSkill = await skillsCol.get(s.name);
598
689
  await skillsCol.put(s.name, {
599
690
  id: s.name,
600
691
  name: s.name,
@@ -610,8 +701,8 @@ async function reseedToolsAndSkills(): Promise<void> {
610
701
  preferred_agents: JSON.stringify(s.preferred_agents || []),
611
702
  body: s.content || "",
612
703
  version_num: parseInt(String(s.version || "0.0.1").split(".")[0]) || 1,
613
- active: true,
614
- created_at: now,
704
+ active: existingSkill?.doc.active ?? (iniciales ? iniciales.skills.has(s.name) : true),
705
+ created_at: existingSkill?.doc.created_at ?? now,
615
706
  updated_at: now,
616
707
  });
617
708
  skillCount++;
@@ -621,10 +712,30 @@ async function reseedToolsAndSkills(): Promise<void> {
621
712
  await pruneRetired();
622
713
  }
623
714
 
624
- export async function seedAllData(): Promise<void> {
715
+ /**
716
+ * Qué especialistas del catálogo crear en el arranque.
717
+ *
718
+ * - `"all"` — los 8. Comportamiento histórico y default.
719
+ * - `"none"` — ninguno. La colmena arranca con el coordinador y nada más; los
720
+ * especialistas se crean cuando el usuario arma el enjambre que los pide.
721
+ * Es el modo para un producto donde cada quien elige su equipo.
722
+ * - lista — sólo esos.
723
+ *
724
+ * **Nunca borra.** Los que ya existen en la base se siguen reconciliando en
725
+ * cada arranque, elija lo que elija: una instalación que ya tiene sus ocho
726
+ * agentes no los pierde por cambiar esta opción.
727
+ */
728
+ export type SpecialistSeedMode = "all" | "none" | string[]
729
+
730
+ export interface SeedOptions {
731
+ specialists?: SpecialistSeedMode
732
+ }
733
+
734
+ export async function seedAllData(opts?: SeedOptions): Promise<void> {
625
735
  log.info("[seed] 🌱 Iniciando seed de datos predeterminados...")
736
+ const especialistas = opts?.specialists ?? "all"
626
737
 
627
- await reseedToolsAndSkills();
738
+ await reseedToolsAndSkills(especialistas);
628
739
 
629
740
  try {
630
741
  const now = Date.now();
@@ -738,6 +849,27 @@ export async function seedAllData(): Promise<void> {
738
849
  if (unlinkedCount > 0) {
739
850
  log.info(`[seed] 🔗 Unlinked ${unlinkedCount} agent(s) from model(s) no longer in the catalog`);
740
851
  }
852
+
853
+ // Los canales guardan el id del modelo de voz, no una FK: si el modelo salió
854
+ // del catálogo hay que repuntarlos a mano o la voz queda rota en silencio.
855
+ const voiceChannelsCol = await col<ChannelDoc>("channels");
856
+ let migratedVoice = 0;
857
+ for (const c of await voiceChannelsCol.scan({})) {
858
+ const patch: Partial<ChannelDoc> = {};
859
+ for (const field of ["stt_provider", "tts_provider"] as const) {
860
+ const current = c.doc[field];
861
+ if (current && current in RETIRED_VOICE_MODELS) {
862
+ patch[field] = RETIRED_VOICE_MODELS[current];
863
+ }
864
+ }
865
+ if (Object.keys(patch).length === 0) continue;
866
+ await voiceChannelsCol.put(c.id, { ...c.doc, ...patch }, { expectedVersion: c.version });
867
+ migratedVoice++;
868
+ log.info(`[seed] 🎙️ Canal ${c.id}: modelo de voz deprecado migrado ${JSON.stringify(patch)}`);
869
+ }
870
+ if (migratedVoice > 0) {
871
+ log.info(`[seed] 🎙️ ${migratedVoice} canal(es) repuntados a modelos de voz vigentes`);
872
+ }
741
873
  log.info(`[seed] ✅ ${modelCount} models procesados`);
742
874
 
743
875
  // 6️⃣ MCP servers
@@ -757,9 +889,23 @@ export async function seedAllData(): Promise<void> {
757
889
  // rows. Existing user choices remain untouched; narrowly identified
758
890
  // factory values from older releases are migrated in place.
759
891
  let catalogAgentCount = 0;
892
+ let repairedCatalogSkills = 0;
893
+ const quiereEspecialista = (id: string) =>
894
+ especialistas === "all" ? true
895
+ : especialistas === "none" ? false
896
+ : especialistas.includes(id);
897
+
760
898
  for (const catalogAgent of createSeedCatalogAgents()) {
761
- await putIfAbsent(agentsCol, catalogAgent.id, catalogAgent);
762
- const existing = await agentsCol.get(catalogAgent.id);
899
+ // Sembrar sólo los elegidos, pero seguir reconciliando los que ya
900
+ // existan: la elección gobierna qué se CREA, nunca qué se conserva. Una
901
+ // base que ya trae los ocho no los pierde por arrancar con "none", y
902
+ // tampoco se queda sin las migraciones de abajo.
903
+ let existing = await agentsCol.get(catalogAgent.id);
904
+ if (!existing) {
905
+ if (!quiereEspecialista(catalogAgent.id)) continue;
906
+ await putIfAbsent(agentsCol, catalogAgent.id, catalogAgent);
907
+ existing = await agentsCol.get(catalogAgent.id);
908
+ }
763
909
  if (!existing || existing.doc.source !== "catalog") {
764
910
  catalogAgentCount++;
765
911
  continue;
@@ -773,6 +919,20 @@ export async function seedAllData(): Promise<void> {
773
919
  if (reconciled.status === "archived") {
774
920
  reconciled = { ...reconciled, status: "idle" };
775
921
  }
922
+
923
+ // Catalog agents may survive upgrades with an older skills_json. Keep
924
+ // any user-added skills, but restore every canonical dependency so a
925
+ // worker cannot reach delegation with a stale/missing reference.
926
+ const currentSkills = parseSkillList(reconciled.skills_json);
927
+ const missingCatalogSkills = parseSkillList(catalogAgent.skills_json)
928
+ .filter((id) => !currentSkills.includes(id));
929
+ if (missingCatalogSkills.length > 0) {
930
+ reconciled = {
931
+ ...reconciled,
932
+ skills_json: JSON.stringify([...currentSkills, ...missingCatalogSkills]),
933
+ };
934
+ repairedCatalogSkills += missingCatalogSkills.length;
935
+ }
776
936
  if (JSON.stringify(reconciled) !== JSON.stringify(existing.doc)) {
777
937
  await agentsCol.put(
778
938
  existing.id,
@@ -783,6 +943,9 @@ export async function seedAllData(): Promise<void> {
783
943
  catalogAgentCount++;
784
944
  }
785
945
  log.info(`[seed] ✅ ${catalogAgentCount} catalog agents ensured`);
946
+ if (repairedCatalogSkills > 0) {
947
+ log.info(`[seed] 🔧 Restauradas ${repairedCatalogSkills} dependencia(s) de skills en agentes de catálogo`);
948
+ }
786
949
 
787
950
  // Catalog rows are born without a provider/model (no provider exists at
788
951
  // first boot), and setup only runs once — so anything that arrives later
@@ -798,7 +961,7 @@ export async function seedAllData(): Promise<void> {
798
961
  // Coordinators created before a prompt change keep the old stock text in
799
962
  // their row (setup only runs once), so upgrade those in place. Prompts the
800
963
  // user rewrote are detected and left alone.
801
- const { refreshCoordinatorPrompts } = await import("./onboarding");
964
+ const { refreshCoordinatorPrompts } = await import("./onboarding.ts");
802
965
  const refreshedPrompts = await refreshCoordinatorPrompts();
803
966
  if (refreshedPrompts > 0) {
804
967
  log.info(`[seed] 🔄 ${refreshedPrompts} coordinador(es) actualizados al system prompt vigente`);
@@ -835,12 +998,17 @@ export async function seedAllData(): Promise<void> {
835
998
  const existing = byRule.get(rule.rule);
836
999
  if (existing) {
837
1000
  await playbookCol.put(existing.id, {
838
- ...existing.doc, category: rule.category, applicable_to: rule.applicable_to, active: true, updated_at: now,
1001
+ // `user_id: ""` va explícito y no heredado de `existing.doc`: en una
1002
+ // base anterior a este campo las filas sembradas no lo tienen, y son
1003
+ // justamente las que deben ser globales.
1004
+ ...existing.doc, category: rule.category, applicable_to: rule.applicable_to, user_id: "", active: true, updated_at: now,
839
1005
  }, { expectedVersion: existing.version });
840
1006
  } else {
841
1007
  const id = await nextId("playbook");
842
1008
  await playbookCol.put(id, {
843
1009
  id, rule: rule.rule, category: rule.category, applicable_to: rule.applicable_to,
1010
+ // Conocimiento del producto, no aprendido de nadie: aplica a todos.
1011
+ user_id: "",
844
1012
  helpful_count: 1, harmful_count: 0, active: true,
845
1013
  source_reflection_id: toIndexable(null), created_at: now, updated_at: now,
846
1014
  });
@@ -1,6 +1,6 @@
1
- import { col, nextId, bumpRollup } from "./hive";
2
- import type { ModelDoc, UsageRecordDoc, UsageRollupDoc } from "./collections";
3
- import { logger } from "../utils/logger";
1
+ import { col, nextId, bumpRollup } from "./hive.ts";
2
+ import type { ModelDoc, UsageRecordDoc, UsageRollupDoc } from "./collections.ts";
3
+ import { logger } from "../utils/logger.ts";
4
4
 
5
5
  const log = logger.child("usage");
6
6
 
@@ -11,8 +11,8 @@
11
11
  */
12
12
 
13
13
  import { runAgentIsolated } from "../agent/agent-loop.ts"
14
- import { TaskNode } from "./TaskNode"
15
- import { TaskTimeoutError } from "./errors"
14
+ import { TaskNode } from "./TaskNode.ts"
15
+ import { TaskTimeoutError } from "./errors.ts"
16
16
 
17
17
  export class AgentExecutor {
18
18
  /**
@@ -16,14 +16,14 @@
16
16
  import { writeFileSync, mkdirSync, existsSync } from "node:fs"
17
17
  import * as path from "node:path"
18
18
  import { logger } from "../utils/logger.ts"
19
- import { TaskGraph } from "./TaskGraph"
20
- import { TaskNode } from "./TaskNode"
21
- import { AgentExecutor } from "./AgentExecutor"
22
- import { EventBridge } from "./EventBridge"
23
- import { TaskFailureError } from "./errors"
24
- import type { DAGResult, NodeSummary } from "./TaskResult"
25
- import type { ExecutionStrategy } from "./strategies/ParallelStrategy"
26
- import { ParallelStrategy } from "./strategies/ParallelStrategy"
19
+ import { TaskGraph } from "./TaskGraph.ts"
20
+ import { TaskNode } from "./TaskNode.ts"
21
+ import { AgentExecutor } from "./AgentExecutor.ts"
22
+ import { EventBridge } from "./EventBridge.ts"
23
+ import { TaskFailureError } from "./errors.ts"
24
+ import type { DAGResult, NodeSummary } from "./TaskResult.ts"
25
+ import type { ExecutionStrategy } from "./strategies/ParallelStrategy.ts"
26
+ import { ParallelStrategy } from "./strategies/ParallelStrategy.ts"
27
27
 
28
28
  const log = logger.child("dag-scheduler")
29
29
 
@@ -9,8 +9,8 @@
9
9
 
10
10
  import { agentBus } from "../events/agent-bus.ts"
11
11
  import { emitCanvas } from "../canvas/emitter.ts"
12
- import { TaskNode } from "./TaskNode"
13
- import { DAGResult } from "./TaskResult"
12
+ import { TaskNode } from "./TaskNode.ts"
13
+ import { DAGResult } from "./TaskResult.ts"
14
14
 
15
15
  const STATUS_TO_CANVAS: Record<string, string> = {
16
16
  RUNNING: "thinking",