@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
@@ -8,7 +8,7 @@ category: web
8
8
  permissions:
9
9
  - browser_control
10
10
  dependencies: []
11
- tools: [browser_navigate, browser_click, browser_type, browser_screenshot]
11
+ tools: [browser_navigate, browser_wait, browser_click, browser_type, browser_screenshot, browser_script, computer_use_task]
12
12
 
13
13
  # Structured skill fields
14
14
  triggers:
@@ -38,13 +38,20 @@ steps:
38
38
  output: page_loaded
39
39
 
40
40
  - step: 2
41
+ action: browser_wait
42
+ instruction: "Wait for the element before acting on it. Clicking or typing before the element exists is the most common failure in web automation, and it fails silently"
43
+ params:
44
+ selector: "CSS selector of the element about to be used"
45
+ output: element_ready
46
+
47
+ - step: 3
41
48
  action: browser_click
42
49
  instruction: "Click on elements (buttons, links) to navigate or trigger actions"
43
50
  params:
44
51
  selector: "CSS selector for element"
45
52
  output: click_result
46
53
 
47
- - step: 3
54
+ - step: 4
48
55
  action: browser_type
49
56
  instruction: "Type text into form fields (inputs, textareas)"
50
57
  params:
@@ -52,12 +59,14 @@ steps:
52
59
  text: "text to type"
53
60
  output: type_result
54
61
 
55
- - step: 4
62
+ - step: 5
56
63
  action: browser_screenshot
57
64
  instruction: "Take screenshot to verify state after interactions"
58
65
  output: verification_screenshot
59
66
 
60
67
  rules:
68
+ - "Escalar sólo cuando haga falta, en este orden: `browser_click`/`browser_type` con un selector → `browser_script` si el elemento no se puede alcanzar con un selector estable → `computer_use_task` si la página no tiene selectores usables. Empezar por el último es lento y caro: mira la pantalla y razona en cada paso."
69
+ - "Esperar con `browser_wait` antes de cada clic o tipeo, no confiar en que la página ya cargó: es la falla más común de la automatización web, y falla en silencio."
61
70
  - "Wait for page to fully load after each navigation or significant interaction"
62
71
  - "Use specific, stable CSS selectors (IDs preferred over classes)"
63
72
  - "Take screenshots after critical steps for verification"
@@ -8,7 +8,7 @@ category: web
8
8
  permissions:
9
9
  - browser_control
10
10
  dependencies: []
11
- tools: [browser_navigate, browser_screenshot, web_fetch]
11
+ tools: [browser_navigate, browser_screenshot, browser_extract, browser_wait]
12
12
 
13
13
  # Structured skill fields
14
14
  triggers:
@@ -39,16 +39,26 @@ steps:
39
39
  output: screenshot
40
40
 
41
41
  - step: 3
42
- action: web_fetch
43
- instruction: "Extract text content from rendered page as markdown"
44
- output: extracted_content
42
+ action: browser_wait
43
+ instruction: "Wait for the content selector before extracting an SPA renders after load fires"
44
+ params:
45
+ selector: "CSS selector of the content that must be present"
46
+ output: content_ready
45
47
 
46
48
  - step: 4
49
+ action: browser_extract
50
+ instruction: "Extract the rendered DOM. Omit the selector for a compact accessibility snapshot of the whole page"
51
+ params:
52
+ selector: "CSS selector, or 'body' for the whole page"
53
+ output: extracted_content
54
+
55
+ - step: 5
47
56
  action: synthesize
48
57
  instruction: "Combine screenshot and text content for comprehensive capture"
49
58
  output: scraped_data
50
59
 
51
60
  rules:
61
+ - "Extraer con `browser_extract`, NUNCA con `web_fetch`: web_fetch vuelve a pedir la URL al servidor y recibe el HTML sin renderizar, que es justamente lo que esta skill existe para evitar. En un SPA devuelve una cáscara vacía."
52
62
  - "Wait for full page load including JavaScript-rendered content"
53
63
  - "Take screenshot before extracting text to capture initial state"
54
64
  - "For infinite scroll pages, scroll down and capture multiple screenshots"
@@ -66,10 +76,10 @@ output_format:
66
76
 
67
77
  examples:
68
78
  - user_input: "capturá el contenido de https://example.com/dashboard"
