@johpaz/hive-sdk 0.1.6 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (238) hide show
  1. package/CHANGELOG.md +441 -0
  2. package/README.md +21 -3
  3. package/package.json +27 -5
  4. package/packages/core/src/agent/acceptance-checks.ts +9 -9
  5. package/packages/core/src/agent/agent-catalog.ts +82 -25
  6. package/packages/core/src/agent/agent-loop.ts +115 -26
  7. package/packages/core/src/agent/capability-search.ts +2 -2
  8. package/packages/core/src/agent/catalog-selector.ts +4 -4
  9. package/packages/core/src/agent/compaction.ts +30 -10
  10. package/packages/core/src/agent/context-compiler.ts +63 -36
  11. package/packages/core/src/agent/conversation-store.ts +167 -9
  12. package/packages/core/src/agent/curator.ts +16 -7
  13. package/packages/core/src/agent/delegation-runtime.ts +5 -5
  14. package/packages/core/src/agent/goal-runner.ts +9 -9
  15. package/packages/core/src/agent/index.ts +1 -0
  16. package/packages/core/src/agent/llm-client.ts +98 -37
  17. package/packages/core/src/agent/llm-providers/anthropic.ts +4 -4
  18. package/packages/core/src/agent/llm-providers/deepseek.ts +1 -1
  19. package/packages/core/src/agent/llm-providers/gemini.ts +4 -4
  20. package/packages/core/src/agent/llm-providers/groq.ts +1 -1
  21. package/packages/core/src/agent/llm-providers/hiveagents.ts +3 -3
  22. package/packages/core/src/agent/llm-providers/interface.ts +2 -2
  23. package/packages/core/src/agent/llm-providers/kimi.ts +1 -1
  24. package/packages/core/src/agent/llm-providers/minimax.ts +1 -1
  25. package/packages/core/src/agent/llm-providers/mistral.ts +1 -1
  26. package/packages/core/src/agent/llm-providers/modelscope.ts +1 -1
  27. package/packages/core/src/agent/llm-providers/nvidia.ts +40 -1
  28. package/packages/core/src/agent/llm-providers/ollama.ts +4 -4
  29. package/packages/core/src/agent/llm-providers/openai-compat-base.ts +47 -7
  30. package/packages/core/src/agent/llm-providers/openai.ts +1 -1
  31. package/packages/core/src/agent/llm-providers/opencode-go.ts +1 -1
  32. package/packages/core/src/agent/llm-providers/openrouter.ts +1 -1
  33. package/packages/core/src/agent/llm-providers/qwen.ts +1 -1
  34. package/packages/core/src/agent/llm-providers/z-ai.ts +1 -1
  35. package/packages/core/src/agent/mcp-result-normalizer.ts +192 -0
  36. package/packages/core/src/agent/playbook-selector.ts +22 -7
  37. package/packages/core/src/agent/prompt-builder.ts +5 -5
  38. package/packages/core/src/agent/proof-packet.ts +5 -5
  39. package/packages/core/src/agent/providers/index.ts +39 -4
  40. package/packages/core/src/agent/realtime-providers/gemini-live.ts +238 -0
  41. package/packages/core/src/agent/realtime-providers/index.ts +29 -0
  42. package/packages/core/src/agent/realtime-providers/interface.ts +108 -0
  43. package/packages/core/src/agent/reflector.ts +38 -15
  44. package/packages/core/src/agent/run-store.ts +8 -8
  45. package/packages/core/src/agent/service.ts +10 -10
  46. package/packages/core/src/agent/skill-selector.ts +6 -6
  47. package/packages/core/src/agent/thread-id.ts +71 -0
  48. package/packages/core/src/agent/thread-store.ts +293 -0
  49. package/packages/core/src/agent/tool-selector.ts +9 -5
  50. package/packages/core/src/agent/tracer.ts +5 -5
  51. package/packages/core/src/api/createAgent.ts +67 -2
  52. package/packages/core/src/artifacts/index.ts +15 -0
  53. package/packages/core/src/artifacts/store.ts +161 -5
  54. package/packages/core/src/canvas/emitter.ts +2 -2
  55. package/packages/core/src/canvas/index.ts +9 -0
  56. package/packages/core/src/channels/telegram.ts +1 -1
  57. package/packages/core/src/channels/webchat.ts +1 -1
  58. package/packages/core/src/config/loader.ts +14 -5
  59. package/packages/core/src/ethics/EthicsGuard.ts +7 -1
  60. package/packages/core/src/events/agent-bus.ts +3 -3
  61. package/packages/core/src/events/channel-narration.ts +3 -3
  62. package/packages/core/src/events/event-bus.ts +1 -1
  63. package/packages/core/src/events/index.ts +18 -0
  64. package/packages/core/src/events/narration.ts +3 -3
  65. package/packages/core/src/events/tool-narration.ts +4 -0
  66. package/packages/core/src/gateway/channel-notify.ts +103 -6
  67. package/packages/core/src/gateway/delegation-groups.ts +4 -4
  68. package/packages/core/src/gateway/durable-queue.ts +18 -6
  69. package/packages/core/src/gateway/index.ts +3 -0
  70. package/packages/core/src/gateway/job-store.ts +11 -5
  71. package/packages/core/src/gateway/notification-inbox.ts +2 -2
  72. package/packages/core/src/gateway/server.ts +2 -2
  73. package/packages/core/src/harness/executors.ts +493 -0
  74. package/packages/core/src/harness/index.ts +12 -2
  75. package/packages/core/src/hooks/index.ts +203 -0
  76. package/packages/core/src/images/index.ts +161 -0
  77. package/packages/core/src/index.ts +1 -0
  78. package/packages/core/src/mcp/MCPClient.ts +3 -3
  79. package/packages/core/src/mcp/hot-reload.ts +5 -5
  80. package/packages/core/src/mcp/tool-sync.ts +5 -5
  81. package/packages/core/src/mcp/transports/index.ts +2 -2
  82. package/packages/core/src/mcp/transports/sse.ts +1 -1
  83. package/packages/core/src/models/index.ts +36 -0
  84. package/packages/core/src/multimodal/index.ts +2 -2
  85. package/packages/core/src/multimodal/vision-service.ts +51 -19
  86. package/packages/core/src/plugins/loader.ts +4 -1
  87. package/packages/core/src/resilience/circuit-breaker.ts +16 -5
  88. package/packages/core/src/resilience/index.ts +13 -0
  89. package/packages/core/src/resilience/retry.ts +1 -1
  90. package/packages/core/src/scheduler/CronScheduler.ts +54 -27
  91. package/packages/core/src/scheduler/cron/expression.ts +165 -0
  92. package/packages/core/src/scheduler/cron/index.ts +10 -0
  93. package/packages/core/src/scheduler/cron/job.ts +339 -0
  94. package/packages/core/src/scheduler/cron/next-run.ts +121 -0
  95. package/packages/core/src/scheduler/cron/zoned-time.ts +138 -0
  96. package/packages/core/src/scheduler/index.ts +21 -3
  97. package/packages/core/src/scheduler/integration.ts +25 -14
  98. package/packages/core/src/scheduler/types.ts +3 -18
  99. package/packages/core/src/services/agents.ts +268 -0
  100. package/packages/core/src/services/cron.ts +257 -0
  101. package/packages/core/src/services/endpoints.ts +289 -0
  102. package/packages/core/src/services/ethics.ts +107 -0
  103. package/packages/core/src/services/images.ts +212 -0
  104. package/packages/core/src/services/index.ts +112 -0
  105. package/packages/core/src/services/mcp.ts +201 -0
  106. package/packages/core/src/services/memory.ts +133 -0
  107. package/packages/core/src/services/models.ts +179 -0
  108. package/packages/core/src/services/providers.ts +152 -0
  109. package/packages/core/src/services/setup.ts +222 -0
  110. package/packages/core/src/services/skills.ts +241 -0
  111. package/packages/core/src/services/swarms.ts +307 -0
  112. package/packages/core/src/services/tools.ts +106 -0
  113. package/packages/core/src/sessions/index.ts +268 -0
  114. package/packages/core/src/sessions/resolve.ts +108 -0
  115. package/packages/core/src/skills/SkillLoader.ts +8 -1
  116. package/packages/core/src/skills/bundled/artifacts/artifact_reader/SKILL.md +105 -0
  117. package/packages/core/src/skills/bundled/cron_manager/SKILL.md +21 -11
  118. package/packages/core/src/skills/bundled/images/image_editor/SKILL.md +120 -0
  119. package/packages/core/src/skills/bundled/web/browser_automate/SKILL.md +12 -3
  120. package/packages/core/src/skills/bundled/web/browser_scrape/SKILL.md +22 -7
  121. package/packages/core/src/skills/bundled-data.generated.ts +110 -12
  122. package/packages/core/src/storage/bootstrap.ts +107 -12
  123. package/packages/core/src/storage/causal-events.ts +1 -1
  124. package/packages/core/src/storage/collections.ts +138 -2
  125. package/packages/core/src/storage/crypto.ts +35 -4
  126. package/packages/core/src/storage/hive.ts +1 -1
  127. package/packages/core/src/storage/hivedb.ts +10 -1
  128. package/packages/core/src/storage/index.ts +2 -1
  129. package/packages/core/src/storage/onboarding.ts +61 -45
  130. package/packages/core/src/storage/reconcile.ts +11 -6
  131. package/packages/core/src/storage/seed.ts +191 -23
  132. package/packages/core/src/storage/usage.ts +3 -3
  133. package/packages/core/src/swarm/AgentExecutor.ts +2 -2
  134. package/packages/core/src/swarm/Coordinator.ts +8 -8
  135. package/packages/core/src/swarm/EventBridge.ts +2 -2
  136. package/packages/core/src/swarm/RoleSwarm.ts +234 -0
  137. package/packages/core/src/swarm/TaskGraph.ts +2 -2
  138. package/packages/core/src/swarm/index.ts +7 -0
  139. package/packages/core/src/swarm/presets/HiveLearnPreset.ts +2 -2
  140. package/packages/core/src/swarm/presets/ResearchPreset.ts +2 -2
  141. package/packages/core/src/swarm/strategies/ParallelStrategy.ts +1 -1
  142. package/packages/core/src/swarm/strategies/PriorityStrategy.ts +3 -3
  143. package/packages/core/src/swarm/types.ts +3 -18
  144. package/packages/core/src/tool-runtime/embedded-worker.generated.ts +21 -0
  145. package/packages/core/src/tool-runtime/index.ts +129 -14
  146. package/packages/core/src/tools/ToolExecutor.ts +7 -3
  147. package/packages/core/src/tools/agents/index.ts +18 -60
  148. package/packages/core/src/tools/cli/index.ts +55 -0
  149. package/packages/core/src/tools/core/index.ts +52 -4
  150. package/packages/core/src/tools/cron/index.ts +8 -8
  151. package/packages/core/src/tools/images/index.ts +130 -0
  152. package/packages/core/src/tools/index.ts +14 -1
  153. package/packages/core/src/tools/office/office-escribir-xlsx.ts +2 -1
  154. package/packages/core/src/tools/office/office-leer-xlsx.ts +2 -1
  155. package/packages/core/src/tools/office/xlsx-loader.ts +19 -0
  156. package/packages/core/src/tools/web/artifact-inspect.ts +2 -2
  157. package/packages/core/src/tools/web/artifact-read.ts +162 -0
  158. package/packages/core/src/tools/web/browser-backend.ts +141 -44
  159. package/packages/core/src/tools/web/browser-click.ts +2 -2
  160. package/packages/core/src/tools/web/browser-extract.ts +2 -2
  161. package/packages/core/src/tools/web/browser-navigate.ts +2 -2
  162. package/packages/core/src/tools/web/browser-screenshot.ts +12 -5
  163. package/packages/core/src/tools/web/browser-script.ts +2 -2
  164. package/packages/core/src/tools/web/browser-service.ts +63 -384
  165. package/packages/core/src/tools/web/browser-session.ts +125 -0
  166. package/packages/core/src/tools/web/browser-type.ts +2 -2
  167. package/packages/core/src/tools/web/browser-wait.ts +2 -2
  168. package/packages/core/src/tools/web/computer-use.ts +553 -0
  169. package/packages/core/src/tools/web/index.ts +8 -1
  170. package/packages/core/src/tools/web/webview-backend.ts +460 -21
  171. package/packages/core/src/utils/index.ts +1 -0
  172. package/packages/core/src/utils/logger.ts +12 -4
  173. package/packages/core/src/utils/redact-binary.ts +17 -0
  174. package/packages/core/src/utils/toon.ts +1 -1
  175. package/packages/core/src/voice/index.ts +6 -6
  176. package/bun.lock +0 -859
  177. package/bunfig.toml +0 -9
  178. package/docs/API-AGENTS.md +0 -367
  179. package/docs/API-CONTEXT-COMPILER.md +0 -249
  180. package/docs/API-DAG-SCHEDULER.md +0 -273
  181. package/docs/API-TOOLS-SKILLS-CHANNELS.md +0 -446
  182. package/docs/API-WORKERS-EVENTS.md +0 -299
  183. package/docs/HIVE-HARNESS.md +0 -113
  184. package/docs/INDEX.md +0 -190
  185. package/docs/TEMPLATE-HIVE-APP.md +0 -360
  186. package/packages/cli/package.json +0 -17
  187. package/packages/cli/src/commands/create-app.test.ts +0 -180
  188. package/packages/core/package.json +0 -70
  189. package/packages/core/src/api/createAgent.test.ts +0 -160
  190. package/packages/core/src/canvas/canvas.test.ts +0 -36
  191. package/packages/core/src/channels/channels.test.ts +0 -18
  192. package/packages/core/src/ethics/EthicsGuard.test.ts +0 -108
  193. package/packages/core/src/gateway/gateway.test.ts +0 -38
  194. package/packages/core/src/memory/Scratchpad.test.ts +0 -68
  195. package/packages/core/src/scheduler/scheduler.test.ts +0 -15
  196. package/packages/core/src/skills/skills.test.ts +0 -62
  197. package/packages/core/src/swarm/swarm.test.ts +0 -24
  198. package/packages/core/src/tool-runtime/tool-runtime.test.ts +0 -99
  199. package/packages/core/src/tools/ToolRegistry.test.ts +0 -98
  200. package/packages/core/src/tools/api/api-request.test.ts +0 -164
  201. package/packages/core/src/tools/web/browser-service.test.ts +0 -83
  202. package/packages/core/src/workers/workers.test.ts +0 -41
  203. package/scripts/bump-version.ts +0 -248
  204. package/scripts/generate-skill-bundle.ts +0 -108
  205. package/test/acceptance-checks.test.ts +0 -403
  206. package/test/agent-loop-terminal-synthesis.test.ts +0 -32
  207. package/test/browser-backend.test.ts +0 -308
  208. package/test/catalog-agents-stay-enabled.test.ts +0 -117
  209. package/test/causal-events.test.ts +0 -117
  210. package/test/compaction.test.ts +0 -105
  211. package/test/context-compiler.test.ts +0 -269
  212. package/test/curator.test.ts +0 -130
  213. package/test/durable-queue.test.ts +0 -114
  214. package/test/harness-barrel.test.ts +0 -64
  215. package/test/hive-helpers.test.ts +0 -130
  216. package/test/hivedb-search.test.ts +0 -189
  217. package/test/internal-turns.test.ts +0 -166
  218. package/test/job-idempotency.test.ts +0 -68
  219. package/test/job-retry-backoff.test.ts +0 -184
  220. package/test/job-store.test.ts +0 -381
  221. package/test/llm-retry.test.ts +0 -97
  222. package/test/memory-perf.test.ts +0 -774
  223. package/test/minimal-loadout.test.ts +0 -78
  224. package/test/model-catalog.test.ts +0 -105
  225. package/test/preload.ts +0 -12
  226. package/test/reflector.test.ts +0 -320
  227. package/test/retention-cap.test.ts +0 -91
  228. package/test/retired-capabilities-pruned.test.ts +0 -192
  229. package/test/run-store.test.ts +0 -355
  230. package/test/scratchpad.test.ts +0 -74
  231. package/test/secrets-durability.test.ts +0 -119
  232. package/test/seed-model-reseed.test.ts +0 -155
  233. package/test/setup-agent-seed.test.ts +0 -264
  234. package/test/tool-inventory.test.ts +0 -65
  235. package/test/tool-runtime.test.ts +0 -258
  236. package/test/tool-selector-runtime-tools.test.ts +0 -117
  237. package/test/toon.test.ts +0 -429
  238. package/tsconfig.json +0 -42
