recallnest 1.4.1 → 2.2.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.
- package/.dockerignore +11 -0
- package/CLAUDE.md +7 -3
- package/Dockerfile +20 -0
- package/README.md +202 -130
- package/README_CN.md +263 -190
- package/ROADMAP.md +128 -81
- package/SKILL.md +250 -0
- package/assets/dashboard.png +0 -0
- package/assets/knowledge-graph.png +0 -0
- package/assets/screenshots/ui-full.png +0 -0
- package/assets/screenshots/ui-overview.png +0 -0
- package/assets/screenshots/ui-search.png +0 -0
- package/assets/ui/app.js +227 -3
- package/assets/ui/index.html +81 -11
- package/assets/ui/styles.css +178 -2
- package/bin/recallnest.mjs +62 -0
- package/bun.lock +337 -0
- package/daily-recall.sh +23 -0
- package/daily-reflections/2026-04-02.md +35 -0
- package/daily-reflections/2026-04-03.md +37 -0
- package/daily-reflections/2026-04-04.md +37 -0
- package/daily-reflections/2026-04-05.md +35 -0
- package/daily-reflections/2026-04-06.md +36 -0
- package/daily-reflections/2026-04-07.md +35 -0
- package/daily-reflections/2026-04-08.md +35 -0
- package/daily-reflections/2026-04-12.md +35 -0
- package/data/alias-map.example.json +22 -0
- package/docs/plans/2026-04-01-recall-boost.md +100 -0
- package/docs/superpowers/plans/2026-04-11-constructive-retrieval-emotion.md +1195 -0
- package/docs/superpowers/specs/2026-04-11-constructive-retrieval-emotion-design.md +398 -0
- package/glama.json +6 -0
- package/integrations/setup-all.sh +31 -0
- package/package.json +10 -3
- package/plan-philosophy-upgrades.md +363 -0
- package/plan-product-upgrades.md +155 -0
- package/plan.md +140 -0
- package/research-memory-evolution.md +440 -0
- package/research-rl-agent-memory.md +330 -0
- package/scripts/backfill-anchors.ts +130 -0
- package/scripts/diagnose-vector-search.ts +132 -0
- package/scripts/migrate-language.ts +75 -0
- package/scripts/verify-emotion-decay.ts +148 -0
- package/src/__tests__/activity-counter.test.ts +96 -0
- package/src/__tests__/admission-control.test.ts +206 -0
- package/src/__tests__/anchor-generator.test.ts +67 -0
- package/src/__tests__/babel-integration.test.ts +139 -0
- package/src/__tests__/capture-engine.test.ts +5 -3
- package/src/__tests__/cascade-forget.test.ts +1 -1
- package/src/__tests__/cc8-cc1-essential-context.test.ts +298 -0
- package/src/__tests__/circuit-breaker.test.ts +99 -0
- package/src/__tests__/cluster-consolidation.test.ts +712 -0
- package/src/__tests__/confidence-metadata.test.ts +125 -0
- package/src/__tests__/confidence-tracker.test.ts +53 -0
- package/src/__tests__/consolidation-engine.test.ts +1 -1
- package/src/__tests__/constructive-retrieval.test.ts +509 -0
- package/src/__tests__/context-collapse-renderer.test.ts +214 -0
- package/src/__tests__/context-reconstructor.test.ts +65 -0
- package/src/__tests__/conversation-importer.test.ts +692 -0
- package/src/__tests__/data-checkup.test.ts +225 -0
- package/src/__tests__/decay-exemption.test.ts +84 -0
- package/src/__tests__/dedup-guard.test.ts +39 -0
- package/src/__tests__/distill-lock.test.ts +176 -0
- package/src/__tests__/dream-pipeline.test.ts +232 -0
- package/src/__tests__/emotion-decay.test.ts +46 -0
- package/src/__tests__/emotion-detector.test.ts +56 -0
- package/src/__tests__/emotion-phase1-integration.test.ts +153 -0
- package/src/__tests__/emotion-retrieval.test.ts +56 -0
- package/src/__tests__/ethics-layer.test.ts +476 -0
- package/src/__tests__/feature-flags-integration.test.ts +54 -0
- package/src/__tests__/frequency-tracker.test.ts +113 -0
- package/src/__tests__/graph-export.test.ts +489 -0
- package/src/__tests__/interference-detector.test.ts +203 -0
- package/src/__tests__/mcp-efficiency.test.ts +288 -0
- package/src/__tests__/memory-evolution-b2-b3-e1.test.ts +243 -0
- package/src/__tests__/memory-evolution.test.ts +271 -0
- package/src/__tests__/memory-lint.test.ts +271 -0
- package/src/__tests__/narrative-architecture.test.ts +456 -0
- package/src/__tests__/pending-review.test.ts +77 -0
- package/src/__tests__/post-retrieval-filter.test.ts +178 -0
- package/src/__tests__/prediction-engine.test.ts +349 -0
- package/src/__tests__/predictive-prospective-memory.test.ts +416 -0
- package/src/__tests__/preference-slots.test.ts +99 -0
- package/src/__tests__/query-expander-alias.test.ts +89 -0
- package/src/__tests__/recall-governor.test.ts +227 -0
- package/src/__tests__/resume-context.test.ts +156 -1
- package/src/__tests__/salience-scoring.test.ts +106 -0
- package/src/__tests__/session-distiller.test.ts +611 -0
- package/src/__tests__/skill-engine.test.ts +546 -0
- package/src/__tests__/skill-promotion.test.ts +349 -0
- package/src/__tests__/supersede-chain.test.ts +154 -0
- package/src/__tests__/temporal-validity.test.ts +160 -0
- package/src/__tests__/topic-tag.test.ts +113 -0
- package/src/__tests__/trusted-memory.test.ts +828 -0
- package/src/__tests__/write-verifier.test.ts +122 -0
- package/src/access-tracker.ts +3 -2
- package/src/activity-counter.ts +109 -0
- package/src/adaptive-retrieval.ts +6 -5
- package/src/admission-control.ts +163 -0
- package/src/anchor-generator.ts +80 -0
- package/src/api-server.ts +10 -0
- package/src/audit-log.ts +122 -0
- package/src/auto-gc.ts +98 -29
- package/src/auto-recall.ts +33 -4
- package/src/capture-engine.ts +372 -23
- package/src/cascade-forget.ts +3 -2
- package/src/cli.ts +107 -5
- package/src/compat.ts +22 -0
- package/src/confidence-tracker.ts +210 -47
- package/src/conflict-store.ts +12 -3
- package/src/consolidation-engine.ts +296 -8
- package/src/context-collapse-renderer.ts +222 -0
- package/src/context-composer-stable-selection.ts +5 -1
- package/src/context-composer.ts +239 -4
- package/src/context-reconstructor.ts +404 -0
- package/src/conversation-importer.ts +441 -0
- package/src/data-checkup.ts +232 -0
- package/src/decay-engine.ts +84 -0
- package/src/distill-lock.ts +122 -0
- package/src/doctor.ts +8 -10
- package/src/dream-pipeline.ts +227 -0
- package/src/emotion-detector.ts +90 -0
- package/src/eval.ts +3 -2
- package/src/forget-engine.ts +269 -0
- package/src/frequency-tracker.ts +175 -0
- package/src/graph-export.ts +644 -0
- package/src/ingest.ts +36 -6
- package/src/interference-detector.ts +187 -0
- package/src/kg-extractor.ts +15 -24
- package/src/kg-store.ts +2 -1
- package/src/language-hook.ts +67 -0
- package/src/llm-client.ts +289 -6
- package/src/mcp-server.ts +707 -80
- package/src/memory-assets.ts +22 -5
- package/src/memory-evolution.ts +365 -0
- package/src/memory-lint.ts +429 -0
- package/src/memory-output.ts +69 -0
- package/src/memory-schema.ts +74 -2
- package/src/narrative-schema.ts +79 -0
- package/src/narrative-tagger.ts +164 -0
- package/src/pii-detector.ts +98 -0
- package/src/post-retrieval-filter.ts +76 -0
- package/src/prediction-engine.ts +253 -0
- package/src/preference-slots.ts +65 -2
- package/src/prospective-memory.ts +215 -0
- package/src/query-expander.ts +67 -0
- package/src/recall-governor.ts +183 -0
- package/src/retention-policy.ts +90 -0
- package/src/retriever.ts +828 -55
- package/src/rif.ts +34 -8
- package/src/runtime-config.ts +23 -8
- package/src/scope-inventory.ts +4 -3
- package/src/scope-policy.ts +4 -0
- package/src/session-distiller.ts +307 -0
- package/src/session-output.ts +40 -0
- package/src/session-schema.ts +37 -0
- package/src/session-store.ts +7 -2
- package/src/skill-engine.ts +208 -0
- package/src/skill-promotion.ts +293 -0
- package/src/skill-schema.ts +39 -0
- package/src/store.ts +96 -10
- package/src/topic-tag.ts +66 -0
- package/src/tracker.ts +3 -1
- package/src/ui-server.ts +80 -8
- package/src/workflow-observation-scope-review.ts +2 -1
- package/src/workflow-observation-store.ts +2 -1
- package/src/write-verifier.ts +126 -0
|
@@ -0,0 +1,363 @@
|
|
|
1
|
+
# Implementation Plan: Memory Philosophy-Driven RecallNest Upgrades
|
|
2
|
+
|
|
3
|
+
> Date: 2026-04-11
|
|
4
|
+
> Status: ✅ ALL 5 PHASES COMPLETE (commits a9e53d3..d150b8d, 1391 tests / 0 fail)
|
|
5
|
+
> Source: Memory philosophy research map + Codex code analysis + Explorer codebase audit
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Overview
|
|
10
|
+
|
|
11
|
+
Five upgrade phases derived from memory philosophy research, each mapped to concrete code changes in the RecallNest codebase. Phase 1 (Emotional Valence in Decay) is implementation-ready today -- the building blocks exist but are not wired into production paths. Phases 2-5 build outward from that foundation. All phases are designed to be independently mergeable and testable.
|
|
12
|
+
|
|
13
|
+
## Dependency Graph
|
|
14
|
+
|
|
15
|
+
```
|
|
16
|
+
Phase 1 (Emotion Decay) <- standalone, no dependencies
|
|
17
|
+
Phase 2 (Ethics Layer) <- standalone, no dependencies on Phase 1
|
|
18
|
+
Phase 3 (Narrative) <- standalone, enriches Phase 4 if done first
|
|
19
|
+
Phase 4 (Constructive) <- benefits from Phase 3 (narrative siblings), Phase 1 (emotion salience)
|
|
20
|
+
Phase 5 (Predictive) <- benefits from Phase 4 (reconstruction surface)
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
Phases 1, 2, and 3 can run in parallel. Phase 4 benefits from all three. Phase 5 builds on Phase 4.
|
|
24
|
+
|
|
25
|
+
## Time Estimates
|
|
26
|
+
|
|
27
|
+
| Phase | Estimated Effort | Complexity |
|
|
28
|
+
|-------|-----------------|------------|
|
|
29
|
+
| Phase 1 | 3-4 hours | Low -- wiring existing code |
|
|
30
|
+
| Phase 2 | 2-3 days | Medium -- new forget engine + lifecycle unification |
|
|
31
|
+
| Phase 3 | 2-3 days | Medium -- new metadata layer + write/read points |
|
|
32
|
+
| Phase 4 | 3-4 days | High -- LLM pipeline changes + grounding rewrite |
|
|
33
|
+
| Phase 5 | 2-3 days | Medium -- new prediction engine + surface layer |
|
|
34
|
+
| **Total** | **~12-15 days** | |
|
|
35
|
+
|
|
36
|
+
---
|
|
37
|
+
|
|
38
|
+
## Phase 1: Emotional Valence in Decay (TODAY)
|
|
39
|
+
|
|
40
|
+
### Goal
|
|
41
|
+
Wire the existing emotion-adjusted decay functions (`adjustHalfLifeForEmotion`, `computeArousalBoost`) into the production retrieval and evolution scoring paths. Extend `EmotionMetadata` with `salience` and `source` fields. Recalculate emotion on text updates. Backfill emotion on import.
|
|
42
|
+
|
|
43
|
+
### Current State
|
|
44
|
+
- `emotion-detector.ts` -- keyword heuristic, zero LLM cost, fully tested
|
|
45
|
+
- `decay-engine.ts:99-119` -- `adjustHalfLifeForEmotion()` and `computeArousalBoost()` exist with tests but are NOT called from production code
|
|
46
|
+
- `store.ts:370` -- `detectEmotionIfEnabled()` auto-annotates on `store()`
|
|
47
|
+
- `retriever.ts:261` -- `applyEmotionWeight()` retrieval scoring is live
|
|
48
|
+
- `retriever.ts:1657` -- `applyTimeDecay()` does NOT use emotion-adjusted half-life
|
|
49
|
+
- `memory-evolution.ts:306` -- `computeDecayScore()` has no emotion factor
|
|
50
|
+
- Feature flag: `RECALLNEST_EMOTION_SCORING=true`
|
|
51
|
+
|
|
52
|
+
### Files Changed
|
|
53
|
+
|
|
54
|
+
| File | Function(s) | Change |
|
|
55
|
+
|------|------------|--------|
|
|
56
|
+
| `src/memory-schema.ts` | `EmotionMetadata`, `EmotionMetadataSchema` | Add `salience` and `source` fields |
|
|
57
|
+
| `src/retriever.ts` | `applyTimeDecay()` (line 1657) | Wire `adjustHalfLifeForEmotion()` into half-life computation |
|
|
58
|
+
| `src/memory-evolution.ts` | `computeDecayScore()` (line 306), weight constants | Add emotion salience factor, rebalance weights |
|
|
59
|
+
| `src/store.ts` | `update()` (line 863) | Recalculate emotion when text changes |
|
|
60
|
+
| `src/store.ts` | `importEntry()` (line 433) | Backfill emotion if absent |
|
|
61
|
+
| `src/emotion-detector.ts` | `detectEmotion()` | Compute `salience` from |valence| + arousal |
|
|
62
|
+
| Tests | New + updated | Emotion-decay integration, update re-detection, import backfill |
|
|
63
|
+
|
|
64
|
+
### Steps
|
|
65
|
+
|
|
66
|
+
#### 1.1 Extend EmotionMetadata schema
|
|
67
|
+
**File:** `src/memory-schema.ts` (lines 40-53)
|
|
68
|
+
|
|
69
|
+
- [x] Add `salience?: number` field to `EmotionMetadata` interface (0-1 composite of |valence| + arousal)
|
|
70
|
+
- [x] Add `source?: "keyword" | "llm" | "user"` field to `EmotionMetadata` interface
|
|
71
|
+
- [x] Update `EmotionMetadataSchema` Zod object to include `salience: z.number().min(0).max(1).optional()` and `source: z.enum(["keyword", "llm", "user"]).optional()`
|
|
72
|
+
- [x] Verify `parseEmotion()` still works with old data (no salience/source)
|
|
73
|
+
- **Why:** Salience is the single composite signal that decay and evolution scoring will consume. Source enables future LLM-based emotion detection without breaking keyword entries.
|
|
74
|
+
- **Risk:** Low -- additive optional fields, backward compatible
|
|
75
|
+
|
|
76
|
+
#### 1.2 Compute salience in detectEmotion
|
|
77
|
+
**File:** `src/emotion-detector.ts`, function `detectEmotion()` (line 62)
|
|
78
|
+
|
|
79
|
+
- [x] After computing `valence` and `arousal`, compute `salience = clamp((Math.abs(valence) + arousal) / 2, 0, 1)`
|
|
80
|
+
- [x] Add `salience` and `source: "keyword"` to the returned `EmotionMetadata` object
|
|
81
|
+
- [x] Update `detectEmotionIfEnabled()` -- no change needed (passes through)
|
|
82
|
+
- **Why:** Decay engine needs a single 0-1 signal, not separate valence/arousal. Formula: average of emotional intensity and arousal, giving equal weight to "how emotional" and "how urgent."
|
|
83
|
+
- **Risk:** Low -- pure addition to return value
|
|
84
|
+
|
|
85
|
+
#### 1.3 Wire emotion into applyTimeDecay
|
|
86
|
+
**File:** `src/retriever.ts`, method `applyTimeDecay()` (line 1657)
|
|
87
|
+
|
|
88
|
+
- [x] Import `adjustHalfLifeForEmotion` from `decay-engine.ts` and `parseEmotion` from `memory-schema.ts`
|
|
89
|
+
- [x] At line 1670-1672 (after `this.accessTracker.computeEffectiveHalfLife()`), add emotion adjustment: if `isEmotionScoringEnabled()`, parse emotion from `r.entry.metadata`, call `adjustHalfLifeForEmotion(halfLife, emotion)` to get final half-life
|
|
90
|
+
- [x] Guard behind `isEmotionScoringEnabled()` flag check
|
|
91
|
+
- [x] The arousal boost (`computeArousalBoost()`) applies to score before decay
|
|
92
|
+
|
|
93
|
+
**Current code pattern:**
|
|
94
|
+
```typescript
|
|
95
|
+
const halfLife = this.accessTracker
|
|
96
|
+
? this.accessTracker.computeEffectiveHalfLife(baseHalfLife, r.entry.metadata)
|
|
97
|
+
: baseHalfLife;
|
|
98
|
+
const tier = resolveTier(r.entry.metadata);
|
|
99
|
+
const factor = weibullDecay(ageDays, halfLife, tier);
|
|
100
|
+
return { ...r, score: clamp01(r.score * factor, r.score * 0.3) };
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
**Target code:**
|
|
104
|
+
```typescript
|
|
105
|
+
let halfLife = this.accessTracker
|
|
106
|
+
? this.accessTracker.computeEffectiveHalfLife(baseHalfLife, r.entry.metadata)
|
|
107
|
+
: baseHalfLife;
|
|
108
|
+
// HP-emo: Emotion-adjusted half-life — strong emotion slows forgetting
|
|
109
|
+
const emotion = isEmotionScoringEnabled() ? parseEmotion(r.entry.metadata) : null;
|
|
110
|
+
if (emotion) {
|
|
111
|
+
halfLife = adjustHalfLifeForEmotion(halfLife, emotion);
|
|
112
|
+
}
|
|
113
|
+
const tier = resolveTier(r.entry.metadata);
|
|
114
|
+
const factor = weibullDecay(ageDays, halfLife, tier);
|
|
115
|
+
const arousalFactor = emotion ? computeArousalBoost(emotion) : 1.0;
|
|
116
|
+
return { ...r, score: clamp01(r.score * arousalFactor * factor, r.score * 0.3) };
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
- **Why:** This is the primary gap -- emotion detection runs on write, emotion weight runs on retrieval scoring, but the decay curve itself ignores emotion. A frustrating debugging session should decay slower than a neutral log entry.
|
|
120
|
+
- **Risk:** Medium -- touches the core scoring pipeline. Parse emotion once per result to avoid double-parse overhead.
|
|
121
|
+
|
|
122
|
+
#### 1.4 Add emotion factor to computeDecayScore
|
|
123
|
+
**File:** `src/memory-evolution.ts`, function `computeDecayScore()` (line 306), constants at lines 292-295
|
|
124
|
+
|
|
125
|
+
- [x] Import `parseEmotion`, `isEmotionScoringEnabled` from `memory-schema.ts`
|
|
126
|
+
- [x] Add optional `metadata?: string` parameter to `computeDecayScore()` (backward compatible)
|
|
127
|
+
- [x] When `isEmotionScoringEnabled()` and metadata is provided, extract salience
|
|
128
|
+
- [x] Rebalance weights from `0.2/0.3/0.5` to `0.15/0.25/0.45/0.15`:
|
|
129
|
+
```typescript
|
|
130
|
+
const EMOTION_WEIGHT = isEmotionScoringEnabled() ? 0.15 : 0;
|
|
131
|
+
const TIME_W = isEmotionScoringEnabled() ? 0.15 : 0.2;
|
|
132
|
+
const FREQ_W = isEmotionScoringEnabled() ? 0.25 : 0.3;
|
|
133
|
+
const IMP_W = isEmotionScoringEnabled() ? 0.45 : 0.5;
|
|
134
|
+
// Final: TIME_W * timeDecay + FREQ_W * frequencyScore + IMP_W * importance + EMOTION_WEIGHT * salience
|
|
135
|
+
```
|
|
136
|
+
- [x] Update all callers to pass metadata where available:
|
|
137
|
+
- `auto-gc.ts:142` -- pass `entry.metadata`
|
|
138
|
+
- `retriever.ts:1712` (applyEvolutionDecayBlend) -- pass `r.entry.metadata`
|
|
139
|
+
- **Why:** The evolution decay score determines GC archival and evolution blend. Without emotion, high-emotion events get same decay as routine logs.
|
|
140
|
+
- **Risk:** Medium -- changes GC archival threshold behavior. Emotional memories will resist archival slightly more (desirable).
|
|
141
|
+
|
|
142
|
+
#### 1.5 Re-detect emotion on text update
|
|
143
|
+
**File:** `src/store.ts`, method `update()` (line 863)
|
|
144
|
+
|
|
145
|
+
- [x] After building the `updated` entry, if `updates.text` is provided (text changed), re-run emotion detection:
|
|
146
|
+
```typescript
|
|
147
|
+
if (updates.text) {
|
|
148
|
+
const emotionResult = detectEmotionIfEnabled(updated.text);
|
|
149
|
+
if (emotionResult) {
|
|
150
|
+
const meta = JSON.parse(updated.metadata || "{}");
|
|
151
|
+
meta.emotion = emotionResult;
|
|
152
|
+
updated.metadata = JSON.stringify(meta);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
```
|
|
156
|
+
- [x] Place this BEFORE the `table!.delete` + `table!.add` at lines 918-920
|
|
157
|
+
- **Why:** When text is updated (e.g., supersede-with-edit), stale emotion metadata creates scoring inaccuracy.
|
|
158
|
+
- **Risk:** Low -- only fires when text is explicitly changed
|
|
159
|
+
|
|
160
|
+
#### 1.6 Backfill emotion on importEntry
|
|
161
|
+
**File:** `src/store.ts`, method `importEntry()` (line 433)
|
|
162
|
+
|
|
163
|
+
- [x] After building `full` entry, check if emotion is already present in metadata. If not, detect and inject:
|
|
164
|
+
```typescript
|
|
165
|
+
const metaParsed = JSON.parse(full.metadata || "{}");
|
|
166
|
+
if (!metaParsed.emotion) {
|
|
167
|
+
const emotionResult = detectEmotionIfEnabled(full.text);
|
|
168
|
+
if (emotionResult) {
|
|
169
|
+
metaParsed.emotion = emotionResult;
|
|
170
|
+
full.metadata = JSON.stringify(metaParsed);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
```
|
|
174
|
+
- **Why:** Imported entries may pre-date emotion detection. Backfilling ensures all entries have emotion metadata.
|
|
175
|
+
- **Risk:** Low -- only adds when absent, never overwrites
|
|
176
|
+
|
|
177
|
+
#### 1.7 Tests
|
|
178
|
+
- [x] **emotion-decay.test.ts**: Add test that `salience` is present in `detectEmotion()` output and matches expected formula
|
|
179
|
+
- [x] **emotion-decay.test.ts**: Add test that `source` field is `"keyword"` in `detectEmotion()` output
|
|
180
|
+
- [x] **New: emotion-evolution-decay.test.ts**: Test `computeDecayScore` with emotion metadata yields higher score than without
|
|
181
|
+
- [x] **New: emotion-evolution-decay.test.ts**: Test backward compat -- no metadata param still works
|
|
182
|
+
- [x] **New: emotion-evolution-decay.test.ts**: Test weight rebalancing (weights sum to 1.0)
|
|
183
|
+
- [x] **Extend retriever tests**: Two entries, same age/importance/frequency, different emotion -- emotional one scores higher after `applyTimeDecay`
|
|
184
|
+
- [x] **Store tests**: Verify `update()` with text change re-detects emotion
|
|
185
|
+
- [x] **Store tests**: Verify `importEntry()` backfills emotion when absent, preserves when present
|
|
186
|
+
- [x] Run `bun test` -- all 1000+ tests must pass
|
|
187
|
+
|
|
188
|
+
### Verification
|
|
189
|
+
1. `bun test` -- full green, baseline maintained
|
|
190
|
+
2. Manual check: store emotional memory, retrieve at simulated t=30d, confirm higher score vs neutral
|
|
191
|
+
3. Check `computeDecayScore` output for emotional vs neutral with same evo params
|
|
192
|
+
|
|
193
|
+
### Risks for Phase 1
|
|
194
|
+
- **Double-parse overhead in applyTimeDecay**: Parse emotion once per result, pass to both functions
|
|
195
|
+
- **Weight rebalancing changes GC behavior**: Test with existing GC tests
|
|
196
|
+
- **Feature flag dependency**: All changes gated by `RECALLNEST_EMOTION_SCORING=true`. Flag off = identical to current
|
|
197
|
+
|
|
198
|
+
---
|
|
199
|
+
|
|
200
|
+
## Phase 2: Memory Ethics Layer
|
|
201
|
+
|
|
202
|
+
### Goal
|
|
203
|
+
Add privacy tiers, build a proper forget engine with cascade deletion, unify lifecycle state inconsistency, expose `forget_memory` MCP tool with audit logging.
|
|
204
|
+
|
|
205
|
+
### Current State
|
|
206
|
+
- `cascade-forget.ts:91` reads legacy `meta.state` -- inconsistent with `evolution.status`
|
|
207
|
+
- `consolidation-engine.ts:71-77` reads BOTH `isActiveMemory()` and `meta.state`
|
|
208
|
+
- `audit-log.ts` exists but lacks "forget" operation type
|
|
209
|
+
- `KGStore.deleteBySource()` exists at `kg-store.ts:314` but never called from forget path
|
|
210
|
+
- No privacy tier field exists
|
|
211
|
+
|
|
212
|
+
### Files Changed
|
|
213
|
+
|
|
214
|
+
| File | Function(s) | Change |
|
|
215
|
+
|------|------------|--------|
|
|
216
|
+
| `src/memory-schema.ts` | New types | `PrivacyTier` type + Zod schema |
|
|
217
|
+
| `src/forget-engine.ts` | **New file** | Full cascade forget with KG cleanup, audit, privacy checks |
|
|
218
|
+
| `src/audit-log.ts` | `AuditOperation` type | Add `"forget"` and `"cascade_forget"` operations |
|
|
219
|
+
| `src/cascade-forget.ts` | `cascadeForget()` | Migrate `meta.state` to `evolution.status` |
|
|
220
|
+
| `src/consolidation-engine.ts` | `isActive()` | Remove legacy `meta.state` double-check |
|
|
221
|
+
| `src/capture-engine.ts` | KG extraction gate | Privacy tier check before KG extraction |
|
|
222
|
+
| `src/mcp-server.ts` | New tool | `forget_memory` MCP tool |
|
|
223
|
+
| `src/store.ts` | `store()`, `StoreMemoryInput` | Accept optional `privacyTier` |
|
|
224
|
+
| Tests | New | forget-engine, privacy-tier, lifecycle-state tests |
|
|
225
|
+
|
|
226
|
+
### Steps
|
|
227
|
+
|
|
228
|
+
#### 2.1 Add PrivacyTier to schema
|
|
229
|
+
- [x] `PrivacyTier` type: `"ephemeral" | "private" | "durable" | "shared"`
|
|
230
|
+
- [x] `PrivacyTierSchema` Zod enum
|
|
231
|
+
- [x] Optional `privacyTier` in `StoreMemoryInputSchema`
|
|
232
|
+
|
|
233
|
+
#### 2.2 Unify lifecycle state
|
|
234
|
+
- [x] `cascade-forget.ts:91` -- replace `meta.state` with `isActiveMemory()`
|
|
235
|
+
- [x] `consolidation-engine.ts:70-77` -- simplify to only `isActiveMemory()`
|
|
236
|
+
- [x] Grep for any other `meta.state` reads, migrate them all
|
|
237
|
+
|
|
238
|
+
#### 2.3 Extend audit operations
|
|
239
|
+
- [x] Add `"forget"` and `"cascade_forget"` to `AuditOperation` union
|
|
240
|
+
|
|
241
|
+
#### 2.4 Build forget engine (NEW: `src/forget-engine.ts`)
|
|
242
|
+
- [x] `forgetMemory()`: fetch → privacy check → evidence export → KG delete → pin archive → cascade → primary delete → audit
|
|
243
|
+
- [x] `forgetByScope()` for bulk scope-level forget
|
|
244
|
+
- [x] Confirmation gate for `"durable"` entries
|
|
245
|
+
|
|
246
|
+
#### 2.5 Privacy tier gate in capture
|
|
247
|
+
- [x] Before KG extraction, skip if `privacyTier === "ephemeral" | "private"`
|
|
248
|
+
|
|
249
|
+
#### 2.6 Register `forget_memory` MCP tool
|
|
250
|
+
- [x] Schema: `{ memoryId: string, confirm: boolean, reason?: string }`
|
|
251
|
+
- [x] Returns deletion summary + evidence paths
|
|
252
|
+
|
|
253
|
+
#### 2.7 Tests
|
|
254
|
+
- [x] forget-engine: KG cleanup, cascade demotion, audit trail
|
|
255
|
+
- [x] Privacy tier blocks without confirm
|
|
256
|
+
- [x] Evidence export for high-importance memories
|
|
257
|
+
- [x] Consolidation/cascade-forget regression with new `isActiveMemory()`
|
|
258
|
+
- [x] `bun test` full green
|
|
259
|
+
|
|
260
|
+
### Verification
|
|
261
|
+
1. Store memory → extract KG → forget → verify KG triples gone
|
|
262
|
+
2. Audit log shows complete forget trail
|
|
263
|
+
3. `"ephemeral"` memory produces no KG triples
|
|
264
|
+
|
|
265
|
+
---
|
|
266
|
+
|
|
267
|
+
## Phase 3: Autobiographical Narrative Architecture
|
|
268
|
+
|
|
269
|
+
### Goal
|
|
270
|
+
Add orthogonal narrative metadata layer (life-period / general-event / specific-event) on top of existing 6 categories. Enable temporal grouping and narrative retrieval without disrupting category logic.
|
|
271
|
+
|
|
272
|
+
### Current State
|
|
273
|
+
- 6 categories hardcoded across `memory-schema.ts`, `memory-boundaries.ts`, `retriever.ts`, `context-composer.ts` -- **do not modify**
|
|
274
|
+
- `event-segmenter.ts:105` has `segmentEvents()`, `temporal-parser.ts:15` has date parsing
|
|
275
|
+
|
|
276
|
+
### Files Changed
|
|
277
|
+
|
|
278
|
+
| File | Function(s) | Change |
|
|
279
|
+
|------|------------|--------|
|
|
280
|
+
| `src/narrative-schema.ts` | **New file** | Narrative metadata types + Zod schemas |
|
|
281
|
+
| `src/narrative-tagger.ts` | **New file** | Rule-based narrative period/event assignment |
|
|
282
|
+
| `src/capture-engine.ts` | `buildStructuredMetadata()` | Inject narrative metadata |
|
|
283
|
+
| `src/ingest.ts` | `buildIngestedEntry()` | Inject narrative metadata |
|
|
284
|
+
| `src/retriever.ts` | New method | `expandNarrativeSiblings()` |
|
|
285
|
+
| `src/context-composer.ts` | Result rendering | Group by narrative period |
|
|
286
|
+
| `src/memory-output.ts` | Rendering | Narrative period labels |
|
|
287
|
+
| `src/graph-export.ts` | Graph edges | Narrative relationship edges |
|
|
288
|
+
|
|
289
|
+
### Steps
|
|
290
|
+
- [x] 3.1 Define `NarrativeMetadata` interface: `lifePeriodId/Label`, `generalEventId/Label`, `specificEventId/Label`, `startAt`, `endAt`, `sequence`
|
|
291
|
+
- [x] 3.2 Build rule-based narrative tagger (scope prefix, temporal clustering, keyword signals)
|
|
292
|
+
- [x] 3.3 Inject narrative at write points (`capture-engine.ts:140`, `ingest.ts:662`)
|
|
293
|
+
- [x] 3.4 `expandNarrativeSiblings()` in retriever: pull entries sharing same `generalEventId`
|
|
294
|
+
- [x] 3.5 Rendering updates: group by `lifePeriodLabel`, narrative edges in graph export
|
|
295
|
+
- [x] 3.6 Tests + `bun test` full green
|
|
296
|
+
|
|
297
|
+
---
|
|
298
|
+
|
|
299
|
+
## Phase 4: Constructive Retrieval
|
|
300
|
+
|
|
301
|
+
### Goal
|
|
302
|
+
Replace "top-k then summarize" with multi-source candidate expansion + grounded reconstruction. Return reconstruction as first-class object.
|
|
303
|
+
|
|
304
|
+
### Current State
|
|
305
|
+
- `context-reconstructor.ts:91` exists, `retriever.ts:706` `runReconstruction()` exists
|
|
306
|
+
- `mcp-server.ts:888` supports `reconstruct=true`
|
|
307
|
+
- But: only top-k summarize, `metadata._reconstruction` is hacky, `computeCoverage()` is lexical
|
|
308
|
+
|
|
309
|
+
### Steps
|
|
310
|
+
- [x] 4.1 Define `ReconstructionOutput` with sources, confidence, contradictions
|
|
311
|
+
- [x] 4.2 Add candidate expansion: KG neighbors + evolution chains + cluster members + narrative siblings
|
|
312
|
+
- [x] 4.3 Replace lexical coverage with source-map grounding + contradiction detection
|
|
313
|
+
- [x] 4.4 Return reconstruction as first-class object (remove `metadata._reconstruction` hack)
|
|
314
|
+
- [x] 4.5 Update MCP rendering for new output shape
|
|
315
|
+
- [x] 4.6 Pass checkpoint context (openLoops, nextActions) into reconstruction prompt
|
|
316
|
+
- [x] 4.7 Tests + `bun test` full green
|
|
317
|
+
|
|
318
|
+
---
|
|
319
|
+
|
|
320
|
+
## Phase 5: Predictive Prospective Memory
|
|
321
|
+
|
|
322
|
+
### Goal
|
|
323
|
+
Evolve `prospective-memory.ts` from explicit reminders to include pattern-predicted suggestions. Surface behavioral insights as ephemeral predicted reminders.
|
|
324
|
+
|
|
325
|
+
### Current State
|
|
326
|
+
- `prospective-memory.ts` -- `setReminder()`, `checkTriggers()`, `fireReminder()` explicit only
|
|
327
|
+
- Behavioral signals: checkpoint openLoops, workflow observations, frequency tracker, access tracker, topic tags
|
|
328
|
+
|
|
329
|
+
### Steps
|
|
330
|
+
- [x] 5.1 Extend `ProspectiveMetadata` with `source`, `confidence`, `evidence`, `lastSuggestedAt`, `acceptedAt`
|
|
331
|
+
- [x] 5.2 Build `prediction-engine.ts`: collect signals, score predictions, threshold at confidence >= 0.6
|
|
332
|
+
- [x] 5.3 `suggestPredictedReminders()`: deduplicate vs existing, store as ephemeral, auto-expire 7d
|
|
333
|
+
- [x] 5.4 Surface in `search_memory` as separate "Suggested Reminders" section
|
|
334
|
+
- [x] 5.5 Acceptance/promotion flow: repeated/accepted → promote to explicit; ignored → demote
|
|
335
|
+
- [x] 5.6 Tests + `bun test` full green
|
|
336
|
+
|
|
337
|
+
---
|
|
338
|
+
|
|
339
|
+
## Global Risks & Mitigations
|
|
340
|
+
|
|
341
|
+
| Risk | Impact | Mitigation |
|
|
342
|
+
|------|--------|-----------|
|
|
343
|
+
| Feature flag proliferation | Complexity | Phase 1-2 reuse `RECALLNEST_EMOTION_SCORING`. Phase 3-5 add `RECALLNEST_NARRATIVE_MODE` and `RECALLNEST_PREDICTIVE_MEMORY` |
|
|
344
|
+
| Metadata JSON bloat | Storage + parse cost | Each phase adds ~100 bytes/entry. Total metadata stays under 2KB |
|
|
345
|
+
| Scoring formula instability | Retrieval quality regression | Every weight change gated by feature flag and tested against eval cases |
|
|
346
|
+
| LLM cost creep (Phase 4-5) | Token spend | Phase 1-3 zero LLM. Phase 4 reuses existing reconstruction budget. Phase 5 zero LLM (heuristic) |
|
|
347
|
+
|
|
348
|
+
---
|
|
349
|
+
|
|
350
|
+
## Success Criteria
|
|
351
|
+
|
|
352
|
+
- [x] Phase 1: Emotional memories decay 20-30% slower than neutral memories of same age
|
|
353
|
+
- [x] Phase 1: `computeDecayScore` with emotion gives higher scores for high-salience memories
|
|
354
|
+
- [x] Phase 1: All existing tests pass, emotion-decay tests extended
|
|
355
|
+
- [x] Phase 2: `forget_memory` MCP tool deletes entry + KG triples + cascade demotes + audit logs
|
|
356
|
+
- [x] Phase 2: No more `meta.state` reads anywhere in codebase (all `evolution.status`)
|
|
357
|
+
- [x] Phase 3: Ingested sessions have narrative metadata with period/event IDs
|
|
358
|
+
- [x] Phase 3: Search returns narrative siblings alongside direct matches
|
|
359
|
+
- [x] Phase 4: Reconstruction uses expanded candidate set (KG + evolution + cluster)
|
|
360
|
+
- [x] Phase 4: Reconstruction is first-class return object, not metadata hack
|
|
361
|
+
- [x] Phase 5: Predicted reminders surface from behavioral signals
|
|
362
|
+
- [x] Phase 5: Predictions auto-expire and respect acceptance/rejection
|
|
363
|
+
- [x] All phases: `bun test` passes with baseline maintained or increased
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
# RecallNest 产品化升级实施计划
|
|
2
|
+
|
|
3
|
+
## 目标
|
|
4
|
+
|
|
5
|
+
把 RecallNest 从"引擎很强但用户无感"变成"用户能看到记忆在成长"。
|
|
6
|
+
|
|
7
|
+
## 四个升级(按优先级)
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
### Upgrade 1: SKILL.md — 记忆伙伴使用协议
|
|
12
|
+
|
|
13
|
+
**做什么**:在 repo 根目录创建 `SKILL.md`,教 LLM 怎么当好记忆伙伴(不只是 API 文档)。
|
|
14
|
+
|
|
15
|
+
**内容结构**:
|
|
16
|
+
- Session Protocol(resume → work → checkpoint)
|
|
17
|
+
- Onboarding Flow(首次检测:memory_stats 为 0 时引导)
|
|
18
|
+
- Memory Feedback(store 后回显,search 后展示匹配)
|
|
19
|
+
- Tool Decision Tree(什么时候 store vs checkpoint vs pin)
|
|
20
|
+
- Weekly Health Check(data_checkup + dream + lint)
|
|
21
|
+
|
|
22
|
+
**改动**:
|
|
23
|
+
- 新建 `SKILL.md`(~250 行 markdown)
|
|
24
|
+
- 零代码改动
|
|
25
|
+
|
|
26
|
+
**风险**:低。纯文档。
|
|
27
|
+
|
|
28
|
+
---
|
|
29
|
+
|
|
30
|
+
### Upgrade 2: Memory Lint — 记忆体检
|
|
31
|
+
|
|
32
|
+
**做什么**:新增 MCP tool + CLI 命令,对记忆做质量自检。
|
|
33
|
+
|
|
34
|
+
**检查项**:
|
|
35
|
+
| 检查 | 复用什么 | 怎么做 |
|
|
36
|
+
|------|---------|--------|
|
|
37
|
+
| 矛盾检测 | `detectHeuristicContradiction`(consolidation-engine.ts) | 同 scope 同 category 内两两比较 |
|
|
38
|
+
| 重复检测 | `cosineSimilarity`(multi-vector.ts) | 向量相似度 > 0.92 的配对 |
|
|
39
|
+
| 陈旧检测 | `parseEvolution` 的 accessCount/lastAccessedAt | 90 天未被召回 + accessCount ≤ 1 |
|
|
40
|
+
| 孤儿检测 | consolidatedInto 指向的 ID | 不存在的引用 |
|
|
41
|
+
| 健康分 | 综合以上 | 100 - (矛盾×10 + 重复×5 + 陈旧×2 + 孤儿×3) |
|
|
42
|
+
|
|
43
|
+
**改动**:
|
|
44
|
+
- 新建 `src/memory-lint.ts`(~180 行)
|
|
45
|
+
- 新建 `src/__tests__/memory-lint.test.ts`(~150 行)
|
|
46
|
+
- 改 `src/mcp-server.ts`:注册 `memory_lint` tool(~25 行)
|
|
47
|
+
- 改 `src/cli.ts`:增加 `lint` 命令(~30 行)
|
|
48
|
+
- 改 `src/api-server.ts`:增加 `GET /v1/lint`(~20 行)
|
|
49
|
+
- 改 `src/consolidation-engine.ts`:export `detectHeuristicContradiction`(1 行)
|
|
50
|
+
- 改 `package.json`:增加 `lint:memory` 脚本
|
|
51
|
+
|
|
52
|
+
**性能守卫**:矛盾/重复检测是 O(n²),每个 scope/category 组限 200 条,按 importance 降序取。
|
|
53
|
+
|
|
54
|
+
**预计**:~405 LOC
|
|
55
|
+
|
|
56
|
+
**风险**:中。矛盾检测基于启发式,会有误报,报告中标注"启发式建议"。
|
|
57
|
+
|
|
58
|
+
---
|
|
59
|
+
|
|
60
|
+
### Upgrade 3: Dashboard 仪表盘首页
|
|
61
|
+
|
|
62
|
+
**做什么**:现有 UI(port 4317)只有搜索,加一个 Dashboard 首页 tab。
|
|
63
|
+
|
|
64
|
+
**展示内容**:
|
|
65
|
+
- 总记忆数 + 分类分布(bar chart,纯 CSS 实现,不引入图表库)
|
|
66
|
+
- 本周/本月新增趋势
|
|
67
|
+
- 健康分(来自 Lint)
|
|
68
|
+
- 最近召回 Top N
|
|
69
|
+
- 沉睡记忆列表(90天未召回)
|
|
70
|
+
|
|
71
|
+
**改动**:
|
|
72
|
+
- 改 `src/ui-server.ts`:新增 4 个 API endpoint(~80 行)
|
|
73
|
+
- `GET /api/dashboard-stats`
|
|
74
|
+
- `GET /api/recent-recalls`
|
|
75
|
+
- `GET /api/lint-summary`
|
|
76
|
+
- `GET /api/stale-memories`
|
|
77
|
+
- 改 `assets/ui/index.html`:增加 Dashboard tab(~60 行)
|
|
78
|
+
- 改 `assets/ui/app.js`:Dashboard 渲染逻辑(~120 行)
|
|
79
|
+
- 改 `assets/ui/styles.css`:Dashboard 样式(~80 行)
|
|
80
|
+
|
|
81
|
+
**依赖**:Upgrade 2(Lint 的健康分)。可以先不接 Lint,用 placeholder。
|
|
82
|
+
|
|
83
|
+
**预计**:~340 LOC
|
|
84
|
+
|
|
85
|
+
**风险**:中。Growth trend 需要扫全量 entries 按时间分桶,大库可能慢。缓存 60s 缓解。
|
|
86
|
+
|
|
87
|
+
---
|
|
88
|
+
|
|
89
|
+
### Upgrade 4: HTML 知识图谱
|
|
90
|
+
|
|
91
|
+
**做什么**:把记忆导出为一个交互式 HTML 文件,浏览器打开即可看到力导向图。
|
|
92
|
+
|
|
93
|
+
**节点/边设计**:
|
|
94
|
+
- 节点 = 每条记忆,颜色按 category(profile=金, preferences=蓝, entities=绿, events=灰, cases=红, patterns=紫)
|
|
95
|
+
- 边 = scope 关系 + consolidation 链 + supersede 链 + cluster 关系
|
|
96
|
+
- 支持缩放、拖拽、点击查看详情
|
|
97
|
+
|
|
98
|
+
**改动**:
|
|
99
|
+
- 新建 `src/graph-export.ts`(~250 行)
|
|
100
|
+
- `buildMemoryGraph()`:从 store 构建节点/边
|
|
101
|
+
- `renderGraphHTML()`:生成自包含 HTML(D3.js via CDN,或 `--offline` 内嵌)
|
|
102
|
+
- `exportMemoryGraph()`:写文件到 `data/exports/`
|
|
103
|
+
- 新建 `src/__tests__/graph-export.test.ts`(~100 行)
|
|
104
|
+
- 改 `src/mcp-server.ts`:注册 `export_graph` tool(~25 行)
|
|
105
|
+
- 改 `src/cli.ts`:增加 `graph` 命令(~25 行)
|
|
106
|
+
- 改 `src/ui-server.ts`:增加 `/api/graph` endpoint(~20 行)
|
|
107
|
+
|
|
108
|
+
**默认上限**:200 节点(按 importance 降序),避免图谱变成乱麻。
|
|
109
|
+
|
|
110
|
+
**预计**:~420 LOC
|
|
111
|
+
|
|
112
|
+
**风险**:中高。>100 节点时力导向布局可能卡顿。限制节点数+scope 过滤。
|
|
113
|
+
|
|
114
|
+
---
|
|
115
|
+
|
|
116
|
+
## 实施顺序
|
|
117
|
+
|
|
118
|
+
```
|
|
119
|
+
Phase 1(可独立合并)
|
|
120
|
+
├── 1.1 SKILL.md(无代码依赖)
|
|
121
|
+
└── 1.2 memory-lint.ts + tests
|
|
122
|
+
|
|
123
|
+
Phase 2(依赖 1.2)
|
|
124
|
+
├── 2.1 Lint MCP tool + CLI
|
|
125
|
+
└── 2.2 Lint API endpoint
|
|
126
|
+
|
|
127
|
+
Phase 3(依赖 Phase 2)
|
|
128
|
+
└── 3.1 Dashboard 首页
|
|
129
|
+
|
|
130
|
+
Phase 4(独立,可与 1-3 并行)
|
|
131
|
+
└── 4.1 HTML 知识图谱
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
**可并行**:SKILL.md 和 Graph Export 不依赖其他升级。
|
|
135
|
+
|
|
136
|
+
## 总改动量
|
|
137
|
+
|
|
138
|
+
| 升级 | 新文件 | 改动文件 | 新增 LOC |
|
|
139
|
+
|------|--------|---------|---------|
|
|
140
|
+
| SKILL.md | 1 | 0 | ~250 (markdown) |
|
|
141
|
+
| Memory Lint | 2 | 4 | ~405 |
|
|
142
|
+
| Dashboard | 0 | 4 | ~340 |
|
|
143
|
+
| Knowledge Graph | 2 | 3 | ~420 |
|
|
144
|
+
| **总计** | **5** | **~8** | **~1,415** |
|
|
145
|
+
|
|
146
|
+
## 成功标准
|
|
147
|
+
|
|
148
|
+
- [ ] SKILL.md 覆盖 5 个核心场景
|
|
149
|
+
- [ ] `memory_lint` MCP tool 返回矛盾/重复/陈旧/孤儿数量 + 0-100 健康分
|
|
150
|
+
- [ ] `bun run src/cli.ts lint` CLI 输出相同报告
|
|
151
|
+
- [ ] Dashboard tab 展示总记忆数、分类分布、健康分、沉睡记忆
|
|
152
|
+
- [ ] `bun run src/cli.ts graph` 生成有效 HTML,浏览器打开有交互图谱
|
|
153
|
+
- [ ] 现有 1168 个测试全部通过
|
|
154
|
+
- [ ] 新增测试 > 20 个
|
|
155
|
+
- [ ] 不引入新 npm 依赖
|
package/plan.md
ADDED
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
# RecallNest 架构迭代 Plan
|
|
2
|
+
|
|
3
|
+
**目标**:提升 RecallNest 架构能力(不刷分,关注真实场景)
|
|
4
|
+
**推送**:全部推河马仓(origin),实用的推公开仓(public)
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## 已完成
|
|
9
|
+
|
|
10
|
+
### Step 1: 隐式偏好检测 (preference-slots.ts)
|
|
11
|
+
- `ImplicitUsagePreferenceSlot` + 8 种中英文模式 | `6db35d08`
|
|
12
|
+
|
|
13
|
+
### Step 2: Source Diversity (retriever.ts)
|
|
14
|
+
- `sourceDiversity` config, round-robin 跨 scope | `6db35d08`
|
|
15
|
+
|
|
16
|
+
### Step 3: Adaptive Candidate Pool (retriever.ts)
|
|
17
|
+
- `adaptivePoolMultiplier` config, 聚合 query 自动扩池 | `6db35d08`
|
|
18
|
+
|
|
19
|
+
### Step 4: 隐式偏好双写 (capture-engine.ts)
|
|
20
|
+
- 非 preference 记忆自动派生 preference 副本 | `778cd906`
|
|
21
|
+
|
|
22
|
+
### Step 5: Multi-hop 两轮检索 (retriever.ts)
|
|
23
|
+
- 实体驱动的两轮检索 + 并行 follow-up | `86a4f0a3`
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
## 待做:架构改进(借鉴 memL + 自身短板)
|
|
28
|
+
|
|
29
|
+
### Step 7: Recall Governor — auto-recall 治理层 [高优先级]
|
|
30
|
+
|
|
31
|
+
**问题**:当前 auto-recall 路径只有 `shouldSkipRetrieval()` (gating) 和 `noise-filter` (事后过滤)。缺少中间治理层:
|
|
32
|
+
- 无字符预算控制,注入过多记忆浪费 token
|
|
33
|
+
- 无会话去重,同一轮对话里同一条记忆可能被多次注入
|
|
34
|
+
- 无状态过滤二次确认(retriever 有 evolution filter 但 auto-recall 路径没有兜底)
|
|
35
|
+
|
|
36
|
+
**方案**:新增 `recall-governor.ts`,在 auto-recall.ts 的 retrieve 后、返回前插入 6 层治理:
|
|
37
|
+
1. Gating — 已有 `shouldSkipRetrieval()`,保持
|
|
38
|
+
2. Query 截断 — 超长 query 截断到 1000 chars(省 embedding 成本)
|
|
39
|
+
3. 检索 — 已有 HybridRetriever,保持
|
|
40
|
+
4. 状态过滤 — 排除 archived/superseded, tier=peripheral
|
|
41
|
+
5. 预算控制 — 总字符预算 + 条目数上限(可配置)
|
|
42
|
+
6. 会话去重 — 维护本轮已注入 ID set,不重复注入
|
|
43
|
+
|
|
44
|
+
**文件**:`src/recall-governor.ts`(新增), `src/auto-recall.ts`(接入)
|
|
45
|
+
**工作量**:约 120 行 + 测试
|
|
46
|
+
|
|
47
|
+
---
|
|
48
|
+
|
|
49
|
+
### Step 8: Admission Control — 写入准入控制 [高优先级]
|
|
50
|
+
|
|
51
|
+
**问题**:当前记忆写入只有 noise-filter(检索时才过滤)和 write-verifier(写后验证),没有写前门控。低质量记忆进库再过滤不如一开始就拦。
|
|
52
|
+
|
|
53
|
+
**方案**:新增 `admission-control.ts`,在 capture-engine.ts 的 persistMemory 入口加准入检查:
|
|
54
|
+
- 最短文本长度(< 10 chars 拒绝)
|
|
55
|
+
- noise-filter 前置(写入前就过滤)
|
|
56
|
+
- importance 下限(< 0.2 拒绝或标记 pending_review)
|
|
57
|
+
- 重复检测(向量相似度 > 0.95 近似重复直接跳过)
|
|
58
|
+
- 每 scope 写入频率限制(防 flood)
|
|
59
|
+
|
|
60
|
+
**文件**:`src/admission-control.ts`(新增), `src/capture-engine.ts`(接入)
|
|
61
|
+
**工作量**:约 80 行 + 测试
|
|
62
|
+
|
|
63
|
+
---
|
|
64
|
+
|
|
65
|
+
### Step 9: LLM 降级策略 — dream-pipeline + capture 容错 [中优先级]
|
|
66
|
+
|
|
67
|
+
**问题**:dream-pipeline 和 LLM importance assessment 依赖外部 LLM。LLM 挂了:
|
|
68
|
+
- dream-pipeline 直接失败
|
|
69
|
+
- importance 静默跳过(fallback 默认 0.7,还行)
|
|
70
|
+
- capture-heuristic 是纯 regex 备选但不在同一链路
|
|
71
|
+
|
|
72
|
+
**方案**:借鉴 memL 三层降级:
|
|
73
|
+
- Level 1: 正常 LLM 调用
|
|
74
|
+
- Level 2: 降级 prompt(更短,更高成功率)
|
|
75
|
+
- Level 3: 确定性 fallback(零 LLM)
|
|
76
|
+
- dream consolidation: 跳过本轮下次再试
|
|
77
|
+
- importance: heuristic 规则(文本长度 + category 权重)
|
|
78
|
+
- capture: capture-heuristic.ts 的 regex 提取
|
|
79
|
+
|
|
80
|
+
**文件**:`src/llm-client.ts`(加 degradation wrapper)
|
|
81
|
+
**工作量**:约 60 行 + 测试
|
|
82
|
+
|
|
83
|
+
---
|
|
84
|
+
|
|
85
|
+
### Step 10: Metadata 显式字段 — 去 JSON bag [中优先级,大工作量]
|
|
86
|
+
|
|
87
|
+
**问题**:85 处 `JSON.parse(metadata)`。metadata 是 JSON string,塞了 evolution/boundary/anchor/preferenceSlot/pii/tags 等所有东西。每次读都要 parse,LanceDB filter 不能直接用内部字段。
|
|
88
|
+
|
|
89
|
+
**方案**:高频字段提升为 MemoryEntry 顶级字段:
|
|
90
|
+
```
|
|
91
|
+
新增:anchor, evolution_status, confidence, access_count,
|
|
92
|
+
last_accessed_at, supersedes, superseded_by, tier
|
|
93
|
+
保留 metadata:低频扩展字段仍用 JSON string
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
**风险**:LanceDB schema 变更需重建表,需 migration 脚本。
|
|
97
|
+
**工作量**:约 300 行 + migration + 大量测试更新
|
|
98
|
+
**建议**:单独一个完整 session,不混其他改动
|
|
99
|
+
|
|
100
|
+
---
|
|
101
|
+
|
|
102
|
+
### Step 11: 两段式捕获 — message buffer + batch persist [低优先级]
|
|
103
|
+
|
|
104
|
+
**问题**:capture-engine 单条同步写入。高频对话产生碎片记忆。
|
|
105
|
+
|
|
106
|
+
**方案**:借鉴 memL 两段式:
|
|
107
|
+
- Stage 1: message_received -> 缓存到内存 buffer
|
|
108
|
+
- Stage 2: agent_end(或 buffer 满/超时)-> 批量合并后写入
|
|
109
|
+
|
|
110
|
+
**价值**:减少碎片,LLM 看到更完整上下文提高提取质量
|
|
111
|
+
**工作量**:约 150 行 + event bus 集成
|
|
112
|
+
**依赖**:host adapter 需提供 message_received / agent_end 事件
|
|
113
|
+
|
|
114
|
+
---
|
|
115
|
+
|
|
116
|
+
## 停车场(不做)
|
|
117
|
+
|
|
118
|
+
| 方案 | 原因 |
|
|
119
|
+
|------|------|
|
|
120
|
+
| Extraction prompt 加偏好示例 | 针对题型优化 = 刷分 |
|
|
121
|
+
| Reader 升级 | 不是 RecallNest 自身能力 |
|
|
122
|
+
| L1 Context Engine | memL 的差异化,RecallNest 定位是 L2 记忆引擎 |
|
|
123
|
+
| Embedding 模型更换 | 当前够用 |
|
|
124
|
+
|
|
125
|
+
---
|
|
126
|
+
|
|
127
|
+
## 优先级排序
|
|
128
|
+
|
|
129
|
+
```
|
|
130
|
+
高优先级(下一个窗口做)
|
|
131
|
+
Step 7: Recall Governor ~120 行 <- 生产环境最需要
|
|
132
|
+
Step 8: Admission Control ~80 行 <- 防垃圾记忆入库
|
|
133
|
+
|
|
134
|
+
中优先级(之后做)
|
|
135
|
+
Step 9: LLM 降级策略 ~60 行 <- 生产容错
|
|
136
|
+
Step 10: Metadata 显式字段 ~300 行 <- 大重构,单独 session
|
|
137
|
+
|
|
138
|
+
低优先级(有空再做)
|
|
139
|
+
Step 11: 两段式捕获 ~150 行 <- 需 host adapter 配合
|
|
140
|
+
```
|