@johpaz/hive-sdk 0.0.14 → 0.0.16

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 (257) hide show
  1. package/CHANGELOG.md +64 -0
  2. package/README.md +280 -0
  3. package/docs/API-AGENTS.md +316 -0
  4. package/docs/API-CONTEXT-COMPILER.md +252 -0
  5. package/docs/API-DAG-SCHEDULER.md +273 -0
  6. package/docs/API-TOOLS-SKILLS-CHANNELS.md +350 -0
  7. package/docs/API-WORKERS-EVENTS.md +299 -0
  8. package/docs/INDEX.md +190 -0
  9. package/docs/README.md +161 -0
  10. package/docs/TEMPLATE-HIVE-APP.md +360 -0
  11. package/package.json +60 -104
  12. package/packages/cli/bin/hive +2 -0
  13. package/packages/cli/package.json +17 -0
  14. package/packages/cli/src/commands/add-skill.ts +42 -0
  15. package/packages/cli/src/commands/add-tool.ts +45 -0
  16. package/packages/cli/src/commands/add-worker.ts +49 -0
  17. package/packages/cli/src/commands/create-app-utils.ts +32 -0
  18. package/packages/cli/src/commands/create-app.test.ts +151 -0
  19. package/packages/cli/src/commands/create-app.ts +35 -0
  20. package/packages/cli/src/commands/init.ts +56 -0
  21. package/packages/cli/src/commands/run.ts +45 -0
  22. package/packages/cli/src/commands/test.ts +42 -0
  23. package/packages/cli/src/commands/trace.ts +55 -0
  24. package/packages/cli/src/index.ts +59 -0
  25. package/packages/cli/templates/hive-app/.env.example +17 -0
  26. package/packages/cli/templates/hive-app/docker-compose.yml +20 -0
  27. package/packages/cli/templates/hive-app/hive.config.ts +19 -0
  28. package/packages/cli/templates/hive-app/package.json +16 -0
  29. package/packages/cli/templates/hive-app/src/agents/coordinator.ts +9 -0
  30. package/packages/cli/templates/hive-app/src/main.ts +56 -0
  31. package/packages/core/package.json +58 -0
  32. package/packages/core/src/ace/Curator.ts +158 -0
  33. package/packages/core/src/ace/Reflector.ts +200 -0
  34. package/packages/core/src/ace/Tracer.ts +100 -0
  35. package/packages/core/src/ace/index.ts +4 -0
  36. package/packages/core/src/agent/AgentRunner.ts +699 -0
  37. package/packages/core/src/agent/Compaction.ts +221 -0
  38. package/packages/core/src/agent/ContextCompiler.ts +567 -0
  39. package/packages/core/src/agent/ContextGuard.ts +91 -0
  40. package/packages/core/src/agent/ConversationStore.ts +244 -0
  41. package/packages/core/src/agent/Hooks.ts +166 -0
  42. package/packages/core/src/agent/NativeTools.ts +31 -0
  43. package/packages/core/src/agent/PromptBuilder.ts +169 -0
  44. package/packages/core/src/agent/Service.ts +267 -0
  45. package/packages/core/src/agent/StuckLoop.ts +133 -0
  46. package/packages/core/src/agent/index.ts +12 -0
  47. package/packages/core/src/agent/providers/LLMClient.ts +149 -0
  48. package/packages/core/src/agent/providers/anthropic.ts +212 -0
  49. package/packages/core/src/agent/providers/gemini.ts +215 -0
  50. package/packages/core/src/agent/providers/index.ts +199 -0
  51. package/packages/core/src/agent/providers/interface.ts +195 -0
  52. package/packages/core/src/agent/providers/ollama.ts +175 -0
  53. package/packages/core/src/agent/providers/openai-compat.ts +231 -0
  54. package/packages/core/src/agent/selectors/PlaybookSelector.ts +147 -0
  55. package/packages/core/src/agent/selectors/SkillSelector.ts +478 -0
  56. package/packages/core/src/agent/selectors/ToolSelector.ts +577 -0
  57. package/packages/core/src/agent/selectors/index.ts +6 -0
  58. package/packages/core/src/api/createAgent.test.ts +48 -0
  59. package/packages/core/src/api/createAgent.ts +122 -0
  60. package/packages/core/src/api/index.ts +2 -0
  61. package/packages/core/src/auth/auth.ts +108 -0
  62. package/packages/core/src/auth/index.ts +1 -0
  63. package/packages/core/src/canvas/CanvasManager.ts +390 -0
  64. package/packages/core/src/canvas/a2ui-tools.ts +255 -0
  65. package/packages/core/src/canvas/canvas-tools.ts +448 -0
  66. package/packages/core/src/canvas/canvas.test.ts +32 -0
  67. package/packages/core/src/canvas/emitter.ts +149 -0
  68. package/packages/core/src/canvas/index.ts +3 -0
  69. package/packages/core/src/channels/base.ts +154 -0
  70. package/packages/core/src/channels/channels.test.ts +18 -0
  71. package/packages/core/src/channels/discord.ts +273 -0
  72. package/packages/core/src/channels/index.ts +7 -0
  73. package/packages/core/src/channels/manager.ts +450 -0
  74. package/packages/core/src/channels/slack.ts +323 -0
  75. package/packages/core/src/channels/telegram.ts +612 -0
  76. package/packages/core/src/channels/webchat.ts +139 -0
  77. package/packages/core/src/channels/whatsapp.ts +548 -0
  78. package/packages/core/src/config/index.ts +2 -0
  79. package/packages/core/src/config/loader.ts +554 -0
  80. package/packages/core/src/ethics/EthicsGuard.test.ts +54 -0
  81. package/packages/core/src/ethics/EthicsGuard.ts +66 -0
  82. package/packages/core/src/ethics/index.ts +2 -0
  83. package/packages/core/src/events/agent-bus.ts +460 -0
  84. package/packages/core/src/events/event-bus.ts +169 -0
  85. package/packages/core/src/gateway/channel-notify.ts +37 -0
  86. package/packages/core/src/gateway/gateway.test.ts +38 -0
  87. package/packages/core/src/gateway/index.ts +2 -0
  88. package/packages/core/src/gateway/server.ts +139 -0
  89. package/packages/core/src/heartbeat/index.ts +157 -0
  90. package/packages/core/src/index.ts +81 -0
  91. package/packages/core/src/mcp/MCPClient.ts +439 -0
  92. package/packages/core/src/mcp/MCPToolAdapter.ts +176 -0
  93. package/packages/core/src/mcp/config.ts +13 -0
  94. package/packages/core/src/mcp/hot-reload.ts +147 -0
  95. package/packages/core/src/mcp/index.ts +11 -0
  96. package/packages/core/src/mcp/logger.ts +42 -0
  97. package/packages/core/src/mcp/singleton.ts +21 -0
  98. package/packages/core/src/mcp/transports/index.ts +67 -0
  99. package/packages/core/src/mcp/transports/sse.ts +241 -0
  100. package/packages/core/src/mcp/transports/websocket.ts +159 -0
  101. package/packages/core/src/memory/Scratchpad.test.ts +47 -0
  102. package/packages/core/src/memory/Scratchpad.ts +37 -0
  103. package/packages/core/src/memory/Storage.ts +6 -0
  104. package/packages/core/src/memory/index.ts +2 -0
  105. package/packages/core/src/multimodal/VisionService.ts +293 -0
  106. package/packages/core/src/multimodal/index.ts +2 -0
  107. package/packages/core/src/multimodal/types.ts +28 -0
  108. package/packages/core/src/multimodal/vision-service.ts +283 -0
  109. package/packages/core/src/plugins/api.ts +128 -0
  110. package/packages/core/src/plugins/index.ts +2 -0
  111. package/packages/core/src/plugins/loader.ts +365 -0
  112. package/packages/core/src/resilience/circuit-breaker.ts +225 -0
  113. package/packages/core/src/scheduler/CronScheduler.ts +699 -0
  114. package/packages/core/src/scheduler/dag/AgentExecutor.ts +53 -0
  115. package/packages/core/src/scheduler/dag/DAGScheduler.ts +250 -0
  116. package/packages/core/src/scheduler/dag/EventBridge.ts +122 -0
  117. package/packages/core/src/scheduler/dag/TaskGraph.ts +192 -0
  118. package/packages/core/src/scheduler/dag/TaskNode.ts +97 -0
  119. package/packages/core/src/scheduler/dag/TaskResult.ts +22 -0
  120. package/packages/core/src/scheduler/dag/errors.ts +37 -0
  121. package/packages/core/src/scheduler/dag/index.ts +26 -0
  122. package/packages/core/src/scheduler/dag/presets/ResearchPreset.ts +97 -0
  123. package/packages/core/src/scheduler/dag/strategies/ParallelStrategy.ts +21 -0
  124. package/packages/core/src/scheduler/dag/strategies/PriorityStrategy.ts +46 -0
  125. package/packages/core/src/scheduler/index.ts +22 -0
  126. package/packages/core/src/scheduler/integration.ts +237 -0
  127. package/packages/core/src/scheduler/scheduler.test.ts +19 -0
  128. package/packages/core/src/scheduler/types.ts +164 -0
  129. package/packages/core/src/security/Pairing.ts +250 -0
  130. package/packages/core/src/security/RateLimit.ts +270 -0
  131. package/packages/core/src/security/google-chat.ts +269 -0
  132. package/packages/core/src/security/index.ts +192 -0
  133. package/packages/core/src/security/rate-limit.ts +270 -0
  134. package/packages/core/src/security/signal.ts +321 -0
  135. package/packages/core/src/skills/SkillLoader.ts +388 -0
  136. package/packages/core/src/skills/bundled-data.generated.ts +3332 -0
  137. package/packages/core/src/skills/defineSkill.ts +18 -0
  138. package/packages/core/src/skills/index.ts +4 -0
  139. package/packages/core/src/state/index.ts +2 -0
  140. package/packages/core/src/state/store.ts +312 -0
  141. package/packages/core/src/storage/SQLiteStorage.ts +407 -0
  142. package/packages/core/src/storage/crypto.ts +233 -0
  143. package/packages/core/src/storage/index.ts +10 -0
  144. package/packages/core/src/storage/onboarding.ts +1603 -0
  145. package/packages/core/src/storage/schema.ts +689 -0
  146. package/packages/core/src/storage/seed.ts +740 -0
  147. package/packages/core/src/storage/storage.test.ts +37 -0
  148. package/packages/core/src/storage/usage.ts +374 -0
  149. package/packages/core/src/swarm/AgentBus.ts +460 -0
  150. package/packages/core/src/swarm/AgentExecutor.ts +53 -0
  151. package/packages/core/src/swarm/Coordinator.ts +251 -0
  152. package/packages/core/src/swarm/EventBridge.ts +122 -0
  153. package/packages/core/src/swarm/EventBus.ts +169 -0
  154. package/packages/core/src/swarm/TaskGraph.ts +192 -0
  155. package/packages/core/src/swarm/TaskNode.ts +97 -0
  156. package/packages/core/src/swarm/TaskResult.ts +22 -0
  157. package/packages/core/src/swarm/WorkerPool.ts +236 -0
  158. package/packages/core/src/swarm/errors.ts +37 -0
  159. package/packages/core/src/swarm/index.ts +30 -0
  160. package/packages/core/src/swarm/presets/HiveLearnPreset.ts +99 -0
  161. package/packages/core/src/swarm/presets/ResearchPreset.ts +97 -0
  162. package/packages/core/src/swarm/presets/index.ts +4 -0
  163. package/packages/core/src/swarm/strategies/ParallelStrategy.ts +21 -0
  164. package/packages/core/src/swarm/strategies/PriorityStrategy.ts +46 -0
  165. package/packages/core/src/swarm/strategies/index.ts +3 -0
  166. package/packages/core/src/swarm/swarm.test.ts +24 -0
  167. package/packages/core/src/swarm/types.ts +164 -0
  168. package/packages/core/src/tool-runtime/index.ts +522 -0
  169. package/packages/core/src/tool-runtime/tool-runtime.test.ts +91 -0
  170. package/packages/core/src/tool-runtime/tool-worker.ts +125 -0
  171. package/packages/core/src/tools/ToolExecutor.ts +58 -0
  172. package/packages/core/src/tools/ToolRegistry.test.ts +98 -0
  173. package/packages/core/src/tools/ToolRegistry.ts +61 -0
  174. package/packages/core/src/tools/agents/get-available-models.ts +118 -0
  175. package/packages/core/src/tools/agents/index.ts +715 -0
  176. package/packages/core/src/tools/bridge-events.ts +26 -0
  177. package/packages/core/src/tools/canvas/index.ts +375 -0
  178. package/packages/core/src/tools/cli/index.ts +142 -0
  179. package/packages/core/src/tools/codebridge/index.ts +342 -0
  180. package/packages/core/src/tools/core/index.ts +476 -0
  181. package/packages/core/src/tools/cron/index.ts +626 -0
  182. package/packages/core/src/tools/filesystem/fs-delete.ts +78 -0
  183. package/packages/core/src/tools/filesystem/fs-edit.ts +106 -0
  184. package/packages/core/src/tools/filesystem/fs-exists.ts +63 -0
  185. package/packages/core/src/tools/filesystem/fs-glob.ts +108 -0
  186. package/packages/core/src/tools/filesystem/fs-list.ts +129 -0
  187. package/packages/core/src/tools/filesystem/fs-read.ts +72 -0
  188. package/packages/core/src/tools/filesystem/fs-write.ts +67 -0
  189. package/packages/core/src/tools/filesystem/index.ts +34 -0
  190. package/packages/core/src/tools/filesystem/workspace-guard.ts +62 -0
  191. package/packages/core/src/tools/index.ts +231 -0
  192. package/packages/core/src/tools/meeting/index.ts +363 -0
  193. package/packages/core/src/tools/office/index.ts +47 -0
  194. package/packages/core/src/tools/office/office-escribir-docx.ts +192 -0
  195. package/packages/core/src/tools/office/office-escribir-pdf.ts +172 -0
  196. package/packages/core/src/tools/office/office-escribir-pptx.ts +174 -0
  197. package/packages/core/src/tools/office/office-escribir-xlsx.ts +116 -0
  198. package/packages/core/src/tools/office/office-leer-docx.ts +93 -0
  199. package/packages/core/src/tools/office/office-leer-pdf.ts +114 -0
  200. package/packages/core/src/tools/office/office-leer-pptx.ts +136 -0
  201. package/packages/core/src/tools/office/office-leer-xlsx.ts +124 -0
  202. package/packages/core/src/tools/projects/index.ts +37 -0
  203. package/packages/core/src/tools/projects/project-create.ts +94 -0
  204. package/packages/core/src/tools/projects/project-done.ts +66 -0
  205. package/packages/core/src/tools/projects/project-fail.ts +66 -0
  206. package/packages/core/src/tools/projects/project-list.ts +96 -0
  207. package/packages/core/src/tools/projects/project-update.ts +72 -0
  208. package/packages/core/src/tools/projects/task-create.ts +68 -0
  209. package/packages/core/src/tools/projects/task-evaluate.ts +93 -0
  210. package/packages/core/src/tools/projects/task-update.ts +93 -0
  211. package/packages/core/src/tools/types.ts +39 -0
  212. package/packages/core/src/tools/voice/index.ts +104 -0
  213. package/packages/core/src/tools/web/browser-click.ts +78 -0
  214. package/packages/core/src/tools/web/browser-extract.ts +139 -0
  215. package/packages/core/src/tools/web/browser-navigate.ts +106 -0
  216. package/packages/core/src/tools/web/browser-screenshot.ts +87 -0
  217. package/packages/core/src/tools/web/browser-script.ts +88 -0
  218. package/packages/core/src/tools/web/browser-service.ts +554 -0
  219. package/packages/core/src/tools/web/browser-type.ts +101 -0
  220. package/packages/core/src/tools/web/browser-wait.ts +136 -0
  221. package/packages/core/src/tools/web/index.ts +41 -0
  222. package/packages/core/src/tools/web/web-fetch.ts +78 -0
  223. package/packages/core/src/tools/web/web-search.ts +123 -0
  224. package/packages/core/src/utils/benchmark.ts +80 -0
  225. package/packages/core/src/utils/crypto.ts +73 -0
  226. package/packages/core/src/utils/date.ts +42 -0
  227. package/packages/core/src/utils/index.ts +10 -0
  228. package/packages/core/src/utils/logger.ts +389 -0
  229. package/packages/core/src/utils/retry.ts +70 -0
  230. package/packages/core/src/utils/toon.ts +253 -0
  231. package/packages/core/src/voice/index.ts +643 -0
  232. package/packages/core/src/workers/WorkerPool.ts +167 -0
  233. package/packages/core/src/workers/agent.worker.ts +68 -0
  234. package/packages/core/src/workers/createWorker.ts +144 -0
  235. package/packages/core/src/workers/index.ts +5 -0
  236. package/packages/core/src/workers/workers.test.ts +48 -0
  237. package/test/setup-db.ts +216 -0
  238. package/tsconfig.json +40 -0
  239. package/src/agents.ts +0 -1
  240. package/src/canvas.ts +0 -1
  241. package/src/channels.ts +0 -1
  242. package/src/config.ts +0 -1
  243. package/src/events.ts +0 -1
  244. package/src/gateway.ts +0 -1
  245. package/src/index.ts +0 -304
  246. package/src/mcp.ts +0 -1
  247. package/src/multimodal.ts +0 -1
  248. package/src/scheduler.ts +0 -1
  249. package/src/security.ts +0 -1
  250. package/src/skills.ts +0 -1
  251. package/src/state.ts +0 -1
  252. package/src/storage.ts +0 -1
  253. package/src/tools.ts +0 -1
  254. package/src/tts.ts +0 -1
  255. package/src/types.ts +0 -82
  256. package/src/utils.ts +0 -1
  257. package/src/voice.ts +0 -1
