recallnest 2.2.0 → 2.3.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 (249) hide show
  1. package/.env +4 -0
  2. package/CLAUDE.md +1 -1
  3. package/README.md +30 -5
  4. package/README_CN.md +30 -5
  5. package/config.json +55 -0
  6. package/connectors/examples/email-adapter.ts +73 -0
  7. package/connectors/examples/logs-adapter.ts +103 -0
  8. package/connectors/examples/rss-adapter.ts +95 -0
  9. package/logs/daily-recall.error.log +0 -0
  10. package/logs/daily-recall.log +60 -0
  11. package/logs/ingest-2026-04-11.log +110 -0
  12. package/logs/ingest-2026-04-12.log +90 -0
  13. package/logs/ingest-2026-04-13.log +87 -0
  14. package/logs/launchagent-stderr.log +0 -0
  15. package/logs/launchagent-stdout.log +0 -0
  16. package/package.json +1 -1
  17. package/src/cli.ts +30 -0
  18. package/src/connector-types.ts +57 -0
  19. package/src/conversation-importer.ts +25 -1
  20. package/src/data-checkup.ts +31 -1
  21. package/src/doctor.ts +29 -0
  22. package/src/ingest.ts +203 -0
  23. package/src/mcp-server.ts +2 -2
  24. package/src/obsidian-connector.ts +282 -0
  25. package/src/session-schema.ts +2 -2
  26. package/src/source-heartbeat.ts +108 -0
  27. package/.claude-plugin/CLAUDE.md +0 -29
  28. package/.claude-plugin/marketplace.json +0 -18
  29. package/.dockerignore +0 -11
  30. package/.github/workflows/ci.yml +0 -28
  31. package/.mcp.json +0 -9
  32. package/CHANGELOG.md +0 -51
  33. package/DEMO.md +0 -94
  34. package/Dockerfile +0 -20
  35. package/EVAL.md +0 -89
  36. package/FAILURES.md +0 -75
  37. package/OPERATIONS.md +0 -59
  38. package/ROADMAP.md +0 -245
  39. package/SKILL.md +0 -250
  40. package/assets/dashboard.png +0 -0
  41. package/assets/knowledge-graph.png +0 -0
  42. package/assets/recallnest-workbench.png +0 -0
  43. package/assets/screenshots/ui-full.png +0 -0
  44. package/assets/screenshots/ui-overview.png +0 -0
  45. package/assets/screenshots/ui-search.png +0 -0
  46. package/assets/ui/app.js +0 -1031
  47. package/assets/ui/index.html +0 -224
  48. package/assets/ui/styles.css +0 -781
  49. package/assets/wechat-qr.jpg +0 -0
  50. package/bun.lock +0 -337
  51. package/daily-reflections/2026-03-05.md +0 -15
  52. package/daily-reflections/2026-03-06.md +0 -15
  53. package/daily-reflections/2026-03-07.md +0 -7
  54. package/daily-reflections/2026-03-08.md +0 -34
  55. package/daily-reflections/2026-03-09.md +0 -35
  56. package/daily-reflections/2026-03-10.md +0 -36
  57. package/daily-reflections/2026-03-11.md +0 -35
  58. package/daily-reflections/2026-03-12.md +0 -36
  59. package/daily-reflections/2026-03-13.md +0 -35
  60. package/daily-reflections/2026-03-14.md +0 -35
  61. package/daily-reflections/2026-03-15.md +0 -35
  62. package/daily-reflections/2026-03-16.md +0 -41
  63. package/daily-reflections/2026-03-17.md +0 -10
  64. package/daily-reflections/2026-03-18.md +0 -10
  65. package/daily-reflections/2026-03-19.md +0 -10
  66. package/daily-reflections/2026-03-20.md +0 -10
  67. package/daily-reflections/2026-03-21.md +0 -10
  68. package/daily-reflections/2026-03-22.md +0 -10
  69. package/daily-reflections/2026-03-23.md +0 -10
  70. package/daily-reflections/2026-03-24.md +0 -10
  71. package/daily-reflections/2026-03-25.md +0 -32
  72. package/daily-reflections/2026-03-26.md +0 -37
  73. package/daily-reflections/2026-03-27.md +0 -35
  74. package/daily-reflections/2026-03-28.md +0 -35
  75. package/daily-reflections/2026-03-29.md +0 -35
  76. package/daily-reflections/2026-03-30.md +0 -36
  77. package/daily-reflections/2026-03-31.md +0 -35
  78. package/daily-reflections/2026-04-01.md +0 -35
  79. package/daily-reflections/2026-04-02.md +0 -35
  80. package/daily-reflections/2026-04-03.md +0 -37
  81. package/daily-reflections/2026-04-04.md +0 -37
  82. package/daily-reflections/2026-04-05.md +0 -35
  83. package/daily-reflections/2026-04-06.md +0 -36
  84. package/daily-reflections/2026-04-07.md +0 -35
  85. package/daily-reflections/2026-04-08.md +0 -35
  86. package/daily-reflections/2026-04-12.md +0 -35
  87. package/data/alias-map.example.json +0 -22
  88. package/docs/api-reference.md +0 -1291
  89. package/docs/architecture.md +0 -168
  90. package/docs/memory-boundary-contract.md +0 -226
  91. package/docs/memory-categories.md +0 -119
  92. package/docs/pipeline-audit-ultramemory.md +0 -177
  93. package/docs/plans/2026-03-08-query-expansion.md +0 -270
  94. package/docs/plans/2026-03-16-continuity-layer.md +0 -196
  95. package/docs/plans/2026-04-01-recall-boost.md +0 -100
  96. package/docs/plans/mcp-tiering-plan.md +0 -126
  97. package/docs/research/recall-quality-audit-2026-03-22.md +0 -153
  98. package/docs/self-evolution.md +0 -198
  99. package/docs/superpowers/plans/2026-03-19-ingest-pipeline-upgrade.md +0 -782
  100. package/docs/superpowers/plans/2026-04-11-constructive-retrieval-emotion.md +0 -1195
  101. package/docs/superpowers/specs/2026-03-19-ingest-pipeline-upgrade-design.md +0 -77
  102. package/docs/superpowers/specs/2026-03-23-pull-claude-desktop-design.md +0 -95
  103. package/docs/superpowers/specs/2026-04-11-constructive-retrieval-emotion-design.md +0 -398
  104. package/eval/continuity/results-2026-03-16.md +0 -117
  105. package/eval/continuity/results-2026-03-19.md +0 -453
  106. package/eval/continuity/runbook.md +0 -110
  107. package/eval/continuity/seed-cases.md +0 -54
  108. package/eval/reports/2026-03-06-abstract-query-baseline.md +0 -96
  109. package/eval/reports/2026-03-06-aws-ssh-baseline.md +0 -82
  110. package/eval/reports/2026-03-06-baseline.md +0 -82
  111. package/eval/reports/query-expansion.md +0 -138
  112. package/glama.json +0 -6
  113. package/lm +0 -19
  114. package/plan-philosophy-upgrades.md +0 -363
  115. package/plan-product-upgrades.md +0 -155
  116. package/plan-v1.2-distributable.md +0 -105
  117. package/plan.md +0 -140
  118. package/research-memory-evolution.md +0 -440
  119. package/research-rl-agent-memory.md +0 -330
  120. package/scripts/archive-distilled-junk.ts +0 -116
  121. package/scripts/backfill-anchors.ts +0 -130
  122. package/scripts/backfill-l0l1l2.ts +0 -98
  123. package/scripts/blind-scan.ts +0 -588
  124. package/scripts/cleanup-step1-exact-dups.ts +0 -117
  125. package/scripts/cleanup-step2-template-dups.ts +0 -113
  126. package/scripts/cleanup-step3-stale-content.ts +0 -149
  127. package/scripts/cleanup-step4-orphan-scopes.ts +0 -131
  128. package/scripts/delete-distilled-junk.ts +0 -88
  129. package/scripts/diagnose-vector-search.ts +0 -132
  130. package/scripts/distill-facts.ts +0 -305
  131. package/scripts/health-check.ts +0 -343
  132. package/scripts/incremental-ingest.sh +0 -71
  133. package/scripts/migrate-language.ts +0 -75
  134. package/scripts/mlp-health-check.ts +0 -382
  135. package/scripts/pull-claude-desktop.ts +0 -515
  136. package/scripts/re-ingest-cc.sh +0 -66
  137. package/scripts/rebalance-memory-health.ts +0 -181
  138. package/scripts/run-desktop-ingest.sh +0 -11
  139. package/scripts/start-server.sh +0 -12
  140. package/scripts/verify-emotion-decay.ts +0 -148
  141. package/scripts/viz-dashboard.html +0 -423
  142. package/scripts/viz-export.ts +0 -703
  143. package/src/__tests__/access-tracker-novelty.test.ts +0 -228
  144. package/src/__tests__/activity-counter.test.ts +0 -96
  145. package/src/__tests__/admission-control.test.ts +0 -206
  146. package/src/__tests__/anchor-generator.test.ts +0 -67
  147. package/src/__tests__/auto-consolidation.test.ts +0 -168
  148. package/src/__tests__/auto-recall.test.ts +0 -131
  149. package/src/__tests__/babel-integration.test.ts +0 -139
  150. package/src/__tests__/batch-dedup.test.ts +0 -65
  151. package/src/__tests__/capture-engine.test.ts +0 -1144
  152. package/src/__tests__/capture-heuristic.test.ts +0 -171
  153. package/src/__tests__/cascade-forget.test.ts +0 -210
  154. package/src/__tests__/category-min-scores.test.ts +0 -33
  155. package/src/__tests__/cc8-cc1-essential-context.test.ts +0 -298
  156. package/src/__tests__/circuit-breaker.test.ts +0 -99
  157. package/src/__tests__/cluster-consolidation.test.ts +0 -712
  158. package/src/__tests__/confidence-metadata.test.ts +0 -125
  159. package/src/__tests__/confidence-tracker.test.ts +0 -249
  160. package/src/__tests__/conflict-advisor.test.ts +0 -206
  161. package/src/__tests__/conflict-escalation.test.ts +0 -149
  162. package/src/__tests__/conflict-lifecycle.test.ts +0 -83
  163. package/src/__tests__/conflict-output.test.ts +0 -85
  164. package/src/__tests__/conflict-store.test.ts +0 -374
  165. package/src/__tests__/consolidation-engine.test.ts +0 -181
  166. package/src/__tests__/constructive-retrieval.test.ts +0 -509
  167. package/src/__tests__/context-collapse-renderer.test.ts +0 -214
  168. package/src/__tests__/context-composer-pins.test.ts +0 -64
  169. package/src/__tests__/context-composer-task-selection.test.ts +0 -24
  170. package/src/__tests__/context-reconstructor.test.ts +0 -65
  171. package/src/__tests__/context-renderer.test.ts +0 -91
  172. package/src/__tests__/continuity-eval.test.ts +0 -275
  173. package/src/__tests__/continuity-schema.test.ts +0 -97
  174. package/src/__tests__/conversation-importer.test.ts +0 -692
  175. package/src/__tests__/core-recall-eval.test.ts +0 -235
  176. package/src/__tests__/core-summary.test.ts +0 -109
  177. package/src/__tests__/data-checkup.test.ts +0 -225
  178. package/src/__tests__/decay-exemption.test.ts +0 -84
  179. package/src/__tests__/dedup-actions.test.ts +0 -58
  180. package/src/__tests__/dedup-guard.test.ts +0 -39
  181. package/src/__tests__/deterministic-id.test.ts +0 -39
  182. package/src/__tests__/distill-lock.test.ts +0 -176
  183. package/src/__tests__/doctor.test.ts +0 -303
  184. package/src/__tests__/dream-pipeline.test.ts +0 -232
  185. package/src/__tests__/drill-down.test.ts +0 -108
  186. package/src/__tests__/embedder.test.ts +0 -122
  187. package/src/__tests__/emotion-decay.test.ts +0 -46
  188. package/src/__tests__/emotion-detector.test.ts +0 -56
  189. package/src/__tests__/emotion-phase1-integration.test.ts +0 -153
  190. package/src/__tests__/emotion-retrieval.test.ts +0 -56
  191. package/src/__tests__/entity-resolver.test.ts +0 -58
  192. package/src/__tests__/ethics-layer.test.ts +0 -476
  193. package/src/__tests__/event-segmenter.test.ts +0 -153
  194. package/src/__tests__/feature-flags-integration.test.ts +0 -54
  195. package/src/__tests__/frequency-tracker.test.ts +0 -113
  196. package/src/__tests__/graph-export.test.ts +0 -489
  197. package/src/__tests__/hotness-blend.test.ts +0 -76
  198. package/src/__tests__/ingest.test.ts +0 -360
  199. package/src/__tests__/interference-detector.test.ts +0 -203
  200. package/src/__tests__/kg-extractor.test.ts +0 -184
  201. package/src/__tests__/kg-store.test.ts +0 -198
  202. package/src/__tests__/llm-consolidation.test.ts +0 -226
  203. package/src/__tests__/mcp-efficiency.test.ts +0 -288
  204. package/src/__tests__/memory-boundaries.test.ts +0 -237
  205. package/src/__tests__/memory-evolution-b2-b3-e1.test.ts +0 -243
  206. package/src/__tests__/memory-evolution.test.ts +0 -271
  207. package/src/__tests__/memory-health-rebalance.test.ts +0 -144
  208. package/src/__tests__/memory-lint.test.ts +0 -271
  209. package/src/__tests__/memory-output.test.ts +0 -215
  210. package/src/__tests__/multi-vector.test.ts +0 -242
  211. package/src/__tests__/narrative-architecture.test.ts +0 -456
  212. package/src/__tests__/pending-review.test.ts +0 -77
  213. package/src/__tests__/post-retrieval-filter.test.ts +0 -178
  214. package/src/__tests__/ppr-traversal.test.ts +0 -256
  215. package/src/__tests__/prediction-engine.test.ts +0 -349
  216. package/src/__tests__/predictive-prospective-memory.test.ts +0 -416
  217. package/src/__tests__/preference-guard-smoke.test.ts +0 -211
  218. package/src/__tests__/preference-matcher.test.ts +0 -230
  219. package/src/__tests__/preference-slots.test.ts +0 -205
  220. package/src/__tests__/prospective-memory.test.ts +0 -283
  221. package/src/__tests__/query-entity-detector.test.ts +0 -171
  222. package/src/__tests__/query-expander-alias.test.ts +0 -89
  223. package/src/__tests__/query-expander.test.ts +0 -34
  224. package/src/__tests__/recall-governor.test.ts +0 -227
  225. package/src/__tests__/recall-mode.test.ts +0 -64
  226. package/src/__tests__/result-synthesizer.test.ts +0 -198
  227. package/src/__tests__/resume-context.test.ts +0 -4898
  228. package/src/__tests__/retrieval-trace.test.ts +0 -213
  229. package/src/__tests__/retriever-boundary-weight.test.ts +0 -136
  230. package/src/__tests__/retroactive-boost.test.ts +0 -223
  231. package/src/__tests__/salience-scoring.test.ts +0 -106
  232. package/src/__tests__/scope-inventory.test.ts +0 -200
  233. package/src/__tests__/scope-policy.test.ts +0 -69
  234. package/src/__tests__/session-checkpoint.test.ts +0 -259
  235. package/src/__tests__/session-distiller.test.ts +0 -611
  236. package/src/__tests__/session-gc.test.ts +0 -215
  237. package/src/__tests__/skill-engine.test.ts +0 -546
  238. package/src/__tests__/skill-promotion.test.ts +0 -349
  239. package/src/__tests__/store-scope-audit.test.ts +0 -81
  240. package/src/__tests__/supersede-chain.test.ts +0 -154
  241. package/src/__tests__/temporal-parser.test.ts +0 -241
  242. package/src/__tests__/temporal-validity.test.ts +0 -160
  243. package/src/__tests__/term-registry.test.ts +0 -121
  244. package/src/__tests__/tool-output-compressor.test.ts +0 -133
  245. package/src/__tests__/topic-tag.test.ts +0 -113
  246. package/src/__tests__/trusted-memory.test.ts +0 -828
  247. package/src/__tests__/version-manager.test.ts +0 -213
  248. package/src/__tests__/workflow-observation.test.ts +0 -400
  249. package/src/__tests__/write-verifier.test.ts +0 -122
