@johpaz/hive-sdk 0.1.3 → 0.1.5

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 (272) hide show
  1. package/CHANGELOG.md +97 -0
  2. package/README.md +78 -23
  3. package/bunfig.toml +4 -2
  4. package/docs/API-AGENTS.md +78 -27
  5. package/docs/API-CONTEXT-COMPILER.md +31 -34
  6. package/docs/API-TOOLS-SKILLS-CHANNELS.md +58 -22
  7. package/docs/HIVE-HARNESS.md +1 -1
  8. package/docs/INDEX.md +4 -4
  9. package/docs/TEMPLATE-HIVE-APP.md +10 -10
  10. package/package.json +9 -4
  11. package/packages/cli/package.json +2 -2
  12. package/packages/cli/src/commands/create-app.test.ts +36 -7
  13. package/packages/cli/src/commands/init.ts +3 -3
  14. package/packages/cli/src/commands/run.ts +1 -1
  15. package/packages/cli/src/commands/test.ts +37 -25
  16. package/packages/cli/src/commands/trace.ts +30 -28
  17. package/packages/cli/templates/hive-app/.env.example +10 -2
  18. package/packages/cli/templates/hive-app/README.md +103 -0
  19. package/packages/cli/templates/hive-app/hive.config.ts +9 -3
  20. package/packages/cli/templates/hive-app/src/agents/coordinator.ts +8 -1
  21. package/packages/cli/templates/hive-app/src/main.ts +12 -19
  22. package/packages/core/package.json +5 -4
  23. package/packages/core/src/agent/acceptance-checks.ts +166 -0
  24. package/packages/core/src/agent/agent-catalog.ts +348 -0
  25. package/packages/core/src/agent/agent-loop.ts +1373 -0
  26. package/packages/core/src/agent/capability-search.ts +186 -0
  27. package/packages/core/src/agent/catalog-selector.ts +103 -0
  28. package/packages/core/src/agent/{Compaction.ts → compaction.ts} +86 -63
  29. package/packages/core/src/agent/context-compiler.ts +689 -0
  30. package/packages/core/src/agent/conversation-store.ts +381 -0
  31. package/packages/core/src/agent/curator.ts +276 -0
  32. package/packages/core/src/agent/delegation-runtime.ts +241 -0
  33. package/packages/core/src/agent/goal-runner.ts +323 -0
  34. package/packages/core/src/agent/index.ts +17 -12
  35. package/packages/core/src/agent/llm-client.ts +266 -0
  36. package/packages/core/src/agent/llm-providers/anthropic.ts +264 -0
  37. package/packages/core/src/agent/llm-providers/deepseek.ts +8 -0
  38. package/packages/core/src/agent/{providers → llm-providers}/gemini.ts +98 -60
  39. package/packages/core/src/agent/llm-providers/groq.ts +5 -0
  40. package/packages/core/src/agent/llm-providers/hiveagents.ts +253 -0
  41. package/packages/core/src/agent/{providers → llm-providers}/interface.ts +73 -13
  42. package/packages/core/src/agent/llm-providers/kimi.ts +8 -0
  43. package/packages/core/src/agent/llm-providers/minimax.ts +13 -0
  44. package/packages/core/src/agent/llm-providers/mistral.ts +5 -0
  45. package/packages/core/src/agent/llm-providers/modelscope.ts +5 -0
  46. package/packages/core/src/agent/llm-providers/nvidia.ts +5 -0
  47. package/packages/core/src/agent/{providers → llm-providers}/ollama.ts +31 -5
  48. package/packages/core/src/agent/llm-providers/openai-compat-base.ts +418 -0
  49. package/packages/core/src/agent/llm-providers/openai.ts +5 -0
  50. package/packages/core/src/agent/llm-providers/opencode-go.ts +9 -0
  51. package/packages/core/src/agent/llm-providers/openrouter.ts +5 -0
  52. package/packages/core/src/agent/llm-providers/qwen.ts +5 -0
  53. package/packages/core/src/agent/llm-providers/z-ai.ts +5 -0
  54. package/packages/core/src/agent/minimal-loadout.ts +47 -0
  55. package/packages/core/src/agent/playbook-selector.ts +119 -0
  56. package/packages/core/src/agent/{PromptBuilder.ts → prompt-builder.ts} +21 -22
  57. package/packages/core/src/{harness → agent}/proof-packet.ts +16 -21
  58. package/packages/core/src/agent/providers/index.ts +35 -16
  59. package/packages/core/src/agent/reflector.ts +320 -0
  60. package/packages/core/src/agent/routing-intent.ts +22 -0
  61. package/packages/core/src/{harness → agent}/run-epoch.ts +4 -3
  62. package/packages/core/src/{harness → agent}/run-store.ts +142 -81
  63. package/packages/core/src/agent/{Service.ts → service.ts} +37 -26
  64. package/packages/core/src/agent/skill-selector.ts +374 -0
  65. package/packages/core/src/agent/stuck-loop.ts +209 -0
  66. package/packages/core/src/agent/{selectors/ToolSelector.ts → tool-selector.ts} +188 -178
  67. package/packages/core/src/{ace/Tracer.ts → agent/tracer.ts} +37 -27
  68. package/packages/core/src/api/createAgent.test.ts +139 -27
  69. package/packages/core/src/api/createAgent.ts +232 -44
  70. package/packages/core/src/artifacts/store.ts +162 -0
  71. package/packages/core/src/canvas/canvas-manager.ts +161 -0
  72. package/packages/core/src/canvas/canvas.test.ts +8 -4
  73. package/packages/core/src/canvas/emitter.ts +131 -80
  74. package/packages/core/src/canvas/index.ts +1 -3
  75. package/packages/core/src/channels/base.ts +9 -1
  76. package/packages/core/src/channels/discord.ts +5 -4
  77. package/packages/core/src/channels/manager.ts +122 -30
  78. package/packages/core/src/channels/slack.ts +5 -4
  79. package/packages/core/src/channels/telegram.ts +36 -6
  80. package/packages/core/src/channels/webchat.ts +11 -10
  81. package/packages/core/src/channels/whatsapp.ts +23 -7
  82. package/packages/core/src/config/index.ts +13 -2
  83. package/packages/core/src/config/loader.ts +71 -29
  84. package/packages/core/src/ethics/EthicsGuard.test.ts +90 -36
  85. package/packages/core/src/ethics/EthicsGuard.ts +51 -47
  86. package/packages/core/src/events/agent-bus.ts +44 -68
  87. package/packages/core/src/events/channel-narration.ts +150 -0
  88. package/packages/core/src/events/narration.ts +82 -0
  89. package/packages/core/src/events/tool-narration.ts +62 -0
  90. package/packages/core/src/gateway/delegation-groups.ts +258 -0
  91. package/packages/core/src/{harness → gateway}/durable-queue.ts +102 -42
  92. package/packages/core/src/{harness → gateway}/job-store.ts +85 -48
  93. package/packages/core/src/gateway/lane-queue.ts +173 -0
  94. package/packages/core/src/gateway/notification-inbox.ts +57 -0
  95. package/packages/core/src/gateway/server.ts +1 -1
  96. package/packages/core/src/harness/index.ts +46 -27
  97. package/packages/core/src/index.ts +33 -20
  98. package/packages/core/src/mcp/hot-reload.ts +32 -23
  99. package/packages/core/src/mcp/index.ts +6 -3
  100. package/packages/core/src/mcp/singleton.ts +1 -4
  101. package/packages/core/src/mcp/tool-sync.ts +138 -0
  102. package/packages/core/src/memory/Scratchpad.test.ts +39 -20
  103. package/packages/core/src/memory/Scratchpad.ts +27 -34
  104. package/packages/core/src/multimodal/vision-service.ts +44 -38
  105. package/packages/core/src/resilience/retry.ts +95 -0
  106. package/packages/core/src/scheduler/CronScheduler.ts +334 -287
  107. package/packages/core/src/scheduler/index.ts +9 -7
  108. package/packages/core/src/scheduler/integration.ts +46 -26
  109. package/packages/core/src/scheduler/scheduler.test.ts +9 -13
  110. package/packages/core/src/scheduler/types.ts +7 -2
  111. package/packages/core/src/security/Pairing.ts +1 -1
  112. package/packages/core/src/skills/bundled/a2ui/a2ui_dashboard/SKILL.md +176 -0
  113. package/packages/core/src/skills/bundled/a2ui/a2ui_form/SKILL.md +202 -0
  114. package/packages/core/src/skills/bundled/a2ui/a2ui_interactive/SKILL.md +206 -0
  115. package/packages/core/src/skills/bundled/agents/agent_spawner/SKILL.md +173 -0
  116. package/packages/core/src/skills/bundled/agents/memory_manager/SKILL.md +143 -0
  117. package/packages/core/src/skills/bundled/agents/research_and_remember/SKILL.md +139 -0
  118. package/packages/core/src/skills/bundled/agents/task_orchestrator/SKILL.md +98 -0
  119. package/packages/core/src/skills/bundled/api/api_client/SKILL.md +132 -0
  120. package/packages/core/src/skills/bundled/cli/cli_pipeline/SKILL.md +135 -0
  121. package/packages/core/src/skills/bundled/cli/cli_safe_exec/SKILL.md +125 -0
  122. package/packages/core/src/skills/bundled/cli/software_engineering/SKILL.md +23 -0
  123. package/packages/core/src/skills/bundled/cron_manager/SKILL.md +188 -0
  124. package/packages/core/src/skills/bundled/cron_reminder/SKILL.md +112 -0
  125. package/packages/core/src/skills/bundled/filesystem/file_manager/SKILL.md +118 -0
  126. package/packages/core/src/skills/bundled/filesystem/file_read_and_summarize/SKILL.md +109 -0
  127. package/packages/core/src/skills/bundled/filesystem/file_writer/SKILL.md +129 -0
  128. package/packages/core/src/skills/bundled/filesystem/workspace_file_operator/SKILL.md +22 -0
  129. package/packages/core/src/skills/bundled/office/office_document_manager/SKILL.md +262 -0
  130. package/packages/core/src/skills/bundled/search_knowledge/capability_discovery/SKILL.md +75 -0
  131. package/packages/core/src/skills/bundled/web/browser_automate/SKILL.md +120 -0
  132. package/packages/core/src/skills/bundled/web/browser_scrape/SKILL.md +109 -0
  133. package/packages/core/src/skills/bundled/web/web_monitor/SKILL.md +127 -0
  134. package/packages/core/src/skills/bundled/web/web_research/SKILL.md +119 -0
  135. package/packages/core/src/skills/bundled-data.generated.ts +731 -2678
  136. package/packages/core/src/skills/skills.test.ts +52 -11
  137. package/packages/core/src/{harness → storage}/boot-id.ts +5 -2
  138. package/packages/core/src/storage/bootstrap.ts +151 -0
  139. package/packages/core/src/storage/causal-events.ts +84 -0
  140. package/packages/core/src/storage/collections.ts +680 -0
  141. package/packages/core/src/storage/crypto.ts +205 -74
  142. package/packages/core/src/{harness/db-helpers.ts → storage/hive.ts} +63 -7
  143. package/packages/core/src/storage/hivedb.ts +61 -0
  144. package/packages/core/src/storage/index.ts +111 -17
  145. package/packages/core/src/storage/model-id.ts +53 -0
  146. package/packages/core/src/storage/onboarding.ts +540 -972
  147. package/packages/core/src/storage/reconcile.ts +238 -0
  148. package/packages/core/src/storage/seed.ts +572 -406
  149. package/packages/core/src/storage/usage.ts +285 -225
  150. package/packages/core/src/storage/user-email.ts +11 -0
  151. package/packages/core/src/swarm/AgentExecutor.ts +1 -1
  152. package/packages/core/src/swarm/EventBridge.ts +1 -1
  153. package/packages/core/src/swarm/index.ts +12 -9
  154. package/packages/core/src/tool-runtime/index.ts +146 -23
  155. package/packages/core/src/tool-runtime/tool-worker.ts +2 -2
  156. package/packages/core/src/tool-runtime/worker-tools.ts +27 -0
  157. package/packages/core/src/{canvas/a2ui-tools.ts → tools/a2ui/index.ts} +17 -8
  158. package/packages/core/src/tools/agents/get-available-models.ts +36 -54
  159. package/packages/core/src/tools/agents/index.ts +784 -292
  160. package/packages/core/src/tools/api/api-request.test.ts +164 -0
  161. package/packages/core/src/tools/api/api-request.ts +174 -0
  162. package/packages/core/src/tools/api/index.ts +16 -0
  163. package/packages/core/src/tools/cli/index.ts +4 -0
  164. package/packages/core/src/tools/core/index.ts +281 -112
  165. package/packages/core/src/tools/cron/index.ts +121 -124
  166. package/packages/core/src/tools/index.ts +63 -78
  167. package/packages/core/src/tools/office/office-escribir-xlsx.ts +3 -1
  168. package/packages/core/src/tools/types.ts +3 -1
  169. package/packages/core/src/tools/web/artifact-inspect.ts +23 -0
  170. package/packages/core/src/tools/web/browser-screenshot.ts +26 -5
  171. package/packages/core/src/tools/web/browser-service.ts +5 -0
  172. package/packages/core/src/tools/web/browser-type.ts +3 -8
  173. package/packages/core/src/tools/web/index.ts +4 -4
  174. package/packages/core/src/voice/index.ts +89 -63
  175. package/packages/core/src/workers/agent.worker.ts +2 -2
  176. package/packages/core/src/workers/workers.test.ts +3 -10
  177. package/scripts/bump-version.ts +248 -0
  178. package/scripts/generate-skill-bundle.ts +108 -0
  179. package/test/agent-loop-terminal-synthesis.test.ts +32 -0
  180. package/test/catalog-agents-stay-enabled.test.ts +117 -0
  181. package/test/causal-events.test.ts +117 -0
  182. package/test/compaction.test.ts +105 -0
  183. package/test/context-compiler.test.ts +269 -0
  184. package/test/curator.test.ts +130 -0
  185. package/test/durable-queue.test.ts +114 -0
  186. package/test/harness-barrel.test.ts +64 -0
  187. package/test/hive-helpers.test.ts +130 -0
  188. package/test/hivedb-search.test.ts +189 -0
  189. package/test/internal-turns.test.ts +166 -0
  190. package/test/job-idempotency.test.ts +68 -0
  191. package/test/job-retry-backoff.test.ts +184 -0
  192. package/test/job-store.test.ts +381 -0
  193. package/test/llm-retry.test.ts +97 -0
  194. package/test/memory-perf.test.ts +774 -0
  195. package/test/minimal-loadout.test.ts +78 -0
  196. package/test/model-catalog.test.ts +105 -0
  197. package/test/preload.ts +12 -0
  198. package/test/reflector.test.ts +320 -0
  199. package/test/retention-cap.test.ts +91 -0
  200. package/test/retired-capabilities-pruned.test.ts +192 -0
  201. package/test/run-store.test.ts +355 -0
  202. package/test/scratchpad.test.ts +74 -0
  203. package/test/secrets-durability.test.ts +119 -0
  204. package/test/seed-model-reseed.test.ts +155 -0
  205. package/test/setup-agent-seed.test.ts +264 -0
  206. package/test/tool-inventory.test.ts +65 -0
  207. package/test/tool-runtime.test.ts +258 -0
  208. package/test/toon.test.ts +429 -0
  209. package/tsconfig.json +2 -0
  210. package/packages/core/src/ace/Curator.ts +0 -158
  211. package/packages/core/src/ace/Reflector.ts +0 -200
  212. package/packages/core/src/ace/index.ts +0 -4
  213. package/packages/core/src/agent/AgentRunner.ts +0 -711
  214. package/packages/core/src/agent/ContextCompiler.ts +0 -567
  215. package/packages/core/src/agent/ContextGuard.ts +0 -91
  216. package/packages/core/src/agent/ConversationStore.ts +0 -254
  217. package/packages/core/src/agent/Hooks.ts +0 -166
  218. package/packages/core/src/agent/StuckLoop.ts +0 -133
  219. package/packages/core/src/agent/providers/LLMClient.ts +0 -149
  220. package/packages/core/src/agent/providers/anthropic.ts +0 -212
  221. package/packages/core/src/agent/providers/openai-compat.ts +0 -231
  222. package/packages/core/src/agent/selectors/PlaybookSelector.ts +0 -121
  223. package/packages/core/src/agent/selectors/SkillSelector.ts +0 -322
  224. package/packages/core/src/agent/selectors/index.ts +0 -6
  225. package/packages/core/src/auth/auth.ts +0 -121
  226. package/packages/core/src/auth/index.ts +0 -1
  227. package/packages/core/src/canvas/CanvasManager.ts +0 -390
  228. package/packages/core/src/canvas/canvas-tools.ts +0 -448
  229. package/packages/core/src/harness/collections.ts +0 -98
  230. package/packages/core/src/harness/goal-verifier.ts +0 -141
  231. package/packages/core/src/harness/harness.test.ts +0 -236
  232. package/packages/core/src/harness/reconcile.ts +0 -149
  233. package/packages/core/src/mcp/MCPToolAdapter.ts +0 -176
  234. package/packages/core/src/multimodal/VisionService.ts +0 -293
  235. package/packages/core/src/scheduler/dag/AgentExecutor.ts +0 -53
  236. package/packages/core/src/scheduler/dag/DAGScheduler.ts +0 -250
  237. package/packages/core/src/scheduler/dag/EventBridge.ts +0 -122
  238. package/packages/core/src/scheduler/dag/TaskGraph.ts +0 -192
  239. package/packages/core/src/scheduler/dag/TaskNode.ts +0 -97
  240. package/packages/core/src/scheduler/dag/TaskResult.ts +0 -22
  241. package/packages/core/src/scheduler/dag/errors.ts +0 -37
  242. package/packages/core/src/scheduler/dag/index.ts +0 -26
  243. package/packages/core/src/scheduler/dag/presets/ResearchPreset.ts +0 -97
  244. package/packages/core/src/scheduler/dag/strategies/ParallelStrategy.ts +0 -21
  245. package/packages/core/src/scheduler/dag/strategies/PriorityStrategy.ts +0 -46
  246. package/packages/core/src/storage/HiveDBStorage.ts +0 -64
  247. package/packages/core/src/storage/SQLiteStorage.ts +0 -414
  248. package/packages/core/src/storage/hiveSeed.ts +0 -308
  249. package/packages/core/src/storage/hiveStorage.test.ts +0 -38
  250. package/packages/core/src/storage/schema.ts +0 -689
  251. package/packages/core/src/storage/storage.test.ts +0 -37
  252. package/packages/core/src/swarm/AgentBus.ts +0 -460
  253. package/packages/core/src/swarm/EventBus.ts +0 -169
  254. package/packages/core/src/swarm/WorkerPool.ts +0 -236
  255. package/packages/core/src/tools/bridge-events.ts +0 -26
  256. package/packages/core/src/tools/canvas/index.ts +0 -375
  257. package/packages/core/src/tools/codebridge/index.ts +0 -342
  258. package/packages/core/src/tools/meeting/index.ts +0 -353
  259. package/packages/core/src/tools/projects/index.ts +0 -37
  260. package/packages/core/src/tools/projects/project-create.ts +0 -94
  261. package/packages/core/src/tools/projects/project-done.ts +0 -66
  262. package/packages/core/src/tools/projects/project-fail.ts +0 -66
  263. package/packages/core/src/tools/projects/project-list.ts +0 -96
  264. package/packages/core/src/tools/projects/project-update.ts +0 -72
  265. package/packages/core/src/tools/projects/task-create.ts +0 -68
  266. package/packages/core/src/tools/projects/task-evaluate.ts +0 -93
  267. package/packages/core/src/tools/projects/task-update.ts +0 -93
  268. package/packages/core/src/tools/voice/index.ts +0 -104
  269. package/packages/core/src/tools/web/api-request.test.ts +0 -170
  270. package/packages/core/src/tools/web/api-request.ts +0 -239
  271. package/test/setup-db.ts +0 -216
  272. /package/packages/core/src/agent/{NativeTools.ts → native-tools.ts} +0 -0
