@johpaz/hive-sdk 0.0.12 → 0.0.15

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 (199) hide show
  1. package/.github/CODEOWNERS +9 -0
  2. package/.github/workflows/publish.yml +89 -0
  3. package/.github/workflows/version-bump.yml +102 -0
  4. package/CHANGELOG.md +38 -0
  5. package/README.md +158 -0
  6. package/bun.lock +543 -0
  7. package/bunfig.toml +7 -0
  8. package/docs/API-AGENTS.md +316 -0
  9. package/docs/API-CONTEXT-COMPILER.md +252 -0
  10. package/docs/API-DAG-SCHEDULER.md +273 -0
  11. package/docs/API-TOOLS-SKILLS-CHANNELS.md +293 -0
  12. package/docs/API-WORKERS-EVENTS.md +152 -0
  13. package/docs/INDEX.md +141 -0
  14. package/docs/README.md +68 -0
  15. package/package.json +54 -105
  16. package/packages/cli/package.json +17 -0
  17. package/packages/cli/src/commands/init.ts +56 -0
  18. package/packages/cli/src/commands/run.ts +45 -0
  19. package/packages/cli/src/commands/test.ts +42 -0
  20. package/packages/cli/src/commands/trace.ts +55 -0
  21. package/packages/cli/src/index.ts +43 -0
  22. package/packages/core/package.json +58 -0
  23. package/packages/core/src/ace/Curator.ts +158 -0
  24. package/packages/core/src/ace/Reflector.ts +200 -0
  25. package/packages/core/src/ace/Tracer.ts +100 -0
  26. package/packages/core/src/ace/index.ts +4 -0
  27. package/packages/core/src/agent/AgentRunner.ts +699 -0
  28. package/packages/core/src/agent/Compaction.ts +221 -0
  29. package/packages/core/src/agent/ContextCompiler.ts +567 -0
  30. package/packages/core/src/agent/ContextGuard.ts +91 -0
  31. package/packages/core/src/agent/ConversationStore.ts +244 -0
  32. package/packages/core/src/agent/Hooks.ts +166 -0
  33. package/packages/core/src/agent/NativeTools.ts +31 -0
  34. package/packages/core/src/agent/PromptBuilder.ts +169 -0
  35. package/packages/core/src/agent/Service.ts +267 -0
  36. package/packages/core/src/agent/StuckLoop.ts +133 -0
  37. package/packages/core/src/agent/index.ts +12 -0
  38. package/packages/core/src/agent/providers/LLMClient.ts +149 -0
  39. package/packages/core/src/agent/providers/anthropic.ts +212 -0
  40. package/packages/core/src/agent/providers/gemini.ts +215 -0
  41. package/packages/core/src/agent/providers/index.ts +199 -0
  42. package/packages/core/src/agent/providers/interface.ts +195 -0
  43. package/packages/core/src/agent/providers/ollama.ts +175 -0
  44. package/packages/core/src/agent/providers/openai-compat.ts +231 -0
  45. package/packages/core/src/agent/providers.ts +1 -0
  46. package/packages/core/src/agent/selectors/PlaybookSelector.ts +147 -0
  47. package/packages/core/src/agent/selectors/SkillSelector.ts +478 -0
  48. package/packages/core/src/agent/selectors/ToolSelector.ts +577 -0
  49. package/packages/core/src/agent/selectors/index.ts +6 -0
  50. package/packages/core/src/api/createAgent.test.ts +48 -0
  51. package/packages/core/src/api/createAgent.ts +122 -0
  52. package/packages/core/src/api/index.ts +2 -0
  53. package/packages/core/src/canvas/CanvasManager.ts +390 -0
  54. package/packages/core/src/canvas/a2ui-tools.ts +255 -0
  55. package/packages/core/src/canvas/canvas-tools.ts +448 -0
  56. package/packages/core/src/canvas/emitter.ts +149 -0
  57. package/packages/core/src/canvas/index.ts +6 -0
  58. package/packages/core/src/config/index.ts +2 -0
  59. package/packages/core/src/config/loader.ts +554 -0
  60. package/packages/core/src/ethics/EthicsGuard.test.ts +54 -0
  61. package/packages/core/src/ethics/EthicsGuard.ts +66 -0
  62. package/packages/core/src/ethics/index.ts +2 -0
  63. package/packages/core/src/gateway/channel-notify.test.ts +14 -0
  64. package/packages/core/src/gateway/channel-notify.ts +12 -0
  65. package/packages/core/src/gateway/index.ts +1 -0
  66. package/packages/core/src/index.ts +37 -0
  67. package/packages/core/src/mcp/MCPClient.ts +439 -0
  68. package/packages/core/src/mcp/MCPToolAdapter.ts +176 -0
  69. package/packages/core/src/mcp/config.ts +13 -0
  70. package/packages/core/src/mcp/hot-reload.ts +147 -0
  71. package/packages/core/src/mcp/index.ts +11 -0
  72. package/packages/core/src/mcp/logger.ts +42 -0
  73. package/packages/core/src/mcp/singleton.ts +21 -0
  74. package/packages/core/src/mcp/transports/index.ts +67 -0
  75. package/packages/core/src/mcp/transports/sse.ts +241 -0
  76. package/packages/core/src/mcp/transports/websocket.ts +159 -0
  77. package/packages/core/src/memory/Scratchpad.test.ts +47 -0
  78. package/packages/core/src/memory/Scratchpad.ts +37 -0
  79. package/packages/core/src/memory/Storage.ts +6 -0
  80. package/packages/core/src/memory/index.ts +2 -0
  81. package/packages/core/src/multimodal/VisionService.ts +293 -0
  82. package/packages/core/src/multimodal/index.ts +2 -0
  83. package/packages/core/src/multimodal/types.ts +28 -0
  84. package/packages/core/src/security/Pairing.ts +250 -0
  85. package/packages/core/src/security/RateLimit.ts +270 -0
  86. package/packages/core/src/security/index.ts +4 -0
  87. package/packages/core/src/skills/SkillLoader.ts +388 -0
  88. package/packages/core/src/skills/bundled-data.generated.ts +3332 -0
  89. package/packages/core/src/skills/defineSkill.ts +18 -0
  90. package/packages/core/src/skills/index.ts +4 -0
  91. package/packages/core/src/state/index.ts +2 -0
  92. package/packages/core/src/state/store.ts +312 -0
  93. package/packages/core/src/storage/SQLiteStorage.ts +407 -0
  94. package/packages/core/src/storage/crypto.ts +101 -0
  95. package/packages/core/src/storage/index.ts +10 -0
  96. package/packages/core/src/storage/onboarding.ts +1603 -0
  97. package/packages/core/src/storage/schema.ts +689 -0
  98. package/packages/core/src/storage/seed.ts +740 -0
  99. package/packages/core/src/storage/usage.ts +374 -0
  100. package/packages/core/src/swarm/AgentBus.ts +460 -0
  101. package/packages/core/src/swarm/AgentExecutor.ts +53 -0
  102. package/packages/core/src/swarm/Coordinator.ts +251 -0
  103. package/packages/core/src/swarm/EventBridge.ts +122 -0
  104. package/packages/core/src/swarm/EventBus.ts +169 -0
  105. package/packages/core/src/swarm/TaskGraph.ts +192 -0
  106. package/packages/core/src/swarm/TaskNode.ts +97 -0
  107. package/packages/core/src/swarm/TaskResult.ts +22 -0
  108. package/packages/core/src/swarm/WorkerPool.ts +236 -0
  109. package/packages/core/src/swarm/errors.ts +37 -0
  110. package/packages/core/src/swarm/index.ts +30 -0
  111. package/packages/core/src/swarm/presets/HiveLearnPreset.ts +99 -0
  112. package/packages/core/src/swarm/presets/ResearchPreset.ts +97 -0
  113. package/packages/core/src/swarm/presets/index.ts +4 -0
  114. package/packages/core/src/swarm/strategies/ParallelStrategy.ts +21 -0
  115. package/packages/core/src/swarm/strategies/PriorityStrategy.ts +46 -0
  116. package/packages/core/src/swarm/strategies/index.ts +3 -0
  117. package/packages/core/src/swarm/types.ts +164 -0
  118. package/packages/core/src/tools/ToolExecutor.ts +58 -0
  119. package/packages/core/src/tools/ToolRegistry.test.ts +98 -0
  120. package/packages/core/src/tools/ToolRegistry.ts +61 -0
  121. package/packages/core/src/tools/agents/get-available-models.ts +118 -0
  122. package/packages/core/src/tools/agents/index.ts +715 -0
  123. package/packages/core/src/tools/bridge-events.ts +26 -0
  124. package/packages/core/src/tools/canvas/index.ts +375 -0
  125. package/packages/core/src/tools/cli/index.ts +142 -0
  126. package/packages/core/src/tools/codebridge/index.ts +342 -0
  127. package/packages/core/src/tools/core/index.ts +476 -0
  128. package/packages/core/src/tools/cron/index.ts +626 -0
  129. package/packages/core/src/tools/filesystem/fs-delete.ts +78 -0
  130. package/packages/core/src/tools/filesystem/fs-edit.ts +106 -0
  131. package/packages/core/src/tools/filesystem/fs-exists.ts +63 -0
  132. package/packages/core/src/tools/filesystem/fs-glob.ts +108 -0
  133. package/packages/core/src/tools/filesystem/fs-list.ts +129 -0
  134. package/packages/core/src/tools/filesystem/fs-read.ts +72 -0
  135. package/packages/core/src/tools/filesystem/fs-write.ts +67 -0
  136. package/packages/core/src/tools/filesystem/index.ts +34 -0
  137. package/packages/core/src/tools/filesystem/workspace-guard.ts +62 -0
  138. package/packages/core/src/tools/index.ts +231 -0
  139. package/packages/core/src/tools/meeting/index.ts +363 -0
  140. package/packages/core/src/tools/office/index.ts +47 -0
  141. package/packages/core/src/tools/office/office-escribir-docx.ts +192 -0
  142. package/packages/core/src/tools/office/office-escribir-pdf.ts +172 -0
  143. package/packages/core/src/tools/office/office-escribir-pptx.ts +174 -0
  144. package/packages/core/src/tools/office/office-escribir-xlsx.ts +116 -0
  145. package/packages/core/src/tools/office/office-leer-docx.ts +93 -0
  146. package/packages/core/src/tools/office/office-leer-pdf.ts +114 -0
  147. package/packages/core/src/tools/office/office-leer-pptx.ts +136 -0
  148. package/packages/core/src/tools/office/office-leer-xlsx.ts +124 -0
  149. package/packages/core/src/tools/projects/index.ts +37 -0
  150. package/packages/core/src/tools/projects/project-create.ts +94 -0
  151. package/packages/core/src/tools/projects/project-done.ts +66 -0
  152. package/packages/core/src/tools/projects/project-fail.ts +66 -0
  153. package/packages/core/src/tools/projects/project-list.ts +96 -0
  154. package/packages/core/src/tools/projects/project-update.ts +72 -0
  155. package/packages/core/src/tools/projects/task-create.ts +68 -0
  156. package/packages/core/src/tools/projects/task-evaluate.ts +93 -0
  157. package/packages/core/src/tools/projects/task-update.ts +93 -0
  158. package/packages/core/src/tools/types.ts +39 -0
  159. package/packages/core/src/tools/voice/index.ts +104 -0
  160. package/packages/core/src/tools/web/browser-click.ts +78 -0
  161. package/packages/core/src/tools/web/browser-extract.ts +139 -0
  162. package/packages/core/src/tools/web/browser-navigate.ts +106 -0
  163. package/packages/core/src/tools/web/browser-screenshot.ts +87 -0
  164. package/packages/core/src/tools/web/browser-script.ts +88 -0
  165. package/packages/core/src/tools/web/browser-service.ts +554 -0
  166. package/packages/core/src/tools/web/browser-type.ts +101 -0
  167. package/packages/core/src/tools/web/browser-wait.ts +136 -0
  168. package/packages/core/src/tools/web/index.ts +41 -0
  169. package/packages/core/src/tools/web/web-fetch.ts +78 -0
  170. package/packages/core/src/tools/web/web-search.ts +123 -0
  171. package/packages/core/src/utils/benchmark.ts +80 -0
  172. package/packages/core/src/utils/crypto.ts +73 -0
  173. package/packages/core/src/utils/date.ts +42 -0
  174. package/packages/core/src/utils/index.ts +10 -0
  175. package/packages/core/src/utils/logger.ts +389 -0
  176. package/packages/core/src/utils/retry.ts +70 -0
  177. package/packages/core/src/utils/toon.ts +253 -0
  178. package/packages/core/src/voice/index.ts +656 -0
  179. package/test/setup-db.ts +216 -0
  180. package/tsconfig.json +39 -0
  181. package/src/agents.ts +0 -1
  182. package/src/canvas.ts +0 -1
  183. package/src/channels.ts +0 -1
  184. package/src/config.ts +0 -1
  185. package/src/events.ts +0 -1
  186. package/src/gateway.ts +0 -1
  187. package/src/index.ts +0 -304
  188. package/src/mcp.ts +0 -1
  189. package/src/multimodal.ts +0 -1
  190. package/src/scheduler.ts +0 -1
  191. package/src/security.ts +0 -1
  192. package/src/skills.ts +0 -1
  193. package/src/state.ts +0 -1
  194. package/src/storage.ts +0 -1
  195. package/src/tools.ts +0 -1
  196. package/src/tts.ts +0 -1
  197. package/src/types.ts +0 -82
  198. package/src/utils.ts +0 -1
  199. package/src/voice.ts +0 -1
