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,398 @@
|
|
|
1
|
+
# Constructive Retrieval + Emotional Valence — Design Spec
|
|
2
|
+
|
|
3
|
+
> Date: 2026-04-11
|
|
4
|
+
> Status: Approved
|
|
5
|
+
> Scope: RecallNest v1.5 upgrade
|
|
6
|
+
> Philosophy basis: Simulation Theory (Michaelian) + Affective Memory (cognitive science)
|
|
7
|
+
> Risk strategy: Triple fallback — every new path degrades gracefully to current behavior
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## 1. Problem Statement
|
|
12
|
+
|
|
13
|
+
RecallNest's retrieval pipeline (21 stages) returns **raw stored text**. This is a "causal theory" model — faithfully reproducing what was stored. But human memory doesn't work this way: we reconstruct memories in context, adapting them to our current needs.
|
|
14
|
+
|
|
15
|
+
Additionally, the decay engine lacks an emotional dimension. Cognitive science shows emotionally charged memories decay slower and are retrieved preferentially in matching emotional contexts. RecallNest currently treats all memories as emotionally neutral.
|
|
16
|
+
|
|
17
|
+
## 2. Goals
|
|
18
|
+
|
|
19
|
+
1. **Constructive Retrieval**: When context benefits from it, synthesize a coherent narrative from top-N retrieved memories, adapted to the current query context
|
|
20
|
+
2. **Emotional Valence**: Tag memories with emotional metadata at storage time, use it to modulate decay rates and retrieval scoring
|
|
21
|
+
3. **Zero regression**: All new behavior behind feature flags, all paths fallback to current behavior
|
|
22
|
+
|
|
23
|
+
## 3. Non-Goals
|
|
24
|
+
|
|
25
|
+
- Replacing the existing retrieval pipeline (it stays as-is)
|
|
26
|
+
- Complex emotion models (no 6-axis emotion wheels; just valence + arousal)
|
|
27
|
+
- Multi-agent shared memory (future phase)
|
|
28
|
+
- Autobiographical narrative architecture (future phase)
|
|
29
|
+
|
|
30
|
+
---
|
|
31
|
+
|
|
32
|
+
## 4. Constructive Retrieval
|
|
33
|
+
|
|
34
|
+
### 4.1 Architecture
|
|
35
|
+
|
|
36
|
+
New component: `context-reconstructor.ts` (~200-300 LOC)
|
|
37
|
+
|
|
38
|
+
Position in pipeline:
|
|
39
|
+
```
|
|
40
|
+
Existing 21-stage pipeline → top-N RetrievalResult[]
|
|
41
|
+
↓
|
|
42
|
+
Reconstruction Gate
|
|
43
|
+
(should reconstruct?)
|
|
44
|
+
↓ yes ↓ no
|
|
45
|
+
Context Reconstructor Return raw
|
|
46
|
+
↓
|
|
47
|
+
Grounding Validator
|
|
48
|
+
↓
|
|
49
|
+
Return { reconstructed, sources, confidence, raw }
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
### 4.2 Reconstruction Gate
|
|
53
|
+
|
|
54
|
+
Conditions for reconstruction (ALL must be true):
|
|
55
|
+
- Feature flag `RECALLNEST_CONSTRUCTIVE_RETRIEVAL=true`
|
|
56
|
+
- Caller opt-in: `reconstruct: true` in retrieval context
|
|
57
|
+
- Retrieved results count ≥ 3 (too few = not enough material)
|
|
58
|
+
- LLM client available and responding
|
|
59
|
+
|
|
60
|
+
If any condition fails → return raw results immediately. No error, no log noise.
|
|
61
|
+
|
|
62
|
+
### 4.3 Context Reconstructor
|
|
63
|
+
|
|
64
|
+
**Input:**
|
|
65
|
+
```ts
|
|
66
|
+
interface ReconstructionInput {
|
|
67
|
+
query: string; // current user query / resume context
|
|
68
|
+
results: RetrievalResult[]; // top-N from pipeline (max 10)
|
|
69
|
+
mode: "resume" | "search"; // affects prompt style
|
|
70
|
+
maxTokens?: number; // output budget (default 500)
|
|
71
|
+
}
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
**LLM Prompt Strategy:**
|
|
75
|
+
```
|
|
76
|
+
System: You are a memory reconstruction engine. Given a set of stored memories
|
|
77
|
+
and a current context, synthesize a coherent, contextually relevant summary.
|
|
78
|
+
|
|
79
|
+
Rules:
|
|
80
|
+
1. Every factual claim MUST cite its source as [src:MEMORY_ID]
|
|
81
|
+
2. Do NOT invent facts not present in any source memory
|
|
82
|
+
3. If memories contradict each other, present both views with [conflict] tag
|
|
83
|
+
4. Prioritize information most relevant to the current query context
|
|
84
|
+
5. Keep output concise — this is context, not an essay
|
|
85
|
+
|
|
86
|
+
Current context: {query}
|
|
87
|
+
|
|
88
|
+
Source memories:
|
|
89
|
+
{for each result: [ID: {id}] {text} (importance: {importance}, stored: {date})}
|
|
90
|
+
|
|
91
|
+
Synthesize a contextually relevant reconstruction:
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
**Output:**
|
|
95
|
+
```ts
|
|
96
|
+
interface ReconstructionOutput {
|
|
97
|
+
reconstructed: string; // synthesized text with [src:ID] citations
|
|
98
|
+
sources: string[]; // list of cited memory IDs
|
|
99
|
+
confidence: number; // [0, 1] grounding confidence
|
|
100
|
+
fallbackReason?: string; // if degraded, why
|
|
101
|
+
raw: RetrievalResult[]; // always included
|
|
102
|
+
}
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
### 4.4 Grounding Validator
|
|
106
|
+
|
|
107
|
+
Three-layer validation, executed sequentially:
|
|
108
|
+
|
|
109
|
+
**Layer 1: ID Verification**
|
|
110
|
+
```ts
|
|
111
|
+
for (const citedId of extractCitedIds(reconstructed)) {
|
|
112
|
+
if (!topNResults.some(r => r.id === citedId)) {
|
|
113
|
+
reconstructed = removeSentencesWithId(reconstructed, citedId);
|
|
114
|
+
confidence -= 0.2;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
```
|
|
118
|
+
- Extract all `[src:MEMORY_ID]` references from LLM output
|
|
119
|
+
- Verify each ID exists in the top-N result set
|
|
120
|
+
- Remove sentences citing non-existent IDs (hallucination)
|
|
121
|
+
- Penalize confidence per phantom citation
|
|
122
|
+
|
|
123
|
+
**Layer 2: Coverage Check**
|
|
124
|
+
```ts
|
|
125
|
+
const coverage = computeSemanticOverlap(reconstructed, topNResults);
|
|
126
|
+
if (coverage < 0.6) {
|
|
127
|
+
return { reconstructed: null, fallbackReason: "low_grounding", raw };
|
|
128
|
+
}
|
|
129
|
+
```
|
|
130
|
+
- Compute semantic overlap between reconstructed text and source memories
|
|
131
|
+
- Method: chunk reconstructed text into sentences, embed each, find max cosine similarity to any source memory
|
|
132
|
+
- Coverage = percentage of sentences with similarity > 0.7
|
|
133
|
+
- Below 60% → full degradation to raw results
|
|
134
|
+
|
|
135
|
+
**Layer 3: Timeout Guard**
|
|
136
|
+
```ts
|
|
137
|
+
const result = await Promise.race([
|
|
138
|
+
reconstruct(input),
|
|
139
|
+
timeout(3000).then(() => ({ fallbackReason: "timeout" }))
|
|
140
|
+
]);
|
|
141
|
+
```
|
|
142
|
+
- 3-second hard timeout on entire reconstruction pipeline
|
|
143
|
+
- Timeout → return raw results
|
|
144
|
+
|
|
145
|
+
### 4.5 Integration Points
|
|
146
|
+
|
|
147
|
+
**resume_context (context-composer.ts):**
|
|
148
|
+
- After assembling stable context + patterns + cases
|
|
149
|
+
- Call reconstructor with mode="resume", query=task description from checkpoint
|
|
150
|
+
- If reconstruction succeeds, use it as the primary context narrative
|
|
151
|
+
- Always keep raw results in response for transparency
|
|
152
|
+
- Default: reconstruction ON when feature flag is ON
|
|
153
|
+
|
|
154
|
+
**search_memory (mcp-server.ts):**
|
|
155
|
+
- New optional parameter: `reconstruct?: boolean` (default false)
|
|
156
|
+
- When true, pass through to retriever with reconstruct flag
|
|
157
|
+
- Return both reconstructed and raw in tool response
|
|
158
|
+
|
|
159
|
+
**brief_memory, memory_lint, list_pins, etc.:**
|
|
160
|
+
- Never reconstruct. These tools need raw data.
|
|
161
|
+
|
|
162
|
+
### 4.6 Observability
|
|
163
|
+
|
|
164
|
+
- Trace stage: `reconstruction` added to TraceCollector
|
|
165
|
+
- Logged fields: `{ attempted: boolean, succeeded: boolean, confidence: number, fallbackReason?: string, latencyMs: number, sourceCount: number }`
|
|
166
|
+
- No memory content logged (privacy)
|
|
167
|
+
|
|
168
|
+
---
|
|
169
|
+
|
|
170
|
+
## 5. Emotional Valence
|
|
171
|
+
|
|
172
|
+
### 5.1 Schema Extension
|
|
173
|
+
|
|
174
|
+
Add optional `emotion` field to memory metadata:
|
|
175
|
+
|
|
176
|
+
```ts
|
|
177
|
+
interface EmotionMetadata {
|
|
178
|
+
valence: number; // [-1, 1] negative ← → positive
|
|
179
|
+
arousal: number; // [0, 1] calm ← → excited
|
|
180
|
+
label?: string; // human-readable: "frustration" | "excitement" | "neutral" | etc.
|
|
181
|
+
}
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
Stored in `metadata` JSON string (no schema migration needed):
|
|
185
|
+
```json
|
|
186
|
+
{
|
|
187
|
+
"tier": "working",
|
|
188
|
+
"emotion": { "valence": -0.7, "arousal": 0.8, "label": "frustration" }
|
|
189
|
+
}
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
### 5.2 Detection at Store Time
|
|
193
|
+
|
|
194
|
+
**Two-tier detection (store.ts / noise-filter.ts):**
|
|
195
|
+
|
|
196
|
+
**Tier 1: Heuristic (zero LLM cost, always runs)**
|
|
197
|
+
```ts
|
|
198
|
+
const NEGATIVE_SIGNALS = ["失败", "痛苦", "困扰", "bug", "broken", "frustrat", "hate", "wrong", "error"];
|
|
199
|
+
const POSITIVE_SIGNALS = ["突破", "搞定", "成功", "solved", "great", "love", "perfect", "works"];
|
|
200
|
+
const HIGH_AROUSAL = ["!", "紧急", "urgent", "critical", "immediately", "ASAP"];
|
|
201
|
+
|
|
202
|
+
function heuristicEmotion(text: string): EmotionMetadata {
|
|
203
|
+
const negCount = NEGATIVE_SIGNALS.filter(s => text.toLowerCase().includes(s)).length;
|
|
204
|
+
const posCount = POSITIVE_SIGNALS.filter(s => text.toLowerCase().includes(s)).length;
|
|
205
|
+
const arousalCount = HIGH_AROUSAL.filter(s => text.includes(s)).length;
|
|
206
|
+
|
|
207
|
+
const valence = clamp((posCount - negCount) * 0.3, -1, 1);
|
|
208
|
+
const arousal = clamp(arousalCount * 0.3, 0, 1);
|
|
209
|
+
const label = valence > 0.3 ? "positive" : valence < -0.3 ? "negative" : "neutral";
|
|
210
|
+
|
|
211
|
+
return { valence, arousal, label };
|
|
212
|
+
}
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
**Tier 2: LLM (optional, piggybacked on importance evaluation)**
|
|
216
|
+
- When LLM is called to evaluate importance (existing flow), add to prompt:
|
|
217
|
+
```
|
|
218
|
+
Also rate the emotional tone:
|
|
219
|
+
- valence: [-1, 1] (negative to positive)
|
|
220
|
+
- arousal: [0, 1] (calm to excited)
|
|
221
|
+
- label: one word (e.g., "frustration", "excitement", "neutral")
|
|
222
|
+
```
|
|
223
|
+
- Merged into existing LLM call → zero additional API cost
|
|
224
|
+
- LLM result overrides heuristic result when available
|
|
225
|
+
|
|
226
|
+
**Backward compatibility:** Existing memories without emotion field → treated as `{ valence: 0, arousal: 0, label: "neutral" }` everywhere.
|
|
227
|
+
|
|
228
|
+
### 5.3 Decay Integration (decay-engine.ts)
|
|
229
|
+
|
|
230
|
+
**Modified half-life calculation:**
|
|
231
|
+
```ts
|
|
232
|
+
function adjustedHalfLife(baseHalfLife: number, emotion?: EmotionMetadata): number {
|
|
233
|
+
if (!emotion) return baseHalfLife;
|
|
234
|
+
const emotionalIntensity = Math.abs(emotion.valence);
|
|
235
|
+
// Emotional memories last up to 30% longer
|
|
236
|
+
const boost = 1 + 0.3 * emotionalIntensity;
|
|
237
|
+
return baseHalfLife * boost;
|
|
238
|
+
}
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
- Strong negative memory (valence = -0.9): half-life × 1.27
|
|
242
|
+
- Strong positive memory (valence = 0.8): half-life × 1.24
|
|
243
|
+
- Neutral memory (valence = 0.1): half-life × 1.03 (negligible)
|
|
244
|
+
- No emotion field: no change
|
|
245
|
+
|
|
246
|
+
**Arousal modulation (secondary):**
|
|
247
|
+
```ts
|
|
248
|
+
// High arousal slightly accelerates initial strength but doesn't change half-life
|
|
249
|
+
// This models the "flashbulb memory" effect — vivid but not necessarily longer-lasting
|
|
250
|
+
const initialBoost = 1 + 0.1 * (emotion?.arousal ?? 0);
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
### 5.4 Retrieval Integration (retriever.ts)
|
|
254
|
+
|
|
255
|
+
**New scoring stage: `applyEmotionWeight` (after `applyImportanceWeight`)**
|
|
256
|
+
|
|
257
|
+
```ts
|
|
258
|
+
function applyEmotionWeight(
|
|
259
|
+
results: ScoredResult[],
|
|
260
|
+
queryEmotion: EmotionMetadata | null
|
|
261
|
+
): ScoredResult[] {
|
|
262
|
+
if (!queryEmotion || Math.abs(queryEmotion.valence) < 0.2) {
|
|
263
|
+
return results; // neutral query → no-op
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
return results.map(r => {
|
|
267
|
+
const memEmotion = parseEmotion(r.metadata);
|
|
268
|
+
if (!memEmotion) return r; // no emotion data → unchanged
|
|
269
|
+
|
|
270
|
+
// Emotional alignment boost: same-valence memories score higher
|
|
271
|
+
const alignment = 1 - Math.abs(queryEmotion.valence - memEmotion.valence) / 2;
|
|
272
|
+
const boost = 1.0 + 0.15 * alignment;
|
|
273
|
+
|
|
274
|
+
return { ...r, score: r.score * boost };
|
|
275
|
+
});
|
|
276
|
+
}
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
- Query has emotional tone + memory has matching emotion → up to 15% score boost
|
|
280
|
+
- Query is neutral → stage is no-op (zero overhead)
|
|
281
|
+
- Memory has no emotion data → unchanged
|
|
282
|
+
|
|
283
|
+
**Query emotion detection:**
|
|
284
|
+
- Reuse heuristic detector on query text
|
|
285
|
+
- Lightweight, no LLM needed at query time
|
|
286
|
+
|
|
287
|
+
### 5.5 Feature Flag
|
|
288
|
+
|
|
289
|
+
`RECALLNEST_EMOTION_SCORING=true` — controls:
|
|
290
|
+
- Emotion detection at store time
|
|
291
|
+
- Emotion-adjusted decay calculation
|
|
292
|
+
- Emotion scoring stage in retriever
|
|
293
|
+
|
|
294
|
+
When OFF: all emotion code paths are no-op. Existing behavior preserved exactly.
|
|
295
|
+
|
|
296
|
+
---
|
|
297
|
+
|
|
298
|
+
## 6. File Change Map
|
|
299
|
+
|
|
300
|
+
| File | Change Type | Description |
|
|
301
|
+
|------|-------------|-------------|
|
|
302
|
+
| `src/context-reconstructor.ts` | **NEW** | Reconstruction engine + grounding validator |
|
|
303
|
+
| `src/retriever.ts` | Modify | Add reconstruction gate at output + emotion scoring stage |
|
|
304
|
+
| `src/decay-engine.ts` | Modify | Add emotion-adjusted half-life |
|
|
305
|
+
| `src/memory-schema.ts` | Modify | Add EmotionMetadata type definition |
|
|
306
|
+
| `src/store.ts` | Modify | Call emotion detector at store time |
|
|
307
|
+
| `src/context-composer.ts` | Modify | Call reconstructor in resume flow |
|
|
308
|
+
| `src/mcp-server.ts` | Modify | Add `reconstruct` param to search_memory |
|
|
309
|
+
| `src/config.ts` | Modify | Add feature flags |
|
|
310
|
+
| `src/__tests__/context-reconstructor.test.ts` | **NEW** | Unit tests for reconstruction + grounding |
|
|
311
|
+
| `src/__tests__/emotion-scoring.test.ts` | **NEW** | Unit tests for emotion detection + decay + retrieval |
|
|
312
|
+
|
|
313
|
+
**Estimated LOC:**
|
|
314
|
+
- New code: ~400-500 lines
|
|
315
|
+
- Modified code: ~100-150 lines across existing files
|
|
316
|
+
- Tests: ~300-400 lines
|
|
317
|
+
|
|
318
|
+
---
|
|
319
|
+
|
|
320
|
+
## 7. Test Strategy
|
|
321
|
+
|
|
322
|
+
### Unit Tests
|
|
323
|
+
- Reconstruction gate: all 4 conditions tested (flag off, no opt-in, too few results, LLM down)
|
|
324
|
+
- Grounding validator: phantom ID removal, coverage threshold, timeout
|
|
325
|
+
- Emotion heuristic: positive/negative/neutral/mixed texts
|
|
326
|
+
- Decay adjustment: verify half-life calculations
|
|
327
|
+
- Retrieval emotion stage: neutral query no-op, matching boost, missing data handling
|
|
328
|
+
|
|
329
|
+
### Integration Tests
|
|
330
|
+
- End-to-end: store memories → search with reconstruct=true → verify output format
|
|
331
|
+
- End-to-end: store emotional memory → verify decay score after N days vs neutral memory
|
|
332
|
+
- resume_context with reconstruction → verify grounding and fallback
|
|
333
|
+
|
|
334
|
+
### Regression Tests
|
|
335
|
+
- All feature flags OFF → existing test suite must pass unchanged (zero regression)
|
|
336
|
+
- Memories without emotion field → same scores as before
|
|
337
|
+
|
|
338
|
+
---
|
|
339
|
+
|
|
340
|
+
## 8. Rollout Plan
|
|
341
|
+
|
|
342
|
+
**Phase 1: Emotion Valence (low risk, no LLM dependency)**
|
|
343
|
+
1. Add schema types
|
|
344
|
+
2. Implement heuristic detector
|
|
345
|
+
3. Integrate into store path
|
|
346
|
+
4. Add decay adjustment
|
|
347
|
+
5. Add retrieval scoring stage
|
|
348
|
+
6. Tests
|
|
349
|
+
7. Feature flag ON for testing
|
|
350
|
+
|
|
351
|
+
**Phase 2: Constructive Retrieval (medium risk, LLM dependent)**
|
|
352
|
+
1. Implement context-reconstructor.ts
|
|
353
|
+
2. Implement grounding validator
|
|
354
|
+
3. Integrate into retriever output
|
|
355
|
+
4. Integrate into context-composer
|
|
356
|
+
5. Add search_memory parameter
|
|
357
|
+
6. Tests
|
|
358
|
+
7. Feature flag ON for testing
|
|
359
|
+
|
|
360
|
+
**Phase 3: LLM Emotion Detection (optional enhancement)**
|
|
361
|
+
1. Piggyback on importance evaluation prompt
|
|
362
|
+
2. Override heuristic when available
|
|
363
|
+
3. A/B test heuristic vs LLM accuracy
|
|
364
|
+
|
|
365
|
+
---
|
|
366
|
+
|
|
367
|
+
## 9. Success Criteria
|
|
368
|
+
|
|
369
|
+
- [ ] Feature flags OFF → all existing tests pass (baseline per CLAUDE.md)
|
|
370
|
+
- [ ] Emotion-tagged memories decay 20-30% slower than neutral (verified in test)
|
|
371
|
+
- [ ] Reconstruction produces grounded output (coverage ≥ 0.6) in ≥ 80% of cases
|
|
372
|
+
- [ ] Reconstruction fallback triggers correctly when LLM is unavailable
|
|
373
|
+
- [ ] resume_context with reconstruction provides more contextually relevant summaries (qualitative)
|
|
374
|
+
- [ ] No additional LLM API calls for emotion detection (piggybacked on existing calls)
|
|
375
|
+
- [ ] Reconstruction latency < 3s in 95% of cases
|
|
376
|
+
|
|
377
|
+
---
|
|
378
|
+
|
|
379
|
+
## 10. Open Questions (resolved)
|
|
380
|
+
|
|
381
|
+
| Question | Decision |
|
|
382
|
+
|----------|----------|
|
|
383
|
+
| How aggressive should reconstruction be? | **Moderate (B)**: LLM rewrite from top-N, not fragment synthesis |
|
|
384
|
+
| What emotion model? | **Valence-Arousal**: simple, proven, low overhead |
|
|
385
|
+
| When to reconstruct by default? | **resume_context only**; search_memory opt-in |
|
|
386
|
+
| Grounding threshold? | **0.6 coverage**; tunable via config |
|
|
387
|
+
| Timeout? | **3 seconds**; hard cutoff |
|
|
388
|
+
|
|
389
|
+
---
|
|
390
|
+
|
|
391
|
+
## Sources
|
|
392
|
+
|
|
393
|
+
- Michaelian, K. — Simulation Theory of Memory
|
|
394
|
+
- Ebbinghaus Forgetting Curve + Weibull extensions
|
|
395
|
+
- Cognitive science consensus on emotional memory persistence
|
|
396
|
+
- [Stanford Encyclopedia of Philosophy: Memory](https://plato.stanford.edu/entries/memory/)
|
|
397
|
+
- [Memory in the Age of AI Agents](https://arxiv.org/abs/2512.13564)
|
|
398
|
+
- [SuperLocalMemory V3.3: Biologically-Inspired Forgetting](https://arxiv.org/html/2604.04514)
|
package/glama.json
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# RecallNest — setup all three terminals at once (idempotent)
|
|
3
|
+
# Usage: bash integrations/setup-all.sh
|
|
4
|
+
|
|
5
|
+
set -euo pipefail
|
|
6
|
+
|
|
7
|
+
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
8
|
+
|
|
9
|
+
echo "RecallNest — setting up all terminals"
|
|
10
|
+
echo "======================================"
|
|
11
|
+
echo ""
|
|
12
|
+
|
|
13
|
+
echo "--- Claude Code ---"
|
|
14
|
+
bash "$SCRIPT_DIR/claude-code/setup.sh"
|
|
15
|
+
echo ""
|
|
16
|
+
|
|
17
|
+
echo "--- Codex ---"
|
|
18
|
+
bash "$SCRIPT_DIR/codex/setup.sh"
|
|
19
|
+
echo ""
|
|
20
|
+
|
|
21
|
+
echo "--- Gemini CLI ---"
|
|
22
|
+
bash "$SCRIPT_DIR/gemini-cli/setup.sh"
|
|
23
|
+
echo ""
|
|
24
|
+
|
|
25
|
+
echo "======================================"
|
|
26
|
+
echo "All terminals configured."
|
|
27
|
+
echo ""
|
|
28
|
+
echo "Next steps:"
|
|
29
|
+
echo " 1. Restart each terminal"
|
|
30
|
+
echo " 2. Run: bun run seed:continuity"
|
|
31
|
+
echo " 3. Run: bun run src/cli.ts doctor"
|
package/package.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "recallnest",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.2.0",
|
|
4
4
|
"description": "RecallNest \u2014 MCP-native, local-first memory search and distillation for AI conversations",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"bin": {
|
|
8
|
-
"recallnest": "
|
|
9
|
-
"local-memory": "
|
|
8
|
+
"recallnest": "bin/recallnest.mjs",
|
|
9
|
+
"local-memory": "bin/recallnest.mjs"
|
|
10
10
|
},
|
|
11
11
|
"scripts": {
|
|
12
12
|
"search": "bun run src/cli.ts search",
|
|
@@ -35,13 +35,20 @@
|
|
|
35
35
|
"ui": "bun run src/ui-server.ts",
|
|
36
36
|
"api": "bun run src/api-server.ts"
|
|
37
37
|
},
|
|
38
|
+
"engines": {
|
|
39
|
+
"node": ">=18.0.0"
|
|
40
|
+
},
|
|
38
41
|
"dependencies": {
|
|
39
42
|
"@lancedb/lancedb": "^0.26.0",
|
|
40
43
|
"@modelcontextprotocol/sdk": "^1.27.1",
|
|
41
44
|
"commander": "^12.0.0",
|
|
42
45
|
"openai": "^4.0.0",
|
|
46
|
+
"tsx": "^4.19.0",
|
|
43
47
|
"zod": "^3.25.76"
|
|
44
48
|
},
|
|
49
|
+
"optionalDependencies": {
|
|
50
|
+
"babel-memory": ">=1.0.0"
|
|
51
|
+
},
|
|
45
52
|
"repository": {
|
|
46
53
|
"type": "git",
|
|
47
54
|
"url": "git+https://github.com/AliceLJY/recallnest.git"
|