@theowlops/boombot 0.0.0-stage → 1.1.1

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 (544) hide show
  1. package/README.md +69 -3
  2. package/dist/LICENSE +21 -0
  3. package/dist/bin/boombot.js +16 -0
  4. package/dist/cli/api-key.js +123 -0
  5. package/dist/cli/bin-bun.js +17 -0
  6. package/dist/cli/bin.js +34 -0
  7. package/dist/cli/cli/cli-error.js +61 -0
  8. package/dist/cli/cli/dispatch.js +138 -0
  9. package/dist/cli/cli/help.js +83 -0
  10. package/dist/cli/cli/parser.js +89 -0
  11. package/dist/cli/cli/registry.js +185 -0
  12. package/dist/cli/cli/spec.js +41 -0
  13. package/dist/cli/cli/suggest.js +125 -0
  14. package/dist/cli/cli/version.js +30 -0
  15. package/dist/cli/cli/vocabulary.js +87 -0
  16. package/dist/cli/commands/doctor.js +365 -0
  17. package/dist/cli/commands/gateway.js +290 -0
  18. package/dist/cli/commands/migrate.js +270 -0
  19. package/dist/cli/commands/plugin.js +97 -0
  20. package/dist/cli/commands/setup.js +244 -0
  21. package/dist/cli/config-file.js +133 -0
  22. package/dist/cli/master-key.js +78 -0
  23. package/dist/cli/open-browser.js +59 -0
  24. package/dist/cli/web-assets.js +58 -0
  25. package/dist/gateway/auth.js +46 -0
  26. package/dist/gateway/config-format.js +202 -0
  27. package/dist/gateway/config.js +427 -0
  28. package/dist/gateway/context.js +1 -0
  29. package/dist/gateway/env-file.js +129 -0
  30. package/dist/gateway/events.js +172 -0
  31. package/dist/gateway/guard/tagging.js +505 -0
  32. package/dist/gateway/handlers/index.js +66 -0
  33. package/dist/gateway/handlers/memory.js +54 -0
  34. package/dist/gateway/handlers/providers.js +73 -0
  35. package/dist/gateway/handlers/registry.js +39 -0
  36. package/dist/gateway/handlers/sessions.js +188 -0
  37. package/dist/gateway/handlers/system.js +12 -0
  38. package/dist/gateway/handlers/tasks.js +191 -0
  39. package/dist/gateway/handlers/turn.js +100 -0
  40. package/dist/gateway/index.js +126 -0
  41. package/dist/gateway/main.js +23 -0
  42. package/dist/gateway/server.js +354 -0
  43. package/dist/gateway/services/context-limits.js +75 -0
  44. package/dist/gateway/services/history-normalizer.js +42 -0
  45. package/dist/gateway/services/image-pipeline.js +56 -0
  46. package/dist/gateway/services/key-roulette-client.js +43 -0
  47. package/dist/gateway/services/llm-client.js +593 -0
  48. package/dist/gateway/services/llm-decoder.js +200 -0
  49. package/dist/gateway/services/local-fallback.js +135 -0
  50. package/dist/gateway/services/memory.js +511 -0
  51. package/dist/gateway/services/persistent-memory.js +196 -0
  52. package/dist/gateway/services/providers.js +44 -0
  53. package/dist/gateway/services/tasks.js +237 -0
  54. package/dist/gateway/services/verification.js +124 -0
  55. package/dist/gateway/services/vision-payload.js +48 -0
  56. package/dist/gateway/services.js +257 -0
  57. package/dist/gateway/session-snapshot.js +19 -0
  58. package/dist/gateway/sessions.js +701 -0
  59. package/dist/gateway/static.js +239 -0
  60. package/dist/gateway/turns/clarify-tool.js +57 -0
  61. package/dist/gateway/turns/cronjob-tool.js +96 -0
  62. package/dist/gateway/turns/deferred-tools.js +154 -0
  63. package/dist/gateway/turns/execute-code-tool.js +84 -0
  64. package/dist/gateway/turns/file-tool-defs.js +178 -0
  65. package/dist/gateway/turns/file-tool-ops.js +178 -0
  66. package/dist/gateway/turns/file-tool-scan.js +182 -0
  67. package/dist/gateway/turns/file-tool.js +302 -0
  68. package/dist/gateway/turns/index.js +416 -0
  69. package/dist/gateway/turns/jev-middleware.js +91 -0
  70. package/dist/gateway/turns/local-reply.js +156 -0
  71. package/dist/gateway/turns/mcp-client.js +643 -0
  72. package/dist/gateway/turns/memory-tool.js +171 -0
  73. package/dist/gateway/turns/middleware.js +96 -0
  74. package/dist/gateway/turns/python-core.js +397 -0
  75. package/dist/gateway/turns/routing/index.js +3 -0
  76. package/dist/gateway/turns/routing/intent-classifier.js +60 -0
  77. package/dist/gateway/turns/routing/planner-adapter.js +91 -0
  78. package/dist/gateway/turns/routing/types.js +1 -0
  79. package/dist/gateway/turns/runtime-deps.js +228 -0
  80. package/dist/gateway/turns/self-config-tool.js +277 -0
  81. package/dist/gateway/turns/service-types.js +11 -0
  82. package/dist/gateway/turns/service.js +820 -0
  83. package/dist/gateway/turns/session-adapter.js +158 -0
  84. package/dist/gateway/turns/session-tool.js +49 -0
  85. package/dist/gateway/turns/shell-tool.js +190 -0
  86. package/dist/gateway/turns/skill-tool.js +239 -0
  87. package/dist/gateway/turns/spillover.js +201 -0
  88. package/dist/gateway/turns/subagent-tool.js +140 -0
  89. package/dist/gateway/turns/system-prompt.js +121 -0
  90. package/dist/gateway/turns/tool-schema.js +90 -0
  91. package/dist/gateway/turns/turn-utils.js +58 -0
  92. package/dist/gateway/turns/vision-tool.js +120 -0
  93. package/dist/gateway/types.js +1 -0
  94. package/dist/native/win32-x64/boombot-native-host.exe +0 -0
  95. package/dist/node_modules/@boombot/channels/handlers.d.ts +9 -0
  96. package/dist/node_modules/@boombot/channels/handlers.js +109 -0
  97. package/dist/node_modules/@boombot/channels/index.d.ts +12 -0
  98. package/dist/node_modules/@boombot/channels/index.js +12 -0
  99. package/dist/node_modules/@boombot/channels/package.json +9 -0
  100. package/dist/node_modules/@boombot/channels/service.d.ts +62 -0
  101. package/dist/node_modules/@boombot/channels/service.js +608 -0
  102. package/dist/node_modules/@boombot/channels/tool.d.ts +10 -0
  103. package/dist/node_modules/@boombot/channels/tool.js +46 -0
  104. package/dist/node_modules/@boombot/channels/transports/common/dedup.d.ts +17 -0
  105. package/dist/node_modules/@boombot/channels/transports/common/dedup.js +42 -0
  106. package/dist/node_modules/@boombot/channels/transports/common/handoff.d.ts +19 -0
  107. package/dist/node_modules/@boombot/channels/transports/common/handoff.js +32 -0
  108. package/dist/node_modules/@boombot/channels/transports/common/index.d.ts +3 -0
  109. package/dist/node_modules/@boombot/channels/transports/common/index.js +3 -0
  110. package/dist/node_modules/@boombot/channels/transports/common/types.d.ts +99 -0
  111. package/dist/node_modules/@boombot/channels/transports/common/types.js +54 -0
  112. package/dist/node_modules/@boombot/channels/transports/common.d.ts +2 -0
  113. package/dist/node_modules/@boombot/channels/transports/common.js +2 -0
  114. package/dist/node_modules/@boombot/channels/transports/dedup/index.d.ts +1 -0
  115. package/dist/node_modules/@boombot/channels/transports/dedup/index.js +1 -0
  116. package/dist/node_modules/@boombot/channels/transports/dedup.d.ts +2 -0
  117. package/dist/node_modules/@boombot/channels/transports/dedup.js +2 -0
  118. package/dist/node_modules/@boombot/channels/transports/discord/index.d.ts +1 -0
  119. package/dist/node_modules/@boombot/channels/transports/discord/index.js +1 -0
  120. package/dist/node_modules/@boombot/channels/transports/discord/transport.d.ts +36 -0
  121. package/dist/node_modules/@boombot/channels/transports/discord/transport.js +199 -0
  122. package/dist/node_modules/@boombot/channels/transports/discord.d.ts +2 -0
  123. package/dist/node_modules/@boombot/channels/transports/discord.js +2 -0
  124. package/dist/node_modules/@boombot/channels/transports/handoff.d.ts +2 -0
  125. package/dist/node_modules/@boombot/channels/transports/handoff.js +2 -0
  126. package/dist/node_modules/@boombot/channels/transports/messenger/index.d.ts +1 -0
  127. package/dist/node_modules/@boombot/channels/transports/messenger/index.js +1 -0
  128. package/dist/node_modules/@boombot/channels/transports/messenger/transport.d.ts +34 -0
  129. package/dist/node_modules/@boombot/channels/transports/messenger/transport.js +180 -0
  130. package/dist/node_modules/@boombot/channels/transports/messenger.d.ts +2 -0
  131. package/dist/node_modules/@boombot/channels/transports/messenger.js +2 -0
  132. package/dist/node_modules/@boombot/channels/transports/slack/index.d.ts +1 -0
  133. package/dist/node_modules/@boombot/channels/transports/slack/index.js +1 -0
  134. package/dist/node_modules/@boombot/channels/transports/slack/transport.d.ts +35 -0
  135. package/dist/node_modules/@boombot/channels/transports/slack/transport.js +183 -0
  136. package/dist/node_modules/@boombot/channels/transports/slack.d.ts +2 -0
  137. package/dist/node_modules/@boombot/channels/transports/slack.js +2 -0
  138. package/dist/node_modules/@boombot/channels/transports/streamer/index.d.ts +1 -0
  139. package/dist/node_modules/@boombot/channels/transports/streamer/index.js +1 -0
  140. package/dist/node_modules/@boombot/channels/transports/streamer/streamer.d.ts +31 -0
  141. package/dist/node_modules/@boombot/channels/transports/streamer/streamer.js +141 -0
  142. package/dist/node_modules/@boombot/channels/transports/streamer.d.ts +2 -0
  143. package/dist/node_modules/@boombot/channels/transports/streamer.js +2 -0
  144. package/dist/node_modules/@boombot/channels/transports/telegram/index.d.ts +1 -0
  145. package/dist/node_modules/@boombot/channels/transports/telegram/index.js +1 -0
  146. package/dist/node_modules/@boombot/channels/transports/telegram/transport.d.ts +75 -0
  147. package/dist/node_modules/@boombot/channels/transports/telegram/transport.js +395 -0
  148. package/dist/node_modules/@boombot/channels/transports/telegram.d.ts +2 -0
  149. package/dist/node_modules/@boombot/channels/transports/telegram.js +2 -0
  150. package/dist/node_modules/@boombot/channels/transports/tiktok/index.d.ts +1 -0
  151. package/dist/node_modules/@boombot/channels/transports/tiktok/index.js +1 -0
  152. package/dist/node_modules/@boombot/channels/transports/tiktok/transport.d.ts +27 -0
  153. package/dist/node_modules/@boombot/channels/transports/tiktok/transport.js +97 -0
  154. package/dist/node_modules/@boombot/channels/transports/tiktok.d.ts +2 -0
  155. package/dist/node_modules/@boombot/channels/transports/tiktok.js +2 -0
  156. package/dist/node_modules/@boombot/channels/transports/whatsapp/index.d.ts +1 -0
  157. package/dist/node_modules/@boombot/channels/transports/whatsapp/index.js +1 -0
  158. package/dist/node_modules/@boombot/channels/transports/whatsapp/transport.d.ts +38 -0
  159. package/dist/node_modules/@boombot/channels/transports/whatsapp/transport.js +189 -0
  160. package/dist/node_modules/@boombot/channels/transports/whatsapp.d.ts +2 -0
  161. package/dist/node_modules/@boombot/channels/transports/whatsapp.js +2 -0
  162. package/dist/node_modules/@boombot/channels/transports/zalo/index.d.ts +2 -0
  163. package/dist/node_modules/@boombot/channels/transports/zalo/index.js +2 -0
  164. package/dist/node_modules/@boombot/channels/transports/zalo/oa.d.ts +28 -0
  165. package/dist/node_modules/@boombot/channels/transports/zalo/oa.js +94 -0
  166. package/dist/node_modules/@boombot/channels/transports/zalo/personal.d.ts +106 -0
  167. package/dist/node_modules/@boombot/channels/transports/zalo/personal.js +171 -0
  168. package/dist/node_modules/@boombot/channels/transports/zalo-personal.d.ts +2 -0
  169. package/dist/node_modules/@boombot/channels/transports/zalo-personal.js +2 -0
  170. package/dist/node_modules/@boombot/channels/transports/zalo.d.ts +2 -0
  171. package/dist/node_modules/@boombot/channels/transports/zalo.js +2 -0
  172. package/dist/node_modules/@boombot/core/agent-core/index.d.ts +12 -0
  173. package/dist/node_modules/@boombot/core/agent-core/index.js +12 -0
  174. package/dist/node_modules/@boombot/core/agent-core/middleware.d.ts +60 -0
  175. package/dist/node_modules/@boombot/core/agent-core/middleware.js +152 -0
  176. package/dist/node_modules/@boombot/core/agent-core/routing.d.ts +128 -0
  177. package/dist/node_modules/@boombot/core/agent-core/routing.js +437 -0
  178. package/dist/node_modules/@boombot/core/agent-core/runtime-deps.d.ts +88 -0
  179. package/dist/node_modules/@boombot/core/agent-core/runtime-deps.js +8 -0
  180. package/dist/node_modules/@boombot/core/agent-core/tool-errors.d.ts +44 -0
  181. package/dist/node_modules/@boombot/core/agent-core/tool-errors.js +60 -0
  182. package/dist/node_modules/@boombot/core/agent-core/turn-loop.d.ts +21 -0
  183. package/dist/node_modules/@boombot/core/agent-core/turn-loop.js +561 -0
  184. package/dist/node_modules/@boombot/core/agent-core/types.d.ts +189 -0
  185. package/dist/node_modules/@boombot/core/agent-core/types.js +7 -0
  186. package/dist/node_modules/@boombot/core/compaction/compactor.d.ts +19 -0
  187. package/dist/node_modules/@boombot/core/compaction/compactor.js +127 -0
  188. package/dist/node_modules/@boombot/core/compaction/estimator.d.ts +10 -0
  189. package/dist/node_modules/@boombot/core/compaction/estimator.js +48 -0
  190. package/dist/node_modules/@boombot/core/compaction/index.d.ts +3 -0
  191. package/dist/node_modules/@boombot/core/compaction/index.js +3 -0
  192. package/dist/node_modules/@boombot/core/compaction/types.d.ts +31 -0
  193. package/dist/node_modules/@boombot/core/compaction/types.js +7 -0
  194. package/dist/node_modules/@boombot/core/index.d.ts +9 -0
  195. package/dist/node_modules/@boombot/core/index.js +9 -0
  196. package/dist/node_modules/@boombot/core/jev/index.d.ts +2 -0
  197. package/dist/node_modules/@boombot/core/jev/index.js +2 -0
  198. package/dist/node_modules/@boombot/core/jev/jev.d.ts +30 -0
  199. package/dist/node_modules/@boombot/core/jev/jev.js +164 -0
  200. package/dist/node_modules/@boombot/core/jev/types.d.ts +22 -0
  201. package/dist/node_modules/@boombot/core/jev/types.js +1 -0
  202. package/dist/node_modules/@boombot/core/memory/consolidation/budget.d.ts +63 -0
  203. package/dist/node_modules/@boombot/core/memory/consolidation/budget.js +94 -0
  204. package/dist/node_modules/@boombot/core/memory/consolidation/consolidator.d.ts +152 -0
  205. package/dist/node_modules/@boombot/core/memory/consolidation/consolidator.js +318 -0
  206. package/dist/node_modules/@boombot/core/memory/consolidation/index.d.ts +12 -0
  207. package/dist/node_modules/@boombot/core/memory/consolidation/index.js +12 -0
  208. package/dist/node_modules/@boombot/core/memory/curation.d.ts +86 -0
  209. package/dist/node_modules/@boombot/core/memory/curation.js +120 -0
  210. package/dist/node_modules/@boombot/core/memory/errors.d.ts +12 -0
  211. package/dist/node_modules/@boombot/core/memory/errors.js +20 -0
  212. package/dist/node_modules/@boombot/core/memory/hybrid-search.d.ts +29 -0
  213. package/dist/node_modules/@boombot/core/memory/hybrid-search.js +52 -0
  214. package/dist/node_modules/@boombot/core/memory/index.d.ts +23 -0
  215. package/dist/node_modules/@boombot/core/memory/index.js +23 -0
  216. package/dist/node_modules/@boombot/core/memory/indexer.d.ts +47 -0
  217. package/dist/node_modules/@boombot/core/memory/indexer.js +138 -0
  218. package/dist/node_modules/@boombot/core/memory/lifecycle.d.ts +12 -0
  219. package/dist/node_modules/@boombot/core/memory/lifecycle.js +66 -0
  220. package/dist/node_modules/@boombot/core/memory/provider.d.ts +84 -0
  221. package/dist/node_modules/@boombot/core/memory/provider.js +117 -0
  222. package/dist/node_modules/@boombot/core/memory/recall.d.ts +7 -0
  223. package/dist/node_modules/@boombot/core/memory/recall.js +111 -0
  224. package/dist/node_modules/@boombot/core/memory/scope-resolver.d.ts +27 -0
  225. package/dist/node_modules/@boombot/core/memory/scope-resolver.js +60 -0
  226. package/dist/node_modules/@boombot/core/memory/search.d.ts +37 -0
  227. package/dist/node_modules/@boombot/core/memory/search.js +158 -0
  228. package/dist/node_modules/@boombot/core/memory/store.d.ts +60 -0
  229. package/dist/node_modules/@boombot/core/memory/store.js +289 -0
  230. package/dist/node_modules/@boombot/core/memory/types.d.ts +121 -0
  231. package/dist/node_modules/@boombot/core/memory/types.js +21 -0
  232. package/dist/node_modules/@boombot/core/memory/vector-index.d.ts +34 -0
  233. package/dist/node_modules/@boombot/core/memory/vector-index.js +65 -0
  234. package/dist/node_modules/@boombot/core/package.json +9 -0
  235. package/dist/node_modules/@boombot/core/reflection/classifier.d.ts +13 -0
  236. package/dist/node_modules/@boombot/core/reflection/classifier.js +77 -0
  237. package/dist/node_modules/@boombot/core/reflection/index.d.ts +2 -0
  238. package/dist/node_modules/@boombot/core/reflection/index.js +2 -0
  239. package/dist/node_modules/@boombot/core/reflection/types.d.ts +13 -0
  240. package/dist/node_modules/@boombot/core/reflection/types.js +4 -0
  241. package/dist/node_modules/@boombot/core/research/config.d.ts +89 -0
  242. package/dist/node_modules/@boombot/core/research/config.js +206 -0
  243. package/dist/node_modules/@boombot/core/research/crawl.d.ts +36 -0
  244. package/dist/node_modules/@boombot/core/research/crawl.js +179 -0
  245. package/dist/node_modules/@boombot/core/research/factory.d.ts +26 -0
  246. package/dist/node_modules/@boombot/core/research/factory.js +46 -0
  247. package/dist/node_modules/@boombot/core/research/http.d.ts +87 -0
  248. package/dist/node_modules/@boombot/core/research/http.js +250 -0
  249. package/dist/node_modules/@boombot/core/research/index.d.ts +17 -0
  250. package/dist/node_modules/@boombot/core/research/index.js +10 -0
  251. package/dist/node_modules/@boombot/core/research/orchestrator.d.ts +113 -0
  252. package/dist/node_modules/@boombot/core/research/orchestrator.js +252 -0
  253. package/dist/node_modules/@boombot/core/research/parse/docx.d.ts +24 -0
  254. package/dist/node_modules/@boombot/core/research/parse/docx.js +183 -0
  255. package/dist/node_modules/@boombot/core/research/parse/guards.d.ts +89 -0
  256. package/dist/node_modules/@boombot/core/research/parse/guards.js +171 -0
  257. package/dist/node_modules/@boombot/core/research/parse/index.d.ts +68 -0
  258. package/dist/node_modules/@boombot/core/research/parse/index.js +219 -0
  259. package/dist/node_modules/@boombot/core/research/parse/pdf.d.ts +38 -0
  260. package/dist/node_modules/@boombot/core/research/parse/pdf.js +567 -0
  261. package/dist/node_modules/@boombot/core/research/providers/arxiv.d.ts +9 -0
  262. package/dist/node_modules/@boombot/core/research/providers/arxiv.js +72 -0
  263. package/dist/node_modules/@boombot/core/research/providers/brave.d.ts +11 -0
  264. package/dist/node_modules/@boombot/core/research/providers/brave.js +36 -0
  265. package/dist/node_modules/@boombot/core/research/providers/duckduckgo.d.ts +9 -0
  266. package/dist/node_modules/@boombot/core/research/providers/duckduckgo.js +78 -0
  267. package/dist/node_modules/@boombot/core/research/providers/exa.d.ts +11 -0
  268. package/dist/node_modules/@boombot/core/research/providers/exa.js +34 -0
  269. package/dist/node_modules/@boombot/core/research/providers/firecrawl.d.ts +16 -0
  270. package/dist/node_modules/@boombot/core/research/providers/firecrawl.js +47 -0
  271. package/dist/node_modules/@boombot/core/research/providers/index.d.ts +17 -0
  272. package/dist/node_modules/@boombot/core/research/providers/index.js +11 -0
  273. package/dist/node_modules/@boombot/core/research/providers/jina.d.ts +13 -0
  274. package/dist/node_modules/@boombot/core/research/providers/jina.js +114 -0
  275. package/dist/node_modules/@boombot/core/research/providers/openalex.d.ts +14 -0
  276. package/dist/node_modules/@boombot/core/research/providers/openalex.js +66 -0
  277. package/dist/node_modules/@boombot/core/research/providers/semantic-scholar.d.ts +9 -0
  278. package/dist/node_modules/@boombot/core/research/providers/semantic-scholar.js +56 -0
  279. package/dist/node_modules/@boombot/core/research/providers/tavily.d.ts +11 -0
  280. package/dist/node_modules/@boombot/core/research/providers/tavily.js +35 -0
  281. package/dist/node_modules/@boombot/core/research/providers/wikipedia.d.ts +12 -0
  282. package/dist/node_modules/@boombot/core/research/providers/wikipedia.js +47 -0
  283. package/dist/node_modules/@boombot/core/research/tools.d.ts +27 -0
  284. package/dist/node_modules/@boombot/core/research/tools.js +251 -0
  285. package/dist/node_modules/@boombot/core/research/types.d.ts +133 -0
  286. package/dist/node_modules/@boombot/core/research/types.js +8 -0
  287. package/dist/node_modules/@boombot/core/research/wiring.d.ts +25 -0
  288. package/dist/node_modules/@boombot/core/research/wiring.js +51 -0
  289. package/dist/node_modules/@boombot/core/scheduler/cron.d.ts +34 -0
  290. package/dist/node_modules/@boombot/core/scheduler/cron.js +147 -0
  291. package/dist/node_modules/@boombot/core/scheduler/evaluator.d.ts +42 -0
  292. package/dist/node_modules/@boombot/core/scheduler/evaluator.js +148 -0
  293. package/dist/node_modules/@boombot/core/scheduler/index.d.ts +15 -0
  294. package/dist/node_modules/@boombot/core/scheduler/index.js +15 -0
  295. package/dist/node_modules/@boombot/core/scheduler/registry.d.ts +81 -0
  296. package/dist/node_modules/@boombot/core/scheduler/registry.js +263 -0
  297. package/dist/node_modules/@boombot/core/scheduler/runner.d.ts +59 -0
  298. package/dist/node_modules/@boombot/core/scheduler/runner.js +257 -0
  299. package/dist/node_modules/@boombot/core/scheduler/store.d.ts +150 -0
  300. package/dist/node_modules/@boombot/core/scheduler/store.js +526 -0
  301. package/dist/node_modules/@boombot/core/scheduler/timezone.d.ts +35 -0
  302. package/dist/node_modules/@boombot/core/scheduler/timezone.js +96 -0
  303. package/dist/node_modules/@boombot/core/scheduler/types.d.ts +157 -0
  304. package/dist/node_modules/@boombot/core/scheduler/types.js +89 -0
  305. package/dist/node_modules/@boombot/core/task-runner/index.d.ts +7 -0
  306. package/dist/node_modules/@boombot/core/task-runner/index.js +5 -0
  307. package/dist/node_modules/@boombot/core/task-runner/planner.d.ts +37 -0
  308. package/dist/node_modules/@boombot/core/task-runner/planner.js +154 -0
  309. package/dist/node_modules/@boombot/core/task-runner/runner.d.ts +8 -0
  310. package/dist/node_modules/@boombot/core/task-runner/runner.js +564 -0
  311. package/dist/node_modules/@boombot/core/task-runner/store.d.ts +28 -0
  312. package/dist/node_modules/@boombot/core/task-runner/store.js +126 -0
  313. package/dist/node_modules/@boombot/core/task-runner/types.d.ts +138 -0
  314. package/dist/node_modules/@boombot/core/task-runner/types.js +11 -0
  315. package/dist/node_modules/@boombot/core/workflow/dag.d.ts +16 -0
  316. package/dist/node_modules/@boombot/core/workflow/dag.js +109 -0
  317. package/dist/node_modules/@boombot/core/workflow/engine.d.ts +34 -0
  318. package/dist/node_modules/@boombot/core/workflow/engine.js +304 -0
  319. package/dist/node_modules/@boombot/core/workflow/index.d.ts +3 -0
  320. package/dist/node_modules/@boombot/core/workflow/index.js +3 -0
  321. package/dist/node_modules/@boombot/core/workflow/types.d.ts +98 -0
  322. package/dist/node_modules/@boombot/core/workflow/types.js +21 -0
  323. package/dist/node_modules/@boombot/cronjobs/handlers.d.ts +11 -0
  324. package/dist/node_modules/@boombot/cronjobs/handlers.js +174 -0
  325. package/dist/node_modules/@boombot/cronjobs/index.d.ts +2 -0
  326. package/dist/node_modules/@boombot/cronjobs/index.js +2 -0
  327. package/dist/node_modules/@boombot/cronjobs/package.json +9 -0
  328. package/dist/node_modules/@boombot/cronjobs/service.d.ts +53 -0
  329. package/dist/node_modules/@boombot/cronjobs/service.js +200 -0
  330. package/dist/node_modules/@boombot/plugins/index.d.ts +2 -0
  331. package/dist/node_modules/@boombot/plugins/index.js +2 -0
  332. package/dist/node_modules/@boombot/plugins/installer.d.ts +45 -0
  333. package/dist/node_modules/@boombot/plugins/installer.js +487 -0
  334. package/dist/node_modules/@boombot/plugins/manager.d.ts +23 -0
  335. package/dist/node_modules/@boombot/plugins/manager.js +243 -0
  336. package/dist/node_modules/@boombot/plugins/package.json +9 -0
  337. package/dist/node_modules/@boombot/protocol/gateway-protocol/commands-channels.d.ts +125 -0
  338. package/dist/node_modules/@boombot/protocol/gateway-protocol/commands-channels.js +76 -0
  339. package/dist/node_modules/@boombot/protocol/gateway-protocol/commands-plugins.d.ts +220 -0
  340. package/dist/node_modules/@boombot/protocol/gateway-protocol/commands-plugins.js +60 -0
  341. package/dist/node_modules/@boombot/protocol/gateway-protocol/commands-scheduler.d.ts +33 -0
  342. package/dist/node_modules/@boombot/protocol/gateway-protocol/commands-scheduler.js +25 -0
  343. package/dist/node_modules/@boombot/protocol/gateway-protocol/commands.d.ts +4349 -0
  344. package/dist/node_modules/@boombot/protocol/gateway-protocol/commands.js +563 -0
  345. package/dist/node_modules/@boombot/protocol/gateway-protocol/envelope.d.ts +32 -0
  346. package/dist/node_modules/@boombot/protocol/gateway-protocol/envelope.js +61 -0
  347. package/dist/node_modules/@boombot/protocol/gateway-protocol/errors.d.ts +13 -0
  348. package/dist/node_modules/@boombot/protocol/gateway-protocol/errors.js +16 -0
  349. package/dist/node_modules/@boombot/protocol/gateway-protocol/events.d.ts +567 -0
  350. package/dist/node_modules/@boombot/protocol/gateway-protocol/events.js +395 -0
  351. package/dist/node_modules/@boombot/protocol/gateway-protocol/index.d.ts +20 -0
  352. package/dist/node_modules/@boombot/protocol/gateway-protocol/index.js +13 -0
  353. package/dist/node_modules/@boombot/protocol/gateway-protocol/types.d.ts +91 -0
  354. package/dist/node_modules/@boombot/protocol/gateway-protocol/types.js +7 -0
  355. package/dist/node_modules/@boombot/protocol/index.d.ts +4 -0
  356. package/dist/node_modules/@boombot/protocol/index.js +3 -0
  357. package/dist/node_modules/@boombot/protocol/package.json +9 -0
  358. package/dist/node_modules/@boombot/protocol/plugin-sdk/channel.d.ts +41 -0
  359. package/dist/node_modules/@boombot/protocol/plugin-sdk/channel.js +17 -0
  360. package/dist/node_modules/@boombot/protocol/plugin-sdk/index.d.ts +10 -0
  361. package/dist/node_modules/@boombot/protocol/plugin-sdk/index.js +10 -0
  362. package/dist/node_modules/@boombot/protocol/plugin-sdk/manifest.d.ts +58 -0
  363. package/dist/node_modules/@boombot/protocol/plugin-sdk/manifest.js +116 -0
  364. package/dist/node_modules/@boombot/protocol/plugin-sdk/plugin.d.ts +25 -0
  365. package/dist/node_modules/@boombot/protocol/plugin-sdk/plugin.js +1 -0
  366. package/dist/node_modules/@boombot/protocol/providers/cipher.d.ts +7 -0
  367. package/dist/node_modules/@boombot/protocol/providers/cipher.js +52 -0
  368. package/dist/node_modules/@boombot/protocol/providers/index.d.ts +19 -0
  369. package/dist/node_modules/@boombot/protocol/providers/index.js +19 -0
  370. package/dist/node_modules/@boombot/protocol/providers/key-roulette.d.ts +79 -0
  371. package/dist/node_modules/@boombot/protocol/providers/key-roulette.js +81 -0
  372. package/dist/node_modules/@boombot/protocol/providers/probe.d.ts +29 -0
  373. package/dist/node_modules/@boombot/protocol/providers/probe.js +96 -0
  374. package/dist/node_modules/@boombot/protocol/providers/profiles/anthropic.d.ts +11 -0
  375. package/dist/node_modules/@boombot/protocol/providers/profiles/anthropic.js +11 -0
  376. package/dist/node_modules/@boombot/protocol/providers/profiles/custom.d.ts +22 -0
  377. package/dist/node_modules/@boombot/protocol/providers/profiles/custom.js +222 -0
  378. package/dist/node_modules/@boombot/protocol/providers/profiles/deepseek.d.ts +7 -0
  379. package/dist/node_modules/@boombot/protocol/providers/profiles/deepseek.js +9 -0
  380. package/dist/node_modules/@boombot/protocol/providers/profiles/google.d.ts +10 -0
  381. package/dist/node_modules/@boombot/protocol/providers/profiles/google.js +10 -0
  382. package/dist/node_modules/@boombot/protocol/providers/profiles/index.d.ts +31 -0
  383. package/dist/node_modules/@boombot/protocol/providers/profiles/index.js +56 -0
  384. package/dist/node_modules/@boombot/protocol/providers/profiles/local.d.ts +10 -0
  385. package/dist/node_modules/@boombot/protocol/providers/profiles/local.js +11 -0
  386. package/dist/node_modules/@boombot/protocol/providers/profiles/mistral.d.ts +7 -0
  387. package/dist/node_modules/@boombot/protocol/providers/profiles/mistral.js +9 -0
  388. package/dist/node_modules/@boombot/protocol/providers/profiles/openai-compatible.d.ts +10 -0
  389. package/dist/node_modules/@boombot/protocol/providers/profiles/openai-compatible.js +10 -0
  390. package/dist/node_modules/@boombot/protocol/providers/profiles/openai.d.ts +7 -0
  391. package/dist/node_modules/@boombot/protocol/providers/profiles/openai.js +11 -0
  392. package/dist/node_modules/@boombot/protocol/providers/profiles/types.d.ts +58 -0
  393. package/dist/node_modules/@boombot/protocol/providers/profiles/types.js +1 -0
  394. package/dist/node_modules/@boombot/protocol/providers/profiles/xai.d.ts +7 -0
  395. package/dist/node_modules/@boombot/protocol/providers/profiles/xai.js +10 -0
  396. package/dist/node_modules/@boombot/protocol/providers/request-profile.d.ts +102 -0
  397. package/dist/node_modules/@boombot/protocol/providers/request-profile.js +118 -0
  398. package/dist/node_modules/@boombot/protocol/providers/service.d.ts +2 -0
  399. package/dist/node_modules/@boombot/protocol/providers/service.js +418 -0
  400. package/dist/node_modules/@boombot/protocol/providers/types.d.ts +141 -0
  401. package/dist/node_modules/@boombot/protocol/providers/types.js +16 -0
  402. package/dist/node_modules/@boombot/sandbox/fs-path.d.ts +13 -0
  403. package/dist/node_modules/@boombot/sandbox/fs-path.js +79 -0
  404. package/dist/node_modules/@boombot/sandbox/index.d.ts +13 -0
  405. package/dist/node_modules/@boombot/sandbox/index.js +13 -0
  406. package/dist/node_modules/@boombot/sandbox/native.d.ts +39 -0
  407. package/dist/node_modules/@boombot/sandbox/native.js +224 -0
  408. package/dist/node_modules/@boombot/sandbox/package.json +9 -0
  409. package/dist/node_modules/@boombot/sandbox/sandbox.d.ts +92 -0
  410. package/dist/node_modules/@boombot/sandbox/sandbox.js +229 -0
  411. package/dist/node_modules/@boombot/security/harness-guard/boundary.d.ts +22 -0
  412. package/dist/node_modules/@boombot/security/harness-guard/boundary.js +105 -0
  413. package/dist/node_modules/@boombot/security/harness-guard/gates.d.ts +90 -0
  414. package/dist/node_modules/@boombot/security/harness-guard/gates.js +791 -0
  415. package/dist/node_modules/@boombot/security/harness-guard/index.d.ts +23 -0
  416. package/dist/node_modules/@boombot/security/harness-guard/index.js +23 -0
  417. package/dist/node_modules/@boombot/security/harness-guard/policy.d.ts +20 -0
  418. package/dist/node_modules/@boombot/security/harness-guard/policy.js +70 -0
  419. package/dist/node_modules/@boombot/security/harness-guard/sanitizer.d.ts +53 -0
  420. package/dist/node_modules/@boombot/security/harness-guard/sanitizer.js +145 -0
  421. package/dist/node_modules/@boombot/security/harness-guard/types.d.ts +71 -0
  422. package/dist/node_modules/@boombot/security/harness-guard/types.js +10 -0
  423. package/dist/node_modules/@boombot/security/harness-guard/verifier.d.ts +59 -0
  424. package/dist/node_modules/@boombot/security/harness-guard/verifier.js +169 -0
  425. package/dist/node_modules/@boombot/security/index.d.ts +5 -0
  426. package/dist/node_modules/@boombot/security/index.js +9 -0
  427. package/dist/node_modules/@boombot/security/package.json +9 -0
  428. package/dist/node_modules/@boombot/security/policy/approval.d.ts +117 -0
  429. package/dist/node_modules/@boombot/security/policy/approval.js +223 -0
  430. package/dist/node_modules/@boombot/security/reasoning-guard/claim-extractor.d.ts +10 -0
  431. package/dist/node_modules/@boombot/security/reasoning-guard/claim-extractor.js +124 -0
  432. package/dist/node_modules/@boombot/security/reasoning-guard/evidence-ledger.d.ts +25 -0
  433. package/dist/node_modules/@boombot/security/reasoning-guard/evidence-ledger.js +70 -0
  434. package/dist/node_modules/@boombot/security/reasoning-guard/gate.d.ts +38 -0
  435. package/dist/node_modules/@boombot/security/reasoning-guard/gate.js +61 -0
  436. package/dist/node_modules/@boombot/security/reasoning-guard/grounding-check.d.ts +12 -0
  437. package/dist/node_modules/@boombot/security/reasoning-guard/grounding-check.js +234 -0
  438. package/dist/node_modules/@boombot/security/reasoning-guard/index.d.ts +17 -0
  439. package/dist/node_modules/@boombot/security/reasoning-guard/index.js +13 -0
  440. package/dist/node_modules/@boombot/security/reasoning-guard/policy.d.ts +15 -0
  441. package/dist/node_modules/@boombot/security/reasoning-guard/policy.js +39 -0
  442. package/dist/node_modules/@boombot/security/reasoning-guard/types.d.ts +46 -0
  443. package/dist/node_modules/@boombot/security/reasoning-guard/types.js +7 -0
  444. package/dist/node_modules/@boombot/security/security/approval.d.ts +63 -0
  445. package/dist/node_modules/@boombot/security/security/approval.js +140 -0
  446. package/dist/node_modules/@boombot/security/security/audit.d.ts +39 -0
  447. package/dist/node_modules/@boombot/security/security/audit.js +70 -0
  448. package/dist/node_modules/@boombot/security/security/index.d.ts +12 -0
  449. package/dist/node_modules/@boombot/security/security/index.js +12 -0
  450. package/dist/node_modules/@boombot/security/security/trust.d.ts +79 -0
  451. package/dist/node_modules/@boombot/security/security/trust.js +87 -0
  452. package/dist/package.json +5 -0
  453. package/dist/proto/agent_core.proto +56 -0
  454. package/dist/python/agent-core-python/pyproject.toml +40 -0
  455. package/dist/python/agent-core-python/src/boombot_agent/__init__.py +5 -0
  456. package/dist/python/agent-core-python/src/boombot_agent/generated/__init__.py +0 -0
  457. package/dist/python/agent-core-python/src/boombot_agent/generated/agent_core_pb2.py +54 -0
  458. package/dist/python/agent-core-python/src/boombot_agent/generated/agent_core_pb2_grpc.py +140 -0
  459. package/dist/python/agent-core-python/src/boombot_agent/rpc.py +265 -0
  460. package/dist/python/agent-core-python/src/boombot_agent/turn.py +577 -0
  461. package/dist/python/agent-core-python/src/boombot_ml/__init__.py +12 -0
  462. package/dist/python/agent-core-python/src/boombot_ml/embeddings.py +58 -0
  463. package/dist/python/agent-core-python/src/boombot_ml/training.py +156 -0
  464. package/dist/python/agent-core-python/uv.lock +2856 -0
  465. package/dist/web/assets/ChatView-BZrSD-64.js +262 -0
  466. package/dist/web/assets/ChatView-Cahbjez6.css +1 -0
  467. package/dist/web/assets/KaTeX_AMS-Regular-BQhdFMY1.woff2 +0 -0
  468. package/dist/web/assets/KaTeX_AMS-Regular-DMm9YOAa.woff +0 -0
  469. package/dist/web/assets/KaTeX_AMS-Regular-DRggAlZN.ttf +0 -0
  470. package/dist/web/assets/KaTeX_Caligraphic-Bold-ATXxdsX0.ttf +0 -0
  471. package/dist/web/assets/KaTeX_Caligraphic-Bold-BEiXGLvX.woff +0 -0
  472. package/dist/web/assets/KaTeX_Caligraphic-Bold-Dq_IR9rO.woff2 +0 -0
  473. package/dist/web/assets/KaTeX_Caligraphic-Regular-CTRA-rTL.woff +0 -0
  474. package/dist/web/assets/KaTeX_Caligraphic-Regular-Di6jR-x-.woff2 +0 -0
  475. package/dist/web/assets/KaTeX_Caligraphic-Regular-wX97UBjC.ttf +0 -0
  476. package/dist/web/assets/KaTeX_Fraktur-Bold-BdnERNNW.ttf +0 -0
  477. package/dist/web/assets/KaTeX_Fraktur-Bold-BsDP51OF.woff +0 -0
  478. package/dist/web/assets/KaTeX_Fraktur-Bold-CL6g_b3V.woff2 +0 -0
  479. package/dist/web/assets/KaTeX_Fraktur-Regular-CB_wures.ttf +0 -0
  480. package/dist/web/assets/KaTeX_Fraktur-Regular-CTYiF6lA.woff2 +0 -0
  481. package/dist/web/assets/KaTeX_Fraktur-Regular-Dxdc4cR9.woff +0 -0
  482. package/dist/web/assets/KaTeX_Main-Bold-Cx986IdX.woff2 +0 -0
  483. package/dist/web/assets/KaTeX_Main-Bold-Jm3AIy58.woff +0 -0
  484. package/dist/web/assets/KaTeX_Main-Bold-waoOVXN0.ttf +0 -0
  485. package/dist/web/assets/KaTeX_Main-BoldItalic-DxDJ3AOS.woff2 +0 -0
  486. package/dist/web/assets/KaTeX_Main-BoldItalic-DzxPMmG6.ttf +0 -0
  487. package/dist/web/assets/KaTeX_Main-BoldItalic-SpSLRI95.woff +0 -0
  488. package/dist/web/assets/KaTeX_Main-Italic-3WenGoN9.ttf +0 -0
  489. package/dist/web/assets/KaTeX_Main-Italic-BMLOBm91.woff +0 -0
  490. package/dist/web/assets/KaTeX_Main-Italic-NWA7e6Wa.woff2 +0 -0
  491. package/dist/web/assets/KaTeX_Main-Regular-B22Nviop.woff2 +0 -0
  492. package/dist/web/assets/KaTeX_Main-Regular-Dr94JaBh.woff +0 -0
  493. package/dist/web/assets/KaTeX_Main-Regular-ypZvNtVU.ttf +0 -0
  494. package/dist/web/assets/KaTeX_Math-BoldItalic-B3XSjfu4.ttf +0 -0
  495. package/dist/web/assets/KaTeX_Math-BoldItalic-CZnvNsCZ.woff2 +0 -0
  496. package/dist/web/assets/KaTeX_Math-BoldItalic-iY-2wyZ7.woff +0 -0
  497. package/dist/web/assets/KaTeX_Math-Italic-DA0__PXp.woff +0 -0
  498. package/dist/web/assets/KaTeX_Math-Italic-flOr_0UB.ttf +0 -0
  499. package/dist/web/assets/KaTeX_Math-Italic-t53AETM-.woff2 +0 -0
  500. package/dist/web/assets/KaTeX_SansSerif-Bold-CFMepnvq.ttf +0 -0
  501. package/dist/web/assets/KaTeX_SansSerif-Bold-D1sUS0GD.woff2 +0 -0
  502. package/dist/web/assets/KaTeX_SansSerif-Bold-DbIhKOiC.woff +0 -0
  503. package/dist/web/assets/KaTeX_SansSerif-Italic-C3H0VqGB.woff2 +0 -0
  504. package/dist/web/assets/KaTeX_SansSerif-Italic-DN2j7dab.woff +0 -0
  505. package/dist/web/assets/KaTeX_SansSerif-Italic-YYjJ1zSn.ttf +0 -0
  506. package/dist/web/assets/KaTeX_SansSerif-Regular-BNo7hRIc.ttf +0 -0
  507. package/dist/web/assets/KaTeX_SansSerif-Regular-CS6fqUqJ.woff +0 -0
  508. package/dist/web/assets/KaTeX_SansSerif-Regular-DDBCnlJ7.woff2 +0 -0
  509. package/dist/web/assets/KaTeX_Script-Regular-C5JkGWo-.ttf +0 -0
  510. package/dist/web/assets/KaTeX_Script-Regular-D3wIWfF6.woff2 +0 -0
  511. package/dist/web/assets/KaTeX_Script-Regular-D5yQViql.woff +0 -0
  512. package/dist/web/assets/KaTeX_Size1-Regular-C195tn64.woff +0 -0
  513. package/dist/web/assets/KaTeX_Size1-Regular-Dbsnue_I.ttf +0 -0
  514. package/dist/web/assets/KaTeX_Size1-Regular-mCD8mA8B.woff2 +0 -0
  515. package/dist/web/assets/KaTeX_Size2-Regular-B7gKUWhC.ttf +0 -0
  516. package/dist/web/assets/KaTeX_Size2-Regular-Dy4dx90m.woff2 +0 -0
  517. package/dist/web/assets/KaTeX_Size2-Regular-oD1tc_U0.woff +0 -0
  518. package/dist/web/assets/KaTeX_Size3-Regular-CTq5MqoE.woff +0 -0
  519. package/dist/web/assets/KaTeX_Size3-Regular-DgpXs0kz.ttf +0 -0
  520. package/dist/web/assets/KaTeX_Size4-Regular-BF-4gkZK.woff +0 -0
  521. package/dist/web/assets/KaTeX_Size4-Regular-DWFBv043.ttf +0 -0
  522. package/dist/web/assets/KaTeX_Size4-Regular-Dl5lxZxV.woff2 +0 -0
  523. package/dist/web/assets/KaTeX_Typewriter-Regular-C0xS9mPB.woff +0 -0
  524. package/dist/web/assets/KaTeX_Typewriter-Regular-CO6r4hn1.woff2 +0 -0
  525. package/dist/web/assets/KaTeX_Typewriter-Regular-D3Ib7_Hf.ttf +0 -0
  526. package/dist/web/assets/MemoryView-BJbXqqs7.css +1 -0
  527. package/dist/web/assets/MemoryView-BfMq_6CD.js +1 -0
  528. package/dist/web/assets/SchedulesView-B22QmPR-.js +1 -0
  529. package/dist/web/assets/SchedulesView-C6XK7A8a.css +1 -0
  530. package/dist/web/assets/SessionsView-C1dqdhxI.css +1 -0
  531. package/dist/web/assets/SessionsView-DS0-aH2a.js +1 -0
  532. package/dist/web/assets/TasksView-Dtasg4hd.css +1 -0
  533. package/dist/web/assets/TasksView-ey0FLsW8.js +2 -0
  534. package/dist/web/assets/Textarea-DN3Zybl1.js +1 -0
  535. package/dist/web/assets/Tooltip-Bn2cqFPz.css +1 -0
  536. package/dist/web/assets/Tooltip-MzV2Gqnc.js +1 -0
  537. package/dist/web/assets/browser-Bnt73-Ub.js +8 -0
  538. package/dist/web/assets/index-BL8bi7Yt.css +1 -0
  539. package/dist/web/assets/index-CuPR73Tn.js +73 -0
  540. package/dist/web/favicon.svg +4 -0
  541. package/dist/web/index.html +26 -0
  542. package/dist/web/logo.jpg +0 -0
  543. package/dist/web/logo.png +0 -0
  544. package/package.json +51 -4