@@ -1,160 +0,0 @@
1
- /**
2
- * `createAgent` persiste su configuración en la fila del agente.
3
- *
4
- * Hasta 0.1.5 aceptaba `provider`, `model`, `maxIterations`, `workspace` y
5
- * `systemPrompt` y los descartaba: construía el loop global y corría con lo que
6
- * hubiera en la base. Estos tests fijan que ahora sí lleguen.
7
- */
8
-
9
- process.env.HIVE_DB_PATH = ":memory:";
10
-
11
- import { describe, it, expect, beforeEach, afterEach } from "bun:test";
12
- import { z } from "zod";
13
- import { closeHiveDb } from "../storage/hivedb.ts";
14
- import { ensureHiveDb } from "../storage/bootstrap.ts";
15
- import { col, fromIndexable } from "../storage/hive.ts";
16
- import { clearAppTools, createAllTools } from "../tools/index.ts";
17
- import { selectTools } from "../agent/tool-selector.ts";
18
- import { loadConfig } from "../config/loader.ts";
19
- import type { AgentDoc, ModelDoc } from "../storage/collections.ts";
20
- import { createAgent } from "./createAgent.ts";
21
- import { defineTool } from "../tools/ToolRegistry.ts";
22
- import { defineSkill } from "../skills/defineSkill.ts";
23
-
24
- beforeEach(async () => {
25
- closeHiveDb();
26
- clearAppTools();
27
- await ensureHiveDb();
28
- });
29
-
30
- afterEach(() => {
31
- clearAppTools();
32
- closeHiveDb();
33
- });
34
-
35
- describe("createAgent", () => {
36
- it("persiste provider, modelo, prompt e iteraciones en la fila del agente", async () => {
37
- const agent = await createAgent({
38
- name: "Test Agent",
39
- provider: "anthropic",
40
- model: "claude-opus-5",
41
- systemPrompt: "Sos un asistente de prueba.",
42
- maxIterations: 7,
43
- workspace: "/tmp/ws",
44
- });
45
-
46
- expect(agent.name).toBe("Test Agent");
47
- expect(agent.id).toBe("test_agent");
48
-
49
- const agentsCol = await col<AgentDoc>("agents");
50
- const row = (await agentsCol.get("test_agent"))!.doc;
51
-
52
- expect(fromIndexable(row.provider_id)).toBe("anthropic");
53
- expect(fromIndexable(row.model_id)).toBe("claude-opus-5");
54
- expect(row.system_prompt).toBe("Sos un asistente de prueba.");
55
- expect(row.max_iterations).toBe(7);
56
- expect(row.workspace).toBe("/tmp/ws");
57
- });
58
-
59
- it("prefija el id del modelo cuando el provider es revendedor", async () => {
60
- await createAgent({
61
- name: "reseller",
62
- provider: "modelscope",
63
- model: "Qwen-Ambassador/Qwen3.8-Max",
64
- });
65
-
66
- const agentsCol = await col<AgentDoc>("agents");
67
- const row = (await agentsCol.get("reseller"))!.doc;
68
-
69
- expect(fromIndexable(row.model_id)).toBe("modelscope/Qwen-Ambassador/Qwen3.8-Max");
70
- });
71
-
72
- it("activa el modelo elegido, o resolveProviderConfig no encuentra su base_url", async () => {
73
- await createAgent({ name: "activador", provider: "anthropic", model: "claude-opus-5" });
74
-
75
- const modelsCol = await col<ModelDoc>("models");
76
- const model = (await modelsCol.get("claude-opus-5"))!.doc;
77
-
78
- expect(model.active).toBe(true);
79
- expect(model.enabled).toBe(true);
80
- });
81
-
82
- it("rechaza un modelo que no está en el catálogo", async () => {
83
- await expect(
84
- createAgent({ name: "fantasma", provider: "anthropic", model: "claude-que-no-existe" })
85
- ).rejects.toThrow(/no está en el catálogo/);
86
- });
87
-
88
- it("pide provider cuando se especifica un modelo", async () => {
89
- // El mismo modelo lo sirven varios providers y la clave del catálogo
90
- // depende de cuál, así que adivinarlo sería elegir por el usuario.
91
- await expect(createAgent({ name: "sin-provider", model: "claude-opus-5" })).rejects.toThrow(
92
- /necesita también `provider`/
93
- );
94
- });
95
-
96
- it("registra las tools de la app con su ejecutor, no sólo la declaración", async () => {
97
- const greet = defineTool({
98
- name: "greet_person",
99
- description: "Saluda a alguien",
100
- schema: z.object({ name: z.string().describe("a quién saludar") }),
101
- execute: async (args: { name: string }) => `Hola ${args.name}`,
102
- });
103
-
104
- await createAgent({ name: "con-tools", tools: [greet] });
105
-
106
- const registered = createAllTools(await loadConfig()).find((t) => t.name === "greet_person");
107
- expect(registered, "la tool no llegó al registry que lee el context compiler").toBeDefined();
108
- expect(registered!.parameters.properties).toHaveProperty("name");
109
- expect(registered!.parameters.required).toEqual(["name"]);
110
- expect(await registered!.execute({ name: "Ana" })).toBe("Hola Ana");
111
- });
112
-
113
- it("deja la tool de la app descubrible por búsqueda de capacidad", async () => {
114
- // El loadout inicial es mínimo a propósito; el resto se encuentra vía
115
- // `search_knowledge`, que corre sobre el índice BM25. Si createAgent no
116
- // siembra la fila en `tools` y no reindexa, la tool tiene ejecutor pero el
117
- // modelo no se entera de que existe.
118
- const weather = defineTool({
119
- name: "get_weather",
120
- description: "Consulta el clima actual de una ciudad. Sinónimos: tiempo, temperatura, pronóstico",
121
- schema: z.object({ city: z.string() }),
122
- execute: async (a: { city: string }) => `Soleado en ${a.city}`,
123
- });
124
-
125
- await createAgent({ name: "descubrible", tools: [weather] });
126
-
127
- const found = await selectTools("clima de una ciudad", undefined, 5);
128
- expect(found.map((t) => t.name)).toContain("get_weather");
129
- });
130
-
131
- it("reusa la fila al recrear un agente con el mismo nombre", async () => {
132
- const first = await createAgent({ name: "estable", provider: "anthropic", model: "claude-opus-5" });
133
- const second = await createAgent({ name: "estable", provider: "anthropic", model: "claude-sonnet-5" });
134
-
135
- expect(second.id).toBe(first.id);
136
-
137
- const agentsCol = await col<AgentDoc>("agents");
138
- const all = (await agentsCol.scan({})).filter((e) => e.id === "estable");
139
- expect(all).toHaveLength(1);
140
- expect(fromIndexable(all[0].doc.model_id)).toBe("claude-sonnet-5");
141
- });
142
- });
143
-
144
- describe("defineTool / defineSkill", () => {
145
- it("siguen siendo funciones de declaración puras", () => {
146
- const tool = defineTool({
147
- name: "greet",
148
- description: "Says hello",
149
- execute: async (args: { name: string }) => `Hello ${args.name}`,
150
- });
151
- expect(tool.name).toBe("greet");
152
-
153
- const skill = defineSkill({
154
- name: "greeting-skill",
155
- description: "Greeting skill",
156
- steps: [{ action: "greet", instruction: "Say hello" }],
157
- });
158
- expect(skill.name).toBe("greeting-skill");
159
- });
160
- });
@@ -1,36 +0,0 @@
1
- import { describe, expect, it } from "bun:test";
2
- import { emitCanvas, subscribeCanvas, unsubscribeCanvas } from "./emitter.ts";
3
-
4
- // `canvas:render` desapareció en 0.1.5: el canvas dejó de emitir componentes
5
- // sueltos y pasó a un modelo de grafo (`node_add` / `node_update` / `edge_*`),
6
- // que es el que consume la vista de oficina 3D.
7
-
8
- describe("canvas emitter", () => {
9
- it("subscribes and unsubscribes websocket-like objects", () => {
10
- let received: any = null;
11
- const ws = {
12
- send: (data: string) => { received = JSON.parse(data); },
13
- };
14
-
15
- subscribeCanvas(ws);
16
- emitCanvas("canvas:node_update", { nodeId: "test", changes: { status: "thinking" } });
17
- unsubscribeCanvas(ws);
18
-
19
- expect(received).toBeDefined();
20
- expect(received.type).toBe("canvas:node_update");
21
- });
22
-
23
- it("stops receiving after unsubscribe", () => {
24
- let count = 0;
25
- const ws = {
26
- send: () => { count++; },
27
- };
28
-
29
- subscribeCanvas(ws);
30
- emitCanvas("canvas:node_update", { nodeId: "a", changes: { status: "thinking" } });
31
- unsubscribeCanvas(ws);
32
- emitCanvas("canvas:node_update", { nodeId: "b", changes: { status: "idle" } });
33
-
34
- expect(count).toBe(1);
35
- });
36
- });
@@ -1,18 +0,0 @@
1
- import { describe, expect, it } from "bun:test";
2
- import { ChannelManager } from "./manager.ts";
3
- import { loadConfig } from "../config/loader.ts";
4
-
5
- describe("ChannelManager", () => {
6
- it("creates a channel manager", () => {
7
- const config = loadConfig();
8
- const manager = new ChannelManager(config);
9
- expect(manager).toBeDefined();
10
- });
11
-
12
- it("has onMessage handler", () => {
13
- const config = loadConfig();
14
- const manager = new ChannelManager(config);
15
- manager.onMessage(async () => {});
16
- expect(manager).toBeDefined();
17
- });
18
- });
@@ -1,108 +0,0 @@
1
- process.env.HIVE_DB_PATH = ":memory:";
2
-
3
- import { describe, it, expect, beforeEach, afterEach } from "bun:test";
4
- import { EthicsGuard } from "./EthicsGuard.ts";
5
- import { closeHiveDb } from "../storage/hivedb.ts";
6
- import { ensureHiveDb } from "../storage/bootstrap.ts";
7
- import { col } from "../storage/hive.ts";
8
- import { toIndexable } from "../storage/hive.ts";
9
- import type { PlaybookDoc } from "../storage/collections.ts";
10
-
11
- async function addRule(id: string, rule: string, category: string, opts?: {
12
- applicableTo?: string;
13
- helpfulCount?: number;
14
- active?: boolean;
15
- }) {
16
- const playbookCol = await col<PlaybookDoc>("playbook");
17
- const now = Date.now();
18
- await playbookCol.put(id, {
19
- id,
20
- rule,
21
- category,
22
- applicable_to: opts?.applicableTo ?? null,
23
- helpful_count: opts?.helpfulCount ?? 0,
24
- harmful_count: 0,
25
- active: opts?.active ?? true,
26
- source_reflection_id: toIndexable(null),
27
- created_at: now,
28
- updated_at: now,
29
- });
30
- }
31
-
32
- beforeEach(async () => {
33
- closeHiveDb();
34
- await ensureHiveDb();
35
- });
36
-
37
- afterEach(() => {
38
- closeHiveDb();
39
- });
40
-
41
- describe("EthicsGuard", () => {
42
- it("sólo devuelve reglas de response_quality activas", async () => {
43
- await addRule("rq-1", "Verificá las fuentes antes de responder", "response_quality");
44
- await addRule("rq-2", "Regla apagada", "response_quality", { active: false });
45
- await addRule("otra", "Usá web_search para noticias", "tool_selection");
46
-
47
- const rules = await new EthicsGuard().getRules();
48
-
49
- expect(rules.map((r) => r.id)).toEqual(["rq-1"]);
50
- });
51
-
52
- it("ordena por helpful_count descendente", async () => {
53
- await addRule("poco", "poco útil", "response_quality", { helpfulCount: 1 });
54
- await addRule("mucho", "muy útil", "response_quality", { helpfulCount: 9 });
55
-
56
- const rules = await new EthicsGuard().getRules();
57
-
58
- expect(rules.map((r) => r.id)).toEqual(["mucho", "poco"]);
59
- });
60
-
61
- it("filtra por agentRole cuando alguna regla lo declara", async () => {
62
- await addRule("para-coord", "regla del coordinador", "response_quality", {
63
- applicableTo: JSON.stringify(["coordinator"]),
64
- });
65
- await addRule("para-worker", "regla del worker", "response_quality", {
66
- applicableTo: JSON.stringify(["worker"]),
67
- });
68
-
69
- const rules = await new EthicsGuard().getRules("coordinator");
70
-
71
- expect(rules.map((r) => r.id)).toEqual(["para-coord"]);
72
- });
73
-
74
- it("cae a todas las reglas si ninguna declara ese rol", async () => {
75
- // Sin esto, un `applicable_to` mal cargado dejaría al agente sin capa
76
- // de calidad en vez de con una de más.
77
- await addRule("generica", "regla general", "response_quality", {
78
- applicableTo: JSON.stringify(["worker"]),
79
- });
80
-
81
- const rules = await new EthicsGuard().getRules("coordinator");
82
-
83
- expect(rules.map((r) => r.id)).toEqual(["generica"]);
84
- });
85
-
86
- it("injectIntoPrompt agrega las reglas y conserva el prompt original", async () => {
87
- await addRule("rq-1", "Verificá las fuentes", "response_quality");
88
-
89
- const guard = new EthicsGuard();
90
- const result = guard.injectIntoPrompt("Eres un asistente.", await guard.getRules());
91
-
92
- expect(result).toContain("Eres un asistente.");
93
- expect(result).toContain("## Reglas de Calidad de Respuesta");
94
- expect(result).toContain("- Verificá las fuentes");
95
- });
96
-
97
- it("injectIntoPrompt devuelve el prompt intacto sin reglas", () => {
98
- expect(new EthicsGuard().injectIntoPrompt("Eres un asistente.", [])).toBe("Eres un asistente.");
99
- });
100
-
101
- it("hasEthicsLayer refleja si hay reglas cargadas", async () => {
102
- const guard = new EthicsGuard();
103
- expect(await guard.hasEthicsLayer()).toBe(false);
104
-
105
- await addRule("rq-1", "Verificá las fuentes", "response_quality");
106
- expect(await guard.hasEthicsLayer()).toBe(true);
107
- });
108
- });
@@ -1,38 +0,0 @@
1
- import { describe, expect, it, beforeAll, afterAll } from "bun:test";
2
- import { startGateway } from "./index.ts";
3
-
4
- describe("gateway", () => {
5
- let server: ReturnType<typeof startGateway> extends Promise<infer T> ? T : never;
6
-
7
- beforeAll(async () => {
8
- server = await startGateway({ host: "127.0.0.1", port: 18791, agentId: "test" });
9
- });
10
-
11
- afterAll(() => {
12
- server?.stop(true);
13
- });
14
-
15
- it("returns health status", async () => {
16
- const res = await fetch("http://127.0.0.1:18791/status");
17
- expect(res.status).toBe(200);
18
- const body = await res.json();
19
- expect(body.status).toBe("ok");
20
- expect(body.gateway).toBe(true);
21
- expect(body.agentId).toBe("test");
22
- });
23
-
24
- it("returns 404 for unknown routes", async () => {
25
- const res = await fetch("http://127.0.0.1:18791/unknown");
26
- expect(res.status).toBe(404);
27
- });
28
-
29
- it("chat endpoint requires database setup", async () => {
30
- const res = await fetch("http://127.0.0.1:18791/chat", {
31
- method: "POST",
32
- headers: { "Content-Type": "application/json" },
33
- body: JSON.stringify({ message: "hello" }),
34
- });
35
- // Will fail because no DB/agent configured, but endpoint exists
36
- expect(res.status).toBe(500);
37
- });
38
- });
@@ -1,68 +0,0 @@
1
- process.env.HIVE_DB_PATH = ":memory:";
2
-
3
- import { describe, it, expect, beforeEach, afterEach } from "bun:test";
4
- import { Scratchpad } from "./Scratchpad.ts";
5
- import { closeHiveDb } from "../storage/hivedb.ts";
6
- import { ensureHiveDb } from "../storage/bootstrap.ts";
7
- import { getScratchpad } from "../agent/conversation-store.ts";
8
-
9
- const THREAD = "test-thread";
10
-
11
- let pad: Scratchpad;
12
-
13
- beforeEach(async () => {
14
- closeHiveDb();
15
- await ensureHiveDb();
16
- pad = new Scratchpad();
17
- });
18
-
19
- afterEach(() => {
20
- closeHiveDb();
21
- });
22
-
23
- describe("Scratchpad", () => {
24
- it("writes and reads a note", async () => {
25
- await pad.write(THREAD, "test-1", "hello world");
26
- expect(await pad.read(THREAD, "test-1")).toBe("hello world");
27
- });
28
-
29
- it("lists notes as key-value map", async () => {
30
- await pad.write(THREAD, "list-a", "aaa");
31
- await pad.write(THREAD, "list-b", "bbb");
32
-
33
- const notes = await pad.list(THREAD);
34
- expect(notes["list-a"]).toBe("aaa");
35
- expect(notes["list-b"]).toBe("bbb");
36
- });
37
-
38
- it("deletes a note", async () => {
39
- await pad.write(THREAD, "to-delete", "delete me");
40
- await pad.delete(THREAD, "to-delete");
41
- expect(await pad.read(THREAD, "to-delete")).toBeUndefined();
42
- });
43
-
44
- it("clear removes all notes for a thread", async () => {
45
- await pad.write(THREAD, "clear-a", "a");
46
- await pad.write(THREAD, "clear-b", "b");
47
- await pad.clear(THREAD);
48
- expect(Object.keys(await pad.list(THREAD))).toHaveLength(0);
49
- });
50
-
51
- it("no toca las notas de otros threads", async () => {
52
- await pad.write("thread-uno", "k", "uno");
53
- await pad.write("thread-dos", "k", "dos");
54
- await pad.clear("thread-uno");
55
-
56
- expect(await pad.read("thread-dos", "k")).toBe("dos");
57
- });
58
-
59
- it("escribe el mismo documento que lee el context compiler", async () => {
60
- // La clase y `conversation-store` comparten colección e id. Antes la clase
61
- // guardaba un doc incompleto (sin `source`, `createdAt` ni `seq`), así que
62
- // una nota escrita por acá se ordenaba mal dentro del prompt.
63
- await pad.write(THREAD, "compartida", "valor", "test");
64
-
65
- const notes = await getScratchpad(THREAD);
66
- expect(notes).toEqual([{ key: "compartida", value: "valor" }]);
67
- });
68
- });
@@ -1,15 +0,0 @@
1
- process.env.HIVE_DB_PATH = ":memory:";
2
-
3
- import { describe, expect, it } from "bun:test";
4
- import { CronScheduler } from "./CronScheduler.ts";
5
-
6
- // `new CronScheduler(db, handler)` pasó a `new CronScheduler(handler)`: los jobs
7
- // viven en la colección `cronJobs` de HiveDB y el scheduler la abre solo, así
8
- // que ya no recibe un handle de base.
9
-
10
- describe("CronScheduler", () => {
11
- it("creates a scheduler instance with a handler", () => {
12
- const scheduler = new CronScheduler(async () => ({ success: true }));
13
- expect(scheduler).toBeDefined();
14
- });
15
- });
@@ -1,62 +0,0 @@
1
- /**
2
- * El catálogo de skills bundled se genera desde los SKILL.md de `skills/bundled/`
3
- * con `bun run skills:bundle`. Hasta 0.1.5 el SDK traía 44 skills copiadas a
4
- * mano, 21 de las cuales invocaban tools que ya no existen (`voice_*`,
5
- * `meeting_transcription`, `canvas_*`, `code_*`, `project_*`): el selector se
6
- * las podía ofrecer al modelo y la ejecución moría sin ejecutor.
7
- */
8
-
9
- import { describe, it, expect } from "bun:test";
10
- import { BUNDLED_SKILLS_DATA } from "./bundled-data.generated.ts";
11
- import { createAllTools } from "../tools/index.ts";
12
- import { loadConfig } from "../config/loader.ts";
13
-
14
- describe("Bundled skills", () => {
15
- it("incluye las skills web y de browser", () => {
16
- const names = BUNDLED_SKILLS_DATA.map((s) => s.name);
17
- expect(names).toContain("web_research");
18
- expect(names).toContain("browser_scrape");
19
- expect(names).toContain("browser_automate");
20
- });
21
-
22
- it("no arrastra las skills retiradas", () => {
23
- const names = BUNDLED_SKILLS_DATA.map((s) => s.name);
24
- for (const retired of [
25
- "web_browser_research",
26
- "voice_input",
27
- "voice_output",
28
- "voice_assistant",
29
- "meeting_transcription",
30
- "canvas_report",
31
- "canvas_dashboard",
32
- "code_review",
33
- "code_generate",
34
- "project_planner",
35
- "busqueda_fts5",
36
- "ai_coder",
37
- "data_analyst",
38
- ]) {
39
- expect(names, `la skill retirada "${retired}" volvió al bundle`).not.toContain(retired);
40
- }
41
- });
42
-
43
- it("cada skill declara sólo tools que existen en el registry", async () => {
44
- const available = new Set(createAllTools(await loadConfig()).map((t) => t.name));
45
-
46
- const dangling = BUNDLED_SKILLS_DATA.flatMap((skill) =>
47
- (skill.tools ?? [])
48
- .filter((tool) => !available.has(tool))
49
- .map((tool) => `${skill.name} → ${tool}`)
50
- );
51
-
52
- expect(dangling, `skills apuntando a tools inexistentes:\n${dangling.join("\n")}`).toEqual([]);
53
- });
54
-
55
- it("toda skill tiene nombre, descripción y categoría", () => {
56
- for (const skill of BUNDLED_SKILLS_DATA) {
57
- expect(skill.name, "skill sin nombre").toBeTruthy();
58
- expect(skill.description, `${skill.name} sin descripción`).toBeTruthy();
59
- expect(skill.category, `${skill.name} sin categoría`).toBeTruthy();
60
- }
61
- });
62
- });
@@ -1,24 +0,0 @@
1
- import { describe, expect, it } from "bun:test";
2
- import { TaskGraph } from "./TaskGraph.ts";
3
-
4
- describe("TaskGraph", () => {
5
- it("creates a graph with nodes", () => {
6
- const graph = new TaskGraph([
7
- { id: "a", agentId: "agent-a", name: "Task A", taskDescription: "Task A", deps: [] },
8
- { id: "b", agentId: "agent-b", name: "Task B", taskDescription: "Task B", deps: ["a"] },
9
- ]);
10
-
11
- expect(graph.nodes.size).toBe(2);
12
- expect(graph.nodes.get("a")?.deps).toEqual([]);
13
- expect(graph.nodes.get("b")?.deps).toEqual(["a"]);
14
- });
15
-
16
- it("validates node existence", () => {
17
- const graph = new TaskGraph([
18
- { id: "a", agentId: "agent-a", name: "Task A", taskDescription: "Task A", deps: [] },
19
- ]);
20
-
21
- expect(graph.nodes.has("a")).toBe(true);
22
- expect(graph.nodes.has("missing")).toBe(false);
23
- });
24
- });
@@ -1,99 +0,0 @@
1
- import { afterEach, describe, expect, it } from "bun:test";
2
- import { executeToolBatch, shutdownToolRuntime, type RuntimeTool, type ToolCallLike } from "./index.ts";
3
- import { loadConfig } from "../config/loader.ts";
4
-
5
- const delay = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms));
6
-
7
- function toolCall(id: string, name: string, args: unknown = {}): ToolCallLike {
8
- return {
9
- id,
10
- function: {
11
- name,
12
- arguments: JSON.stringify(args),
13
- },
14
- };
15
- }
16
-
17
- describe("tool runtime worker pool", () => {
18
- afterEach(() => {
19
- shutdownToolRuntime();
20
- });
21
-
22
- it("runs multiple tools in parallel through worker scheduling", async () => {
23
- // Per-tool delay + threshold sized for CI headroom: worker spawn/scheduling
24
- // overhead is roughly fixed, so a larger delay keeps that overhead a small
25
- // fraction of the budget instead of dominating it on a loaded runner.
26
- // Serial execution would take ~3x the delay; the threshold stays well
27
- // under that so the assertion still proves parallelism, not just patience.
28
- const TOOL_DELAY_MS = 200;
29
- const PARALLEL_THRESHOLD_MS = 450;
30
-
31
- const tools: RuntimeTool[] = ["slow_a", "slow_b", "slow_c"].map((name) => ({
32
- name,
33
- execute: async () => {
34
- await delay(TOOL_DELAY_MS);
35
- return { name };
36
- },
37
- }));
38
-
39
- const startedAt = performance.now();
40
- const results = await executeToolBatch({
41
- toolCalls: [
42
- toolCall("1", "slow_a"),
43
- toolCall("2", "slow_b"),
44
- toolCall("3", "slow_c"),
45
- ],
46
- allTools: tools,
47
- toolConfig: {},
48
- hiveConfig: loadConfig(),
49
- workerPool: { enabled: true, maxWorkers: 3, toolTimeoutMs: 5000, parallelToolCalls: true },
50
- });
51
- const elapsed = performance.now() - startedAt;
52
-
53
- expect(results.map((result) => (result.result as any).name)).toEqual(["slow_a", "slow_b", "slow_c"]);
54
- expect(elapsed).toBeLessThan(PARALLEL_THRESHOLD_MS);
55
- });
56
-
57
- it("preserves input order when tools complete out of order", async () => {
58
- const tools: RuntimeTool[] = [
59
- { name: "first", execute: async () => { await delay(120); return { value: 1 } } },
60
- { name: "second", execute: async () => { await delay(20); return { value: 2 } } },
61
- { name: "third", execute: async () => { await delay(60); return { value: 3 } } },
62
- ];
63
-
64
- const results = await executeToolBatch({
65
- toolCalls: [toolCall("1", "first"), toolCall("2", "second"), toolCall("3", "third")],
66
- allTools: tools,
67
- toolConfig: {},
68
- hiveConfig: loadConfig(),
69
- workerPool: { enabled: true, maxWorkers: 3, toolTimeoutMs: 1000, parallelToolCalls: true },
70
- });
71
-
72
- expect(results.map((r) => (r.result as any).value)).toEqual([1, 2, 3]);
73
- });
74
-
75
- it("handles tool errors gracefully", async () => {
76
- const tools: RuntimeTool[] = [
77
- {
78
- name: "fail",
79
- execute: async () => {
80
- throw new Error("intentional failure");
81
- },
82
- },
83
- ];
84
-
85
- const results = await executeToolBatch({
86
- toolCalls: [toolCall("1", "fail")],
87
- allTools: tools,
88
- toolConfig: {},
89
- hiveConfig: loadConfig(),
90
- workerPool: { enabled: true, maxWorkers: 1, toolTimeoutMs: 1000, parallelToolCalls: false },
91
- });
92
-
93
- expect(results[0].ok).toBe(false);
94
- expect(results[0].result).toBeDefined();
95
- const result = results[0].result as any;
96
- expect(result.error).toBe(true);
97
- expect(result.message).toContain("intentional failure");
98
- });
99
- });