@@ -0,0 +1,125 @@
1
+ import { createAllTools } from "../tools/index.ts"
2
+ import type { Config } from "../config/loader.ts"
3
+
4
+ type WorkerRunMessage = {
5
+ type: "run"
6
+ jobId: string
7
+ toolName: string
8
+ args: unknown
9
+ toolConfig: Record<string, unknown>
10
+ hiveConfig: Config
11
+ mainThreadToolNames: string[]
12
+ }
13
+
14
+ type WorkerRpcResponse = {
15
+ type: "rpc_result"
16
+ rpcId: string
17
+ ok: boolean
18
+ result?: unknown
19
+ error?: SerializedError
20
+ }
21
+
22
+ type SerializedError = {
23
+ name: string
24
+ message: string
25
+ stack?: string
26
+ }
27
+
28
+ const pendingRpc = new Map<string, {
29
+ resolve: (value: unknown) => void
30
+ reject: (error: Error) => void
31
+ }>()
32
+
33
+ function serializeError(error: unknown): SerializedError {
34
+ const err = error instanceof Error ? error : new Error(String(error))
35
+ return {
36
+ name: err.name,
37
+ message: err.message,
38
+ stack: err.stack,
39
+ }
40
+ }
41
+
42
+ function parseArgs(args: unknown): Record<string, unknown> {
43
+ if (typeof args === "string") {
44
+ return JSON.parse(args) as Record<string, unknown>
45
+ }
46
+ if (args && typeof args === "object") {
47
+ return args as Record<string, unknown>
48
+ }
49
+ return {}
50
+ }
51
+
52
+ function requestMainThreadTool(
53
+ jobId: string,
54
+ toolName: string,
55
+ args: unknown,
56
+ toolConfig: Record<string, unknown>
57
+ ): Promise<unknown> {
58
+ const rpcId = `${jobId}:${crypto.randomUUID()}`
59
+ return new Promise((resolve, reject) => {
60
+ pendingRpc.set(rpcId, { resolve, reject })
61
+ postMessage({
62
+ type: "rpc_call",
63
+ rpcId,
64
+ jobId,
65
+ toolName,
66
+ args,
67
+ toolConfig,
68
+ })
69
+ })
70
+ }
71
+
72
+ async function runTool(message: WorkerRunMessage): Promise<void> {
73
+ const startedAt = performance.now()
74
+
75
+ try {
76
+ const parsedArgs = parseArgs(message.args)
77
+ const forceMainThread = message.mainThreadToolNames.includes(message.toolName)
78
+ const allTools = forceMainThread ? [] : createAllTools(message.hiveConfig)
79
+ const tool = allTools.find((candidate) => candidate.name === message.toolName)
80
+
81
+ const result = tool?.execute
82
+ ? await tool.execute(parsedArgs, { configurable: message.toolConfig })
83
+ : await requestMainThreadTool(message.jobId, message.toolName, parsedArgs, message.toolConfig)
84
+
85
+ postMessage({
86
+ type: "result",
87
+ jobId: message.jobId,
88
+ ok: true,
89
+ result,
90
+ durationMs: Math.round(performance.now() - startedAt),
91
+ })
92
+ } catch (error) {
93
+ postMessage({
94
+ type: "result",
95
+ jobId: message.jobId,
96
+ ok: false,
97
+ error: serializeError(error),
98
+ durationMs: Math.round(performance.now() - startedAt),
99
+ })
100
+ }
101
+ }
102
+
103
+ onmessage = (event: MessageEvent<WorkerRunMessage | WorkerRpcResponse>) => {
104
+ const message = event.data
105
+
106
+ if (message.type === "rpc_result") {
107
+ const pending = pendingRpc.get(message.rpcId)
108
+ if (!pending) return
109
+
110
+ pendingRpc.delete(message.rpcId)
111
+ if (message.ok) {
112
+ pending.resolve(message.result)
113
+ } else {
114
+ const error = new Error(message.error?.message || "Tool RPC failed")
115
+ error.name = message.error?.name || "ToolRpcError"
116
+ error.stack = message.error?.stack
117
+ pending.reject(error)
118
+ }
119
+ return
120
+ }
121
+
122
+ if (message.type === "run") {
123
+ void runTool(message)
124
+ }
125
+ }
@@ -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
+ }
@@ -0,0 +1,118 @@
1
+ /**
2
+ * Get Available Models Tool
3
+ *
4
+ * Permite a los agentes consultar providers y modelos activos en la BD
5
+ * para seleccionar el modelo óptimo al crear nuevos agentes.
6
+ *
7
+ * @category agents
8
+ */
9
+
10
+ import type { Tool } from "../types.ts";
11
+ import { getDb } from "../../storage/SQLiteStorage.ts";
12
+
13
+ export const getAvailableModelsTool: Tool = {
14
+ name: "get_available_models",
15
+ description: "Obtener lista de providers y modelos activos de la base de datos. Sinónimos: ver modelos, listar providers, modelos disponibles, consultar modelos, provider activo, qué modelos tengo, modelos para código, modelos para chat",
16
+ parameters: {
17
+ type: "object",
18
+ properties: {
19
+ providerId: {
20
+ type: "string",
21
+ description: "Opcional: filtrar por provider (openai, ollama, anthropic, gemini, etc.)"
22
+ },
23
+ modelType: {
24
+ type: "string",
25
+ description: "Opcional: filtrar por tipo (llm, stt, tts, vision, embedding)"
26
+ },
27
+ capabilities: {
28
+ type: "string",
29
+ description: "Opcional: filtrar por capacidad (coding, chat, analysis, vision, reasoning)"
30
+ }
31
+ },
32
+ },
33
+ execute: async (params: Record<string, unknown>) => {
34
+ const db = getDb();
35
+ const { providerId, modelType, capabilities } = params as {
36
+ providerId?: string;
37
+ modelType?: string;
38
+ capabilities?: string;
39
+ };
40
+
41
+ try {
42
+ // Construir query con filtros opcionales
43
+ let query = `
44
+ SELECT
45
+ p.id as provider_id,
46
+ p.name as provider_name,
47
+ p.category as provider_category,
48
+ m.id as model_id,
49
+ m.name as model_name,
50
+ m.model_type,
51
+ m.context_window,
52
+ m.capabilities
53
+ FROM models m
54
+ INNER JOIN providers p ON m.provider_id = p.id
55
+ WHERE m.enabled = 1 AND m.active = 1 AND p.enabled = 1 AND p.active = 1
56
+ `;
57
+
58
+ const whereClauses: string[] = [];
59
+ const queryParams: string[] = [];
60
+
61
+ if (providerId) {
62
+ whereClauses.push("p.id = ?");
63
+ queryParams.push(providerId as string);
64
+ }
65
+
66
+ if (modelType) {
67
+ whereClauses.push("m.model_type = ?");
68
+ queryParams.push(modelType as string);
69
+ }
70
+
71
+ if (capabilities) {
72
+ whereClauses.push("m.capabilities LIKE ?");
73
+ queryParams.push(`%${capabilities as string}%`);
74
+ }
75
+
76
+ if (whereClauses.length > 0) {
77
+ query += " AND " + whereClauses.join(" AND ");
78
+ }
79
+
80
+ query += " ORDER BY p.name, m.name";
81
+
82
+ // Ejecutar query
83
+ const rows = db.query<any, string[]>(query).all(...queryParams) as Array<{
84
+ provider_id: string;
85
+ provider_name: string;
86
+ provider_category: string;
87
+ model_id: string;
88
+ model_name: string;
89
+ model_type: string;
90
+ context_window: number | null;
91
+ capabilities: string | null;
92
+ }>;
93
+
94
+ // Transformar a formato amigable
95
+ const result = rows.map(row => ({
96
+ providerId: row.provider_id,
97
+ providerName: row.provider_name,
98
+ providerCategory: row.provider_category,
99
+ modelId: row.model_id,
100
+ modelName: row.model_name,
101
+ modelType: row.model_type,
102
+ contextWindow: row.context_window,
103
+ capabilities: row.capabilities ? JSON.parse(row.capabilities) : null,
104
+ }));
105
+
106
+ return {
107
+ ok: true,
108
+ count: result.length,
109
+ models: result,
110
+ };
111
+ } catch (error) {
112
+ return {
113
+ ok: false,
114
+ error: `Failed to get available models: ${(error as Error).message}`,
115
+ };
116
+ }
117
+ },
118
+ };