@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
@@ -1,122 +0,0 @@
1
- /**
2
- * DAGScheduler — EventBridge
3
- *
4
- * Maps DAG lifecycle events to the existing agentBus so that the rest of
5
- * Hive OSS can observe swarm progress without coupling to DAGScheduler directly.
6
- *
7
- * Also emits canvas:node_update events so the UI reflects task state in real time.
8
- */
9
-
10
- import { agentBus } from "../../events/agent-bus"
11
- import { emitCanvas } from "../../canvas/emitter"
12
- import { TaskNode } from "./TaskNode"
13
- import { DAGResult } from "./TaskResult"
14
-
15
- const STATUS_TO_CANVAS: Record<string, string> = {
16
- RUNNING: "thinking",
17
- COMPLETED: "idle",
18
- FAILED: "error",
19
- }
20
-
21
- export class EventBridge {
22
- private swarmId: string
23
- private projectId: string
24
- private coordinatorId: string
25
-
26
- constructor(swarmId: string, projectId: string, coordinatorId: string) {
27
- this.swarmId = swarmId
28
- this.projectId = projectId
29
- this.coordinatorId = coordinatorId
30
- }
31
-
32
- onSwarmStarted(totalTasks: number): void {
33
- agentBus.publish("project:started", {
34
- projectId: this.projectId,
35
- projectName: `swarm:${this.swarmId}`,
36
- coordinatorId: this.coordinatorId,
37
- timestamp: Date.now(),
38
- })
39
-
40
- emitCanvas("canvas:node_update", {
41
- nodeId: this.projectId,
42
- changes: { status: "thinking", label: `Swarm started (${totalTasks} tasks)` },
43
- })
44
- }
45
-
46
- onTaskStarted(node: TaskNode): void {
47
- agentBus.notifyTaskStarted(
48
- node.agentId,
49
- node.name,
50
- 0, // task numeric ID not tracked here — DAG uses string IDs
51
- node.name,
52
- this.projectId
53
- )
54
-
55
- emitCanvas("canvas:node_update", {
56
- nodeId: node.agentId,
57
- changes: { status: STATUS_TO_CANVAS["RUNNING"], label: node.name },
58
- })
59
- }
60
-
61
- onTaskCompleted(node: TaskNode, progress: number): void {
62
- agentBus.notifyTaskCompleted(
63
- node.agentId,
64
- node.name,
65
- 0,
66
- node.name,
67
- this.projectId,
68
- node.result ?? ""
69
- )
70
-
71
- emitCanvas("canvas:node_update", {
72
- nodeId: node.agentId,
73
- changes: { status: STATUS_TO_CANVAS["COMPLETED"], progress },
74
- })
75
-
76
- // Broadcast overall swarm progress
77
- agentBus.publish("message:custom", {
78
- fromWorkerId: this.coordinatorId,
79
- fromWorkerName: "DAGScheduler",
80
- topic: "swarm:progress",
81
- content: String(progress),
82
- timestamp: Date.now(),
83
- })
84
- }
85
-
86
- onTaskFailed(node: TaskNode, progress: number): void {
87
- agentBus.notifyTaskFailed(
88
- node.agentId,
89
- node.name,
90
- 0,
91
- node.name,
92
- this.projectId,
93
- node.error ?? "unknown error"
94
- )
95
-
96
- emitCanvas("canvas:node_update", {
97
- nodeId: node.agentId,
98
- changes: { status: STATUS_TO_CANVAS["FAILED"] },
99
- })
100
- }
101
-
102
- onSwarmCompleted(result: DAGResult): void {
103
- const summary = `Completed ${result.completed.length}/${result.completed.length + result.failed.length} tasks in ${Math.round(result.totalDurationMs / 1000)}s`
104
-
105
- agentBus.publish("project:completed", {
106
- projectId: this.projectId,
107
- projectName: `swarm:${this.swarmId}`,
108
- coordinatorId: this.coordinatorId,
109
- summary,
110
- timestamp: Date.now(),
111
- })
112
-
113
- emitCanvas("canvas:node_update", {
114
- nodeId: this.projectId,
115
- changes: {
116
- status: result.success ? "idle" : "error",
117
- progress: 100,
118
- label: summary,
119
- },
120
- })
121
- }
122
- }
@@ -1,192 +0,0 @@
1
- /**
2
- * DAGScheduler — TaskGraph
3
- *
4
- * Owns the full set of TaskNodes for one swarm execution.
5
- * Responsibilities:
6
- * 1. Validate no cyclic dependencies (DFS) at construction time
7
- * 2. Calculate the critical path (longest weighted path)
8
- * 3. Provide runtime queries: ready nodes, overall progress
9
- */
10
-
11
- import { TaskNode, type TaskNodeConfig } from "./TaskNode"
12
- import { CyclicDependencyError } from "./errors"
13
-
14
- export class TaskGraph {
15
- readonly nodes: Map<string, TaskNode>
16
- private criticalPath_: string[] | null = null
17
-
18
- constructor(configs: TaskNodeConfig[]) {
19
- this.nodes = new Map(configs.map(c => [c.id, new TaskNode(c)]))
20
- this.validateNoCycles()
21
- }
22
-
23
- // ─── Validation ─────────────────────────────────────────────────────────────
24
-
25
- private validateNoCycles(): void {
26
- // Three-color DFS: WHITE=unvisited, GRAY=in-stack, BLACK=done
27
- const WHITE = 0, GRAY = 1, BLACK = 2
28
- const color = new Map<string, number>()
29
-
30
- for (const id of this.nodes.keys()) color.set(id, WHITE)
31
-
32
- const path: string[] = []
33
-
34
- const visit = (id: string): void => {
35
- color.set(id, GRAY)
36
- path.push(id)
37
-
38
- const node = this.nodes.get(id)!
39
- for (const dep of node.deps) {
40
- if (!this.nodes.has(dep)) {
41
- throw new Error(`TaskGraph: node "${id}" depends on unknown node "${dep}"`)
42
- }
43
- const c = color.get(dep)!
44
- if (c === GRAY) {
45
- // Found back-edge: reconstruct cycle
46
- const cycleStart = path.indexOf(dep)
47
- throw new CyclicDependencyError([...path.slice(cycleStart), dep])
48
- }
49
- if (c === WHITE) visit(dep)
50
- }
51
-
52
- path.pop()
53
- color.set(id, BLACK)
54
- }
55
-
56
- for (const id of this.nodes.keys()) {
57
- if (color.get(id) === WHITE) visit(id)
58
- }
59
- }
60
-
61
- // ─── Critical Path ───────────────────────────────────────────────────────────
62
-
63
- /**
64
- * Returns the IDs of the longest dependency chain (by node count).
65
- * Nodes on this path get higher priority in PriorityStrategy.
66
- */
67
- getCriticalPath(): string[] {
68
- if (this.criticalPath_) return this.criticalPath_
69
-
70
- // longest[id] = length of longest path ending at id (inclusive)
71
- const longest = new Map<string, number>()
72
- const predecessor = new Map<string, string | null>()
73
-
74
- const compute = (id: string): number => {
75
- if (longest.has(id)) return longest.get(id)!
76
- const node = this.nodes.get(id)!
77
- if (node.deps.length === 0) {
78
- longest.set(id, 1)
79
- predecessor.set(id, null)
80
- return 1
81
- }
82
- let max = 0
83
- let maxPred: string | null = null
84
- for (const dep of node.deps) {
85
- const l = compute(dep)
86
- if (l > max) { max = l; maxPred = dep }
87
- }
88
- longest.set(id, max + 1)
89
- predecessor.set(id, maxPred)
90
- return max + 1
91
- }
92
-
93
- for (const id of this.nodes.keys()) compute(id)
94
-
95
- // Find sink with max longest
96
- let sinkId = ""
97
- let maxLen = 0
98
- for (const [id, len] of longest) {
99
- if (len > maxLen) { maxLen = len; sinkId = id }
100
- }
101
-
102
- // Reconstruct path from sink to source, then reverse
103
- const path: string[] = []
104
- let cur: string | null = sinkId
105
- while (cur !== null) {
106
- path.push(cur)
107
- cur = predecessor.get(cur) ?? null
108
- }
109
- path.reverse()
110
-
111
- this.criticalPath_ = path
112
- return path
113
- }
114
-
115
- // ─── Runtime queries ─────────────────────────────────────────────────────────
116
-
117
- /** Nodes that are still PENDING but now have all deps completed */
118
- getNewlyReadyNodes(completedIds: Set<string>): TaskNode[] {
119
- const ready: TaskNode[] = []
120
- for (const node of this.nodes.values()) {
121
- if (node.status === "PENDING" && node.canStart(completedIds)) {
122
- ready.push(node)
123
- }
124
- }
125
- return ready
126
- }
127
-
128
- /** All nodes currently in READY state */
129
- getReadyNodes(): TaskNode[] {
130
- return [...this.nodes.values()].filter(n => n.status === "READY")
131
- }
132
-
133
- /** IDs of all COMPLETED nodes */
134
- getCompletedIds(): Set<string> {
135
- const ids = new Set<string>()
136
- for (const [id, node] of this.nodes) {
137
- if (node.status === "COMPLETED") ids.add(id)
138
- }
139
- return ids
140
- }
141
-
142
- /** Collect results of all deps for a given node */
143
- getDepResults(nodeId: string): Record<string, string> {
144
- const node = this.nodes.get(nodeId)!
145
- const results: Record<string, string> = {}
146
- for (const dep of node.deps) {
147
- const depNode = this.nodes.get(dep)!
148
- if (depNode.result !== undefined) results[dep] = depNode.result
149
- }
150
- return results
151
- }
152
-
153
- /** 0–100 progress based on nodes in terminal state */
154
- getProgress(): number {
155
- const total = this.nodes.size
156
- if (total === 0) return 100
157
- let done = 0
158
- for (const node of this.nodes.values()) {
159
- if (node.status === "COMPLETED" || node.status === "FAILED") done++
160
- }
161
- return Math.round((done / total) * 100)
162
- }
163
-
164
- /** True when every node is in a terminal state */
165
- isComplete(): boolean {
166
- for (const node of this.nodes.values()) {
167
- if (node.status === "PENDING" || node.status === "READY" || node.status === "RUNNING") {
168
- return false
169
- }
170
- }
171
- return true
172
- }
173
-
174
- /** Propagate FAILED status to all nodes that depend (directly or transitively) on failedId */
175
- propagateFailure(failedId: string, reason: string): void {
176
- const failedSet = new Set<string>([failedId])
177
-
178
- let changed = true
179
- while (changed) {
180
- changed = false
181
- for (const node of this.nodes.values()) {
182
- if (node.status === "PENDING" || node.status === "READY") {
183
- if (node.deps.some(d => failedSet.has(d))) {
184
- node.markFailed(`dependency_failed: ${reason}`)
185
- failedSet.add(node.id)
186
- changed = true
187
- }
188
- }
189
- }
190
- }
191
- }
192
- }
@@ -1,97 +0,0 @@
1
- /**
2
- * DAGScheduler — TaskNode
3
- *
4
- * Represents a single node in the task graph. Tracks its own state,
5
- * retry count, timing, and the results of its dependencies.
6
- */
7
-
8
- export type NodeStatus = "PENDING" | "READY" | "RUNNING" | "COMPLETED" | "FAILED"
9
-
10
- export interface TaskNodeConfig {
11
- /** Unique ID within this graph (can match SQLite task.id) */
12
- id: string
13
- /** agents.id of the worker agent to execute */
14
- agentId: string
15
- /** Human-readable name for logging */
16
- name: string
17
- /** Task description passed to the worker */
18
- taskDescription: string
19
- /** IDs of other TaskNodes that must complete first */
20
- deps: string[]
21
- /** Timeout in ms before the task is cancelled. Default: 120_000 */
22
- timeout?: number
23
- /** How many times to retry on failure. Default: 1 */
24
- maxRetries?: number
25
- /** Priority hint for PriorityStrategy. Higher = runs first. Default: 0 */
26
- priority?: number
27
- /** Optional arbitrary metadata forwarded to the worker */
28
- metadata?: Record<string, unknown>
29
- }
30
-
31
- export class TaskNode {
32
- readonly id: string
33
- readonly agentId: string
34
- readonly name: string
35
- readonly taskDescription: string
36
- readonly deps: string[]
37
- readonly timeout: number
38
- readonly maxRetries: number
39
- readonly priority: number
40
- readonly metadata: Record<string, unknown>
41
-
42
- status: NodeStatus = "PENDING"
43
- retryCount = 0
44
- startedAt?: number
45
- completedAt?: number
46
- result?: string
47
- error?: string
48
-
49
- constructor(config: TaskNodeConfig) {
50
- this.id = config.id
51
- this.agentId = config.agentId
52
- this.name = config.name
53
- this.taskDescription = config.taskDescription
54
- this.deps = config.deps
55
- this.timeout = config.timeout ?? 120_000
56
- this.maxRetries = config.maxRetries ?? 1
57
- this.priority = config.priority ?? 0
58
- this.metadata = config.metadata ?? {}
59
- }
60
-
61
- /** Returns true if all dependency IDs are in the completed set */
62
- canStart(completedIds: Set<string>): boolean {
63
- return this.deps.every(dep => completedIds.has(dep))
64
- }
65
-
66
- markReady(): void {
67
- this.status = "READY"
68
- }
69
-
70
- markRunning(): void {
71
- this.status = "RUNNING"
72
- this.startedAt = Date.now()
73
- }
74
-
75
- markCompleted(result: string): void {
76
- this.status = "COMPLETED"
77
- this.completedAt = Date.now()
78
- this.result = result
79
- }
80
-
81
- markFailed(error: string): void {
82
- this.status = "FAILED"
83
- this.completedAt = Date.now()
84
- this.error = error
85
- }
86
-
87
- canRetry(): boolean {
88
- return this.retryCount < this.maxRetries
89
- }
90
-
91
- /** Elapsed time in seconds since start, or total duration if done */
92
- elapsedSeconds(): number {
93
- if (!this.startedAt) return 0
94
- const end = this.completedAt ?? Date.now()
95
- return Math.round((end - this.startedAt) / 1000)
96
- }
97
- }
@@ -1,22 +0,0 @@
1
- /**
2
- * DAGScheduler — Result types
3
- */
4
-
5
- export interface NodeSummary {
6
- id: string
7
- name: string
8
- status: "COMPLETED" | "FAILED"
9
- durationMs: number
10
- result?: string
11
- error?: string
12
- retries: number
13
- }
14
-
15
- export interface DAGResult {
16
- swarmId: string
17
- totalDurationMs: number
18
- completed: NodeSummary[]
19
- failed: NodeSummary[]
20
- /** true if all nodes completed successfully */
21
- success: boolean
22
- }
@@ -1,37 +0,0 @@
1
- /**
2
- * DAGScheduler — Custom errors
3
- */
4
-
5
- export class CyclicDependencyError extends Error {
6
- readonly cycle: string[]
7
-
8
- constructor(cycle: string[]) {
9
- super(`Cyclic dependency detected: ${cycle.join(" → ")}`)
10
- this.name = "CyclicDependencyError"
11
- this.cycle = cycle
12
- }
13
- }
14
-
15
- export class TaskTimeoutError extends Error {
16
- readonly nodeId: string
17
- readonly timeoutMs: number
18
-
19
- constructor(nodeId: string, timeoutMs: number) {
20
- super(`Task "${nodeId}" timed out after ${timeoutMs}ms`)
21
- this.name = "TaskTimeoutError"
22
- this.nodeId = nodeId
23
- this.timeoutMs = timeoutMs
24
- }
25
- }
26
-
27
- export class TaskFailureError extends Error {
28
- readonly nodeId: string
29
- readonly cause: Error
30
-
31
- constructor(nodeId: string, cause: Error) {
32
- super(`Task "${nodeId}" failed: ${cause.message}`)
33
- this.name = "TaskFailureError"
34
- this.nodeId = nodeId
35
- this.cause = cause
36
- }
37
- }
@@ -1,26 +0,0 @@
1
- /**
2
- * DAGScheduler — Public API
3
- *
4
- * Usage:
5
- * import { DAGScheduler, TaskGraph, ParallelStrategy } from "./dag"
6
- */
7
-
8
- export { DAGScheduler } from "./DAGScheduler"
9
- export type { DAGSchedulerOptions } from "./DAGScheduler"
10
-
11
- export { TaskGraph } from "./TaskGraph"
12
- export { TaskNode } from "./TaskNode"
13
- export type { TaskNodeConfig, NodeStatus } from "./TaskNode"
14
- export type { DAGResult, NodeSummary } from "./TaskResult"
15
-
16
- export { AgentExecutor } from "./AgentExecutor"
17
- export { EventBridge } from "./EventBridge"
18
-
19
- export { CyclicDependencyError, TaskTimeoutError, TaskFailureError } from "./errors"
20
-
21
- export { ParallelStrategy } from "./strategies/ParallelStrategy"
22
- export type { ExecutionStrategy } from "./strategies/ParallelStrategy"
23
- export { PriorityStrategy } from "./strategies/PriorityStrategy"
24
-
25
- export { createResearchGraph } from "./presets/ResearchPreset"
26
- export type { ResearchAgentIds } from "./presets/ResearchPreset"
@@ -1,97 +0,0 @@
1
- /**
2
- * ResearchPreset — Pre-configured DAG for general research swarms
3
- *
4
- * Dependency graph:
5
- * ResearchAgent ─┐
6
- * StrategyAgent ├── SynthesisAgent (all three run in parallel)
7
- * DesignAgent ─┘
8
- *
9
- * All three parallel agents are fully independent. SynthesisAgent
10
- * waits for all three and combines their outputs into a final deliverable.
11
- *
12
- * Usage:
13
- * const graph = createResearchGraph(
14
- * { research: "agent-uuid-1", strategy: "agent-uuid-2",
15
- * design: "agent-uuid-3", synthesis: "agent-uuid-4" },
16
- * "Design a distributed caching strategy for the platform"
17
- * )
18
- * await scheduler.execute(graph, { projectId, coordinatorId })
19
- */
20
-
21
- import { TaskGraph } from "../TaskGraph"
22
- import type { TaskNodeConfig } from "../TaskNode"
23
-
24
- export interface ResearchAgentIds {
25
- research: string
26
- strategy: string
27
- design: string
28
- synthesis: string
29
- }
30
-
31
- export function createResearchGraph(
32
- agentIds: ResearchAgentIds,
33
- topic: string,
34
- options: {
35
- researchTimeout?: number
36
- strategyTimeout?: number
37
- designTimeout?: number
38
- synthesisTimeout?: number
39
- } = {}
40
- ): TaskGraph {
41
- const nodes: TaskNodeConfig[] = [
42
- {
43
- id: "research",
44
- agentId: agentIds.research,
45
- name: "ResearchAgent",
46
- taskDescription:
47
- `Research the following topic using available knowledge bases and sources: "${topic}".` +
48
- ` Output: { findings: string[], sources: string[], keyInsights: string[] }.`,
49
- deps: [],
50
- timeout: options.researchTimeout ?? 120_000,
51
- maxRetries: 1,
52
- priority: 8,
53
- },
54
- {
55
- id: "strategy",
56
- agentId: agentIds.strategy,
57
- name: "StrategyAgent",
58
- taskDescription:
59
- `Design a strategic framework or approach for: "${topic}".` +
60
- ` Work independently — you will NOT have the research findings yet.` +
61
- ` Output: { approach: string, phases: string[], risks: string[], successMetrics: string[] }.`,
62
- deps: [],
63
- timeout: options.strategyTimeout ?? 90_000,
64
- maxRetries: 1,
65
- priority: 8,
66
- },
67
- {
68
- id: "design",
69
- agentId: agentIds.design,
70
- name: "DesignAgent",
71
- taskDescription:
72
- `Design the structure or architecture for: "${topic}".` +
73
- ` Work independently — focus on structure, not content.` +
74
- ` Output: { structure: string, components: string[], diagram: string (ASCII or Mermaid) }.`,
75
- deps: [],
76
- timeout: options.designTimeout ?? 90_000,
77
- maxRetries: 1,
78
- priority: 8,
79
- },
80
- {
81
- id: "synthesis",
82
- agentId: agentIds.synthesis,
83
- name: "SynthesisAgent",
84
- taskDescription:
85
- `Synthesize the research findings, strategic framework, and design structure into a cohesive deliverable.` +
86
- ` The dependency context contains all three agents' outputs.` +
87
- ` Topic: "${topic}".` +
88
- ` Output a comprehensive, well-structured document that combines all inputs coherently.`,
89
- deps: ["research", "strategy", "design"],
90
- timeout: options.synthesisTimeout ?? 150_000,
91
- maxRetries: 2,
92
- priority: 0,
93
- },
94
- ]
95
-
96
- return new TaskGraph(nodes)
97
- }
@@ -1,21 +0,0 @@
1
- /**
2
- * ParallelStrategy — executes DAG nodes in parallel as slots become available
3
- *
4
- * Picks nodes from the READY queue in FIFO order.
5
- * Nodes are launched immediately when a worker slot is available,
6
- * otherwise they wait in the queue.
7
- */
8
-
9
- import { TaskNode } from "../TaskNode"
10
-
11
- export interface ExecutionStrategy {
12
- pick(queue: TaskNode[]): TaskNode | undefined
13
- /** Called once at graph start to allow strategy-level initialization */
14
- initialize?(nodes: Map<string, TaskNode>): void
15
- }
16
-
17
- export class ParallelStrategy implements ExecutionStrategy {
18
- pick(queue: TaskNode[]): TaskNode | undefined {
19
- return queue.shift()
20
- }
21
- }
@@ -1,46 +0,0 @@
1
- /**
2
- * PriorityStrategy — for research swarms
3
- *
4
- * Boosts the priority of nodes on the critical path so they run first
5
- * when slots are limited. Within same effective priority, FIFO order applies.
6
- */
7
-
8
- import { TaskNode } from "../TaskNode"
9
- import { TaskGraph } from "../TaskGraph"
10
- import type { ExecutionStrategy } from "./ParallelStrategy"
11
-
12
- export class PriorityStrategy implements ExecutionStrategy {
13
- private criticalPathSet = new Set<string>()
14
- private readonly CRITICAL_BOOST = 1000
15
-
16
- initialize(nodes: Map<string, TaskNode>): void {
17
- // Build a temporary graph for critical path calculation
18
- const configs = [...nodes.values()].map(n => ({
19
- id: n.id,
20
- agentId: n.agentId,
21
- name: n.name,
22
- taskDescription: n.taskDescription,
23
- deps: n.deps,
24
- timeout: n.timeout,
25
- maxRetries: n.maxRetries,
26
- priority: n.priority,
27
- }))
28
- const graph = new TaskGraph(configs)
29
- for (const id of graph.getCriticalPath()) {
30
- this.criticalPathSet.add(id)
31
- }
32
- }
33
-
34
- pick(queue: TaskNode[]): TaskNode | undefined {
35
- if (queue.length === 0) return undefined
36
-
37
- // Sort: critical path nodes first, then by node.priority desc, then FIFO (stable)
38
- queue.sort((a, b) => {
39
- const aBoost = this.criticalPathSet.has(a.id) ? this.CRITICAL_BOOST : 0
40
- const bBoost = this.criticalPathSet.has(b.id) ? this.CRITICAL_BOOST : 0
41
- return (b.priority + bBoost) - (a.priority + aBoost)
42
- })
43
-
44
- return queue.shift()
45
- }
46
- }