hippo-memory 1.71.0 → 2.0.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 (625) hide show
  1. package/README.md +7 -5
  2. package/dist/agent-memories/apply.d.ts +0 -11
  3. package/dist/agent-memories/apply.js +11 -26
  4. package/dist/agent-memories/claude-code.js +1 -1
  5. package/dist/agent-memories/codex.js +1 -1
  6. package/dist/agent-memories/copilot.d.ts +1 -3
  7. package/dist/agent-memories/copilot.js +1 -17
  8. package/dist/agent-memories/project-folds.d.ts +10 -0
  9. package/dist/agent-memories/project-folds.js +34 -0
  10. package/dist/agent-memories/sync.js +8 -6
  11. package/dist/api/assemble.js +3 -2
  12. package/dist/api/audit.d.ts +30 -2
  13. package/dist/api/audit.js +48 -7
  14. package/dist/api/auth.d.ts +11 -9
  15. package/dist/api/auth.js +39 -40
  16. package/dist/api/auto-sleep.d.ts +5 -2
  17. package/dist/api/auto-sleep.js +7 -3
  18. package/dist/api/availability.js +2 -3
  19. package/dist/api/cards.d.ts +42 -0
  20. package/dist/api/cards.js +52 -0
  21. package/dist/api/conflicts.d.ts +28 -0
  22. package/dist/api/conflicts.js +61 -0
  23. package/dist/api/context-auto.js +4 -2
  24. package/dist/api/context-render.js +4 -3
  25. package/dist/api/context-select.js +15 -29
  26. package/dist/api/context.js +29 -18
  27. package/dist/api/continuity.d.ts +47 -0
  28. package/dist/api/continuity.js +66 -0
  29. package/dist/api/dormant.js +4 -2
  30. package/dist/api/drill-down.js +3 -2
  31. package/dist/api/embeddings.d.ts +17 -0
  32. package/dist/api/embeddings.js +28 -0
  33. package/dist/api/error-reply.d.ts +8 -0
  34. package/dist/api/error-reply.js +21 -0
  35. package/dist/api/forget.d.ts +7 -3
  36. package/dist/api/forget.js +24 -14
  37. package/dist/api/goals.d.ts +1 -1
  38. package/dist/api/goals.js +5 -9
  39. package/dist/api/graph.js +2 -1
  40. package/dist/api/index.d.ts +4 -2
  41. package/dist/api/index.js +4 -2
  42. package/dist/api/instruction-detect.js +5 -1
  43. package/dist/api/learn.d.ts +5 -1
  44. package/dist/api/learn.js +71 -44
  45. package/dist/api/ledger-db.d.ts +2 -6
  46. package/dist/api/ledger-db.js +4 -36
  47. package/dist/api/memories.d.ts +21 -1
  48. package/dist/api/memories.js +51 -1
  49. package/dist/api/objects.d.ts +1 -1
  50. package/dist/api/objects.js +2 -1
  51. package/dist/api/outcome.d.ts +5 -5
  52. package/dist/api/outcome.js +17 -16
  53. package/dist/api/pilot-arm.d.ts +1 -11
  54. package/dist/api/pilot-arm.js +5 -45
  55. package/dist/api/predictions.d.ts +3 -1
  56. package/dist/api/predictions.js +8 -1
  57. package/dist/api/projects.d.ts +21 -0
  58. package/dist/api/projects.js +24 -0
  59. package/dist/api/promote.d.ts +3 -3
  60. package/dist/api/promote.js +26 -28
  61. package/dist/api/prompt-hook.d.ts +17 -2
  62. package/dist/api/prompt-hook.js +45 -4
  63. package/dist/api/quarantine.js +2 -1
  64. package/dist/api/recall-cli.d.ts +3 -0
  65. package/dist/api/recall-cli.js +13 -4
  66. package/dist/api/recall-core.js +10 -5
  67. package/dist/api/recall-pipeline.js +23 -24
  68. package/dist/api/recall-request.js +1 -1
  69. package/dist/api/recall-types.d.ts +3 -1
  70. package/dist/api/recall.d.ts +0 -3
  71. package/dist/api/recall.js +51 -73
  72. package/dist/api/remember-local.d.ts +5 -2
  73. package/dist/api/remember-local.js +15 -7
  74. package/dist/api/remember.d.ts +7 -3
  75. package/dist/api/remember.js +19 -16
  76. package/dist/api/session-end.d.ts +46 -0
  77. package/dist/api/session-end.js +131 -0
  78. package/dist/api/sleep-run.d.ts +1 -1
  79. package/dist/api/sleep-run.js +16 -11
  80. package/dist/api/sleep.js +4 -3
  81. package/dist/api/status.d.ts +24 -0
  82. package/dist/api/status.js +40 -0
  83. package/dist/api/store-init.d.ts +4 -0
  84. package/dist/api/store-init.js +9 -0
  85. package/dist/api/tokens.js +2 -2
  86. package/dist/api/types.d.ts +3 -7
  87. package/dist/api/types.js +6 -1
  88. package/dist/capture/caller-session.d.ts +0 -3
  89. package/dist/capture/caller-session.js +1 -12
  90. package/dist/capture/capture-error.d.ts +2 -2
  91. package/dist/capture/capture-error.js +23 -18
  92. package/dist/capture/codex-patch.js +3 -1
  93. package/dist/capture/command.js +36 -95
  94. package/dist/capture/compact.js +10 -5
  95. package/dist/capture/compaction-items-caller.js +11 -20
  96. package/dist/capture/compaction-record.d.ts +7 -93
  97. package/dist/capture/compaction-record.js +29 -426
  98. package/dist/capture/compaction-spool.d.ts +7 -7
  99. package/dist/capture/compaction-spool.js +60 -51
  100. package/dist/capture/copilot-transcript.d.ts +2 -1
  101. package/dist/capture/copilot-transcript.js +2 -1
  102. package/dist/capture/extract.d.ts +5 -2
  103. package/dist/capture/extract.js +4 -3
  104. package/dist/capture/failure-caller.d.ts +1 -1
  105. package/dist/capture/failure-caller.js +21 -16
  106. package/dist/capture/failure-reading.d.ts +2 -1
  107. package/dist/capture/failure-reading.js +7 -9
  108. package/dist/capture/pre-compact-caller.js +5 -4
  109. package/dist/capture/session-digest.js +4 -3
  110. package/dist/capture/session-end-caller.js +3 -2
  111. package/dist/capture/session-worker.js +22 -10
  112. package/dist/capture/transcript.d.ts +2 -1
  113. package/dist/capture/transcript.js +6 -3
  114. package/dist/capture/working-state.d.ts +4 -2
  115. package/dist/capture/working-state.js +4 -2
  116. package/dist/cli/audit-prune.d.ts +0 -25
  117. package/dist/cli/audit-prune.js +1 -27
  118. package/dist/cli/audit.js +20 -20
  119. package/dist/cli/auth.d.ts +1 -1
  120. package/dist/cli/auth.js +16 -17
  121. package/dist/cli/briefs.d.ts +1 -4
  122. package/dist/cli/briefs.js +37 -292
  123. package/dist/cli/card.js +41 -33
  124. package/dist/cli/client.d.ts +6 -2
  125. package/dist/cli/client.js +37 -21
  126. package/dist/cli/compact-resume-payload.js +1 -1
  127. package/dist/cli/context.d.ts +1 -1
  128. package/dist/cli/context.js +13 -13
  129. package/dist/cli/continuity.d.ts +1 -1
  130. package/dist/cli/continuity.js +36 -39
  131. package/dist/cli/curate.d.ts +2 -2
  132. package/dist/cli/curate.js +32 -36
  133. package/dist/cli/dag.d.ts +1 -1
  134. package/dist/cli/dag.js +23 -8
  135. package/dist/cli/decisions.d.ts +0 -2
  136. package/dist/cli/decisions.js +7 -285
  137. package/dist/cli/eval.d.ts +1 -1
  138. package/dist/cli/eval.js +12 -13
  139. package/dist/cli/explain.d.ts +1 -1
  140. package/dist/cli/explain.js +21 -25
  141. package/dist/cli/flag-values.js +16 -6
  142. package/dist/cli/flags.d.ts +0 -289
  143. package/dist/cli/flags.js +3 -138
  144. package/dist/cli/graph.d.ts +3 -0
  145. package/dist/cli/graph.js +83 -0
  146. package/dist/cli/hook-runtime.d.ts +6 -6
  147. package/dist/cli/hook-runtime.js +9 -36
  148. package/dist/cli/incidents.d.ts +3 -0
  149. package/dist/cli/incidents.js +112 -0
  150. package/dist/cli/init.d.ts +1 -1
  151. package/dist/cli/init.js +28 -19
  152. package/dist/cli/install-steps.d.ts +2 -1
  153. package/dist/cli/install-steps.js +11 -3
  154. package/dist/cli/last-sleep.js +1 -1
  155. package/dist/cli/maintenance.d.ts +3 -3
  156. package/dist/cli/maintenance.js +29 -30
  157. package/dist/cli/notes.d.ts +2 -0
  158. package/dist/cli/notes.js +41 -0
  159. package/dist/cli/object-verbs.d.ts +2 -2
  160. package/dist/cli/object-verbs.js +4 -4
  161. package/dist/cli/open-browser.d.ts +14 -0
  162. package/dist/cli/open-browser.js +26 -0
  163. package/dist/cli/playbooks.d.ts +3 -4
  164. package/dist/cli/playbooks.js +126 -290
  165. package/dist/cli/predictions.d.ts +3 -0
  166. package/dist/cli/predictions.js +174 -0
  167. package/dist/cli/print.js +2 -1
  168. package/dist/cli/projects.js +30 -22
  169. package/dist/cli/quality-repair-once.d.ts +1 -1
  170. package/dist/cli/quality-repair-once.js +6 -5
  171. package/dist/cli/recall.js +13 -7
  172. package/dist/cli/refine-llm.js +18 -17
  173. package/dist/cli/remember.js +17 -17
  174. package/dist/cli/scheduler.js +2 -1
  175. package/dist/cli/serve.js +11 -6
  176. package/dist/cli/session-hooks.d.ts +1 -5
  177. package/dist/cli/session-hooks.js +89 -168
  178. package/dist/cli/setup.d.ts +1 -1
  179. package/dist/cli/setup.js +17 -10
  180. package/dist/cli/shared.d.ts +2 -6
  181. package/dist/cli/shared.js +9 -29
  182. package/dist/cli/sleep-render.js +6 -3
  183. package/dist/cli/sleep.js +6 -37
  184. package/dist/cli/status.d.ts +3 -3
  185. package/dist/cli/status.js +32 -35
  186. package/dist/cli/transfer.d.ts +3 -3
  187. package/dist/cli/transfer.js +64 -43
  188. package/dist/cli/usage.d.ts +1 -80
  189. package/dist/cli/usage.js +2 -696
  190. package/dist/cli/verb-row.d.ts +34 -0
  191. package/dist/cli/verb-row.js +6 -0
  192. package/dist/cli/verbs/health.d.ts +27 -0
  193. package/dist/cli/verbs/health.js +234 -0
  194. package/dist/cli/verbs/memory.d.ts +16 -0
  195. package/dist/cli/verbs/memory.js +236 -0
  196. package/dist/cli/verbs/objects.d.ts +20 -0
  197. package/dist/cli/verbs/objects.js +257 -0
  198. package/dist/cli/verbs/sessions.d.ts +31 -0
  199. package/dist/cli/verbs/sessions.js +314 -0
  200. package/dist/cli/verbs.d.ts +81 -0
  201. package/dist/cli/verbs.js +7 -0
  202. package/dist/cli/versioned-verbs.d.ts +51 -0
  203. package/dist/cli/versioned-verbs.js +79 -0
  204. package/dist/cli.d.ts +1 -272
  205. package/dist/cli.js +24 -315
  206. package/dist/connectors/dlq.d.ts +39 -3
  207. package/dist/connectors/dlq.js +39 -4
  208. package/dist/connectors/github/backfill.js +12 -3
  209. package/dist/connectors/github/deletion.js +2 -1
  210. package/dist/connectors/github/dlq.js +31 -73
  211. package/dist/connectors/github/ingest.d.ts +2 -6
  212. package/dist/connectors/github/ingest.js +5 -29
  213. package/dist/connectors/github/tenant-routing.js +2 -1
  214. package/dist/connectors/github/webhook.d.ts +2 -1
  215. package/dist/connectors/github/webhook.js +35 -2
  216. package/dist/connectors/ingest.d.ts +10 -0
  217. package/dist/connectors/ingest.js +29 -0
  218. package/dist/connectors/slack/deletion.js +2 -1
  219. package/dist/connectors/slack/dlq.js +49 -71
  220. package/dist/connectors/slack/ingest.d.ts +2 -6
  221. package/dist/connectors/slack/ingest.js +4 -28
  222. package/dist/connectors/slack/tenant-routing.js +2 -1
  223. package/dist/connectors/slack/webhook.d.ts +2 -1
  224. package/dist/connectors/slack/webhook.js +2 -1
  225. package/dist/consolidate/conflicts.js +2 -2
  226. package/dist/consolidate/dag.js +29 -18
  227. package/dist/consolidate/dedupe.d.ts +7 -0
  228. package/dist/consolidate/dedupe.js +6 -4
  229. package/dist/consolidate/llm-passes.js +45 -19
  230. package/dist/consolidate/memory-value.js +3 -2
  231. package/dist/consolidate/merge.js +8 -8
  232. package/dist/consolidate/physics-pass.d.ts +6 -1
  233. package/dist/consolidate/physics-pass.js +26 -6
  234. package/dist/consolidate/replay.js +11 -4
  235. package/dist/consolidate/sleep.js +9 -6
  236. package/dist/consolidate/traces.js +5 -5
  237. package/dist/core/ablation.d.ts +10 -0
  238. package/dist/core/ablation.js +12 -0
  239. package/dist/{sharing/scope.d.ts → core/active-scope.d.ts} +1 -1
  240. package/dist/{sharing/scope.js → core/active-scope.js} +1 -1
  241. package/dist/core/ambient.d.ts +4 -0
  242. package/dist/core/ambient.js +39 -18
  243. package/dist/core/api-errors.d.ts +16 -0
  244. package/dist/core/api-errors.js +20 -0
  245. package/dist/core/card.js +3 -1
  246. package/dist/core/compaction-timing.d.ts +7 -0
  247. package/dist/core/compaction-timing.js +9 -0
  248. package/dist/core/config.d.ts +1 -1
  249. package/dist/core/config.js +22 -18
  250. package/dist/core/cosine.d.ts +3 -0
  251. package/dist/core/cosine.js +19 -0
  252. package/dist/{store → core}/markdown.d.ts +1 -1
  253. package/dist/{store → core}/markdown.js +4 -4
  254. package/dist/core/memory-audit.d.ts +17 -0
  255. package/dist/core/memory-audit.js +54 -0
  256. package/dist/core/memory.d.ts +14 -8
  257. package/dist/core/memory.js +35 -23
  258. package/dist/{consolidate → core}/merged-row.d.ts +1 -1
  259. package/dist/{consolidate → core}/merged-row.js +1 -1
  260. package/dist/core/physics.d.ts +3 -1
  261. package/dist/core/physics.js +23 -18
  262. package/dist/core/prediction.d.ts +3 -0
  263. package/dist/core/prediction.js +6 -0
  264. package/dist/core/project-identity.d.ts +3 -0
  265. package/dist/core/project-identity.js +12 -2
  266. package/dist/{store → core}/recall-scope.d.ts +1 -10
  267. package/dist/{store → core}/recall-scope.js +2 -19
  268. package/dist/core/search-types.d.ts +1 -1
  269. package/dist/dashboard/dashboard-actions.d.ts +2 -2
  270. package/dist/dashboard/dashboard-actions.js +5 -5
  271. package/dist/dashboard/dashboard-queries.js +2 -7
  272. package/dist/dashboard/dashboard-snapshot.js +1 -3
  273. package/dist/dashboard/dashboard.js +16 -5
  274. package/dist/db/busy.d.ts +2 -7
  275. package/dist/db/busy.js +21 -26
  276. package/dist/db/connect.d.ts +2 -2
  277. package/dist/db/connect.js +7 -7
  278. package/dist/db/index.d.ts +3 -3
  279. package/dist/db/index.js +3 -3
  280. package/dist/db/migrate.js +14 -7
  281. package/dist/db/migrations/index.d.ts +1 -1
  282. package/dist/db/migrations/index.js +3 -1
  283. package/dist/db/migrations/v11.js +1 -0
  284. package/dist/db/migrations/v14.js +1 -0
  285. package/dist/db/migrations/v55.d.ts +3 -0
  286. package/dist/db/migrations/v55.js +17 -0
  287. package/dist/db/open.d.ts +0 -2
  288. package/dist/db/open.js +6 -10
  289. package/dist/db/physics-state.d.ts +0 -4
  290. package/dist/db/physics-state.js +7 -33
  291. package/dist/db/request-stores.d.ts +1 -0
  292. package/dist/db/request-stores.js +2 -1
  293. package/dist/db/tables.d.ts +2 -0
  294. package/dist/db/tables.js +6 -2
  295. package/dist/db/vector-store.js +19 -5
  296. package/dist/db/wal-checkpointer.js +2 -1
  297. package/dist/doctor.d.ts +3 -0
  298. package/dist/doctor.js +18 -15
  299. package/dist/embeddings/local.d.ts +62 -0
  300. package/dist/embeddings/local.js +146 -0
  301. package/dist/{store/embeddings → embeddings}/provider.d.ts +5 -2
  302. package/dist/{store/embeddings → embeddings}/provider.js +19 -25
  303. package/dist/embeddings/transformers.d.ts +26 -0
  304. package/dist/embeddings/transformers.js +89 -0
  305. package/dist/entry/session-text.d.ts +1 -1
  306. package/dist/entry/session-text.js +1 -1
  307. package/dist/entry/store-kit.d.ts +37 -0
  308. package/dist/entry/store-kit.js +25 -0
  309. package/dist/entry/testing.d.ts +6 -0
  310. package/dist/entry/testing.js +7 -0
  311. package/dist/eval/eval-suite.js +17 -11
  312. package/dist/eval/eval.js +1 -1
  313. package/dist/eval/judgment.js +12 -5
  314. package/dist/graph/extract.js +3 -3
  315. package/dist/graph/recall.js +1 -1
  316. package/dist/graph/view.js +13 -5
  317. package/dist/graph/write.d.ts +1 -1
  318. package/dist/graph/write.js +9 -9
  319. package/dist/hooks/codex-session.js +3 -2
  320. package/dist/hooks/codex-wrapper.js +2 -1
  321. package/dist/hooks/json-hooks.js +10 -4
  322. package/dist/hooks/opencode.js +8 -5
  323. package/dist/hooks/shared.d.ts +0 -6
  324. package/dist/hooks/shared.js +4 -15
  325. package/dist/importers/core.js +4 -4
  326. package/dist/importers/sources.js +5 -4
  327. package/dist/importers/vault.d.ts +1 -1
  328. package/dist/importers/vault.js +25 -23
  329. package/dist/index.d.ts +5 -4
  330. package/dist/index.js +4 -3
  331. package/dist/learn/autolearn.d.ts +15 -3
  332. package/dist/learn/autolearn.js +38 -16
  333. package/dist/learn/churn-git.js +13 -4
  334. package/dist/learn/extract.d.ts +3 -2
  335. package/dist/learn/extract.js +7 -5
  336. package/dist/learn/forward-claim-detector.js +4 -2
  337. package/dist/learn/invalidation.d.ts +2 -1
  338. package/dist/learn/invalidation.js +18 -9
  339. package/dist/mcp/admin-tools.d.ts +2 -2
  340. package/dist/mcp/admin-tools.js +27 -48
  341. package/dist/mcp/format.js +3 -2
  342. package/dist/mcp/framing.d.ts +1 -0
  343. package/dist/mcp/framing.js +1 -1
  344. package/dist/mcp/memory-tools.d.ts +1 -1
  345. package/dist/mcp/memory-tools.js +8 -9
  346. package/dist/mcp/protocol.d.ts +11 -7
  347. package/dist/mcp/protocol.js +25 -12
  348. package/dist/mcp/recall-tools.js +12 -9
  349. package/dist/mcp/request.js +22 -20
  350. package/dist/mcp/stdio.js +37 -16
  351. package/dist/mcp/tool-args.js +2 -1
  352. package/dist/mcp/tools.js +44 -21
  353. package/dist/objects/customer-notes.d.ts +2 -2
  354. package/dist/objects/decisions.d.ts +2 -2
  355. package/dist/objects/descriptor.d.ts +1 -1
  356. package/dist/objects/incidents.d.ts +2 -2
  357. package/dist/objects/lifecycle.d.ts +1 -1
  358. package/dist/objects/lifecycle.js +2 -1
  359. package/dist/objects/policies.d.ts +2 -2
  360. package/dist/objects/policies.js +2 -1
  361. package/dist/objects/processes.d.ts +2 -2
  362. package/dist/objects/project-briefs.d.ts +2 -2
  363. package/dist/objects/project-briefs.js +2 -3
  364. package/dist/objects/skills.d.ts +2 -2
  365. package/dist/postinstall.js +1 -1
  366. package/dist/rerankers/clef.js +3 -6
  367. package/dist/rerankers/cross-encoder.d.ts +31 -2
  368. package/dist/rerankers/cross-encoder.js +71 -98
  369. package/dist/rerankers/index.js +5 -4
  370. package/dist/rerankers/jev.js +2 -4
  371. package/dist/rerankers/outage-warning.d.ts +3 -1
  372. package/dist/rerankers/outage-warning.js +5 -3
  373. package/dist/search/bm25-search.js +1 -1
  374. package/dist/search/boosts.js +1 -1
  375. package/dist/search/embed-memories.d.ts +12 -0
  376. package/dist/search/embed-memories.js +389 -0
  377. package/dist/search/engine.d.ts +8 -0
  378. package/dist/search/engine.js +10 -0
  379. package/dist/search/goal-boost.d.ts +1 -1
  380. package/dist/search/goal-boost.js +6 -3
  381. package/dist/search/hybrid.d.ts +9 -2
  382. package/dist/search/hybrid.js +9 -4
  383. package/dist/search/physics-search.d.ts +6 -3
  384. package/dist/search/physics-search.js +22 -15
  385. package/dist/search/rerank.js +1 -1
  386. package/dist/search/vector.d.ts +8 -6
  387. package/dist/search/vector.js +14 -17
  388. package/dist/server/auth.d.ts +3 -1
  389. package/dist/server/auth.js +24 -15
  390. package/dist/server/boot.d.ts +2 -1
  391. package/dist/server/boot.js +34 -84
  392. package/dist/server/client-ip.d.ts +9 -6
  393. package/dist/server/client-ip.js +36 -17
  394. package/dist/server/deadline.d.ts +0 -2
  395. package/dist/server/deadline.js +1 -7
  396. package/dist/server/defaults.d.ts +1 -0
  397. package/dist/server/defaults.js +1 -0
  398. package/dist/server/mcp-http.js +16 -11
  399. package/dist/server/request.js +7 -2
  400. package/dist/server/route-checks.d.ts +7 -0
  401. package/dist/server/route-checks.js +42 -0
  402. package/dist/server/route-table.d.ts +9 -8
  403. package/dist/server/route-table.js +127 -133
  404. package/dist/server/routes/admin.d.ts +8 -8
  405. package/dist/server/routes/admin.js +13 -21
  406. package/dist/server/routes/customer-notes.d.ts +6 -6
  407. package/dist/server/routes/customer-notes.js +1 -2
  408. package/dist/server/routes/decisions.d.ts +6 -6
  409. package/dist/server/routes/decisions.js +2 -4
  410. package/dist/server/routes/incidents.d.ts +6 -6
  411. package/dist/server/routes/incidents.js +2 -5
  412. package/dist/server/routes/memories.d.ts +9 -9
  413. package/dist/server/routes/memories.js +19 -40
  414. package/dist/server/routes/object-routes.d.ts +6 -6
  415. package/dist/server/routes/object-routes.js +4 -7
  416. package/dist/server/routes/policies.d.ts +7 -7
  417. package/dist/server/routes/policies.js +2 -4
  418. package/dist/server/routes/predictions.d.ts +6 -6
  419. package/dist/server/routes/predictions.js +9 -13
  420. package/dist/server/routes/processes.d.ts +6 -6
  421. package/dist/server/routes/processes.js +1 -2
  422. package/dist/server/routes/project-briefs.d.ts +7 -7
  423. package/dist/server/routes/project-briefs.js +2 -4
  424. package/dist/server/routes/recall.d.ts +5 -5
  425. package/dist/server/routes/recall.js +6 -10
  426. package/dist/server/routes/skills.d.ts +7 -7
  427. package/dist/server/routes/skills.js +2 -4
  428. package/dist/server/server-detect.d.ts +7 -1
  429. package/dist/server/server-detect.js +36 -11
  430. package/dist/server/sleep-child.js +26 -7
  431. package/dist/server/sleep-offload.d.ts +11 -5
  432. package/dist/server/sleep-offload.js +17 -11
  433. package/dist/server/tls.d.ts +7 -2
  434. package/dist/server/tls.js +17 -5
  435. package/dist/server/types.d.ts +29 -12
  436. package/dist/server/validation.d.ts +1 -2
  437. package/dist/server/validation.js +6 -11
  438. package/dist/server.d.ts +4 -40
  439. package/dist/server.js +3 -29
  440. package/dist/sharing/global-store.d.ts +4 -5
  441. package/dist/sharing/global-store.js +8 -13
  442. package/dist/sharing/global-sync.js +38 -45
  443. package/dist/sharing/project-merge.d.ts +7 -14
  444. package/dist/sharing/project-merge.js +57 -121
  445. package/dist/sharing/search-both.js +10 -3
  446. package/dist/sharing/share.d.ts +2 -0
  447. package/dist/sharing/share.js +39 -38
  448. package/dist/store/ambient.js +7 -7
  449. package/dist/store/audit-event.d.ts +1 -1
  450. package/dist/store/audit.d.ts +0 -16
  451. package/dist/store/audit.js +4 -55
  452. package/dist/store/auth.d.ts +4 -2
  453. package/dist/store/auth.js +7 -3
  454. package/dist/store/candidates.d.ts +3 -2
  455. package/dist/store/candidates.js +59 -30
  456. package/dist/store/capture-write.d.ts +17 -0
  457. package/dist/store/capture-write.js +35 -0
  458. package/dist/store/cards.js +6 -5
  459. package/dist/store/compaction-caller.d.ts +18 -0
  460. package/dist/store/compaction-caller.js +29 -0
  461. package/dist/store/compactions-record.d.ts +115 -0
  462. package/dist/store/compactions-record.js +418 -0
  463. package/dist/store/compactions.js +6 -4
  464. package/dist/store/conflicts.d.ts +7 -1
  465. package/dist/store/conflicts.js +13 -9
  466. package/dist/store/connectors/dlq.d.ts +10 -0
  467. package/dist/store/connectors/dlq.js +33 -0
  468. package/dist/store/connectors/event-log.d.ts +13 -0
  469. package/dist/store/connectors/event-log.js +24 -0
  470. package/dist/store/connectors/github.d.ts +7 -9
  471. package/dist/store/connectors/github.js +35 -60
  472. package/dist/store/connectors/slack.d.ts +2 -11
  473. package/dist/store/connectors/slack.js +24 -57
  474. package/dist/store/dashboard-reads.js +8 -6
  475. package/dist/store/delete-and-batch.d.ts +6 -0
  476. package/dist/store/delete-and-batch.js +40 -6
  477. package/dist/store/delivery-recorder.d.ts +12 -5
  478. package/dist/store/delivery-recorder.js +13 -11
  479. package/dist/store/descendant-page.js +8 -4
  480. package/dist/store/dormant.d.ts +1 -1
  481. package/dist/store/dormant.js +10 -4
  482. package/dist/store/embeddings/index.d.ts +2 -12
  483. package/dist/store/embeddings/index.js +5 -374
  484. package/dist/store/entry-reads.d.ts +35 -4
  485. package/dist/store/entry-reads.js +86 -19
  486. package/dist/store/entry-row.js +9 -2
  487. package/dist/store/entry-writes.d.ts +15 -12
  488. package/dist/store/entry-writes.js +54 -22
  489. package/dist/store/failure-log-at.d.ts +8 -0
  490. package/dist/store/failure-log-at.js +16 -0
  491. package/dist/store/failure-log.d.ts +2 -2
  492. package/dist/store/failure-log.js +5 -3
  493. package/dist/{trust → store}/gated-write.d.ts +3 -1
  494. package/dist/{trust → store}/gated-write.js +7 -5
  495. package/dist/store/goals.js +22 -19
  496. package/dist/store/graph-reads.js +9 -6
  497. package/dist/store/graph-view-rows.js +2 -1
  498. package/dist/store/graph-writes.d.ts +6 -6
  499. package/dist/store/graph-writes.js +48 -71
  500. package/dist/store/half-life.js +2 -2
  501. package/dist/store/handoffs.d.ts +10 -4
  502. package/dist/store/handoffs.js +10 -9
  503. package/dist/store/index-and-stats.js +2 -2
  504. package/dist/store/index.d.ts +2 -2
  505. package/dist/store/index.js +1 -1
  506. package/dist/store/key-writes.js +1 -1
  507. package/dist/store/ledger-turn.d.ts +9 -0
  508. package/dist/store/ledger-turn.js +38 -0
  509. package/dist/store/mirrors.js +19 -10
  510. package/dist/store/open.d.ts +2 -5
  511. package/dist/store/open.js +42 -54
  512. package/dist/store/pilot-arm.d.ts +12 -0
  513. package/dist/store/pilot-arm.js +42 -0
  514. package/dist/store/port.d.ts +68 -6
  515. package/dist/store/port.js +8 -0
  516. package/dist/store/predictions.d.ts +1 -2
  517. package/dist/store/predictions.js +3 -6
  518. package/dist/store/project-tags.d.ts +62 -0
  519. package/dist/store/project-tags.js +67 -0
  520. package/dist/store/quality-repair.js +1 -1
  521. package/dist/store/quarantine.js +2 -1
  522. package/dist/store/recall-trace.d.ts +2 -0
  523. package/dist/store/recall-trace.js +20 -3
  524. package/dist/store/rejected-values.js +16 -10
  525. package/dist/store/rejection-probe.d.ts +4 -0
  526. package/dist/store/rejection-probe.js +19 -0
  527. package/dist/store/rejection.d.ts +0 -17
  528. package/dist/store/rejection.js +1 -21
  529. package/dist/store/rows.js +2 -2
  530. package/dist/store/rule-sql.d.ts +11 -0
  531. package/dist/store/rule-sql.js +31 -6
  532. package/dist/store/search-rows.d.ts +5 -5
  533. package/dist/store/search-rows.js +18 -16
  534. package/dist/store/sessions.js +4 -2
  535. package/dist/store/set-aside.d.ts +14 -0
  536. package/dist/store/set-aside.js +23 -0
  537. package/dist/store/sqlite/busy.d.ts +3 -0
  538. package/dist/store/sqlite/busy.js +8 -0
  539. package/dist/store/sqlite/connector-events-group.js +4 -7
  540. package/dist/store/sqlite/connector-writes-group.js +6 -4
  541. package/dist/store/sqlite/entry-writes-group.d.ts +3 -3
  542. package/dist/store/sqlite/entry-writes-group.js +3 -3
  543. package/dist/store/sqlite/error-codec.js +4 -3
  544. package/dist/store/sqlite/executor.js +10 -4
  545. package/dist/store/sqlite/graph-reads-group.js +1 -1
  546. package/dist/store/sqlite/held-connection.d.ts +11 -0
  547. package/dist/store/sqlite/held-connection.js +41 -0
  548. package/dist/store/sqlite/last-recall-group.d.ts +13 -0
  549. package/dist/store/sqlite/last-recall-group.js +57 -0
  550. package/dist/store/sqlite/local.d.ts +0 -17
  551. package/dist/store/sqlite/local.js +0 -31
  552. package/dist/store/sqlite/maintenance-groups.d.ts +6 -0
  553. package/dist/store/sqlite/maintenance-groups.js +60 -0
  554. package/dist/store/sqlite/object-rows.d.ts +1 -1
  555. package/dist/store/sqlite/objects-group.d.ts +1 -1
  556. package/dist/store/sqlite/objects-group.js +15 -7
  557. package/dist/store/sqlite/store.d.ts +1 -8
  558. package/dist/store/sqlite/store.js +13 -22
  559. package/dist/store/summaries.d.ts +10 -3
  560. package/dist/store/summaries.js +54 -11
  561. package/dist/store/token-ledger-rows.js +3 -2
  562. package/dist/store/token-ledger.d.ts +0 -7
  563. package/dist/store/token-ledger.js +0 -35
  564. package/dist/store/vector-index.js +8 -4
  565. package/dist/support-bundle.js +2 -3
  566. package/dist/trust/reject-flow.js +2 -2
  567. package/dist/util/agent-homes.d.ts +15 -0
  568. package/dist/util/agent-homes.js +34 -0
  569. package/dist/util/anthropic-messages.d.ts +6 -1
  570. package/dist/util/anthropic-messages.js +26 -7
  571. package/dist/util/atomic-write.d.ts +5 -2
  572. package/dist/util/atomic-write.js +12 -8
  573. package/dist/util/chunked.d.ts +3 -0
  574. package/dist/util/chunked.js +10 -0
  575. package/dist/util/ellipsize.d.ts +3 -0
  576. package/dist/util/ellipsize.js +5 -0
  577. package/dist/util/env.d.ts +12 -2
  578. package/dist/util/env.js +12 -2
  579. package/dist/util/format.d.ts +5 -0
  580. package/dist/util/format.js +10 -0
  581. package/dist/util/hook-payload.d.ts +8 -0
  582. package/dist/util/hook-payload.js +37 -0
  583. package/dist/util/http-retry.d.ts +6 -0
  584. package/dist/util/http-retry.js +43 -5
  585. package/dist/util/http-util.d.ts +0 -8
  586. package/dist/util/http-util.js +10 -21
  587. package/dist/util/limits.d.ts +7 -0
  588. package/dist/util/limits.js +14 -0
  589. package/dist/util/log.d.ts +4 -0
  590. package/dist/util/log.js +9 -0
  591. package/dist/util/request-scope.d.ts +9 -3
  592. package/dist/util/request-scope.js +18 -9
  593. package/dist/util/secret-detect.js +6 -1
  594. package/dist/util/spawn-argv.d.ts +9 -0
  595. package/dist/util/spawn-argv.js +57 -0
  596. package/dist/util/sql.d.ts +3 -0
  597. package/dist/util/sql.js +6 -0
  598. package/dist/util/sqlite-blocked.d.ts +2 -0
  599. package/dist/util/sqlite-blocked.js +5 -0
  600. package/dist/util/stream-tee.d.ts +3 -0
  601. package/dist/util/stream-tee.js +35 -0
  602. package/dist/util/time.d.ts +4 -0
  603. package/dist/util/time.js +4 -0
  604. package/dist/util/vector-codec.d.ts +4 -0
  605. package/dist/util/vector-codec.js +15 -0
  606. package/dist/util/version.d.ts +1 -1
  607. package/dist/util/version.js +1 -1
  608. package/extensions/openclaw-plugin/openclaw.plugin.json +1 -1
  609. package/extensions/openclaw-plugin/package.json +1 -1
  610. package/openclaw.plugin.json +1 -1
  611. package/package.json +4 -2
  612. package/dist/api/on-store.d.ts +0 -16
  613. package/dist/api/on-store.js +0 -38
  614. package/dist/store/embeddings/local.d.ts +0 -15
  615. package/dist/store/embeddings/local.js +0 -175
  616. /package/dist/{cli → api}/correction-latency.d.ts +0 -0
  617. /package/dist/{cli → api}/correction-latency.js +0 -0
  618. /package/dist/{cli → api}/provenance-coverage.d.ts +0 -0
  619. /package/dist/{cli → api}/provenance-coverage.js +0 -0
  620. /package/dist/{store → core}/object-types.d.ts +0 -0
  621. /package/dist/{store → core}/object-types.js +0 -0
  622. /package/dist/{capture → util}/compaction-items.d.ts +0 -0
  623. /package/dist/{capture → util}/compaction-items.js +0 -0
  624. /package/dist/{store → util}/yaml.d.ts +0 -0
  625. /package/dist/{store → util}/yaml.js +0 -0
