recallnest 1.4.1 → 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.
- package/.env +4 -0
- package/CLAUDE.md +7 -3
- package/README.md +202 -130
- package/README_CN.md +263 -190
- package/bin/recallnest.mjs +62 -0
- package/config.json +55 -0
- package/daily-recall.sh +23 -0
- package/integrations/setup-all.sh +31 -0
- package/logs/daily-recall.error.log +0 -0
- package/logs/daily-recall.log +30 -0
- package/logs/ingest-2026-04-11.log +110 -0
- package/logs/ingest-2026-04-12.log +90 -0
- package/logs/launchagent-stderr.log +0 -0
- package/logs/launchagent-stdout.log +0 -0
- package/package.json +10 -3
- 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
- package/.claude-plugin/CLAUDE.md +0 -29
- package/.claude-plugin/marketplace.json +0 -18
- package/.github/workflows/ci.yml +0 -28
- package/.mcp.json +0 -9
- package/CHANGELOG.md +0 -51
- package/DEMO.md +0 -94
- package/EVAL.md +0 -89
- package/FAILURES.md +0 -75
- package/OPERATIONS.md +0 -59
- package/ROADMAP.md +0 -198
- package/assets/recallnest-workbench.png +0 -0
- package/assets/ui/app.js +0 -807
- package/assets/ui/index.html +0 -154
- package/assets/ui/styles.css +0 -605
- package/assets/wechat-qr.jpg +0 -0
- package/daily-reflections/2026-03-05.md +0 -15
- package/daily-reflections/2026-03-06.md +0 -15
- package/daily-reflections/2026-03-07.md +0 -7
- package/daily-reflections/2026-03-08.md +0 -34
- package/daily-reflections/2026-03-09.md +0 -35
- package/daily-reflections/2026-03-10.md +0 -36
- package/daily-reflections/2026-03-11.md +0 -35
- package/daily-reflections/2026-03-12.md +0 -36
- package/daily-reflections/2026-03-13.md +0 -35
- package/daily-reflections/2026-03-14.md +0 -35
- package/daily-reflections/2026-03-15.md +0 -35
- package/daily-reflections/2026-03-16.md +0 -41
- package/daily-reflections/2026-03-17.md +0 -10
- package/daily-reflections/2026-03-18.md +0 -10
- package/daily-reflections/2026-03-19.md +0 -10
- package/daily-reflections/2026-03-20.md +0 -10
- package/daily-reflections/2026-03-21.md +0 -10
- package/daily-reflections/2026-03-22.md +0 -10
- package/daily-reflections/2026-03-23.md +0 -10
- package/daily-reflections/2026-03-24.md +0 -10
- package/daily-reflections/2026-03-25.md +0 -32
- package/daily-reflections/2026-03-26.md +0 -37
- package/daily-reflections/2026-03-27.md +0 -35
- package/daily-reflections/2026-03-28.md +0 -35
- package/daily-reflections/2026-03-29.md +0 -35
- package/daily-reflections/2026-03-30.md +0 -36
- package/daily-reflections/2026-03-31.md +0 -35
- package/daily-reflections/2026-04-01.md +0 -35
- package/docs/api-reference.md +0 -1291
- package/docs/architecture.md +0 -168
- package/docs/memory-boundary-contract.md +0 -226
- package/docs/memory-categories.md +0 -119
- package/docs/pipeline-audit-ultramemory.md +0 -177
- package/docs/plans/2026-03-08-query-expansion.md +0 -270
- package/docs/plans/2026-03-16-continuity-layer.md +0 -196
- package/docs/plans/mcp-tiering-plan.md +0 -126
- package/docs/research/recall-quality-audit-2026-03-22.md +0 -153
- package/docs/self-evolution.md +0 -198
- package/docs/superpowers/plans/2026-03-19-ingest-pipeline-upgrade.md +0 -782
- package/docs/superpowers/specs/2026-03-19-ingest-pipeline-upgrade-design.md +0 -77
- package/docs/superpowers/specs/2026-03-23-pull-claude-desktop-design.md +0 -95
- package/eval/continuity/results-2026-03-16.md +0 -117
- package/eval/continuity/results-2026-03-19.md +0 -453
- package/eval/continuity/runbook.md +0 -110
- package/eval/continuity/seed-cases.md +0 -54
- package/eval/reports/2026-03-06-abstract-query-baseline.md +0 -96
- package/eval/reports/2026-03-06-aws-ssh-baseline.md +0 -82
- package/eval/reports/2026-03-06-baseline.md +0 -82
- package/eval/reports/query-expansion.md +0 -138
- package/lm +0 -19
- package/plan-v1.2-distributable.md +0 -105
- package/scripts/archive-distilled-junk.ts +0 -116
- package/scripts/backfill-l0l1l2.ts +0 -98
- package/scripts/blind-scan.ts +0 -588
- package/scripts/cleanup-step1-exact-dups.ts +0 -117
- package/scripts/cleanup-step2-template-dups.ts +0 -113
- package/scripts/cleanup-step3-stale-content.ts +0 -149
- package/scripts/cleanup-step4-orphan-scopes.ts +0 -131
- package/scripts/delete-distilled-junk.ts +0 -88
- package/scripts/distill-facts.ts +0 -305
- package/scripts/health-check.ts +0 -343
- package/scripts/incremental-ingest.sh +0 -71
- package/scripts/mlp-health-check.ts +0 -382
- package/scripts/pull-claude-desktop.ts +0 -515
- package/scripts/re-ingest-cc.sh +0 -66
- package/scripts/rebalance-memory-health.ts +0 -181
- package/scripts/run-desktop-ingest.sh +0 -11
- package/scripts/start-server.sh +0 -12
- package/scripts/viz-dashboard.html +0 -423
- package/scripts/viz-export.ts +0 -703
- package/src/__tests__/access-tracker-novelty.test.ts +0 -228
- package/src/__tests__/auto-consolidation.test.ts +0 -168
- package/src/__tests__/auto-recall.test.ts +0 -131
- package/src/__tests__/batch-dedup.test.ts +0 -65
- package/src/__tests__/capture-engine.test.ts +0 -1142
- package/src/__tests__/capture-heuristic.test.ts +0 -171
- package/src/__tests__/cascade-forget.test.ts +0 -210
- package/src/__tests__/category-min-scores.test.ts +0 -33
- package/src/__tests__/confidence-tracker.test.ts +0 -196
- package/src/__tests__/conflict-advisor.test.ts +0 -206
- package/src/__tests__/conflict-escalation.test.ts +0 -149
- package/src/__tests__/conflict-lifecycle.test.ts +0 -83
- package/src/__tests__/conflict-output.test.ts +0 -85
- package/src/__tests__/conflict-store.test.ts +0 -374
- package/src/__tests__/consolidation-engine.test.ts +0 -181
- package/src/__tests__/context-composer-pins.test.ts +0 -64
- package/src/__tests__/context-composer-task-selection.test.ts +0 -24
- package/src/__tests__/context-renderer.test.ts +0 -91
- package/src/__tests__/continuity-eval.test.ts +0 -275
- package/src/__tests__/continuity-schema.test.ts +0 -97
- package/src/__tests__/core-recall-eval.test.ts +0 -235
- package/src/__tests__/core-summary.test.ts +0 -109
- package/src/__tests__/dedup-actions.test.ts +0 -58
- package/src/__tests__/deterministic-id.test.ts +0 -39
- package/src/__tests__/doctor.test.ts +0 -303
- package/src/__tests__/drill-down.test.ts +0 -108
- package/src/__tests__/embedder.test.ts +0 -122
- package/src/__tests__/entity-resolver.test.ts +0 -58
- package/src/__tests__/event-segmenter.test.ts +0 -153
- package/src/__tests__/hotness-blend.test.ts +0 -76
- package/src/__tests__/ingest.test.ts +0 -360
- package/src/__tests__/kg-extractor.test.ts +0 -184
- package/src/__tests__/kg-store.test.ts +0 -198
- package/src/__tests__/llm-consolidation.test.ts +0 -226
- package/src/__tests__/memory-boundaries.test.ts +0 -237
- package/src/__tests__/memory-health-rebalance.test.ts +0 -144
- package/src/__tests__/memory-output.test.ts +0 -215
- package/src/__tests__/multi-vector.test.ts +0 -242
- package/src/__tests__/ppr-traversal.test.ts +0 -256
- package/src/__tests__/preference-guard-smoke.test.ts +0 -211
- package/src/__tests__/preference-matcher.test.ts +0 -230
- package/src/__tests__/preference-slots.test.ts +0 -106
- package/src/__tests__/prospective-memory.test.ts +0 -283
- package/src/__tests__/query-entity-detector.test.ts +0 -171
- package/src/__tests__/query-expander.test.ts +0 -34
- package/src/__tests__/recall-mode.test.ts +0 -64
- package/src/__tests__/result-synthesizer.test.ts +0 -198
- package/src/__tests__/resume-context.test.ts +0 -4743
- package/src/__tests__/retrieval-trace.test.ts +0 -213
- package/src/__tests__/retriever-boundary-weight.test.ts +0 -136
- package/src/__tests__/retroactive-boost.test.ts +0 -223
- package/src/__tests__/scope-inventory.test.ts +0 -200
- package/src/__tests__/scope-policy.test.ts +0 -69
- package/src/__tests__/session-checkpoint.test.ts +0 -259
- package/src/__tests__/session-gc.test.ts +0 -215
- package/src/__tests__/store-scope-audit.test.ts +0 -81
- package/src/__tests__/temporal-parser.test.ts +0 -241
- package/src/__tests__/term-registry.test.ts +0 -121
- package/src/__tests__/tool-output-compressor.test.ts +0 -133
- package/src/__tests__/version-manager.test.ts +0 -213
- package/src/__tests__/workflow-observation.test.ts +0 -400
package/src/context-composer.ts
CHANGED
|
@@ -13,7 +13,7 @@ import {
|
|
|
13
13
|
buildTaskResultSections,
|
|
14
14
|
} from "./context-composer-task-results.js";
|
|
15
15
|
import type { RetrievalContext, RetrievalResult } from "./retriever.js";
|
|
16
|
-
import type { ResumeContextResponse, SessionCheckpointRecord } from "./session-schema.js";
|
|
16
|
+
import type { EssentialContext, ResumeContextResponse, SessionCheckpointRecord } from "./session-schema.js";
|
|
17
17
|
import { ResumeContextRequestSchema, ResumeContextResponseSchema } from "./session-schema.js";
|
|
18
18
|
import { formatCheckpointRecallSummary } from "./session-output.js";
|
|
19
19
|
import {
|
|
@@ -24,6 +24,10 @@ import {
|
|
|
24
24
|
} from "./term-registry.js";
|
|
25
25
|
import { synthesizeSection } from "./result-synthesizer.js";
|
|
26
26
|
import type { LLMClient } from "./llm-client.js";
|
|
27
|
+
import { collapseResults, estimateTokens, type CollapseInput } from "./context-collapse-renderer.js";
|
|
28
|
+
import { filterByRelevance } from "./post-retrieval-filter.js";
|
|
29
|
+
import { reconstruct as runReconstruction } from "./context-reconstructor.js";
|
|
30
|
+
import { parseNarrative, isNarrativeModeEnabled } from "./narrative-schema.js";
|
|
27
31
|
type ResumeCategory = "profile" | "preferences" | "entities" | "patterns" | "cases";
|
|
28
32
|
|
|
29
33
|
interface ResumeRetriever {
|
|
@@ -154,6 +158,142 @@ function buildSummary(params: {
|
|
|
154
158
|
return cleanText(parts.join(" "), 800);
|
|
155
159
|
}
|
|
156
160
|
|
|
161
|
+
// ---------------------------------------------------------------------------
|
|
162
|
+
// CC-8: Post-Compact Reconstruction — assemble essential context
|
|
163
|
+
// ---------------------------------------------------------------------------
|
|
164
|
+
|
|
165
|
+
const ESSENTIAL_CONTEXT_TOKEN_BUDGET = 2000;
|
|
166
|
+
|
|
167
|
+
function buildEssentialContext(params: {
|
|
168
|
+
pinAssets: Array<PinAsset & { path: string }>;
|
|
169
|
+
patternResults: RetrievalResult[];
|
|
170
|
+
latestCheckpoint: SessionCheckpointRecord | null;
|
|
171
|
+
}): EssentialContext | undefined {
|
|
172
|
+
let tokensUsed = 0;
|
|
173
|
+
|
|
174
|
+
// 1. Pinned memories: take up to 3 most recent pins' summaries
|
|
175
|
+
const pinnedMemories: string[] = [];
|
|
176
|
+
for (const pin of params.pinAssets.slice(0, 3)) {
|
|
177
|
+
const text = pin.summary || pin.title;
|
|
178
|
+
const cost = estimateTokens(text);
|
|
179
|
+
if (tokensUsed + cost > ESSENTIAL_CONTEXT_TOKEN_BUDGET) break;
|
|
180
|
+
pinnedMemories.push(text);
|
|
181
|
+
tokensUsed += cost;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
// 2. Active patterns: take top 1-2 by score
|
|
185
|
+
const activePatterns: string[] = [];
|
|
186
|
+
const sortedPatterns = [...params.patternResults].sort((a, b) => b.score - a.score);
|
|
187
|
+
for (const pattern of sortedPatterns.slice(0, 2)) {
|
|
188
|
+
const text = cleanText(pattern.entry.text, 200);
|
|
189
|
+
const cost = estimateTokens(text);
|
|
190
|
+
if (tokensUsed + cost > ESSENTIAL_CONTEXT_TOKEN_BUDGET) break;
|
|
191
|
+
activePatterns.push(text);
|
|
192
|
+
tokensUsed += cost;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
// 3. Open loops from latest checkpoint
|
|
196
|
+
const openLoops: string[] = [];
|
|
197
|
+
if (params.latestCheckpoint?.openLoops) {
|
|
198
|
+
for (const loop of params.latestCheckpoint.openLoops.slice(0, 3)) {
|
|
199
|
+
const cost = estimateTokens(loop);
|
|
200
|
+
if (tokensUsed + cost > ESSENTIAL_CONTEXT_TOKEN_BUDGET) break;
|
|
201
|
+
openLoops.push(loop);
|
|
202
|
+
tokensUsed += cost;
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
// Return undefined if nothing was collected
|
|
207
|
+
if (pinnedMemories.length === 0 && activePatterns.length === 0 && openLoops.length === 0) {
|
|
208
|
+
return undefined;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
return {
|
|
212
|
+
...(pinnedMemories.length > 0 ? { pinnedMemories } : {}),
|
|
213
|
+
...(activePatterns.length > 0 ? { activePatterns } : {}),
|
|
214
|
+
...(openLoops.length > 0 ? { openLoops } : {}),
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
// ---------------------------------------------------------------------------
|
|
219
|
+
// MP-3: Ultra-Light Wake-up — <300 token resume for low-budget terminals
|
|
220
|
+
// ---------------------------------------------------------------------------
|
|
221
|
+
|
|
222
|
+
const LIGHT_TOKEN_BUDGET = 300;
|
|
223
|
+
const LIGHT_MEMORY_CHAR_LIMIT = 200; // ~50 tokens
|
|
224
|
+
|
|
225
|
+
export interface LightResumeResult {
|
|
226
|
+
text: string;
|
|
227
|
+
resolvedScope?: string;
|
|
228
|
+
generatedAt: string;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
export async function composeLightResumeContext(
|
|
232
|
+
deps: ResumeContextDeps,
|
|
233
|
+
rawInput: unknown,
|
|
234
|
+
): Promise<LightResumeResult> {
|
|
235
|
+
const input = ResumeContextRequestSchema.parse(rawInput);
|
|
236
|
+
const latestCheckpoint = await resolveLatestCheckpoint(deps.checkpointStore, {
|
|
237
|
+
includeLatestCheckpoint: true,
|
|
238
|
+
sessionId: input.sessionId,
|
|
239
|
+
scope: input.scope,
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
const resolvedScope = input.scope || latestCheckpoint?.resolvedScope;
|
|
243
|
+
|
|
244
|
+
// Retrieve top 3 stable memories (profile + preferences + entities combined)
|
|
245
|
+
const stableResults = await retrieveCandidates(deps.retriever, {
|
|
246
|
+
query: input.task || "identity key facts and preferences",
|
|
247
|
+
limit: 3,
|
|
248
|
+
scope: resolvedScope,
|
|
249
|
+
});
|
|
250
|
+
|
|
251
|
+
// Pin assets provide high-signal stable context
|
|
252
|
+
const pinAssets = (deps.listPins || listPinAssets)(3);
|
|
253
|
+
|
|
254
|
+
const parts: string[] = [];
|
|
255
|
+
let tokensUsed = 0;
|
|
256
|
+
|
|
257
|
+
// 1. Checkpoint summary (1 sentence, ~30 tokens)
|
|
258
|
+
if (latestCheckpoint) {
|
|
259
|
+
const cpLine = `Last session (${latestCheckpoint.sessionId}): ${cleanText(latestCheckpoint.summary, 120)}`;
|
|
260
|
+
parts.push(cpLine);
|
|
261
|
+
tokensUsed += estimateTokens(cpLine);
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
// 2. Top pinned memories (most reliable stable context)
|
|
265
|
+
if (pinAssets.length > 0) {
|
|
266
|
+
for (const pin of pinAssets) {
|
|
267
|
+
if (tokensUsed >= LIGHT_TOKEN_BUDGET - 40) break;
|
|
268
|
+
const line = `- ${cleanText(pin.summary || pin.title, LIGHT_MEMORY_CHAR_LIMIT)}`;
|
|
269
|
+
parts.push(line);
|
|
270
|
+
tokensUsed += estimateTokens(line);
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
// 3. Top stable memories (fill remaining budget)
|
|
275
|
+
if (stableResults.length > 0 && tokensUsed < LIGHT_TOKEN_BUDGET - 40) {
|
|
276
|
+
const pinTexts = new Set(pinAssets.map(p => (p.summary || p.title).toLowerCase()));
|
|
277
|
+
for (const r of stableResults) {
|
|
278
|
+
if (tokensUsed >= LIGHT_TOKEN_BUDGET - 40) break;
|
|
279
|
+
const textLower = r.entry.text.toLowerCase().slice(0, 100);
|
|
280
|
+
if (pinTexts.has(textLower)) continue;
|
|
281
|
+
const line = `- ${cleanText(r.entry.text, LIGHT_MEMORY_CHAR_LIMIT)}`;
|
|
282
|
+
parts.push(line);
|
|
283
|
+
tokensUsed += estimateTokens(line);
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
// 4. Upgrade hint
|
|
288
|
+
parts.push("\nFor complete context, call resume_context(mode='full').");
|
|
289
|
+
|
|
290
|
+
return {
|
|
291
|
+
text: parts.join("\n"),
|
|
292
|
+
resolvedScope,
|
|
293
|
+
generatedAt: new Date().toISOString(),
|
|
294
|
+
};
|
|
295
|
+
}
|
|
296
|
+
|
|
157
297
|
export async function composeResumeContext(
|
|
158
298
|
deps: ResumeContextDeps,
|
|
159
299
|
rawInput: unknown,
|
|
@@ -221,6 +361,17 @@ export async function composeResumeContext(
|
|
|
221
361
|
const preferenceResults = mergeRetrievalResults(preferenceResultSets, Math.max(4, stableLimit * 3));
|
|
222
362
|
const entityResults = mergeRetrievalResults(entityResultSets, Math.max(4, stableLimit * 3));
|
|
223
363
|
|
|
364
|
+
// E-2: Post-retrieval LLM relevance filter for pattern/case results.
|
|
365
|
+
// Only fires when LLM is available; stable context (profile/preferences/entities) skipped
|
|
366
|
+
// because those are identity-level and already curated by the selection pipeline.
|
|
367
|
+
const llm = deps.llm ?? null;
|
|
368
|
+
const [filteredPatterns, filteredCases] = llm && taskSeed
|
|
369
|
+
? await Promise.all([
|
|
370
|
+
filterByRelevance(patternResults, taskSeed, llm),
|
|
371
|
+
filterByRelevance(caseResults, taskSeed, llm),
|
|
372
|
+
])
|
|
373
|
+
: [patternResults, caseResults];
|
|
374
|
+
|
|
224
375
|
const continuityTask = looksLikeContinuityTask(taskSeed);
|
|
225
376
|
const pinAssets = (deps.listPins || listPinAssets)(Math.max(4, stableLimit * 2));
|
|
226
377
|
const {
|
|
@@ -246,8 +397,8 @@ export async function composeResumeContext(
|
|
|
246
397
|
limit,
|
|
247
398
|
scope,
|
|
248
399
|
}),
|
|
249
|
-
patternResults,
|
|
250
|
-
caseResults,
|
|
400
|
+
patternResults: filteredPatterns,
|
|
401
|
+
caseResults: filteredCases,
|
|
251
402
|
continuityTask,
|
|
252
403
|
hasLatestCheckpoint: Boolean(latestCheckpoint),
|
|
253
404
|
taskLimit,
|
|
@@ -258,7 +409,6 @@ export async function composeResumeContext(
|
|
|
258
409
|
|
|
259
410
|
// Tier 3.5: Optionally synthesize sections into coherent narratives via LLM.
|
|
260
411
|
// Only activates when RECALLNEST_SYNTHESIZE=true and llm is provided.
|
|
261
|
-
const llm = deps.llm ?? null;
|
|
262
412
|
const queryHint = taskSeed || resolvedScope || "general";
|
|
263
413
|
const [synthStable, synthPatterns, synthCases] = await Promise.all([
|
|
264
414
|
synthesizeSection(stableContext, queryHint, llm),
|
|
@@ -266,6 +416,83 @@ export async function composeResumeContext(
|
|
|
266
416
|
synthesizeSection(recentCases, queryHint, llm),
|
|
267
417
|
]);
|
|
268
418
|
|
|
419
|
+
// HP-narrative: Group recalled items by life period for narrative context
|
|
420
|
+
let narrativeGroups: Array<{ period: string; items: string[] }> | undefined;
|
|
421
|
+
if (isNarrativeModeEnabled()) {
|
|
422
|
+
const allNarrativeResults = [...profileResults, ...preferenceResults, ...entityResults, ...filteredPatterns, ...filteredCases];
|
|
423
|
+
const periodMap = new Map<string, string[]>();
|
|
424
|
+
for (const r of allNarrativeResults) {
|
|
425
|
+
const narrative = parseNarrative(r.entry.metadata);
|
|
426
|
+
if (!narrative) continue;
|
|
427
|
+
const items = periodMap.get(narrative.lifePeriodLabel) ?? [];
|
|
428
|
+
items.push(cleanText(r.entry.text, 120));
|
|
429
|
+
periodMap.set(narrative.lifePeriodLabel, items);
|
|
430
|
+
}
|
|
431
|
+
if (periodMap.size > 0) {
|
|
432
|
+
narrativeGroups = [...periodMap.entries()]
|
|
433
|
+
.map(([period, items]) => ({ period, items: items.slice(0, 5) }));
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
// CC-7: Collapse rendering — build mixed-granularity view of all recalled items.
|
|
438
|
+
// Gathers all retrieval results, deduplicates, and renders at L0/L1/L2 based on score.
|
|
439
|
+
const allResults: RetrievalResult[] = [];
|
|
440
|
+
const seenIds = new Set<string>();
|
|
441
|
+
for (const r of [...profileResults, ...preferenceResults, ...entityResults, ...filteredPatterns, ...filteredCases]) {
|
|
442
|
+
if (!seenIds.has(r.entry.id)) {
|
|
443
|
+
seenIds.add(r.entry.id);
|
|
444
|
+
allResults.push(r);
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
const collapseInput: CollapseInput[] = allResults.map(r => ({
|
|
448
|
+
entryId: r.entry.id,
|
|
449
|
+
text: r.entry.text,
|
|
450
|
+
metadata: r.entry.metadata,
|
|
451
|
+
score: r.score,
|
|
452
|
+
timestamp: r.entry.timestamp,
|
|
453
|
+
}));
|
|
454
|
+
const collapsedItems = collapseInput.length > 0
|
|
455
|
+
? collapseResults(collapseInput)
|
|
456
|
+
: undefined;
|
|
457
|
+
|
|
458
|
+
// CC-8: Build essential context from pinned memories, top patterns, and open loops.
|
|
459
|
+
const essentialContext = buildEssentialContext({
|
|
460
|
+
pinAssets,
|
|
461
|
+
patternResults: filteredPatterns,
|
|
462
|
+
latestCheckpoint,
|
|
463
|
+
});
|
|
464
|
+
|
|
465
|
+
// Phase 4: Constructive retrieval reconstruction for resume context
|
|
466
|
+
// Pass checkpoint openLoops/nextActions/scope into reconstruction prompt
|
|
467
|
+
let reconstructedContext: string | undefined;
|
|
468
|
+
let reconstructionConfidence: number | undefined;
|
|
469
|
+
let reconstructionContradictions: Array<{ memoryIds: [string, string]; description: string }> | undefined;
|
|
470
|
+
const constructiveFlag = process.env.RECALLNEST_CONSTRUCTIVE_RETRIEVAL === "true";
|
|
471
|
+
if (constructiveFlag && deps.llm?.isAvailable?.()) {
|
|
472
|
+
const allReconResults = [...profileResults, ...preferenceResults, ...entityResults, ...filteredPatterns, ...filteredCases];
|
|
473
|
+
if (allReconResults.length >= 3) {
|
|
474
|
+
try {
|
|
475
|
+
const taskQuery = latestCheckpoint?.summary ?? taskSeed ?? "general context";
|
|
476
|
+
const checkpointContext = latestCheckpoint ? {
|
|
477
|
+
openLoops: latestCheckpoint.openLoops,
|
|
478
|
+
nextActions: latestCheckpoint.nextActions,
|
|
479
|
+
scope: resolvedScope,
|
|
480
|
+
} : resolvedScope ? { scope: resolvedScope } : undefined;
|
|
481
|
+
const recon = await runReconstruction(
|
|
482
|
+
{ query: taskQuery, results: allReconResults, mode: "resume", maxTokens: 600, checkpointContext },
|
|
483
|
+
deps.llm,
|
|
484
|
+
);
|
|
485
|
+
if (recon.reconstructed) {
|
|
486
|
+
reconstructedContext = recon.reconstructed;
|
|
487
|
+
reconstructionConfidence = recon.confidence;
|
|
488
|
+
}
|
|
489
|
+
if (recon.contradictions.length > 0) {
|
|
490
|
+
reconstructionContradictions = recon.contradictions;
|
|
491
|
+
}
|
|
492
|
+
} catch { /* silent fallback */ }
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
|
|
269
496
|
const response = {
|
|
270
497
|
summary: buildSummary({
|
|
271
498
|
stableContext: synthStable,
|
|
@@ -277,6 +504,8 @@ export async function composeResumeContext(
|
|
|
277
504
|
stableContext: synthStable,
|
|
278
505
|
relevantPatterns: synthPatterns,
|
|
279
506
|
recentCases: synthCases,
|
|
507
|
+
collapsedItems: collapsedItems && collapsedItems.length > 0 ? collapsedItems : undefined,
|
|
508
|
+
essentialContext,
|
|
280
509
|
latestCheckpoint: latestCheckpoint
|
|
281
510
|
? {
|
|
282
511
|
sessionId: latestCheckpoint.sessionId,
|
|
@@ -285,6 +514,8 @@ export async function composeResumeContext(
|
|
|
285
514
|
updatedAt: latestCheckpoint.updatedAt,
|
|
286
515
|
}
|
|
287
516
|
: undefined,
|
|
517
|
+
injectionHint: "user_attachment" as const,
|
|
518
|
+
ephemeral: true,
|
|
288
519
|
responseMode: recallOnlyTask ? "recall-only" as const : "default" as const,
|
|
289
520
|
responseGuidance: recallOnlyTask
|
|
290
521
|
? (
|
|
@@ -293,6 +524,10 @@ export async function composeResumeContext(
|
|
|
293
524
|
: "Recall-only mode: answer only from the recalled stable context items. Keep the reply brief and do not expand into extra rules, examples, or local writing docs unless the user explicitly asks."
|
|
294
525
|
)
|
|
295
526
|
: undefined,
|
|
527
|
+
reconstructedContext,
|
|
528
|
+
reconstructionConfidence,
|
|
529
|
+
reconstructionContradictions,
|
|
530
|
+
narrativeGroups,
|
|
296
531
|
generatedAt: new Date().toISOString(),
|
|
297
532
|
};
|
|
298
533
|
|