hippo-memory 1.60.0 → 1.62.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 (593) hide show
  1. package/README.md +29 -54
  2. package/dist/ablation.js +9 -27
  3. package/dist/agent-memories/apply.d.ts +1 -1
  4. package/dist/agent-memories/apply.js +4 -1
  5. package/dist/agent-memories/claude-code.d.ts +3 -1
  6. package/dist/agent-memories/claude-code.js +54 -10
  7. package/dist/agent-memories/codex.js +1 -1
  8. package/dist/agent-memories/gemini.js +1 -1
  9. package/dist/agent-memories/legacy.js +1 -1
  10. package/dist/agent-memories/source.js +1 -1
  11. package/dist/agent-memories/sync.d.ts +3 -3
  12. package/dist/agent-memories/sync.js +22 -9
  13. package/dist/agent-memories/types.d.ts +0 -2
  14. package/dist/ambient-store.d.ts +14 -0
  15. package/dist/ambient-store.js +90 -0
  16. package/dist/ambient.d.ts +23 -0
  17. package/dist/ambient.js +72 -50
  18. package/dist/api/assemble.d.ts +93 -0
  19. package/dist/api/assemble.js +153 -0
  20. package/dist/api/audit.d.ts +17 -0
  21. package/dist/api/audit.js +23 -0
  22. package/dist/api/auth.d.ts +79 -0
  23. package/dist/api/auth.js +178 -0
  24. package/dist/api/context-select.d.ts +49 -0
  25. package/dist/api/context-select.js +344 -0
  26. package/dist/api/context-types.d.ts +105 -0
  27. package/dist/api/context-types.js +3 -0
  28. package/dist/api/context.d.ts +31 -0
  29. package/dist/api/context.js +378 -0
  30. package/dist/api/dormant.d.ts +30 -0
  31. package/dist/api/dormant.js +140 -0
  32. package/dist/api/drill-down.d.ts +84 -0
  33. package/dist/api/drill-down.js +126 -0
  34. package/dist/api/forget.d.ts +57 -0
  35. package/dist/api/forget.js +87 -0
  36. package/dist/api/goals.d.ts +18 -0
  37. package/dist/api/goals.js +33 -0
  38. package/dist/api/learn.d.ts +31 -0
  39. package/dist/api/learn.js +88 -0
  40. package/dist/api/outcome.d.ts +61 -0
  41. package/dist/api/outcome.js +66 -0
  42. package/dist/api/promote.d.ts +54 -0
  43. package/dist/api/promote.js +192 -0
  44. package/dist/api/quarantine.d.ts +24 -0
  45. package/dist/api/quarantine.js +121 -0
  46. package/dist/api/recall-types.d.ts +390 -0
  47. package/dist/api/recall-types.js +3 -0
  48. package/dist/api/recall.d.ts +36 -0
  49. package/dist/api/recall.js +499 -0
  50. package/dist/api/remember.d.ts +35 -0
  51. package/dist/api/remember.js +43 -0
  52. package/dist/api/sleep.d.ts +136 -0
  53. package/dist/api/sleep.js +256 -0
  54. package/dist/api/tokens.d.ts +26 -0
  55. package/dist/api/tokens.js +60 -0
  56. package/dist/api/types.d.ts +56 -0
  57. package/dist/api/types.js +38 -0
  58. package/dist/api.d.ts +20 -1262
  59. package/dist/api.js +25 -2727
  60. package/dist/audit.d.ts +3 -0
  61. package/dist/audit.js +6 -3
  62. package/dist/auth.d.ts +45 -4
  63. package/dist/auth.js +125 -48
  64. package/dist/autolearn.js +2 -2
  65. package/dist/capture/command.d.ts +33 -0
  66. package/dist/capture/command.js +264 -0
  67. package/dist/capture/compact.d.ts +44 -0
  68. package/dist/capture/compact.js +354 -0
  69. package/dist/capture/extract.d.ts +21 -0
  70. package/dist/capture/extract.js +464 -0
  71. package/dist/capture/transcript.d.ts +40 -0
  72. package/dist/capture/transcript.js +193 -0
  73. package/dist/capture-error.js +2 -1
  74. package/dist/churn-git.js +4 -2
  75. package/dist/cli/audit.d.ts +3 -0
  76. package/dist/cli/audit.js +159 -0
  77. package/dist/cli/auth.d.ts +2 -0
  78. package/dist/cli/auth.js +171 -0
  79. package/dist/cli/briefs.d.ts +4 -0
  80. package/dist/cli/briefs.js +453 -0
  81. package/dist/cli/card.d.ts +3 -0
  82. package/dist/cli/card.js +333 -0
  83. package/dist/cli/context.d.ts +15 -0
  84. package/dist/cli/context.js +376 -0
  85. package/dist/cli/continuity.d.ts +6 -0
  86. package/dist/cli/continuity.js +457 -0
  87. package/dist/cli/curate.d.ts +19 -0
  88. package/dist/cli/curate.js +556 -0
  89. package/dist/cli/dag.d.ts +5 -0
  90. package/dist/cli/dag.js +177 -0
  91. package/dist/cli/decisions.d.ts +4 -0
  92. package/dist/cli/decisions.js +528 -0
  93. package/dist/cli/eval.d.ts +5 -0
  94. package/dist/cli/eval.js +213 -0
  95. package/dist/cli/explain.d.ts +4 -0
  96. package/dist/cli/explain.js +156 -0
  97. package/dist/cli/goals.d.ts +2 -0
  98. package/dist/cli/goals.js +196 -0
  99. package/dist/cli/hook-blocks.d.ts +18 -0
  100. package/dist/cli/hook-blocks.js +233 -0
  101. package/dist/cli/init.d.ts +2 -0
  102. package/dist/cli/init.js +305 -0
  103. package/dist/cli/maintenance.d.ts +4 -0
  104. package/dist/cli/maintenance.js +190 -0
  105. package/dist/cli/playbooks.d.ts +4 -0
  106. package/dist/cli/playbooks.js +573 -0
  107. package/dist/cli/projects.js +9 -6
  108. package/dist/cli/recall.d.ts +7 -0
  109. package/dist/cli/recall.js +582 -0
  110. package/dist/cli/remember.d.ts +5 -0
  111. package/dist/cli/remember.js +485 -0
  112. package/dist/cli/serve.d.ts +5 -0
  113. package/dist/cli/serve.js +40 -0
  114. package/dist/cli/session-hooks.d.ts +29 -0
  115. package/dist/cli/session-hooks.js +647 -0
  116. package/dist/cli/setup.d.ts +4 -0
  117. package/dist/cli/setup.js +397 -0
  118. package/dist/cli/shared.d.ts +15 -19
  119. package/dist/cli/shared.js +50 -341
  120. package/dist/cli/slack.d.ts +2 -0
  121. package/dist/cli/slack.js +171 -0
  122. package/dist/cli/status.d.ts +18 -0
  123. package/dist/cli/status.js +409 -0
  124. package/dist/cli/transfer.d.ts +10 -0
  125. package/dist/cli/transfer.js +424 -0
  126. package/dist/cli/usage.d.ts +85 -0
  127. package/dist/cli/usage.js +741 -0
  128. package/dist/cli.d.ts +71 -120
  129. package/dist/cli.js +170 -8469
  130. package/dist/client.js +15 -8
  131. package/dist/compaction-record.d.ts +0 -2
  132. package/dist/compaction-record.js +7 -5
  133. package/dist/connectors/github/backfill.js +94 -87
  134. package/dist/connectors/github/cli-impl.js +4 -3
  135. package/dist/connectors/github/dlq.js +67 -54
  136. package/dist/connectors/github/ingest.js +34 -35
  137. package/dist/connectors/github/tenant-routing.js +3 -2
  138. package/dist/connectors/github/webhook.js +135 -216
  139. package/dist/connectors/slack/dlq.js +49 -61
  140. package/dist/connectors/slack/ingest.js +55 -48
  141. package/dist/connectors/slack/tenant-routing.js +4 -3
  142. package/dist/connectors/slack/webhook.js +72 -74
  143. package/dist/consolidate/conflicts.d.ts +10 -0
  144. package/dist/consolidate/conflicts.js +178 -0
  145. package/dist/consolidate/decay.d.ts +12 -0
  146. package/dist/consolidate/decay.js +145 -0
  147. package/dist/consolidate/llm-passes.d.ts +3 -0
  148. package/dist/consolidate/llm-passes.js +141 -0
  149. package/dist/consolidate/merge.d.ts +7 -0
  150. package/dist/consolidate/merge.js +251 -0
  151. package/dist/consolidate/physics-pass.d.ts +3 -0
  152. package/dist/consolidate/physics-pass.js +60 -0
  153. package/dist/consolidate/run.d.ts +69 -0
  154. package/dist/consolidate/run.js +76 -0
  155. package/dist/consolidate/sleep.d.ts +18 -0
  156. package/dist/consolidate/sleep.js +209 -0
  157. package/dist/consolidate/traces.d.ts +4 -0
  158. package/dist/consolidate/traces.js +178 -0
  159. package/dist/context-auto.js +7 -11
  160. package/dist/context-render.d.ts +1 -1
  161. package/dist/context-render.js +1 -1
  162. package/dist/customer-notes.d.ts +3 -0
  163. package/dist/customer-notes.js +83 -72
  164. package/dist/dag.js +225 -188
  165. package/dist/dashboard-actions.d.ts +20 -0
  166. package/dist/dashboard-actions.js +88 -0
  167. package/dist/dashboard-params.d.ts +45 -0
  168. package/dist/dashboard-params.js +127 -0
  169. package/dist/dashboard-queries.d.ts +15 -0
  170. package/dist/dashboard-queries.js +355 -0
  171. package/dist/dashboard-snapshot.d.ts +138 -0
  172. package/dist/dashboard-snapshot.js +308 -0
  173. package/dist/dashboard-types.d.ts +163 -0
  174. package/dist/dashboard-types.js +3 -0
  175. package/dist/dashboard.d.ts +6 -7
  176. package/dist/dashboard.js +228 -202
  177. package/dist/db/busy.d.ts +5 -0
  178. package/dist/db/busy.js +24 -0
  179. package/dist/db/continuity.d.ts +5 -0
  180. package/dist/db/continuity.js +145 -0
  181. package/dist/db/meta.d.ts +8 -0
  182. package/dist/db/meta.js +35 -0
  183. package/dist/db/migrate.d.ts +9 -0
  184. package/dist/db/migrate.js +138 -0
  185. package/dist/db/migrations/index.d.ts +5 -0
  186. package/dist/db/migrations/index.js +109 -0
  187. package/dist/db/migrations/types.d.ts +14 -0
  188. package/dist/db/migrations/types.js +2 -0
  189. package/dist/db/migrations/v01.d.ts +3 -0
  190. package/dist/db/migrations/v01.js +38 -0
  191. package/dist/db/migrations/v02.d.ts +3 -0
  192. package/dist/db/migrations/v02.js +21 -0
  193. package/dist/db/migrations/v03.d.ts +3 -0
  194. package/dist/db/migrations/v03.js +22 -0
  195. package/dist/db/migrations/v04.d.ts +3 -0
  196. package/dist/db/migrations/v04.js +28 -0
  197. package/dist/db/migrations/v05.d.ts +3 -0
  198. package/dist/db/migrations/v05.js +21 -0
  199. package/dist/db/migrations/v06.d.ts +3 -0
  200. package/dist/db/migrations/v06.js +25 -0
  201. package/dist/db/migrations/v07.d.ts +3 -0
  202. package/dist/db/migrations/v07.js +13 -0
  203. package/dist/db/migrations/v08.d.ts +3 -0
  204. package/dist/db/migrations/v08.js +8 -0
  205. package/dist/db/migrations/v09.d.ts +3 -0
  206. package/dist/db/migrations/v09.js +13 -0
  207. package/dist/db/migrations/v10.d.ts +3 -0
  208. package/dist/db/migrations/v10.js +17 -0
  209. package/dist/db/migrations/v11.d.ts +3 -0
  210. package/dist/db/migrations/v11.js +15 -0
  211. package/dist/db/migrations/v12.d.ts +3 -0
  212. package/dist/db/migrations/v12.js +11 -0
  213. package/dist/db/migrations/v13.d.ts +3 -0
  214. package/dist/db/migrations/v13.js +15 -0
  215. package/dist/db/migrations/v14.d.ts +3 -0
  216. package/dist/db/migrations/v14.js +66 -0
  217. package/dist/db/migrations/v15.d.ts +3 -0
  218. package/dist/db/migrations/v15.js +42 -0
  219. package/dist/db/migrations/v16.d.ts +3 -0
  220. package/dist/db/migrations/v16.js +61 -0
  221. package/dist/db/migrations/v17.d.ts +3 -0
  222. package/dist/db/migrations/v17.js +46 -0
  223. package/dist/db/migrations/v18.d.ts +3 -0
  224. package/dist/db/migrations/v18.js +60 -0
  225. package/dist/db/migrations/v19.d.ts +3 -0
  226. package/dist/db/migrations/v19.js +28 -0
  227. package/dist/db/migrations/v20.d.ts +3 -0
  228. package/dist/db/migrations/v20.js +42 -0
  229. package/dist/db/migrations/v21.d.ts +3 -0
  230. package/dist/db/migrations/v21.js +16 -0
  231. package/dist/db/migrations/v22.d.ts +3 -0
  232. package/dist/db/migrations/v22.js +82 -0
  233. package/dist/db/migrations/v23.d.ts +3 -0
  234. package/dist/db/migrations/v23.js +48 -0
  235. package/dist/db/migrations/v24.d.ts +3 -0
  236. package/dist/db/migrations/v24.js +72 -0
  237. package/dist/db/migrations/v25.d.ts +3 -0
  238. package/dist/db/migrations/v25.js +46 -0
  239. package/dist/db/migrations/v26.d.ts +3 -0
  240. package/dist/db/migrations/v26.js +23 -0
  241. package/dist/db/migrations/v27.d.ts +3 -0
  242. package/dist/db/migrations/v27.js +57 -0
  243. package/dist/db/migrations/v28.d.ts +3 -0
  244. package/dist/db/migrations/v28.js +38 -0
  245. package/dist/db/migrations/v29.d.ts +3 -0
  246. package/dist/db/migrations/v29.js +78 -0
  247. package/dist/db/migrations/v30.d.ts +3 -0
  248. package/dist/db/migrations/v30.js +92 -0
  249. package/dist/db/migrations/v31.d.ts +3 -0
  250. package/dist/db/migrations/v31.js +74 -0
  251. package/dist/db/migrations/v32.d.ts +3 -0
  252. package/dist/db/migrations/v32.js +102 -0
  253. package/dist/db/migrations/v33.d.ts +3 -0
  254. package/dist/db/migrations/v33.js +104 -0
  255. package/dist/db/migrations/v34.d.ts +3 -0
  256. package/dist/db/migrations/v34.js +93 -0
  257. package/dist/db/migrations/v35.d.ts +3 -0
  258. package/dist/db/migrations/v35.js +98 -0
  259. package/dist/db/migrations/v36.d.ts +3 -0
  260. package/dist/db/migrations/v36.js +98 -0
  261. package/dist/db/migrations/v37.d.ts +3 -0
  262. package/dist/db/migrations/v37.js +219 -0
  263. package/dist/db/migrations/v38.d.ts +3 -0
  264. package/dist/db/migrations/v38.js +277 -0
  265. package/dist/db/migrations/v39.d.ts +3 -0
  266. package/dist/db/migrations/v39.js +59 -0
  267. package/dist/db/migrations/v40.d.ts +3 -0
  268. package/dist/db/migrations/v40.js +74 -0
  269. package/dist/db/migrations/v41.d.ts +3 -0
  270. package/dist/db/migrations/v41.js +43 -0
  271. package/dist/db/migrations/v42.d.ts +3 -0
  272. package/dist/db/migrations/v42.js +41 -0
  273. package/dist/db/migrations/v43.d.ts +3 -0
  274. package/dist/db/migrations/v43.js +67 -0
  275. package/dist/db/migrations/v44.d.ts +3 -0
  276. package/dist/db/migrations/v44.js +28 -0
  277. package/dist/db/migrations/v45.d.ts +3 -0
  278. package/dist/db/migrations/v45.js +30 -0
  279. package/dist/db/migrations/v46.d.ts +3 -0
  280. package/dist/db/migrations/v46.js +25 -0
  281. package/dist/db/migrations/v47.d.ts +3 -0
  282. package/dist/db/migrations/v47.js +17 -0
  283. package/dist/db/migrations/v48.d.ts +3 -0
  284. package/dist/db/migrations/v48.js +10 -0
  285. package/dist/db/migrations/v49.d.ts +3 -0
  286. package/dist/db/migrations/v49.js +31 -0
  287. package/dist/db/migrations/v50.d.ts +3 -0
  288. package/dist/db/migrations/v50.js +67 -0
  289. package/dist/db/migrations/v51.d.ts +3 -0
  290. package/dist/db/migrations/v51.js +14 -0
  291. package/dist/db/migrations/v52.d.ts +3 -0
  292. package/dist/db/migrations/v52.js +7 -0
  293. package/dist/db/open.d.ts +23 -0
  294. package/dist/db/open.js +146 -0
  295. package/dist/db/sqlite.d.ts +21 -0
  296. package/dist/db/sqlite.js +8 -0
  297. package/dist/db/tables.d.ts +7 -0
  298. package/dist/db/tables.js +38 -0
  299. package/dist/db.d.ts +6 -46
  300. package/dist/db.js +5 -3049
  301. package/dist/decisions.d.ts +4 -1
  302. package/dist/decisions.js +102 -83
  303. package/dist/dedupe.js +3 -2
  304. package/dist/delivery-recorder.js +4 -1
  305. package/dist/doctor.js +14 -10
  306. package/dist/embedding-provider.d.ts +1 -1
  307. package/dist/embedding-provider.js +4 -3
  308. package/dist/embeddings.d.ts +9 -52
  309. package/dist/embeddings.js +43 -297
  310. package/dist/env.d.ts +75 -0
  311. package/dist/env.js +119 -0
  312. package/dist/eval-suite.js +1 -1
  313. package/dist/eval.js +2 -2
  314. package/dist/extract.js +1 -1
  315. package/dist/gated-write.js +3 -1
  316. package/dist/goals.d.ts +3 -1
  317. package/dist/goals.js +117 -86
  318. package/dist/graph/read.d.ts +73 -0
  319. package/dist/graph/read.js +325 -0
  320. package/dist/graph/rows.d.ts +45 -0
  321. package/dist/graph/rows.js +51 -0
  322. package/dist/graph/types.d.ts +83 -0
  323. package/dist/graph/types.js +11 -0
  324. package/dist/graph/write.d.ts +93 -0
  325. package/dist/{graph.js → graph/write.js} +6 -384
  326. package/dist/graph-extract.js +2 -1
  327. package/dist/graph-recall.d.ts +1 -1
  328. package/dist/graph-recall.js +2 -2
  329. package/dist/graph-stream.js +1 -1
  330. package/dist/graph-view.d.ts +1 -1
  331. package/dist/graph-view.js +1 -1
  332. package/dist/half-life-migration.d.ts +1 -1
  333. package/dist/half-life-migration.js +2 -1
  334. package/dist/hooks/codex-session.d.ts +8 -0
  335. package/dist/hooks/codex-session.js +76 -0
  336. package/dist/hooks/codex-wrapper.d.ts +55 -0
  337. package/dist/hooks/codex-wrapper.js +288 -0
  338. package/dist/hooks/json-hooks.d.ts +63 -0
  339. package/dist/hooks/json-hooks.js +356 -0
  340. package/dist/hooks/opencode.d.ts +50 -0
  341. package/dist/hooks/opencode.js +202 -0
  342. package/dist/hooks/shared.d.ts +54 -0
  343. package/dist/hooks/shared.js +77 -0
  344. package/dist/http-retry.d.ts +2 -0
  345. package/dist/http-retry.js +4 -3
  346. package/dist/http-util.d.ts +3 -0
  347. package/dist/http-util.js +10 -0
  348. package/dist/{importers.d.ts → importers/core.d.ts} +13 -17
  349. package/dist/importers/core.js +141 -0
  350. package/dist/importers/markdown-parse.d.ts +41 -0
  351. package/dist/importers/markdown-parse.js +132 -0
  352. package/dist/importers/markdown.d.ts +3 -0
  353. package/dist/importers/markdown.js +92 -0
  354. package/dist/importers/sources.d.ts +7 -0
  355. package/dist/importers/sources.js +229 -0
  356. package/dist/importers/vault.d.ts +11 -0
  357. package/dist/importers/vault.js +352 -0
  358. package/dist/incidents.d.ts +3 -0
  359. package/dist/incidents.js +52 -43
  360. package/dist/index.d.ts +25 -6
  361. package/dist/index.js +23 -6
  362. package/dist/invalidation.js +2 -1
  363. package/dist/judgment.js +2 -1
  364. package/dist/keyset.d.ts +13 -0
  365. package/dist/keyset.js +8 -0
  366. package/dist/local-embedding.d.ts +13 -0
  367. package/dist/local-embedding.js +165 -0
  368. package/dist/log.d.ts +7 -0
  369. package/dist/log.js +19 -1
  370. package/dist/mcp/admin-tools.d.ts +8 -0
  371. package/dist/mcp/admin-tools.js +116 -0
  372. package/dist/mcp/format.d.ts +27 -0
  373. package/dist/mcp/format.js +135 -0
  374. package/dist/mcp/memory-tools.d.ts +5 -0
  375. package/dist/mcp/memory-tools.js +83 -0
  376. package/dist/mcp/protocol.d.ts +83 -0
  377. package/dist/mcp/protocol.js +55 -0
  378. package/dist/mcp/recall-tools.d.ts +6 -0
  379. package/dist/mcp/recall-tools.js +320 -0
  380. package/dist/mcp/request.d.ts +10 -0
  381. package/dist/mcp/request.js +163 -0
  382. package/dist/mcp/server.d.ts +4 -75
  383. package/dist/mcp/server.js +7 -1190
  384. package/dist/mcp/session-state.d.ts +11 -0
  385. package/dist/mcp/session-state.js +28 -0
  386. package/dist/mcp/stdio.d.ts +8 -0
  387. package/dist/mcp/stdio.js +79 -0
  388. package/dist/mcp/tools.d.ts +11 -0
  389. package/dist/mcp/tools.js +247 -0
  390. package/dist/memory.d.ts +3 -0
  391. package/dist/memory.js +27 -1
  392. package/dist/multihop.d.ts +1 -1
  393. package/dist/multihop.js +2 -1
  394. package/dist/owner-validation.js +2 -1
  395. package/dist/physics-state.js +10 -7
  396. package/dist/policies.d.ts +3 -0
  397. package/dist/policies.js +93 -74
  398. package/dist/postinstall.js +3 -2
  399. package/dist/predictions/planning-fallacy.d.ts +100 -0
  400. package/dist/predictions/planning-fallacy.js +190 -0
  401. package/dist/{predictions.d.ts → predictions/store.d.ts} +7 -102
  402. package/dist/predictions/store.js +434 -0
  403. package/dist/processes.d.ts +3 -0
  404. package/dist/processes.js +94 -76
  405. package/dist/project-briefs.d.ts +3 -0
  406. package/dist/project-briefs.js +142 -113
  407. package/dist/project-identity.js +3 -2
  408. package/dist/project-merge.d.ts +12 -4
  409. package/dist/project-merge.js +132 -45
  410. package/dist/quarantine.d.ts +2 -1
  411. package/dist/quarantine.js +8 -5
  412. package/dist/raw-archive.js +1 -1
  413. package/dist/recall-history.js +3 -2
  414. package/dist/recall-pipeline.d.ts +2 -2
  415. package/dist/recall-pipeline.js +16 -8
  416. package/dist/recall-scope.js +1 -1
  417. package/dist/recall-trace.d.ts +1 -1
  418. package/dist/refine-llm.js +2 -1
  419. package/dist/reject-flow.js +6 -1
  420. package/dist/rerankers/clef.js +6 -5
  421. package/dist/rerankers/jev.d.ts +1 -1
  422. package/dist/rerankers/jev.js +4 -4
  423. package/dist/rerankers/llm.d.ts +4 -2
  424. package/dist/rerankers/llm.js +58 -38
  425. package/dist/rerankers/types.d.ts +1 -1
  426. package/dist/salience.js +1 -1
  427. package/dist/scheduler.d.ts +1 -0
  428. package/dist/scheduler.js +26 -4
  429. package/dist/scope.js +4 -3
  430. package/dist/search/as-of.d.ts +10 -0
  431. package/dist/search/as-of.js +22 -0
  432. package/dist/search/bm25-search.d.ts +14 -0
  433. package/dist/search/bm25-search.js +43 -0
  434. package/dist/search/bm25.d.ts +15 -0
  435. package/dist/search/bm25.js +54 -0
  436. package/dist/search/boosts.d.ts +54 -0
  437. package/dist/search/boosts.js +94 -0
  438. package/dist/search/breakdown.d.ts +7 -0
  439. package/dist/search/breakdown.js +20 -0
  440. package/dist/search/explain.d.ts +25 -0
  441. package/dist/search/explain.js +31 -0
  442. package/dist/search/finalize.d.ts +8 -0
  443. package/dist/search/finalize.js +52 -0
  444. package/dist/search/fusion.d.ts +27 -0
  445. package/dist/search/fusion.js +42 -0
  446. package/dist/search/hybrid-score.d.ts +20 -0
  447. package/dist/search/hybrid-score.js +73 -0
  448. package/dist/search/hybrid.d.ts +46 -0
  449. package/dist/search/hybrid.js +64 -0
  450. package/dist/search/physics-search.d.ts +29 -0
  451. package/dist/search/physics-search.js +162 -0
  452. package/dist/search/rerank.d.ts +10 -0
  453. package/dist/search/rerank.js +72 -0
  454. package/dist/search/temporal.d.ts +15 -0
  455. package/dist/search/temporal.js +45 -0
  456. package/dist/search/types.d.ts +91 -0
  457. package/dist/search/types.js +2 -0
  458. package/dist/search/vector.d.ts +30 -0
  459. package/dist/search/vector.js +71 -0
  460. package/dist/secret-detect.d.ts +2 -0
  461. package/dist/secret-detect.js +2 -1
  462. package/dist/server/auth.d.ts +52 -0
  463. package/dist/server/auth.js +221 -0
  464. package/dist/server/client-ip.d.ts +25 -0
  465. package/dist/server/client-ip.js +92 -0
  466. package/dist/server/cursor.d.ts +23 -0
  467. package/dist/server/cursor.js +58 -0
  468. package/dist/server/lifecycle.d.ts +7 -0
  469. package/dist/server/lifecycle.js +29 -0
  470. package/dist/server/mcp-http.d.ts +5 -0
  471. package/dist/server/mcp-http.js +199 -0
  472. package/dist/server/request.d.ts +33 -0
  473. package/dist/server/request.js +103 -0
  474. package/dist/server/routes/admin.d.ts +9 -0
  475. package/dist/server/routes/admin.js +158 -0
  476. package/dist/server/routes/customer-notes.d.ts +7 -0
  477. package/dist/server/routes/customer-notes.js +112 -0
  478. package/dist/server/routes/decisions.d.ts +7 -0
  479. package/dist/server/routes/decisions.js +133 -0
  480. package/dist/server/routes/incidents.d.ts +7 -0
  481. package/dist/server/routes/incidents.js +126 -0
  482. package/dist/server/routes/memories.d.ts +10 -0
  483. package/dist/server/routes/memories.js +179 -0
  484. package/dist/server/routes/policies.d.ts +8 -0
  485. package/dist/server/routes/policies.js +151 -0
  486. package/dist/server/routes/predictions.d.ts +7 -0
  487. package/dist/server/routes/predictions.js +164 -0
  488. package/dist/server/routes/processes.d.ts +7 -0
  489. package/dist/server/routes/processes.js +161 -0
  490. package/dist/server/routes/project-briefs.d.ts +8 -0
  491. package/dist/server/routes/project-briefs.js +136 -0
  492. package/dist/server/routes/recall.d.ts +8 -0
  493. package/dist/server/routes/recall.js +340 -0
  494. package/dist/server/routes/skills.d.ts +8 -0
  495. package/dist/server/routes/skills.js +150 -0
  496. package/dist/server/types.d.ts +56 -0
  497. package/dist/server/types.js +2 -0
  498. package/dist/server/validation.d.ts +14 -0
  499. package/dist/server/validation.js +91 -0
  500. package/dist/server.d.ts +7 -61
  501. package/dist/server.js +69 -2362
  502. package/dist/session-digest.d.ts +1 -1
  503. package/dist/session-digest.js +9 -2
  504. package/dist/shared.d.ts +12 -1
  505. package/dist/shared.js +33 -27
  506. package/dist/skills.d.ts +3 -0
  507. package/dist/skills.js +88 -70
  508. package/dist/stdin.js +2 -2
  509. package/dist/store/audit-event.d.ts +19 -0
  510. package/dist/store/audit-event.js +33 -0
  511. package/dist/store/candidates.d.ts +42 -0
  512. package/dist/store/candidates.js +152 -0
  513. package/dist/store/conflicts.d.ts +44 -0
  514. package/dist/store/conflicts.js +444 -0
  515. package/dist/store/delete-and-batch.d.ts +63 -0
  516. package/dist/store/delete-and-batch.js +310 -0
  517. package/dist/store/entry-reads.d.ts +92 -0
  518. package/dist/store/entry-reads.js +255 -0
  519. package/dist/store/entry-row.d.ts +67 -0
  520. package/dist/store/entry-row.js +208 -0
  521. package/dist/store/entry-writes.d.ts +46 -0
  522. package/dist/store/entry-writes.js +148 -0
  523. package/dist/store/handoffs.d.ts +26 -0
  524. package/dist/store/handoffs.js +184 -0
  525. package/dist/store/index-and-stats.d.ts +52 -0
  526. package/dist/store/index-and-stats.js +214 -0
  527. package/dist/store/markdown.d.ts +10 -0
  528. package/dist/store/markdown.js +108 -0
  529. package/dist/store/mirrors.d.ts +49 -0
  530. package/dist/store/mirrors.js +312 -0
  531. package/dist/store/open.d.ts +15 -0
  532. package/dist/store/open.js +223 -0
  533. package/dist/store/rows.d.ts +178 -0
  534. package/dist/store/rows.js +158 -0
  535. package/dist/store/search-rows.d.ts +86 -0
  536. package/dist/store/search-rows.js +260 -0
  537. package/dist/store/sessions.d.ts +83 -0
  538. package/dist/store/sessions.js +272 -0
  539. package/dist/store/summaries.d.ts +94 -0
  540. package/dist/store/summaries.js +377 -0
  541. package/dist/store/tenant-lookup.d.ts +12 -0
  542. package/dist/store/tenant-lookup.js +16 -0
  543. package/dist/store-cards.js +2 -1
  544. package/dist/summary-dirty.d.ts +4 -0
  545. package/dist/summary-dirty.js +32 -0
  546. package/dist/support-bundle.js +4 -3
  547. package/dist/tenant.js +2 -2
  548. package/dist/tokenize.d.ts +2 -0
  549. package/dist/tokenize.js +16 -0
  550. package/dist/transcript-tail.d.ts +7 -0
  551. package/dist/transcript-tail.js +48 -0
  552. package/dist/vector-store.d.ts +27 -0
  553. package/dist/vector-store.js +210 -0
  554. package/dist/version.d.ts +2 -2
  555. package/dist/version.js +2 -2
  556. package/dist/working-memory.js +1 -1
  557. package/dist/yaml.js +36 -11
  558. package/dist-ui/assets/ibm-plex-mono-latin-400-normal-CvHOgSBP.woff +0 -0
  559. package/dist-ui/assets/ibm-plex-mono-latin-400-normal-DMJ8VG8y.woff2 +0 -0
  560. package/dist-ui/assets/ibm-plex-mono-latin-500-normal-CB9ihrfo.woff +0 -0
  561. package/dist-ui/assets/ibm-plex-mono-latin-500-normal-DSY6xOcd.woff2 +0 -0
  562. package/dist-ui/assets/ibm-plex-mono-latin-600-normal-BgSNZQsw.woff2 +0 -0
  563. package/dist-ui/assets/ibm-plex-mono-latin-600-normal-DWFSQ4vo.woff +0 -0
  564. package/dist-ui/assets/ibm-plex-sans-latin-400-normal-CDDApCn2.woff2 +0 -0
  565. package/dist-ui/assets/ibm-plex-sans-latin-400-normal-CYLoc0-x.woff +0 -0
  566. package/dist-ui/assets/ibm-plex-sans-latin-500-normal-6ng42L7E.woff2 +0 -0
  567. package/dist-ui/assets/ibm-plex-sans-latin-500-normal-BgVn5rGT.woff +0 -0
  568. package/dist-ui/assets/ibm-plex-sans-latin-600-normal-Cu4Hd6ag.woff +0 -0
  569. package/dist-ui/assets/ibm-plex-sans-latin-600-normal-CuJfVYMP.woff2 +0 -0
  570. package/dist-ui/assets/index-DPN7cP19.js +33 -0
  571. package/dist-ui/assets/index-dFloKRVr.css +1 -0
  572. package/dist-ui/index.html +3 -25
  573. package/extensions/openclaw-plugin/openclaw.plugin.json +1 -1
  574. package/extensions/openclaw-plugin/package.json +1 -1
  575. package/openclaw.plugin.json +1 -1
  576. package/package.json +1 -1
  577. package/dist/capture.d.ts +0 -155
  578. package/dist/capture.js +0 -1295
  579. package/dist/consolidate.d.ts +0 -58
  580. package/dist/consolidate.js +0 -1124
  581. package/dist/graph.d.ts +0 -245
  582. package/dist/hooks.d.ts +0 -208
  583. package/dist/hooks.js +0 -1076
  584. package/dist/importers.js +0 -900
  585. package/dist/predictions.js +0 -620
  586. package/dist/search.d.ts +0 -320
  587. package/dist/search.js +0 -970
  588. package/dist/store.d.ts +0 -776
  589. package/dist/store.js +0 -3473
  590. package/dist-ui/assets/d3-BiWEKnn4.js +0 -1
  591. package/dist-ui/assets/index-BhT8RvO6.js +0 -61
  592. package/dist-ui/assets/index-RoXXJ5dq.css +0 -1
  593. package/dist-ui/assets/three-BDgTxR1l.js +0 -4112