@@ -1,7 +1,7 @@
1
1
  import type { MemoryEntry } from '../core/memory.js';
2
2
  import { type PromptRecallGate } from '../core/prompt-recall.js';
3
3
  export type DeliveryRuntime = 'claude-code' | 'codex' | 'copilot' | 'unknown';
4
- export type DeliveryEventType = 'prompt-submit' | 'pinned-manual' | 'pre-compact' | 'compact-resume' | 'session-end' | 'context';
4
+ export type DeliveryEventType = 'prompt-submit' | 'pinned-manual' | 'pre-compact' | 'compact-resume' | 'session-end' | 'context' | 'tool-failure';
5
5
  /** True for the boundary types: a compaction's two hooks and the end of a session. */
6
6
  export declare const isBoundaryEvent: (type: DeliveryEventType) => boolean;
7
7
  export type DeliverySurface = 'hook' | 'context';
@@ -12,8 +12,9 @@ export type DeliveryPool = 'pin' | 'recent' | 'prompt-recall' | 'strength' | 'se
12
12
  export type DeliveryStage = 'load' | 'eligible' | 'gate' | 'budget' | 'limit' | 'final';
13
13
  export type DeliveryOutcome = 'emitted' | 'reused' | 'rejected';
14
14
  export type DeliveryRejectReason = 'budget' | 'gate-below-threshold' | 'gate-max-items' | 'duplicate' | 'scope' | 'quality' | 'limit';