@@ -1,330 +0,0 @@
1
- # RL + Agent Memory: Research Report from "Memory in the Age of AI Agents"
2
-
3
- **Source**: arXiv 2512.13564 (v2, Jan 2026), 107 pages
4
- **Focus**: Section 7.3 + all cross-references to RL-driven memory systems
5
- **Purpose**: Extract actionable design insights for RecallNest renovation
6
-
7
- ---
8
-
9
- ## 1. The Three-Stage Evolution (Figure 11, Page 71)
10
-
11
- The paper identifies a clear evolutionary trajectory from manually designed to fully learned memory systems.
12
-
13
- ### Stage 1: RL-Free Memory Systems
14
-
15
- These rely on **heuristic or manually specified mechanisms** with no RL training:
16
-
17
- | Mechanism | Examples | How It Works |
18
- |-----------|----------|--------------|
19
- | Heuristic Threshold | MemoryBank | Fixed thresholding rules inspired by forgetting curves |
20
- | Semantic Search | MemOS, Mem0, MemoBase | Rigid semantic search pipelines (embedding similarity) |
21
- | Chunk Concat | Early systems | Simple concatenation-based strategies for storing chunks |
22
- | Prompt-based Generation | ExpeL, EvolveR, G-Memory, Dynamic Cheatsheet, A-Mem, ReasoningBank | LLM generates memory entries but has **no dedicated training** for memory control. Behavior is entirely prompt-driven. |
23
-
24
- **Key insight from the paper**: "The LLM is asked to generate memory entries but has not received any dedicated training for effective memory control." This describes **most current production systems including RecallNest**.
25
-
26
- ### Stage 2: RL Partially Involved (Current SOTA)
27
-
28
- RL governs **selected** memory operations while others remain manual:
29
-
30
- | System | Memory Op RL-ified | What Remains Manual |
31
- |--------|-------------------|-------------------|
32
- | **RMM** | Retrieval reranking | Memory formation, storage structure |
33
- | **Mem-alpha** | Memory construction (writing) + memory updating | Retrieval pipelines |
34
- | **Memory-R1** | Memory extraction fusion component | Extraction itself (LLMExtract module), retrieval |
35
- | **Mem1** | Summarization (PPO) | Memory structure, retrieval |
36
- | **MemAgent** | Summarization (GRPO) | Memory structure |
37
- | **Memento** | Trajectory selection (Q-learning) | Memory formation |
38
- | **MemSearcher** | Search + memory management (end-to-end RL) | Long-term consolidation |
39
- | **ReSum** | Summary-conditioned behavior (RL) | Memory structure |
40
- | **IterResearch** | Workspace reconstruction (MDP-inspired) | Storage architecture |
41
- | **Context Folding** | Folding/compression policy (RL) | Storage, long-term memory |
42
- | **Memory-as-Action** | Context compression (RL) | Storage architecture |
43
- | **MemGen** | Latent memory trigger + weaver (RL) | External storage |
44
- | **ACON** | State consolidation (optimization) | Actually PE, not RL |
45
-
46
- ### Stage 3: Fully RL-Driven (Future Vision)
47
-
48
- The paper's two defining properties for this stage:
49
-
50
- 1. **No human-engineered priors**: Agents should invent their own memory organizations (formats, schemas, update rules) through RL incentives rather than inheriting human cognitive analogies (hippocampal, cortical, episodic/semantic/core categories).
51
-
52
- 2. **Complete lifecycle control**: The agent autonomously handles formation + evolution + retrieval in an integrated manner via end-to-end RL training.
53
-
54
- **The paper states this does not yet exist.** No current system achieves both properties.
55
-
56
- ---
57
-
58
- ## 2. Detailed System Analysis
59
-
60
- ### RMM (Tan et al., 2025c)
61
-
62
- | Aspect | Detail |
63
- |--------|--------|
64
- | **Memory op RL optimizes** | Retrieval reranking |
65
- | **RL algorithm** | Lightweight policy gradient |
66
- | **Reward signal** | Downstream task performance after reranking |
67
- | **How it works** | After initial retrieval (BM25 or semantic similarity), a lightweight policy gradient learner ranks memory chunks by predicted utility |
68
- | **Difference from prompt-engineering** | The reranker is trained, not prompted. Fixed retriever + learned reranker |
69
- | **Memory structure** | Reflection-organized flat entries; topic-based memory with top-K similarity matching and LLM-based merge decisions |
70
-
71
- ### Mem-alpha (Wang et al., 2025p) -- arXiv 2509.25911
72
-
73
- | Aspect | Detail |
74
- |--------|--------|
75
- | **Memory op RL optimizes** | Memory formation (insight extraction) + memory updating |
76
- | **RL algorithm** | RL-based policy learning (specific algorithm not named in survey, likely GRPO/PPO-family given the field) |
77
- | **Reward signal** | Downstream task performance (document reasoning, multi-objective QA) |
78
- | **How it works** | "Explicitly trains the LLM on **what insights to extract and how to preserve them**." Delegates the entire process of memory construction to an RL-trained agent. Memory updating is formulated as a policy-learning problem -- the LLM learns when, how, and whether to update. |
79
- | **Difference from prompt-engineering** | Most systems use fixed prompts for insight extraction (sensitive to prompt design). Mem-alpha makes extraction itself a learnable policy. |
80
- | **Memory structure** | Core, Semantic, and Episodic memory (three-tier) |
81
- | **Gap** | Still relies on manually defined retrieval pipelines |
82
-
83
- ### Memory-R1 (Yan et al., 2025c) -- arXiv 2508.19828
84
-
85
- | Aspect | Detail |
86
- |--------|--------|
87
- | **Memory op RL optimizes** | Memory fusion (integrating extracted outputs into memory bank) + post-retrieval filtering |
88
- | **RL algorithm** | RL-trained (specific algorithm not named; "R1" naming convention suggests GRPO-family like DeepSeek-R1) |
89
- | **Reward signal** | Answer correctness in long-conversation QA |
90
- | **How it works** | An auxiliary agent with a "memory manager" tool handles memory updates. Uses an LLMExtract module for experiential/factual knowledge extraction. Only the fusion component is trained. Also introduces LLM-based evaluators that filter retrieved content before final response. |
91
- | **Difference from prompt-engineering** | The extraction module itself is not RL-trained (falls short), but the integration/fusion layer is. Prompt-based filtering is limited by LLM capacity; RL training improves robustness. |
92
- | **Memory structure** | RL-managed mem0-like architecture |
93
-
94
- ### MemGen (Zhang et al., 2025d)
95
-
96
- | Aspect | Detail |
97
- |--------|--------|
98
- | **Memory op RL optimizes** | Memory formation (latent representation) + retrieval timing |
99
- | **RL algorithm** | RL + SFT (combined) |
100
- | **Reward signal** | Task performance across web search, embodied simulation, reasoning, math, code |
101
- | **How it works** | Two LoRA adapters: one determines **where** to insert memory fragments, another determines **what** latent content to insert. A "memory trigger" detects critical retrieval moments from latent rollout states. Converts explicit agent-level retrieval decisions into **latent, trainable processes**. |
102
- | **Difference from prompt-engineering** | Memory is latent tokens injected into reasoning stream (not text). Retrieval timing is learned, not rule-based. End-to-end differentiable. |
103
- | **Memory structure** | Latent memory tokens (not human-readable) |
104
-
105
- ### Context Folding (Sun et al., 2025b)
106
-
107
- | Aspect | Detail |
108
- |--------|--------|
109
- | **Memory op RL optimizes** | Working memory compression (hierarchical folding) |
110
- | **RL algorithm** | RL (specific variant not named) |
111
- | **Reward signal** | Task performance in deep research and SWE tasks |
112
- | **How it works** | Makes the folding operation a **learnable policy**. Agents learn to autonomously determine **when to branch** into sub-trajectories and **how to abstract** them into high-level states. Internalizes the ability to compress working memory. In multi-step interactions, automatically summarizes and condenses the global context after each step. |
113
- | **Difference from prompt-engineering** | HiAgent (prompt-based) uses fixed subgoal-based folding. Context Folding trains the folding policy via RL. |
114
-
115
- ### Memory-as-Action (Zhang et al., 2025r) -- also listed as "MemAct" in tables
116
-
117
- | Aspect | Detail |
118
- |--------|--------|
119
- | **Memory op RL optimizes** | Working memory management (context compression) |
120
- | **RL algorithm** | RL (specific variant not named) |
121
- | **Reward signal** | Multi-objective QA task performance |
122
- | **How it works** | Treats memory operations as actions in the agent's policy. Context compression and management are framed as agent actions optimized via RL. |
123
- | **Difference from prompt-engineering** | Memory management is part of the action space, not a separate pipeline |
124
-
125
- ### MemSearcher (Yuan et al., 2025a)
126
-
127
- | Aspect | Detail |
128
- |--------|--------|
129
- | **Memory op RL optimizes** | Reasoning + search + memory management (end-to-end) |
130
- | **RL algorithm** | SFT + RL (end-to-end reinforcement learning per the title) |
131
- | **Reward signal** | Multi-hop QA correctness |
132
- | **How it works** | Employs recurrent mechanisms to update fixed-budget memory and discard redundancy. Answers queries from a compact, evolving state. Title literally says "Training LLMs to Reason, Search and Manage Memory via End-to-End Reinforcement Learning." |
133
- | **Difference from prompt-engineering** | Jointly trains reasoning, search, and memory management. Not a modular pipeline. |
134
- | **Gap** | Focuses primarily on short-term working memory; does not address long-term consolidation or evolution |
135
-
136
- ### Mem1 / MEM1 (Zhou et al., 2025b) -- arXiv 2506.15841
137
-
138
- | Aspect | Detail |
139
- |--------|--------|
140
- | **Memory op RL optimizes** | Incremental summarization |
141
- | **RL algorithm** | **PPO** (Proximal Policy Optimization) |
142
- | **Reward signal** | Retrieval accuracy, open-domain QA, shopping task performance |
143
- | **How it works** | Maintains a shared internal state that merges new observations with prior memory. Enhanced LLM's own summarization capability through RL with PPO. "Learning to synergize memory and reasoning for efficient long-horizon agents." |
144
- | **Difference from prompt-engineering** | MemGPT/Mem0 rely on LLM's inherent summarization (often drifts). Mem1 trains the summarization policy. |
145
-
146
- ### ReSum (Wu et al., 2025f) -- arXiv 2509.13313
147
-
148
- | Aspect | Detail |
149
- |--------|--------|
150
- | **Memory op RL optimizes** | Summary-conditioned behavior for exploration |
151
- | **RL algorithm** | RL (specific variant not named) |
152
- | **Reward signal** | Long-horizon web search task performance |
153
- | **How it works** | Periodically distills history into reasoning states. Uses RL to optimize summary-conditioned behavior for indefinite exploration. "Unlocking Long-Horizon Search Intelligence via Context Summarization." |
154
- | **Difference from prompt-engineering** | The summarization is optimized for downstream exploration performance, not just compression fidelity |
155
-
156
- ### IterResearch (Chen et al., 2025b)
157
-
158
- | Aspect | Detail |
159
- |--------|--------|
160
- | **Memory op RL optimizes** | Workspace reconstruction (iterative memory synthesis) |
161
- | **RL algorithm** | RL with MDP-inspired formulation |
162
- | **Reward signal** | Long-horizon QA, reasoning, web navigation performance |
163
- | **How it works** | Adopts an MDP-inspired formulation with iterative workspace reconstruction. An evolving report serves as persistent memory. Periodic synthesis mitigates "context suffocation" and noise contamination. |
164
- | **Difference from prompt-engineering** | Framed as sequential decision-making (MDP), not static summarization |
165
-
166
- ### Additional RL-Adjacent Systems
167
-
168
- | System | RL Method | What It Does |
169
- |--------|-----------|-------------|
170
- | **MemAgent** (Yu et al., 2025a) | GRPO | Multi-conversation RL-based memory agent. Recurrent memory update for long-term doc QA |
171
- | **Memento** (Zhou et al., 2025a) | Q-learning | Predicts probability that a retrieved item contributes to a correct answer. Fine-tunes retrieval without fine-tuning LLMs. |
172
- | **ACON** (Kang et al., 2025c) | PE (not RL) | Frames state consolidation as optimization but uses prompt engineering, not gradient-based RL |
173
- | **AgentEvolver** | RL | Evolves memory architecture patterns, not just content |
174
- | **SUMER** | RL | QA-focused summarization |
175
- | **Sculptor** | PE + RL | Multi-needle QA |
176
-
177
- ---
178
-
179
- ## 3. Which Memory Operations Are RL-ified vs. Still Manual?
180
-
181
- ### Memory Lifecycle Coverage
182
-
183
- | Memory Operation | RL-ified Examples | Still Mostly Manual/Prompt-Based |
184
- |-----------------|-------------------|----------------------------------|
185
- | **Formation: Summarization** | Mem1 (PPO), MemAgent (GRPO), ReSum (RL) | MemGPT, Mem0 (prompt-based) |
186
- | **Formation: Knowledge Distillation** | Mem-alpha (policy learning), Memory-R1 (fusion only) | ExpeL, Reflexion, H2R (all prompt-based) |
187
- | **Formation: Structured Construction** | None fully RL | GraphRAG, Zep, AriGraph (all heuristic/prompt) |
188
- | **Formation: Latent Representation** | MemGen (RL + SFT) | MemoryLLM, M+ (SFT only) |
189
- | **Evolution: Consolidation** | Context Folding (RL policy) | Most systems (rule-based merge) |
190
- | **Evolution: Updating** | Mem-alpha (policy learning) | MemGPT, D-SMART, Mem0g (rule-based) |
191
- | **Evolution: Forgetting** | None fully RL | All systems (heuristic: LRU, LFU, time-decay) |
192
- | **Retrieval: Timing** | MemGen (learned triggers) | MemGPT (prompt-based triggers) |
193
- | **Retrieval: Reranking** | RMM (policy gradient), Memento (Q-learning) | Most systems (cosine similarity + top-K) |
194
- | **Retrieval: Query Construction** | Limited work | Mostly prompt-engineered |
195
- | **Working Memory: Compression** | MemSearcher, Context Folding, Memory-as-Action, IterResearch | HiAgent, ACON (prompt-based) |
196
-
197
- ### Key Gaps (Still Entirely Manual)
198
-
199
- 1. **Memory forgetting**: No RL-based forgetting policy exists. All use heuristic LRU/LFU/time-decay.
200
- 2. **Structured construction**: No RL for building knowledge graphs or tree structures.
201
- 3. **Retrieval query construction**: Almost entirely prompt-engineered.
202
- 4. **Cross-stage coordination**: No system integrates formation + evolution + retrieval under a single RL policy.
203
-
204
- ---
205
-
206
- ## 4. Practical Takeaways for RecallNest
207
-
208
- ### What We Can Implement WITHOUT Training Our Own Models
209
-
210
- These are architectural and pipeline improvements inspired by RL systems but implementable with prompt-engineering or off-the-shelf components:
211
-
212
- | Improvement | Inspired By | Implementation Approach |
213
- |-------------|------------|----------------------|
214
- | **Memory-as-Action framing** | Memory-as-Action, MemSearcher | Expose memory operations (store/update/delete/retrieve) as explicit tool calls. The LLM agent reasons about when and how to use them. RecallNest already does this via MCP tools -- validate and refine the tool design. |
215
- | **Hierarchical folding for working memory** | HiAgent (prompt-based), ACON | Implement subgoal-based context compression. When a sub-task completes, fold its detailed trace into a summary. ACON does this with prompt engineering only. |
216
- | **Dual-phase updating** | MOOM, LightMem | Soft online update (immediate) + offline reflective consolidation (batch merge/conflict resolution). No RL needed. |
217
- | **Temporal-aware soft deletion** | Zep | Instead of hard-delete, mark conflicting facts with invalid timestamps. Preserves history. |
218
- | **Composite retrieval scoring** | Generative Agents, MAICC | Score memories by recency + importance + relevance (multi-factor). Existing prompt-based approach. |
219
- | **LLM-based post-retrieval filtering** | Memory-R1 | Before injecting retrieved memories into context, have the LLM evaluate relevance and filter. Works without training. |
220
- | **Importance-driven forgetting** | TiM, MemTool | Use LLM to assess memory importance rather than pure recency/frequency heuristics. |
221
- | **Three-tier memory structure** | Mem-alpha | Organize into Core (permanent), Semantic (factual), Episodic (event-based) tiers with different retention policies. |
222
- | **MDP-style workspace reconstruction** | IterResearch | For long research tasks, periodically synthesize an evolving report as persistent state. Reduces context noise. |
223
-
224
- ### What REQUIRES Model Training (Cannot Do with Prompt-Only)
225
-
226
- | Capability | Why Training Is Needed | Example System |
227
- |-----------|----------------------|---------------|
228
- | **RL-trained summarization** | PPO/GRPO-optimized summarization significantly outperforms prompt-based (reduces semantic drift over iterations) | Mem1, MemAgent |
229
- | **Learned memory construction policy** | Training what insights to extract and how to preserve them -- prompt sensitivity is the bottleneck | Mem-alpha |
230
- | **Latent memory tokens** | Requires LoRA adapters trained to inject latent representations into reasoning stream | MemGen |
231
- | **Trained retrieval reranker** | Policy gradient or Q-learning trained reranker consistently outperforms prompt-based reranking | RMM, Memento |
232
- | **End-to-end memory + reasoning** | Joint optimization of search, memory management, and reasoning | MemSearcher |
233
- | **Learned folding policy** | When to fold and how to abstract sub-trajectories | Context Folding |
234
-
235
- ### Hybrid Strategy: What RecallNest Should Do
236
-
237
- **Phase 1 (No training, immediate)**:
238
- - Refine MCP tool design to match the "Memory-as-Action" paradigm. Each tool call should be a deliberate memory action the agent reasons about.
239
- - Implement hierarchical memory tiers (core/semantic/episodic) with differentiated retention policies.
240
- - Add temporal-aware soft deletion instead of hard-delete.
241
- - Implement dual-phase updating (online soft + offline consolidation).
242
- - Add multi-factor retrieval scoring (recency + importance + relevance).
243
- - Add LLM-based post-retrieval filtering before context injection.
244
-
245
- **Phase 2 (Lightweight training / fine-tuning)**:
246
- - Train a small reranker model for memory retrieval (following RMM). This is a lightweight policy gradient learner, not a full LLM training job.
247
- - Fine-tune a summarization adapter using task performance as reward. Even SFT on curated summary examples would help.
248
-
249
- **Phase 3 (Full RL, requires infrastructure)**:
250
- - Train memory construction policy (Mem-alpha style): what to extract, when to update.
251
- - End-to-end RL for memory management (MemSearcher style): joint optimization of retrieval + storage + reasoning.
252
-
253
- ---
254
-
255
- ## 5. Is "Fully RL-Driven Memory" Realistic for an MCP Server?
256
-
257
- ### The Paper's Prediction
258
-
259
- The paper predicts fully RL-driven memory as "the next major stage" with two properties:
260
- 1. No human-engineered priors (agent invents its own memory organization)
261
- 2. Complete lifecycle control (formation + evolution + retrieval integrated under RL)
262
-
263
- ### Reality Check for RecallNest (MCP Server Context)
264
-
265
- **Structural constraint**: RecallNest operates as an external MCP server called by LLM agents. It does not control the LLM's weights or training process. This creates a fundamental architectural gap:
266
-
267
- | Paper's Vision | RecallNest's Reality | Implication |
268
- |---------------|---------------------|-------------|
269
- | RL trains the agent's memory policy | RecallNest is a tool, not the agent | RecallNest can't train the calling LLM. It can only design better tools for the LLM to use. |
270
- | End-to-end RL across memory lifecycle | MCP tools are discrete API calls | Each tool call is a separate decision by the LLM. No gradient flows through RecallNest. |
271
- | Agent invents memory architecture | MCP server defines the schema | RecallNest defines what memory operations exist. The agent can only choose among them. |
272
- | Latent memory tokens | MCP transmits text | RecallNest cannot inject latent representations into the LLM's reasoning stream. |
273
-
274
- **What this means**: RecallNest will never be a "fully RL-driven memory system" in the paper's sense. That requires model-native integration (LoRA adapters, KV-cache manipulation, gradient-based optimization). An MCP server is architecturally external.
275
-
276
- **However**, RecallNest can still capture significant value:
277
-
278
- 1. **Be the best possible tool for RL-capable agents**: As LLMs become RL-trained for memory management (Mem-alpha, MemSearcher), they need well-designed external memory tools. RecallNest should provide the richest, most flexible tool interface.
279
-
280
- 2. **Server-side intelligence without RL**: Even without RL, RecallNest can implement sophisticated heuristics on the server side:
281
- - Importance scoring for memories
282
- - Conflict detection during updates
283
- - Temporal-aware retrieval with decay functions
284
- - Automatic consolidation of related memories
285
- - Proactive forgetting of low-value entries
286
-
287
- 3. **Prepare for model-native integration**: When future LLMs expose hooks for external memory systems to inject into their reasoning (KV-cache APIs, latent memory injection), RecallNest should be architecturally ready to plug in. This means:
288
- - Keep memory representations rich enough to be converted to latent tokens
289
- - Maintain structured metadata that could inform a retrieval reranker
290
- - Design the API to support streaming/incremental operations, not just request-response
291
-
292
- ### Bottom Line
293
-
294
- The "fully RL-driven" vision is **not realistic for an MCP server in its current architectural form**. But it is realistic for RecallNest to be the **best external memory system** that RL-trained agents want to use. The key insight is: as agents get smarter about memory management via RL, they need **richer, more capable external memory stores** -- not simpler ones. The demand for sophisticated MCP memory servers increases, not decreases, in an RL-driven world.
295
-
296
- ---
297
-
298
- ## 6. Summary Table: All RL Memory Systems
299
-
300
- | System | RL Algorithm | Memory Op Optimized | Reward Signal | Stage |
301
- |--------|-------------|-------------------|---------------|-------|
302
- | RMM | Policy gradient | Retrieval reranking | Task accuracy | Partial |
303
- | Mem-alpha | RL policy learning | Formation + updating | Task performance | Partial |
304
- | Memory-R1 | RL (R1-family) | Fusion + filtering | QA correctness | Partial |
305
- | MemGen | RL + SFT | Latent formation + retrieval timing | Multi-task performance | Partial |
306
- | Context Folding | RL | Working memory folding | Research/SWE performance | Partial |
307
- | Memory-as-Action | RL | Context compression | Multi-obj QA | Partial |
308
- | MemSearcher | SFT + RL (E2E) | Reasoning + search + memory | Multi-hop QA | Partial |
309
- | Mem1 | PPO | Summarization | QA + retrieval accuracy | Partial |
310
- | MemAgent | GRPO | Summarization | Doc QA | Partial |
311
- | ReSum | RL | Summary-conditioned exploration | Web search performance | Partial |
312
- | IterResearch | RL (MDP) | Workspace reconstruction | Long-horizon QA | Partial |
313
- | Memento | Q-learning | Trajectory selection | Answer contribution probability | Partial |
314
- | SUMER | RL | QA summarization | QA accuracy | Partial |
315
- | AgentEvolver | RL | Architecture evolution | Task performance | Partial |
316
- | (Fully RL-driven) | -- | All operations | -- | **Does not exist yet** |
317
-
318
- ---
319
-
320
- ## 7. Key Quotes from the Paper
321
-
322
- > "Memory, as one of the foundational components of agentic capability, follows a similar trend from pipeline-based to model-native paradigm." (p.71)
323
-
324
- > "Mem-alpha delegates the entire process of memory construction to an agent trained with RL, and Memory-R1 employs a similar philosophy." (p.71)
325
-
326
- > "Mem-alpha automates certain aspects of memory writing yet still relies on manually defined retrieval pipelines, whereas systems such as MemSearcher focus primarily on short-term working memory without addressing long-term consolidation or evolution." (p.72)
327
-
328
- > "A fully agentic memory system would require the agent to autonomously handle multi-granular memory formation, memory evolution, and memory retrieval in an integrated manner. Achieving this level of control will almost certainly require end-to-end RL training, since heuristic or prompt-based methods are insufficient for coordinating the complex interactions among these components across long-time horizons." (p.72)
329
-
330
- > "The agent is encouraged to design new memory formats, storage schemas, or update rules through RL incentives, enabling memory architectures that are adaptive and creative rather than handcrafted." (p.72)
@@ -1,116 +0,0 @@
1
- #!/usr/bin/env bun
2
- /**
3
- * Archive raw fact fragments that have already been distilled.
4
- * Targets: entries in distill-completed scopes with importance < 0.4, no L0, category=fact.
5
- * Action: set tier="archived", importance=0.05 — they won't surface but data isn't lost.
6
- *
7
- * Usage:
8
- * bun scripts/archive-distilled-junk.ts --dry-run # preview
9
- * bun scripts/archive-distilled-junk.ts # execute
10
- */
11
-
12
- import fs from "fs";
13
- import path from "path";
14
- import { loadDotEnv, loadConfig, expandHome } from "../src/runtime-config.js";
15
- import { loadLanceDB } from "../src/store.js";
16
-
17
- loadDotEnv();
18
- const config = loadConfig();
19
- const dryRun = process.argv.includes("--dry-run");
20
-
21
- const PROGRESS_FILE = path.join(import.meta.dir, "..", "data", "distill-progress.json");
22
-
23
- async function main() {
24
- // Load distill progress to know which scopes are done
25
- const progress = JSON.parse(fs.readFileSync(PROGRESS_FILE, "utf-8"));
26
- const completedScopes = new Set<string>(progress.completedScopes);
27
- console.log(`=== Archive distilled junk${dryRun ? " (dry run)" : ""} ===\n`);
28
- console.log(` Distill-completed scopes: ${completedScopes.size}`);
29
-
30
- const lancedb = await loadLanceDB();
31
- const dbPath = expandHome(config.database?.path || "data/lancedb");
32
- const db = await lancedb.connect(dbPath);
33
- const table = await db.openTable("memories");
34
-
35
- // Read all fact entries
36
- const allFacts = await table.query()
37
- .where("category = 'fact'")
38
- .select(["id", "text", "vector", "category", "scope", "importance", "timestamp", "metadata"])
39
- .toArray();
40
-
41
- console.log(` Total fact entries: ${allFacts.length}`);
42
-
43
- // Filter: in completed scope, importance < 0.4, no L0
44
- const toArchive: any[] = [];
45
- const sampleJunk: string[] = [];
46
-
47
- for (const row of allFacts) {
48
- const scope = (row.scope as string) || "";
49
- if (!completedScopes.has(scope)) continue;
50
-
51
- const imp = Number(row.importance);
52
- if (imp >= 0.4) continue;
53
-
54
- const metaStr = (row.metadata as string) || "{}";
55
- let meta: Record<string, unknown>;
56
- try { meta = JSON.parse(metaStr); } catch { continue; }
57
-
58
- // Has L0 = already a quality entry, skip
59
- if (typeof meta.l0_abstract === "string" && meta.l0_abstract.length > 0) continue;
60
-
61
- // Mark as archived
62
- meta.tier = "archived";
63
- meta.archived_reason = "distilled-junk-cleanup-2026-03-26";
64
-
65
- toArchive.push({
66
- id: row.id,
67
- text: row.text,
68
- vector: Array.from(row.vector as Iterable<number>),
69
- category: row.category,
70
- scope: scope,
71
- importance: 0.05, // near-zero so it never surfaces
72
- timestamp: Number(row.timestamp),
73
- metadata: JSON.stringify(meta),
74
- });
75
-
76
- // Collect samples
77
- if (sampleJunk.length < 10) {
78
- const text = (row.text as string).slice(0, 80);
79
- sampleJunk.push(` ${(row.id as string).slice(0, 8)} imp=${imp.toFixed(2)} scope=${scope.slice(0, 15)} | ${text}`);
80
- }
81
- }
82
-
83
- console.log(` Junk to archive: ${toArchive.length}`);
84
- console.log(` Would keep: ${allFacts.length - toArchive.length} fact entries\n`);
85
-
86
- if (sampleJunk.length > 0) {
87
- console.log(` Sample junk:\n${sampleJunk.join("\n")}\n`);
88
- }
89
-
90
- if (dryRun) {
91
- console.log(` (dry run — no changes made)`);
92
- return;
93
- }
94
-
95
- if (toArchive.length === 0) {
96
- console.log(` Nothing to archive.`);
97
- return;
98
- }
99
-
100
- // Batch update
101
- const batchSize = 1000;
102
- for (let i = 0; i < toArchive.length; i += batchSize) {
103
- const batch = toArchive.slice(i, i + batchSize);
104
- const ids = batch.map((r: any) => `'${r.id.replace(/'/g, "''")}'`).join(",");
105
- await table.delete(`id IN (${ids})`);
106
- await table.add(batch);
107
- console.log(` Batch ${Math.floor(i / batchSize) + 1}: archived ${batch.length} entries`);
108
- }
109
-
110
- console.log(`\nDone. Archived ${toArchive.length} junk fact entries (importance → 0.05, tier → archived).`);
111
- }
112
-
113
- main().catch(err => {
114
- console.error("Archive failed:", err);
115
- process.exit(1);
116
- });
@@ -1,130 +0,0 @@
1
- #!/usr/bin/env bun
2
- /**
3
- * P0.1 backfill: generate retrieval anchors for existing memories that lack one.
4
- * Anchors are short (≤80 chars) text summaries stored in metadata.anchor,
5
- * used by the retriever to boost short query recall.
6
- *
7
- * Usage:
8
- * bun scripts/backfill-anchors.ts --dry-run # preview changes
9
- * bun scripts/backfill-anchors.ts # execute
10
- */
11
-
12
- import { loadDotEnv, loadConfig, expandHome } from "../src/runtime-config.js";
13
- import { loadLanceDB } from "../src/store.js";
14
- import { generateAnchor } from "../src/anchor-generator.js";
15
-
16
- loadDotEnv();
17
- const config = loadConfig();
18
- const dryRun = process.argv.includes("--dry-run");
19
-
20
- async function main() {
21
- const lancedb = await loadLanceDB();
22
- const dbPath = expandHome(config.database?.path || "data/lancedb");
23
- const db = await lancedb.connect(dbPath);
24
- const table = await db.openTable("memories");
25
-
26
- console.log(`=== Anchor backfill${dryRun ? " (dry run)" : ""} ===\n`);
27
-
28
- const allRows = await table.query()
29
- .select(["id", "text", "vector", "category", "scope", "importance", "timestamp", "metadata"])
30
- .toArray();
31
-
32
- console.log(` Total entries: ${allRows.length}`);
33
-
34
- let skippedShort = 0;
35
- let skippedHasAnchor = 0;
36
- let generated = 0;
37
- const toUpdate: Array<{
38
- id: string;
39
- text: string;
40
- vector: number[];
41
- category: string;
42
- scope: string;
43
- importance: number;
44
- timestamp: number;
45
- metadata: string;
46
- }> = [];
47
-
48
- for (const row of allRows) {
49
- const text = row.text as string;
50
- const metaStr = row.metadata as string;
51
-
52
- let meta: Record<string, unknown>;
53
- try { meta = JSON.parse(metaStr || "{}"); } catch { meta = {}; }
54
-
55
- // Skip if already has anchor
56
- if (typeof meta.anchor === "string" && meta.anchor.length > 0) {
57
- skippedHasAnchor++;
58
- continue;
59
- }
60
-
61
- // Generate anchor
62
- const anchor = generateAnchor(text, meta);
63
- if (!anchor) {
64
- skippedShort++;
65
- continue;
66
- }
67
-
68
- meta.anchor = anchor;
69
- generated++;
70
-
71
- if (!dryRun) {
72
- toUpdate.push({
73
- id: row.id as string,
74
- text,
75
- vector: Array.from(row.vector as Iterable<number>),
76
- category: row.category as string,
77
- scope: row.scope as string,
78
- importance: row.importance as number,
79
- timestamp: row.timestamp as number,
80
- metadata: JSON.stringify(meta),
81
- });
82
- }
83
-
84
- if (generated <= 5) {
85
- console.log(` [sample] id=${(row.id as string).slice(0, 8)}… anchor="${anchor}"`);
86
- }
87
- }
88
-
89
- console.log(`\n Summary:`);
90
- console.log(` Already has anchor: ${skippedHasAnchor}`);
91
- console.log(` Text too short (≤80 chars): ${skippedShort}`);
92
- console.log(` Anchors generated: ${generated}`);
93
-
94
- if (dryRun) {
95
- console.log(`\n Dry run — no changes written. Run without --dry-run to apply.`);
96
- return;
97
- }
98
-
99
- if (toUpdate.length === 0) {
100
- console.log(`\n Nothing to update.`);
101
- return;
102
- }
103
-
104
- // Deduplicate by ID (keep last occurrence — handles duplicate rows in source data)
105
- const deduped = new Map<string, (typeof toUpdate)[0]>();
106
- for (const entry of toUpdate) {
107
- deduped.set(entry.id, entry);
108
- }
109
- const uniqueUpdates = [...deduped.values()];
110
- if (uniqueUpdates.length < toUpdate.length) {
111
- console.log(` Deduplicated: ${toUpdate.length} → ${uniqueUpdates.length} unique IDs`);
112
- }
113
-
114
- // Batch upsert (LanceDB mergeInsert with overwrite)
115
- console.log(`\n Writing ${uniqueUpdates.length} updates...`);
116
- const BATCH = 200;
117
- for (let i = 0; i < uniqueUpdates.length; i += BATCH) {
118
- const batch = uniqueUpdates.slice(i, i + BATCH);
119
- await table.mergeInsert("id")
120
- .whenMatchedUpdateAll()
121
- .execute(batch);
122
- process.stdout.write(` ${Math.min(i + BATCH, uniqueUpdates.length)}/${uniqueUpdates.length}\r`);
123
- }
124
- console.log(`\n Done! ${uniqueUpdates.length} entries updated with anchors.`);
125
- }
126
-
127
- main().catch(err => {
128
- console.error("Backfill failed:", err);
129
- process.exit(1);
130
- });
@@ -1,98 +0,0 @@
1
- #!/usr/bin/env bun
2
- /**
3
- * One-time backfill: normalize legacy l0/l1 short names to l0_abstract/l1_overview/l2_content
4
- * in metadata. Uses batch read + batch write for performance.
5
- *
6
- * Usage:
7
- * bun scripts/backfill-l0l1l2.ts --dry-run # preview
8
- * bun scripts/backfill-l0l1l2.ts # execute
9
- */
10
-
11
- import { loadDotEnv, loadConfig, expandHome } from "../src/runtime-config.js";
12
- import { loadLanceDB } from "../src/store.js";
13
-
14
- loadDotEnv();
15
- const config = loadConfig();
16
- const dryRun = process.argv.includes("--dry-run");
17
-
18
- async function main() {
19
- const lancedb = await loadLanceDB();
20
- const dbPath = expandHome(config.database?.path || "data/lancedb");
21
- const db = await lancedb.connect(dbPath);
22
- const table = await db.openTable("memories");
23
-
24
- console.log(`=== L0/L1/L2 metadata backfill${dryRun ? " (dry run)" : ""} ===\n`);
25
-
26
- // Read all rows with metadata
27
- const allRows = await table.query()
28
- .select(["id", "text", "vector", "category", "scope", "importance", "timestamp", "metadata"])
29
- .toArray();
30
-
31
- console.log(` Total entries: ${allRows.length}`);
32
-
33
- const toMigrate: any[] = [];
34
-
35
- for (const row of allRows) {
36
- const metaStr = row.metadata as string;
37
- if (!metaStr) continue;
38
-
39
- let meta: Record<string, unknown>;
40
- try { meta = JSON.parse(metaStr); } catch { continue; }
41
-
42
- const hasShortL0 = typeof meta.l0 === "string" && (meta.l0 as string).length > 0;
43
- const hasShortL1 = typeof meta.l1 === "string" && (meta.l1 as string).length > 0;
44
- const hasLongL0 = typeof meta.l0_abstract === "string";
45
- const hasLongL1 = typeof meta.l1_overview === "string";
46
-
47
- if (!hasShortL0 && !hasShortL1) continue;
48
- if (hasLongL0 && hasLongL1) continue;
49
-
50
- // Migrate field names
51
- if (hasShortL0 && !hasLongL0) meta.l0_abstract = meta.l0;
52
- if (hasShortL1 && !hasLongL1) meta.l1_overview = meta.l1;
53
- if (!meta.l2_content && row.text) meta.l2_content = row.text;
54
- delete meta.l0;
55
- delete meta.l1;
56
-
57
- toMigrate.push({
58
- id: row.id,
59
- text: row.text,
60
- vector: Array.from(row.vector as Iterable<number>),
61
- category: row.category,
62
- scope: row.scope ?? "",
63
- importance: Number(row.importance),
64
- timestamp: Number(row.timestamp),
65
- metadata: JSON.stringify(meta),
66
- });
67
- }
68
-
69
- console.log(` Need migration: ${toMigrate.length}`);
70
- console.log(` Skipped: ${allRows.length - toMigrate.length}`);
71
-
72
- if (dryRun) {
73
- console.log(`\n (dry run — no changes made)`);
74
- return;
75
- }
76
-
77
- if (toMigrate.length === 0) {
78
- console.log(`\n Nothing to do.`);
79
- return;
80
- }
81
-
82
- // Batch delete + batch add
83
- const batchSize = 1000;
84
- for (let i = 0; i < toMigrate.length; i += batchSize) {
85
- const batch = toMigrate.slice(i, i + batchSize);
86
- const ids = batch.map((r: any) => `'${r.id.replace(/'/g, "''")}'`).join(",");
87
- await table.delete(`id IN (${ids})`);
88
- await table.add(batch);
89
- console.log(` Batch ${Math.floor(i / batchSize) + 1}: migrated ${batch.length} entries`);
90
- }
91
-
92
- console.log(`\nDone. Migrated ${toMigrate.length} entries.`);
93
- }
94
-
95
- main().catch(err => {
96
- console.error("Backfill failed:", err);
97
- process.exit(1);
98
- });