@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,5 +1,17 @@
1
1
  import {
2
- __esm
2
+ contentSha256,
3
+ init_profile_sync
4
+ } from "./cli-10ym38qc.js";
5
+ import {
6
+ getDb,
7
+ getDbClient,
8
+ init_db,
9
+ isSqliteVecAvailable
10
+ } from "./cli-g9df2m37.js";
11
+ import {
12
+ __esm,
13
+ __export,
14
+ __toCommonJS
3
15
  } from "./cli-bc05qbss.js";
4
16
 
5
17
  // node_modules/openai/internal/tslib.mjs
@@ -7951,70 +7963,12 @@ var init_client = __esm(() => {
7951
7963
  });
7952
7964
 
7953
7965
  // node_modules/openai/azure.mjs
7954
- var AzureOpenAI, _deployments_endpoints;
7966
+ var _deployments_endpoints;
7955
7967
  var init_azure = __esm(() => {
7956
7968
  init_headers();
7957
7969
  init_error2();
7958
7970
  init_utils2();
7959
7971
  init_client();
7960
- AzureOpenAI = class AzureOpenAI extends OpenAI {
7961
- constructor({ baseURL = readEnv("OPENAI_BASE_URL"), apiKey = readEnv("AZURE_OPENAI_API_KEY"), apiVersion = readEnv("OPENAI_API_VERSION"), endpoint, deployment, azureADTokenProvider, dangerouslyAllowBrowser, ...opts } = {}) {
7962
- if (!apiVersion) {
7963
- throw new OpenAIError("The OPENAI_API_VERSION environment variable is missing or empty; either provide it, or instantiate the AzureOpenAI client with an apiVersion option, like new AzureOpenAI({ apiVersion: 'My API Version' }).");
7964
- }
7965
- if (typeof azureADTokenProvider === "function") {
7966
- dangerouslyAllowBrowser = true;
7967
- }
7968
- if (!azureADTokenProvider && !apiKey) {
7969
- throw new OpenAIError("Missing credentials. Please pass one of `apiKey` and `azureADTokenProvider`, or set the `AZURE_OPENAI_API_KEY` environment variable.");
7970
- }
7971
- if (azureADTokenProvider && apiKey) {
7972
- throw new OpenAIError("The `apiKey` and `azureADTokenProvider` arguments are mutually exclusive; only one can be passed at a time.");
7973
- }
7974
- opts.defaultQuery = { ...opts.defaultQuery, "api-version": apiVersion };
7975
- if (!baseURL) {
7976
- if (!endpoint) {
7977
- endpoint = process.env["AZURE_OPENAI_ENDPOINT"];
7978
- }
7979
- if (!endpoint) {
7980
- throw new OpenAIError("Must provide one of the `baseURL` or `endpoint` arguments, or the `AZURE_OPENAI_ENDPOINT` environment variable");
7981
- }
7982
- baseURL = `${endpoint}/openai`;
7983
- } else {
7984
- if (endpoint) {
7985
- throw new OpenAIError("baseURL and endpoint are mutually exclusive");
7986
- }
7987
- }
7988
- super({
7989
- apiKey: azureADTokenProvider ?? apiKey,
7990
- baseURL,
7991
- ...opts,
7992
- ...dangerouslyAllowBrowser !== undefined ? { dangerouslyAllowBrowser } : {}
7993
- });
7994
- this.apiVersion = "";
7995
- this.apiVersion = apiVersion;
7996
- this.deploymentName = deployment;
7997
- }
7998
- async buildRequest(options, props = {}) {
7999
- if (_deployments_endpoints.has(options.path) && options.method === "post" && options.body !== undefined) {
8000
- if (!isObj(options.body)) {
8001
- throw new Error("Expected request body to be an object");
8002
- }
8003
- const model = this.deploymentName || options.body["model"] || options.__metadata?.["model"];
8004
- if (model !== undefined && !this.baseURL.includes("/deployments")) {
8005
- options.path = `/deployments/${model}${options.path}`;
8006
- }
8007
- }
8008
- return super.buildRequest(options, props);
8009
- }
8010
- async authHeaders(opts, schemes) {
8011
- const security = schemes ?? { bearerAuth: true, adminAPIKeyAuth: true };
8012
- if (security.bearerAuth && typeof this._options.apiKey === "string") {
8013
- return buildHeaders([{ "api-key": this.apiKey }]);
8014
- }
8015
- return super.authHeaders(opts, security);
8016
- }
8017
- };
8018
7972
  _deployments_endpoints = new Set([
8019
7973
  "/completions",
8020
7974
  "/chat/completions",
@@ -8039,4 +7993,1124 @@ var init_openai = __esm(() => {
8039
7993
  init_azure();
8040
7994
  });
8041
7995
 
8042
- export { OpenAI, AzureOpenAI, init_openai };
7996
+ // src/be/memory/constants.ts
7997
+ function numEnv(key, fallback) {
7998
+ const val = process.env[key];
7999
+ if (val === undefined)
8000
+ return fallback;
8001
+ const parsed = Number(val);
8002
+ return Number.isNaN(parsed) ? fallback : parsed;
8003
+ }
8004
+ function recencyDecayHalfLifeDays(source = "task_completion") {
8005
+ const raw = process.env.MEMORY_RECENCY_HALF_LIFE_DAYS;
8006
+ if (raw != null && raw !== "") {
8007
+ const parsed = Number(raw);
8008
+ if (Number.isFinite(parsed))
8009
+ return parsed;
8010
+ }
8011
+ return DEFAULT_RECENCY_DECAY_HALF_LIFE[source];
8012
+ }
8013
+ function minSimilarity() {
8014
+ return numEnv("MEMORY_MIN_SIMILARITY", 0.1);
8015
+ }
8016
+ function accessBoostMaxMultiplier() {
8017
+ return numEnv("MEMORY_ACCESS_BOOST_MAX", 1.5);
8018
+ }
8019
+ function isHybridSearchEnabled() {
8020
+ const val = process.env.MEMORY_HYBRID_SEARCH?.trim().toLowerCase();
8021
+ return val !== "0" && val !== "false";
8022
+ }
8023
+ function isGraphExpansionEnabled() {
8024
+ const val = process.env.MEMORY_GRAPH_EXPANSION?.trim().toLowerCase();
8025
+ return val !== "0" && val !== "false";
8026
+ }
8027
+ 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;
8028
+ var init_constants = __esm(() => {
8029
+ TTL_DEFAULTS = {
8030
+ task_completion: 7,
8031
+ session_summary: 3,
8032
+ file_index: 30,
8033
+ manual: null
8034
+ };
8035
+ DEFAULT_RECENCY_DECAY_HALF_LIFE = {
8036
+ manual: Number.POSITIVE_INFINITY,
8037
+ file_index: 180,
8038
+ task_completion: 14,
8039
+ session_summary: 7
8040
+ };
8041
+ SOURCE_QUALITY_MULTIPLIER = {
8042
+ manual: 1.5,
8043
+ file_index: 1,
8044
+ task_completion: 0.7,
8045
+ session_summary: 0.5
8046
+ };
8047
+ ACCESS_BOOST_RECENCY_WINDOW_HOURS = numEnv("MEMORY_ACCESS_RECENCY_HOURS", 48);
8048
+ CANDIDATE_SET_MULTIPLIER = numEnv("MEMORY_CANDIDATE_MULTIPLIER", 3);
8049
+ EMBEDDING_DIMENSIONS = numEnv("EMBEDDING_DIMENSIONS", 512);
8050
+ PROTECTED_SOURCES = new Set(["manual"]);
8051
+ });
8052
+
8053
+ // src/be/memory/providers/openai-embedding.ts
8054
+ var exports_openai_embedding = {};
8055
+ __export(exports_openai_embedding, {
8056
+ OpenAIEmbeddingProvider: () => OpenAIEmbeddingProvider
8057
+ });
8058
+
8059
+ class OpenAIEmbeddingProvider {
8060
+ name;
8061
+ dimensions;
8062
+ client = null;
8063
+ model;
8064
+ apiKey;
8065
+ constructor(config) {
8066
+ this.apiKey = config?.apiKey ?? process.env.EMBEDDING_API_KEY ?? process.env.OPENAI_API_KEY;
8067
+ this.model = config?.model ?? process.env.EMBEDDING_MODEL ?? "text-embedding-3-small";
8068
+ this.dimensions = config?.dimensions ?? EMBEDDING_DIMENSIONS;
8069
+ this.name = config?.model ? `openai/${config.model}` : process.env.EMBEDDING_MODEL ?? DEFAULT_EMBEDDING_MODEL;
8070
+ }
8071
+ isConfigured() {
8072
+ return !!this.apiKey;
8073
+ }
8074
+ getClient() {
8075
+ if (!this.apiKey)
8076
+ return null;
8077
+ if (!this.client)
8078
+ this.client = new OpenAI({
8079
+ baseURL: process.env.EMBEDDING_API_BASE_URL,
8080
+ apiKey: this.apiKey
8081
+ });
8082
+ return this.client;
8083
+ }
8084
+ async embed(text) {
8085
+ const client = this.getClient();
8086
+ if (!client)
8087
+ return null;
8088
+ try {
8089
+ const cleaned = text.replace(/[\n\r]/g, " ").trim();
8090
+ if (!cleaned)
8091
+ return null;
8092
+ const response = await client.embeddings.create({
8093
+ model: this.model,
8094
+ input: cleaned,
8095
+ dimensions: this.dimensions,
8096
+ encoding_format: "float"
8097
+ });
8098
+ const values2 = response.data[0]?.embedding;
8099
+ if (!values2)
8100
+ return null;
8101
+ if (values2.length !== this.dimensions) {
8102
+ console.error(`[memory] Embedding dimension mismatch: expected=${this.dimensions} got=${values2.length}. Provider may not support the 'dimensions' parameter.`);
8103
+ return null;
8104
+ }
8105
+ return new Float32Array(values2);
8106
+ } catch (err) {
8107
+ console.error("[memory] Embedding failed:", err.message);
8108
+ return null;
8109
+ }
8110
+ }
8111
+ async embedBatch(texts) {
8112
+ const client = this.getClient();
8113
+ if (!client)
8114
+ return texts.map(() => null);
8115
+ const cleaned = texts.map((t) => t.replace(/[\n\r]/g, " ").trim());
8116
+ const nonEmptyIndices = [];
8117
+ const nonEmptyTexts = [];
8118
+ for (let i = 0;i < cleaned.length; i++) {
8119
+ if (cleaned[i]) {
8120
+ nonEmptyIndices.push(i);
8121
+ nonEmptyTexts.push(cleaned[i]);
8122
+ }
8123
+ }
8124
+ if (nonEmptyTexts.length === 0)
8125
+ return texts.map(() => null);
8126
+ try {
8127
+ const response = await client.embeddings.create({
8128
+ model: this.model,
8129
+ input: nonEmptyTexts,
8130
+ dimensions: this.dimensions,
8131
+ encoding_format: "float"
8132
+ });
8133
+ const results = texts.map(() => null);
8134
+ for (const item of response.data) {
8135
+ const originalIndex = nonEmptyIndices[item.index];
8136
+ if (originalIndex !== undefined && item.embedding) {
8137
+ if (item.embedding.length !== this.dimensions) {
8138
+ console.error(`[memory] Batch embedding dimension mismatch: expected=${this.dimensions} got=${item.embedding.length}. Provider may not support the 'dimensions' parameter.`);
8139
+ continue;
8140
+ }
8141
+ results[originalIndex] = new Float32Array(item.embedding);
8142
+ }
8143
+ }
8144
+ return results;
8145
+ } catch (err) {
8146
+ console.error("[memory] Batch embedding failed:", err.message);
8147
+ return texts.map(() => null);
8148
+ }
8149
+ }
8150
+ }
8151
+ var init_openai_embedding = __esm(() => {
8152
+ init_openai();
8153
+ init_constants();
8154
+ });
8155
+
8156
+ // src/be/embedding.ts
8157
+ function cosineSimilarity(a, b) {
8158
+ if (a.length !== b.length)
8159
+ throw new Error("Vectors must have the same length");
8160
+ if (a.length === 0)
8161
+ return 0;
8162
+ let dotProduct = 0;
8163
+ let normA = 0;
8164
+ let normB = 0;
8165
+ for (let i = 0;i < a.length; i++) {
8166
+ const ai = a[i];
8167
+ const bi = b[i];
8168
+ dotProduct += ai * bi;
8169
+ normA += ai * ai;
8170
+ normB += bi * bi;
8171
+ }
8172
+ const denominator = Math.sqrt(normA) * Math.sqrt(normB);
8173
+ if (denominator === 0)
8174
+ return 0;
8175
+ return dotProduct / denominator;
8176
+ }
8177
+ function serializeEmbedding(embedding) {
8178
+ return Buffer.from(embedding.buffer, embedding.byteOffset, embedding.byteLength);
8179
+ }
8180
+ function deserializeEmbedding(buffer) {
8181
+ const copy = new ArrayBuffer(buffer.length);
8182
+ const view = new Uint8Array(copy);
8183
+ view.set(buffer);
8184
+ return new Float32Array(copy);
8185
+ }
8186
+ var init_embedding = () => {};
8187
+
8188
+ // src/be/memory/reranker.ts
8189
+ function recencyDecay(createdAt, now, source) {
8190
+ const halfLife = recencyDecayHalfLifeDays(source);
8191
+ if (!Number.isFinite(halfLife))
8192
+ return 1;
8193
+ const ageDays = (now.getTime() - new Date(createdAt).getTime()) / MS_PER_DAY;
8194
+ if (ageDays <= 0)
8195
+ return 1;
8196
+ return 2 ** (-ageDays / halfLife);
8197
+ }
8198
+ function accessBoost(accessedAt, accessCount, now) {
8199
+ if (accessCount <= 0)
8200
+ return 1;
8201
+ const hoursSinceAccess = (now.getTime() - new Date(accessedAt).getTime()) / MS_PER_HOUR;
8202
+ const recencyFactor = hoursSinceAccess <= ACCESS_BOOST_RECENCY_WINDOW_HOURS ? 1 : 0.5;
8203
+ const boost = 1 + Math.min(accessCount / 10, accessBoostMaxMultiplier() - 1) * recencyFactor;
8204
+ return boost;
8205
+ }
8206
+ function sourceQuality(source) {
8207
+ return SOURCE_QUALITY_MULTIPLIER[source] ?? 1;
8208
+ }
8209
+ function readDemotionFloor() {
8210
+ const raw = process.env.MEMORY_DEMOTION_FLOOR;
8211
+ const n = raw == null || raw === "" ? 1 : Number(raw);
8212
+ return Number.isFinite(n) ? n : 1;
8213
+ }
8214
+ function usefulness(alpha, beta) {
8215
+ const denom = alpha + beta;
8216
+ if (denom <= 0)
8217
+ return 1;
8218
+ const mean = alpha / denom;
8219
+ return Math.max(readDemotionFloor(), Math.min(2, 2 * mean));
8220
+ }
8221
+ function computeScore(candidate, now) {
8222
+ const decay = candidate.recencyDecayApplied ? 1 : recencyDecay(candidate.createdAt, now, candidate.source);
8223
+ return candidate.similarity * decay * accessBoost(candidate.accessedAt, candidate.accessCount, now) * sourceQuality(candidate.source) * usefulness(candidate.alpha, candidate.beta);
8224
+ }
8225
+ function rerank(candidates, options) {
8226
+ const { limit: limit2, now = new Date } = options;
8227
+ const uncapped = new Map;
8228
+ for (const candidate of candidates)
8229
+ uncapped.set(candidate.id, computeScore(candidate, now));
8230
+ const byId = new Map(candidates.map((c) => [c.id, c]));
8231
+ const capped = new Map;
8232
+ const cappedScore = (candidate, seen) => {
8233
+ const cached = capped.get(candidate.id);
8234
+ if (cached !== undefined)
8235
+ return cached;
8236
+ let score = uncapped.get(candidate.id);
8237
+ const parent = candidate.graphParentId ? byId.get(candidate.graphParentId) : undefined;
8238
+ if (parent && !seen.has(parent.id)) {
8239
+ seen.add(candidate.id);
8240
+ score = Math.min(score, cappedScore(parent, seen));
8241
+ }
8242
+ capped.set(candidate.id, score);
8243
+ return score;
8244
+ };
8245
+ const scored = candidates.map((candidate) => {
8246
+ const rawSimilarity = candidate.rawSimilarity ?? candidate.similarity;
8247
+ const compositeScore = cappedScore(candidate, new Set);
8248
+ return {
8249
+ ...candidate,
8250
+ rawSimilarity,
8251
+ compositeScore,
8252
+ similarity: compositeScore
8253
+ };
8254
+ });
8255
+ scored.sort((a, b) => b.similarity - a.similarity || b.rawSimilarity - a.rawSimilarity);
8256
+ return scored.slice(0, limit2);
8257
+ }
8258
+ var MS_PER_DAY, MS_PER_HOUR;
8259
+ var init_reranker = __esm(() => {
8260
+ init_constants();
8261
+ MS_PER_DAY = 1000 * 60 * 60 * 24;
8262
+ MS_PER_HOUR = 1000 * 60 * 60;
8263
+ });
8264
+
8265
+ // src/be/memory/providers/sqlite-store.ts
8266
+ var exports_sqlite_store = {};
8267
+ __export(exports_sqlite_store, {
8268
+ SqliteMemoryStore: () => SqliteMemoryStore,
8269
+ applyEditMode: () => applyEditMode,
8270
+ computeRrfScore: () => computeRrfScore,
8271
+ fusedSimilarity: () => fusedSimilarity,
8272
+ rowToCandidate: () => rowToCandidate
8273
+ });
8274
+ function rowToAgentMemory(row) {
8275
+ return {
8276
+ id: row.id,
8277
+ agentId: row.agentId,
8278
+ scope: row.scope,
8279
+ key: row.key ?? null,
8280
+ name: row.name,
8281
+ content: row.content,
8282
+ summary: row.summary,
8283
+ source: row.source,
8284
+ sourceTaskId: row.sourceTaskId,
8285
+ sourcePath: row.sourcePath,
8286
+ chunkIndex: row.chunkIndex,
8287
+ totalChunks: row.totalChunks,
8288
+ tags: JSON.parse(row.tags || "[]"),
8289
+ createdAt: row.createdAt,
8290
+ updatedAt: row.updatedAt ?? null,
8291
+ accessedAt: row.accessedAt,
8292
+ expiresAt: row.expiresAt ?? null,
8293
+ accessCount: row.accessCount ?? 0,
8294
+ embeddingModel: row.embeddingModel ?? null,
8295
+ contentHash: row.contentHash ?? null,
8296
+ version: row.version ?? 1
8297
+ };
8298
+ }
8299
+ function rowToCandidate(row, similarity) {
8300
+ return {
8301
+ ...rowToAgentMemory(row),
8302
+ similarity,
8303
+ accessCount: row.accessCount ?? 0,
8304
+ expiresAt: row.expiresAt ?? null,
8305
+ embeddingModel: row.embeddingModel ?? null,
8306
+ alpha: row.alpha ?? 1,
8307
+ beta: row.beta ?? 1
8308
+ };
8309
+ }
8310
+ function retrievalSourceFor(sources) {
8311
+ if (sources.has("fts") && sources.has("vec"))
8312
+ return "hybrid";
8313
+ if (sources.has("fts"))
8314
+ return "fts";
8315
+ if (sources.has("vec"))
8316
+ return "vec";
8317
+ return "fallback";
8318
+ }
8319
+ function computeRrfScore(rank, decayFactor, k = 60) {
8320
+ return 1 / (k + rank + 1) * decayFactor;
8321
+ }
8322
+ function fusedSimilarity(cosine, rrfScore, k = 60) {
8323
+ const agreement = Math.min(1, rrfScore * (k + 1) / 2);
8324
+ return cosine * (0.5 + 0.5 * agreement);
8325
+ }
8326
+ function applyEditMode(mode, currentContent, fields) {
8327
+ if (mode === "replace") {
8328
+ if (fields.content == null)
8329
+ throw new Error("replace mode requires content");
8330
+ return fields.content;
8331
+ }
8332
+ if (!fields.oldString || fields.newString == null) {
8333
+ throw new Error("exact mode requires oldString and newString");
8334
+ }
8335
+ const first = currentContent.indexOf(fields.oldString);
8336
+ if (first === -1)
8337
+ throw new Error("oldString not found");
8338
+ if (currentContent.indexOf(fields.oldString, first + fields.oldString.length) !== -1) {
8339
+ throw new Error("oldString is ambiguous");
8340
+ }
8341
+ return currentContent.slice(0, first) + fields.newString + currentContent.slice(first + fields.oldString.length);
8342
+ }
8343
+ function computeExpiresAt(source) {
8344
+ const ttlDays = TTL_DEFAULTS[source];
8345
+ if (ttlDays == null)
8346
+ return null;
8347
+ return new Date(Date.now() + ttlDays * 86400000).toISOString();
8348
+ }
8349
+
8350
+ class SqliteMemoryStore {
8351
+ vecInitialized = false;
8352
+ ftsInitialized = false;
8353
+ lastPopulate = null;
8354
+ constructor() {
8355
+ this.ensureVecTable();
8356
+ this.ensureFtsTable();
8357
+ }
8358
+ ensureFtsTable() {
8359
+ if (this.ftsInitialized)
8360
+ return;
8361
+ const db = getDb();
8362
+ try {
8363
+ db.run(`
8364
+ CREATE VIRTUAL TABLE IF NOT EXISTS memory_fts USING fts5(
8365
+ memory_id UNINDEXED,
8366
+ name,
8367
+ content,
8368
+ tokenize='porter unicode61'
8369
+ )
8370
+ `);
8371
+ this.populateFtsTable();
8372
+ this.ftsInitialized = true;
8373
+ } catch (err) {
8374
+ this.ftsInitialized = false;
8375
+ console.error("[memory-fts] Failed to initialize memory_fts:", err.message);
8376
+ }
8377
+ }
8378
+ async getFtsTableSchema() {
8379
+ try {
8380
+ const row = await getDbClient().get("SELECT sql FROM sqlite_master WHERE type = 'table' AND name = 'memory_fts'");
8381
+ return row?.sql ?? null;
8382
+ } catch {
8383
+ return null;
8384
+ }
8385
+ }
8386
+ populateFtsTable() {
8387
+ const db = getDb();
8388
+ const deletedExtra = db.prepare(`DELETE FROM memory_fts
8389
+ WHERE memory_id NOT IN (SELECT id FROM agent_memory)`).run();
8390
+ if (deletedExtra.changes > 0) {
8391
+ console.warn(`[memory-fts] removed_extra_rows count=${deletedExtra.changes}`);
8392
+ }
8393
+ const inserted = db.prepare(`INSERT INTO memory_fts(memory_id, name, content)
8394
+ SELECT m.id, m.name, m.content
8395
+ FROM agent_memory m
8396
+ WHERE NOT EXISTS (SELECT 1 FROM memory_fts f WHERE f.memory_id = m.id)`).run();
8397
+ console.log(`[memory-fts] populate inserted=${inserted.changes}`);
8398
+ }
8399
+ async syncFtsRow(memoryId, name, content) {
8400
+ if (!this.ftsInitialized && !await this.getFtsTableSchema())
8401
+ return;
8402
+ try {
8403
+ await getDbClient().run("DELETE FROM memory_fts WHERE memory_id = ?", [memoryId]);
8404
+ await getDbClient().run("INSERT INTO memory_fts(memory_id, name, content) VALUES (?, ?, ?)", [
8405
+ memoryId,
8406
+ name,
8407
+ content
8408
+ ]);
8409
+ } catch (err) {
8410
+ console.error(`[memory-fts] sync failed memory_id=${memoryId}: ${err.message}`);
8411
+ }
8412
+ }
8413
+ async deleteFtsRows(ids) {
8414
+ if (ids.length === 0 || !await this.getFtsTableSchema())
8415
+ return;
8416
+ const placeholders = ids.map(() => "?").join(",");
8417
+ await getDbClient().run(`DELETE FROM memory_fts WHERE memory_id IN (${placeholders})`, ids);
8418
+ }
8419
+ ensureVecTable() {
8420
+ if (this.vecInitialized)
8421
+ return;
8422
+ if (!isSqliteVecAvailable()) {
8423
+ console.warn("[memory-vec] sqlite-vec extension_loaded=false; retrieval_mode=fallback");
8424
+ return;
8425
+ }
8426
+ const db = getDb();
8427
+ try {
8428
+ console.log(`[memory-vec] sqlite-vec extension_loaded=true vector_dimensions=${EMBEDDING_DIMENSIONS}`);
8429
+ const existingSchema = this.getVecTableSchema();
8430
+ if (existingSchema && !existingSchema.includes("distance_metric=cosine")) {
8431
+ console.warn("[memory-vec] Existing memory_vec table is missing cosine distance metric; rebuilding from agent_memory");
8432
+ db.run("DROP TABLE memory_vec");
8433
+ }
8434
+ db.run(`
8435
+ CREATE VIRTUAL TABLE IF NOT EXISTS memory_vec USING vec0(
8436
+ memory_id TEXT PRIMARY KEY,
8437
+ embedding float[${EMBEDDING_DIMENSIONS}] distance_metric=cosine
8438
+ )
8439
+ `);
8440
+ const healthBefore = this.getHealthCounts();
8441
+ if (healthBefore.missingFromVec > 0 || healthBefore.extraInVec > 0) {
8442
+ this.populateVecTable(healthBefore.memoryVec);
8443
+ } else {
8444
+ console.log(`[memory-vec] populate skipped attempted=0 inserted=0 memory_vec=${healthBefore.memoryVec} valid_embedding=${healthBefore.validEmbedding}`);
8445
+ }
8446
+ this.vecInitialized = true;
8447
+ } catch (err) {
8448
+ this.vecInitialized = false;
8449
+ console.error("[memory-vec] Failed to initialize memory_vec:", err.message);
8450
+ }
8451
+ }
8452
+ getVecTableSchema() {
8453
+ try {
8454
+ return getDb().prepare("SELECT sql FROM sqlite_master WHERE type = 'table' AND name = 'memory_vec'").get()?.sql ?? null;
8455
+ } catch {
8456
+ return null;
8457
+ }
8458
+ }
8459
+ getVecCount() {
8460
+ if (!this.getVecTableSchema())
8461
+ return 0;
8462
+ return getDb().prepare("SELECT COUNT(*) as count FROM memory_vec").get()?.count ?? 0;
8463
+ }
8464
+ populateVecTable(beforeCount) {
8465
+ const db = getDb();
8466
+ const deletedExtra = db.prepare(`DELETE FROM memory_vec
8467
+ WHERE memory_id NOT IN (SELECT id FROM agent_memory)`).run();
8468
+ if (deletedExtra.changes > 0) {
8469
+ console.warn(`[memory-vec] removed_extra_rows count=${deletedExtra.changes}`);
8470
+ }
8471
+ const rows = db.prepare("SELECT id, embedding FROM agent_memory WHERE embedding IS NOT NULL").all();
8472
+ const deleteVec = db.prepare("DELETE FROM memory_vec WHERE memory_id = ?");
8473
+ const insertVec = db.prepare("INSERT INTO memory_vec(memory_id, embedding) VALUES (?, ?)");
8474
+ let attempted = 0;
8475
+ let inserted = 0;
8476
+ let skippedInvalidDimensions = 0;
8477
+ let failed = 0;
8478
+ for (const row of rows) {
8479
+ const embeddingBuffer = this.toVecBuffer(row.embedding);
8480
+ if (!embeddingBuffer) {
8481
+ skippedInvalidDimensions++;
8482
+ continue;
8483
+ }
8484
+ attempted++;
8485
+ try {
8486
+ deleteVec.run(row.id);
8487
+ insertVec.run(row.id, embeddingBuffer);
8488
+ inserted++;
8489
+ } catch (err) {
8490
+ failed++;
8491
+ console.error(`[memory-vec] populate failed memory_id=${row.id}: ${err.message}`);
8492
+ }
8493
+ }
8494
+ const afterCount = this.getVecCount();
8495
+ this.lastPopulate = {
8496
+ attempted,
8497
+ inserted,
8498
+ skippedInvalidDimensions,
8499
+ failed,
8500
+ beforeCount,
8501
+ afterCount
8502
+ };
8503
+ console.log(`[memory-vec] populate attempted=${attempted} inserted=${inserted} skipped_invalid_dimensions=${skippedInvalidDimensions} failed=${failed} before_count=${beforeCount} after_count=${afterCount}`);
8504
+ if (failed > 0 || afterCount < attempted) {
8505
+ console.error(`[memory-vec] populate incomplete attempted=${attempted} after_count=${afterCount} failed=${failed}`);
8506
+ }
8507
+ }
8508
+ toVecBuffer(embedding) {
8509
+ if (embedding instanceof Float32Array) {
8510
+ if (embedding.length !== EMBEDDING_DIMENSIONS)
8511
+ return null;
8512
+ return serializeEmbedding(embedding);
8513
+ }
8514
+ if (embedding.length !== VECTOR_BYTES)
8515
+ return null;
8516
+ return embedding;
8517
+ }
8518
+ async store(input) {
8519
+ const id = crypto.randomUUID();
8520
+ const now = new Date().toISOString();
8521
+ const expiresAt = computeExpiresAt(input.source);
8522
+ const key = input.key ?? `${input.scope}/${input.source}/${id}`;
8523
+ const contentHash = contentSha256(input.content);
8524
+ const version = 1;
8525
+ const row = await getDbClient().transaction(async (tx) => {
8526
+ 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)
8527
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING *`, [
8528
+ id,
8529
+ input.agentId ?? null,
8530
+ input.scope,
8531
+ key,
8532
+ input.name,
8533
+ input.content,
8534
+ input.summary ?? null,
8535
+ input.source,
8536
+ input.sourceTaskId ?? null,
8537
+ input.sourcePath ?? null,
8538
+ input.chunkIndex ?? 0,
8539
+ input.totalChunks ?? 1,
8540
+ JSON.stringify(input.tags ?? []),
8541
+ now,
8542
+ now,
8543
+ now,
8544
+ expiresAt,
8545
+ 0,
8546
+ null,
8547
+ input.contextKey ?? null,
8548
+ contentHash,
8549
+ version
8550
+ ]);
8551
+ if (!inserted)
8552
+ throw new Error("Failed to create memory");
8553
+ await tx.run(`INSERT INTO agent_memory_version (id, memory_id, version, content, contentHash, intent, operation, changedByAgentId, createdAt, updatedAt, created_by, updated_by)
8554
+ VALUES (?, ?, ?, ?, ?, ?, 'create', ?, ?, ?, ?, ?)`, [
8555
+ crypto.randomUUID(),
8556
+ inserted.id,
8557
+ version,
8558
+ input.content,
8559
+ contentHash,
8560
+ input.intent ?? "create memory",
8561
+ input.agentId ?? null,
8562
+ now,
8563
+ now,
8564
+ input.agentId ?? null,
8565
+ input.agentId ?? null
8566
+ ]);
8567
+ return inserted;
8568
+ });
8569
+ await this.syncFtsRow(row.id, row.name, row.content);
8570
+ return rowToAgentMemory(row);
8571
+ }
8572
+ async storeBatch(inputs) {
8573
+ const results = [];
8574
+ await getDbClient().transaction(async () => {
8575
+ for (const input of inputs) {
8576
+ results.push(await this.store(input));
8577
+ }
8578
+ });
8579
+ return results;
8580
+ }
8581
+ async get(id) {
8582
+ const db = getDbClient();
8583
+ const row = await db.get("SELECT * FROM agent_memory WHERE id = ?", [id]);
8584
+ if (!row)
8585
+ return null;
8586
+ await db.run("UPDATE agent_memory SET accessedAt = ?, accessCount = accessCount + 1 WHERE id = ?", [new Date().toISOString(), id]);
8587
+ return rowToAgentMemory(row);
8588
+ }
8589
+ async peek(id) {
8590
+ const row = await getDbClient().get("SELECT * FROM agent_memory WHERE id = ?", [
8591
+ id
8592
+ ]);
8593
+ if (!row)
8594
+ return null;
8595
+ return rowToAgentMemory(row);
8596
+ }
8597
+ async search(embedding, agentId, options = {}) {
8598
+ const { scope = "all", limit: limit2 = 10, source, isLead = false, includeExpired = false } = options;
8599
+ const health = this.getHealth();
8600
+ if (isHybridSearchEnabled() && options.queryText && this.ftsInitialized && await this.getFtsTableSchema() && health.retrievalMode === "vec" && embedding.length === EMBEDDING_DIMENSIONS) {
8601
+ console.log(`[memory-search] retrieval_path=hybrid scope=${scope} limit=${limit2} vec_rows=${health.counts.memoryVec} searchable=${health.counts.searchable}`);
8602
+ return this.searchHybrid(embedding, options.queryText, agentId, {
8603
+ scope,
8604
+ limit: limit2,
8605
+ source,
8606
+ isLead,
8607
+ includeExpired
8608
+ });
8609
+ }
8610
+ if (health.retrievalMode === "vec" && embedding.length === EMBEDDING_DIMENSIONS) {
8611
+ console.log(`[memory-search] retrieval_path=vec scope=${scope} limit=${limit2} vec_rows=${health.counts.memoryVec} searchable=${health.counts.searchable}`);
8612
+ return this.searchWithVec(embedding, agentId, {
8613
+ scope,
8614
+ limit: limit2,
8615
+ source,
8616
+ isLead,
8617
+ includeExpired
8618
+ });
8619
+ }
8620
+ if (options.queryText && this.ftsInitialized && await this.getFtsTableSchema()) {
8621
+ console.log(`[memory-search] retrieval_path=fts scope=${scope} limit=${limit2} reason=${embedding.length !== EMBEDDING_DIMENSIONS ? "query_dimension_mismatch" : health.reasons.join("|") || "vec_unavailable"}`);
8622
+ return this.searchFts(options.queryText, agentId, {
8623
+ scope,
8624
+ limit: limit2,
8625
+ source,
8626
+ isLead,
8627
+ includeExpired
8628
+ });
8629
+ }
8630
+ console.log(`[memory-search] retrieval_path=fallback scope=${scope} limit=${limit2} reason=${embedding.length !== EMBEDDING_DIMENSIONS ? "query_dimension_mismatch" : health.reasons.join("|") || "vec_unavailable"}`);
8631
+ return this.searchBruteForce(embedding, agentId, {
8632
+ scope,
8633
+ limit: limit2,
8634
+ source,
8635
+ isLead,
8636
+ includeExpired
8637
+ });
8638
+ }
8639
+ async searchHybrid(queryEmbedding, queryText, agentId, options) {
8640
+ const overfetchLimit = Math.min(Math.max(options.limit * 4, options.limit), 100);
8641
+ const vectorCandidates = await this.searchWithVec(queryEmbedding, agentId, {
8642
+ ...options,
8643
+ limit: overfetchLimit
8644
+ });
8645
+ const ftsCandidates = await this.searchFts(queryText, agentId, {
8646
+ ...options,
8647
+ limit: overfetchLimit
8648
+ });
8649
+ const byId = new Map;
8650
+ const rrf = new Map;
8651
+ const cosines = new Map;
8652
+ const sources = new Map;
8653
+ const add = (candidate, rank) => {
8654
+ byId.set(candidate.id, byId.get(candidate.id) ?? candidate);
8655
+ const retrievalSource = candidate.retrievalSource === "fts" ? "fts" : "vec";
8656
+ const candidateSources = sources.get(candidate.id) ?? new Set;
8657
+ candidateSources.add(retrievalSource);
8658
+ sources.set(candidate.id, candidateSources);
8659
+ if (retrievalSource === "vec")
8660
+ cosines.set(candidate.id, candidate.similarity);
8661
+ rrf.set(candidate.id, (rrf.get(candidate.id) ?? 0) + computeRrfScore(rank, 1));
8662
+ };
8663
+ vectorCandidates.forEach(add);
8664
+ ftsCandidates.forEach(add);
8665
+ await this.fillCosines(queryEmbedding, [...byId.keys()], cosines);
8666
+ return [...byId.values()].map((candidate) => {
8667
+ const similarity = fusedSimilarity(cosines.get(candidate.id) ?? 0, rrf.get(candidate.id) ?? 0);
8668
+ return {
8669
+ ...candidate,
8670
+ rawSimilarity: similarity,
8671
+ similarity,
8672
+ retrievalSource: retrievalSourceFor(sources.get(candidate.id) ?? new Set),
8673
+ recencyDecayApplied: false
8674
+ };
8675
+ }).sort((a, b) => b.similarity - a.similarity).slice(0, options.limit);
8676
+ }
8677
+ async fillCosines(queryEmbedding, ids, cosines) {
8678
+ const missing = ids.filter((id) => !cosines.has(id));
8679
+ if (missing.length === 0)
8680
+ return;
8681
+ const rows = await getDbClient().query(`SELECT id, embedding FROM agent_memory WHERE id IN (${missing.map(() => "?").join(",")})`, missing);
8682
+ for (const row of rows) {
8683
+ if (!row.embedding)
8684
+ continue;
8685
+ const embedding = deserializeEmbedding(row.embedding);
8686
+ if (embedding.length !== queryEmbedding.length)
8687
+ continue;
8688
+ cosines.set(row.id, Math.max(0, cosineSimilarity(queryEmbedding, embedding)));
8689
+ }
8690
+ }
8691
+ async searchFts(queryText, agentId, options) {
8692
+ const match = this.buildFtsMatch(queryText);
8693
+ if (!match)
8694
+ return [];
8695
+ const { scope, limit: limit2, source, isLead, includeExpired } = options;
8696
+ const conditions = ["memory_fts MATCH ?"];
8697
+ const params = [match];
8698
+ this.addScopeConditions(conditions, params, agentId, scope, isLead, "m");
8699
+ if (source) {
8700
+ conditions.push("m.source = ?");
8701
+ params.push(source);
8702
+ }
8703
+ if (!includeExpired) {
8704
+ conditions.push("(m.expiresAt IS NULL OR m.expiresAt > datetime('now'))");
8705
+ }
8706
+ try {
8707
+ const sqlLimit = Math.min(Math.max(limit2 * 4, limit2), 100);
8708
+ const rows = await getDbClient().query(`SELECT m.*, bm25(memory_fts) AS rank
8709
+ FROM memory_fts
8710
+ JOIN agent_memory m ON m.id = memory_fts.memory_id
8711
+ WHERE ${conditions.join(" AND ")}
8712
+ ORDER BY rank
8713
+ LIMIT ?`, [...params, sqlLimit]);
8714
+ const now = new Date;
8715
+ return rows.map((row, index) => {
8716
+ const rawSimilarity = 1 / (index + 1);
8717
+ return {
8718
+ ...rowToCandidate(row, rawSimilarity * recencyDecay(row.createdAt, now, row.source)),
8719
+ rawSimilarity,
8720
+ retrievalSource: "fts",
8721
+ recencyDecayApplied: true
8722
+ };
8723
+ }).sort((a, b) => b.similarity - a.similarity).slice(0, limit2);
8724
+ } catch (err) {
8725
+ console.warn("[memory-fts] query failed:", err.message);
8726
+ return [];
8727
+ }
8728
+ }
8729
+ buildFtsMatch(queryText) {
8730
+ const terms = queryText.trim().split(/[^\p{L}\p{N}_-]+/u).map((term) => term.trim()).filter((term) => term.length > 0).slice(0, 12);
8731
+ if (terms.length === 0)
8732
+ return null;
8733
+ return terms.map((term) => `"${term.replaceAll('"', '""')}"`).join(" OR ");
8734
+ }
8735
+ async searchWithVec(queryEmbedding, agentId, options) {
8736
+ const { scope, limit: limit2, source, isLead, includeExpired } = options;
8737
+ const embeddingBuffer = serializeEmbedding(queryEmbedding);
8738
+ const knnLimit = Math.min(Math.max(limit2, this.getVecCount()), 4096);
8739
+ const conditions = ["v.embedding MATCH ?"];
8740
+ const params = [embeddingBuffer];
8741
+ this.addScopeConditions(conditions, params, agentId, scope, isLead, "m");
8742
+ if (source) {
8743
+ conditions.push("m.source = ?");
8744
+ params.push(source);
8745
+ }
8746
+ if (!includeExpired) {
8747
+ conditions.push("(m.expiresAt IS NULL OR m.expiresAt > datetime('now'))");
8748
+ }
8749
+ conditions.push("v.k = ?");
8750
+ params.push(knnLimit);
8751
+ const rows = await getDbClient().query(`SELECT m.*, v.distance
8752
+ FROM memory_vec v
8753
+ JOIN agent_memory m ON m.id = v.memory_id
8754
+ WHERE ${conditions.join(" AND ")}
8755
+ ORDER BY v.distance
8756
+ LIMIT ?`, [...params, limit2]);
8757
+ const candidates = [];
8758
+ for (const row of rows) {
8759
+ const similarity = 1 - row.distance;
8760
+ if (similarity < minSimilarity())
8761
+ continue;
8762
+ candidates.push({ ...rowToCandidate(row, similarity), retrievalSource: "vec" });
8763
+ }
8764
+ return candidates;
8765
+ }
8766
+ async searchBruteForce(queryEmbedding, agentId, options) {
8767
+ const { scope, limit: limit2, source, isLead, includeExpired } = options;
8768
+ const conditions = ["embedding IS NOT NULL"];
8769
+ const params = [];
8770
+ this.addScopeConditions(conditions, params, agentId, scope, isLead);
8771
+ if (source) {
8772
+ conditions.push("source = ?");
8773
+ params.push(source);
8774
+ }
8775
+ if (!includeExpired) {
8776
+ conditions.push("(expiresAt IS NULL OR expiresAt > datetime('now'))");
8777
+ }
8778
+ const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
8779
+ const rows = await getDbClient().query(`SELECT * FROM agent_memory ${whereClause}`, params);
8780
+ const candidates = [];
8781
+ for (const row of rows) {
8782
+ if (!row.embedding)
8783
+ continue;
8784
+ const emb = deserializeEmbedding(row.embedding);
8785
+ if (emb.length !== queryEmbedding.length)
8786
+ continue;
8787
+ const similarity = cosineSimilarity(queryEmbedding, emb);
8788
+ if (similarity < minSimilarity())
8789
+ continue;
8790
+ candidates.push({ ...rowToCandidate(row, similarity), retrievalSource: "fallback" });
8791
+ }
8792
+ candidates.sort((a, b) => b.similarity - a.similarity);
8793
+ return candidates.slice(0, limit2);
8794
+ }
8795
+ addScopeConditions(conditions, params, agentId, scope, isLead, tableAlias = "") {
8796
+ const col = (name) => tableAlias ? `${tableAlias}.${name}` : name;
8797
+ if (!isLead) {
8798
+ if (scope === "agent") {
8799
+ conditions.push(`${col("agentId")} = ? AND ${col("scope")} = 'agent'`);
8800
+ params.push(agentId);
8801
+ } else if (scope === "swarm") {
8802
+ conditions.push(`${col("scope")} = 'swarm'`);
8803
+ } else {
8804
+ conditions.push(`(${col("agentId")} = ? OR ${col("scope")} = 'swarm')`);
8805
+ params.push(agentId);
8806
+ }
8807
+ } else {
8808
+ if (scope === "agent") {
8809
+ conditions.push(`${col("scope")} = 'agent'`);
8810
+ } else if (scope === "swarm") {
8811
+ conditions.push(`${col("scope")} = 'swarm'`);
8812
+ }
8813
+ }
8814
+ }
8815
+ buildListWhereClause(agentId, options) {
8816
+ const { scope = "all", isLead = false, ownerAgentId, source, sourcePath } = options;
8817
+ const conditions = [];
8818
+ const params = [];
8819
+ this.addScopeConditions(conditions, params, agentId, scope, isLead);
8820
+ if (ownerAgentId) {
8821
+ conditions.push("agentId = ?");
8822
+ params.push(ownerAgentId);
8823
+ }
8824
+ if (source) {
8825
+ conditions.push("source = ?");
8826
+ params.push(source);
8827
+ }
8828
+ const sourcePathNeedle = sourcePath?.trim().toLowerCase();
8829
+ if (sourcePathNeedle) {
8830
+ conditions.push("instr(lower(coalesce(sourcePath, '')), ?) > 0");
8831
+ params.push(sourcePathNeedle);
8832
+ }
8833
+ return {
8834
+ whereClause: conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "",
8835
+ params
8836
+ };
8837
+ }
8838
+ async list(agentId, options = {}) {
8839
+ const { limit: limit2 = 20, offset = 0 } = options;
8840
+ const { whereClause, params } = this.buildListWhereClause(agentId, options);
8841
+ const queryParams = [...params, limit2, offset];
8842
+ const rows = await getDbClient().query(`SELECT * FROM agent_memory ${whereClause} ORDER BY createdAt DESC LIMIT ? OFFSET ?`, queryParams);
8843
+ return rows.map(rowToAgentMemory);
8844
+ }
8845
+ async count(agentId, options = {}) {
8846
+ const { whereClause, params } = this.buildListWhereClause(agentId, options);
8847
+ const row = await getDbClient().get(`SELECT COUNT(*) AS count FROM agent_memory ${whereClause}`, params);
8848
+ return row?.count ?? 0;
8849
+ }
8850
+ isSourceProtected(source) {
8851
+ return PROTECTED_SOURCES.has(source);
8852
+ }
8853
+ async edit(input) {
8854
+ if (!input.id && !(input.key && input.scope)) {
8855
+ throw new Error("memory edit requires either id or key+scope");
8856
+ }
8857
+ const { result, ftsContent } = await getDbClient().transaction(async (tx) => {
8858
+ const row = input.id ? await tx.get("SELECT * FROM agent_memory WHERE id = ?", [input.id]) : await tx.get(`SELECT * FROM agent_memory
8859
+ WHERE key = ? AND scope = ? AND coalesce(agentId, '') = coalesce(?, '')
8860
+ ORDER BY chunkIndex ASC
8861
+ LIMIT 1`, [input.key, input.scope, input.agentId ?? null]);
8862
+ if (!row)
8863
+ throw new Error("memory not found");
8864
+ if ((row.totalChunks ?? 1) !== 1)
8865
+ throw new Error("memory edit only supports single-chunk rows");
8866
+ if (input.expectedVersion && input.expectedVersion !== (row.version ?? 1)) {
8867
+ throw new Error("memory version conflict");
8868
+ }
8869
+ const previousVersion = row.version ?? 1;
8870
+ const nextContent = applyEditMode(input.mode, row.content, {
8871
+ content: input.content,
8872
+ oldString: input.oldString,
8873
+ newString: input.newString
8874
+ });
8875
+ const nextHash = contentSha256(nextContent);
8876
+ if (nextHash === row.contentHash) {
8877
+ return {
8878
+ result: {
8879
+ memory: rowToAgentMemory(row),
8880
+ changed: false,
8881
+ previousVersion,
8882
+ version: previousVersion,
8883
+ contentHash: nextHash
8884
+ },
8885
+ ftsContent: null
8886
+ };
8887
+ }
8888
+ const nextVersion = previousVersion + 1;
8889
+ const now = new Date().toISOString();
8890
+ await tx.run(`INSERT INTO agent_memory_version (id, memory_id, version, content, contentHash, intent, operation, changedByAgentId, createdAt, updatedAt, created_by, updated_by)
8891
+ VALUES (?, ?, ?, ?, ?, ?, 'edit', ?, ?, ?, ?, ?)`, [
8892
+ crypto.randomUUID(),
8893
+ row.id,
8894
+ nextVersion,
8895
+ nextContent,
8896
+ nextHash,
8897
+ input.intent,
8898
+ input.changedByAgentId ?? null,
8899
+ now,
8900
+ now,
8901
+ input.changedByAgentId ?? null,
8902
+ input.changedByAgentId ?? null
8903
+ ]);
8904
+ await tx.run(`UPDATE agent_memory
8905
+ SET content = ?, contentHash = ?, version = ?, updatedAt = ?
8906
+ WHERE id = ?`, [nextContent, nextHash, nextVersion, now, row.id]);
8907
+ return {
8908
+ result: {
8909
+ memory: rowToAgentMemory({
8910
+ ...row,
8911
+ content: nextContent,
8912
+ contentHash: nextHash,
8913
+ version: nextVersion,
8914
+ updatedAt: now
8915
+ }),
8916
+ changed: true,
8917
+ previousVersion,
8918
+ version: nextVersion,
8919
+ contentHash: nextHash
8920
+ },
8921
+ ftsContent: nextContent
8922
+ };
8923
+ });
8924
+ if (ftsContent !== null) {
8925
+ await this.syncFtsRow(result.memory.id, result.memory.name, ftsContent);
8926
+ }
8927
+ return result;
8928
+ }
8929
+ async listForCuration(agentId) {
8930
+ const db = getDbClient();
8931
+ const protectedList = [...PROTECTED_SOURCES].map((s) => `'${s}'`).join(",");
8932
+ if (agentId) {
8933
+ return db.query(`SELECT id, source, name, createdAt FROM agent_memory
8934
+ WHERE agentId = ? AND source NOT IN (${protectedList})`, [agentId]);
8935
+ }
8936
+ return db.query(`SELECT id, source, name, createdAt FROM agent_memory
8937
+ WHERE source NOT IN (${protectedList})`);
8938
+ }
8939
+ async listForReembedding(options) {
8940
+ const db = getDbClient();
8941
+ if (options?.agentId) {
8942
+ return db.query("SELECT id, content FROM agent_memory WHERE agentId = ?", [options.agentId]);
8943
+ }
8944
+ return db.query("SELECT id, content FROM agent_memory");
8945
+ }
8946
+ async purgeByIds(ids) {
8947
+ if (ids.length === 0)
8948
+ return;
8949
+ if (this.vecInitialized && this.getVecTableSchema()) {
8950
+ const placeholders = ids.map(() => "?").join(",");
8951
+ await getDbClient().run(`DELETE FROM memory_vec WHERE memory_id IN (${placeholders})`, ids);
8952
+ }
8953
+ await this.deleteFtsRows(ids);
8954
+ }
8955
+ async delete(id) {
8956
+ await this.purgeByIds([id]);
8957
+ const result = await getDbClient().run("DELETE FROM agent_memory WHERE id = ?", [id]);
8958
+ return result.changes > 0;
8959
+ }
8960
+ async deleteBySourcePath(sourcePath, agentId) {
8961
+ const db = getDbClient();
8962
+ const ids = await db.query("SELECT id FROM agent_memory WHERE sourcePath = ? AND agentId = ?", [sourcePath, agentId]);
8963
+ await this.purgeByIds(ids.map((r) => r.id));
8964
+ const result = await db.run("DELETE FROM agent_memory WHERE sourcePath = ? AND agentId = ?", [
8965
+ sourcePath,
8966
+ agentId
8967
+ ]);
8968
+ return ids.length || result.changes;
8969
+ }
8970
+ async purgeExpired() {
8971
+ const db = getDbClient();
8972
+ const expiredIds = await db.query("SELECT id FROM agent_memory WHERE expiresAt IS NOT NULL AND expiresAt <= datetime('now')");
8973
+ if (expiredIds.length === 0)
8974
+ return 0;
8975
+ const batchSize = 500;
8976
+ for (let i = 0;i < expiredIds.length; i += batchSize) {
8977
+ await this.purgeByIds(expiredIds.slice(i, i + batchSize).map((r) => r.id));
8978
+ }
8979
+ const result = await db.run("DELETE FROM agent_memory WHERE expiresAt IS NOT NULL AND expiresAt <= datetime('now')");
8980
+ console.log(`[memory] Purged ${result.changes} expired memory row(s) (vec cleanup: ${expiredIds.length} id(s))`);
8981
+ return result.changes;
8982
+ }
8983
+ async updateEmbedding(id, embedding, model) {
8984
+ const db = getDbClient();
8985
+ const buffer = serializeEmbedding(embedding);
8986
+ await db.run("UPDATE agent_memory SET embedding = ?, embeddingModel = ? WHERE id = ?", [
8987
+ buffer,
8988
+ model,
8989
+ id
8990
+ ]);
8991
+ if (this.vecInitialized && this.getVecTableSchema()) {
8992
+ const vecBuffer = this.toVecBuffer(embedding);
8993
+ if (!vecBuffer) {
8994
+ console.warn(`[memory-vec] update skipped memory_id=${id} reason=invalid_dimensions dimensions=${embedding.length} expected=${EMBEDDING_DIMENSIONS}`);
8995
+ return;
8996
+ }
8997
+ try {
8998
+ await db.run("DELETE FROM memory_vec WHERE memory_id = ?", [id]);
8999
+ await db.run("INSERT INTO memory_vec(memory_id, embedding) VALUES (?, ?)", [id, vecBuffer]);
9000
+ } catch (err) {
9001
+ console.error(`[memory-vec] update failed memory_id=${id}: ${err.message}`);
9002
+ }
9003
+ }
9004
+ }
9005
+ async getStats(agentId) {
9006
+ const db = getDbClient();
9007
+ const total = await db.get("SELECT COUNT(*) as count FROM agent_memory WHERE agentId = ?", [agentId]);
9008
+ const bySourceRows = await db.query("SELECT source, COUNT(*) as count FROM agent_memory WHERE agentId = ? GROUP BY source", [agentId]);
9009
+ const byScopeRows = await db.query("SELECT scope, COUNT(*) as count FROM agent_memory WHERE agentId = ? GROUP BY scope", [agentId]);
9010
+ const withEmbeddings = await db.get("SELECT COUNT(*) as count FROM agent_memory WHERE agentId = ? AND embedding IS NOT NULL", [agentId]);
9011
+ const expired = await db.get("SELECT COUNT(*) as count FROM agent_memory WHERE agentId = ? AND expiresAt IS NOT NULL AND expiresAt <= datetime('now')", [agentId]);
9012
+ const bySource = {};
9013
+ for (const row of bySourceRows)
9014
+ bySource[row.source] = row.count;
9015
+ const byScope = {};
9016
+ for (const row of byScopeRows)
9017
+ byScope[row.scope] = row.count;
9018
+ return {
9019
+ total: total?.count ?? 0,
9020
+ bySource,
9021
+ byScope,
9022
+ withEmbeddings: withEmbeddings?.count ?? 0,
9023
+ expired: expired?.count ?? 0
9024
+ };
9025
+ }
9026
+ getHealthCounts() {
9027
+ const db = getDb();
9028
+ const tableExists = this.getVecTableSchema() !== null;
9029
+ const tableUsable = tableExists && isSqliteVecAvailable();
9030
+ const count = (sql) => db.prepare(sql).get()?.count ?? 0;
9031
+ return {
9032
+ total: count("SELECT COUNT(*) as count FROM agent_memory"),
9033
+ withEmbedding: count("SELECT COUNT(*) as count FROM agent_memory WHERE embedding IS NOT NULL"),
9034
+ validEmbedding: count(`SELECT COUNT(*) as count FROM agent_memory WHERE embedding IS NOT NULL AND length(embedding) = ${VECTOR_BYTES}`),
9035
+ invalidEmbedding: count(`SELECT COUNT(*) as count FROM agent_memory WHERE embedding IS NOT NULL AND length(embedding) != ${VECTOR_BYTES}`),
9036
+ searchable: count(`SELECT COUNT(*) as count FROM agent_memory
9037
+ WHERE embedding IS NOT NULL
9038
+ AND length(embedding) = ${VECTOR_BYTES}
9039
+ AND (expiresAt IS NULL OR expiresAt > datetime('now'))`),
9040
+ memoryVec: tableUsable ? count("SELECT COUNT(*) as count FROM memory_vec") : 0,
9041
+ missingFromVec: tableUsable ? count(`SELECT COUNT(*) as count
9042
+ FROM agent_memory m
9043
+ LEFT JOIN memory_vec v ON v.memory_id = m.id
9044
+ WHERE m.embedding IS NOT NULL
9045
+ AND length(m.embedding) = ${VECTOR_BYTES}
9046
+ AND v.memory_id IS NULL`) : count(`SELECT COUNT(*) as count FROM agent_memory WHERE embedding IS NOT NULL AND length(embedding) = ${VECTOR_BYTES}`),
9047
+ extraInVec: tableUsable ? count(`SELECT COUNT(*) as count
9048
+ FROM memory_vec v
9049
+ LEFT JOIN agent_memory m ON m.id = v.memory_id
9050
+ WHERE m.id IS NULL`) : 0
9051
+ };
9052
+ }
9053
+ getHealth() {
9054
+ const schema = this.getVecTableSchema();
9055
+ const counts = this.getHealthCounts();
9056
+ const reasons = [];
9057
+ if (!isSqliteVecAvailable())
9058
+ reasons.push("sqlite_vec_extension_unavailable");
9059
+ if (!schema)
9060
+ reasons.push("memory_vec_table_missing");
9061
+ if (!this.vecInitialized)
9062
+ reasons.push("memory_vec_not_initialized");
9063
+ if (counts.memoryVec === 0)
9064
+ reasons.push("memory_vec_empty");
9065
+ if (counts.missingFromVec > 0)
9066
+ reasons.push("memory_vec_missing_embeddings");
9067
+ if (counts.extraInVec > 0)
9068
+ reasons.push("memory_vec_extra_rows");
9069
+ return {
9070
+ sqliteVec: {
9071
+ extensionLoaded: isSqliteVecAvailable(),
9072
+ tableExists: schema !== null,
9073
+ initialized: this.vecInitialized,
9074
+ vectorDimensions: EMBEDDING_DIMENSIONS,
9075
+ distanceMetric: "cosine",
9076
+ schema,
9077
+ lastPopulate: this.lastPopulate
9078
+ },
9079
+ counts,
9080
+ retrievalMode: reasons.length === 0 ? "vec" : "fallback",
9081
+ reasons
9082
+ };
9083
+ }
9084
+ }
9085
+ var VECTOR_BYTES;
9086
+ var init_sqlite_store = __esm(() => {
9087
+ init_db();
9088
+ init_embedding();
9089
+ init_profile_sync();
9090
+ init_constants();
9091
+ init_reranker();
9092
+ VECTOR_BYTES = EMBEDDING_DIMENSIONS * Float32Array.BYTES_PER_ELEMENT;
9093
+ });
9094
+
9095
+ // src/be/memory/index.ts
9096
+ var embeddingProvider = null;
9097
+ var memoryStore = null;
9098
+ function getEmbeddingProvider() {
9099
+ if (!embeddingProvider) {
9100
+ const { OpenAIEmbeddingProvider: OpenAIEmbeddingProvider2 } = (init_openai_embedding(), __toCommonJS(exports_openai_embedding));
9101
+ embeddingProvider = new OpenAIEmbeddingProvider2;
9102
+ }
9103
+ return embeddingProvider;
9104
+ }
9105
+ function resetEmbeddingProvider() {
9106
+ embeddingProvider = null;
9107
+ }
9108
+ function getMemoryStore() {
9109
+ if (!memoryStore) {
9110
+ const { SqliteMemoryStore: SqliteMemoryStore2 } = (init_sqlite_store(), __toCommonJS(exports_sqlite_store));
9111
+ memoryStore = new SqliteMemoryStore2;
9112
+ }
9113
+ return memoryStore;
9114
+ }
9115
+
9116
+ export { cosineSimilarity, serializeEmbedding, deserializeEmbedding, init_embedding, OpenAI, init_openai, CANDIDATE_SET_MULTIPLIER, isGraphExpansionEnabled, EMBEDDING_DIMENSIONS, init_constants, computeScore, rerank, init_reranker, rowToCandidate, init_sqlite_store, getEmbeddingProvider, resetEmbeddingProvider, getMemoryStore };