@@ -0,0 +1,121 @@
1
+ /**
2
+ * @boombot/core — public types.
3
+ *
4
+ * Every record names an
5
+ * explicit scope, and every query names authorized scopes. Retrieval applies
6
+ * authorization before ranking; revoked/deleted records never surface.
7
+ *
8
+ * Scope kinds used here:
9
+ * - `principal` — private to one authenticated principal (≈ spec `user`).
10
+ * - `session` — visible inside one session only.
11
+ * - `global` — shared knowledge visible to every principal.
12
+ */
13
+ /** Scope a memory record belongs to. */
14
+ export type MemoryScopeKind = 'principal' | 'session' | 'global' | 'conversation' | 'group';
15
+ export interface MemoryScope {
16
+ kind: MemoryScopeKind;
17
+ /** Principal id / session id / the literal id of the shared scope. */
18
+ id: string;
19
+ }
20
+ /** Where a record came from — provenance is preserved, never inferred. */
21
+ export interface MemoryProvenance {
22
+ source: 'user' | 'system' | 'tool' | 'model';
23
+ /** Human/machine reference, e.g. a turn id or tool call id. */
24
+ reference: string;
25
+ /** Principal (or system component) that proposed the write. */
26
+ actorId: string;
27
+ /** ISO-8601 timestamp of the write proposal. */
28
+ at: string;
29
+ }
30
+ /** A durable memory record. Recalled content is untrusted context. */
31
+ export interface MemoryRecord {
32
+ /** Stable id, caller-provided (e.g. uuid). */
33
+ id: string;
34
+ scope: MemoryScope;
35
+ /** Normalized content that gets indexed by FTS5. */
36
+ text: string;
37
+ provenance: MemoryProvenance;
38
+ /** ISO-8601 creation timestamp. */
39
+ createdAt: string;
40
+ /** Set when revoked (tombstoned). Tombstoned records stay for audit. */
41
+ tombstonedAt?: string;
42
+ }
43
+ /** What the host resolved for the caller before any query runs. */
44
+ export interface MemoryAuthorization {
45
+ principalId: string;
46
+ /** Scopes the caller may read. The store never widens this set. */
47
+ readableScopes: readonly MemoryScope[];
48
+ }
49
+ export type MatchMode = 'any' | 'all';
50
+ export interface SearchOptions {
51
+ /** Raw user query — never passed to FTS directly, always sanitized. */
52
+ query: string;
53
+ /** Authorized scopes to search. Must be non-empty. */
54
+ scopes: readonly MemoryScope[];
55
+ /** Max hits. Clamped to [1, MAX_SEARCH_LIMIT]. Default 20. */
56
+ limit?: number;
57
+ /** 'any' (OR, default) or 'all' (AND) term combination. */
58
+ match?: MatchMode;
59
+ /** Highlight markers for snippets. Defaults are angle brackets, NOT html. */
60
+ highlightStart?: string;
61
+ highlightEnd?: string;
62
+ }
63
+ export interface SearchHit {
64
+ record: MemoryRecord;
65
+ /**
66
+ * Raw FTS5 bm25() rank. Lower (more negative) = more relevant.
67
+ * Exposed for debugging/diagnostics only — never shown to end users.
68
+ */
69
+ score: number;
70
+ /** Excerpt with highlight markers around matched terms. */
71
+ snippet: string;
72
+ }
73
+ export interface RecallOptions {
74
+ authorization: MemoryAuthorization;
75
+ /** Raw user query; omit for latest-first scoped listing. */
76
+ query?: string;
77
+ match?: MatchMode;
78
+ /** Max records in the snapshot. Default 10. */
79
+ maxResults?: number;
80
+ /** Max chars per hit excerpt. Default 500. */
81
+ maxCharsPerHit?: number;
82
+ /** Max total chars across the snapshot. Default 4000. */
83
+ maxTotalChars?: number;
84
+ }
85
+ export interface MemorySnapshot {
86
+ evaluatedAt: string;
87
+ hits: readonly SearchHit[];
88
+ /** True when results were cut by maxResults / maxTotalChars. */
89
+ truncated: boolean;
90
+ totalChars: number;
91
+ }
92
+ export interface RevokeInput {
93
+ id: string;
94
+ scope: MemoryScope;
95
+ actorId: string;
96
+ reason: string;
97
+ }
98
+ export interface ForgetInput {
99
+ id: string;
100
+ scope: MemoryScope;
101
+ actorId: string;
102
+ reason: string;
103
+ }
104
+ /** Append-only audit entry. Never carries record content. */
105
+ export interface MemoryAuditEntry {
106
+ auditId: string;
107
+ memoryId: string;
108
+ action: 'create' | 'revoke' | 'forget' | 'reindex';
109
+ actorId: string;
110
+ at: string;
111
+ detail: string;
112
+ }
113
+ /** The single shared scope visible to every principal. */
114
+ export declare const GLOBAL_SCOPE: MemoryScope;
115
+ /** Resource bounds — DoS protection at the memory boundary. */
116
+ export declare const MAX_TEXT_BYTES: number;
117
+ export declare const MAX_QUERY_CHARS = 2000;
118
+ export declare const MAX_QUERY_TERMS = 32;
119
+ export declare const MAX_SEARCH_LIMIT = 200;
120
+ export declare const MAX_SCOPE_ID_CHARS = 256;
121
+ export declare const MAX_SNIPPET_TOKENS = 32;
@@ -0,0 +1,21 @@
1
+ /**
2
+ * @boombot/core — public types.
3
+ *
4
+ * Every record names an
5
+ * explicit scope, and every query names authorized scopes. Retrieval applies
6
+ * authorization before ranking; revoked/deleted records never surface.
7
+ *
8
+ * Scope kinds used here:
9
+ * - `principal` — private to one authenticated principal (≈ spec `user`).
10
+ * - `session` — visible inside one session only.
11
+ * - `global` — shared knowledge visible to every principal.
12
+ */
13
+ /** The single shared scope visible to every principal. */
14
+ export const GLOBAL_SCOPE = Object.freeze({ kind: 'global', id: 'global' });
15
+ /** Resource bounds — DoS protection at the memory boundary. */
16
+ export const MAX_TEXT_BYTES = 64 * 1024; // 64 KiB per record
17
+ export const MAX_QUERY_CHARS = 2000;
18
+ export const MAX_QUERY_TERMS = 32;
19
+ export const MAX_SEARCH_LIMIT = 200;
20
+ export const MAX_SCOPE_ID_CHARS = 256;
21
+ export const MAX_SNIPPET_TOKENS = 32;
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Vector Index and Cosine Similarity.
3
+ *
4
+ * Provides in-memory / persistent float vector storage and fast cosine similarity
5
+ * ranking for semantic memory recall.
6
+ */
7
+ export interface VectorRecord {
8
+ readonly id: string;
9
+ readonly scopeId: string;
10
+ readonly vector: Float32Array;
11
+ readonly metadata?: Record<string, unknown>;
12
+ }
13
+ export interface VectorSearchResult {
14
+ readonly id: string;
15
+ readonly similarity: number;
16
+ readonly metadata?: Record<string, unknown>;
17
+ }
18
+ /**
19
+ * Computes cosine similarity between two normalized or unnormalized float vectors.
20
+ * Returns value in range [-1, 1], where 1 is identical direction.
21
+ */
22
+ export declare function cosineSimilarity(a: Float32Array, b: Float32Array): number;
23
+ export declare class InMemoryVectorIndex {
24
+ private readonly records;
25
+ upsert(record: VectorRecord): void;
26
+ delete(id: string): boolean;
27
+ get(id: string): VectorRecord | undefined;
28
+ size(): number;
29
+ search(queryVector: Float32Array, options?: {
30
+ topK?: number;
31
+ minSimilarity?: number;
32
+ allowedScopeIds?: readonly string[];
33
+ }): VectorSearchResult[];
34
+ }
@@ -0,0 +1,65 @@
1
+ /**
2
+ * Vector Index and Cosine Similarity.
3
+ *
4
+ * Provides in-memory / persistent float vector storage and fast cosine similarity
5
+ * ranking for semantic memory recall.
6
+ */
7
+ /**
8
+ * Computes cosine similarity between two normalized or unnormalized float vectors.
9
+ * Returns value in range [-1, 1], where 1 is identical direction.
10
+ */
11
+ export function cosineSimilarity(a, b) {
12
+ if (a.length !== b.length || a.length === 0)
13
+ return 0;
14
+ let dotProduct = 0;
15
+ let normA = 0;
16
+ let normB = 0;
17
+ for (let i = 0; i < a.length; i++) {
18
+ const valA = a[i];
19
+ const valB = b[i];
20
+ dotProduct += valA * valB;
21
+ normA += valA * valA;
22
+ normB += valB * valB;
23
+ }
24
+ if (normA === 0 || normB === 0)
25
+ return 0;
26
+ return dotProduct / (Math.sqrt(normA) * Math.sqrt(normB));
27
+ }
28
+ export class InMemoryVectorIndex {
29
+ records = new Map();
30
+ upsert(record) {
31
+ this.records.set(record.id, record);
32
+ }
33
+ delete(id) {
34
+ return this.records.delete(id);
35
+ }
36
+ get(id) {
37
+ return this.records.get(id);
38
+ }
39
+ size() {
40
+ return this.records.size;
41
+ }
42
+ search(queryVector, options = {}) {
43
+ const topK = Math.max(1, options.topK ?? 10);
44
+ const minSim = options.minSimilarity ?? 0.0;
45
+ const allowedScopes = options.allowedScopeIds
46
+ ? new Set(options.allowedScopeIds)
47
+ : undefined;
48
+ const scored = [];
49
+ for (const record of this.records.values()) {
50
+ if (allowedScopes && !allowedScopes.has(record.scopeId)) {
51
+ continue;
52
+ }
53
+ const sim = cosineSimilarity(queryVector, record.vector);
54
+ if (sim >= minSim) {
55
+ scored.push({
56
+ id: record.id,
57
+ similarity: sim,
58
+ metadata: record.metadata,
59
+ });
60
+ }
61
+ }
62
+ scored.sort((a, b) => b.similarity - a.similarity);
63
+ return scored.slice(0, topK);
64
+ }
65
+ }
@@ -0,0 +1,9 @@
1
+ {
2
+ "name": "@boombot/core",
3
+ "version": "2.0.0",
4
+ "type": "module",
5
+ "main": "./index.js",
6
+ "exports": {
7
+ ".": "./index.js"
8
+ }
9
+ }
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Reflection Classifier and Self-Healing Guidance Generator.
3
+ *
4
+ * Intercepts tool execution failures and enriches the tool output with
5
+ * structured, actionable hints to prevent the model from repeating the same error.
6
+ */
7
+ import type { ToolCall, ToolResult } from '../agent-core/types.js';
8
+ import type { ReflectionRemedy, SelfHealingResult } from './types.js';
9
+ export declare function classifyToolError(_call: ToolCall, errorMessage: string): ReflectionRemedy;
10
+ /**
11
+ * Enriches a failed tool result with self-healing feedback.
12
+ */
13
+ export declare function enrichWithSelfHealing(call: ToolCall, result: ToolResult): SelfHealingResult;
@@ -0,0 +1,77 @@
1
+ /**
2
+ * Reflection Classifier and Self-Healing Guidance Generator.
3
+ *
4
+ * Intercepts tool execution failures and enriches the tool output with
5
+ * structured, actionable hints to prevent the model from repeating the same error.
6
+ */
7
+ export function classifyToolError(_call, errorMessage) {
8
+ const lower = errorMessage.toLowerCase();
9
+ let category = 'UNKNOWN';
10
+ let actionableHint = 'Review tool parameters and environment prerequisites before retrying.';
11
+ if (lower.includes('enoent') ||
12
+ lower.includes('no such file') ||
13
+ lower.includes('not found') ||
14
+ lower.includes('file does not exist')) {
15
+ category = 'FILE_NOT_FOUND';
16
+ actionableHint =
17
+ 'The requested path does not exist. Use file.glob or file.grep to discover the actual file location before re-attempting.';
18
+ }
19
+ else if (lower.includes('eacces') ||
20
+ lower.includes('eperm') ||
21
+ lower.includes('permission denied') ||
22
+ lower.includes('access is denied')) {
23
+ category = 'PERMISSION_DENIED';
24
+ actionableHint =
25
+ 'The path or process is locked or restricted. Check write permissions or choose a writable scratch directory ($TMPDIR).';
26
+ }
27
+ else if (lower.includes('syntax') ||
28
+ lower.includes('invalid argument') ||
29
+ lower.includes('missing required') ||
30
+ lower.includes('validation error') ||
31
+ lower.includes('pattern')) {
32
+ category = 'INVALID_PARAMETERS';
33
+ actionableHint =
34
+ 'Parameter validation failed. Inspect the tool definition schema and ensure parameter names/types/regex patterns match strictly.';
35
+ }
36
+ else if (lower.includes('exit code') ||
37
+ lower.includes('command failed') ||
38
+ lower.includes('non-zero exit')) {
39
+ category = 'COMMAND_FAILED';
40
+ actionableHint =
41
+ 'The shell command exited with an error. Read stderr carefully, verify installed binaries, and fix syntax before re-running.';
42
+ }
43
+ else if (lower.includes('timeout') ||
44
+ lower.includes('timed out') ||
45
+ lower.includes('econnrefused') ||
46
+ lower.includes('etimedout')) {
47
+ category = 'NETWORK_TIMEOUT';
48
+ actionableHint =
49
+ 'Network or endpoint timeout. Verify the target service is running, host/port are correct, or increase timeout.';
50
+ }
51
+ return {
52
+ category,
53
+ originalError: errorMessage,
54
+ actionableHint,
55
+ };
56
+ }
57
+ /**
58
+ * Enriches a failed tool result with self-healing feedback.
59
+ */
60
+ export function enrichWithSelfHealing(call, result) {
61
+ if (!result.error) {
62
+ return result;
63
+ }
64
+ const remedy = classifyToolError(call, result.output);
65
+ const enrichedOutput = [
66
+ result.output,
67
+ '',
68
+ `[SELF-HEALING GUIDANCE: ${remedy.category}]`,
69
+ `Reason: ${remedy.originalError.slice(0, 300)}`,
70
+ `Suggested Correction: ${remedy.actionableHint}`,
71
+ ].join('\n');
72
+ return {
73
+ ...result,
74
+ output: enrichedOutput,
75
+ remedy,
76
+ };
77
+ }
@@ -0,0 +1,2 @@
1
+ export * from './types.js';
2
+ export * from './classifier.js';
@@ -0,0 +1,2 @@
1
+ export * from './types.js';
2
+ export * from './classifier.js';
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Tool Self-Healing and Reflection Types.
3
+ */
4
+ import type { ToolResult } from '../agent-core/types.js';
5
+ export type ToolErrorCategory = 'FILE_NOT_FOUND' | 'PERMISSION_DENIED' | 'COMMAND_FAILED' | 'INVALID_PARAMETERS' | 'NETWORK_TIMEOUT' | 'UNKNOWN';
6
+ export interface ReflectionRemedy {
7
+ readonly category: ToolErrorCategory;
8
+ readonly originalError: string;
9
+ readonly actionableHint: string;
10
+ }
11
+ export interface SelfHealingResult extends ToolResult {
12
+ readonly remedy?: ReflectionRemedy;
13
+ }
@@ -0,0 +1,4 @@
1
+ /**
2
+ * Tool Self-Healing and Reflection Types.
3
+ */
4
+ export {};
@@ -0,0 +1,89 @@
1
+ /**
2
+ * Configuration loading and provider-registry helpers.
3
+ *
4
+ * Design note for the provider/orchestrator executors:
5
+ * `resolveSearchProviders` and `resolveExtractProvider` take fully-built
6
+ * provider *instances* — they only sort, filter and select. This keeps this
7
+ * skeleton free of any construction logic (and of the free providers, which
8
+ * do not exist yet). The composition root (executor 4 / gateway wiring) owns
9
+ * construction and passes instances in; tests pass stubs.
10
+ */
11
+ import type { ExtractProvider, ResearchConfig, ResearchProvider, SearchResult } from './types.js';
12
+ /**
13
+ * Engines the general `research.search` fan-out calls by default. Deliberately
14
+ * just the two general-purpose ones: the scholarly engines are the slowest to
15
+ * answer (they dominated the tens-of-seconds tool rounds measured in
16
+ * production) and a general query rarely needs them. They stay reachable
17
+ * through `research.academic`, which searches the full free pool.
18
+ */
19
+ export declare const DEFAULT_SEARCH_ENGINES: readonly string[];
20
+ /**
21
+ * Read API keys from the environment. Values are trimmed; empty strings
22
+ * become `undefined`. Keys are kept in memory only — never logged.
23
+ */
24
+ export declare function loadResearchConfig(env?: NodeJS.ProcessEnv): ResearchConfig;
25
+ /**
26
+ * Build the effective search chain.
27
+ *
28
+ * Order: every paid provider that has a key (tavily → exa → brave), then the
29
+ * free engines named by `config.engines` — by default
30
+ * `[wikipedia, duckduckgo]`, not the whole pool. Paid instances without a
31
+ * configured key are dropped. Unknown ids sort after the known ones, stable
32
+ * within themselves — additive, never a hard failure.
33
+ *
34
+ * The scholarly engines are deliberately absent unless `engines` asks for
35
+ * them: `research.academic` serves them from the same pool
36
+ * (`resolveAcademicProviders`), so narrowing the fan-out never takes a tool
37
+ * away, it only stops an ordinary search paying for slow engines.
38
+ *
39
+ * @param all.paid — constructed paid search instances (may include ones with no key)
40
+ * @param all.free — constructed free search instances
41
+ */
42
+ export declare function resolveSearchProviders(config: ResearchConfig, all: {
43
+ readonly paid: readonly ResearchProvider[];
44
+ readonly free: readonly ResearchProvider[];
45
+ }): ResearchProvider[];
46
+ /**
47
+ * The scholarly engines, for `research.academic`.
48
+ *
49
+ * Sourced from the raw free pool rather than from the resolved search chain,
50
+ * because the default chain omits them to keep the general fan-out fast.
51
+ * Being too slow to include by default is not a reason to be unavailable
52
+ * when a caller asks for them by name.
53
+ */
54
+ export declare function resolveAcademicProviders(all: {
55
+ readonly free: readonly ResearchProvider[];
56
+ }): ResearchProvider[];
57
+ /**
58
+ * Pick the extraction backend: firecrawl when its key is configured (and an
59
+ * instance is provided), otherwise jina-reader. Jina is the free default.
60
+ */
61
+ export declare function resolveExtractProvider(config: ResearchConfig, candidates: {
62
+ readonly firecrawl?: ExtractProvider;
63
+ readonly jina: ExtractProvider;
64
+ }): ExtractProvider;
65
+ /**
66
+ * Normalize a URL for dedupe: lowercase host, drop fragment, strip a single
67
+ * trailing slash from the path (query strings are significant and kept).
68
+ * Returns `undefined` when the URL cannot be parsed.
69
+ */
70
+ export declare function normalizeUrl(raw: string): string | undefined;
71
+ /**
72
+ * Remove duplicate results by normalized URL, keeping the first occurrence
73
+ * and the original relative order. Unparseable URLs are kept as-is
74
+ * (never silently dropped).
75
+ */
76
+ export declare function dedupeByUrl(results: readonly SearchResult[]): SearchResult[];
77
+ /** True when at least one paid key is configured. */
78
+ export declare function isConfigured(config: ResearchConfig): boolean;
79
+ /**
80
+ * Deterministic start-up summary of the effective provider chain, derived
81
+ * from config alone (no network, no provider instances — the same rules as
82
+ * `resolveSearchProviders` / `resolveExtractProvider` but pure). The
83
+ * gateway logs it at boot so the operator sees which backends will serve
84
+ * research calls. Paid providers are suffixed `*`; keys are NEVER included.
85
+ */
86
+ export declare function describeResearchConfig(config: ResearchConfig): {
87
+ readonly search: readonly string[];
88
+ readonly extract: string;
89
+ };
@@ -0,0 +1,206 @@
1
+ /**
2
+ * Configuration loading and provider-registry helpers.
3
+ *
4
+ * Design note for the provider/orchestrator executors:
5
+ * `resolveSearchProviders` and `resolveExtractProvider` take fully-built
6
+ * provider *instances* — they only sort, filter and select. This keeps this
7
+ * skeleton free of any construction logic (and of the free providers, which
8
+ * do not exist yet). The composition root (executor 4 / gateway wiring) owns
9
+ * construction and passes instances in; tests pass stubs.
10
+ */
11
+ /** Paid search providers in fallback priority order: tavily > exa > brave. */
12
+ const PAID_SEARCH_ORDER = ['tavily', 'exa', 'brave'];
13
+ /**
14
+ * Every free engine the factory can build, in presentation order. This is
15
+ * the POOL, not the default fan-out — see `DEFAULT_SEARCH_ENGINES`.
16
+ */
17
+ const FREE_SEARCH_ORDER = [
18
+ 'wikipedia',
19
+ 'duckduckgo',
20
+ 'arxiv',
21
+ 'openalex',
22
+ 'semanticScholar',
23
+ ];
24
+ /**
25
+ * Engines the general `research.search` fan-out calls by default. Deliberately
26
+ * just the two general-purpose ones: the scholarly engines are the slowest to
27
+ * answer (they dominated the tens-of-seconds tool rounds measured in
28
+ * production) and a general query rarely needs them. They stay reachable
29
+ * through `research.academic`, which searches the full free pool.
30
+ */
31
+ export const DEFAULT_SEARCH_ENGINES = [
32
+ 'wikipedia',
33
+ 'duckduckgo',
34
+ ];
35
+ /** Scholarly engines `research.academic` selects out of the free pool. */
36
+ const ACADEMIC_SEARCH_IDS = [
37
+ 'arxiv',
38
+ 'openalex',
39
+ 'semanticScholar',
40
+ ];
41
+ /**
42
+ * Read API keys from the environment. Values are trimmed; empty strings
43
+ * become `undefined`. Keys are kept in memory only — never logged.
44
+ */
45
+ export function loadResearchConfig(env = process.env) {
46
+ const pick = (name) => {
47
+ const raw = env[name];
48
+ if (raw === undefined)
49
+ return undefined;
50
+ const trimmed = raw.trim();
51
+ return trimmed === '' ? undefined : trimmed;
52
+ };
53
+ const engines = pick('BOOMBOT_RESEARCH_ENGINES');
54
+ return {
55
+ tavilyApiKey: pick('TAVILY_API_KEY'),
56
+ exaApiKey: pick('EXA_API_KEY'),
57
+ braveApiKey: pick('BRAVE_API_KEY'),
58
+ firecrawlApiKey: pick('FIRECRAWL_API_KEY'),
59
+ defaultMode: 'auto',
60
+ // Comma-separated engine ids. Absent = the built-in default set; an id
61
+ // the factory cannot build simply matches no provider. Read as a list
62
+ // rather than validated against a whitelist so a new engine needs no
63
+ // change here.
64
+ ...(engines === undefined
65
+ ? {}
66
+ : {
67
+ engines: engines
68
+ .split(',')
69
+ .map((id) => id.trim())
70
+ .filter((id) => id !== ''),
71
+ }),
72
+ };
73
+ }
74
+ function hasKey(config, paidId) {
75
+ switch (paidId) {
76
+ case 'tavily':
77
+ return config.tavilyApiKey !== undefined;
78
+ case 'exa':
79
+ return config.exaApiKey !== undefined;
80
+ case 'brave':
81
+ return config.braveApiKey !== undefined;
82
+ default:
83
+ return false;
84
+ }
85
+ }
86
+ function orderById(providers, order) {
87
+ const rank = new Map();
88
+ order.forEach((id, i) => rank.set(id, i));
89
+ return [...providers].sort((a, b) => {
90
+ const ra = rank.get(a.id) ?? Number.MAX_SAFE_INTEGER;
91
+ const rb = rank.get(b.id) ?? Number.MAX_SAFE_INTEGER;
92
+ return ra - rb;
93
+ });
94
+ }
95
+ /**
96
+ * Build the effective search chain.
97
+ *
98
+ * Order: every paid provider that has a key (tavily → exa → brave), then the
99
+ * free engines named by `config.engines` — by default
100
+ * `[wikipedia, duckduckgo]`, not the whole pool. Paid instances without a
101
+ * configured key are dropped. Unknown ids sort after the known ones, stable
102
+ * within themselves — additive, never a hard failure.
103
+ *
104
+ * The scholarly engines are deliberately absent unless `engines` asks for
105
+ * them: `research.academic` serves them from the same pool
106
+ * (`resolveAcademicProviders`), so narrowing the fan-out never takes a tool
107
+ * away, it only stops an ordinary search paying for slow engines.
108
+ *
109
+ * @param all.paid — constructed paid search instances (may include ones with no key)
110
+ * @param all.free — constructed free search instances
111
+ */
112
+ export function resolveSearchProviders(config, all) {
113
+ const paid = orderById(all.paid, PAID_SEARCH_ORDER).filter((p) => hasKey(config, p.id));
114
+ const engines = config.engines ?? DEFAULT_SEARCH_ENGINES;
115
+ const free = orderById(all.free, FREE_SEARCH_ORDER).filter((p) => engines.includes(p.id));
116
+ return [...paid, ...free];
117
+ }
118
+ /**
119
+ * The scholarly engines, for `research.academic`.
120
+ *
121
+ * Sourced from the raw free pool rather than from the resolved search chain,
122
+ * because the default chain omits them to keep the general fan-out fast.
123
+ * Being too slow to include by default is not a reason to be unavailable
124
+ * when a caller asks for them by name.
125
+ */
126
+ export function resolveAcademicProviders(all) {
127
+ return orderById(all.free, FREE_SEARCH_ORDER).filter((p) => ACADEMIC_SEARCH_IDS.includes(p.id));
128
+ }
129
+ /**
130
+ * Pick the extraction backend: firecrawl when its key is configured (and an
131
+ * instance is provided), otherwise jina-reader. Jina is the free default.
132
+ */
133
+ export function resolveExtractProvider(config, candidates) {
134
+ if (config.firecrawlApiKey !== undefined && candidates.firecrawl !== undefined) {
135
+ return candidates.firecrawl;
136
+ }
137
+ return candidates.jina;
138
+ }
139
+ /**
140
+ * Normalize a URL for dedupe: lowercase host, drop fragment, strip a single
141
+ * trailing slash from the path (query strings are significant and kept).
142
+ * Returns `undefined` when the URL cannot be parsed.
143
+ */
144
+ export function normalizeUrl(raw) {
145
+ try {
146
+ const u = new URL(raw);
147
+ u.host = u.host.toLowerCase();
148
+ u.hash = '';
149
+ const path = u.pathname;
150
+ if (path.length > 1 && path.endsWith('/')) {
151
+ u.pathname = path.slice(0, -1);
152
+ }
153
+ return u.toString();
154
+ }
155
+ catch {
156
+ return undefined;
157
+ }
158
+ }
159
+ /**
160
+ * Remove duplicate results by normalized URL, keeping the first occurrence
161
+ * and the original relative order. Unparseable URLs are kept as-is
162
+ * (never silently dropped).
163
+ */
164
+ export function dedupeByUrl(results) {
165
+ const seen = new Set();
166
+ const out = [];
167
+ for (const r of results) {
168
+ const key = normalizeUrl(r.url);
169
+ if (key === undefined || !seen.has(key)) {
170
+ if (key !== undefined)
171
+ seen.add(key);
172
+ out.push(r);
173
+ }
174
+ }
175
+ return out;
176
+ }
177
+ /** True when at least one paid key is configured. */
178
+ export function isConfigured(config) {
179
+ return (config.tavilyApiKey !== undefined ||
180
+ config.exaApiKey !== undefined ||
181
+ config.braveApiKey !== undefined ||
182
+ config.firecrawlApiKey !== undefined);
183
+ }
184
+ /**
185
+ * Deterministic start-up summary of the effective provider chain, derived
186
+ * from config alone (no network, no provider instances — the same rules as
187
+ * `resolveSearchProviders` / `resolveExtractProvider` but pure). The
188
+ * gateway logs it at boot so the operator sees which backends will serve
189
+ * research calls. Paid providers are suffixed `*`; keys are NEVER included.
190
+ */
191
+ export function describeResearchConfig(config) {
192
+ const search = [];
193
+ if (config.tavilyApiKey !== undefined)
194
+ search.push('tavily*');
195
+ if (config.exaApiKey !== undefined)
196
+ search.push('exa*');
197
+ if (config.braveApiKey !== undefined)
198
+ search.push('brave*');
199
+ // The fan-out as it will actually run, so the boot log answers "why did
200
+ // that search only call two engines?" without reading this file.
201
+ search.push(...(config.engines ?? DEFAULT_SEARCH_ENGINES));
202
+ return {
203
+ search,
204
+ extract: config.firecrawlApiKey !== undefined ? 'firecrawl*' : 'jina',
205
+ };
206
+ }