@@ -0,0 +1,99 @@
1
+ /**
2
+ * HiveLearnPreset — Pre-configured DAG for the HiveLearn swarm
3
+ *
4
+ * Dependency graph:
5
+ * CurriculumAgent (no deps, priority=10)
6
+ * ↓ ↓
7
+ * ContentAgent VisualAgent ← run IN PARALLEL after Curriculum
8
+ * ↓ ↓
9
+ * └──── GamificationAgent (waits for both)
10
+ *
11
+ * Expected timing with maxConcurrentWorkers=2 on BOSGAME:
12
+ * T=0s → CurriculumAgent starts
13
+ * T=~30s → CurriculumAgent done → Content + Visual start in parallel
14
+ * T=~100s → both done → GamificationAgent starts
15
+ * T=~120s → GamificationAgent done → swarm:completed
16
+ * Savings vs sequential: ~38% (~75s)
17
+ */
18
+
19
+ import { TaskGraph } from "../TaskGraph"
20
+ import type { TaskNodeConfig } from "../TaskNode"
21
+
22
+ export interface HiveLearnAgentIds {
23
+ curriculum: string
24
+ content: string
25
+ visual: string
26
+ gamification: string
27
+ }
28
+
29
+ export interface HiveLearnInput {
30
+ learnerGoal: string
31
+ nodeType: string
32
+ /** Optional session/user context to include in descriptions */
33
+ context?: string
34
+ }
35
+
36
+ export function createHiveLearnGraph(
37
+ agentIds: HiveLearnAgentIds,
38
+ input: HiveLearnInput
39
+ ): TaskGraph {
40
+ const ctxNote = input.context ? ` Context: ${input.context}` : ""
41
+
42
+ const nodes: TaskNodeConfig[] = [
43
+ {
44
+ id: "curriculum",
45
+ agentId: agentIds.curriculum,
46
+ name: "CurriculumAgent",
47
+ taskDescription:
48
+ `Design a structured curriculum for the following learner goal: "${input.learnerGoal}".` +
49
+ ` Focus on the node type: "${input.nodeType}".` +
50
+ ` Output a JSON object with: { title, objectives: string[], prerequisites: string[], estimatedMinutes: number }.` +
51
+ ctxNote,
52
+ deps: [],
53
+ timeout: 60_000,
54
+ maxRetries: 1,
55
+ priority: 10,
56
+ },
57
+ {
58
+ id: "content",
59
+ agentId: agentIds.content,
60
+ name: "ContentAgent",
61
+ taskDescription:
62
+ `Generate educational content for the node type "${input.nodeType}".` +
63
+ ` Use the curriculum from the dependency context.` +
64
+ ` Output: { explanation: string, examples: string[], exercises: { question: string, answer: string }[] }.`,
65
+ deps: ["curriculum"],
66
+ timeout: 90_000,
67
+ maxRetries: 2,
68
+ priority: 5,
69
+ },
70
+ {
71
+ id: "visual",
72
+ agentId: agentIds.visual,
73
+ name: "VisualAgent",
74
+ taskDescription:
75
+ `Generate visual asset descriptions for the node type "${input.nodeType}".` +
76
+ ` You only need the curriculum context (NOT the full text content).` +
77
+ ` Output: { diagram: string (mermaid or ASCII), iconSuggestion: string, colorTheme: string }.`,
78
+ deps: ["curriculum"],
79
+ timeout: 120_000,
80
+ maxRetries: 2,
81
+ priority: 5,
82
+ },
83
+ {
84
+ id: "gamification",
85
+ agentId: agentIds.gamification,
86
+ name: "GamificationAgent",
87
+ taskDescription:
88
+ `Add a gamification layer to the educational node.` +
89
+ ` You have access to the generated content AND visual assets in the dependency context.` +
90
+ ` Output: { xpReward: number, badge: string, challengeMode: { description: string, successCriteria: string } }.`,
91
+ deps: ["content", "visual"],
92
+ timeout: 45_000,
93
+ maxRetries: 1,
94
+ priority: 0,
95
+ },
96
+ ]
97
+
98
+ return new TaskGraph(nodes)
99
+ }
@@ -0,0 +1,97 @@
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 HiveLearn"
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
+ }
@@ -0,0 +1,4 @@
1
+ export type { HiveLearnAgentIds, HiveLearnInput } from "./HiveLearnPreset.ts";
2
+ export { createHiveLearnGraph } from "./HiveLearnPreset.ts";
3
+ export type { ResearchAgentIds } from "./ResearchPreset.ts";
4
+ export { createResearchGraph } from "./ResearchPreset.ts";
@@ -0,0 +1,21 @@
1
+ /**
2
+ * ParallelStrategy — default for HiveLearn
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
+ }
@@ -0,0 +1,46 @@
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
+ }
@@ -0,0 +1,3 @@
1
+ export type { ExecutionStrategy } from "./ParallelStrategy.ts";
2
+ export { ParallelStrategy } from "./ParallelStrategy.ts";
3
+ export { PriorityStrategy } from "./PriorityStrategy.ts";
@@ -0,0 +1,164 @@
1
+ /**
2
+ * Hive Scheduler - Type Definitions
3
+ *
4
+ * Type interfaces for the Croner-based scheduling system.
5
+ * All names use "CronJob" terminology (formerly ScheduledTask).
6
+ */
7
+
8
+ import type { Database } from "bun:sqlite";
9
+ import type { Cron } from "croner";
10
+
11
+ /**
12
+ * Task type: recurring uses cron expression, one_shot uses fire_at
13
+ */
14
+ export type TaskType = "recurring" | "one_shot";
15
+
16
+ /**
17
+ * Task status
18
+ */
19
+ export type TaskStatus = "active" | "paused" | "completed" | "failed" | "cancelled";
20
+
21
+ /**
22
+ * Task run status
23
+ */
24
+ export type TaskRunStatus = "running" | "success" | "failed" | "timeout";
25
+
26
+ /**
27
+ * CronJob as stored in SQLite (cron_jobs table)
28
+ */
29
+ export interface CronJob {
30
+ id: string;
31
+ name: string;
32
+ task: string;
33
+ task_type: TaskType;
34
+ cron_expression: string | null;
35
+ fire_at: string | null;
36
+ timezone: string;
37
+ start_at: string | null;
38
+ stop_at: string | null;
39
+ dom_and_dow: number;
40
+ max_runs: number | null;
41
+ protect: number;
42
+ interval_sec: number | null;
43
+ agent_id: string | null;
44
+ channel: string;
45
+ payload: string;
46
+ tool_name: string | null;
47
+ status: TaskStatus;
48
+ run_count: number;
49
+ error_count: number;
50
+ last_error: string | null;
51
+ created_at: string;
52
+ updated_at: string;
53
+ last_run_at: string | null;
54
+ next_run_at: string | null;
55
+ completed_at: string | null;
56
+ }
57
+
58
+ /**
59
+ * Task run history record
60
+ */
61
+ export interface TaskRun {
62
+ id: string;
63
+ task_id: string;
64
+ status: TaskRunStatus;
65
+ started_at: string;
66
+ finished_at: string | null;
67
+ duration_ms: number | null;
68
+ error_message: string | null;
69
+ payload_snapshot: string | null;
70
+ agent_response: string | null;
71
+ }
72
+
73
+ /**
74
+ * Input for creating a new cron job
75
+ */
76
+ export interface CreateCronJobInput {
77
+ name: string;
78
+ task: string;
79
+ task_type: TaskType;
80
+ cron_expression?: string;
81
+ fire_at?: string;
82
+ timezone: string;
83
+ start_at?: string;
84
+ stop_at?: string;
85
+ dom_and_dow?: boolean;
86
+ agent_id?: string | null;
87
+ channel?: string;
88
+ payload?: Record<string, unknown>;
89
+ tool_name?: string | null;
90
+ max_runs?: number | null;
91
+ protect?: boolean;
92
+ interval_sec?: number | null;
93
+ }
94
+
95
+ /**
96
+ * Input for updating an existing cron job
97
+ */
98
+ export interface UpdateCronJobInput {
99
+ name?: string;
100
+ task?: string;
101
+ task_type?: TaskType;
102
+ cron_expression?: string | null;
103
+ fire_at?: string | null;
104
+ timezone?: string;
105
+ start_at?: string | null;
106
+ stop_at?: string | null;
107
+ dom_and_dow?: boolean;
108
+ agent_id?: string | null;
109
+ channel?: string;
110
+ payload?: Record<string, unknown>;
111
+ tool_name?: string | null;
112
+ max_runs?: number | null;
113
+ protect?: boolean;
114
+ interval_sec?: number | null;
115
+ status?: TaskStatus;
116
+ }
117
+
118
+ /**
119
+ * Scheduler status for a cron job
120
+ */
121
+ export interface CronJobStatus {
122
+ id: string;
123
+ name: string;
124
+ nextRun: Date | null;
125
+ isBusy: boolean;
126
+ status: TaskStatus;
127
+ }
128
+
129
+ /**
130
+ * Handler function type for executing cron jobs
131
+ */
132
+ export type CronJobExecutionHandler = (job: CronJob) => Promise<CronJobExecutionResult>;
133
+
134
+ /**
135
+ * Result of cron job execution
136
+ */
137
+ export interface CronJobExecutionResult {
138
+ success: boolean;
139
+ response?: string;
140
+ error?: string;
141
+ }
142
+
143
+ /**
144
+ * Internal job wrapper holding Croner instance and metadata
145
+ */
146
+ export interface CronJobEntry {
147
+ job: CronJob;
148
+ cron: Cron;
149
+ }
150
+
151
+ /**
152
+ * Options for Croner job creation
153
+ */
154
+ export interface CronerOptions {
155
+ timezone: string;
156
+ protect: boolean;
157
+ catch: boolean | ((error: Error) => void);
158
+ name: string;
159
+ maxRuns?: number;
160
+ interval?: number;
161
+ startAt?: string;
162
+ stopAt?: string;
163
+ domAndDow?: boolean;
164
+ }
@@ -0,0 +1,58 @@
1
+ import type { ToolDefinition } from "./ToolRegistry";
2
+ import type { ToolRegistry } from "./ToolRegistry";
3
+
4
+ export interface ToolExecutionResult {
5
+ toolName: string;
6
+ args: any;
7
+ result: any;
8
+ durationMs: number;
9
+ error?: string;
10
+ }
11
+
12
+ export class ToolExecutor {
13
+ constructor(private registry: ToolRegistry) {}
14
+
15
+ async execute(
16
+ name: string,
17
+ args: any,
18
+ config?: any
19
+ ): Promise<ToolExecutionResult> {
20
+ const tool = this.registry.get(name);
21
+ if (!tool) {
22
+ return {
23
+ toolName: name,
24
+ args,
25
+ result: null,
26
+ durationMs: 0,
27
+ error: `Tool '${name}' not found`,
28
+ };
29
+ }
30
+
31
+ const start = Date.now();
32
+ try {
33
+ const validatedArgs = tool.schema ? tool.schema.parse(args) : args;
34
+ const result = await tool.execute(validatedArgs, config);
35
+ return {
36
+ toolName: name,
37
+ args: validatedArgs,
38
+ result,
39
+ durationMs: Date.now() - start,
40
+ };
41
+ } catch (error: any) {
42
+ return {
43
+ toolName: name,
44
+ args,
45
+ result: null,
46
+ durationMs: Date.now() - start,
47
+ error: error.message || String(error),
48
+ };
49
+ }
50
+ }
51
+
52
+ async executeBatch(
53
+ calls: Array<{ name: string; args: any }>,
54
+ config?: any
55
+ ): Promise<ToolExecutionResult[]> {
56
+ return Promise.all(calls.map(c => this.execute(c.name, c.args, config)));
57
+ }
58
+ }
@@ -0,0 +1,98 @@
1
+ import { describe, it, expect } from "bun:test";
2
+ import { ToolRegistry, defineTool } from "./ToolRegistry.ts";
3
+ import { ToolExecutor } from "./ToolExecutor.ts";
4
+
5
+ describe("defineTool", () => {
6
+ it("creates a tool definition", () => {
7
+ const tool = defineTool({
8
+ name: "hello",
9
+ description: "Say hello",
10
+ execute: async (args: { name?: string }) => ({ greeting: `Hello, ${args.name ?? "world"}!` }),
11
+ });
12
+ expect(tool.name).toBe("hello");
13
+ expect(tool.description).toBe("Say hello");
14
+ });
15
+ });
16
+
17
+ describe("ToolRegistry", () => {
18
+ it("register, get, has", () => {
19
+ const reg = new ToolRegistry();
20
+ const tool = defineTool({
21
+ name: "test",
22
+ description: "a test tool",
23
+ execute: async () => ({ ok: true }),
24
+ });
25
+ reg.register(tool);
26
+ expect(reg.has("test")).toBe(true);
27
+ expect(reg.get("test")).toBe(tool);
28
+ expect(reg.get("nope")).toBeUndefined();
29
+ });
30
+
31
+ it("throws on duplicate registration", () => {
32
+ const reg = new ToolRegistry();
33
+ reg.register(defineTool({ name: "dup", description: "", execute: async () => ({}) }));
34
+ expect(() =>
35
+ reg.register(defineTool({ name: "dup", description: "", execute: async () => ({}) }))
36
+ ).toThrow("already registered");
37
+ });
38
+
39
+ it("lists and categorizes", () => {
40
+ const reg = new ToolRegistry();
41
+ reg.register(defineTool({ name: "a", description: "", category: "web", execute: async () => ({}) }));
42
+ reg.register(defineTool({ name: "b", description: "", category: "fs", execute: async () => ({}) }));
43
+ reg.register(defineTool({ name: "c", description: "", category: "web", execute: async () => ({}) }));
44
+ expect(reg.size()).toBe(3);
45
+ expect(reg.list()).toHaveLength(3);
46
+ expect(reg.getByCategory("web")).toHaveLength(2);
47
+ expect(reg.getNames()).toEqual(["a", "b", "c"]);
48
+ });
49
+
50
+ it("merge and clear", () => {
51
+ const a = new ToolRegistry();
52
+ const b = new ToolRegistry();
53
+ a.register(defineTool({ name: "x", description: "", execute: async () => ({}) }));
54
+ b.register(defineTool({ name: "y", description: "", execute: async () => ({}) }));
55
+ a.merge(b);
56
+ expect(a.size()).toBe(2);
57
+ a.clear();
58
+ expect(a.size()).toBe(0);
59
+ });
60
+ });
61
+
62
+ describe("ToolExecutor", () => {
63
+ it("executes a registered tool", async () => {
64
+ const reg = new ToolRegistry();
65
+ reg.register(
66
+ defineTool({
67
+ name: "echo",
68
+ description: "echo args",
69
+ execute: async (args) => args,
70
+ })
71
+ );
72
+ const exec = new ToolExecutor(reg);
73
+ const result = await exec.execute("echo", { msg: "hi" });
74
+ expect(result.toolName).toBe("echo");
75
+ expect(result.result).toEqual({ msg: "hi" });
76
+ expect(result.error).toBeUndefined();
77
+ expect(result.durationMs).toBeGreaterThanOrEqual(0);
78
+ });
79
+
80
+ it("returns error for unknown tool", async () => {
81
+ const exec = new ToolExecutor(new ToolRegistry());
82
+ const result = await exec.execute("ghost", {});
83
+ expect(result.error).toBeString();
84
+ expect(result.error).toContain("not found");
85
+ });
86
+
87
+ it("executes batch", async () => {
88
+ const reg = new ToolRegistry();
89
+ reg.register(defineTool({ name: "t1", description: "", execute: async () => 1 }));
90
+ reg.register(defineTool({ name: "t2", description: "", execute: async () => 2 }));
91
+ const exec = new ToolExecutor(reg);
92
+ const results = await exec.executeBatch([{ name: "t1", args: {} }, { name: "t2", args: {} }, { name: "nope", args: {} }]);
93
+ expect(results).toHaveLength(3);
94
+ expect(results[0].result).toBe(1);
95
+ expect(results[1].result).toBe(2);
96
+ expect(results[2].error).toBeString();
97
+ });
98
+ });
@@ -0,0 +1,61 @@
1
+ import { z } from "zod";
2
+
3
+ export interface ToolDefinition {
4
+ name: string;
5
+ description: string;
6
+ schema?: z.ZodType;
7
+ execute: (args: any, config?: any) => Promise<any>;
8
+ category?: string;
9
+ abstractionLevel?: "atomic" | "orchestration";
10
+ }
11
+
12
+ export class ToolRegistry {
13
+ private tools: Map<string, ToolDefinition> = new Map();
14
+
15
+ register(tool: ToolDefinition): void {
16
+ if (this.tools.has(tool.name)) {
17
+ throw new Error(`Tool '${tool.name}' already registered`);
18
+ }
19
+ this.tools.set(tool.name, tool);
20
+ }
21
+
22
+ get(name: string): ToolDefinition | undefined {
23
+ return this.tools.get(name);
24
+ }
25
+
26
+ has(name: string): boolean {
27
+ return this.tools.has(name);
28
+ }
29
+
30
+ list(): ToolDefinition[] {
31
+ return Array.from(this.tools.values());
32
+ }
33
+
34
+ getByCategory(category: string): ToolDefinition[] {
35
+ return this.list().filter(t => t.category === category);
36
+ }
37
+
38
+ getNames(): string[] {
39
+ return Array.from(this.tools.keys());
40
+ }
41
+
42
+ size(): number {
43
+ return this.tools.size;
44
+ }
45
+
46
+ merge(other: ToolRegistry): void {
47
+ for (const tool of other.list()) {
48
+ if (!this.tools.has(tool.name)) {
49
+ this.tools.set(tool.name, tool);
50
+ }
51
+ }
52
+ }
53
+
54
+ clear(): void {
55
+ this.tools.clear();
56
+ }
57
+ }
58
+
59
+ export function defineTool(config: ToolDefinition): ToolDefinition {
60
+ return config;
61
+ }