recallnest 2.2.0 → 2.2.1

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 (232) hide show
  1. package/.env +4 -0
  2. package/config.json +55 -0
  3. package/logs/daily-recall.error.log +0 -0
  4. package/logs/daily-recall.log +30 -0
  5. package/logs/ingest-2026-04-11.log +110 -0
  6. package/logs/ingest-2026-04-12.log +90 -0
  7. package/logs/launchagent-stderr.log +0 -0
  8. package/logs/launchagent-stdout.log +0 -0
  9. package/package.json +1 -1
  10. package/.claude-plugin/CLAUDE.md +0 -29
  11. package/.claude-plugin/marketplace.json +0 -18
  12. package/.dockerignore +0 -11
  13. package/.github/workflows/ci.yml +0 -28
  14. package/.mcp.json +0 -9
  15. package/CHANGELOG.md +0 -51
  16. package/DEMO.md +0 -94
  17. package/Dockerfile +0 -20
  18. package/EVAL.md +0 -89
  19. package/FAILURES.md +0 -75
  20. package/OPERATIONS.md +0 -59
  21. package/ROADMAP.md +0 -245
  22. package/SKILL.md +0 -250
  23. package/assets/dashboard.png +0 -0
  24. package/assets/knowledge-graph.png +0 -0
  25. package/assets/recallnest-workbench.png +0 -0
  26. package/assets/screenshots/ui-full.png +0 -0
  27. package/assets/screenshots/ui-overview.png +0 -0
  28. package/assets/screenshots/ui-search.png +0 -0
  29. package/assets/ui/app.js +0 -1031
  30. package/assets/ui/index.html +0 -224
  31. package/assets/ui/styles.css +0 -781
  32. package/assets/wechat-qr.jpg +0 -0
  33. package/bun.lock +0 -337
  34. package/daily-reflections/2026-03-05.md +0 -15
  35. package/daily-reflections/2026-03-06.md +0 -15
  36. package/daily-reflections/2026-03-07.md +0 -7
  37. package/daily-reflections/2026-03-08.md +0 -34
  38. package/daily-reflections/2026-03-09.md +0 -35
  39. package/daily-reflections/2026-03-10.md +0 -36
  40. package/daily-reflections/2026-03-11.md +0 -35
  41. package/daily-reflections/2026-03-12.md +0 -36
  42. package/daily-reflections/2026-03-13.md +0 -35
  43. package/daily-reflections/2026-03-14.md +0 -35
  44. package/daily-reflections/2026-03-15.md +0 -35
  45. package/daily-reflections/2026-03-16.md +0 -41
  46. package/daily-reflections/2026-03-17.md +0 -10
  47. package/daily-reflections/2026-03-18.md +0 -10
  48. package/daily-reflections/2026-03-19.md +0 -10
  49. package/daily-reflections/2026-03-20.md +0 -10
  50. package/daily-reflections/2026-03-21.md +0 -10
  51. package/daily-reflections/2026-03-22.md +0 -10
  52. package/daily-reflections/2026-03-23.md +0 -10
  53. package/daily-reflections/2026-03-24.md +0 -10
  54. package/daily-reflections/2026-03-25.md +0 -32
  55. package/daily-reflections/2026-03-26.md +0 -37
  56. package/daily-reflections/2026-03-27.md +0 -35
  57. package/daily-reflections/2026-03-28.md +0 -35
  58. package/daily-reflections/2026-03-29.md +0 -35
  59. package/daily-reflections/2026-03-30.md +0 -36
  60. package/daily-reflections/2026-03-31.md +0 -35
  61. package/daily-reflections/2026-04-01.md +0 -35
  62. package/daily-reflections/2026-04-02.md +0 -35
  63. package/daily-reflections/2026-04-03.md +0 -37
  64. package/daily-reflections/2026-04-04.md +0 -37
  65. package/daily-reflections/2026-04-05.md +0 -35
  66. package/daily-reflections/2026-04-06.md +0 -36
  67. package/daily-reflections/2026-04-07.md +0 -35
  68. package/daily-reflections/2026-04-08.md +0 -35
  69. package/daily-reflections/2026-04-12.md +0 -35
  70. package/data/alias-map.example.json +0 -22
  71. package/docs/api-reference.md +0 -1291
  72. package/docs/architecture.md +0 -168
  73. package/docs/memory-boundary-contract.md +0 -226
  74. package/docs/memory-categories.md +0 -119
  75. package/docs/pipeline-audit-ultramemory.md +0 -177
  76. package/docs/plans/2026-03-08-query-expansion.md +0 -270
  77. package/docs/plans/2026-03-16-continuity-layer.md +0 -196
  78. package/docs/plans/2026-04-01-recall-boost.md +0 -100
  79. package/docs/plans/mcp-tiering-plan.md +0 -126
  80. package/docs/research/recall-quality-audit-2026-03-22.md +0 -153
  81. package/docs/self-evolution.md +0 -198
  82. package/docs/superpowers/plans/2026-03-19-ingest-pipeline-upgrade.md +0 -782
  83. package/docs/superpowers/plans/2026-04-11-constructive-retrieval-emotion.md +0 -1195
  84. package/docs/superpowers/specs/2026-03-19-ingest-pipeline-upgrade-design.md +0 -77
  85. package/docs/superpowers/specs/2026-03-23-pull-claude-desktop-design.md +0 -95
  86. package/docs/superpowers/specs/2026-04-11-constructive-retrieval-emotion-design.md +0 -398
  87. package/eval/continuity/results-2026-03-16.md +0 -117
  88. package/eval/continuity/results-2026-03-19.md +0 -453
  89. package/eval/continuity/runbook.md +0 -110
  90. package/eval/continuity/seed-cases.md +0 -54
  91. package/eval/reports/2026-03-06-abstract-query-baseline.md +0 -96
  92. package/eval/reports/2026-03-06-aws-ssh-baseline.md +0 -82
  93. package/eval/reports/2026-03-06-baseline.md +0 -82
  94. package/eval/reports/query-expansion.md +0 -138
  95. package/glama.json +0 -6
  96. package/lm +0 -19
  97. package/plan-philosophy-upgrades.md +0 -363
  98. package/plan-product-upgrades.md +0 -155
  99. package/plan-v1.2-distributable.md +0 -105
  100. package/plan.md +0 -140
  101. package/research-memory-evolution.md +0 -440
  102. package/research-rl-agent-memory.md +0 -330
  103. package/scripts/archive-distilled-junk.ts +0 -116
  104. package/scripts/backfill-anchors.ts +0 -130
  105. package/scripts/backfill-l0l1l2.ts +0 -98
  106. package/scripts/blind-scan.ts +0 -588
  107. package/scripts/cleanup-step1-exact-dups.ts +0 -117
  108. package/scripts/cleanup-step2-template-dups.ts +0 -113
  109. package/scripts/cleanup-step3-stale-content.ts +0 -149
  110. package/scripts/cleanup-step4-orphan-scopes.ts +0 -131
  111. package/scripts/delete-distilled-junk.ts +0 -88
  112. package/scripts/diagnose-vector-search.ts +0 -132
  113. package/scripts/distill-facts.ts +0 -305
  114. package/scripts/health-check.ts +0 -343
  115. package/scripts/incremental-ingest.sh +0 -71
  116. package/scripts/migrate-language.ts +0 -75
  117. package/scripts/mlp-health-check.ts +0 -382
  118. package/scripts/pull-claude-desktop.ts +0 -515
  119. package/scripts/re-ingest-cc.sh +0 -66
  120. package/scripts/rebalance-memory-health.ts +0 -181
  121. package/scripts/run-desktop-ingest.sh +0 -11
  122. package/scripts/start-server.sh +0 -12
  123. package/scripts/verify-emotion-decay.ts +0 -148
  124. package/scripts/viz-dashboard.html +0 -423
  125. package/scripts/viz-export.ts +0 -703
  126. package/src/__tests__/access-tracker-novelty.test.ts +0 -228
  127. package/src/__tests__/activity-counter.test.ts +0 -96
  128. package/src/__tests__/admission-control.test.ts +0 -206
  129. package/src/__tests__/anchor-generator.test.ts +0 -67
  130. package/src/__tests__/auto-consolidation.test.ts +0 -168
  131. package/src/__tests__/auto-recall.test.ts +0 -131
  132. package/src/__tests__/babel-integration.test.ts +0 -139
  133. package/src/__tests__/batch-dedup.test.ts +0 -65
  134. package/src/__tests__/capture-engine.test.ts +0 -1144
  135. package/src/__tests__/capture-heuristic.test.ts +0 -171
  136. package/src/__tests__/cascade-forget.test.ts +0 -210
  137. package/src/__tests__/category-min-scores.test.ts +0 -33
  138. package/src/__tests__/cc8-cc1-essential-context.test.ts +0 -298
  139. package/src/__tests__/circuit-breaker.test.ts +0 -99
  140. package/src/__tests__/cluster-consolidation.test.ts +0 -712
  141. package/src/__tests__/confidence-metadata.test.ts +0 -125
  142. package/src/__tests__/confidence-tracker.test.ts +0 -249
  143. package/src/__tests__/conflict-advisor.test.ts +0 -206
  144. package/src/__tests__/conflict-escalation.test.ts +0 -149
  145. package/src/__tests__/conflict-lifecycle.test.ts +0 -83
  146. package/src/__tests__/conflict-output.test.ts +0 -85
  147. package/src/__tests__/conflict-store.test.ts +0 -374
  148. package/src/__tests__/consolidation-engine.test.ts +0 -181
  149. package/src/__tests__/constructive-retrieval.test.ts +0 -509
  150. package/src/__tests__/context-collapse-renderer.test.ts +0 -214
  151. package/src/__tests__/context-composer-pins.test.ts +0 -64
  152. package/src/__tests__/context-composer-task-selection.test.ts +0 -24
  153. package/src/__tests__/context-reconstructor.test.ts +0 -65
  154. package/src/__tests__/context-renderer.test.ts +0 -91
  155. package/src/__tests__/continuity-eval.test.ts +0 -275
  156. package/src/__tests__/continuity-schema.test.ts +0 -97
  157. package/src/__tests__/conversation-importer.test.ts +0 -692
  158. package/src/__tests__/core-recall-eval.test.ts +0 -235
  159. package/src/__tests__/core-summary.test.ts +0 -109
  160. package/src/__tests__/data-checkup.test.ts +0 -225
  161. package/src/__tests__/decay-exemption.test.ts +0 -84
  162. package/src/__tests__/dedup-actions.test.ts +0 -58
  163. package/src/__tests__/dedup-guard.test.ts +0 -39
  164. package/src/__tests__/deterministic-id.test.ts +0 -39
  165. package/src/__tests__/distill-lock.test.ts +0 -176
  166. package/src/__tests__/doctor.test.ts +0 -303
  167. package/src/__tests__/dream-pipeline.test.ts +0 -232
  168. package/src/__tests__/drill-down.test.ts +0 -108
  169. package/src/__tests__/embedder.test.ts +0 -122
  170. package/src/__tests__/emotion-decay.test.ts +0 -46
  171. package/src/__tests__/emotion-detector.test.ts +0 -56
  172. package/src/__tests__/emotion-phase1-integration.test.ts +0 -153
  173. package/src/__tests__/emotion-retrieval.test.ts +0 -56
  174. package/src/__tests__/entity-resolver.test.ts +0 -58
  175. package/src/__tests__/ethics-layer.test.ts +0 -476
  176. package/src/__tests__/event-segmenter.test.ts +0 -153
  177. package/src/__tests__/feature-flags-integration.test.ts +0 -54
  178. package/src/__tests__/frequency-tracker.test.ts +0 -113
  179. package/src/__tests__/graph-export.test.ts +0 -489
  180. package/src/__tests__/hotness-blend.test.ts +0 -76
  181. package/src/__tests__/ingest.test.ts +0 -360
  182. package/src/__tests__/interference-detector.test.ts +0 -203
  183. package/src/__tests__/kg-extractor.test.ts +0 -184
  184. package/src/__tests__/kg-store.test.ts +0 -198
  185. package/src/__tests__/llm-consolidation.test.ts +0 -226
  186. package/src/__tests__/mcp-efficiency.test.ts +0 -288
  187. package/src/__tests__/memory-boundaries.test.ts +0 -237
  188. package/src/__tests__/memory-evolution-b2-b3-e1.test.ts +0 -243
  189. package/src/__tests__/memory-evolution.test.ts +0 -271
  190. package/src/__tests__/memory-health-rebalance.test.ts +0 -144
  191. package/src/__tests__/memory-lint.test.ts +0 -271
  192. package/src/__tests__/memory-output.test.ts +0 -215
  193. package/src/__tests__/multi-vector.test.ts +0 -242
  194. package/src/__tests__/narrative-architecture.test.ts +0 -456
  195. package/src/__tests__/pending-review.test.ts +0 -77
  196. package/src/__tests__/post-retrieval-filter.test.ts +0 -178
  197. package/src/__tests__/ppr-traversal.test.ts +0 -256
  198. package/src/__tests__/prediction-engine.test.ts +0 -349
  199. package/src/__tests__/predictive-prospective-memory.test.ts +0 -416
  200. package/src/__tests__/preference-guard-smoke.test.ts +0 -211
  201. package/src/__tests__/preference-matcher.test.ts +0 -230
  202. package/src/__tests__/preference-slots.test.ts +0 -205
  203. package/src/__tests__/prospective-memory.test.ts +0 -283
  204. package/src/__tests__/query-entity-detector.test.ts +0 -171
  205. package/src/__tests__/query-expander-alias.test.ts +0 -89
  206. package/src/__tests__/query-expander.test.ts +0 -34
  207. package/src/__tests__/recall-governor.test.ts +0 -227
  208. package/src/__tests__/recall-mode.test.ts +0 -64
  209. package/src/__tests__/result-synthesizer.test.ts +0 -198
  210. package/src/__tests__/resume-context.test.ts +0 -4898
  211. package/src/__tests__/retrieval-trace.test.ts +0 -213
  212. package/src/__tests__/retriever-boundary-weight.test.ts +0 -136
  213. package/src/__tests__/retroactive-boost.test.ts +0 -223
  214. package/src/__tests__/salience-scoring.test.ts +0 -106
  215. package/src/__tests__/scope-inventory.test.ts +0 -200
  216. package/src/__tests__/scope-policy.test.ts +0 -69
  217. package/src/__tests__/session-checkpoint.test.ts +0 -259
  218. package/src/__tests__/session-distiller.test.ts +0 -611
  219. package/src/__tests__/session-gc.test.ts +0 -215
  220. package/src/__tests__/skill-engine.test.ts +0 -546
  221. package/src/__tests__/skill-promotion.test.ts +0 -349
  222. package/src/__tests__/store-scope-audit.test.ts +0 -81
  223. package/src/__tests__/supersede-chain.test.ts +0 -154
  224. package/src/__tests__/temporal-parser.test.ts +0 -241
  225. package/src/__tests__/temporal-validity.test.ts +0 -160
  226. package/src/__tests__/term-registry.test.ts +0 -121
  227. package/src/__tests__/tool-output-compressor.test.ts +0 -133
  228. package/src/__tests__/topic-tag.test.ts +0 -113
  229. package/src/__tests__/trusted-memory.test.ts +0 -828
  230. package/src/__tests__/version-manager.test.ts +0 -213
  231. package/src/__tests__/workflow-observation.test.ts +0 -400
  232. 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
- });