69
- expected_behavior: "browser_navigate → wait for JS render → browser_screenshot → browser_fetch → return both"
79
+ expected_behavior: "browser_navigate → browser_wait → browser_screenshot → browser_extract → return both"
70
80
 
71
81
  - user_input: "obtené la página renderizada de la app"
72
- expected_behavior: "Navigate → wait for SPA to load → screenshot + fetch content"
82
+ expected_behavior: "Navigate → browser_wait for the SPA root → screenshot + browser_extract"
73
83
 
74
84
  - user_input: "scrapeá este sitio con javascript"
75
85
  expected_behavior: "Full browser render → capture visual and text content"
@@ -87,7 +97,12 @@ Esta skill se activa para sitios web dinámicos que requieren JavaScript renderi
87
97
  |------|----------|---------------|
88
98
  | `browser_navigate` | Navega y renderiza página completa | Sitios con JavaScript/SPA |
89
99
  | `browser_screenshot` | Captura estado visual | Evidencia de contenido renderizado |
90
- | `web_fetch` | Extrae texto como markdown | Contenido textual de página renderizada |
100
+ | `browser_extract` | Extrae del DOM ya renderizado | Contenido textual o estructurado del SPA |
101
+ | `browser_wait` | Espera a que aparezca un selector | Antes de extraer, en páginas que cargan por partes |
102
+
103
+ > **No usar `web_fetch` acá.** Vuelve a pedir la URL al servidor y recibe el HTML
104
+ > sin JavaScript ejecutado — en un SPA, una cáscara vacía. Para eso está
105
+ > `browser_extract`, que lee el DOM que el navegador ya renderizó.
91
106
 
92
107
  ## Workflow
93
108
 
@@ -460,22 +460,32 @@ Para gestionar tareas programadas (cron jobs): crear, listar, actualizar, pausar
460
460
  | \`cron_expression\` | string | Expresión cron (solo para recurring) |
461
461
  | \`fire_at\` | string | Datetime ISO (solo para one_shot) |
462
462
  | \`channel\` | string | Canal de notificación |
463
- | \`start_at\` | string | Inicio de ventana opcional (Croner startAt) |
464
- | \`stop_at\` | string | Fin de ventana opcional (Croner stopAt) |
463
+ | \`start_at\` | string | Inicio de ventana opcional |
464
+ | \`stop_at\` | string | Fin de ventana opcional |
465
465
  | \`dom_and_dow\` | number | 0=OR (default), 1=AND (día mes + día semana) |
466
+ | \`max_runs\` | number | Deja de correr después de N corridas ("recordámelo 3 veces") |
467
+ | \`payload\` | object | Datos que recibe el agente al ejecutarse |
468
+ | \`agent_id\` | string | Agente concreto que debe ejecutarla. Si se omite, decide el coordinador |
469
+ | \`tool_name\` | string | Ejecutar una tool directamente, sin pasar por un agente |
470
+
471
+ > **La zona horaria no se pasa acá**: sale del perfil del usuario. No la
472
+ > inventes ni la pidas — si el usuario dice "a las 9", son las 9 de su reloj.
466
473
 
467
474
  ## Cron Expression Format
468
475
 
469
476
  \`\`\`
470
- * * * * *
471
- │ │
472
- │ │ └── Día semana (0-6, 0=Domingo)
473
- │ │ │ └──── Mes (1-12)
474
- │ │ └────── Día del mes (1-31)
475
- └──────── Hora (0-23)
476
- └────────── Minuto (0-59)
477
+ ┌───────── segundos (0-59) ← opcional, sólo si hacen falta
478
+ ┌─────── minuto (0-59)
479
+ │ │ ┌───── hora (0-23)
480
+ │ │ │ ┌─── día del mes (1-31)
481
+ │ │ ┌─ mes (1-12 o JAN-DEC)
482
+ │ │ ┌ día de semana (0-7 o SUN-SAT, 0 y 7 = domingo)
483
+ * * * * * *
477
484
  \`\`\`
478
485
 
486
+ Cinco campos, o seis poniendo los segundos adelante. Acepta \`*\`, listas \`1,15\`,
487
+ rangos \`1-5\`, pasos \`*/2\`, y nombres de mes y de día.
488
+
479
489
  ## Ejemplos Comunes
480
490
 
481
491
  | Expresión | Significado |
@@ -834,7 +844,7 @@ Esta skill se activa cuando el usuario necesita:
834
844
  description: `Automate web workflows with navigation, clicks, form filling, and visual verification`,
835
845
  category: "web",
836
846
  version: "1.0.0",
837
- tools: ["browser_navigate","browser_click","browser_type","browser_screenshot"],
847
+ tools: ["browser_navigate","browser_wait","browser_click","browser_type","browser_screenshot","browser_script","computer_use_task"],
838
848
  triggers: ["automatizá el navegador","automate browser","completá el formulario","fill form","hacé clic en","click on","iniciá sesión","login","registrate","sign up","interactuá con la web","interact with website","flujo web","web workflow"],
839
849
  body: `
