@desplega.ai/agent-swarm 1.158.0 → 1.159.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (272) hide show
  1. package/dist/{acp-adapter-xaq4n6pc.js → acp-adapter-qhch0n2v.js} +1 -1
  2. package/dist/{actions-p9hz5yat.js → actions-dtsh1mfb.js} +33 -29
  3. package/dist/{anthropic-messages-51pz26qe.js → anthropic-messages-f2h06k64.js} +8 -3
  4. package/dist/{app-g26wdcz6.js → app-y1b9srva.js} +10 -9
  5. package/dist/{assistant-wydfqkb3.js → assistant-31hwy5xj.js} +34 -30
  6. package/dist/{azure-openai-responses-8gksqtmz.js → azure-openai-responses-0k1mfax5.js} +12 -13
  7. package/dist/{boot-reembed-se8zmdcp.js → boot-reembed-48d2qpkt.js} +11 -11
  8. package/dist/{boot-reembed-g5ckg9yb.js → boot-reembed-w0bryhkr.js} +12 -12
  9. package/dist/{boot-scrub-logs-wfxqan61.js → boot-scrub-logs-t65wbrn7.js} +9 -8
  10. package/dist/{boot-seeds-s3q01xj3.js → boot-seeds-h7c32hvm.js} +12 -11
  11. package/dist/{claude-adapter-tv2x4f36.js → claude-adapter-1t6611ne.js} +26 -21
  12. package/dist/{claude-managed-adapter-41b2s7fd.js → claude-managed-adapter-werp659j.js} +4 -2
  13. package/dist/{claude-managed-setup-60g8aazx.js → claude-managed-setup-y6rdgbc1.js} +11 -2
  14. package/dist/claude-sdk-session-zhkyk8yw.js +29319 -0
  15. package/dist/{cli-vj6h9kc2.js → cli-0m7wct0d.js} +59 -1
  16. package/dist/{cli-wscdvcqz.js → cli-0n2e4x49.js} +1 -1
  17. package/dist/cli-0xqde53b.js +176 -0
  18. package/dist/{cli-xberxa1r.js → cli-10ym38qc.js} +2 -2
  19. package/dist/{cli-5b6b62tz.js → cli-13hw4z91.js} +1 -1
  20. package/dist/{cli-rqz8qbw7.js → cli-20035trh.js} +50 -18
  21. package/dist/{cli-k0g1sjzm.js → cli-31nkw3g3.js} +3 -3
  22. package/dist/cli-3gvrr8vj.js +1422 -0
  23. package/dist/{cli-c07r9a2m.js → cli-48527fpw.js} +9 -8
  24. package/dist/{cli-24k806sc.js → cli-4aj25szq.js} +2 -2
  25. package/dist/{cli-7gtvvpbh.js → cli-4tvgz99m.js} +7 -7
  26. package/dist/cli-503ya656.js +455 -0
  27. package/dist/{cli-cw9zck8j.js → cli-5f2hq128.js} +8 -4
  28. package/dist/{cli-s8eet254.js → cli-68bmme5p.js} +11078 -27833
  29. package/dist/{cli-ftfvggzx.js → cli-79aq9cgb.js} +794 -563
  30. package/dist/cli-7cxw8b60.js +14910 -0
  31. package/dist/cli-7kyk9jr3.js +22 -0
  32. package/dist/cli-7zttzetj.js +324 -0
  33. package/dist/{cli-y95wp3tg.js → cli-96qd5psa.js} +1 -1
  34. package/dist/{cli-g8djp6qe.js → cli-9yg65c1j.js} +22 -0
  35. package/dist/{cli-3gmcwfyx.js → cli-ardpzhjm.js} +5 -5
  36. package/dist/{cli-7s3syk22.js → cli-b6thtzac.js} +5 -5
  37. package/dist/{cli-00w2c66p.js → cli-bgv70kym.js} +13 -2
  38. package/dist/{cli-j55n64b6.js → cli-bv0a38v9.js} +163 -44
  39. package/dist/cli-ca2w7zv7.js +115 -0
  40. package/dist/cli-cpvsaqsw.js +333 -0
  41. package/dist/cli-cygyqj3b.js +754 -0
  42. package/dist/{cli-x24pshtq.js → cli-dvjpkkjd.js} +6 -6
  43. package/dist/{cli-5d10vd2m.js → cli-e0ndxhtk.js} +4 -4
  44. package/dist/{cli-4198qc9v.js → cli-e4xnc0qp.js} +15 -3
  45. package/dist/{cli-rjehvrts.js → cli-eg7cdg68.js} +8 -8
  46. package/dist/cli-ejpygnqz.js +3815 -0
  47. package/dist/{cli-fgqxwrpv.js → cli-fjtp3463.js} +1631 -127
  48. package/dist/{cli-zt1227k1.js → cli-fkqhbg8g.js} +5 -3
  49. package/dist/{cli-47m6dkd3.js → cli-g9df2m37.js} +409 -168
  50. package/dist/cli-gzyh0j0g.js +8455 -0
  51. package/dist/cli-hgqfttfc.js +183 -0
  52. package/dist/cli-hj65wsts.js +17755 -0
  53. package/dist/cli-j9z8mfx3.js +476 -0
  54. package/dist/{cli-aehm1rbq.js → cli-kc3dp84d.js} +1135 -61
  55. package/dist/{cli-h38x0qhg.js → cli-kdnehe0t.js} +4 -3
  56. package/dist/{cli-20cj37vt.js → cli-m4excttz.js} +136 -2216
  57. package/dist/{cli-8qmme6vd.js → cli-mg24hkt4.js} +2 -2
  58. package/dist/{cli-xhaeg2nc.js → cli-mzkqpxee.js} +1 -1
  59. package/dist/{cli-q67y4wzm.js → cli-phsaj4xq.js} +24 -2
  60. package/dist/{cli-pw9rj5t9.js → cli-pqetb83f.js} +1 -176
  61. package/dist/{cli-rj19hc34.js → cli-qjxy52w7.js} +1 -1
  62. package/dist/{cli-53sz8gkz.js → cli-qv4jv8bx.js} +1 -1
  63. package/dist/cli-qvnnx4ct.js +1051 -0
  64. package/dist/cli-rb9m6rpe.js +4980 -0
  65. package/dist/{cli-tt9k8r35.js → cli-rfezr056.js} +476 -909
  66. package/dist/{cli-ggm92wcn.js → cli-rgjprct3.js} +1 -0
  67. package/dist/{cli-9httdpyq.js → cli-rrqmqr1s.js} +1 -1
  68. package/dist/cli-rykfmgwg.js +102 -0
  69. package/dist/{cli-eetrvv91.js → cli-t3p77qk1.js} +1 -1
  70. package/dist/{cli-68w09sjw.js → cli-vn0qv9cj.js} +25 -88
  71. package/dist/{cli-987hg0aa.js → cli-vwbbaecp.js} +2 -2
  72. package/dist/cli-wd9hz40d.js +69 -0
  73. package/dist/{cli-j57qkrpq.js → cli-wgjx0q33.js} +13 -13
  74. package/dist/cli-xgpf00sk.js +2149 -0
  75. package/dist/{cli-mcnhgnn1.js → cli-ykk5jaax.js} +184 -26
  76. package/dist/{cli-aky8tctm.js → cli-z9x0sh1t.js} +3 -3
  77. package/dist/{cli-1hkrch3k.js → cli-zw65mab6.js} +5 -5
  78. package/dist/cli.js +38 -29
  79. package/dist/cloudflare-workers-ai-system-one-1sg586qv.js +46 -0
  80. package/dist/{codex-adapter-cnm8wk11.js → codex-adapter-jqfqqa21.js} +21 -14
  81. package/dist/{codex-hook-9hptmdhj.js → codex-hook-5eys3dya.js} +2 -2
  82. package/dist/{codex-session-runner-gfg547zj.js → codex-session-runner-zd341dsm.js} +21 -14
  83. package/dist/{commands-e3bn0p75.js → commands-vfsysz4s.js} +9 -8
  84. package/dist/{db-03v9kzr2.js → db-s3znhvbn.js} +15 -10
  85. package/dist/{dispatcher-nrmg8yht.js → dispatcher-5xn0c7rf.js} +32 -28
  86. package/dist/{dsh-adapter-k03nfqa6.js → dsh-adapter-894mgfvs.js} +3 -3
  87. package/dist/{e2b-93x1k0j5.js → e2b-ez07znam.js} +4 -3
  88. package/dist/execute-71ysgv35.js +965 -0
  89. package/dist/{google-generative-ai-bxmv50nc.js → google-generative-ai-1nfcdphp.js} +5 -4
  90. package/dist/{google-vertex-809af514.js → google-vertex-1tqcd7b1.js} +5 -4
  91. package/dist/{handlers-aqcedbyb.js → handlers-5w4jwycr.js} +35 -31
  92. package/dist/{hook-7vkskkre.js → hook-853bxrr6.js} +16 -13
  93. package/dist/{hook-ybvmrmhq.js → hook-z0hbxj85.js} +16 -13
  94. package/dist/{http-2eqa8t24.js → http-akc3wy3m.js} +600 -123
  95. package/dist/{index-f6cryxwe.js → index-4a5njnm1.js} +2 -59
  96. package/dist/{index-a3vn96n8.js → index-5sz16ksh.js} +187 -47
  97. package/dist/{index-c6zsv1bd.js → index-bjmjh9h4.js} +11 -11
  98. package/dist/{index-chgdkq36.js → index-cd151qkq.js} +32 -28
  99. package/dist/{index-x71bvq0p.js → index-k661dzzr.js} +33 -29
  100. package/dist/{index-1yks3qcr.js → index-ttpbhnjg.js} +32 -28
  101. package/dist/{keepalive-vtkf5n99.js → keepalive-8p9rpvz5.js} +11 -10
  102. package/dist/{lead-h3sp357x.js → lead-jp69z5h3.js} +49 -45
  103. package/dist/llama-cpp-classify-t2tccams.js +335 -0
  104. package/dist/{maintenance-jzeqtk3q.js → maintenance-fwx4ev0k.js} +12 -12
  105. package/dist/{mistral-conversations-zx0kn554.js → mistral-conversations-bhvwqcnk.js} +14 -17
  106. package/dist/{oauth-refresh-sweep-qp3dzmdp.js → oauth-refresh-sweep-cwcq1ctx.js} +10 -9
  107. package/dist/{onboard-tmsp0qbz.js → onboard-2b4q0t84.js} +6 -5
  108. package/dist/{openai-codex-responses-4vjqzvjp.js → openai-codex-responses-nekthgks.js} +21 -8
  109. package/dist/{openai-completions-9hjrqbw8.js → openai-completions-hxtzwj0s.js} +8 -11
  110. package/dist/{openai-responses-7b1pn0xt.js → openai-responses-w4r118w7.js} +22 -17
  111. package/dist/{opencode-adapter-x6x2da1z.js → opencode-adapter-zz7xvjj6.js} +6 -4
  112. package/dist/{openrouter-images-9f9ek4rw.js → openrouter-images-b6sqqjgn.js} +4 -6
  113. package/dist/{otel-impl-9mz73q65.js → otel-impl-g8rs4vwr.js} +1 -1
  114. package/dist/{pi-messages-txpjj39q.js → pi-messages-vxdt8v7j.js} +2 -1
  115. package/dist/{pi-mono-adapter-m6dvv0dz.js → pi-mono-adapter-n0me28wt.js} +29 -17
  116. package/dist/pricing-refresh-0v77385v.js +39 -0
  117. package/dist/{rbac-roles-c9wqz83x.js → rbac-roles-krjyazbj.js} +10 -9
  118. package/dist/{render-v2-gryrh9h8.js → render-v2-3wjsp9aw.js} +10 -9
  119. package/dist/runtime-ktjysacx.js +24 -0
  120. package/dist/{setup-q9720bt6.js → setup-yeqryke6.js} +6 -5
  121. package/dist/typesafe-system-one-96960jxp.js +27 -0
  122. package/dist/{virtual-modules-3htpgn8x.js → virtual-modules-dzdeq1sf.js} +21 -13
  123. package/dist/{work-objects-b76x7deb.js → work-objects-3pakpkw0.js} +35 -31
  124. package/dist/{worker-6vrxbv41.js → worker-85testgj.js} +49 -45
  125. package/openapi.json +863 -14
  126. package/package.json +9 -8
  127. package/src/be/db/agents.ts +20 -0
  128. package/src/be/db/tasks/human-free.ts +442 -0
  129. package/src/be/db/tasks/read.ts +56 -1
  130. package/src/be/db/tasks/write.ts +107 -11
  131. package/src/be/db.ts +89 -165
  132. package/src/be/harness-model-support.ts +182 -0
  133. package/src/be/human-free-drain.ts +67 -0
  134. package/src/be/migrations/182_task_human_free_flag.sql +63 -0
  135. package/src/be/migrations/183_human_free_reclassify_queue.sql +25 -0
  136. package/src/be/migrations/184_model_catalog.sql +120 -0
  137. package/src/be/model-catalog-store.ts +644 -0
  138. package/src/be/model-tier-keys.ts +31 -0
  139. package/src/be/model-tier-resolution.ts +489 -0
  140. package/src/be/model-validation.ts +112 -0
  141. package/src/be/models-catalog.ts +61 -7
  142. package/src/be/modelsdev-cache.json +82 -0
  143. package/src/be/modelsdev-cache.ts +2 -0
  144. package/src/be/pricing-refresh.ts +154 -12
  145. package/src/be/scripts/typecheck.ts +15 -0
  146. package/src/be/seed-scripts/catalog/task-failure-audit.ts +61 -9
  147. package/src/be/swarm-config-guard.ts +6 -0
  148. package/src/cli.tsx +10 -0
  149. package/src/commands/claude-managed-setup.ts +3 -1
  150. package/src/commands/runner.ts +76 -2
  151. package/src/extensions/contract-types.generated.ts +1 -1
  152. package/src/heartbeat/heartbeat.ts +64 -15
  153. package/src/heartbeat/templates.ts +2 -2
  154. package/src/http/agents.ts +49 -1
  155. package/src/http/index.ts +8 -0
  156. package/src/http/models-catalog.ts +357 -8
  157. package/src/http/poll.ts +45 -2
  158. package/src/http/schedules.ts +36 -6
  159. package/src/http/session-data.ts +2 -5
  160. package/src/http/stats.ts +6 -8
  161. package/src/http/tasks.ts +26 -1
  162. package/src/http/usage-cache.ts +56 -15
  163. package/src/http/workflows.ts +35 -8
  164. package/src/prompts/session-templates.ts +1 -0
  165. package/src/providers/claude-managed-models.ts +47 -161
  166. package/src/providers/codex-adapter.ts +4 -4
  167. package/src/providers/codex-models.ts +65 -198
  168. package/src/providers/reasoning-effort.ts +44 -140
  169. package/src/rbac/legacy-policy.ts +25 -0
  170. package/src/rbac/permissions.ts +10 -0
  171. package/src/scripts-runtime/sdk-allowlist.ts +4 -0
  172. package/src/scripts-runtime/types/stdlib.d.ts +15 -0
  173. package/src/scripts-runtime/types/swarm-extension.d.ts +3 -0
  174. package/src/scripts-runtime/types/swarm-sdk.d.ts +15 -0
  175. package/src/server.ts +6 -0
  176. package/src/slack/message-text.ts +56 -2
  177. package/src/slack/thread-buffer.ts +10 -2
  178. package/src/tests/agents-list-model-display.test.ts +4 -6
  179. package/src/tests/base-prompt.test.ts +3 -0
  180. package/src/tests/claude-adapter.test.ts +10 -0
  181. package/src/tests/claude-managed-adapter.test.ts +12 -18
  182. package/src/tests/codex-adapter.test.ts +2 -1
  183. package/src/tests/codex-gpt6-release.test.ts +66 -5
  184. package/src/tests/context-window.test.ts +7 -5
  185. package/src/tests/db-extraction-contract.test.ts +1 -0
  186. package/src/tests/db-task-read-contract.test.ts +5 -1
  187. package/src/tests/db-task-write-contract.test.ts +4 -1
  188. package/src/tests/docs-index-footprint.test.js +3 -3
  189. package/src/tests/explicit-model-validation.test.ts +332 -0
  190. package/src/tests/harness-model-support.test.ts +374 -0
  191. package/src/tests/heartbeat-checklist-config.test.ts +71 -0
  192. package/src/tests/heartbeat-checklist.test.ts +4 -2
  193. package/src/tests/heartbeat-orphan-resume.test.ts +48 -0
  194. package/src/tests/human-free-flag.test.ts +279 -0
  195. package/src/tests/human-free-oracle.ts +57 -0
  196. package/src/tests/human-free-reclassify.test.ts +669 -0
  197. package/src/tests/migration-046-budgets.test.ts +3 -3
  198. package/src/tests/model-catalog-migration.test.ts +134 -0
  199. package/src/tests/model-catalog-table.test.ts +249 -0
  200. package/src/tests/model-catalog-write-access.test.ts +387 -0
  201. package/src/tests/model-tier-resolution.test.ts +519 -0
  202. package/src/tests/models-catalog.test.ts +1 -1
  203. package/src/tests/multi-runtime-enabled-stats.test.ts +65 -1
  204. package/src/tests/package-publish.test.ts +137 -36
  205. package/src/tests/pricing-routes.test.ts +2 -2
  206. package/src/tests/rbac-engine.test.ts +42 -2
  207. package/src/tests/reasoning-effort.test.ts +109 -0
  208. package/src/tests/refresh-modelsdev-carryforward.test.ts +5 -5
  209. package/src/tests/runtime-model-catalog.test.ts +86 -0
  210. package/src/tests/script-connections.test.ts +5 -0
  211. package/src/tests/seed-scripts.test.ts +89 -0
  212. package/src/tests/session-costs.test.ts +14 -11
  213. package/src/tests/slack-message-text.test.ts +101 -0
  214. package/src/tests/slack-thread-buffer-context.test.ts +93 -0
  215. package/src/tests/task-cascade-fail.test.ts +148 -2
  216. package/src/tests/tool-annotations.test.ts +1 -1
  217. package/src/tests/usage-cache.test.ts +166 -0
  218. package/src/tests/workflow-executors.test.ts +5 -2
  219. package/src/tests/workflow-system-one-decision-review.test.ts +1021 -0
  220. package/src/tests/workflow-system-one-decision-save-warnings.test.ts +365 -0
  221. package/src/tests/workflow-system-one-decision.test.ts +2063 -0
  222. package/src/tools/model-catalog/index.ts +137 -0
  223. package/src/tools/schedules/create-schedule.ts +16 -1
  224. package/src/tools/schedules/patch-schedule.ts +17 -0
  225. package/src/tools/schedules/update-schedule.ts +17 -0
  226. package/src/tools/send-task.ts +14 -0
  227. package/src/tools/task-action.ts +12 -0
  228. package/src/tools/tool-config.ts +3 -1
  229. package/src/tools/workflows/create-workflow.ts +9 -2
  230. package/src/tools/workflows/patch-workflow-node.ts +17 -7
  231. package/src/tools/workflows/patch-workflow.ts +9 -2
  232. package/src/tools/workflows/update-workflow.ts +9 -2
  233. package/src/types.ts +30 -1
  234. package/src/utils/context-window.ts +47 -53
  235. package/src/utils/harness-cli-version.ts +115 -0
  236. package/src/utils/harness-model-error.ts +33 -0
  237. package/src/utils/runtime-model-catalog.ts +137 -0
  238. package/src/workflows/approval-resolution.ts +39 -0
  239. package/src/workflows/definition.ts +7 -0
  240. package/src/workflows/engine.ts +69 -1
  241. package/src/workflows/executors/agent-task.ts +9 -0
  242. package/src/workflows/executors/base.ts +53 -0
  243. package/src/workflows/executors/human-in-the-loop.ts +8 -8
  244. package/src/workflows/executors/index.ts +1 -0
  245. package/src/workflows/executors/registry.ts +2 -0
  246. package/src/workflows/executors/system-one-decision.ts +1232 -0
  247. package/src/workflows/executors/system-one-providers.ts +301 -0
  248. package/src/workflows/executors/workflow-llm.ts +13 -1
  249. package/src/workflows/readiness.ts +86 -0
  250. package/src/workflows/recovery.ts +12 -12
  251. package/src/workflows/resume.ts +23 -9
  252. package/templates/schedules/daily-blocker-digest/content.md +4 -5
  253. package/templates/skills/agent-browser/SKILL.md +6 -5
  254. package/templates/skills/agent-browser/content.md +6 -5
  255. package/templates/skills/heartbeat-runbook/config.json +1 -1
  256. package/templates/skills/heartbeat-runbook/content.md +2 -2
  257. package/templates/skills/swarm-scripts/SKILL.md +1 -1
  258. package/templates/skills/swarm-scripts/content.md +1 -1
  259. package/templates/skills/workflow-iterate/content.md +81 -1
  260. package/templates/workflows/claude-code-changelog-watch/content.md +2 -0
  261. package/templates/workflows/pr-review-status-sweep/content.md +2 -0
  262. package/dist/claude-sdk-session-t442qz6f.js +0 -39108
  263. package/dist/cli-0xjkj1j7.js +0 -61
  264. package/dist/cli-65hjmev5.js +0 -1141
  265. package/dist/cli-aw1jwp1r.js +0 -14075
  266. package/dist/cli-h967nb6r.js +0 -6603
  267. package/dist/cli-vapyk8sw.js +0 -20
  268. package/dist/cli-ws6rqycm.js +0 -247
  269. package/dist/pricing-refresh-v1cbr9te.js +0 -27
  270. package/src/providers/modelsdev-reasoning.json +0 -6453
  271. package/dist/{codex-login-x3jk4etn.js → codex-login-he9vrn90.js} +3 -3
  272. package/dist/{index-f24115ge.js → index-2wsdsnmm.js} +3 -3