@@ -5,38 +5,151 @@
5
5
  */
6
6
 
7
7
  import type { Tool } from "../types.ts";
8
- import { getDb } from "../../storage/SQLiteStorage.ts";
9
- import { getHiveDB } from "../../storage/HiveDBStorage.ts";
8
+ import { col } from "../../storage/hive.ts";
9
+ import type { ToolDoc, SkillDoc, PlaybookDoc, McpToolDoc, TaskDoc, AgentDoc } from "../../storage/collections.ts";
10
10
  import { logger } from "../../utils/logger.ts";
11
+ import {
12
+ searchCapabilities,
13
+ type CapabilityHit,
14
+ type CapabilityType,
15
+ } from "../../agent/capability-search.ts";
16
+ import { CORE_TOOL_CATALOG } from "../../agent/tool-selector.ts";
17
+ import { saveScratchpadNote } from "../../agent/conversation-store.ts";
11
18
 
12
19
  const log = logger.child("core");
13
20
 
14
- // ─── search_knowledge ────────────────────────────────────────────────────────
21
+ // ─── Bilingual dictionary: Spanish → English ────────────────────────────────
22
+
23
+ const ES_EN_DICT: Record<string, string[]> = {
24
+ // Acciones
25
+ "buscar": ["search", "find", "list", "get", "query"],
26
+ "listar": ["list", "get", "fetch", "retrieve"],
27
+ "crear": ["create", "add", "insert", "new", "make"],
28
+ "actualizar": ["update", "edit", "modify", "change"],
29
+ "eliminar": ["delete", "remove", "destroy"],
30
+ "obtener": ["get", "fetch", "retrieve", "read"],
31
+ "enviar": ["send", "post", "submit", "push"],
32
+ "leer": ["read", "get", "fetch"],
33
+ "escribir": ["write", "create", "save"],
34
+ "modificar": ["update", "modify", "edit", "change"],
35
+ "ejecutar": ["execute", "run", "invoke"],
36
+ "conectar": ["connect", "link"],
37
+ "desconectar": ["disconnect", "remove"],
38
+ "descargar": ["download", "export", "fetch"],
39
+ "subir": ["upload", "import", "create"],
40
+ "analizar": ["analyze", "review", "examine"],
41
+ "generar": ["generate", "create", "produce"],
42
+ "convertir": ["convert", "transform", "translate"],
43
+ "validar": ["validate", "verify", "check"],
44
+ "importar": ["import", "load", "ingest"],
45
+ "exportar": ["export", "download", "extract"],
46
+ "comprimir": ["compress", "zip", "archive"],
47
+ "extraer": ["extract", "get", "retrieve", "parse"],
48
+ "reemplazar": ["replace", "update", "swap"],
49
+ "cargar": ["load", "import", "upload"],
50
+ "guardar": ["save", "store", "create"],
51
+ "consultar": ["query", "search", "get", "list"],
52
+ "registrar": ["register", "create", "log", "record"],
53
+ "programar": ["schedule", "plan", "cron"],
54
+ "notificar": ["notify", "alert", "send"],
55
+ "reiniciar": ["restart", "reset", "reboot"],
56
+ "configurar": ["configure", "setup", "set"],
57
+ "autenticar": ["authenticate", "login", "auth"],
58
+ "publicar": ["publish", "deploy", "release"],
59
+ "desplegar": ["deploy", "publish", "release"],
60
+ "copiar": ["copy", "clone", "duplicate"],
61
+ "mover": ["move", "transfer", "migrate"],
62
+ "comparar": ["compare", "diff", "match"],
63
+ "fusionar": ["merge", "combine", "join"],
64
+ "dividir": ["split", "divide", "partition"],
65
+ "filtrar": ["filter", "search", "query"],
66
+ "ordenar": ["sort", "order", "arrange"],
67
+ "traducir": ["translate", "convert"],
68
+
69
+ // Entidades
70
+ "base": ["base", "database", "db"],
71
+ "bases": ["bases", "databases"],
72
+ "datos": ["data", "records", "rows", "entries"],
73
+ "registro": ["record", "entry", "row", "item"],
74
+ "registros": ["records", "entries", "rows", "items"],
75
+ "tabla": ["table", "schema", "collection"],
76
+ "tablas": ["tables", "schemas"],
77
+ "campo": ["field", "column", "property"],
78
+ "campos": ["fields", "columns", "properties"],
79
+ "usuario": ["user", "account"],
80
+ "usuarios": ["users", "accounts"],
81
+ "proyecto": ["project", "repo", "workspace"],
82
+ "proyectos": ["projects", "repos", "workspaces"],
83
+ "archivo": ["file", "document"],
84
+ "archivos": ["files", "documents"],
85
+ "correo": ["email", "mail", "message"],
86
+ "correos": ["emails", "mails", "messages"],
87
+ "noticia": ["news", "article", "post"],
88
+ "noticias": ["news", "articles", "posts"],
89
+ "contenido": ["content", "data", "text"],
90
+ "tarea": ["task", "job", "issue", "ticket"],
91
+ "tareas": ["tasks", "jobs", "issues", "tickets"],
92
+ "pagina": ["page", "site", "web"],
93
+ "enlace": ["link", "url", "reference"],
94
+ "imagen": ["image", "picture", "photo"],
95
+ "video": ["video", "media"],
96
+ "audio": ["audio", "sound", "media"],
97
+ "categoria": ["category", "tag", "label"],
98
+ "estado": ["status", "state", "condition"],
99
+ "error": ["error", "exception", "fault"],
100
+ "fuente": ["source", "origin", "reference"],
101
+ "esquema": ["schema", "structure", "model"],
102
+ "respuesta": ["response", "reply", "answer"],
103
+ "solicitud": ["request", "query", "call"],
104
+ "repositorio": ["repository", "repo"],
105
+ "seguridad": ["security", "auth", "permission"],
106
+ "permiso": ["permission", "role", "access"],
107
+ "acceso": ["access", "login", "entry"],
108
+ "servidor": ["server", "host", "service"],
109
+ "conexion": ["connection", "link", "integration"],
110
+ "integracion": ["integration", "connector", "plugin"],
111
+ "herramienta": ["tool", "utility", "function"],
112
+ "informacion": ["info", "information", "details"],
113
+ "lista": ["list", "collection", "array"],
114
+ "reporte": ["report", "summary", "analytics"],
115
+ "metrica": ["metric", "stat", "analytics"],
116
+ "contacto": ["contact", "lead", "person"],
117
+ };
118
+
119
+ /**
120
+ * Translate a Spanish query to English equivalents for the bilingual BM25 fallback.
121
+ * Returns an array of English keyword tokens.
122
+ */
123
+ function translateQueryToEnglish(query: string): string {
124
+ const words = query.toLowerCase().replace(/_/g, " ").split(/\s+/).filter(w => w.length > 1);
125
+ const translated: string[] = [];
126
+
127
+ for (const word of words) {
128
+ const equivalents = ES_EN_DICT[word];
129
+ if (equivalents) {
130
+ translated.push(...equivalents);
131
+ }
132
+ }
15
133
 
16
- function buildSearchQuery(query: string): string {
17
- return query
18
- .toLowerCase()
19
- .replace(/[^\p{L}\p{N}\s]/gu, " ")
20
- .split(/\s+/)
21
- .filter(w => w.length > 2)
22
- .slice(0, 8)
23
- .join(" ");
134
+ return [...new Set(translated)].join(" ");
24
135
  }
25
136
 
137
+ // ─── search_knowledge ────────────────────────────────────────────────────────
138
+
26
139
  export const searchKnowledgeTool: Tool = {
27
140
  name: "search_knowledge",
28
- description: "Busca herramientas NATIVAS (tools), MCP (tools externas), habilidades (skills) o reglas del playbook en la base de conocimientos. Usa búsqueda híbrida (BM25 + vector). type='mcp' para herramientas MCP, type='all' para buscar en todo.",
141
+ description: "Busca en TODO el conocimiento de Hive: tools nativas, MCP, skills, agentes de catálogo y playbook.",
29
142
  parameters: {
30
143
  type: "object",
31
144
  properties: {
32
145
  query: {
33
146
  type: "string",
34
- description: "Término de búsqueda (nombre, descripción, categoría).",
147
+ description: "Una palabra clave. Ejemplos: 'email', 'github', 'pdf', 'browser', 'calendar'. Busca en nombres, descripciones y categorías.",
35
148
  },
36
149
  type: {
37
150
  type: "string",
38
- enum: ["all", "tools", "skills", "playbook", "mcp"],
39
- description: "Tipo de conocimiento a buscar",
151
+ enum: ["all", "tools", "skills", "playbook", "mcp", "agents"],
152
+ description: "Opcional. Por defecto 'all' (busca en todo). Usa 'mcp' para filtrar solo herramientas externas, 'tools' para solo nativas.",
40
153
  },
41
154
  limit: {
42
155
  type: "number",
@@ -46,108 +159,166 @@ export const searchKnowledgeTool: Tool = {
46
159
  required: ["query"],
47
160
  },
48
161
  execute: async (params: Record<string, unknown>) => {
49
- const db = await getHiveDB();
50
162
  const query = params.query as string;
51
163
  const type = (params.type as string) ?? "all";
52
164
  const limit = (params.limit as number) ?? 10;
165
+ const MIN_RESULTS_FOR_BILINGUAL = 2;
166
+
167
+ // Map the tool's `type` param onto capability types
168
+ const typeMap: Record<string, CapabilityType[] | undefined> = {
169
+ all: undefined,
170
+ tools: ["tool"],
171
+ skills: ["skill"],
172
+ playbook: ["playbook"],
173
+ mcp: ["mcp"],
174
+ agents: ["agent"],
175
+ };
176
+ const types = typeMap[type] ?? undefined;
53
177
 
54
178
  try {
55
- const searchQuery = buildSearchQuery(query);
56
- if (!searchQuery) {
57
- return { ok: true, query, type, tools: [], skills: [], playbook: [], toolsmcp: [], totalResults: 0 };
179
+ if (!query) {
180
+ log.info(`[search_knowledge] Empty query — returning empty results`)
181
+ return { query, type, tools: [], skills: [], playbook: [], toolsmcp: [], agents: [] }
58
182
  }
183
+ // HiveDB parses raw text leniently (accents, quotes, operators are all
184
+ // safe), so the query goes in as-is — only underscores become spaces so
185
+ // tool ids like "send_email" match their tokens.
186
+ const normalizedQuery = query.replace(/_/g, " ").trim();
59
187
 
60
- const result: any = { query, type, tools: [], skills: [], playbook: [], toolsmcp: [] };
188
+ const result: any = { query, type, tools: [], skills: [], playbook: [], toolsmcp: [], agents: [] };
61
189
 
62
- async function searchByType(docType: string) {
63
- return db.queryHybrid({
64
- text: searchQuery,
65
- k: limit,
66
- filters: [{ field: "type", value: docType }],
67
- boosts: { name: 5.0, body: 3.0, tags: 2.0 },
68
- });
69
- }
190
+ // ─── Hydration from HiveDB collections (index stores only ids + search text) ──
70
191
 
71
- if (type === "all" || type === "tools") {
72
- const hits = await searchByType("tool");
73
- const toolsCol = db.collection<{ name: string; description: string; category: string; enabled: boolean; active: boolean }>("tools");
74
- for (const hit of hits) {
75
- const entry = await toolsCol.get(hit.id);
76
- const doc = entry?.doc;
77
- result.tools.push({
78
- id: hit.id,
79
- name: doc?.name ?? hit.id,
80
- description: doc?.description ?? "",
81
- category: doc?.category ?? "core",
82
- enabled: doc?.enabled ?? true,
83
- active: doc?.active ?? true,
84
- rank: hit.score,
85
- });
192
+ const coreCatalog = new Map(CORE_TOOL_CATALOG.map(t => [t.name, t]));
193
+
194
+ const toolsCol = await col<ToolDoc>("tools");
195
+ const skillsCol = await col<SkillDoc>("skills");
196
+ const playbookCol = await col<PlaybookDoc>("playbook");
197
+ const mcpToolsCol = await col<McpToolDoc>("mcpTools");
198
+ const agentsCol = await col<AgentDoc>("agents");
199
+
200
+ async function hydrateTool(hit: CapabilityHit): Promise<any | null> {
201
+ const entry = await toolsCol.get(hit.rawId);
202
+ if (entry) {
203
+ const row = entry.doc;
204
+ return {
205
+ id: row.id, name: row.name, description: row.description, category: row.category,
206
+ enabled: row.enabled, active: row.active, rank: hit.score,
207
+ };
86
208
  }
209
+ // Core catalog tools may not exist in the tools collection
210
+ const cat = coreCatalog.get(hit.rawId);
211
+ if (!cat) return null;
212
+ return {
213
+ id: cat.name, name: cat.name, description: cat.description, category: cat.category,
214
+ enabled: true, active: true, rank: hit.score,
215
+ };
87
216
  }
88
217
 
89
- if (type === "all" || type === "skills") {
90
- const hits = await searchByType("skill");
91
- const skillsCol = db.collection<{ name: string; description: string; category: string; body: string; tools: string[]; triggers: string[]; active: boolean }>("skills");
92
- for (const hit of hits) {
93
- const entry = await skillsCol.get(hit.id);
94
- const doc = entry?.doc;
95
- result.skills.push({
96
- id: hit.id,
97
- name: doc?.name ?? hit.id,
98
- description: doc?.description ?? "",
99
- category: doc?.category ?? "general",
100
- tools: doc?.tools ?? [],
101
- triggers: doc?.triggers ?? [],
102
- body: doc?.body ? (doc.body.length > 400 ? doc.body.substring(0, 400) + "…" : doc.body) : undefined,
103
- active: doc?.active ?? true,
104
- rank: hit.score,
105
- });
106
- }
218
+ async function hydrateSkill(hit: CapabilityHit): Promise<any | null> {
219
+ const entry = await skillsCol.get(hit.rawId);
220
+ const s = entry?.doc;
221
+ if (!s || !s.active) return null;
222
+ return {
223
+ id: s.id, name: s.name, description: s.description, category: s.category,
224
+ tools: s.tools, triggers: s.triggers,
225
+ preferred_agents: s.preferred_agents ? JSON.parse(s.preferred_agents) : [],
226
+ body: s.body ? (s.body.length > 1500 ? s.body.substring(0, 1500) + "…" : s.body) : undefined,
227
+ active: s.active, rank: hit.score,
228
+ };
229
+ }
230
+
231
+ async function hydratePlaybook(hit: CapabilityHit): Promise<any | null> {
232
+ const entry = await playbookCol.get(hit.rawId);
233
+ const p = entry?.doc;
234
+ if (!p || !p.active) return null;
235
+ return {
236
+ id: p.id, rule: p.rule, category: p.category,
237
+ applicable_to: p.applicable_to ? JSON.parse(p.applicable_to) : null,
238
+ helpful_count: p.helpful_count, harmful_count: p.harmful_count,
239
+ active: p.active, rank: hit.score,
240
+ };
241
+ }
242
+
243
+ async function hydrateMcp(hit: CapabilityHit): Promise<any | null> {
244
+ const entry = await mcpToolsCol.get(hit.rawId);
245
+ const t = entry?.doc;
246
+ if (!t || !t.active) return null;
247
+ return {
248
+ id: t.id, full_name: t.id, server_id: t.server_id, server_name: t.server_name, tool_name: t.tool_name,
249
+ description: t.description, category: t.category,
250
+ active: t.active, rank: hit.score,
251
+ };
107
252
  }
108
253
 
109
- if (type === "all" || type === "playbook") {
110
- const hits = await searchByType("playbook");
111
- const playbookCol = db.collection<{ rule: string; category: string; applicableTo?: string[]; active: boolean }>("playbook");
254
+ async function hydrateAgent(hit: CapabilityHit): Promise<any | null> {
255
+ const entry = await agentsCol.get(hit.rawId);
256
+ const agent = entry?.doc;
257
+ if (!agent || agent.source !== "catalog" || !agent.enabled) return null;
258
+ return {
259
+ id: agent.id,
260
+ name: agent.name,
261
+ description: agent.description,
262
+ default_acceptance: agent.default_acceptance_json ? JSON.parse(agent.default_acceptance_json) : [],
263
+ active: agent.enabled,
264
+ rank: hit.score,
265
+ };
266
+ }
267
+
268
+ const seenIds = new Set<string>();
269
+
270
+ async function mergeHits(hits: CapabilityHit[]): Promise<number> {
271
+ let added = 0;
112
272
  for (const hit of hits) {
113
- const entry = await playbookCol.get(hit.id);
114
- const doc = entry?.doc;
115
- result.playbook.push({
116
- id: hit.id,
117
- rule: doc?.rule ?? "",
118
- category: doc?.category ?? "",
119
- applicable_to: doc?.applicableTo ?? null,
120
- active: doc?.active ?? true,
121
- rank: hit.score,
122
- });
273
+ if (seenIds.has(hit.id)) continue;
274
+ let entry: any = null;
275
+ let bucket: any[] | null = null;
276
+ switch (hit.type) {
277
+ case "tool":
278
+ if (result.tools.length < limit) { entry = await hydrateTool(hit); bucket = result.tools; }
279
+ break;
280
+ case "skill":
281
+ if (result.skills.length < limit) { entry = await hydrateSkill(hit); bucket = result.skills; }
282
+ break;
283
+ case "playbook":
284
+ if (result.playbook.length < limit) { entry = await hydratePlaybook(hit); bucket = result.playbook; }
285
+ break;
286
+ case "mcp":
287
+ if (result.toolsmcp.length < limit) { entry = await hydrateMcp(hit); bucket = result.toolsmcp; }
288
+ break;
289
+ case "agent":
290
+ if (result.agents.length < limit) { entry = await hydrateAgent(hit); bucket = result.agents; }
291
+ break;
292
+ }
293
+ if (entry && bucket) {
294
+ bucket.push(entry);
295
+ seenIds.add(hit.id);
296
+ added++;
297
+ }
123
298
  }
299
+ return added;
124
300
  }
125
301
 
126
- if (type === "all" || type === "mcp") {
127
- const mcpCol = db.collection<{ serverName: string; toolName: string; description: string; category: string; active: boolean }>("mcp_tools");
128
- const entries = await mcpCol.scan();
129
- const q = searchQuery.toLowerCase();
130
- const matches = entries
131
- .map(e => e.doc)
132
- .filter(m => m.active && (
133
- m.toolName.toLowerCase().includes(q) ||
134
- m.description.toLowerCase().includes(q) ||
135
- m.category.toLowerCase().includes(q)
136
- ))
137
- .slice(0, limit);
138
- result.toolsmcp = matches.map(m => ({
139
- id: `${m.serverName}__${m.toolName}`,
140
- full_name: `${m.serverName}__${m.toolName}`,
141
- server_name: m.serverName,
142
- tool_name: m.toolName,
143
- description: m.description,
144
- category: m.category,
145
- active: true,
146
- rank: 0,
147
- }));
302
+ // ─── Pass 1: Search with original query ─────────────────────────
303
+ // `rank` is the raw BM25 score: positive, higher = more relevant.
304
+
305
+ const hits1 = await searchCapabilities(normalizedQuery, { types, k: limit * 4 });
306
+ const totalFirst = await mergeHits(hits1);
307
+
308
+ // ─── Pass 2: Bilingual fallback (ES → EN) ──────────────────────
309
+ // HiveDB stems Spanish but does not translate: "correo" still won't
310
+ // match English-only descriptions ("email") without this dictionary.
311
+
312
+ if (totalFirst < MIN_RESULTS_FOR_BILINGUAL) {
313
+ const englishQuery = translateQueryToEnglish(normalizedQuery);
314
+ if (englishQuery.length > 0) {
315
+ log.info(`[search_knowledge] Bilingual fallback: "${normalizedQuery}" → "${englishQuery}" (first pass: ${totalFirst} results)`);
316
+ const hits2 = await searchCapabilities(englishQuery, { types, k: limit * 4 });
317
+ await mergeHits(hits2);
318
+ }
148
319
  }
149
320
 
150
- result.totalResults = result.tools.length + result.skills.length + result.playbook.length + result.toolsmcp.length;
321
+ result.totalResults = result.tools.length + result.skills.length + result.playbook.length + result.toolsmcp.length + result.agents.length;
151
322
 
152
323
  return { ok: true, ...result };
153
324
  } catch (error) {
@@ -175,7 +346,7 @@ export const notifyTool: Tool = {
175
346
  required: ["message"],
176
347
  },
177
348
  execute: async (params: Record<string, unknown>, config?: any) => {
178
- const { sendToUserChannel } = await import("../../gateway/channel-notify.ts");
349
+ const { sendToUserChannel } = await import("../../gateway/channel-notify");
179
350
  const message = params.message as string;
180
351
  const channel = (config?.configurable?.channel as string) ?? "webchat";
181
352
  const userId = (config?.configurable?.user_id as string) ?? "";
@@ -190,13 +361,6 @@ export const notifyTool: Tool = {
190
361
 
191
362
  // ─── save_note (scratchpad) ──────────────────────────────────────────────────
192
363
 
193
- interface ScratchpadDoc {
194
- threadId: string;
195
- key: string;
196
- value: string;
197
- updatedAt: number;
198
- }
199
-
200
364
  export const saveNoteTool: Tool = {
201
365
  name: "save_note",
202
366
  description: "Save a note to the scratchpad (survives context compression).",
@@ -219,15 +383,12 @@ export const saveNoteTool: Tool = {
219
383
  required: ["key", "value"],
220
384
  },
221
385
  execute: async (params: Record<string, unknown>, config?: any) => {
222
- const db = await getHiveDB();
223
386
  const key = params.key as string;
224
387
  const value = params.value as string;
225
388
  const threadId = (params.thread_id as string) ?? config?.configurable?.thread_id ?? "default";
226
389
 
227
390
  try {
228
- const col = db.collection<ScratchpadDoc>("scratchpad");
229
- await col.put(`${threadId}:${key}`, { threadId, key, value, updatedAt: Date.now() });
230
-
391
+ await saveScratchpadNote(threadId, key, value, "agent");
231
392
  return { ok: true, key, message: "Note saved." };
232
393
  } catch (error) {
233
394
  return {
@@ -262,7 +423,7 @@ export const reportProgressTool: Tool = {
262
423
  required: ["progress", "message"],
263
424
  },
264
425
  execute: async (params: Record<string, unknown>, config?: any) => {
265
- const { sendToUserChannel } = await import("../../gateway/channel-notify.ts");
426
+ const { sendToUserChannel } = await import("../../gateway/channel-notify");
266
427
  const progress = params.progress as number;
267
428
  const message = params.message as string;
268
429
  const taskId = (params.task_id as string) ?? null;
@@ -273,8 +434,16 @@ export const reportProgressTool: Tool = {
273
434
 
274
435
  // Update task progress in DB if task_id provided
275
436
  if (taskId) {
276
- const db = getDb();
277
- db.query(`UPDATE tasks SET progress = ?, updated_at = unixepoch() WHERE id = ?`).run(progress, taskId);
437
+ try {
438
+ const tasksCol = await col<TaskDoc>("tasks");
439
+ const id = /^\d+$/.test(taskId) ? taskId.padStart(15, "0") : taskId;
440
+ const existing = await tasksCol.get(id);
441
+ if (existing) {
442
+ await tasksCol.put(id, { ...existing.doc, progress, updated_at: Date.now() }, { expectedVersion: existing.version });
443
+ }
444
+ } catch {
445
+ // Best-effort — task_id may not correspond to a real task.
446
+ }
278
447
  }
279
448
 
280
449
  // Send real-time update to the user's channel