15
- /** Row format version in `delivery_events.ledger_version`: 3 = written by a binary that can write session-end and context rows, so `event_type` has six values. */
16
- export declare const DELIVERY_LEDGER_VERSION = 3;
15
+ /** Row format version in `delivery_events.ledger_version`: 4 = written by a binary that can write `tool-failure` rows and hashes the
16
+ * store's resolved root. */
17
+ export declare const DELIVERY_LEDGER_VERSION = 4;
17
18
  /** Rejected candidate rows kept per event; the rest only add to `rejected_unlisted`. */
18
19
  export declare const DELIVERY_REJECTED_ROW_CAP = 16;
19
20
  export interface DeliveryCandidateInput {
@@ -61,6 +62,10 @@ export interface DeliveryEventInput {
61
62
  recallHash: string | null;
62
63
  emittedHash: string | null;
63
64
  elapsedMs: number;
65
+ /** The host's id for the tool call; set on `tool-failure` rows only. */
66
+ toolUseId?: string | null;
67
+ /** The `failure_log` row the failure was logged as; set on `tool-failure` rows only. */
68
+ failureId?: number | null;
64
69
  candidates: readonly DeliveryCandidateInput[];
65
70
  }
66
71
  export interface DeliveryFacts {
@@ -116,6 +121,8 @@ export interface DeliveryOutcomeInput {
116
121
  export interface DeliveryRecorder extends DeliveryObserver {
117
122
  readonly root: string;
118
123
  delivered(outcome: DeliveryOutcomeInput): void;
124
+ /** The failure log row id a `tool-failure` event links to; null when the log write threw. */
125
+ logged(failureId: number | null): void;
119
126
  /** Builds the event and hands it to `write` once per call; throws on an injected fault, and writes nothing once broken. */
120
127
  flush(write: (input: DeliveryEventInput) => number | null): void;
121
128
  }
@@ -131,10 +138,10 @@ export interface DeliveryRecorderInit {
131
138
  runtime?: DeliveryRuntime;
132
139
  /** Set by hooks that are not prompt or context calls; without it the payload's hook event decides. */
133
140
  eventType?: DeliveryEventType;
141
+ /** Makes this recorder throw at one stage; only tests set it, and no CLI flag or environment variable reaches it. */
142
+ fault?: DeliveryFault;
134
143
  }
135
144
  export type DeliveryFault = 'observe' | 'build' | 'flush';
136
- /** Makes every recorder created afterwards throw at one stage. Only tests call it; the shipped CLI and server have no route here. */
137
- export declare function _setDeliveryFaultForTests(fault: DeliveryFault | null): void;
138
145
  /** A recorder for one call; every observer method is guarded, and a throw marks it broken instead of escaping. */
139
146
  export declare function createDeliveryRecorder(init: DeliveryRecorderInit): DeliveryRecorder;
140
147
  //# sourceMappingURL=delivery-recorder.d.ts.map
@@ -1,14 +1,15 @@
1
1
  import { evalNow } from '../core/ablation.js';
2
2
  import { scoreOverlap } from '../core/prompt-recall.js';
3
- import { hookPayloadSessionId, hookPayloadString, isSubagentPayload } from './token-ledger.js';
3
+ import { hookPayloadSessionId, hookPayloadString, isSubagentPayload } from '../util/hook-payload.js';
4
4
  import { blockHash, estimateTokens } from '../util/token-text.js';
5
5
  import { errorMessage, log } from '../util/log.js';
6
6
  /** True for the boundary types: a compaction's two hooks and the end of a session. */
7
7
  export const isBoundaryEvent = (type) => type === 'pre-compact' || type === 'compact-resume' || type === 'session-end';
8
8
  /** Only the per-prompt calls keep prompt facts; a boundary or a `hippo context` run is not a prompt. */
9
9
  const carriesPrompt = (type) => type === 'prompt-submit' || type === 'pinned-manual';
10
- /** Row format version in `delivery_events.ledger_version`: 3 = written by a binary that can write session-end and context rows, so `event_type` has six values. */
11
- export const DELIVERY_LEDGER_VERSION = 3;
10
+ /** Row format version in `delivery_events.ledger_version`: 4 = written by a binary that can write `tool-failure` rows and hashes the
11
+ * store's resolved root. */
12
+ export const DELIVERY_LEDGER_VERSION = 4;
12
13
  /** Rejected candidate rows kept per event; the rest only add to `rejected_unlisted`. */
13
14
  export const DELIVERY_REJECTED_ROW_CAP = 16;
14
15
  // Deeper stages were closer to being sent, so the row cap keeps them first.
@@ -35,10 +36,13 @@ function readPayload(init) {
35
36
  const rawTurnId = hookPayloadString(init.stdinText, 'turn_id');
36
37
  const hostTurnId = rawTurnId !== null && rawTurnId.trim() !== '' ? rawTurnId : null;
37
38
  const hookEvent = hookPayloadString(init.stdinText, 'hook_event_name');
39
+ const rawToolUseId = hookPayloadString(init.stdinText, 'tool_use_id')?.trim() ?? '';
40
+ // Cut as failure_log cuts its payload fields: the payload is not trusted to be short.
41
+ const toolUseId = rawToolUseId !== '' ? rawToolUseId.slice(0, 128) : null;
38
42
  const sessionState = subagent
39
43
  ? 'subagent'
40
44
  : payloadSession !== null ? 'payload' : envSession !== null ? 'env' : 'missing';
41
- return { payloadSession, envSession, prompt, hostTurnId, hookEvent, sessionState };
45
+ return { payloadSession, envSession, prompt, hostTurnId, hookEvent, toolUseId, sessionState };
42
46
  }
43
47
  function rejectId(state, id, rejection) {
44
48
  const { stage, reason, score, tokens } = rejection;
@@ -136,6 +140,8 @@ function buildEvent(init, payload, state, ts, startedMs) {
136
140
  recallHash: outcome.recallHash ?? null,
137
141
  emittedHash: emitted !== null ? blockHash(emitted) : null,
138
142
  elapsedMs: Math.max(0, Date.now() - startedMs),
143
+ toolUseId: eventType === 'tool-failure' ? payload.toolUseId : null,
144
+ failureId: eventType === 'tool-failure' ? state.failureId : null,
139
145
  candidates: rows,
140
146
  };
141
147
  }
@@ -192,20 +198,15 @@ function candidateMethods(state, guard) {
192
198
  }),
193
199
  };
194
200
  }