@@ -0,0 +1,499 @@
1
+ // Read path: recall (sync) and retrieve (async, adds the vector arm).
2
+ import { envRequireSessionScopedFreshTail } from '../env.js';
3
+ import { openHippoDb, closeHippoDb } from '../db.js';
4
+ import { DEFAULT_SEARCH_CANDIDATE_LIMIT } from '../store/rows.js';
5
+ import { strengthenRetrieved } from '../store/entry-writes.js';
6
+ import { isRecallBoostAblated } from '../ablation.js';
7
+ import { loadEntriesByIds, loadFreshRawMemories } from '../store/entry-reads.js';
8
+ import { loadRecallSearchEntries, recallScopeFilter } from '../store/search-rows.js';
9
+ import { loadActiveTaskSnapshot, listSessionEvents } from '../store/sessions.js';
10
+ import { loadLatestHandoff } from '../store/handoffs.js';
11
+ import { estimateTokens } from '../token-ledger.js';
12
+ import { formatHandoffEvidenceLine } from '../handoff.js';
13
+ import { appendAuditEvent, auditQueryFields } from '../audit.js';
14
+ import { writeRecallTrace, writeRecallTraceAtRoot } from '../recall-trace.js';
15
+ import { applyGoalStackBoost } from '../goals.js';
16
+ import { hybridSearch } from '../search/hybrid.js';
17
+ import { physicsSearch } from '../search/physics-search.js';
18
+ import { churnStaleFactor } from '../search/boosts.js';
19
+ import { compareEntryIdentity } from '../compare.js';
20
+ import { dropHeldCopies, duplicateKey, storedTextKeys } from '../same-text.js';
21
+ import { loadConfig } from '../config.js';
22
+ import { computePlanningFallacyOutput } from '../predictions/planning-fallacy.js';
23
+ import { detectAnchoring, hashQueryText, biasHintEnabled } from '../recall-history.js';
24
+ import { detectAvailabilityBias } from '../availability.js';
25
+ import { passesScopeFilterForRecall, assertScopeRequestAllowed, isRestrictedScope } from '../recall-scope.js';
26
+ import { RecallContractError } from './types.js';
27
+ /**
28
+ * Shared construction helper for `RecallSuppressionSummary`. Used by
29
+ * `api.recall`, `cmdRecall`, and the MCP `hippo_recall` handler so all three
30
+ * pipelines produce the same shape without duplicating field-construction
31
+ * logic. Pass-through identity today; kept as a helper so future field
32
+ * additions (B4 interference counter wiring, etc.) land at one site.
33
+ */
34
+ export function buildSuppressionSummary(counts) {
35
+ return {
36
+ totalCandidates: counts.totalCandidates,
37
+ droppedPreRank: counts.droppedPreRank,
38
+ droppedByBudget: counts.droppedByBudget,
39
+ summarySubstitutionsAdded: counts.summarySubstitutionsAdded,
40
+ freshTailAdded: counts.freshTailAdded,
41
+ suppressedByInterference: counts.suppressedByInterference,
42
+ };
43
+ }
44
+ /**
45
+ * Domain-level recall. Loads BM25-ranked candidates from SQLite scoped to
46
+ * `ctx.tenantId` and keeps that order whatever `mode` says; `retrieve` is the
47
+ * mode-aware, strengthening variant the HTTP route uses.
48
+ *
49
+ * **api.recall does NOT mutate `index.last_retrieval_ids`** (v1.11.5 contract
50
+ * lock). The CLI `cmdRecall` (cli.ts) writes `last_retrieval_ids` because the
51
+ * CLI is interactive (user is about to run `hippo outcome --good`). SDK callers
52
+ * are programmatic: they either pass explicit ids to `api.outcome` or call
53
+ * `api.getContext` first for the context-then-outcome workflow (getContext
54
+ * DOES write `last_retrieval_ids`). Adding the side-effect here would change
55
+ * `api.recall` from a pure read into a read+write, breaking SDK callers who
56
+ * batch recall calls in a row. Locked by
57
+ * `tests/api-recall-no-side-effects.test.ts`.
58
+ */
59
+ export function recall(ctx, opts) {
60
+ // A member key may not unlock a private or quarantined scope by naming it.
61
+ assertScopeRequestAllowed(ctx.actor, opts.scope);
62
+ const windowSize = recallWindowSize(opts);
63
+ return recallFrom(ctx, opts, windowSize, loadRecallSearchEntries(ctx.hippoRoot, opts.query, windowSize, ctx.tenantId, opts.scope, 'exact', false));
64
+ }
65
+ /** Mode-aware recall that strengthens each returned row; never writes last_retrieval_ids (v1.11.5 lock). */
66
+ export async function retrieve(ctx, opts) {
67
+ assertScopeRequestAllowed(ctx.actor, opts.scope);
68
+ const windowSize = recallWindowSize(opts);
69
+ if (opts.showRanked)
70
+ return retrieveFromStore(ctx, opts, windowSize, opts.showRanked);
71
+ let candidates = loadRecallSearchEntries(ctx.hippoRoot, opts.query, windowSize, ctx.tenantId, opts.scope, 'exact', false);
72
+ if (opts.mode === 'hybrid' || opts.mode === 'physics') {
73
+ const searchOpts = { budget: Infinity, hippoRoot: ctx.hippoRoot, scope: opts.scope ?? null, vectorCandidates: recallVectorSpec(ctx, opts) };
74
+ const ranked = opts.mode === 'physics'
75
+ ? await physicsSearch(opts.query, candidates, { ...searchOpts, physicsConfig: loadConfig(ctx.hippoRoot).physics })
76
+ : await hybridSearch(opts.query, candidates, searchOpts);
77
+ const rankedIds = new Set(ranked.map((r) => r.entry.id));
78
+ candidates = [...ranked.map((r) => r.entry), ...candidates.filter((e) => !rankedIds.has(e.id))];
79
+ }
80
+ const result = recallFrom(ctx, opts, windowSize, candidates);
81
+ strengthenRetrieved(ctx.hippoRoot, result.results.map((r) => r.id), { tenantId: ctx.tenantId, recallBoostAblated: isRecallBoostAblated() });
82
+ return result;
83
+ }
84
+ /** api.retrieve's vector arm: the recall load's exact-scope rule, current rows only. */
85
+ function recallVectorSpec(ctx, opts) {
86
+ return {
87
+ tenantId: ctx.tenantId,
88
+ scope: recallScopeFilter(opts.scope, 'exact'),
89
+ includeSuperseded: false,
90
+ admit: (e) => passesScopeFilterForRecall(e.scope ?? null, opts.scope),
91
+ };
92
+ }
93
+ // Tag, pin and recency boosts can lift a row from deep in the BM25 order, so MCP ranks a wide lexical window.
94
+ const SHOW_RANKED_LEXICAL_WINDOW = 1000;
95
+ /** `retrieve` under `showRanked`: physics when `mode` says so, hybrid otherwise, over a wide lexical window plus the nearest vectors. */
96
+ async function retrieveFromStore(ctx, opts, windowSize, show) {
97
+ const loaded = loadRecallSearchEntries(ctx.hippoRoot, opts.query, Math.max(windowSize, SHOW_RANKED_LEXICAL_WINDOW), ctx.tenantId, opts.scope, 'exact', false);
98
+ const pool = loaded.filter((e) => passesScopeFilterForRecall(e.scope ?? null, opts.scope));
99
+ // No scope option: the scope boost follows HIPPO_SCOPE and the skill env, as MCP recall always ranked.
100
+ const searchOpts = { budget: Infinity, hippoRoot: ctx.hippoRoot, vectorCandidates: recallVectorSpec(ctx, opts) };
101
+ let ranked = opts.mode === 'physics'
102
+ ? await physicsSearch(opts.query, pool, { ...searchOpts, physicsConfig: loadConfig(ctx.hippoRoot).physics })
103
+ : await hybridSearch(opts.query, pool, searchOpts);
104
+ if (opts.sessionId && !opts.goalTag) {
105
+ const db = openHippoDb(ctx.hippoRoot);
106
+ try {
107
+ ranked = applyGoalStackBoost(db, ranked, { sessionId: opts.sessionId, tenantId: ctx.tenantId, limit: ranked.length });
108
+ }
109
+ finally {
110
+ closeHippoDb(db);
111
+ }
112
+ }
113
+ const window = ranked.slice(0, windowSize).map((r) => r.entry);
114
+ const result = recallFrom(ctx, { ...opts, suppressRecallTrace: true }, windowSize, window);
115
+ // Rows the vector arm added count as candidates too.
116
+ const inPool = new Set(pool.map((e) => e.id));
117
+ const candidates = [...pool, ...ranked.map((r) => r.entry).filter((e) => !inPool.has(e.id))];
118
+ const shown = show({ ranked, pool: candidates, droppedByScope: loaded.length - pool.length }, result);
119
+ strengthenRetrieved(ctx.hippoRoot, shown, { tenantId: ctx.tenantId, recallBoostAblated: isRecallBoostAblated() });
120
+ if (!opts.suppressRecallTrace) {
121
+ const scores = new Map(ranked.map((r) => [r.entry.id, r.score]));
122
+ writeRecallTraceAtRoot(ctx.hippoRoot, {
123
+ tenantId: ctx.tenantId,
124
+ sessionId: opts.sessionId ?? null,
125
+ pipeline: 'mcp',
126
+ query: opts.query,
127
+ results: shown.map((id) => ({ memoryId: id, score: scores.get(id) ?? 0 })),
128
+ });
129
+ }
130
+ return result;
131
+ }
132
+ /** Contract preflight: throws before any store-touching work. */
133
+ function recallWindowSize(opts) {
134
+ // F5 (v1.6.5) preflight — codex P1: original guard fired AFTER
135
+ // loadSearchEntries (which runs initStore, migrating legacy state on first
136
+ // call). For a true contract preflight we want the throw before any
137
+ // store-touching work. Single check here; the consumer site at
138
+ // `if (freshTailCount > 0)` does NOT re-validate (would be a no-op).
139
+ const freshTailCountPreflight = opts.freshTailCount ?? 0;
140
+ if (freshTailCountPreflight > 0 &&
141
+ !opts.freshTailSessionId &&
142
+ envRequireSessionScopedFreshTail()) {
143
+ throw new RecallContractError('fresh_tail_requires_session_id', 'fresh-tail requires a session id when HIPPO_REQUIRE_SESSION_SCOPED_FRESH_TAIL=1; ' +
144
+ 'pass opts.freshTailSessionId or unset the env to allow tenant-wide fresh-tail.');
145
+ }
146
+ // F3 (v1.7.0): scorerWindow opt-in. When undefined (default),
147
+ // loadSearchEntries uses its own store-internal default — this
148
+ // preserves every pre-v1.7.0 caller's behaviour bit-for-bit (codex
149
+ // mk2-pass P0-1: defaulting to `limit` would have shrunk the
150
+ // candidate pool and killed overflow summaries).
151
+ // DEFAULT_SEARCH_CANDIDATE_LIMIT is imported from store.ts so the two
152
+ // values cannot drift (codex diff-pass P1 #3).
153
+ // Validate the input — codex diff-pass P1 #1 caught that scorerWindow=0
154
+ // would route through FTS/LIKE LIMIT 0 and then fall through to an
155
+ // uncapped full-store fallback. Reject non-positive / non-finite values.
156
+ if (opts.scorerWindow !== undefined) {
157
+ if (!Number.isFinite(opts.scorerWindow) ||
158
+ !Number.isInteger(opts.scorerWindow) ||
159
+ opts.scorerWindow < 1) {
160
+ throw new RecallContractError('invalid_scorer_window', `scorerWindow must be a positive integer; got ${opts.scorerWindow}`);
161
+ }
162
+ }
163
+ return opts.scorerWindow ?? DEFAULT_SEARCH_CANDIDATE_LIMIT;
164
+ }
165
+ function recallFrom(ctx, opts, windowSize, all) {
166
+ const limit = opts.limit ?? 10;
167
+ const window = admitCandidates(opts, all, limit);
168
+ // One db handle spans the goal-stack boost and the audit and trace rows; it closes before the continuity block.
169
+ const db = openHippoDb(ctx.hippoRoot);
170
+ let bands;
171
+ try {
172
+ bands = rankBands(db, ctx, opts, window, limit);
173
+ auditAndTraceRecall(db, ctx, opts, bands.rankedOut);
174
+ }
175
+ finally {
176
+ closeHippoDb(db);
177
+ }
178
+ const rankedOut = bands.rankedOut;
179
+ const { continuity, continuityTokens } = opts.includeContinuity
180
+ ? loadContinuity(ctx, opts)
181
+ : { continuity: undefined, continuityTokens: undefined };
182
+ // Query-derived, so MCP and CLI read this one hint instead of recomputing; HIPPO_AUTODEBIAS=off disables it.
183
+ // The hint and the no-class-match / tiebreak watching variant are mutually exclusive; both go out as optional fields.
184
+ const planningFallacyOutput = computePlanningFallacyOutput(ctx.hippoRoot, ctx.tenantId, opts.query, { actor: ctx.actor.subject });
185
+ const planningFallacyHint = planningFallacyOutput.hint ?? null;
186
+ const planningFallacyWatching = planningFallacyOutput.watching ?? null;
187
+ const { anchoringHint, suppressedByInterference } = detectRecallAnchoring(ctx, opts, rankedOut[0]?.id ?? null);
188
+ const availabilityHint = detectRecallAvailability(ctx, opts, bands.baseSlice, window.entries);
189
+ const result = {
190
+ results: rankedOut,
191
+ total: window.entries.length,
192
+ tokens: rankedOut.reduce((acc, r) => acc + estimateTokens(r.content), 0),
193
+ continuity,
194
+ continuityTokens,
195
+ windowSize,
196
+ suppressionSummary: buildSuppressionSummary({
197
+ totalCandidates: all.length,
198
+ droppedPreRank: window.droppedPreRank + bands.heldDropped,
199
+ droppedByBudget: window.droppedByBudget,
200
+ summarySubstitutionsAdded: bands.summarySubstitutions,
201
+ freshTailAdded: bands.freshTailAdded,
202
+ suppressedByInterference,
203
+ }),
204
+ };
205
+ if (planningFallacyHint)
206
+ result.planningFallacyHint = planningFallacyHint;
207
+ if (planningFallacyWatching)
208
+ result.planningFallacyWatching = planningFallacyWatching;
209
+ if (anchoringHint)
210
+ result.anchoringHint = anchoringHint;
211
+ if (availabilityHint)
212
+ result.availabilityHint = availabilityHint;
213
+ return result;
214
+ }
215
+ // The SQL load already applied tenant and scope; any recall-mode loader must go through loadRecallSearchEntries.
216
+ function admitCandidates(opts, all, limit) {
217
+ const current = all.filter((e) => !e.superseded_by);
218
+ let entries;
219
+ if (opts.scope !== undefined && opts.scope !== '') {
220
+ // SQL already exact-matched; the JS filter is defense-in-depth against a SQL-clause regression.
221
+ entries = current.filter((e) => e.scope === opts.scope);
222
+ }
223
+ else {
224
+ // SQL pre-filtered ':private:' loosely before the window; this is the exact anchored `<source>:private:*` rule.
225
+ entries = current.filter((e) => !isRestrictedScope(e.scope ?? null));
226
+ }
227
+ const droppedPreRank = all.length - entries.length;
228
+ entries = entries
229
+ .map((e, i) => ({ e, s: (1 - i / entries.length) * churnStaleFactor(e) }))
230
+ .sort((a, b) => b.s - a.s)
231
+ .map((r) => r.e);
232
+ // BM25 ordering already comes from loadRecallSearchEntries; cap to `limit`.
233
+ const baseSlice = entries.slice(0, limit);
234
+ return { entries, baseSlice, droppedPreRank, droppedByBudget: entries.length - baseSlice.length };
235
+ }
236
+ // The goal-stack boost touches the primary band only; the fresh-tail and summary bands keep their fixed placement.
237
+ function rankBands(db, ctx, opts, window, limit) {
238
+ let baseScored = window.baseSlice.map((entry, idx) => ({
239
+ entry,
240
+ score: Math.max(0, 1 - idx / Math.max(1, limit)),
241
+ }));
242
+ // Allocated only under explain, so the boost's default-path math stays byte-identical.
243
+ const explainTrace = opts.explain ? new Map() : undefined;
244
+ if (opts.sessionId && !opts.goalTag) {
245
+ baseScored = applyGoalStackBoost(db, baseScored, {
246
+ sessionId: opts.sessionId,
247
+ tenantId: ctx.tenantId,
248
+ limit,
249
+ trace: explainTrace,
250
+ });
251
+ }
252
+ let substituted = (opts.summarizeOverflow ?? true) && window.entries.length > limit
253
+ ? substituteOverflow(ctx, opts, window.entries, baseScored.map((r) => r.entry), limit)
254
+ : [];
255
+ let heldDropped = 0;
256
+ if (!opts.keepHeldCopies) {
257
+ const shownIds = new Set(dropHeldCopies([...baseScored.map((r) => r.entry), ...substituted.map((s) => s.entry)], (e) => e).map((e) => e.id));
258
+ heldDropped = baseScored.filter((r) => !shownIds.has(r.entry.id)).length;
259
+ baseScored = baseScored.filter((r) => shownIds.has(r.entry.id));
260
+ substituted = substituted.filter((s) => shownIds.has(s.entry.id));
261
+ }
262
+ const baseSlice = baseScored.map((r) => r.entry);
263
+ const baseRanked = baseScored.map((r) => baseItem(r, opts, explainTrace));
264
+ const summaryRanked = substituted.map((s) => summaryItem(s, opts));
265
+ const freshRanked = (opts.freshTailCount ?? 0) > 0
266
+ ? freshTailBand(ctx, opts, baseRanked, summaryRanked, opts.keepHeldCopies ? [] : [...baseSlice, ...substituted.map((s) => s.entry)])
267
+ : [];
268
+ return {
269
+ rankedOut: [...freshRanked, ...baseRanked, ...summaryRanked],
270
+ baseSlice,
271
+ heldDropped,
272
+ summarySubstitutions: substituted.length,
273
+ freshTailAdded: freshRanked.length,
274
+ };
275
+ }
276
+ // When the overflow holds 2+ children of one level-2 summary, that summary stands in for them, capped at 30% of
277
+ // `limit`. Each one is tenant-scoped and re-checked against the scope filter; drillDown recovers the children.
278
+ function substituteOverflow(ctx, opts, entries, baseSlice, limit) {
279
+ const overflow = entries.slice(limit);
280
+ const baseIds = new Set(baseSlice.map((e) => e.id));
281
+ const overflowByParent = new Map();
282
+ for (const e of overflow) {
283
+ const parentId = e.dag_parent_id;
284
+ if (!parentId)
285
+ continue;
286
+ if ((e.dag_level ?? 0) > 1)
287
+ continue;
288
+ const list = overflowByParent.get(parentId) ?? [];
289
+ list.push(e);
290
+ overflowByParent.set(parentId, list);
291
+ }
292
+ const eligibleParentIds = Array.from(overflowByParent.keys()).filter((pid) => (overflowByParent.get(pid)?.length ?? 0) >= 2 && !baseIds.has(pid));
293
+ if (eligibleParentIds.length === 0)
294
+ return [];
295
+ const parents = loadEntriesByIds(ctx.hippoRoot, eligibleParentIds, ctx.tenantId);
296
+ const eligibleParents = parents.filter((p) => (p.dag_level ?? 0) === 2 && !p.superseded_by && passesScopeFilterForRecall(p.scope ?? null, opts.scope));
297
+ const maxSub = Math.max(1, Math.ceil(limit * 0.3));
298
+ // Most overflowed children first; compareEntryIdentity only breaks a tie, which used to fall to scan order.
299
+ eligibleParents.sort((a, b) => {
300
+ const ac = overflowByParent.get(a.id)?.length ?? 0;
301
+ const bc = overflowByParent.get(b.id)?.length ?? 0;
302
+ return bc !== ac ? bc - ac : compareEntryIdentity(a, b);
303
+ });
304
+ return eligibleParents.slice(0, maxSub).map((p) => ({
305
+ entry: p,
306
+ childIds: (overflowByParent.get(p.id) ?? []).map((e) => e.id),
307
+ }));
308
+ }
309
+ function baseItem(r, opts, explainTrace) {
310
+ const item = {
311
+ id: r.entry.id,
312
+ content: r.entry.content,
313
+ score: r.score,
314
+ layer: r.entry.layer,
315
+ strength: r.entry.strength,
316
+ };
317
+ // Only this band passes through the goal boost, so only it can carry a rerank step.
318
+ if (opts.explain) {
319
+ item.rerankPipeline = 'api';
320
+ const step = explainTrace?.get(r.entry.id);
321
+ if (step)
322
+ item.rerankTrace = [step];
323
+ }
324
+ return item;
325
+ }
326
+ // Score 0.5 keeps a summary below the strong top-N matches but above the weakest leaves.
327
+ function summaryItem(s, opts) {
328
+ const item = {
329
+ id: s.entry.id,
330
+ content: s.entry.content,
331
+ score: 0.5,
332
+ layer: s.entry.layer,
333
+ strength: s.entry.strength,
334
+ isSummary: true,
335
+ substitutedFor: s.childIds,
336
+ descendantCount: s.entry.descendant_count ?? s.childIds.length,
337
+ };
338
+ if (opts.explain)
339
+ item.rerankPipeline = 'api';
340
+ return item;
341
+ }
342
+ // The last N raw rows, so "what did I just see" always covers the recent window. A recent row already in the BM25
343
+ // band is only tagged isFreshTail; new ones are prepended, so every recent row appears exactly once.
344
+ function freshTailBand(ctx, opts, baseRanked, summaryRanked, shownEntries) {
345
+ // The session-id contract was already checked by recallWindowSize's preflight.
346
+ const recent = loadFreshRawMemories(ctx.hippoRoot, opts.freshTailCount ?? 0, ctx.tenantId, opts.freshTailSessionId);
347
+ const recentScoped = recent.filter((m) => passesScopeFilterForRecall(m.scope ?? null, opts.scope));
348
+ const recentIdSet = new Set(recentScoped.map((m) => m.id));
349
+ for (const r of baseRanked) {
350
+ if (recentIdSet.has(r.id))
351
+ r.isFreshTail = true;
352
+ }
353
+ const seenIds = new Set([...baseRanked.map((r) => r.id), ...summaryRanked.map((r) => r.id)]);
354
+ const shownKeys = storedTextKeys(shownEntries);
355
+ const freshRanked = [];
356
+ for (const m of recentScoped) {
357
+ if (seenIds.has(m.id) || shownKeys.has(duplicateKey(m.content)))
358
+ continue;
359
+ shownKeys.add(duplicateKey(m.content));
360
+ const item = {
361
+ id: m.id,
362
+ content: m.content,
363
+ score: 1.0,
364
+ layer: m.layer,
365
+ strength: m.strength,
366
+ isFreshTail: true,
367
+ };
368
+ if (opts.explain)
369
+ item.rerankPipeline = 'api';
370
+ freshRanked.push(item);
371
+ seenIds.add(m.id);
372
+ }
373
+ return freshRanked;
374
+ }
375
+ // The audit row stores a hash of the query, never its text, so an archived memory's words cannot persist there.
376
+ // The trace sits beside it as observability, not retrieval state; a caller that traces its own result set suppresses it.
377
+ function auditAndTraceRecall(db, ctx, opts, rankedOut) {
378
+ appendAuditEvent(db, {
379
+ tenantId: ctx.tenantId,
380
+ actor: ctx.actor.subject,
381
+ op: 'recall',
382
+ metadata: {
383
+ ...auditQueryFields(opts.query),
384
+ results: rankedOut.length,
385
+ },
386
+ });
387
+ if (!opts.suppressRecallTrace) {
388
+ writeRecallTrace(db, {
389
+ tenantId: ctx.tenantId,
390
+ sessionId: opts.sessionId ?? null,
391
+ pipeline: 'api',
392
+ query: opts.query,
393
+ explainMode: opts.explain === true,
394
+ results: rankedOut.map((r) => ({
395
+ memoryId: r.id,
396
+ score: r.score,
397
+ rerankSteps: r.rerankTrace,
398
+ })),
399
+ });
400
+ }
401
+ }
402
+ // No active snapshot means no anchor, so no handoff or events: a stale handoff from a closed session never resurfaces.
403
+ function loadContinuity(ctx, opts) {
404
+ const snapshot = loadActiveTaskSnapshot(ctx.hippoRoot, ctx.tenantId);
405
+ const sessionId = snapshot?.session_id ?? undefined;
406
+ const sessionHandoff = sessionId
407
+ ? loadLatestHandoff(ctx.hippoRoot, ctx.tenantId, sessionId)
408
+ : null;
409
+ const recentSessionEvents = sessionId
410
+ ? listSessionEvents(ctx.hippoRoot, ctx.tenantId, { session_id: sessionId, limit: 5 })
411
+ : [];
412
+ // The memory-recall scope rule: an explicit scope must match exactly; without one, private and legacy rows are denied.
413
+ const rowScope = (r) => r?.scope ?? null;
414
+ const filteredSnapshot = snapshot && passesScopeFilterForRecall(rowScope(snapshot), opts.scope) ? snapshot : null;
415
+ const filteredHandoff = sessionHandoff && passesScopeFilterForRecall(rowScope(sessionHandoff), opts.scope) ? sessionHandoff : null;
416
+ const filteredEvents = recentSessionEvents.filter((e) => passesScopeFilterForRecall(rowScope(e), opts.scope));
417
+ const continuity = {
418
+ activeSnapshot: filteredSnapshot,
419
+ sessionHandoff: filteredHandoff,
420
+ recentSessionEvents: filteredEvents,
421
+ };
422
+ return { continuity, continuityTokens: continuityTokensOf(continuity) };
423
+ }
424
+ function continuityTokensOf(c) {
425
+ const filteredSnapshot = c.activeSnapshot;
426
+ const filteredHandoff = c.sessionHandoff;
427
+ const tokenize = (s) => s ? estimateTokens(s) : 0;
428
+ return tokenize(filteredSnapshot?.task) +
429
+ tokenize(filteredSnapshot?.summary) +
430
+ tokenize(filteredSnapshot?.next_step) +
431
+ tokenize(filteredHandoff?.summary) +
432
+ tokenize(filteredHandoff?.nextAction) +
433
+ (filteredHandoff?.artifacts ?? []).reduce((acc, a) => acc + tokenize(a), 0) +
434
+ (filteredHandoff?.constraints ?? []).reduce((acc, c) => acc + tokenize(c), 0) +
435
+ tokenize(filteredHandoff?.evidence ? formatHandoffEvidenceLine(filteredHandoff.evidence) : null) +
436
+ tokenize(filteredHandoff?.outcome) +
437
+ tokenize(filteredHandoff?.targetRuntime) +
438
+ tokenize(filteredHandoff?.cardId) +
439
+ c.recentSessionEvents.reduce((acc, e) => acc + tokenize(e.content), 0);
440
+ }
441
+ /** One audit row on its own short-lived handle, as each bias detector writes it. */
442
+ function appendRecallAudit(ctx, event) {
443
+ const db = openHippoDb(ctx.hippoRoot);
444
+ try {
445
+ appendAuditEvent(db, { tenantId: ctx.tenantId, actor: ctx.actor.subject, ...event });
446
+ }
447
+ finally {
448
+ closeHippoDb(db);
449
+ }
450
+ }
451
+ // A pure read of the caller's recallHistory snapshot against this top-1. HIPPO_ANCHORING=off skips even the detect
452
+ // call; CLI paths pass no history (cmdRecall computes its own hint), so the hint stays absent there.
453
+ function detectRecallAnchoring(ctx, opts, topMemoryId) {
454
+ if (!biasHintEnabled('anchoring') || !opts.recallHistory)
455
+ return { anchoringHint: null, suppressedByInterference: 0 };
456
+ const queryHash = hashQueryText(opts.query);
457
+ const anchoringHint = detectAnchoring(opts.recallHistory, queryHash, topMemoryId);
458
+ if (anchoringHint?.reason === 'memory_dominance') {
459
+ appendRecallAudit(ctx, {
460
+ op: 'recall_anchor_detected_memory_dominance',
461
+ targetId: anchoringHint.memoryId,
462
+ metadata: {
463
+ memory_id: anchoringHint.memoryId,
464
+ query_count: anchoringHint.queryCount ?? null,
465
+ },
466
+ });
467
+ return { anchoringHint, suppressedByInterference: 1 };
468
+ }
469
+ if (anchoringHint?.reason === 'query_repeat') {
470
+ appendRecallAudit(ctx, {
471
+ op: 'recall_anchor_detected_query_repeat',
472
+ targetId: anchoringHint.memoryId,
473
+ metadata: { memory_id: anchoringHint.memoryId },
474
+ });
475
+ }
476
+ return { anchoringHint, suppressedByInterference: 0 };
477
+ }
478
+ // Compares the returned top-K's ages with the scope-filtered pool it came from, never `all`, whose hidden rows would
479
+ // leak pool shape. A soft warning only; HIPPO_AVAILABILITY=off or a caller computing its own hint skips it.
480
+ function detectRecallAvailability(ctx, opts, baseSlice, entries) {
481
+ if (!biasHintEnabled('availability') || opts.suppressAvailabilityHint)
482
+ return null;
483
+ const availabilityHint = detectAvailabilityBias({
484
+ topK: baseSlice.map((e) => ({ id: e.id, created: e.created })),
485
+ pool: entries.map((e) => ({ id: e.id, created: e.created })),
486
+ });
487
+ if (availabilityHint) {
488
+ appendRecallAudit(ctx, {
489
+ op: 'recall_availability_detected',
490
+ metadata: {
491
+ recent_fraction: availabilityHint.recentFraction,
492
+ older_passed_over: availabilityHint.olderCandidatesPassedOver,
493
+ returned_count: availabilityHint.returnedCount,
494
+ },
495
+ });
496
+ }
497
+ return availabilityHint;
498
+ }
499
+ //# sourceMappingURL=recall.js.map
@@ -0,0 +1,35 @@
1
+ import type { DatabaseSyncLike } from '../db.js';
2
+ import { type MemoryKind } from '../memory.js';
3
+ import type { Context } from './types.js';
4
+ export interface RememberOpts {
5
+ content: string;
6
+ kind?: MemoryKind;
7
+ scope?: string;
8
+ owner?: string;
9
+ artifactRef?: string;
10
+ tags?: string[];
11
+ /**
12
+ * Optional hook invoked inside the same transaction as the underlying
13
+ * memories INSERT. Used by ingestion connectors (E1.3+) to stamp
14
+ * idempotency / cursor rows atomically with the memory row, so a crash
15
+ * mid-write cannot produce a memory without its corresponding side-effect
16
+ * log row (or vice versa). If the callback throws, the INSERT is rolled
17
+ * back and the error is rethrown.
18
+ */
19
+ afterWrite?: (db: DatabaseSyncLike, memoryId: string) => void;
20
+ /** CD5: connector-ingested content an agent doesn't control; gates detectInstruction. CLI/HTTP/MCP never set this. */
21
+ untrusted?: boolean;
22
+ }
23
+ export interface RememberResult {
24
+ id: string;
25
+ kind: MemoryKind;
26
+ tenantId: string;
27
+ /** Set only when untrusted content was flagged and quarantined instead of stored under its requested scope. */
28
+ quarantined?: {
29
+ reason: string;
30
+ };
31
+ /** Set only when the content held secret material: untrusted text had it redacted, typed text was stored as sent. */
32
+ warnings?: string[];
33
+ }
34
+ export declare function remember(ctx: Context, opts: RememberOpts): RememberResult;
35
+ //# sourceMappingURL=remember.d.ts.map
@@ -0,0 +1,43 @@
1
+ // Write path: remember stores one memory after secret vetting and, for untrusted content, the instruction check.
2
+ import { writeEntry } from '../store/entry-writes.js';
3
+ import { detectInstruction } from '../instruction-detect.js';
4
+ import { quarantineScopeFor, recordQuarantine } from '../quarantine.js';
5
+ import { createMemory } from '../memory.js';
6
+ import { loadConfig } from '../config.js';
7
+ import { vetSecrets } from '../secret-detect.js';
8
+ export function remember(ctx, opts) {
9
+ const vetted = vetSecrets(opts.content, opts.tags ?? [], opts.untrusted === true);
10
+ const detection = opts.untrusted ? detectInstruction(vetted.content) : { flagged: false, reason: null };
11
+ const requestedScope = opts.scope ?? null;
12
+ const entry = createMemory(vetted.content, {
13
+ kind: opts.kind ?? 'distilled',
14
+ scope: detection.flagged ? quarantineScopeFor(requestedScope) : requestedScope,
15
+ owner: opts.owner ?? null,
16
+ artifact_ref: opts.artifactRef ?? null,
17
+ tags: opts.tags,
18
+ tenantId: ctx.tenantId,
19
+ baseHalfLifeDays: loadConfig(ctx.hippoRoot).defaultHalfLifeDays,
20
+ });
21
+ // writeEntry threads ctx.actor.subject into its internal audit hook, so exactly
22
+ // one 'remember' event lands in the log with the supplied actor.
23
+ const afterWrite = detection.flagged
24
+ ? (db, memoryId) => {
25
+ recordQuarantine(db, {
26
+ tenantId: ctx.tenantId,
27
+ memoryId,
28
+ originalScope: requestedScope,
29
+ reason: detection.reason ?? 'unknown',
30
+ actor: ctx.actor.subject,
31
+ });
32
+ opts.afterWrite?.(db, memoryId);
33
+ }
34
+ : opts.afterWrite;
35
+ writeEntry(ctx.hippoRoot, entry, { actor: ctx.actor.subject, afterWrite });
36
+ const result = { id: entry.id, kind: entry.kind, tenantId: ctx.tenantId };
37
+ if (detection.flagged)
38
+ result.quarantined = { reason: detection.reason ?? 'unknown' };
39
+ if (vetted.warnings.length > 0)
40
+ result.warnings = vetted.warnings;
41
+ return result;
42
+ }
43
+ //# sourceMappingURL=remember.js.map