840
850
  # Browser Automate Skill
@@ -879,7 +889,7 @@ Esta skill se activa para automatizar flujos de interacción con aplicaciones we
879
889
  description: `Navigate to web pages and capture rendered content including screenshots for dynamic sites`,
880
890
  category: "web",
881
891
  version: "1.0.0",
882
- tools: ["browser_navigate","browser_screenshot","web_fetch"],
892
+ tools: ["browser_navigate","browser_screenshot","browser_extract","browser_wait"],
883
893
  triggers: ["capturá el contenido","scrape content","obtené la página renderizada","get rendered page","sitios dinámicos","dynamic sites","web con javascript","javascript websites","tomá screenshot y contenido","screenshot and content"],
884
894
  body: `
885
895
  # Browser Scrape Skill
@@ -894,7 +904,12 @@ Esta skill se activa para sitios web dinámicos que requieren JavaScript renderi
894
904
  |------|----------|---------------|
895
905
  | \`browser_navigate\` | Navega y renderiza página completa | Sitios con JavaScript/SPA |
896
906
  | \`browser_screenshot\` | Captura estado visual | Evidencia de contenido renderizado |
897
- | \`web_fetch\` | Extrae texto como markdown | Contenido textual de página renderizada |
907
+ | \`browser_extract\` | Extrae del DOM ya renderizado | Contenido textual o estructurado del SPA |
908
+ | \`browser_wait\` | Espera a que aparezca un selector | Antes de extraer, en páginas que cargan por partes |
909
+
910
+ > **No usar \`web_fetch\` acá.** Vuelve a pedir la URL al servidor y recibe el HTML
911
+ > sin JavaScript ejecutado — en un SPA, una cáscara vacía. Para eso está
912
+ > \`browser_extract\`, que lee el DOM que el navegador ya renderizó.
898
913
 
899
914
  ## Workflow
900
915
 
@@ -1430,6 +1445,89 @@ Para crear flujos interactivos multi-paso usando A2UI v0.9. Usar cuando se neces
1430
1445
  - Agregar validación con \`checks\` en TextField
1431
1446
  - Mantener el estado del flujo en el data model (\`/data/step\`, \`/data/serviceType\`, etc.)
1432
1447
  - Eliminar surfaces con \`a2ui_delete_surface\` al completar o cancelar
1448
+ `,
1449
+ },
1450
+ {
1451
+ name: "image_editor",
1452
+ description: `Convertir, redimensionar y rotar imágenes con Bun.Image. Inspeccionar dimensiones y formato sin cargar la imagen al contexto.`,
1453
+ category: "images",
1454
+ version: "1.0.0",
1455
+ tools: ["image_metadata","image_transform","artifact_inspect"],
1456
+ triggers: ["convertí la imagen","convert image","redimensioná la imagen","resize image","achicá la foto","make it smaller","pasala a webp","convert to webp","rotá la imagen","rotate image","qué tamaño tiene","image dimensions","comprimí la imagen","compress image","hacé una miniatura","make a thumbnail"],
1457
+ body: `
1458
+ # Image Editor Skill
1459
+
1460
+ ## Cuándo se Activa
1461
+
1462
+ Cuando el usuario quiere **cambiar** una imagen (formato, tamaño, rotación) o
1463
+ **saber** sus características. Corre sobre \`Bun.Image\`, nativo del runtime.
1464
+
1465
+ ## Herramientas Disponibles
1466
+
1467
+ | Tool | Qué hace | Cuándo usarla |
1468
+ |------|----------|---------------|
1469
+ | \`image_metadata\` | Ancho, alto y formato | Siempre antes de transformar |
1470
+ | \`image_transform\` | Convierte, redimensiona, rota | El trabajo en sí |
1471
+ | \`artifact_inspect\` | Tipo MIME, integridad, tamaño | Cuando no está claro si el artefacto es una imagen |
1472
+
1473
+ ## Lo Que Hay Que Entender
1474
+
1475
+ **Todo pasa por artefactos.** Una imagen no viaja en el mensaje: vive como
1476
+ artefacto y se la nombra por su \`artifact_id\`. Es lo que evita que una foto de 4
1477
+ MB entre a la ventana de contexto y se reenvíe en cada turno de la conversación.
1478
+
1479
+ **Transformar no destruye.** \`image_transform\` devuelve un artefacto **nuevo**.
1480
+ El original sigue disponible, así que se puede probar un tamaño, ver que no
1481
+ gustó y probar otro sin haber perdido nada.
1482
+
1483
+ **La proporción se pierde en silencio.** Si se pasan \`width\` y \`height\` juntos,
1484
+ la imagen se estira sin avisar. Pasando uno solo, el otro se calcula.
1485
+
1486
+ ## Formatos
1487
+
1488
+ \`jpeg\` · \`png\` · \`webp\` · \`avif\` · \`heic\`
1489
+
1490
+ Ante la duda, **webp**: pesa bastante menos que jpeg y png a calidad comparable,
1491
+ y lo entienden todos los navegadores actuales.
1492
+ `,
1493
+ },
1494
+ {
1495
+ name: "artifact_reader",
1496
+ description: `Leer archivos grandes que llegaron como artifact_ref: por tramos o buscando dentro, sin volcarlos enteros al contexto.`,
1497
+ category: "artifacts",
1498
+ version: "1.0.0",
1499
+ tools: ["artifact_read","artifact_inspect"],
1500
+ triggers: ["leé el archivo adjunto","read the attachment","qué dice el documento","what does the document say","buscá en el archivo","search in the file","artifact_ref","el resultado quedó truncado","the result was truncated","seguí leyendo","keep reading"],
1501
+ body: `
1502
+ # Artifact Reader Skill
1503
+
1504
+ ## Cuándo se Activa
1505
+
1506
+ Cuando aparece un **\`artifact_ref\`**: un archivo, un adjunto o el resultado de
1507
+ una tool que era demasiado grande para entrar en el contexto.
1508
+
1509
+ ## Herramientas Disponibles
1510
+
1511
+ | Tool | Qué hace | Cuándo usarla |
1512
+ |------|----------|---------------|
1513
+ | \`artifact_inspect\` | Tamaño, tipo MIME, integridad | Antes de leer, para decidir cómo |
1514
+ | \`artifact_read\` | Contenido, por tramos o buscando | Para leer de verdad |
1515
+
1516
+ ## Lo Que Hay Que Entender
1517
+
1518
+ **Un \`artifact_ref\` no es un error.** Es el mecanismo por el que un archivo
1519
+ grande queda fuera de la ventana de contexto y a la vez disponible. El archivo
1520
+ está entero; lo que cambia es que se lee a pedido en vez de entrar completo en
1521
+ cada turno de la conversación.
1522
+
1523
+ **Buscar cuesta mucho menos que paginar.** \`artifact_read\` con \`search\` recorre
1524
+ el archivo del lado del servidor y devuelve extractos de cada coincidencia con
1525
+ su contexto alrededor. Paginar el mismo archivo con \`offset\`/\`limit\` gasta un
1526
+ turno por tramo y mete en el contexto un montón de texto que no hacía falta.
1527
+ Cuando se sabe qué se busca, se busca.
1528
+
1529
+ **Continuar es explícito.** Cada lectura devuelve \`next_offset\`. Ese es el valor
1530
+ que se pasa para seguir — no se calcula a mano.
1433
1531
  `,
1434
1532
  },