@@ -1,1141 +0,0 @@
1
- import {
2
- contentSha256,
3
- init_profile_sync
4
- } from "./cli-xberxa1r.js";
5
- import {
6
- OpenAI,
7
- init_openai
8
- } from "./cli-aehm1rbq.js";
9
- import {
10
- getDb,
11
- getDbClient,
12
- init_db,
13
- isSqliteVecAvailable
14
- } from "./cli-47m6dkd3.js";
15
- import {
16
- __esm,
17
- __export,
18
- __toCommonJS
19
- } from "./cli-bc05qbss.js";
20
-
21
- // src/be/memory/constants.ts
22
- function numEnv(key, fallback) {
23
- const val = process.env[key];
24
- if (val === undefined)
25
- return fallback;
26
- const parsed = Number(val);
27
- return Number.isNaN(parsed) ? fallback : parsed;
28
- }
29
- function recencyDecayHalfLifeDays(source = "task_completion") {
30
- const raw = process.env.MEMORY_RECENCY_HALF_LIFE_DAYS;
31
- if (raw != null && raw !== "") {
32
- const parsed = Number(raw);
33
- if (Number.isFinite(parsed))
34
- return parsed;
35
- }
36
- return DEFAULT_RECENCY_DECAY_HALF_LIFE[source];
37
- }
38
- function minSimilarity() {
39
- return numEnv("MEMORY_MIN_SIMILARITY", 0.1);
40
- }
41
- function accessBoostMaxMultiplier() {
42
- return numEnv("MEMORY_ACCESS_BOOST_MAX", 1.5);
43
- }
44
- function isHybridSearchEnabled() {
45
- const val = process.env.MEMORY_HYBRID_SEARCH?.trim().toLowerCase();
46
- return val !== "0" && val !== "false";
47
- }
48
- function isGraphExpansionEnabled() {
49
- const val = process.env.MEMORY_GRAPH_EXPANSION?.trim().toLowerCase();
50
- return val !== "0" && val !== "false";
51
- }
52
- var TTL_DEFAULTS, DEFAULT_RECENCY_DECAY_HALF_LIFE, SOURCE_QUALITY_MULTIPLIER, ACCESS_BOOST_RECENCY_WINDOW_HOURS, CANDIDATE_SET_MULTIPLIER, EMBEDDING_DIMENSIONS, DEFAULT_EMBEDDING_MODEL = "openai/text-embedding-3-small", PROTECTED_SOURCES;
53
- var init_constants = __esm(() => {
54
- TTL_DEFAULTS = {
55
- task_completion: 7,
56
- session_summary: 3,
57
- file_index: 30,
58
- manual: null
59
- };
60
- DEFAULT_RECENCY_DECAY_HALF_LIFE = {
61
- manual: Number.POSITIVE_INFINITY,
62
- file_index: 180,
63
- task_completion: 14,
64
- session_summary: 7
65
- };
66
- SOURCE_QUALITY_MULTIPLIER = {
67
- manual: 1.5,
68
- file_index: 1,
69
- task_completion: 0.7,
70
- session_summary: 0.5
71
- };
72
- ACCESS_BOOST_RECENCY_WINDOW_HOURS = numEnv("MEMORY_ACCESS_RECENCY_HOURS", 48);
73
- CANDIDATE_SET_MULTIPLIER = numEnv("MEMORY_CANDIDATE_MULTIPLIER", 3);
74
- EMBEDDING_DIMENSIONS = numEnv("EMBEDDING_DIMENSIONS", 512);
75
- PROTECTED_SOURCES = new Set(["manual"]);
76
- });
77
-
78
- // src/be/memory/providers/openai-embedding.ts
79
- var exports_openai_embedding = {};
80
- __export(exports_openai_embedding, {
81
- OpenAIEmbeddingProvider: () => OpenAIEmbeddingProvider
82
- });
83
-
84
- class OpenAIEmbeddingProvider {
85
- name;
86
- dimensions;
87
- client = null;
88
- model;
89
- apiKey;
90
- constructor(config) {
91
- this.apiKey = config?.apiKey ?? process.env.EMBEDDING_API_KEY ?? process.env.OPENAI_API_KEY;
92
- this.model = config?.model ?? process.env.EMBEDDING_MODEL ?? "text-embedding-3-small";
93
- this.dimensions = config?.dimensions ?? EMBEDDING_DIMENSIONS;
94
- this.name = config?.model ? `openai/${config.model}` : process.env.EMBEDDING_MODEL ?? DEFAULT_EMBEDDING_MODEL;
95
- }
96
- isConfigured() {
97
- return !!this.apiKey;
98
- }
99
- getClient() {
100
- if (!this.apiKey)
101
- return null;
102
- if (!this.client)
103
- this.client = new OpenAI({
104
- baseURL: process.env.EMBEDDING_API_BASE_URL,
105
- apiKey: this.apiKey
106
- });
107
- return this.client;
108
- }
109
- async embed(text) {
110
- const client = this.getClient();
111
- if (!client)
112
- return null;
113
- try {
114
- const cleaned = text.replace(/[\n\r]/g, " ").trim();
115
- if (!cleaned)
116
- return null;
117
- const response = await client.embeddings.create({
118
- model: this.model,
119
- input: cleaned,
120
- dimensions: this.dimensions,
121
- encoding_format: "float"
122
- });
123
- const values = response.data[0]?.embedding;
124
- if (!values)
125
- return null;
126
- if (values.length !== this.dimensions) {
127
- console.error(`[memory] Embedding dimension mismatch: expected=${this.dimensions} got=${values.length}. Provider may not support the 'dimensions' parameter.`);
128
- return null;
129
- }
130
- return new Float32Array(values);
131
- } catch (err) {
132
- console.error("[memory] Embedding failed:", err.message);
133
- return null;
134
- }
135
- }
136
- async embedBatch(texts) {
137
- const client = this.getClient();
138
- if (!client)
139
- return texts.map(() => null);
140
- const cleaned = texts.map((t) => t.replace(/[\n\r]/g, " ").trim());
141
- const nonEmptyIndices = [];
142
- const nonEmptyTexts = [];
143
- for (let i = 0;i < cleaned.length; i++) {
144
- if (cleaned[i]) {
145
- nonEmptyIndices.push(i);
146
- nonEmptyTexts.push(cleaned[i]);
147
- }
148
- }
149
- if (nonEmptyTexts.length === 0)
150
- return texts.map(() => null);
151
- try {
152
- const response = await client.embeddings.create({
153
- model: this.model,
154
- input: nonEmptyTexts,
155
- dimensions: this.dimensions,
156
- encoding_format: "float"
157
- });
158
- const results = texts.map(() => null);
159
- for (const item of response.data) {
160
- const originalIndex = nonEmptyIndices[item.index];
161
- if (originalIndex !== undefined && item.embedding) {
162
- if (item.embedding.length !== this.dimensions) {
163
- console.error(`[memory] Batch embedding dimension mismatch: expected=${this.dimensions} got=${item.embedding.length}. Provider may not support the 'dimensions' parameter.`);
164
- continue;
165
- }
166
- results[originalIndex] = new Float32Array(item.embedding);
167
- }
168
- }
169
- return results;
170
- } catch (err) {
171
- console.error("[memory] Batch embedding failed:", err.message);
172
- return texts.map(() => null);
173
- }
174
- }
175
- }
176
- var init_openai_embedding = __esm(() => {
177
- init_openai();
178
- init_constants();
179
- });
180
-
181
- // src/be/embedding.ts
182
- function cosineSimilarity(a, b) {
183
- if (a.length !== b.length)
184
- throw new Error("Vectors must have the same length");
185
- if (a.length === 0)
186
- return 0;
187
- let dotProduct = 0;
188
- let normA = 0;
189
- let normB = 0;
190
- for (let i = 0;i < a.length; i++) {
191
- const ai = a[i];
192
- const bi = b[i];
193
- dotProduct += ai * bi;
194
- normA += ai * ai;
195
- normB += bi * bi;
196
- }
197
- const denominator = Math.sqrt(normA) * Math.sqrt(normB);
198
- if (denominator === 0)
199
- return 0;
200
- return dotProduct / denominator;
201
- }
202
- function serializeEmbedding(embedding) {
203
- return Buffer.from(embedding.buffer, embedding.byteOffset, embedding.byteLength);
204
- }
205
- function deserializeEmbedding(buffer) {
206
- const copy = new ArrayBuffer(buffer.length);
207
- const view = new Uint8Array(copy);
208
- view.set(buffer);
209
- return new Float32Array(copy);
210
- }
211
- var init_embedding = () => {};
212
-
213
- // src/be/memory/reranker.ts
214
- function recencyDecay(createdAt, now, source) {
215
- const halfLife = recencyDecayHalfLifeDays(source);
216
- if (!Number.isFinite(halfLife))
217
- return 1;
218
- const ageDays = (now.getTime() - new Date(createdAt).getTime()) / MS_PER_DAY;
219
- if (ageDays <= 0)
220
- return 1;
221
- return 2 ** (-ageDays / halfLife);
222
- }
223
- function accessBoost(accessedAt, accessCount, now) {
224
- if (accessCount <= 0)
225
- return 1;
226
- const hoursSinceAccess = (now.getTime() - new Date(accessedAt).getTime()) / MS_PER_HOUR;
227
- const recencyFactor = hoursSinceAccess <= ACCESS_BOOST_RECENCY_WINDOW_HOURS ? 1 : 0.5;
228
- const boost = 1 + Math.min(accessCount / 10, accessBoostMaxMultiplier() - 1) * recencyFactor;
229
- return boost;
230
- }
231
- function sourceQuality(source) {
232
- return SOURCE_QUALITY_MULTIPLIER[source] ?? 1;
233
- }
234
- function readDemotionFloor() {
235
- const raw = process.env.MEMORY_DEMOTION_FLOOR;
236
- const n = raw == null || raw === "" ? 1 : Number(raw);
237
- return Number.isFinite(n) ? n : 1;
238
- }
239
- function usefulness(alpha, beta) {
240
- const denom = alpha + beta;
241
- if (denom <= 0)
242
- return 1;
243
- const mean = alpha / denom;
244
- return Math.max(readDemotionFloor(), Math.min(2, 2 * mean));
245
- }
246
- function computeScore(candidate, now) {
247
- const decay = candidate.recencyDecayApplied ? 1 : recencyDecay(candidate.createdAt, now, candidate.source);
248
- return candidate.similarity * decay * accessBoost(candidate.accessedAt, candidate.accessCount, now) * sourceQuality(candidate.source) * usefulness(candidate.alpha, candidate.beta);
249
- }
250
- function rerank(candidates, options) {
251
- const { limit, now = new Date } = options;
252
- const uncapped = new Map;
253
- for (const candidate of candidates)
254
- uncapped.set(candidate.id, computeScore(candidate, now));
255
- const byId = new Map(candidates.map((c) => [c.id, c]));
256
- const capped = new Map;
257
- const cappedScore = (candidate, seen) => {
258
- const cached = capped.get(candidate.id);
259
- if (cached !== undefined)
260
- return cached;
261
- let score = uncapped.get(candidate.id);
262
- const parent = candidate.graphParentId ? byId.get(candidate.graphParentId) : undefined;
263
- if (parent && !seen.has(parent.id)) {
264
- seen.add(candidate.id);
265
- score = Math.min(score, cappedScore(parent, seen));
266
- }
267
- capped.set(candidate.id, score);
268
- return score;
269
- };
270
- const scored = candidates.map((candidate) => {
271
- const rawSimilarity = candidate.rawSimilarity ?? candidate.similarity;
272
- const compositeScore = cappedScore(candidate, new Set);
273
- return {
274
- ...candidate,
275
- rawSimilarity,
276
- compositeScore,
277
- similarity: compositeScore
278
- };
279
- });
280
- scored.sort((a, b) => b.similarity - a.similarity || b.rawSimilarity - a.rawSimilarity);
281
- return scored.slice(0, limit);
282
- }
283
- var MS_PER_DAY, MS_PER_HOUR;
284
- var init_reranker = __esm(() => {
285
- init_constants();
286
- MS_PER_DAY = 1000 * 60 * 60 * 24;
287
- MS_PER_HOUR = 1000 * 60 * 60;
288
- });
289
-
290
- // src/be/memory/providers/sqlite-store.ts
291
- var exports_sqlite_store = {};
292
- __export(exports_sqlite_store, {
293
- SqliteMemoryStore: () => SqliteMemoryStore,
294
- applyEditMode: () => applyEditMode,
295
- computeRrfScore: () => computeRrfScore,
296
- fusedSimilarity: () => fusedSimilarity,
297
- rowToCandidate: () => rowToCandidate
298
- });
299
- function rowToAgentMemory(row) {
300
- return {
301
- id: row.id,
302
- agentId: row.agentId,
303
- scope: row.scope,
304
- key: row.key ?? null,
305
- name: row.name,
306
- content: row.content,
307
- summary: row.summary,
308
- source: row.source,
309
- sourceTaskId: row.sourceTaskId,
310
- sourcePath: row.sourcePath,
311
- chunkIndex: row.chunkIndex,
312
- totalChunks: row.totalChunks,
313
- tags: JSON.parse(row.tags || "[]"),
314
- createdAt: row.createdAt,
315
- updatedAt: row.updatedAt ?? null,
316
- accessedAt: row.accessedAt,
317
- expiresAt: row.expiresAt ?? null,
318
- accessCount: row.accessCount ?? 0,
319
- embeddingModel: row.embeddingModel ?? null,
320
- contentHash: row.contentHash ?? null,
321
- version: row.version ?? 1
322
- };
323
- }
324
- function rowToCandidate(row, similarity) {
325
- return {
326
- ...rowToAgentMemory(row),
327
- similarity,
328
- accessCount: row.accessCount ?? 0,
329
- expiresAt: row.expiresAt ?? null,
330
- embeddingModel: row.embeddingModel ?? null,
331
- alpha: row.alpha ?? 1,
332
- beta: row.beta ?? 1
333
- };
334
- }
335
- function retrievalSourceFor(sources) {
336
- if (sources.has("fts") && sources.has("vec"))
337
- return "hybrid";
338
- if (sources.has("fts"))
339
- return "fts";
340
- if (sources.has("vec"))
341
- return "vec";
342
- return "fallback";
343
- }
344
- function computeRrfScore(rank, decayFactor, k = 60) {
345
- return 1 / (k + rank + 1) * decayFactor;
346
- }
347
- function fusedSimilarity(cosine, rrfScore, k = 60) {
348
- const agreement = Math.min(1, rrfScore * (k + 1) / 2);
349
- return cosine * (0.5 + 0.5 * agreement);
350
- }
351
- function applyEditMode(mode, currentContent, fields) {
352
- if (mode === "replace") {
353
- if (fields.content == null)
354
- throw new Error("replace mode requires content");
355
- return fields.content;
356
- }
357
- if (!fields.oldString || fields.newString == null) {
358
- throw new Error("exact mode requires oldString and newString");
359
- }
360
- const first = currentContent.indexOf(fields.oldString);
361
- if (first === -1)
362
- throw new Error("oldString not found");
363
- if (currentContent.indexOf(fields.oldString, first + fields.oldString.length) !== -1) {
364
- throw new Error("oldString is ambiguous");
365
- }
366
- return currentContent.slice(0, first) + fields.newString + currentContent.slice(first + fields.oldString.length);
367
- }
368
- function computeExpiresAt(source) {
369
- const ttlDays = TTL_DEFAULTS[source];
370
- if (ttlDays == null)
371
- return null;
372
- return new Date(Date.now() + ttlDays * 86400000).toISOString();
373
- }
374
-
375
- class SqliteMemoryStore {
376
- vecInitialized = false;
377
- ftsInitialized = false;
378
- lastPopulate = null;
379
- constructor() {
380
- this.ensureVecTable();
381
- this.ensureFtsTable();
382
- }
383
- ensureFtsTable() {
384
- if (this.ftsInitialized)
385
- return;
386
- const db = getDb();
387
- try {
388
- db.run(`
389
- CREATE VIRTUAL TABLE IF NOT EXISTS memory_fts USING fts5(
390
- memory_id UNINDEXED,
391
- name,
392
- content,
393
- tokenize='porter unicode61'
394
- )
395
- `);
396
- this.populateFtsTable();
397
- this.ftsInitialized = true;
398
- } catch (err) {
399
- this.ftsInitialized = false;
400
- console.error("[memory-fts] Failed to initialize memory_fts:", err.message);
401
- }
402
- }
403
- async getFtsTableSchema() {
404
- try {
405
- const row = await getDbClient().get("SELECT sql FROM sqlite_master WHERE type = 'table' AND name = 'memory_fts'");
406
- return row?.sql ?? null;
407
- } catch {
408
- return null;
409
- }
410
- }
411
- populateFtsTable() {
412
- const db = getDb();
413
- const deletedExtra = db.prepare(`DELETE FROM memory_fts
414
- WHERE memory_id NOT IN (SELECT id FROM agent_memory)`).run();
415
- if (deletedExtra.changes > 0) {
416
- console.warn(`[memory-fts] removed_extra_rows count=${deletedExtra.changes}`);
417
- }
418
- const inserted = db.prepare(`INSERT INTO memory_fts(memory_id, name, content)
419
- SELECT m.id, m.name, m.content
420
- FROM agent_memory m
421
- WHERE NOT EXISTS (SELECT 1 FROM memory_fts f WHERE f.memory_id = m.id)`).run();
422
- console.log(`[memory-fts] populate inserted=${inserted.changes}`);
423
- }
424
- async syncFtsRow(memoryId, name, content) {
425
- if (!this.ftsInitialized && !await this.getFtsTableSchema())
426
- return;
427
- try {
428
- await getDbClient().run("DELETE FROM memory_fts WHERE memory_id = ?", [memoryId]);
429
- await getDbClient().run("INSERT INTO memory_fts(memory_id, name, content) VALUES (?, ?, ?)", [
430
- memoryId,
431
- name,
432
- content
433
- ]);
434
- } catch (err) {
435
- console.error(`[memory-fts] sync failed memory_id=${memoryId}: ${err.message}`);
436
- }
437
- }
438
- async deleteFtsRows(ids) {
439
- if (ids.length === 0 || !await this.getFtsTableSchema())
440
- return;
441
- const placeholders = ids.map(() => "?").join(",");
442
- await getDbClient().run(`DELETE FROM memory_fts WHERE memory_id IN (${placeholders})`, ids);
443
- }
444
- ensureVecTable() {
445
- if (this.vecInitialized)
446
- return;
447
- if (!isSqliteVecAvailable()) {
448
- console.warn("[memory-vec] sqlite-vec extension_loaded=false; retrieval_mode=fallback");
449
- return;
450
- }
451
- const db = getDb();
452
- try {
453
- console.log(`[memory-vec] sqlite-vec extension_loaded=true vector_dimensions=${EMBEDDING_DIMENSIONS}`);
454
- const existingSchema = this.getVecTableSchema();
455
- if (existingSchema && !existingSchema.includes("distance_metric=cosine")) {
456
- console.warn("[memory-vec] Existing memory_vec table is missing cosine distance metric; rebuilding from agent_memory");
457
- db.run("DROP TABLE memory_vec");
458
- }
459
- db.run(`
460
- CREATE VIRTUAL TABLE IF NOT EXISTS memory_vec USING vec0(
461
- memory_id TEXT PRIMARY KEY,
462
- embedding float[${EMBEDDING_DIMENSIONS}] distance_metric=cosine
463
- )
464
- `);
465
- const healthBefore = this.getHealthCounts();
466
- if (healthBefore.missingFromVec > 0 || healthBefore.extraInVec > 0) {
467
- this.populateVecTable(healthBefore.memoryVec);
468
- } else {
469
- console.log(`[memory-vec] populate skipped attempted=0 inserted=0 memory_vec=${healthBefore.memoryVec} valid_embedding=${healthBefore.validEmbedding}`);
470
- }
471
- this.vecInitialized = true;
472
- } catch (err) {
473
- this.vecInitialized = false;
474
- console.error("[memory-vec] Failed to initialize memory_vec:", err.message);
475
- }
476
- }
477
- getVecTableSchema() {
478
- try {
479
- return getDb().prepare("SELECT sql FROM sqlite_master WHERE type = 'table' AND name = 'memory_vec'").get()?.sql ?? null;
480
- } catch {
481
- return null;
482
- }
483
- }
484
- getVecCount() {
485
- if (!this.getVecTableSchema())
486
- return 0;
487
- return getDb().prepare("SELECT COUNT(*) as count FROM memory_vec").get()?.count ?? 0;
488
- }
489
- populateVecTable(beforeCount) {
490
- const db = getDb();
491
- const deletedExtra = db.prepare(`DELETE FROM memory_vec
492
- WHERE memory_id NOT IN (SELECT id FROM agent_memory)`).run();
493
- if (deletedExtra.changes > 0) {
494
- console.warn(`[memory-vec] removed_extra_rows count=${deletedExtra.changes}`);
495
- }
496
- const rows = db.prepare("SELECT id, embedding FROM agent_memory WHERE embedding IS NOT NULL").all();
497
- const deleteVec = db.prepare("DELETE FROM memory_vec WHERE memory_id = ?");
498
- const insertVec = db.prepare("INSERT INTO memory_vec(memory_id, embedding) VALUES (?, ?)");
499
- let attempted = 0;
500
- let inserted = 0;
501
- let skippedInvalidDimensions = 0;
502
- let failed = 0;
503
- for (const row of rows) {
504
- const embeddingBuffer = this.toVecBuffer(row.embedding);
505
- if (!embeddingBuffer) {
506
- skippedInvalidDimensions++;
507
- continue;
508
- }
509
- attempted++;
510
- try {
511
- deleteVec.run(row.id);
512
- insertVec.run(row.id, embeddingBuffer);
513
- inserted++;
514
- } catch (err) {
515
- failed++;
516
- console.error(`[memory-vec] populate failed memory_id=${row.id}: ${err.message}`);
517
- }
518
- }
519
- const afterCount = this.getVecCount();
520
- this.lastPopulate = {
521
- attempted,
522
- inserted,
523
- skippedInvalidDimensions,
524
- failed,
525
- beforeCount,
526
- afterCount
527
- };
528
- console.log(`[memory-vec] populate attempted=${attempted} inserted=${inserted} skipped_invalid_dimensions=${skippedInvalidDimensions} failed=${failed} before_count=${beforeCount} after_count=${afterCount}`);
529
- if (failed > 0 || afterCount < attempted) {
530
- console.error(`[memory-vec] populate incomplete attempted=${attempted} after_count=${afterCount} failed=${failed}`);
531
- }
532
- }
533
- toVecBuffer(embedding) {
534
- if (embedding instanceof Float32Array) {
535
- if (embedding.length !== EMBEDDING_DIMENSIONS)
536
- return null;
537
- return serializeEmbedding(embedding);
538
- }
539
- if (embedding.length !== VECTOR_BYTES)
540
- return null;
541
- return embedding;
542
- }
543
- async store(input) {
544
- const id = crypto.randomUUID();
545
- const now = new Date().toISOString();
546
- const expiresAt = computeExpiresAt(input.source);
547
- const key = input.key ?? `${input.scope}/${input.source}/${id}`;
548
- const contentHash = contentSha256(input.content);
549
- const version = 1;
550
- const row = await getDbClient().transaction(async (tx) => {
551
- const inserted = await tx.get(`INSERT INTO agent_memory (id, agentId, scope, key, name, content, summary, source, sourceTaskId, sourcePath, chunkIndex, totalChunks, tags, createdAt, updatedAt, accessedAt, expiresAt, accessCount, embeddingModel, contextKey, contentHash, version)
552
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING *`, [
553
- id,
554
- input.agentId ?? null,
555
- input.scope,
556
- key,
557
- input.name,
558
- input.content,
559
- input.summary ?? null,
560
- input.source,
561
- input.sourceTaskId ?? null,
562
- input.sourcePath ?? null,
563
- input.chunkIndex ?? 0,
564
- input.totalChunks ?? 1,
565
- JSON.stringify(input.tags ?? []),
566
- now,
567
- now,
568
- now,
569
- expiresAt,
570
- 0,
571
- null,
572
- input.contextKey ?? null,
573
- contentHash,
574
- version
575
- ]);
576
- if (!inserted)
577
- throw new Error("Failed to create memory");
578
- await tx.run(`INSERT INTO agent_memory_version (id, memory_id, version, content, contentHash, intent, operation, changedByAgentId, createdAt, updatedAt, created_by, updated_by)
579
- VALUES (?, ?, ?, ?, ?, ?, 'create', ?, ?, ?, ?, ?)`, [
580
- crypto.randomUUID(),
581
- inserted.id,
582
- version,
583
- input.content,
584
- contentHash,
585
- input.intent ?? "create memory",
586
- input.agentId ?? null,
587
- now,
588
- now,
589
- input.agentId ?? null,
590
- input.agentId ?? null
591
- ]);
592
- return inserted;
593
- });
594
- await this.syncFtsRow(row.id, row.name, row.content);
595
- return rowToAgentMemory(row);
596
- }
597
- async storeBatch(inputs) {
598
- const results = [];
599
- await getDbClient().transaction(async () => {
600
- for (const input of inputs) {
601
- results.push(await this.store(input));
602
- }
603
- });
604
- return results;
605
- }
606
- async get(id) {
607
- const db = getDbClient();
608
- const row = await db.get("SELECT * FROM agent_memory WHERE id = ?", [id]);
609
- if (!row)
610
- return null;
611
- await db.run("UPDATE agent_memory SET accessedAt = ?, accessCount = accessCount + 1 WHERE id = ?", [new Date().toISOString(), id]);
612
- return rowToAgentMemory(row);
613
- }
614
- async peek(id) {
615
- const row = await getDbClient().get("SELECT * FROM agent_memory WHERE id = ?", [
616
- id
617
- ]);
618
- if (!row)
619
- return null;
620
- return rowToAgentMemory(row);
621
- }
622
- async search(embedding, agentId, options = {}) {
623
- const { scope = "all", limit = 10, source, isLead = false, includeExpired = false } = options;
624
- const health = this.getHealth();
625
- if (isHybridSearchEnabled() && options.queryText && this.ftsInitialized && await this.getFtsTableSchema() && health.retrievalMode === "vec" && embedding.length === EMBEDDING_DIMENSIONS) {
626
- console.log(`[memory-search] retrieval_path=hybrid scope=${scope} limit=${limit} vec_rows=${health.counts.memoryVec} searchable=${health.counts.searchable}`);
627
- return this.searchHybrid(embedding, options.queryText, agentId, {
628
- scope,
629
- limit,
630
- source,
631
- isLead,
632
- includeExpired
633
- });
634
- }
635
- if (health.retrievalMode === "vec" && embedding.length === EMBEDDING_DIMENSIONS) {
636
- console.log(`[memory-search] retrieval_path=vec scope=${scope} limit=${limit} vec_rows=${health.counts.memoryVec} searchable=${health.counts.searchable}`);
637
- return this.searchWithVec(embedding, agentId, {
638
- scope,
639
- limit,
640
- source,
641
- isLead,
642
- includeExpired
643
- });
644
- }
645
- if (options.queryText && this.ftsInitialized && await this.getFtsTableSchema()) {
646
- console.log(`[memory-search] retrieval_path=fts scope=${scope} limit=${limit} reason=${embedding.length !== EMBEDDING_DIMENSIONS ? "query_dimension_mismatch" : health.reasons.join("|") || "vec_unavailable"}`);
647
- return this.searchFts(options.queryText, agentId, {
648
- scope,
649
- limit,
650
- source,
651
- isLead,
652
- includeExpired
653
- });
654
- }
655
- console.log(`[memory-search] retrieval_path=fallback scope=${scope} limit=${limit} reason=${embedding.length !== EMBEDDING_DIMENSIONS ? "query_dimension_mismatch" : health.reasons.join("|") || "vec_unavailable"}`);
656
- return this.searchBruteForce(embedding, agentId, {
657
- scope,
658
- limit,
659
- source,
660
- isLead,
661
- includeExpired
662
- });
663
- }
664
- async searchHybrid(queryEmbedding, queryText, agentId, options) {
665
- const overfetchLimit = Math.min(Math.max(options.limit * 4, options.limit), 100);
666
- const vectorCandidates = await this.searchWithVec(queryEmbedding, agentId, {
667
- ...options,
668
- limit: overfetchLimit
669
- });
670
- const ftsCandidates = await this.searchFts(queryText, agentId, {
671
- ...options,
672
- limit: overfetchLimit
673
- });
674
- const byId = new Map;
675
- const rrf = new Map;
676
- const cosines = new Map;
677
- const sources = new Map;
678
- const add = (candidate, rank) => {
679
- byId.set(candidate.id, byId.get(candidate.id) ?? candidate);
680
- const retrievalSource = candidate.retrievalSource === "fts" ? "fts" : "vec";
681
- const candidateSources = sources.get(candidate.id) ?? new Set;
682
- candidateSources.add(retrievalSource);
683
- sources.set(candidate.id, candidateSources);
684
- if (retrievalSource === "vec")
685
- cosines.set(candidate.id, candidate.similarity);
686
- rrf.set(candidate.id, (rrf.get(candidate.id) ?? 0) + computeRrfScore(rank, 1));
687
- };
688
- vectorCandidates.forEach(add);
689
- ftsCandidates.forEach(add);
690
- await this.fillCosines(queryEmbedding, [...byId.keys()], cosines);
691
- return [...byId.values()].map((candidate) => {
692
- const similarity = fusedSimilarity(cosines.get(candidate.id) ?? 0, rrf.get(candidate.id) ?? 0);
693
- return {
694
- ...candidate,
695
- rawSimilarity: similarity,
696
- similarity,
697
- retrievalSource: retrievalSourceFor(sources.get(candidate.id) ?? new Set),
698
- recencyDecayApplied: false
699
- };
700
- }).sort((a, b) => b.similarity - a.similarity).slice(0, options.limit);
701
- }
702
- async fillCosines(queryEmbedding, ids, cosines) {
703
- const missing = ids.filter((id) => !cosines.has(id));
704
- if (missing.length === 0)
705
- return;
706
- const rows = await getDbClient().query(`SELECT id, embedding FROM agent_memory WHERE id IN (${missing.map(() => "?").join(",")})`, missing);
707
- for (const row of rows) {
708
- if (!row.embedding)
709
- continue;
710
- const embedding = deserializeEmbedding(row.embedding);
711
- if (embedding.length !== queryEmbedding.length)
712
- continue;
713
- cosines.set(row.id, Math.max(0, cosineSimilarity(queryEmbedding, embedding)));
714
- }
715
- }
716
- async searchFts(queryText, agentId, options) {
717
- const match = this.buildFtsMatch(queryText);
718
- if (!match)
719
- return [];
720
- const { scope, limit, source, isLead, includeExpired } = options;
721
- const conditions = ["memory_fts MATCH ?"];
722
- const params = [match];
723
- this.addScopeConditions(conditions, params, agentId, scope, isLead, "m");
724
- if (source) {
725
- conditions.push("m.source = ?");
726
- params.push(source);
727
- }
728
- if (!includeExpired) {
729
- conditions.push("(m.expiresAt IS NULL OR m.expiresAt > datetime('now'))");
730
- }
731
- try {
732
- const sqlLimit = Math.min(Math.max(limit * 4, limit), 100);
733
- const rows = await getDbClient().query(`SELECT m.*, bm25(memory_fts) AS rank
734
- FROM memory_fts
735
- JOIN agent_memory m ON m.id = memory_fts.memory_id
736
- WHERE ${conditions.join(" AND ")}
737
- ORDER BY rank
738
- LIMIT ?`, [...params, sqlLimit]);
739
- const now = new Date;
740
- return rows.map((row, index) => {
741
- const rawSimilarity = 1 / (index + 1);
742
- return {
743
- ...rowToCandidate(row, rawSimilarity * recencyDecay(row.createdAt, now, row.source)),
744
- rawSimilarity,
745
- retrievalSource: "fts",
746
- recencyDecayApplied: true
747
- };
748
- }).sort((a, b) => b.similarity - a.similarity).slice(0, limit);
749
- } catch (err) {
750
- console.warn("[memory-fts] query failed:", err.message);
751
- return [];
752
- }
753
- }
754
- buildFtsMatch(queryText) {
755
- const terms = queryText.trim().split(/[^\p{L}\p{N}_-]+/u).map((term) => term.trim()).filter((term) => term.length > 0).slice(0, 12);
756
- if (terms.length === 0)
757
- return null;
758
- return terms.map((term) => `"${term.replaceAll('"', '""')}"`).join(" OR ");
759
- }
760
- async searchWithVec(queryEmbedding, agentId, options) {
761
- const { scope, limit, source, isLead, includeExpired } = options;
762
- const embeddingBuffer = serializeEmbedding(queryEmbedding);
763
- const knnLimit = Math.min(Math.max(limit, this.getVecCount()), 4096);
764
- const conditions = ["v.embedding MATCH ?"];
765
- const params = [embeddingBuffer];
766
- this.addScopeConditions(conditions, params, agentId, scope, isLead, "m");
767
- if (source) {
768
- conditions.push("m.source = ?");
769
- params.push(source);
770
- }
771
- if (!includeExpired) {
772
- conditions.push("(m.expiresAt IS NULL OR m.expiresAt > datetime('now'))");
773
- }
774
- conditions.push("v.k = ?");
775
- params.push(knnLimit);
776
- const rows = await getDbClient().query(`SELECT m.*, v.distance
777
- FROM memory_vec v
778
- JOIN agent_memory m ON m.id = v.memory_id
779
- WHERE ${conditions.join(" AND ")}
780
- ORDER BY v.distance
781
- LIMIT ?`, [...params, limit]);
782
- const candidates = [];
783
- for (const row of rows) {
784
- const similarity = 1 - row.distance;
785
- if (similarity < minSimilarity())
786
- continue;
787
- candidates.push({ ...rowToCandidate(row, similarity), retrievalSource: "vec" });
788
- }
789
- return candidates;
790
- }
791
- async searchBruteForce(queryEmbedding, agentId, options) {
792
- const { scope, limit, source, isLead, includeExpired } = options;
793
- const conditions = ["embedding IS NOT NULL"];
794
- const params = [];
795
- this.addScopeConditions(conditions, params, agentId, scope, isLead);
796
- if (source) {
797
- conditions.push("source = ?");
798
- params.push(source);
799
- }
800
- if (!includeExpired) {
801
- conditions.push("(expiresAt IS NULL OR expiresAt > datetime('now'))");
802
- }
803
- const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
804
- const rows = await getDbClient().query(`SELECT * FROM agent_memory ${whereClause}`, params);
805
- const candidates = [];
806
- for (const row of rows) {
807
- if (!row.embedding)
808
- continue;
809
- const emb = deserializeEmbedding(row.embedding);
810
- if (emb.length !== queryEmbedding.length)
811
- continue;
812
- const similarity = cosineSimilarity(queryEmbedding, emb);
813
- if (similarity < minSimilarity())
814
- continue;
815
- candidates.push({ ...rowToCandidate(row, similarity), retrievalSource: "fallback" });
816
- }
817
- candidates.sort((a, b) => b.similarity - a.similarity);
818
- return candidates.slice(0, limit);
819
- }
820
- addScopeConditions(conditions, params, agentId, scope, isLead, tableAlias = "") {
821
- const col = (name) => tableAlias ? `${tableAlias}.${name}` : name;
822
- if (!isLead) {
823
- if (scope === "agent") {
824
- conditions.push(`${col("agentId")} = ? AND ${col("scope")} = 'agent'`);
825
- params.push(agentId);
826
- } else if (scope === "swarm") {
827
- conditions.push(`${col("scope")} = 'swarm'`);
828
- } else {
829
- conditions.push(`(${col("agentId")} = ? OR ${col("scope")} = 'swarm')`);
830
- params.push(agentId);
831
- }
832
- } else {
833
- if (scope === "agent") {
834
- conditions.push(`${col("scope")} = 'agent'`);
835
- } else if (scope === "swarm") {
836
- conditions.push(`${col("scope")} = 'swarm'`);
837
- }
838
- }
839
- }
840
- buildListWhereClause(agentId, options) {
841
- const { scope = "all", isLead = false, ownerAgentId, source, sourcePath } = options;
842
- const conditions = [];
843
- const params = [];
844
- this.addScopeConditions(conditions, params, agentId, scope, isLead);
845
- if (ownerAgentId) {
846
- conditions.push("agentId = ?");
847
- params.push(ownerAgentId);
848
- }
849
- if (source) {
850
- conditions.push("source = ?");
851
- params.push(source);
852
- }
853
- const sourcePathNeedle = sourcePath?.trim().toLowerCase();
854
- if (sourcePathNeedle) {
855
- conditions.push("instr(lower(coalesce(sourcePath, '')), ?) > 0");
856
- params.push(sourcePathNeedle);
857
- }
858
- return {
859
- whereClause: conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "",
860
- params
861
- };
862
- }
863
- async list(agentId, options = {}) {
864
- const { limit = 20, offset = 0 } = options;
865
- const { whereClause, params } = this.buildListWhereClause(agentId, options);
866
- const queryParams = [...params, limit, offset];
867
- const rows = await getDbClient().query(`SELECT * FROM agent_memory ${whereClause} ORDER BY createdAt DESC LIMIT ? OFFSET ?`, queryParams);
868
- return rows.map(rowToAgentMemory);
869
- }
870
- async count(agentId, options = {}) {
871
- const { whereClause, params } = this.buildListWhereClause(agentId, options);
872
- const row = await getDbClient().get(`SELECT COUNT(*) AS count FROM agent_memory ${whereClause}`, params);
873
- return row?.count ?? 0;
874
- }
875
- isSourceProtected(source) {
876
- return PROTECTED_SOURCES.has(source);
877
- }
878
- async edit(input) {
879
- if (!input.id && !(input.key && input.scope)) {
880
- throw new Error("memory edit requires either id or key+scope");
881
- }
882
- const { result, ftsContent } = await getDbClient().transaction(async (tx) => {
883
- const row = input.id ? await tx.get("SELECT * FROM agent_memory WHERE id = ?", [input.id]) : await tx.get(`SELECT * FROM agent_memory
884
- WHERE key = ? AND scope = ? AND coalesce(agentId, '') = coalesce(?, '')
885
- ORDER BY chunkIndex ASC
886
- LIMIT 1`, [input.key, input.scope, input.agentId ?? null]);
887
- if (!row)
888
- throw new Error("memory not found");
889
- if ((row.totalChunks ?? 1) !== 1)
890
- throw new Error("memory edit only supports single-chunk rows");
891
- if (input.expectedVersion && input.expectedVersion !== (row.version ?? 1)) {
892
- throw new Error("memory version conflict");
893
- }
894
- const previousVersion = row.version ?? 1;
895
- const nextContent = applyEditMode(input.mode, row.content, {
896
- content: input.content,
897
- oldString: input.oldString,
898
- newString: input.newString
899
- });
900
- const nextHash = contentSha256(nextContent);
901
- if (nextHash === row.contentHash) {
902
- return {
903
- result: {
904
- memory: rowToAgentMemory(row),
905
- changed: false,
906
- previousVersion,
907
- version: previousVersion,
908
- contentHash: nextHash
909
- },
910
- ftsContent: null
911
- };
912
- }
913
- const nextVersion = previousVersion + 1;
914
- const now = new Date().toISOString();
915
- await tx.run(`INSERT INTO agent_memory_version (id, memory_id, version, content, contentHash, intent, operation, changedByAgentId, createdAt, updatedAt, created_by, updated_by)
916
- VALUES (?, ?, ?, ?, ?, ?, 'edit', ?, ?, ?, ?, ?)`, [
917
- crypto.randomUUID(),
918
- row.id,
919
- nextVersion,
920
- nextContent,
921
- nextHash,
922
- input.intent,
923
- input.changedByAgentId ?? null,
924
- now,
925
- now,
926
- input.changedByAgentId ?? null,
927
- input.changedByAgentId ?? null
928
- ]);
929
- await tx.run(`UPDATE agent_memory
930
- SET content = ?, contentHash = ?, version = ?, updatedAt = ?
931
- WHERE id = ?`, [nextContent, nextHash, nextVersion, now, row.id]);
932
- return {
933
- result: {
934
- memory: rowToAgentMemory({
935
- ...row,
936
- content: nextContent,
937
- contentHash: nextHash,
938
- version: nextVersion,
939
- updatedAt: now
940
- }),
941
- changed: true,
942
- previousVersion,
943
- version: nextVersion,
944
- contentHash: nextHash
945
- },
946
- ftsContent: nextContent
947
- };
948
- });
949
- if (ftsContent !== null) {
950
- await this.syncFtsRow(result.memory.id, result.memory.name, ftsContent);
951
- }
952
- return result;
953
- }
954
- async listForCuration(agentId) {
955
- const db = getDbClient();
956
- const protectedList = [...PROTECTED_SOURCES].map((s) => `'${s}'`).join(",");
957
- if (agentId) {
958
- return db.query(`SELECT id, source, name, createdAt FROM agent_memory
959
- WHERE agentId = ? AND source NOT IN (${protectedList})`, [agentId]);
960
- }
961
- return db.query(`SELECT id, source, name, createdAt FROM agent_memory
962
- WHERE source NOT IN (${protectedList})`);
963
- }
964
- async listForReembedding(options) {
965
- const db = getDbClient();
966
- if (options?.agentId) {
967
- return db.query("SELECT id, content FROM agent_memory WHERE agentId = ?", [options.agentId]);
968
- }
969
- return db.query("SELECT id, content FROM agent_memory");
970
- }
971
- async purgeByIds(ids) {
972
- if (ids.length === 0)
973
- return;
974
- if (this.vecInitialized && this.getVecTableSchema()) {
975
- const placeholders = ids.map(() => "?").join(",");
976
- await getDbClient().run(`DELETE FROM memory_vec WHERE memory_id IN (${placeholders})`, ids);
977
- }
978
- await this.deleteFtsRows(ids);
979
- }
980
- async delete(id) {
981
- await this.purgeByIds([id]);
982
- const result = await getDbClient().run("DELETE FROM agent_memory WHERE id = ?", [id]);
983
- return result.changes > 0;
984
- }
985
- async deleteBySourcePath(sourcePath, agentId) {
986
- const db = getDbClient();
987
- const ids = await db.query("SELECT id FROM agent_memory WHERE sourcePath = ? AND agentId = ?", [sourcePath, agentId]);
988
- await this.purgeByIds(ids.map((r) => r.id));
989
- const result = await db.run("DELETE FROM agent_memory WHERE sourcePath = ? AND agentId = ?", [
990
- sourcePath,
991
- agentId
992
- ]);
993
- return ids.length || result.changes;
994
- }
995
- async purgeExpired() {
996
- const db = getDbClient();
997
- const expiredIds = await db.query("SELECT id FROM agent_memory WHERE expiresAt IS NOT NULL AND expiresAt <= datetime('now')");
998
- if (expiredIds.length === 0)
999
- return 0;
1000
- const batchSize = 500;
1001
- for (let i = 0;i < expiredIds.length; i += batchSize) {
1002
- await this.purgeByIds(expiredIds.slice(i, i + batchSize).map((r) => r.id));
1003
- }
1004
- const result = await db.run("DELETE FROM agent_memory WHERE expiresAt IS NOT NULL AND expiresAt <= datetime('now')");
1005
- console.log(`[memory] Purged ${result.changes} expired memory row(s) (vec cleanup: ${expiredIds.length} id(s))`);
1006
- return result.changes;
1007
- }
1008
- async updateEmbedding(id, embedding, model) {
1009
- const db = getDbClient();
1010
- const buffer = serializeEmbedding(embedding);
1011
- await db.run("UPDATE agent_memory SET embedding = ?, embeddingModel = ? WHERE id = ?", [
1012
- buffer,
1013
- model,
1014
- id
1015
- ]);
1016
- if (this.vecInitialized && this.getVecTableSchema()) {
1017
- const vecBuffer = this.toVecBuffer(embedding);
1018
- if (!vecBuffer) {
1019
- console.warn(`[memory-vec] update skipped memory_id=${id} reason=invalid_dimensions dimensions=${embedding.length} expected=${EMBEDDING_DIMENSIONS}`);
1020
- return;
1021
- }
1022
- try {
1023
- await db.run("DELETE FROM memory_vec WHERE memory_id = ?", [id]);
1024
- await db.run("INSERT INTO memory_vec(memory_id, embedding) VALUES (?, ?)", [id, vecBuffer]);
1025
- } catch (err) {
1026
- console.error(`[memory-vec] update failed memory_id=${id}: ${err.message}`);
1027
- }
1028
- }
1029
- }
1030
- async getStats(agentId) {
1031
- const db = getDbClient();
1032
- const total = await db.get("SELECT COUNT(*) as count FROM agent_memory WHERE agentId = ?", [agentId]);
1033
- const bySourceRows = await db.query("SELECT source, COUNT(*) as count FROM agent_memory WHERE agentId = ? GROUP BY source", [agentId]);
1034
- const byScopeRows = await db.query("SELECT scope, COUNT(*) as count FROM agent_memory WHERE agentId = ? GROUP BY scope", [agentId]);
1035
- const withEmbeddings = await db.get("SELECT COUNT(*) as count FROM agent_memory WHERE agentId = ? AND embedding IS NOT NULL", [agentId]);
1036
- const expired = await db.get("SELECT COUNT(*) as count FROM agent_memory WHERE agentId = ? AND expiresAt IS NOT NULL AND expiresAt <= datetime('now')", [agentId]);
1037
- const bySource = {};
1038
- for (const row of bySourceRows)
1039
- bySource[row.source] = row.count;
1040
- const byScope = {};
1041
- for (const row of byScopeRows)
1042
- byScope[row.scope] = row.count;
1043
- return {
1044
- total: total?.count ?? 0,
1045
- bySource,
1046
- byScope,
1047
- withEmbeddings: withEmbeddings?.count ?? 0,
1048
- expired: expired?.count ?? 0
1049
- };
1050
- }
1051
- getHealthCounts() {
1052
- const db = getDb();
1053
- const tableExists = this.getVecTableSchema() !== null;
1054
- const tableUsable = tableExists && isSqliteVecAvailable();
1055
- const count = (sql) => db.prepare(sql).get()?.count ?? 0;
1056
- return {
1057
- total: count("SELECT COUNT(*) as count FROM agent_memory"),
1058
- withEmbedding: count("SELECT COUNT(*) as count FROM agent_memory WHERE embedding IS NOT NULL"),
1059
- validEmbedding: count(`SELECT COUNT(*) as count FROM agent_memory WHERE embedding IS NOT NULL AND length(embedding) = ${VECTOR_BYTES}`),
1060
- invalidEmbedding: count(`SELECT COUNT(*) as count FROM agent_memory WHERE embedding IS NOT NULL AND length(embedding) != ${VECTOR_BYTES}`),
1061
- searchable: count(`SELECT COUNT(*) as count FROM agent_memory
1062
- WHERE embedding IS NOT NULL
1063
- AND length(embedding) = ${VECTOR_BYTES}
1064
- AND (expiresAt IS NULL OR expiresAt > datetime('now'))`),
1065
- memoryVec: tableUsable ? count("SELECT COUNT(*) as count FROM memory_vec") : 0,
1066
- missingFromVec: tableUsable ? count(`SELECT COUNT(*) as count
1067
- FROM agent_memory m
1068
- LEFT JOIN memory_vec v ON v.memory_id = m.id
1069
- WHERE m.embedding IS NOT NULL
1070
- AND length(m.embedding) = ${VECTOR_BYTES}
1071
- AND v.memory_id IS NULL`) : count(`SELECT COUNT(*) as count FROM agent_memory WHERE embedding IS NOT NULL AND length(embedding) = ${VECTOR_BYTES}`),
1072
- extraInVec: tableUsable ? count(`SELECT COUNT(*) as count
1073
- FROM memory_vec v
1074
- LEFT JOIN agent_memory m ON m.id = v.memory_id
1075
- WHERE m.id IS NULL`) : 0
1076
- };
1077
- }
1078
- getHealth() {
1079
- const schema = this.getVecTableSchema();
1080
- const counts = this.getHealthCounts();
1081
- const reasons = [];
1082
- if (!isSqliteVecAvailable())
1083
- reasons.push("sqlite_vec_extension_unavailable");
1084
- if (!schema)
1085
- reasons.push("memory_vec_table_missing");
1086
- if (!this.vecInitialized)
1087
- reasons.push("memory_vec_not_initialized");
1088
- if (counts.memoryVec === 0)
1089
- reasons.push("memory_vec_empty");
1090
- if (counts.missingFromVec > 0)
1091
- reasons.push("memory_vec_missing_embeddings");
1092
- if (counts.extraInVec > 0)
1093
- reasons.push("memory_vec_extra_rows");
1094
- return {
1095
- sqliteVec: {
1096
- extensionLoaded: isSqliteVecAvailable(),
1097
- tableExists: schema !== null,
1098
- initialized: this.vecInitialized,
1099
- vectorDimensions: EMBEDDING_DIMENSIONS,
1100
- distanceMetric: "cosine",
1101
- schema,
1102
- lastPopulate: this.lastPopulate
1103
- },
1104
- counts,
1105
- retrievalMode: reasons.length === 0 ? "vec" : "fallback",
1106
- reasons
1107
- };
1108
- }
1109
- }
1110
- var VECTOR_BYTES;
1111
- var init_sqlite_store = __esm(() => {
1112
- init_db();
1113
- init_embedding();
1114
- init_profile_sync();
1115
- init_constants();
1116
- init_reranker();
1117
- VECTOR_BYTES = EMBEDDING_DIMENSIONS * Float32Array.BYTES_PER_ELEMENT;
1118
- });
1119
-
1120
- // src/be/memory/index.ts
1121
- var embeddingProvider = null;
1122
- var memoryStore = null;
1123
- function getEmbeddingProvider() {
1124
- if (!embeddingProvider) {
1125
- const { OpenAIEmbeddingProvider: OpenAIEmbeddingProvider2 } = (init_openai_embedding(), __toCommonJS(exports_openai_embedding));
1126
- embeddingProvider = new OpenAIEmbeddingProvider2;
1127
- }
1128
- return embeddingProvider;
1129
- }
1130
- function resetEmbeddingProvider() {
1131
- embeddingProvider = null;
1132
- }
1133
- function getMemoryStore() {
1134
- if (!memoryStore) {
1135
- const { SqliteMemoryStore: SqliteMemoryStore2 } = (init_sqlite_store(), __toCommonJS(exports_sqlite_store));
1136
- memoryStore = new SqliteMemoryStore2;
1137
- }
1138
- return memoryStore;
1139
- }
1140
-
1141
- export { cosineSimilarity, serializeEmbedding, deserializeEmbedding, init_embedding, CANDIDATE_SET_MULTIPLIER, isGraphExpansionEnabled, EMBEDDING_DIMENSIONS, init_constants, computeScore, rerank, init_reranker, rowToCandidate, init_sqlite_store, getEmbeddingProvider, resetEmbeddingProvider, getMemoryStore };