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.
Files changed (166) hide show
  1. package/.dockerignore +11 -0
  2. package/CLAUDE.md +7 -3
  3. package/Dockerfile +20 -0
  4. package/README.md +202 -130
  5. package/README_CN.md +263 -190
  6. package/ROADMAP.md +128 -81
  7. package/SKILL.md +250 -0
  8. package/assets/dashboard.png +0 -0
  9. package/assets/knowledge-graph.png +0 -0
  10. package/assets/screenshots/ui-full.png +0 -0
  11. package/assets/screenshots/ui-overview.png +0 -0
  12. package/assets/screenshots/ui-search.png +0 -0
  13. package/assets/ui/app.js +227 -3
  14. package/assets/ui/index.html +81 -11
  15. package/assets/ui/styles.css +178 -2
  16. package/bin/recallnest.mjs +62 -0
  17. package/bun.lock +337 -0
  18. package/daily-recall.sh +23 -0
  19. package/daily-reflections/2026-04-02.md +35 -0
  20. package/daily-reflections/2026-04-03.md +37 -0
  21. package/daily-reflections/2026-04-04.md +37 -0
  22. package/daily-reflections/2026-04-05.md +35 -0
  23. package/daily-reflections/2026-04-06.md +36 -0
  24. package/daily-reflections/2026-04-07.md +35 -0
  25. package/daily-reflections/2026-04-08.md +35 -0
  26. package/daily-reflections/2026-04-12.md +35 -0
  27. package/data/alias-map.example.json +22 -0
  28. package/docs/plans/2026-04-01-recall-boost.md +100 -0
  29. package/docs/superpowers/plans/2026-04-11-constructive-retrieval-emotion.md +1195 -0
  30. package/docs/superpowers/specs/2026-04-11-constructive-retrieval-emotion-design.md +398 -0
  31. package/glama.json +6 -0
  32. package/integrations/setup-all.sh +31 -0
  33. package/package.json +10 -3
  34. package/plan-philosophy-upgrades.md +363 -0
  35. package/plan-product-upgrades.md +155 -0
  36. package/plan.md +140 -0
  37. package/research-memory-evolution.md +440 -0
  38. package/research-rl-agent-memory.md +330 -0
  39. package/scripts/backfill-anchors.ts +130 -0
  40. package/scripts/diagnose-vector-search.ts +132 -0
  41. package/scripts/migrate-language.ts +75 -0
  42. package/scripts/verify-emotion-decay.ts +148 -0
  43. package/src/__tests__/activity-counter.test.ts +96 -0
  44. package/src/__tests__/admission-control.test.ts +206 -0
  45. package/src/__tests__/anchor-generator.test.ts +67 -0
  46. package/src/__tests__/babel-integration.test.ts +139 -0
  47. package/src/__tests__/capture-engine.test.ts +5 -3
  48. package/src/__tests__/cascade-forget.test.ts +1 -1
  49. package/src/__tests__/cc8-cc1-essential-context.test.ts +298 -0
  50. package/src/__tests__/circuit-breaker.test.ts +99 -0
  51. package/src/__tests__/cluster-consolidation.test.ts +712 -0
  52. package/src/__tests__/confidence-metadata.test.ts +125 -0
  53. package/src/__tests__/confidence-tracker.test.ts +53 -0
  54. package/src/__tests__/consolidation-engine.test.ts +1 -1
  55. package/src/__tests__/constructive-retrieval.test.ts +509 -0
  56. package/src/__tests__/context-collapse-renderer.test.ts +214 -0
  57. package/src/__tests__/context-reconstructor.test.ts +65 -0
  58. package/src/__tests__/conversation-importer.test.ts +692 -0
  59. package/src/__tests__/data-checkup.test.ts +225 -0
  60. package/src/__tests__/decay-exemption.test.ts +84 -0
  61. package/src/__tests__/dedup-guard.test.ts +39 -0
  62. package/src/__tests__/distill-lock.test.ts +176 -0
  63. package/src/__tests__/dream-pipeline.test.ts +232 -0
  64. package/src/__tests__/emotion-decay.test.ts +46 -0
  65. package/src/__tests__/emotion-detector.test.ts +56 -0
  66. package/src/__tests__/emotion-phase1-integration.test.ts +153 -0
  67. package/src/__tests__/emotion-retrieval.test.ts +56 -0
  68. package/src/__tests__/ethics-layer.test.ts +476 -0
  69. package/src/__tests__/feature-flags-integration.test.ts +54 -0
  70. package/src/__tests__/frequency-tracker.test.ts +113 -0
  71. package/src/__tests__/graph-export.test.ts +489 -0
  72. package/src/__tests__/interference-detector.test.ts +203 -0
  73. package/src/__tests__/mcp-efficiency.test.ts +288 -0
  74. package/src/__tests__/memory-evolution-b2-b3-e1.test.ts +243 -0
  75. package/src/__tests__/memory-evolution.test.ts +271 -0
  76. package/src/__tests__/memory-lint.test.ts +271 -0
  77. package/src/__tests__/narrative-architecture.test.ts +456 -0
  78. package/src/__tests__/pending-review.test.ts +77 -0
  79. package/src/__tests__/post-retrieval-filter.test.ts +178 -0
  80. package/src/__tests__/prediction-engine.test.ts +349 -0
  81. package/src/__tests__/predictive-prospective-memory.test.ts +416 -0
  82. package/src/__tests__/preference-slots.test.ts +99 -0
  83. package/src/__tests__/query-expander-alias.test.ts +89 -0
  84. package/src/__tests__/recall-governor.test.ts +227 -0
  85. package/src/__tests__/resume-context.test.ts +156 -1
  86. package/src/__tests__/salience-scoring.test.ts +106 -0
  87. package/src/__tests__/session-distiller.test.ts +611 -0
  88. package/src/__tests__/skill-engine.test.ts +546 -0
  89. package/src/__tests__/skill-promotion.test.ts +349 -0
  90. package/src/__tests__/supersede-chain.test.ts +154 -0
  91. package/src/__tests__/temporal-validity.test.ts +160 -0
  92. package/src/__tests__/topic-tag.test.ts +113 -0
  93. package/src/__tests__/trusted-memory.test.ts +828 -0
  94. package/src/__tests__/write-verifier.test.ts +122 -0
  95. package/src/access-tracker.ts +3 -2
  96. package/src/activity-counter.ts +109 -0
  97. package/src/adaptive-retrieval.ts +6 -5
  98. package/src/admission-control.ts +163 -0
  99. package/src/anchor-generator.ts +80 -0
  100. package/src/api-server.ts +10 -0
  101. package/src/audit-log.ts +122 -0
  102. package/src/auto-gc.ts +98 -29
  103. package/src/auto-recall.ts +33 -4
  104. package/src/capture-engine.ts +372 -23
  105. package/src/cascade-forget.ts +3 -2
  106. package/src/cli.ts +107 -5
  107. package/src/compat.ts +22 -0
  108. package/src/confidence-tracker.ts +210 -47
  109. package/src/conflict-store.ts +12 -3
  110. package/src/consolidation-engine.ts +296 -8
  111. package/src/context-collapse-renderer.ts +222 -0
  112. package/src/context-composer-stable-selection.ts +5 -1
  113. package/src/context-composer.ts +239 -4
  114. package/src/context-reconstructor.ts +404 -0
  115. package/src/conversation-importer.ts +441 -0
  116. package/src/data-checkup.ts +232 -0
  117. package/src/decay-engine.ts +84 -0
  118. package/src/distill-lock.ts +122 -0
  119. package/src/doctor.ts +8 -10
  120. package/src/dream-pipeline.ts +227 -0
  121. package/src/emotion-detector.ts +90 -0
  122. package/src/eval.ts +3 -2
  123. package/src/forget-engine.ts +269 -0
  124. package/src/frequency-tracker.ts +175 -0
  125. package/src/graph-export.ts +644 -0
  126. package/src/ingest.ts +36 -6
  127. package/src/interference-detector.ts +187 -0
  128. package/src/kg-extractor.ts +15 -24
  129. package/src/kg-store.ts +2 -1
  130. package/src/language-hook.ts +67 -0
  131. package/src/llm-client.ts +289 -6
  132. package/src/mcp-server.ts +707 -80
  133. package/src/memory-assets.ts +22 -5
  134. package/src/memory-evolution.ts +365 -0
  135. package/src/memory-lint.ts +429 -0
  136. package/src/memory-output.ts +69 -0
  137. package/src/memory-schema.ts +74 -2
  138. package/src/narrative-schema.ts +79 -0
  139. package/src/narrative-tagger.ts +164 -0
  140. package/src/pii-detector.ts +98 -0
  141. package/src/post-retrieval-filter.ts +76 -0
  142. package/src/prediction-engine.ts +253 -0
  143. package/src/preference-slots.ts +65 -2
  144. package/src/prospective-memory.ts +215 -0
  145. package/src/query-expander.ts +67 -0
  146. package/src/recall-governor.ts +183 -0
  147. package/src/retention-policy.ts +90 -0
  148. package/src/retriever.ts +828 -55
  149. package/src/rif.ts +34 -8
  150. package/src/runtime-config.ts +23 -8
  151. package/src/scope-inventory.ts +4 -3
  152. package/src/scope-policy.ts +4 -0
  153. package/src/session-distiller.ts +307 -0
  154. package/src/session-output.ts +40 -0
  155. package/src/session-schema.ts +37 -0
  156. package/src/session-store.ts +7 -2
  157. package/src/skill-engine.ts +208 -0
  158. package/src/skill-promotion.ts +293 -0
  159. package/src/skill-schema.ts +39 -0
  160. package/src/store.ts +96 -10
  161. package/src/topic-tag.ts +66 -0
  162. package/src/tracker.ts +3 -1
  163. package/src/ui-server.ts +80 -8
  164. package/src/workflow-observation-scope-review.ts +2 -1
  165. package/src/workflow-observation-store.ts +2 -1
  166. package/src/write-verifier.ts +126 -0
@@ -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