@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.
- package/CHANGELOG.md +129 -0
- package/README.md +78 -23
- package/bun.lock +55 -29
- package/bunfig.toml +4 -2
- package/docs/API-AGENTS.md +78 -27
- package/docs/API-CONTEXT-COMPILER.md +31 -34
- package/docs/API-TOOLS-SKILLS-CHANNELS.md +58 -22
- package/docs/HIVE-HARNESS.md +1 -1
- package/docs/INDEX.md +4 -4
- package/docs/TEMPLATE-HIVE-APP.md +10 -10
- package/package.json +17 -12
- package/packages/cli/package.json +2 -2
- package/packages/cli/src/commands/create-app.test.ts +36 -7
- package/packages/cli/src/commands/init.ts +3 -3
- package/packages/cli/src/commands/run.ts +1 -1
- package/packages/cli/src/commands/test.ts +37 -25
- package/packages/cli/src/commands/trace.ts +30 -28
- package/packages/cli/templates/hive-app/.env.example +10 -2
- package/packages/cli/templates/hive-app/README.md +103 -0
- package/packages/cli/templates/hive-app/hive.config.ts +9 -3
- package/packages/cli/templates/hive-app/src/agents/coordinator.ts +8 -1
- package/packages/cli/templates/hive-app/src/main.ts +12 -19
- package/packages/core/package.json +13 -12
- package/packages/core/src/agent/acceptance-checks.ts +172 -0
- package/packages/core/src/agent/agent-catalog.ts +348 -0
- package/packages/core/src/agent/agent-loop.ts +1373 -0
- package/packages/core/src/agent/capability-search.ts +186 -0
- package/packages/core/src/agent/catalog-selector.ts +103 -0
- package/packages/core/src/agent/{Compaction.ts → compaction.ts} +86 -63
- package/packages/core/src/agent/context-compiler.ts +689 -0
- package/packages/core/src/agent/conversation-store.ts +381 -0
- package/packages/core/src/agent/curator.ts +276 -0
- package/packages/core/src/agent/delegation-runtime.ts +241 -0
- package/packages/core/src/agent/goal-runner.ts +323 -0
- package/packages/core/src/agent/index.ts +17 -12
- package/packages/core/src/agent/llm-client.ts +266 -0
- package/packages/core/src/agent/llm-providers/anthropic.ts +264 -0
- package/packages/core/src/agent/llm-providers/deepseek.ts +8 -0
- package/packages/core/src/agent/{providers → llm-providers}/gemini.ts +98 -60
- package/packages/core/src/agent/llm-providers/groq.ts +5 -0
- package/packages/core/src/agent/llm-providers/hiveagents.ts +253 -0
- package/packages/core/src/agent/{providers → llm-providers}/interface.ts +73 -13
- package/packages/core/src/agent/llm-providers/kimi.ts +8 -0
- package/packages/core/src/agent/llm-providers/minimax.ts +13 -0
- package/packages/core/src/agent/llm-providers/mistral.ts +5 -0
- package/packages/core/src/agent/llm-providers/modelscope.ts +5 -0
- package/packages/core/src/agent/llm-providers/nvidia.ts +5 -0
- package/packages/core/src/agent/{providers → llm-providers}/ollama.ts +31 -5
- package/packages/core/src/agent/llm-providers/openai-compat-base.ts +418 -0
- package/packages/core/src/agent/llm-providers/openai.ts +5 -0
- package/packages/core/src/agent/llm-providers/opencode-go.ts +9 -0
- package/packages/core/src/agent/llm-providers/openrouter.ts +5 -0
- package/packages/core/src/agent/llm-providers/qwen.ts +5 -0
- package/packages/core/src/agent/llm-providers/z-ai.ts +5 -0
- package/packages/core/src/agent/minimal-loadout.ts +47 -0
- package/packages/core/src/agent/playbook-selector.ts +119 -0
- package/packages/core/src/agent/{PromptBuilder.ts → prompt-builder.ts} +21 -22
- package/packages/core/src/{harness → agent}/proof-packet.ts +16 -21
- package/packages/core/src/agent/providers/index.ts +35 -16
- package/packages/core/src/agent/reflector.ts +320 -0
- package/packages/core/src/agent/routing-intent.ts +22 -0
- package/packages/core/src/{harness → agent}/run-epoch.ts +4 -3
- package/packages/core/src/{harness → agent}/run-store.ts +142 -81
- package/packages/core/src/agent/{Service.ts → service.ts} +37 -26
- package/packages/core/src/agent/skill-selector.ts +374 -0
- package/packages/core/src/agent/stuck-loop.ts +209 -0
- package/packages/core/src/agent/{selectors/ToolSelector.ts → tool-selector.ts} +188 -178
- package/packages/core/src/{ace/Tracer.ts → agent/tracer.ts} +37 -27
- package/packages/core/src/api/createAgent.test.ts +139 -27
- package/packages/core/src/api/createAgent.ts +232 -44
- package/packages/core/src/artifacts/store.ts +162 -0
- package/packages/core/src/canvas/canvas-manager.ts +161 -0
- package/packages/core/src/canvas/canvas.test.ts +8 -4
- package/packages/core/src/canvas/emitter.ts +131 -80
- package/packages/core/src/canvas/index.ts +1 -3
- package/packages/core/src/channels/base.ts +9 -1
- package/packages/core/src/channels/discord.ts +5 -4
- package/packages/core/src/channels/manager.ts +122 -30
- package/packages/core/src/channels/slack.ts +5 -4
- package/packages/core/src/channels/telegram.ts +36 -6
- package/packages/core/src/channels/webchat.ts +11 -10
- package/packages/core/src/channels/whatsapp.ts +23 -7
- package/packages/core/src/config/index.ts +13 -2
- package/packages/core/src/config/loader.ts +76 -29
- package/packages/core/src/ethics/EthicsGuard.test.ts +90 -36
- package/packages/core/src/ethics/EthicsGuard.ts +51 -47
- package/packages/core/src/events/agent-bus.ts +44 -68
- package/packages/core/src/events/channel-narration.ts +150 -0
- package/packages/core/src/events/narration.ts +82 -0
- package/packages/core/src/events/tool-narration.ts +62 -0
- package/packages/core/src/gateway/delegation-groups.ts +258 -0
- package/packages/core/src/{harness → gateway}/durable-queue.ts +102 -42
- package/packages/core/src/{harness → gateway}/job-store.ts +85 -48
- package/packages/core/src/gateway/lane-queue.ts +173 -0
- package/packages/core/src/gateway/notification-inbox.ts +57 -0
- package/packages/core/src/gateway/server.ts +1 -1
- package/packages/core/src/harness/index.ts +46 -27
- package/packages/core/src/index.ts +33 -27
- package/packages/core/src/mcp/hot-reload.ts +32 -23
- package/packages/core/src/mcp/index.ts +6 -3
- package/packages/core/src/mcp/singleton.ts +1 -4
- package/packages/core/src/mcp/tool-sync.ts +138 -0
- package/packages/core/src/memory/Scratchpad.test.ts +39 -20
- package/packages/core/src/memory/Scratchpad.ts +27 -34
- package/packages/core/src/multimodal/vision-service.ts +44 -38
- package/packages/core/src/resilience/retry.ts +95 -0
- package/packages/core/src/scheduler/CronScheduler.ts +334 -287
- package/packages/core/src/scheduler/index.ts +9 -7
- package/packages/core/src/scheduler/integration.ts +46 -26
- package/packages/core/src/scheduler/scheduler.test.ts +9 -13
- package/packages/core/src/scheduler/types.ts +7 -2
- package/packages/core/src/security/Pairing.ts +1 -1
- package/packages/core/src/skills/bundled/a2ui/a2ui_dashboard/SKILL.md +176 -0
- package/packages/core/src/skills/bundled/a2ui/a2ui_form/SKILL.md +202 -0
- package/packages/core/src/skills/bundled/a2ui/a2ui_interactive/SKILL.md +206 -0
- package/packages/core/src/skills/bundled/agents/agent_spawner/SKILL.md +173 -0
- package/packages/core/src/skills/bundled/agents/memory_manager/SKILL.md +143 -0
- package/packages/core/src/skills/bundled/agents/research_and_remember/SKILL.md +139 -0
- package/packages/core/src/skills/bundled/agents/task_orchestrator/SKILL.md +98 -0
- package/packages/core/src/skills/bundled/api/api_client/SKILL.md +132 -0
- package/packages/core/src/skills/bundled/cli/cli_pipeline/SKILL.md +135 -0
- package/packages/core/src/skills/bundled/cli/cli_safe_exec/SKILL.md +125 -0
- package/packages/core/src/skills/bundled/cli/software_engineering/SKILL.md +23 -0
- package/packages/core/src/skills/bundled/cron_manager/SKILL.md +188 -0
- package/packages/core/src/skills/bundled/cron_reminder/SKILL.md +112 -0
- package/packages/core/src/skills/bundled/filesystem/file_manager/SKILL.md +118 -0
- package/packages/core/src/skills/bundled/filesystem/file_read_and_summarize/SKILL.md +109 -0
- package/packages/core/src/skills/bundled/filesystem/file_writer/SKILL.md +129 -0
- package/packages/core/src/skills/bundled/filesystem/workspace_file_operator/SKILL.md +22 -0
- package/packages/core/src/skills/bundled/office/office_document_manager/SKILL.md +262 -0
- package/packages/core/src/skills/bundled/search_knowledge/capability_discovery/SKILL.md +75 -0
- package/packages/core/src/skills/bundled/web/browser_automate/SKILL.md +120 -0
- package/packages/core/src/skills/bundled/web/browser_scrape/SKILL.md +109 -0
- package/packages/core/src/skills/bundled/web/web_monitor/SKILL.md +127 -0
- package/packages/core/src/skills/bundled/web/web_research/SKILL.md +119 -0
- package/packages/core/src/skills/bundled-data.generated.ts +731 -2678
- package/packages/core/src/skills/skills.test.ts +52 -11
- package/packages/core/src/{harness → storage}/boot-id.ts +5 -2
- package/packages/core/src/storage/bootstrap.ts +151 -0
- package/packages/core/src/storage/causal-events.ts +84 -0
- package/packages/core/src/storage/collections.ts +680 -0
- package/packages/core/src/storage/crypto.ts +205 -74
- package/packages/core/src/{harness/db-helpers.ts → storage/hive.ts} +63 -7
- package/packages/core/src/storage/hivedb.ts +61 -0
- package/packages/core/src/storage/index.ts +111 -18
- package/packages/core/src/storage/model-id.ts +53 -0
- package/packages/core/src/storage/onboarding.ts +540 -972
- package/packages/core/src/storage/reconcile.ts +238 -0
- package/packages/core/src/storage/seed.ts +572 -406
- package/packages/core/src/storage/usage.ts +285 -225
- package/packages/core/src/storage/user-email.ts +11 -0
- package/packages/core/src/swarm/AgentExecutor.ts +1 -1
- package/packages/core/src/swarm/EventBridge.ts +1 -1
- package/packages/core/src/swarm/index.ts +12 -9
- package/packages/core/src/tool-runtime/index.ts +146 -23
- package/packages/core/src/tool-runtime/tool-worker.ts +2 -2
- package/packages/core/src/tool-runtime/worker-tools.ts +27 -0
- package/packages/core/src/{canvas/a2ui-tools.ts → tools/a2ui/index.ts} +17 -8
- package/packages/core/src/tools/agents/get-available-models.ts +36 -54
- package/packages/core/src/tools/agents/index.ts +784 -292
- package/packages/core/src/tools/api/api-request.test.ts +164 -0
- package/packages/core/src/tools/api/api-request.ts +174 -0
- package/packages/core/src/tools/api/index.ts +16 -0
- package/packages/core/src/tools/cli/index.ts +4 -0
- package/packages/core/src/tools/core/index.ts +281 -112
- package/packages/core/src/tools/cron/index.ts +121 -124
- package/packages/core/src/tools/index.ts +63 -78
- package/packages/core/src/tools/office/office-escribir-xlsx.ts +3 -1
- package/packages/core/src/tools/types.ts +3 -1
- package/packages/core/src/tools/web/artifact-inspect.ts +23 -0
- package/packages/core/src/tools/web/browser-backend.ts +129 -0
- package/packages/core/src/tools/web/browser-screenshot.ts +26 -5
- package/packages/core/src/tools/web/browser-service.ts +80 -35
- package/packages/core/src/tools/web/browser-type.ts +3 -8
- package/packages/core/src/tools/web/index.ts +4 -4
- package/packages/core/src/tools/web/webview-backend.ts +412 -0
- package/packages/core/src/voice/index.ts +89 -63
- package/packages/core/src/workers/agent.worker.ts +2 -2
- package/packages/core/src/workers/workers.test.ts +3 -10
- package/scripts/bump-version.ts +248 -0
- package/scripts/generate-skill-bundle.ts +108 -0
- package/test/acceptance-checks.test.ts +403 -0
- package/test/agent-loop-terminal-synthesis.test.ts +32 -0
- package/test/browser-backend.test.ts +308 -0
- package/test/catalog-agents-stay-enabled.test.ts +117 -0
- package/test/causal-events.test.ts +117 -0
- package/test/compaction.test.ts +105 -0
- package/test/context-compiler.test.ts +269 -0
- package/test/curator.test.ts +130 -0
- package/test/durable-queue.test.ts +114 -0
- package/test/harness-barrel.test.ts +64 -0
- package/test/hive-helpers.test.ts +130 -0
- package/test/hivedb-search.test.ts +189 -0
- package/test/internal-turns.test.ts +166 -0
- package/test/job-idempotency.test.ts +68 -0
- package/test/job-retry-backoff.test.ts +184 -0
- package/test/job-store.test.ts +381 -0
- package/test/llm-retry.test.ts +97 -0
- package/test/memory-perf.test.ts +774 -0
- package/test/minimal-loadout.test.ts +78 -0
- package/test/model-catalog.test.ts +105 -0
- package/test/preload.ts +12 -0
- package/test/reflector.test.ts +320 -0
- package/test/retention-cap.test.ts +91 -0
- package/test/retired-capabilities-pruned.test.ts +192 -0
- package/test/run-store.test.ts +355 -0
- package/test/scratchpad.test.ts +74 -0
- package/test/secrets-durability.test.ts +119 -0
- package/test/seed-model-reseed.test.ts +155 -0
- package/test/setup-agent-seed.test.ts +264 -0
- package/test/tool-inventory.test.ts +65 -0
- package/test/tool-runtime.test.ts +258 -0
- package/test/tool-selector-runtime-tools.test.ts +117 -0
- package/test/toon.test.ts +429 -0
- package/tsconfig.json +2 -0
- package/packages/core/src/ace/Curator.ts +0 -158
- package/packages/core/src/ace/Reflector.ts +0 -200
- package/packages/core/src/ace/index.ts +0 -4
- package/packages/core/src/agent/AgentRunner.ts +0 -711
- package/packages/core/src/agent/ContextCompiler.ts +0 -567
- package/packages/core/src/agent/ContextGuard.ts +0 -91
- package/packages/core/src/agent/ConversationStore.ts +0 -254
- package/packages/core/src/agent/Hooks.ts +0 -166
- package/packages/core/src/agent/StuckLoop.ts +0 -133
- package/packages/core/src/agent/providers/LLMClient.ts +0 -149
- package/packages/core/src/agent/providers/anthropic.ts +0 -212
- package/packages/core/src/agent/providers/openai-compat.ts +0 -231
- package/packages/core/src/agent/selectors/PlaybookSelector.ts +0 -121
- package/packages/core/src/agent/selectors/SkillSelector.ts +0 -322
- package/packages/core/src/agent/selectors/index.ts +0 -6
- package/packages/core/src/auth/auth.ts +0 -121
- package/packages/core/src/auth/index.ts +0 -1
- package/packages/core/src/canvas/CanvasManager.ts +0 -390
- package/packages/core/src/canvas/canvas-tools.ts +0 -448
- package/packages/core/src/harness/collections.ts +0 -98
- package/packages/core/src/harness/goal-verifier.ts +0 -141
- package/packages/core/src/harness/harness.test.ts +0 -236
- package/packages/core/src/harness/reconcile.ts +0 -149
- package/packages/core/src/mcp/MCPToolAdapter.ts +0 -176
- package/packages/core/src/multimodal/VisionService.ts +0 -293
- package/packages/core/src/scheduler/dag/AgentExecutor.ts +0 -53
- package/packages/core/src/scheduler/dag/DAGScheduler.ts +0 -250
- package/packages/core/src/scheduler/dag/EventBridge.ts +0 -122
- package/packages/core/src/scheduler/dag/TaskGraph.ts +0 -192
- package/packages/core/src/scheduler/dag/TaskNode.ts +0 -97
- package/packages/core/src/scheduler/dag/TaskResult.ts +0 -22
- package/packages/core/src/scheduler/dag/errors.ts +0 -37
- package/packages/core/src/scheduler/dag/index.ts +0 -26
- package/packages/core/src/scheduler/dag/presets/ResearchPreset.ts +0 -97
- package/packages/core/src/scheduler/dag/strategies/ParallelStrategy.ts +0 -21
- package/packages/core/src/scheduler/dag/strategies/PriorityStrategy.ts +0 -46
- package/packages/core/src/storage/HiveDBStorage.ts +0 -64
- package/packages/core/src/storage/SQLiteStorage.ts +0 -414
- package/packages/core/src/storage/hiveSeed.ts +0 -308
- package/packages/core/src/storage/hiveStorage.test.ts +0 -38
- package/packages/core/src/storage/schema.ts +0 -689
- package/packages/core/src/storage/storage.test.ts +0 -37
- package/packages/core/src/swarm/AgentBus.ts +0 -460
- package/packages/core/src/swarm/EventBus.ts +0 -169
- package/packages/core/src/swarm/WorkerPool.ts +0 -236
- package/packages/core/src/tools/bridge-events.ts +0 -26
- package/packages/core/src/tools/canvas/index.ts +0 -375
- package/packages/core/src/tools/codebridge/index.ts +0 -342
- package/packages/core/src/tools/meeting/index.ts +0 -353
- package/packages/core/src/tools/projects/index.ts +0 -37
- package/packages/core/src/tools/projects/project-create.ts +0 -94
- package/packages/core/src/tools/projects/project-done.ts +0 -66
- package/packages/core/src/tools/projects/project-fail.ts +0 -66
- package/packages/core/src/tools/projects/project-list.ts +0 -96
- package/packages/core/src/tools/projects/project-update.ts +0 -72
- package/packages/core/src/tools/projects/task-create.ts +0 -68
- package/packages/core/src/tools/projects/task-evaluate.ts +0 -93
- package/packages/core/src/tools/projects/task-update.ts +0 -93
- package/packages/core/src/tools/voice/index.ts +0 -104
- package/packages/core/src/tools/web/api-request.test.ts +0 -170
- package/packages/core/src/tools/web/api-request.ts +0 -239
- package/test/setup-db.ts +0 -216
- /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
|
-
}
|