195
- let injectedFault = null;
196
- /** Makes every recorder created afterwards throw at one stage. Only tests call it; the shipped CLI and server have no route here. */
197
- export function _setDeliveryFaultForTests(fault) {
198
- injectedFault = fault;
199
- }
200
201
  /** A recorder for one call; every observer method is guarded, and a throw marks it broken instead of escaping. */
201
202
  export function createDeliveryRecorder(init) {
202
203
  const startedMs = Date.now();
203
204
  const ts = evalNow().toISOString();
204
- const fault = injectedFault;
205
+ const fault = init.fault ?? null;
205
206
  const payload = readPayload(init);
206
207
  const state = {
207
208
  candidates: new Map(), picked: new Map(), filtered: new Set(), facts: null, shown: 0, dropped: 0,
208
- disabledSeen: false, outcome: { state: 'empty' }, queryHash: null, recallTraceId: null, broken: null, flushed: false,
209
+ disabledSeen: false, outcome: { state: 'empty' }, queryHash: null, recallTraceId: null, failureId: null, broken: null, flushed: false,
209
210
  };
210
211
  const guard = guardFor(state, fault);
211
212
  const { qualityDropped, offer, reject, dropMissing, gated, selected } = candidateMethods(state, guard);
@@ -229,6 +230,7 @@ export function createDeliveryRecorder(init) {
229
230
  queried: (query) => guard(() => { state.queryHash = blockHash(query); }),
230
231
  traced: (traceId) => guard(() => { state.recallTraceId = traceId; }),
231
232
  delivered: (o) => guard(() => { state.outcome = { ...o }; }),
233
+ logged: (failureId) => guard(() => { state.failureId = failureId; }),
232
234
  flush: (write) => {
233
235
  if (state.flushed)
234
236
  return;
@@ -1,6 +1,8 @@
1
- import { chunked, selectEntriesByIds, TENANT_IS } from './entry-reads.js';
1
+ import { selectEntriesByIds, TENANT_IS } from './entry-reads.js';
2
+ import { chunked } from '../util/chunked.js';
2
3
  import { MEMORY_SELECT_COLUMNS, rowToEntry } from './rows.js';
3
- const marks = (ids) => ids.map(() => '?').join(',');
4
+ import { placeholders } from '../util/sql.js';
5
+ const marks = (ids) => placeholders(ids.length);
4
6
  /** The walk `summaryWithDescendants` documents, with `levels` cut to the first `page.rows` rows and each level's full count in `sizes`. */
5
7
  export function pagedDescendants(db, walk, summaryAdmitted) {
6
8
  const sizes = [];
@@ -53,7 +55,8 @@ function countedLevel(db, walk, parents, room) {
53
55
  const perParent = new Map();
54
56
  for (const chunk of chunked([...parents])) {
55
57
  // SAFETY: the SELECT names exactly ChildGroup's four fields, and the WHERE keeps dag_parent_id a string.
56
- const groups = db.prepare(`SELECT dag_parent_id, scope, origin_project, COUNT(*) AS n FROM memories WHERE dag_parent_id IN (${marks(chunk)}) AND ${TENANT_IS} AND id <> ? GROUP BY dag_parent_id, scope, origin_project`).all(...chunk, walk.tenantId, walk.summary.id);
58
+ const groups = db.prepare(`SELECT dag_parent_id, scope, origin_project, COUNT(*) AS n FROM memories ` +
59
+ `WHERE dag_parent_id IN (${marks(chunk)}) AND ${TENANT_IS} AND id <> ? GROUP BY dag_parent_id, scope, origin_project`).all(...chunk, walk.tenantId, walk.summary.id);
57
60
  for (const group of groups) {
58
61
  if (!walk.page.admit(group))
59
62
  return null;
@@ -85,7 +88,8 @@ function childrenInOrder(db, walk, parents, limit) {
85
88
  const byParent = new Map();
86
89
  for (const chunk of chunked([...parents])) {
87
90
  // SAFETY: selects exactly MEMORY_SELECT_COLUMNS, matching MemoryRow's field set.
88
- const rows = db.prepare(`SELECT ${MEMORY_SELECT_COLUMNS} FROM memories WHERE dag_parent_id IN (${marks(chunk)}) AND ${TENANT_IS} AND id <> ? ORDER BY created ASC, id ASC LIMIT ?`).all(...chunk, walk.tenantId, walk.summary.id, limit);
91
+ const rows = db.prepare(`SELECT ${MEMORY_SELECT_COLUMNS} FROM memories WHERE dag_parent_id IN (${marks(chunk)}) AND ${TENANT_IS} AND id <> ? ` +
92
+ `ORDER BY created ASC, id ASC LIMIT ?`).all(...chunk, walk.tenantId, walk.summary.id, limit);
89
93
  for (const row of rows) {
90
94
  const bucket = byParent.get(row.dag_parent_id ?? '');
91
95
  if (bucket)
@@ -3,7 +3,7 @@
3
3
  * Not the raw archive (`raw_archive`, `archiveRawMemory`), which keeps metadata only. db-taking helpers leave the handle and transaction to the caller. */
4
4
  import { type DatabaseSyncLike } from '../db/index.js';
5
5
  import type { MemoryEntry } from '../core/memory.js';
6
- import type { SqlFragment } from './recall-scope.js';
6
+ import type { SqlFragment } from './rule-sql.js';
7
7
  import type { WriteBudget } from '../util/write-budget.js';
8
8
  /** Why a memory went dormant: sleep's decay pass, an imported agent memory whose note was deleted, `hippo projects repair`
9
9
  * splitting a two-project merge, or `hippo audit repair` setting aside an automatic memory with a certain defect. */
@@ -3,7 +3,8 @@
3
3
  * Not the raw archive (`raw_archive`, `archiveRawMemory`), which keeps metadata only. db-taking helpers leave the handle and transaction to the caller. */
4
4
  import { closeHippoDb, openHippoDb, withWriteScope, withWriteScopeOr } from '../db/index.js';
5
5
  import { onHandle } from './open.js';
6
- import { RejectedValueError, rejectionDigest } from './rejection.js';
6
+ import { rejectionDigest } from './rejection.js';
7
+ import { RejectedValueError } from '../core/api-errors.js';
7
8
  import { escapeLike } from '../util/escape.js';
8
9
  import { warnDamagedColumn } from '../util/stored-json.js';
9
10
  import { DAY_MS } from '../util/time.js';
@@ -23,15 +24,20 @@ export function insertDormantRow(db, move) {
23
24
  reason = excluded.reason,
24
25
  strength = excluded.strength,
25
26
  dormant_at = excluded.dormant_at
26
- `).run(move.entry.tenantId, move.entry.id, move.entry.content, JSON.stringify(move.entry), move.reason, move.strength, move.dormantAt);
27
+ `).run(move.entry.tenant_id, move.entry.id, move.entry.content, JSON.stringify(move.entry), move.reason, move.strength, move.dormantAt);
28
+ }
29
+ function toCurrentEntry({ tenantId, summary_dirty, tenant_id, ...rest }) {
30
+ return { ...rest, tenant_id: tenant_id ?? tenantId ?? '', summary_dirty: summary_dirty === true || summary_dirty === 1 };
27
31
  }
28
32
  /** Parse a stored snapshot back into a MemoryEntry, or null when the row no longer matches it (edited by hand, or truncated). */
29
33
  function parseSnapshot(row) {
30
34
  try {
31
35
  // SAFETY: entry_json is only written by insertDormantRow from a MemoryEntry;
32
36
  // the id / tenant / content checks below reject a row edited out of shape.
33
- const entry = JSON.parse(row.entry_json);
34
- if (entry.id !== row.id || entry.tenantId !== row.tenant_id || entry.content !== row.content) {
37
+ // SAFETY: entry_json came from JSON.stringify of a MemoryEntry (2.0) or a 1.x one; the checks below reject a row edited out of shape.
38
+ const entry = toCurrentEntry(JSON.parse(row.entry_json));
39
+ if (entry.id !== row.id || entry.tenant_id !== row.tenant_id || entry.content !== row.content) {
40
+ warnDamagedColumn({ table: 'dormant_memories', id: row.id, column: 'entry_json' }, 'wrong shape');
35
41
  return null;
36
42
  }
37
43
  return entry;
@@ -1,9 +1,6 @@
1
- /** Optional embedding-based semantic search for Hippo.
2
- * Uses @huggingface/transformers (local, no API keys, ~22MB model); falls back silently if not installed. */
3
- import { MemoryEntry } from '../../core/memory.js';
1
+ /** The stored vector index's identity: which model and text format built it, and when a provider change means a rebuild.
2
+ * Picking a provider and computing vectors sit in src/search/embed-memories.ts; this module only reads and writes what is stored. */
4
3
  import { EMBEDDING_MODEL_META_KEY } from '../../db/vector-store.js';
5
- import { type EmbeddingProvider } from './provider.js';
6
- import type { HippoStore } from '../index.js';
7
4
  export { EMBEDDING_MODEL_META_KEY };
8
5
  /** Bump when `embeddingInputText` changes existing vectors; folded into the stored index identity (`embeddingIndexIdentity`) so it reindexes like a model
9
6
  * change. Format 2 = `path:*` tags excluded; format 1 (implicit, no suffix) included them. */
@@ -26,11 +23,4 @@ export declare function resolveIndexedEmbeddingModel(hippoRoot: string, index?:
26
23
  export declare function embeddingModelRequiresReindex(hippoRoot: string, model: string, index?: Record<string, number[]>): boolean;
27
24
  /** Cosine similarity; handles unnormalized vectors, returns 0 for empty or mismatched vectors. */
28
25
  export declare function cosineSimilarity(a: number[], b: number[]): number;
29
- /** `cosineSimilarity` over any indexable vectors; a Float32 view reads the same doubles as its number[] copy, so the score is the same. */
30
- export declare function cosineOf(a: ArrayLike<number>, b: ArrayLike<number>): number;
31
- /** Embed a single memory entry and cache the result in the embedding index; with `store`, through its vectorWrites, never opening hippo.db. */
32
- export declare function embedMemory(hippoRoot: string, entry: MemoryEntry, model?: string, store?: HippoStore): Promise<void>;
33
- /** Embeds every entry with no cached vector, prunes vectors of deleted memories, and returns how many it embedded; `provider` defaults to the
34
- * configured one. With `store`, every tenant's memories with no vector for the provider's model go through its `vectorWrites`, never hippo.db. */
35
- export declare function embedAll(hippoRoot: string, model?: string, provider?: EmbeddingProvider, store?: HippoStore): Promise<number>;
36
26
  //# sourceMappingURL=index.d.ts.map
@@ -1,19 +1,10 @@
1
- /** Optional embedding-based semantic search for Hippo.
2
- * Uses @huggingface/transformers (local, no API keys, ~22MB model); falls back silently if not installed. */
3
- import { envByName } from '../../util/env.js';
4
- import * as fs from 'fs';
5
- import * as path from 'path';
6
- import { randomUUID } from 'crypto';
7
- import { chunked, loadAllEntryIds, loadEntriesByIds } from '../entry-reads.js';
8
- import { rethrowIfSqliteBlocked } from '../../db/index.js';
1
+ /** The stored vector index's identity: which model and text format built it, and when a provider change means a rebuild.
2
+ * Picking a provider and computing vectors sit in src/search/embed-memories.ts; this module only reads and writes what is stored. */
3
+ import { cosineOf } from '../../core/cosine.js';
9
4
  import { EMBEDDING_MODEL_META_KEY } from '../../db/vector-store.js';
10
- import { initializeParticle } from '../../db/physics-state.js';
11
- import { indexedModel, pruneStoredVectors, replacesIndex, resetStoredParticles, saveEmbeddingIndex, saveIndexIdentity, saveStoredVectors, seedStoredParticle, storedIndexState, } from '../vector-index.js';
12
- import { loadConfig } from '../../core/config.js';
13
- import { resolveEmbeddingProvider } from './provider.js';
14
- import { redactSecretsStrict } from '../../util/secret-detect.js';
5
+ import { indexedModel, saveIndexIdentity, storedIndexState } from '../vector-index.js';
15
6
  import { errorMessage, log } from '../../util/log.js';
16
- import { StoreNotPortedError } from '../../util/sqlite-blocked.js';
7
+ import { rethrowIfSqliteBlocked } from '../../util/sqlite-blocked.js';
17
8
  export { EMBEDDING_MODEL_META_KEY };
18
9
  /** Bump when `embeddingInputText` changes existing vectors; folded into the stored index identity (`embeddingIndexIdentity`) so it reindexes like a model
19
10
  * change. Format 2 = `path:*` tags excluded; format 1 (implicit, no suffix) included them. */
@@ -57,368 +48,8 @@ export function resolveIndexedEmbeddingModel(hippoRoot, index) {
57
48
  export function embeddingModelRequiresReindex(hippoRoot, model, index) {
58
49
  return indexNeedsRebuild(resolveIndexedEmbeddingModel(hippoRoot, index), model);
59
50
  }
60
- const STORE_PAGE = 64;
61
- /** The rows for `ids`, a page at a time and in that order; an id deleted since it was listed is skipped. */
62
- function* entryPages(hippoRoot, ids) {
63
- for (const page of chunked(ids, STORE_PAGE)) {
64
- const byId = new Map(loadEntriesByIds(hippoRoot, page).map((e) => [e.id, e]));
65
- const entries = page.flatMap((id) => byId.get(id) ?? []);
66
- if (entries.length > 0)
67
- yield entries;
68
- }
69
- }
70
- async function rebuildEmbeddingIndex(hippoRoot, ids, provider) {
71
- const rebuilt = {};
72
- for (const entries of entryPages(hippoRoot, ids)) {
73
- // On a hard transport/auth failure provider.embed throws, so the caller aborts WITHOUT saving
74
- // a partial index (atomic reindex: the old index + stored identity are preserved).
75
- const vectors = await provider.embed(entries.map((e) => embeddingInputText(e)), 'passage');
76
- for (let i = 0; i < entries.length; i++) {
77
- const vec = vectors[i];
78
- if (vec && vec.length > 0) {
79
- rebuilt[entries[i].id] = vec;
80
- }
81
- else {
82
- noteSkippedEmbedding(entries[i].id);
83
- }
84
- }
85
- }
86
- return rebuilt;
87
- }
88
- function resetPhysicsFromIndex(hippoRoot, ids, index) {
89
- try {
90
- resetStoredParticles(hippoRoot, ids, index);
91
- }
92
- catch (err) {
93
- // Best effort: retrieval still falls back without physics state.
94
- log.warn(`physics reset after reindex failed: ${errorMessage(err)}`);
95
- }
96
- }
97
- /** A provider's `[]` row is a swallowed per-item failure; name the memory so the gap can be traced. */
98
- function noteSkippedEmbedding(id) {
99
- log.warn('memory not embedded; the next embed run retries it', { id });
100
- }
101
51
  /** Cosine similarity; handles unnormalized vectors, returns 0 for empty or mismatched vectors. */
102
52
  export function cosineSimilarity(a, b) {
103
53
  return cosineOf(a, b);
104
54
  }
105
- /** `cosineSimilarity` over any indexable vectors; a Float32 view reads the same doubles as its number[] copy, so the score is the same. */
106
- export function cosineOf(a, b) {
107
- if (a.length === 0 || b.length === 0 || a.length !== b.length)
108
- return 0;
109
- let dot = 0;
110
- let normA = 0;
111
- let normB = 0;
112
- for (let i = 0; i < a.length; i++) {
113
- dot += a[i] * b[i];
114
- normA += a[i] * a[i];
115
- normB += b[i] * b[i];
116
- }
117
- const denom = Math.sqrt(normA) * Math.sqrt(normB);
118
- if (denom < 1e-10)
119
- return 0;
120
- // Clamp to [-1, 1] to handle floating point drift
121
- return Math.min(1, Math.max(-1, dot / denom));
122
- }
123
- const EMBED_LOCK_FILE = 'embeddings.lock';
124
- const EMBED_LOCK_WAIT_MS = 10_000;
125
- const EMBED_LOCK_OWNER = `${process.pid}:${randomUUID()}`;
126
- // In-process mutex plus an O_EXCL "<pid>:<token>" lock file: our token is a lock we leaked; our PID
127
- // with another token is a live worker thread, unless the lock predates this process (a reused PID).
128
- let _embedWriteLock = Promise.resolve();
129
- function embedLockHolderAlive(lockPath) {
130
- let raw;
131
- try {
132
- raw = fs.readFileSync(lockPath, 'utf8');
133
- }
134
- catch (err) {
135
- return !(err instanceof Error && 'code' in err && err.code === 'ENOENT');
136
- }
137
- const mtimeMs = fs.statSync(lockPath, { throwIfNoEntry: false })?.mtimeMs ?? 0;
138
- const pid = Number(raw.split(':')[0]);
139
- // An empty lock is a holder between create and write; after 5 s it is a crashed one.
140
- if (!Number.isInteger(pid) || pid <= 0)
141
- return Date.now() - mtimeMs < 5_000;
142
- if (raw === EMBED_LOCK_OWNER)
143
- return false;
144
- if (pid === process.pid)
145
- return mtimeMs >= Date.now() - process.uptime() * 1000;
146
- try {
147
- process.kill(pid, 0);
148
- return true;
149
- }
150
- catch (err) {
151
- return err instanceof Error && 'code' in err && err.code === 'EPERM';
152
- }
153
- }
154
- // After the double-break race below the file can be another writer's lock, so remove only our own.
155
- function releaseEmbedFileLock(lockPath) {
156
- let raw;
157
- try {
158
- raw = fs.readFileSync(lockPath, 'utf8');
159
- }
160
- catch (err) {
161
- if (err instanceof Error && 'code' in err && err.code === 'ENOENT')
162
- return;
163
- throw err;
164
- }
165
- if (raw === EMBED_LOCK_OWNER)
166
- fs.rmSync(lockPath, { force: true });
167
- }
168
- async function acquireEmbedFileLock(hippoRoot) {
169
- const lockPath = path.join(hippoRoot, EMBED_LOCK_FILE);
170
- const deadline = Date.now() + EMBED_LOCK_WAIT_MS;
171
- for (;;) {
172
- try {
173
- fs.writeFileSync(lockPath, EMBED_LOCK_OWNER, { flag: 'wx' });
174
- return () => releaseEmbedFileLock(lockPath);
175
- }
176
- catch (err) {
177
- if (!(err instanceof Error && 'code' in err && err.code === 'EEXIST'))
178
- throw err;
179
- }
180
- // SHORTCUT: two waiters can both break one dead holder's lock; a vector lost that way is backfilled by the next `hippo embed`.
181
- if (!embedLockHolderAlive(lockPath)) {
182
- fs.rmSync(lockPath, { force: true });
183
- continue;
184
- }
185
- if (Date.now() >= deadline)
186
- throw new Error(`the embedding index is busy: another hippo process holds ${lockPath}`);
187
- await new Promise((r) => setTimeout(r, 50));
188
- }
189
- }
190
- async function withEmbedLock(hippoRoot, fn) {
191
- return withProcessEmbedLock(async () => {
192
- const release = await acquireEmbedFileLock(hippoRoot);
193
- try {
194
- return await fn();
195
- }
196
- finally {
197
- release();
198
- }
199
- });
200
- }
201
- // A store keeps each write whole in its own transaction, and a lock file in hippoRoot would not reach a worker on another host.
202
- async function withProcessEmbedLock(fn) {
203
- let resolve;
204
- const next = new Promise(r => { resolve = r; });
205
- const prev = _embedWriteLock;
206
- _embedWriteLock = next;
207
- await prev;
208
- try {
209
- return await fn();
210
- }
211
- finally {
212
- resolve();
213
- }
214
- }
215
- // A bad key fails every write; one warning tells the user, N would bury the command's own output.
216
- let _embedFailureWarned = false;
217
- function warnEmbedFailureOnce(source, rawMessage) {
218
- if (_embedFailureWarned)
219
- return;
220
- _embedFailureWarned = true;
221
- // Strict scrub: this line can land in a hook log file, and an API may echo the key back in its error body.
222
- const message = redactSecretsStrict(rawMessage).replace(/\s+/g, ' ').replace(/\.+$/, '');
223
- log.warn(`embedding failed (${source}): ${message}. Memories are stored without embeddings until this is fixed.`);
224
- }
225
- // requireGroup (src/store/port.ts) would close an import cycle with this module.
226
- function vectorGroups(store) {
227
- if (store.vectors === undefined)
228
- throw new StoreNotPortedError(store.kind, 'vectors');
229
- if (store.vectorWrites === undefined)
230
- throw new StoreNotPortedError(store.kind, 'vectorWrites');
231
- return [store.vectors, store.vectorWrites];
232
- }
233
- /** Writes one page's vectors, one writeVectors per tenant, and stops at the first refused write; `withParticles` seeds each memory's particle. */
234
- async function writeVectorPage(writes, write, page, vectors, withParticles) {
235
- const byTenant = new Map();
236
- page.forEach((entry, i) => {
237
- const vector = vectors[i];
238
- if (!vector || vector.length === 0)
239
- return noteSkippedEmbedding(entry.id);
240
- const row = withParticles ? { memoryId: entry.id, vector, particle: initializeParticle(entry, vector) } : { memoryId: entry.id, vector };
241
- byTenant.set(entry.tenantId, [...(byTenant.get(entry.tenantId) ?? []), row]);
242
- });
243
- let written = 0;
244
- for (const [tenantId, rows] of byTenant) {
245
- const result = await writes.writeVectors({ ...write, tenantId, rows });
246
- if (result.modelMismatch)
247
- return { written, modelMismatch: true };
248
- written += result.written;
249
- }
250
- return { written, modelMismatch: false };
251
- }
252
- const OTHER_MODEL_INDEX = "the vector index was built by another embedding model; run 'hippo embed' to rebuild it";
253
- /** Embeds every memory with no vector under `model`, page by page, so a provider failure keeps the pages written; a rebuild reseeds the particles it drops. */
254
- async function backfillInStore(writes, provider, model, rebuild) {
255
- let count = 0;
256
- let afterId;
257
- for (;;) {
258
- const page = await writes.entriesWithoutVector({ model, afterId, limit: STORE_PAGE });
259
- if (page.length === 0)
260
- return count;
261
- afterId = page[page.length - 1].id;
262
- const vectors = await provider.embed(page.map((e) => embeddingInputText(e)), 'passage');
263
- const result = await writeVectorPage(writes, { model, replaceIndex: rebuild }, page, vectors, rebuild);
264
- // Another process rebuilt the index mid-run; every later page would be refused too, after paying the provider for it.
265
- if (result.modelMismatch)
266
- throw new Error(OTHER_MODEL_INDEX);
267
- count += result.written;
268
- }
269
- }
270
- /** embedAll on a store: a model change re-embeds every memory, and the first page written drops the old index. */
271
- async function embedAllInStore(store, provider) {
272
- const [reads, writes] = vectorGroups(store);
273
- const rebuild = indexNeedsRebuild(indexedModel(await reads.embeddingIndexState()), provider.id);
274
- return backfillInStore(writes, provider, embeddingIndexIdentity(provider.id), rebuild);
275
- }
276
- /** embedMemory on a store; like the hippo.db path it resolves whatever fails. Unlike it, it leaves a model change to embedAll, so a stale
277
- * read here never drops another process's rebuild; the read only saves a paid embed call, as the write refuses another model itself. */
278
- function embedMemoryInStore(store, provider, entry) {
279
- return withProcessEmbedLock(async () => {
280
- const [reads, writes] = vectorGroups(store);
281
- const model = embeddingIndexIdentity(provider.id);
282
- try {
283
- const refused = replacesIndex(await reads.embeddingIndexState(), model)
284
- || (await writeVectorPage(writes, { model, replaceIndex: false }, [entry], await provider.embed([embeddingInputText(entry)], 'passage'), true)).modelMismatch;
285
- if (refused)
286
- warnEmbedFailureOnce('index', OTHER_MODEL_INDEX);
287
- }
288
- catch (err) {
289
- warnEmbedFailureOnce(provider.kind, errorMessage(err));
290
- }
291
- }).catch((err) => {
292
- log.warn(`skipped embedding ${entry.id} (${errorMessage(err)})`);
293
- });
294
- }
295
- /** Embed a single memory entry and cache the result in the embedding index; with `store`, through its vectorWrites, never opening hippo.db. */
296
- export async function embedMemory(hippoRoot, entry, model, store) {
297
- let provider;
298
- try {
299
- provider = resolveEmbeddingProvider(hippoRoot, { model });
300
- }
301
- catch (err) {
302
- // Callers fire and forget, so this must resolve: a bad config warns once instead of rejecting.
303
- warnEmbedFailureOnce('config', errorMessage(err));
304
- return;
305
- }
306
- if (!provider.isAvailable())
307
- return;
308
- if (store)
309
- return embedMemoryInStore(store, provider, entry);
310
- return withEmbedLock(hippoRoot, async () => {
311
- // Best-effort: an embedding failure (API down, bad key, 5xx) must not reject the caller's write; the existing index is left as-is.
312
- // Failures surface on the explicit `hippo embed` / `embedAll` path.
313
- try {
314
- const identity = provider.id;
315
- if (embeddingModelRequiresReindex(hippoRoot, identity)) {
316
- await rebuildIndexForProvider(hippoRoot, provider);
317
- return;
318
- }
319
- const text = embeddingInputText(entry);
320
- const [vector] = await provider.embed([text], 'passage');
321
- if (!vector || vector.length === 0)
322
- return;
323
- saveStoredVectors(hippoRoot, [[entry.id, vector]], embeddingIndexIdentity(identity));
324
- saveStoredEmbeddingModel(hippoRoot, identity);
325
- // Initialize physics state for this memory
326
- initializePhysicsIfMissing(hippoRoot, entry, vector);
327
- }
328
- catch (err) {
329
- // Provider failure (API down / bad key). Best-effort: leave the index as-is, but say so once.
330
- warnEmbedFailureOnce(provider.kind, errorMessage(err));
331
- }
332
- }).catch((err) => {
333
- log.warn(`skipped embedding ${entry.id} (${errorMessage(err)}); run 'hippo embed' to backfill`);
334
- });
335
- }
336
- // Every page is embedded before one transaction replaces the index, and the identity is saved only after that: a provider failure or a crash
337
- // at any earlier point leaves the old identity, so embeddingModelRequiresReindex has the next run rebuild from the start.
338
- async function rebuildIndexForProvider(hippoRoot, provider) {
339
- const identity = provider.id;
340
- // Host-wide rebuild: one embedding index per hippoRoot, keyed by tenant-scoped entry.id; per-tenant indices would be a larger architecture change.
341
- const ids = loadAllEntryIds(hippoRoot);
342
- const rebuiltIndex = await rebuildEmbeddingIndex(hippoRoot, ids, provider);
343
- saveEmbeddingIndex(hippoRoot, rebuiltIndex, embeddingIndexIdentity(identity));
344
- saveStoredEmbeddingModel(hippoRoot, identity);
345
- resetPhysicsFromIndex(hippoRoot, ids, rebuiltIndex);
346
- return Object.keys(rebuiltIndex).length;
347
- }
348
- function initializePhysicsIfMissing(hippoRoot, entry, vector) {
349
- try {
350
- seedStoredParticle(hippoRoot, entry, vector);
351
- }
352
- catch (err) {
353
- // Physics init is best-effort and must not fail the embedding that just landed.
354
- log.debug(`physics state not initialised for ${entry.id}: ${errorMessage(err)}`);
355
- }
356
- }
357
- /** Throws when an unavailable provider is a misconfiguration rather than an intentional no-op. */
358
- function throwIfProviderKeyMissing(hippoRoot, provider) {
359
- // A configured API provider with a missing key is a misconfiguration: surface it so callers of the exported embedAll() learn nothing was written.
360
- // Local-not-installed and an explicit enabled=false stay silent no-ops.
361
- const cfg = loadConfig(hippoRoot).embeddings;
362
- if (provider.kind !== 'local' &&
363
- cfg.enabled !== false &&
364
- provider.keyEnv &&
365
- !envByName(provider.keyEnv)?.trim()) {
366
- throw new Error(`Embedding provider '${provider.kind}' is configured but ${provider.keyEnv} is not set.`);
367
- }
368
- }
369
- // Embeds entries without a cached vector in save-checkpointed chunks; a `[]` row means that item could not be embedded and is retried next run.
370
- // On a hard provider failure mid-backfill the chunks already embedded are persisted (paid progress), then it stops and resumes next run.
371
- async function backfillPending(hippoRoot, provider, pending, model) {
372
- let count = 0;
373
- // Initialized to `undefined` so it stays a plain `unknown` binding for the arbitrary caught value; falsy either way.
374
- let backfillError = undefined;
375
- for (const chunk of entryPages(hippoRoot, pending)) {
376
- let vectors;
377
- try {
378
- vectors = await provider.embed(chunk.map((e) => embeddingInputText(e)), 'passage');
379
- }
380
- catch (err) {
381
- // Preserve the chunks already saved this run, then surface the failure
382
- // below so the explicit `hippo embed` path never reports a false success.
383
- backfillError = err;
384
- break;
385
- }
386
- const rows = [];
387
- for (let j = 0; j < chunk.length; j++) {
388
- const vec = vectors[j];
389
- if (vec && vec.length > 0)
390
- rows.push([chunk[j].id, vec]);
391
- else
392
- noteSkippedEmbedding(chunk[j].id);
393
- }
394
- count += saveStoredVectors(hippoRoot, rows, model);
395
- }
396
- return { count, backfillError };
397
- }
398
- /** Embeds every entry with no cached vector, prunes vectors of deleted memories, and returns how many it embedded; `provider` defaults to the
399
- * configured one. With `store`, every tenant's memories with no vector for the provider's model go through its `vectorWrites`, never hippo.db. */
400
- export async function embedAll(hippoRoot, model, provider = resolveEmbeddingProvider(hippoRoot, { model }), store) {
401
- if (!provider.isAvailable()) {
402
- throwIfProviderKeyMissing(hippoRoot, provider);
403
- return 0;
404
- }
405
- if (store)
406
- return withProcessEmbedLock(() => embedAllInStore(store, provider));
407
- return withEmbedLock(hippoRoot, async () => {
408
- const identity = provider.id;
409
- if (embeddingModelRequiresReindex(hippoRoot, identity))
410
- return rebuildIndexForProvider(hippoRoot, provider);
411
- // Host-wide by design: embedAll backfills all tenants' entries into the per-host index; per-tenant filtering would produce partial indices and break
412
- // recall.
413
- const embedded = pruneStoredVectors(hippoRoot);
414
- const pending = loadAllEntryIds(hippoRoot).filter((id) => !embedded.has(id));
415
- const { count, backfillError } = await backfillPending(hippoRoot, provider, pending, embeddingIndexIdentity(identity));
416
- saveStoredEmbeddingModel(hippoRoot, identity);
417
- // Partial progress is now persisted; surface a hard backfill failure so the
418
- // explicit embed path reports it (best-effort callers go via embedMemory).
419
- if (backfillError)
420
- throw backfillError;
421
- return count;
422
- });
423
- }
424
55
  //# sourceMappingURL=index.js.map