1435
1533
  ];
@@ -11,10 +11,11 @@
11
11
  * instead of `DELETE`+`INSERT`.
12
12
  */
13
13
 
14
- import { getHiveDb } from "./hivedb";
15
- import { col } from "./hive";
16
- import { seedAllData } from "./seed";
17
- import { ensureSecretsBackend } from "./crypto";
14
+ import { getHiveDb, getOpenHiveDb } from "./hivedb.ts";
15
+ import { col } from "./hive.ts";
16
+ import { seedAllData, type SeedOptions } from "./seed.ts";
17
+ import { ensureSecretsBackend } from "./crypto.ts";
18
+ import { ensureLegacyThread } from "../agent/thread-store.ts";
18
19
 
19
20
  interface IndexSpec {
20
21
  collection: string;
@@ -102,6 +103,13 @@ const INDEXES: IndexSpec[] = [
102
103
  // Stage 7 — meeting
103
104
  { collection: "meetingSessions", field: "user_id" },
104
105
  { collection: "meetingSessions", field: "status" },
106
+ { collection: "conversationThreads", field: "user_id" },
107
+ { collection: "conversationThreads", field: "channel" },
108
+ { collection: "conversationThreads", field: "archived" },
109
+ { collection: "swarms", field: "enabled" },
110
+ { collection: "apiEndpoints", field: "enabled" },
111
+ { collection: "memory", field: "user_id" },
112
+ { collection: "playbook", field: "user_id" },
105
113
  ];
106
114
 
107
115
  async function ensureIndexes(): Promise<void> {
@@ -119,33 +127,120 @@ async function ensureIndexes(): Promise<void> {
119
127
  * user-toggleable fields (enabled/active) and doesn't touch `users`, so it's
120
128
  * safe to call unconditionally before any onboarding has happened.
121
129
  */
122
- async function ensureSeedData(): Promise<void> {
123
- await seedAllData();
130
+ async function ensureSeedData(opts?: SeedOptions): Promise<void> {
131
+ await seedAllData(opts);
124
132
  }
125
133
 
126
- let bootstrapped = false;
134
+ // Bootstrap state belongs to a specific database instance. A boolean that
135
+ // survives closeHiveDb() can report a closed/replaced database as ready when
136
+ // tests or long-running processes open a fresh instance in the same runtime.
137
+ let bootstrappedDb: Awaited<ReturnType<typeof getHiveDb>> | null = null;
138
+
139
+ /**
140
+ * Antes de la separación por canal todos los canales compartían un solo hilo cuyo
141
+ * `thread_id` era el `userId`. Esa conversación se registra —sin mover un solo
142
+ * mensaje— como una conversación más de la web, para que siga siendo legible desde
143
+ * la lista. Idempotente: no hace nada si ya está registrada o si no hay historial.
144
+ */
145
+ /**
146
+ * Reasigna las memorias anteriores al aislamiento por usuario.
147
+ *
148
+ * Antes la colección era global: `id` era el título y no había `user_id`. Al
149
+ * introducir el aislamiento esas filas quedarían invisibles —nadie las
150
+ * encontraría, porque toda lectura filtra por dueño— así que se les asigna el
151
+ * usuario existente y se re-clavean a `${userId}:${title}`.
152
+ *
153
+ * Idempotente: una fila que ya tiene `user_id` no se toca. Si todavía no hay
154
+ * usuario (onboarding sin terminar) se deja para el próximo arranque, cuando lo
155
+ * haya, en vez de asignarlas a `""` y tener que deshacerlo.
156
+ */
157
+ async function migrateLegacyMemories(): Promise<void> {
158
+ try {
159
+ const memories = await col<{ id: string; user_id?: string; title: string }>("memory");
160
+ const legacy = (await memories.scan({})).filter((e) => !e.doc.user_id);
161
+ if (legacy.length === 0) return;
162
+
163
+ const users = await col<{ id: string }>("users");
164
+ const primero = (await users.scan({ limit: 1 }))[0];
165
+ if (!primero) return;
166
+
167
+ for (const entry of legacy) {
168
+ const nuevoId = `${primero.id}:${entry.doc.title}`;
169
+ await memories.put(nuevoId, { ...entry.doc, id: nuevoId, user_id: primero.id });
170
+ if (nuevoId !== entry.id) await memories.delete(entry.id).catch(() => {});
171
+ }
172
+ } catch {
173
+ // La memoria no es crítica para arrancar: si falla, se reintenta al próximo boot.
174
+ }
175
+ }
176
+
177
+ /**
178
+ * Reglas del playbook anteriores a `user_id`.
179
+ *
180
+ * Se aprendieron cuando la instalación era de un solo usuario, así que son de
181
+ * él. Dejarlas sin dueño las volvería globales y se las inyectaría a cualquier
182
+ * usuario que se dé de alta después, que es exactamente el aislamiento que este
183
+ * campo viene a cerrar. Las sembradas no pasan por acá: `seedAllData()` les
184
+ * pone `user_id: ""` en cada arranque.
185
+ */
186
+ async function migrateLegacyPlaybook(): Promise<void> {
187
+ try {
188
+ const playbook = await col<{ id: string; user_id?: string }>("playbook");
189
+ const legacy = (await playbook.scan({})).filter((e) => e.doc.user_id === undefined);
190
+ if (legacy.length === 0) return;
191
+
192
+ const users = await col<{ id: string }>("users");
193
+ const primero = (await users.scan({ limit: 1 }))[0];
194
+ if (!primero) return;
195
+
196
+ for (const entry of legacy) {
197
+ await playbook.put(
198
+ entry.id,
199
+ { ...entry.doc, user_id: primero.id },
200
+ { expectedVersion: entry.version },
201
+ );
202
+ }
203
+ } catch {
204
+ // El playbook no es crítico para arrancar: se reintenta al próximo boot.
205
+ }
206
+ }
207
+
208
+ async function ensureLegacyThreads(): Promise<void> {
209
+ try {
210
+ const users = await col<{ id: string }>("users");
211
+ for (const user of await users.scan({})) {
212
+ await ensureLegacyThread(user.id);
213
+ }
214
+ } catch {
215
+ // Base sin usuarios todavía (onboarding pendiente) — nada que registrar.
216
+ }
217
+ }
127
218
 
128
219
  /**
129
220
  * Idempotent entry point: opens the database, ensures indexes, reseeds the
130
221
  * static catalogs, and records the schema version. Safe to call on every
131
222
  * gateway boot.
132
223
  */
133
- export async function ensureHiveDb(): Promise<void> {
134
- await getHiveDb();
224
+ export async function ensureHiveDb(opts?: SeedOptions): Promise<void> {
225
+ const db = await getHiveDb();
135
226
  await ensureIndexes();
136
227
  // Mint the master key before anything can save an API key, so a fresh
137
228
  // install is durable from the first keystroke rather than after a restart
138
229
  // has already dropped the secret.
139
230
  ensureSecretsBackend();
140
- await ensureSeedData();
231
+ await ensureSeedData(opts);
232
+
233
+ await ensureLegacyThreads();
234
+ await migrateLegacyMemories();
235
+ await migrateLegacyPlaybook();
141
236
 
142
237
  const meta = await col<{ value: number }>("meta");
143
238
  const existing = await meta.get("schemaVersion");
144
239
  if (!existing) await meta.put("schemaVersion", { value: 1 }, { expectedVersion: 0 });
145
240
 
146
- bootstrapped = true;
241
+ bootstrappedDb = db;
147
242
  }
148
243
 
149
244
  export function isBootstrapped(): boolean {
150
- return bootstrapped;
245
+ return bootstrappedDb !== null && bootstrappedDb === getOpenHiveDb();
151
246
  }
@@ -6,7 +6,7 @@
6
6
  * co-located with the DB singleton accessor.
7
7
  */
8
8
 
9
- import { getHiveDb } from "./hivedb"
9
+ import { getHiveDb } from "./hivedb.ts"
10
10
  import type { Event, EventPattern } from "@johpaz/hive-db"
11
11
 
12
12
  export type { Event as CausalEvent, EventPattern as CausalEventPattern }
@@ -40,7 +40,8 @@ export interface ModelDoc {
40
40
  id: string
41
41
  provider_id: string
42
42
  name: string
43
- model_type: "llm" | "stt" | "tts" | "vision" | "embedding"
43
+ /** "realtime": voz full-duplex (Live API), no confundir con stt+tts encadenados. */
44
+ model_type: "llm" | "stt" | "tts" | "vision" | "embedding" | "realtime"
44
45
  context_window: number
45
46
  capabilities: string | null
46
47
  enabled: boolean
@@ -269,6 +270,14 @@ export interface RefreshTokenDoc {
269
270
  export type TurnSource =
270
271
  | "message" | "audio" | "a2ui" | "canvas" | "api"
271
272
  | "task_complete" | "delegation_summary"
273
+ /** Turno hablado en una sesión de voz en tiempo real. A diferencia de "audio"
274
+ * (nota de voz: STT → turno → TTS) la voz la pone el modelo realtime, así que
275
+ * el turno nunca sintetiza audio al final. */
276
+ | "realtime"
277
+ /** Charla hablada que la voz YA resolvió sin tocar la colmena. Se guarda como
278
+ * contexto del hilo, nunca como pedido pendiente: tratarla como accionable
279
+ * hacía que el coordinador re-delegara todo lo que se había dicho en voz. */
280
+ | "realtime_chat"
272
281
 
273
282
  /** What gets persisted — adds the synthetic marker for rows written before `source` existed. */
274
283
  export type MessageSource = TurnSource | "legacy_internal"
@@ -298,6 +307,28 @@ export interface SummaryDoc {
298
307
  last_message_id: string | null
299
308
  }
300
309
 
310
+ /**
311
+ * Una conversación: el registro de un `conversations.thread_id`, con lo necesario
312
+ * para listarla en la web sin escanear los mensajes. `id` ES el threadId
313
+ * (`${user}/${canal}/${peer}` — ver agent/thread-id.ts), salvo la fila del hilo
314
+ * legacy anterior a la separación por canal, cuyo id es el userId pelado.
315
+ */
316
+ export interface ConversationThreadDoc {
317
+ id: string
318
+ user_id: string
319
+ channel: string
320
+ /** Contacto/grupo del canal, o el id de conversación en la web. */
321
+ peer_id: string
322
+ peer_kind: "direct" | "group"
323
+ /** null hasta el primer mensaje del usuario, de donde se deriva. */
324
+ title: string | null
325
+ /** Borrado suave: sigue en la base pero no se lista ni se reabre. */
326
+ archived: boolean
327
+ created_at: number
328
+ last_message_at: number
329
+ message_count: number
330
+ }
331
+
301
332
  export interface TraceDoc {
302
333
  id: string
303
334
  thread_id: string
@@ -320,6 +351,8 @@ export interface TraceDoc {
320
351
  export interface ReflectionDoc {
321
352
  id: string
322
353
  trace_ids: string
354
+ /** Usuario del que salieron las trazas. `""` cuando abarca varios. */
355
+ user_id: string
323
356
  insight_type: "success_pattern" | "failure_pattern" | "optimization" | "ethics_violation" | "root_cause" | "learning_proposal"
324
357
  description: string
325
358
  affected_tools: string | null
@@ -332,6 +365,16 @@ export interface PlaybookDoc {
332
365
  id: string
333
366
  rule: string
334
367
  category: string
368
+ /**
369
+ * De quién es lo aprendido. `""` = global, que es lo que corresponde a las
370
+ * reglas sembradas: son conocimiento del producto, no de nadie en particular.
371
+ *
372
+ * Sin esto el playbook era global a la instalación, así que **lo que el agente
373
+ * aprendía interactuando con una persona se le aplicaba a todas**. En una
374
+ * instalación de un solo usuario da igual; en un host multi-inquilino es una
375
+ * fuga entre workspaces.
376
+ */
377
+ user_id: string
335
378
  applicable_to: string | null
336
379
  helpful_count: number
337
380
  harmful_count: number
@@ -490,7 +533,15 @@ export interface ArtifactDoc {
490
533
  height: number | null
491
534
  status: "active" | "expired"
492
535
  created_at: number
493
- expires_at: number
536
+ /**
537
+ * `null` = no expira nunca.
538
+ *
539
+ * Los artefactos internos —capturas, resultados de tools grandes— son basura
540
+ * transitoria y se limpian solos a los 7 días. Pero un archivo que el usuario
541
+ * subió o transformó no es basura: borrárselo a la semana convierte un
542
+ * servicio en una pérdida de datos. Quien lo crea decide.
543
+ */
544
+ expires_at: number | null
494
545
  expired_at: number | null
495
546
  }
496
547
 
@@ -521,8 +572,21 @@ export interface TaskRunDoc {
521
572
  // ─── Stage 6: orchestration ───────────────────────────────────────────────────
522
573
 
523
574
  /** id = title — the old `notes`/`memory_*` table never existed, so this is a from-scratch fix. */
575
+ /**
576
+ * Memoria de largo plazo de un usuario.
577
+ *
578
+ * `id` es `${user_id}:${title}`. Hasta acá era sólo el título y la colección era
579
+ * global al proceso —coherente con que hive es mono-usuario, pero inservible
580
+ * para un runtime donde cada quien arma su colmena: dos usuarios no podían
581
+ * tener una memoria con el mismo título, y cualquiera veía la del otro.
582
+ *
583
+ * Las filas anteriores (id = título, sin `user_id`) se migran al arrancar
584
+ * asignándolas al usuario existente. Ver `migrateLegacyMemories`.
585
+ */
524
586
  export interface MemoryDoc {
525
587
  id: string
588
+ /** Dueño de la memoria. Las filas legacy se migran al usuario único. */
589
+ user_id: string
526
590
  title: string
527
591
  content: string
528
592
  created_at: number
@@ -582,6 +646,78 @@ export interface DelegationGroupDoc {
582
646
  notified_at: number | null
583
647
  }
584
648
 
649
+ /**
650
+ * Un enjambre guardado: qué agentes lo componen, con qué rol y en qué orden.
651
+ *
652
+ * Hasta acá un enjambre sólo existía mientras corría — `runRoleSwarm()` recibe
653
+ * los agentes en la llamada y no persiste nada. Quien armara uno desde una
654
+ * interfaz lo perdía al cerrar la ventana, y por eso hive-cloud terminó creando
655
+ * sus propias tablas en Postgres: no le quedaba alternativa.
656
+ *
657
+ * `agents_json` guarda `[{agentId, role, orderIndex}]`. Se deja como JSON y no
658
+ * como colección aparte a propósito: un enjambre se lee y se escribe entero,
659
+ * nunca por agente suelto, así que una tabla de unión sólo agregaría joins.
660
+ */
661
+ /**
662
+ * Un endpoint HTTP registrado como herramienta.
663
+ *
664
+ * Una tool normal es código con un `execute`, así que desde una interfaz no hay
665
+ * dónde ponerlo. Un endpoint declarativo invierte eso: el usuario aporta
666
+ * **datos** —URL, método, cabeceras, qué parámetros acepta— y el ejecutor es
667
+ * genérico y vive en el SDK. Es la única forma de que alguien sume una
668
+ * capacidad propia desde una UI sin abrir la puerta a ejecutar código
669
+ * arbitrario, y sin levantar un servidor MCP.
670
+ *
671
+ * Las credenciales NO viven acá: van cifradas en el secret store bajo
672
+ * `endpoint:<id>:headers`, igual que las de proveedores y canales. Esta fila es
673
+ * pública y se muestra en la UI; la clave, no.
674
+ */
675
+ export interface ApiEndpointDoc {
676
+ id: string
677
+ name: string
678
+ description: string
679
+ method: string
680
+ url: string
681
+ /** Cabeceras no sensibles. Las que llevan credenciales van al secret store. */
682
+ headers_json: string | null
683
+ /** Query fijos que siempre acompañan la llamada. */
684
+ query_json: string | null
685
+ /**
686
+ * Cuerpo con marcadores `{{param}}` que se reemplazan por lo que pase el
687
+ * modelo. Sin esto un endpoint POST sólo serviría con cuerpo fijo.
688
+ */
689
+ body_template: string | null
690
+ /** JSON Schema de lo que el modelo puede pasar — lo que ve como parámetros. */
691
+ param_schema_json: string | null
692
+ enabled: boolean
693
+ created_at: number
694
+ updated_at: number
695
+ }
696
+
697
+ export interface SwarmDoc {
698
+ id: string
699
+ name: string
700
+ description: string | null
701
+ /** Cómo se coordinan: en cadena, en paralelo, o con un orquestador que delega. */
702
+ strategy: "sequential" | "parallel" | "hierarchical"
703
+ /** Requerido por `hierarchical`; null en las otras dos. */
704
+ orchestrator_agent_id: string | null
705
+ /** `[{ agentId, role, orderIndex }]` — ver SwarmMemberSpec. */
706
+ agents_json: string
707
+ enabled: boolean
708
+ /** Tope de delegaciones en la estrategia jerárquica; null = el del runtime. */
709
+ max_delegations: number | null
710
+ created_at: number
711
+ updated_at: number
712
+ }
713
+
714
+ /** Un integrante del enjambre, tal como se serializa en `SwarmDoc.agents_json`. */
715
+ export interface SwarmMemberSpec {
716
+ agentId: string
717
+ role: "orchestrator" | "worker"
718
+ orderIndex: number
719
+ }
720
+
585
721
  export interface AgentBusMessageDoc {
586
722
  id: string
587
723
  event_type: string