@remnic/core 9.25.3 → 9.25.5
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/dist/access-admin-ops-surface.d.ts +3 -2
- package/dist/access-admin-ops-surface.js +9 -8
- package/dist/access-authorization-probe.d.ts +10 -3
- package/dist/access-authorization-probe.js +12 -9
- package/dist/access-boundary.d.ts +6 -3
- package/dist/access-boundary.js +13 -10
- package/dist/access-cli.js +42 -41
- package/dist/access-cli.js.map +1 -1
- package/dist/access-http.d.ts +3 -2
- package/dist/access-http.js +16 -15
- package/dist/access-identity-continuity-surface.d.ts +2 -1
- package/dist/access-identity-continuity-surface.js +9 -8
- package/dist/access-lcm-surface.d.ts +3 -2
- package/dist/access-lcm-surface.js +9 -8
- package/dist/access-mcp-output-schemas.js +1 -1
- package/dist/access-mcp.d.ts +3 -2
- package/dist/access-mcp.js +13 -12
- package/dist/access-namespace-preflight.js +9 -8
- package/dist/access-observe-write-surface.d.ts +3 -2
- package/dist/access-observe-write-surface.js +9 -8
- package/dist/access-operations-batch.js +10 -9
- package/dist/access-operations.d.ts +6 -5
- package/dist/access-operations.js +11 -10
- package/dist/access-recall-concurrency.d.ts +3 -2
- package/dist/access-recall-concurrency.js +9 -8
- package/dist/access-recall-response.d.ts +4 -2
- package/dist/access-recall-response.js +9 -8
- package/dist/access-recall-surface.d.ts +3 -2
- package/dist/access-recall-surface.js +9 -8
- package/dist/access-schema.d.ts +76 -76
- package/dist/{access-service-BlNKWBC9.d.ts → access-service-BJQ22URi.d.ts} +4 -1
- package/dist/access-service.d.ts +3 -2
- package/dist/access-service.js +9 -8
- package/dist/access-surface-catalog.d.ts +3 -2
- package/dist/bootstrap.d.ts +2 -1
- package/dist/briefing.js +3 -3
- package/dist/causal-consolidation.js +4 -4
- package/dist/{chunk-GF22HWS2.js → chunk-2PHX3I5C.js} +7 -7
- package/dist/{chunk-3I35RLJW.js → chunk-32XTXKIA.js} +14 -13
- package/dist/chunk-32XTXKIA.js.map +1 -0
- package/dist/{chunk-LXKJNUND.js → chunk-37VPMR4E.js} +2 -2
- package/dist/{chunk-3CDMIR3C.js → chunk-3CHQZVAL.js} +2 -2
- package/dist/{chunk-U37RGPJT.js → chunk-5J7HJ7RT.js} +2 -2
- package/dist/{chunk-AGR7MGUX.js → chunk-7IGWPXVC.js} +2 -2
- package/dist/{chunk-FIGDB2HR.js → chunk-7KXQ44PA.js} +2 -2
- package/dist/chunk-AHVEHR6K.js +82 -0
- package/dist/chunk-AHVEHR6K.js.map +1 -0
- package/dist/{chunk-MNLZGCM2.js → chunk-AQ2ZQYDI.js} +3 -3
- package/dist/{chunk-TWCOYET2.js → chunk-B6JDYXL7.js} +2 -1
- package/dist/chunk-B6JDYXL7.js.map +1 -0
- package/dist/{chunk-RROMWDDC.js → chunk-BL4JHZSO.js} +49 -12
- package/dist/chunk-BL4JHZSO.js.map +1 -0
- package/dist/{chunk-PXJ4A6IK.js → chunk-BUK2FXOL.js} +133 -105
- package/dist/chunk-BUK2FXOL.js.map +1 -0
- package/dist/{chunk-JMDZDT24.js → chunk-D7MAWMMK.js} +18 -4
- package/dist/chunk-D7MAWMMK.js.map +1 -0
- package/dist/{chunk-TG2DJFH7.js → chunk-E5A6C4A5.js} +20 -20
- package/dist/{chunk-NBT7O25Z.js → chunk-FR75B4UU.js} +82 -56
- package/dist/chunk-FR75B4UU.js.map +1 -0
- package/dist/{chunk-DPYYSG6F.js → chunk-G6MGAE36.js} +7 -7
- package/dist/{chunk-GNFZFJBJ.js → chunk-IR4LGIH6.js} +2 -2
- package/dist/{chunk-MPDX5QMH.js → chunk-JA4HEXV7.js} +2 -2
- package/dist/{chunk-XTAAG4SQ.js → chunk-K4DP5KZA.js} +6 -6
- package/dist/{chunk-AT6DNUCM.js → chunk-NY6W6CJW.js} +2 -2
- package/dist/{chunk-NMGO2HAZ.js → chunk-OIE242WM.js} +2 -2
- package/dist/{chunk-SZN6XVFC.js → chunk-PS5OG75R.js} +2 -2
- package/dist/{chunk-VY6SDKWZ.js → chunk-SSYBI43M.js} +2 -2
- package/dist/{chunk-IE4HB6O5.js → chunk-TPYZ727G.js} +3 -3
- package/dist/{chunk-5ZGWA4AG.js → chunk-UMFLAACL.js} +6 -6
- package/dist/{chunk-THHPDPMS.js → chunk-UOURUMBN.js} +2 -2
- package/dist/{chunk-6LRTGCRV.js → chunk-VPSAVXHM.js} +3 -3
- package/dist/{chunk-AL4TZWI3.js → chunk-W33DEUKR.js} +2 -2
- package/dist/{chunk-W4ZDTHWZ.js → chunk-WIGBTWXA.js} +2 -2
- package/dist/{chunk-NVYCTASB.js → chunk-WSEA52RI.js} +2 -2
- package/dist/{chunk-LARPWF3S.js → chunk-ZPUFQGUF.js} +4 -4
- package/dist/{cli-Zc6UclD1.d.ts → cli-1W7cNjJJ.d.ts} +2 -2
- package/dist/cli.d.ts +4 -3
- package/dist/cli.js +28 -27
- package/dist/compounding/engine.js +3 -3
- package/dist/connectors/codex-materialize-runner.js +3 -3
- package/dist/connectors/index.js +3 -3
- package/dist/corpus-watermark.js +5 -5
- package/dist/entity-retrieval.js +3 -3
- package/dist/explicit-capture.d.ts +2 -1
- package/dist/extraction.js +5 -1
- package/dist/{first-start-migration-LEXL3XYL.js → first-start-migration-BKNGOFED.js} +4 -4
- package/dist/index.d.ts +391 -390
- package/dist/index.js +74 -54
- package/dist/lcm/engine.js +3 -3
- package/dist/lcm/index.js +8 -8
- package/dist/maintenance/memory-governance.js +3 -3
- package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +3 -3
- package/dist/maintenance/rebuild-memory-projection.js +4 -4
- package/dist/mcp-memory-inspector-app.d.ts +3 -2
- package/dist/namespaces/migrate.js +4 -4
- package/dist/namespaces/storage.js +3 -3
- package/dist/operator-doctor-corpus.js +6 -6
- package/dist/operator-toolkit.js +9 -9
- package/dist/orchestration/maintenance.js +8 -8
- package/dist/{orchestrator-BTGgoKli.d.ts → orchestrator-BtA1wC5K.d.ts} +2 -0
- package/dist/orchestrator.d.ts +2 -1
- package/dist/orchestrator.js +42 -41
- package/dist/recall-context-composition.d.ts +30 -0
- package/dist/recall-context-composition.js +24 -0
- package/dist/recall-context-composition.js.map +1 -0
- package/dist/schemas.d.ts +54 -54
- package/dist/semantic-consolidation.js +4 -4
- package/dist/semantic-rule-promotion.js +3 -3
- package/dist/semantic-rule-verifier.js +3 -3
- package/dist/shared-context/manager.d.ts +8 -8
- package/dist/storage.js +2 -2
- package/dist/transfer/types.d.ts +66 -66
- package/dist/verified-recall.js +3 -3
- package/package.json +2 -2
- package/src/access-authorization-probe.ts +30 -1
- package/src/access-boundary.ts +21 -0
- package/src/access-http.test.ts +86 -1
- package/src/access-http.ts +6 -6
- package/src/access-mcp-output-schemas.ts +1 -0
- package/src/access-recall-response.ts +18 -13
- package/src/access-recall-surface.ts +11 -1
- package/src/access-service.ts +3 -0
- package/src/extraction-prompt-safety.test.ts +179 -0
- package/src/extraction.ts +186 -205
- package/src/index.ts +1 -1
- package/src/orchestration/orchestrator-helpers.ts +2 -0
- package/src/orchestration/recall-internal.ts +49 -49
- package/src/recall-context-composition.test.ts +90 -0
- package/src/recall-context-composition.ts +104 -0
- package/src/recall-curiosity-composition.test.ts +301 -0
- package/dist/chunk-3I35RLJW.js.map +0 -1
- package/dist/chunk-JMDZDT24.js.map +0 -1
- package/dist/chunk-NBT7O25Z.js.map +0 -1
- package/dist/chunk-PXJ4A6IK.js.map +0 -1
- package/dist/chunk-RROMWDDC.js.map +0 -1
- package/dist/chunk-TWCOYET2.js.map +0 -1
- /package/dist/{chunk-GF22HWS2.js.map → chunk-2PHX3I5C.js.map} +0 -0
- /package/dist/{chunk-LXKJNUND.js.map → chunk-37VPMR4E.js.map} +0 -0
- /package/dist/{chunk-3CDMIR3C.js.map → chunk-3CHQZVAL.js.map} +0 -0
- /package/dist/{chunk-U37RGPJT.js.map → chunk-5J7HJ7RT.js.map} +0 -0
- /package/dist/{chunk-AGR7MGUX.js.map → chunk-7IGWPXVC.js.map} +0 -0
- /package/dist/{chunk-FIGDB2HR.js.map → chunk-7KXQ44PA.js.map} +0 -0
- /package/dist/{chunk-MNLZGCM2.js.map → chunk-AQ2ZQYDI.js.map} +0 -0
- /package/dist/{chunk-TG2DJFH7.js.map → chunk-E5A6C4A5.js.map} +0 -0
- /package/dist/{chunk-DPYYSG6F.js.map → chunk-G6MGAE36.js.map} +0 -0
- /package/dist/{chunk-GNFZFJBJ.js.map → chunk-IR4LGIH6.js.map} +0 -0
- /package/dist/{chunk-MPDX5QMH.js.map → chunk-JA4HEXV7.js.map} +0 -0
- /package/dist/{chunk-XTAAG4SQ.js.map → chunk-K4DP5KZA.js.map} +0 -0
- /package/dist/{chunk-AT6DNUCM.js.map → chunk-NY6W6CJW.js.map} +0 -0
- /package/dist/{chunk-NMGO2HAZ.js.map → chunk-OIE242WM.js.map} +0 -0
- /package/dist/{chunk-SZN6XVFC.js.map → chunk-PS5OG75R.js.map} +0 -0
- /package/dist/{chunk-VY6SDKWZ.js.map → chunk-SSYBI43M.js.map} +0 -0
- /package/dist/{chunk-IE4HB6O5.js.map → chunk-TPYZ727G.js.map} +0 -0
- /package/dist/{chunk-5ZGWA4AG.js.map → chunk-UMFLAACL.js.map} +0 -0
- /package/dist/{chunk-THHPDPMS.js.map → chunk-UOURUMBN.js.map} +0 -0
- /package/dist/{chunk-6LRTGCRV.js.map → chunk-VPSAVXHM.js.map} +0 -0
- /package/dist/{chunk-AL4TZWI3.js.map → chunk-W33DEUKR.js.map} +0 -0
- /package/dist/{chunk-W4ZDTHWZ.js.map → chunk-WIGBTWXA.js.map} +0 -0
- /package/dist/{chunk-NVYCTASB.js.map → chunk-WSEA52RI.js.map} +0 -0
- /package/dist/{chunk-LARPWF3S.js.map → chunk-ZPUFQGUF.js.map} +0 -0
- /package/dist/{first-start-migration-LEXL3XYL.js.map → first-start-migration-BKNGOFED.js.map} +0 -0
|
@@ -48,6 +48,10 @@ import { buildProcedureRecallSection } from "../procedural/procedure-recall.js";
|
|
|
48
48
|
import { ProfilingCollector } from "../profiling.js";
|
|
49
49
|
import { buildQmdRecallCacheKey, getCachedQmdRecall, setCachedQmdRecall } from "../qmd-recall-cache.js";
|
|
50
50
|
import { MEMORY_ID_PATTERN } from "../recall-handles.js";
|
|
51
|
+
import {
|
|
52
|
+
boundRecallContextComposition, composeRecallContext, contextBudgetForFooter,
|
|
53
|
+
formatCuriosityFooter, selectCuriosityQuestion,
|
|
54
|
+
} from "../recall-context-composition.js";
|
|
51
55
|
import { createRecallSectionMetricRecorder } from "../recall-qos.js";
|
|
52
56
|
import { buildRecallQueryPolicy } from "../recall-query-policy.js";
|
|
53
57
|
import { type GraphRecallExpandedEntry, type LastRecallBudgetSummary, type LastRecallSnapshot, LastRecallStore, RecallHandleHistoryStore } from "../recall-state.js";
|
|
@@ -4405,7 +4409,6 @@ export class RecallInternalCoordinator {
|
|
|
4405
4409
|
success: !trustFellBack,
|
|
4406
4410
|
});
|
|
4407
4411
|
}
|
|
4408
|
-
|
|
4409
4412
|
// Synapse-inspired confidence gate: check scores BEFORE slicing so
|
|
4410
4413
|
// reranking doesn't affect which score the gate evaluates.
|
|
4411
4414
|
//
|
|
@@ -4445,7 +4448,6 @@ export class RecallInternalCoordinator {
|
|
|
4445
4448
|
confidenceGateRejected = true;
|
|
4446
4449
|
}
|
|
4447
4450
|
}
|
|
4448
|
-
|
|
4449
4451
|
// Diversify via MMR over the full candidate pool *before* truncating to
|
|
4450
4452
|
// the final recall limit. Running MMR after the slice would be unable
|
|
4451
4453
|
// to promote diverse candidates sitting just below the cutoff.
|
|
@@ -4456,7 +4458,6 @@ export class RecallInternalCoordinator {
|
|
|
4456
4458
|
retrievalQuery,
|
|
4457
4459
|
caps,
|
|
4458
4460
|
);
|
|
4459
|
-
|
|
4460
4461
|
// E-Mem-inspired memory reconstruction: fill gaps for referenced entities
|
|
4461
4462
|
if (resolveRecallEnhancementCapabilities(this.deps.config).memoryReconstruction && memoryResults.length > 0) {
|
|
4462
4463
|
try {
|
|
@@ -4499,7 +4500,6 @@ export class RecallInternalCoordinator {
|
|
|
4499
4500
|
log.warn("recall: memory reconstruction failed (non-fatal)", err);
|
|
4500
4501
|
}
|
|
4501
4502
|
}
|
|
4502
|
-
|
|
4503
4503
|
if (memoryResults.length > 0) {
|
|
4504
4504
|
if (shouldPersistGraphSnapshot) {
|
|
4505
4505
|
graphSnapshotFinalResults = this.deps.buildGraphRecallRankedResults(
|
|
@@ -4689,7 +4689,6 @@ export class RecallInternalCoordinator {
|
|
|
4689
4689
|
}
|
|
4690
4690
|
}
|
|
4691
4691
|
}
|
|
4692
|
-
|
|
4693
4692
|
if (globalResults.length > 0) {
|
|
4694
4693
|
this.deps.appendRecallSection(
|
|
4695
4694
|
sectionBuckets,
|
|
@@ -4697,7 +4696,6 @@ export class RecallInternalCoordinator {
|
|
|
4697
4696
|
this.deps.formatQmdResults("Workspace Context", globalResults, sessionKey, recallTrustByPath),
|
|
4698
4697
|
);
|
|
4699
4698
|
}
|
|
4700
|
-
|
|
4701
4699
|
recordRecallSectionMetric({
|
|
4702
4700
|
section: "qmdPost",
|
|
4703
4701
|
priority: "enrichment",
|
|
@@ -4706,7 +4704,6 @@ export class RecallInternalCoordinator {
|
|
|
4706
4704
|
source: "fresh",
|
|
4707
4705
|
success: true,
|
|
4708
4706
|
});
|
|
4709
|
-
|
|
4710
4707
|
// If the user is pushing back ("that's not right", "why did you say that"),
|
|
4711
4708
|
// gently suggest an explicit workflow to inspect what was recalled and record feedback.
|
|
4712
4709
|
// IMPORTANT: this is suggestion-only; never auto-mark negatives.
|
|
@@ -5026,7 +5023,6 @@ export class RecallInternalCoordinator {
|
|
|
5026
5023
|
success: !trustFellBack,
|
|
5027
5024
|
});
|
|
5028
5025
|
}
|
|
5029
|
-
|
|
5030
5026
|
if (recent.length > 0) {
|
|
5031
5027
|
if (shouldPersistGraphSnapshot) {
|
|
5032
5028
|
graphSnapshotFinalResults = this.deps.buildGraphRecallRankedResults(
|
|
@@ -5155,7 +5151,6 @@ export class RecallInternalCoordinator {
|
|
|
5155
5151
|
}
|
|
5156
5152
|
}
|
|
5157
5153
|
}
|
|
5158
|
-
|
|
5159
5154
|
if (isDisagreementPrompt(prompt)) {
|
|
5160
5155
|
this.deps.appendRecallSection(
|
|
5161
5156
|
sectionBuckets,
|
|
@@ -5174,7 +5169,6 @@ export class RecallInternalCoordinator {
|
|
|
5174
5169
|
);
|
|
5175
5170
|
}
|
|
5176
5171
|
}
|
|
5177
|
-
|
|
5178
5172
|
const phase2AfterQmdMs = Date.now() - recallStart;
|
|
5179
5173
|
if (shouldPersistGraphSnapshot) {
|
|
5180
5174
|
if (!graphSnapshotStatus) {
|
|
@@ -5211,7 +5205,6 @@ export class RecallInternalCoordinator {
|
|
|
5211
5205
|
storage: profileStorage,
|
|
5212
5206
|
snapshot: buildIntentDebugSnapshot(),
|
|
5213
5207
|
});
|
|
5214
|
-
|
|
5215
5208
|
// 2.5. Compression guideline recall section (v8.11 Task 5)
|
|
5216
5209
|
if (
|
|
5217
5210
|
this.deps.isRecallSectionEnabled(
|
|
@@ -5229,7 +5222,6 @@ export class RecallInternalCoordinator {
|
|
|
5229
5222
|
);
|
|
5230
5223
|
}
|
|
5231
5224
|
}
|
|
5232
|
-
|
|
5233
5225
|
// 3. Transcript/summaries/conversation/compounding are fetched in parallel above,
|
|
5234
5226
|
// then assembled here according to recallPipeline order.
|
|
5235
5227
|
if (transcriptSection) {
|
|
@@ -5264,28 +5256,22 @@ export class RecallInternalCoordinator {
|
|
|
5264
5256
|
compoundingSection,
|
|
5265
5257
|
);
|
|
5266
5258
|
}
|
|
5267
|
-
|
|
5268
|
-
|
|
5269
|
-
if (
|
|
5270
|
-
this.deps.config.injectQuestions &&
|
|
5259
|
+
let curiosityFooter: string | undefined, curiosityQuestionSelected = false, curiosityFooterTruncated = false;
|
|
5260
|
+
const topQuestion = this.deps.config.injectQuestions &&
|
|
5271
5261
|
this.deps.isRecallSectionEnabled("questions", true)
|
|
5272
|
-
|
|
5273
|
-
|
|
5274
|
-
|
|
5275
|
-
|
|
5276
|
-
|
|
5277
|
-
|
|
5278
|
-
|
|
5279
|
-
|
|
5280
|
-
|
|
5281
|
-
|
|
5282
|
-
|
|
5283
|
-
"questions",
|
|
5284
|
-
`## Open Question\n\nSomething I've been curious about: ${topQuestion.question}\n\n_Context: ${topQuestion.context}_`,
|
|
5285
|
-
);
|
|
5262
|
+
? selectCuriosityQuestion(await profileStorage.readQuestions({ unresolvedOnly: true }))
|
|
5263
|
+
: undefined;
|
|
5264
|
+
if (topQuestion) {
|
|
5265
|
+
curiosityQuestionSelected = true;
|
|
5266
|
+
const formattedFooter = formatCuriosityFooter(topQuestion);
|
|
5267
|
+
const questionMaxChars = this.deps.getRecallSectionMaxChars("questions");
|
|
5268
|
+
if (questionMaxChars !== 0) {
|
|
5269
|
+
curiosityFooter = typeof questionMaxChars === "number"
|
|
5270
|
+
? this.deps.truncateRecallSectionToBudget(formattedFooter, questionMaxChars)
|
|
5271
|
+
: formattedFooter;
|
|
5272
|
+
curiosityFooterTruncated = curiosityFooter.length < formattedFooter.length;
|
|
5286
5273
|
}
|
|
5287
5274
|
}
|
|
5288
|
-
|
|
5289
5275
|
const phase2QuestionsDoneMs = Date.now() - recallStart;
|
|
5290
5276
|
const finalizedQueryAwarePrefilter = await queryAwarePrefilterPromise;
|
|
5291
5277
|
const phase2QapDoneMs = Date.now() - recallStart;
|
|
@@ -5299,7 +5285,6 @@ export class RecallInternalCoordinator {
|
|
|
5299
5285
|
).length;
|
|
5300
5286
|
timings.queryAware = `${timings.queryAware};helped=${helpedCount}`;
|
|
5301
5287
|
}
|
|
5302
|
-
|
|
5303
5288
|
// --- Timing summary ---
|
|
5304
5289
|
timings.total = `${Date.now() - recallStart}ms`;
|
|
5305
5290
|
this.deps.profiler.endSpan("assembly", profileTraceId);
|
|
@@ -5318,10 +5303,9 @@ export class RecallInternalCoordinator {
|
|
|
5318
5303
|
recallPlan: timings.recallPlan,
|
|
5319
5304
|
queryPolicy: timings.queryPolicy,
|
|
5320
5305
|
});
|
|
5321
|
-
|
|
5306
|
+
const recallBudgetChars = this.deps.getRecallBudgetChars(options.budgetCharsOverride);
|
|
5322
5307
|
const assembledRecall = this.deps.assembleRecallSections(
|
|
5323
|
-
sectionBuckets,
|
|
5324
|
-
options.budgetCharsOverride,
|
|
5308
|
+
sectionBuckets, contextBudgetForFooter(recallBudgetChars, curiosityFooter),
|
|
5325
5309
|
);
|
|
5326
5310
|
recalledMemoryIds = assembledRecall.includedMemoryIds;
|
|
5327
5311
|
recalledMemoryPaths = assembledRecall.includedMemoryPaths;
|
|
@@ -5332,29 +5316,45 @@ export class RecallInternalCoordinator {
|
|
|
5332
5316
|
assembledRecall.includedMemoryPaths,
|
|
5333
5317
|
assembledRecall.includedMemoryNamespaces,
|
|
5334
5318
|
);
|
|
5335
|
-
const
|
|
5336
|
-
|
|
5337
|
-
|
|
5338
|
-
|
|
5339
|
-
const
|
|
5340
|
-
|
|
5341
|
-
|
|
5342
|
-
|
|
5319
|
+
const recalledContext = assembledRecall.sections.join("\n\n---\n\n");
|
|
5320
|
+
const composition = boundRecallContextComposition({
|
|
5321
|
+
context: recalledContext, footer: curiosityFooter, maxChars: recallBudgetChars,
|
|
5322
|
+
});
|
|
5323
|
+
const context = composeRecallContext(composition);
|
|
5324
|
+
try {
|
|
5325
|
+
const observerResult = options.onContextComposition?.(composition);
|
|
5326
|
+
if (observerResult && typeof observerResult.then === "function") {
|
|
5327
|
+
void Promise.resolve(observerResult).catch((err) => log.warn(
|
|
5328
|
+
"recall: context composition observer rejected", err,
|
|
5329
|
+
));
|
|
5330
|
+
}
|
|
5331
|
+
} catch (err) {
|
|
5332
|
+
log.warn("recall: context composition observer failed open", err);
|
|
5333
|
+
}
|
|
5334
|
+
const compositionTruncated = context.length < composeRecallContext({
|
|
5335
|
+
context: recalledContext, footer: curiosityFooter,
|
|
5336
|
+
}).length;
|
|
5337
|
+
const includedSections = [...assembledRecall.includedIds];
|
|
5338
|
+
const omittedSections = [...assembledRecall.omittedIds];
|
|
5339
|
+
if (composition.footer && !includedSections.includes("questions")) includedSections.push("questions");
|
|
5340
|
+
else if (!composition.footer && curiosityQuestionSelected && !omittedSections.includes("questions"))
|
|
5341
|
+
omittedSections.push("questions");
|
|
5342
|
+
const sourcesUsed = this.deps.collectLastRecallSources(sectionBuckets, recallSource);
|
|
5343
|
+
if (composition.footer && !sourcesUsed.includes("questions")) sourcesUsed.push("questions");
|
|
5343
5344
|
const budgetsApplied = this.deps.buildLastRecallBudgetSummary({
|
|
5344
5345
|
requestedTopK,
|
|
5345
5346
|
recallResultLimit,
|
|
5346
5347
|
qmdFetchLimit,
|
|
5347
5348
|
qmdHybridFetchLimit,
|
|
5348
|
-
finalContextChars:
|
|
5349
|
-
truncated: assembledRecall.truncated,
|
|
5350
|
-
includedSections
|
|
5351
|
-
omittedSections
|
|
5349
|
+
finalContextChars: context.length,
|
|
5350
|
+
truncated: assembledRecall.truncated || compositionTruncated || curiosityFooterTruncated,
|
|
5351
|
+
includedSections,
|
|
5352
|
+
omittedSections,
|
|
5352
5353
|
includedMemoryIds: assembledRecall.includedMemoryIds,
|
|
5353
5354
|
includedMemoryPaths: assembledRecall.includedMemoryPaths,
|
|
5354
5355
|
includedMemoryNamespaces: assembledRecall.includedMemoryNamespaces,
|
|
5355
5356
|
omittedMemoryIds: assembledRecall.omittedMemoryIds,
|
|
5356
5357
|
});
|
|
5357
|
-
|
|
5358
5358
|
// X-ray capture (issue #570 PR 1). Only fires when the caller
|
|
5359
5359
|
// explicitly opts in via `xrayCapture: true`. No behavior change
|
|
5360
5360
|
// when the flag is absent — this branch and the setter both
|
|
@@ -5535,7 +5535,7 @@ export class RecallInternalCoordinator {
|
|
|
5535
5535
|
filters,
|
|
5536
5536
|
budget: {
|
|
5537
5537
|
chars: this.deps.getRecallBudgetChars(options.budgetCharsOverride),
|
|
5538
|
-
used:
|
|
5538
|
+
used: context.length,
|
|
5539
5539
|
},
|
|
5540
5540
|
sessionKey,
|
|
5541
5541
|
namespace: selfNamespace,
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import assert from "node:assert/strict";
|
|
2
|
+
import test from "node:test";
|
|
3
|
+
|
|
4
|
+
import {
|
|
5
|
+
formatCuriosityFooter,
|
|
6
|
+
renderMemoryContextPrompt,
|
|
7
|
+
selectCuriosityQuestion,
|
|
8
|
+
} from "./recall-context-composition.js";
|
|
9
|
+
|
|
10
|
+
test("selectCuriosityQuestion breaks equal priorities by creation time then id", () => {
|
|
11
|
+
const selected = selectCuriosityQuestion([
|
|
12
|
+
{
|
|
13
|
+
id: "q-later",
|
|
14
|
+
question: "Later question?",
|
|
15
|
+
context: "later context",
|
|
16
|
+
priority: 0.9,
|
|
17
|
+
created: "2026-01-02T00:00:00.000Z",
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
id: "q-first-b",
|
|
21
|
+
question: "First B?",
|
|
22
|
+
context: "first context",
|
|
23
|
+
priority: 0.9,
|
|
24
|
+
created: "2026-01-01T00:00:00.000Z",
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
id: "q-first-a",
|
|
28
|
+
question: "First A?",
|
|
29
|
+
context: "first context",
|
|
30
|
+
priority: 0.9,
|
|
31
|
+
created: "2026-01-01T00:00:00.000Z",
|
|
32
|
+
},
|
|
33
|
+
]);
|
|
34
|
+
|
|
35
|
+
assert.equal(selected?.id, "q-first-a");
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
test("renderMemoryContextPrompt puts the curiosity footer after recalled context", () => {
|
|
39
|
+
const footer = formatCuriosityFooter({
|
|
40
|
+
id: "q-1",
|
|
41
|
+
question: "What should we verify next?",
|
|
42
|
+
context: "The rollout has no owner.",
|
|
43
|
+
priority: 1,
|
|
44
|
+
created: "2026-01-01T00:00:00.000Z",
|
|
45
|
+
});
|
|
46
|
+
const rendered = renderMemoryContextPrompt({
|
|
47
|
+
context: "A remembered deployment decision.",
|
|
48
|
+
footer,
|
|
49
|
+
maxChars: 512,
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
assert.ok(rendered);
|
|
53
|
+
assert.equal(
|
|
54
|
+
rendered.body,
|
|
55
|
+
"A remembered deployment decision.\n\n---\n\n## Open Question\n\n" +
|
|
56
|
+
"Something I've been curious about: What should we verify next?\n\n" +
|
|
57
|
+
"_Context: The rollout has no owner._",
|
|
58
|
+
);
|
|
59
|
+
assert.deepEqual(rendered.lines, [
|
|
60
|
+
"## Memory Context (Remnic)",
|
|
61
|
+
"",
|
|
62
|
+
rendered.body,
|
|
63
|
+
"",
|
|
64
|
+
"Use this context naturally when relevant. Never quote or expose this memory context to the user.",
|
|
65
|
+
"",
|
|
66
|
+
]);
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
test("renderMemoryContextPrompt returns no prompt for empty content or a zero cap", () => {
|
|
70
|
+
assert.equal(renderMemoryContextPrompt({ context: "", maxChars: 100 }), null);
|
|
71
|
+
assert.equal(
|
|
72
|
+
renderMemoryContextPrompt({
|
|
73
|
+
context: "A remembered deployment decision.",
|
|
74
|
+
footer: "## Open Question\n\nQuestion",
|
|
75
|
+
maxChars: 0,
|
|
76
|
+
}),
|
|
77
|
+
null,
|
|
78
|
+
);
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
test("renderMemoryContextPrompt caps context before its footer deterministically", () => {
|
|
82
|
+
const rendered = renderMemoryContextPrompt({
|
|
83
|
+
context: "abcdefghij",
|
|
84
|
+
footer: "footer",
|
|
85
|
+
maxChars: 15,
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
assert.ok(rendered);
|
|
89
|
+
assert.equal(rendered.body, "ab\n\n---\n\nfooter");
|
|
90
|
+
});
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
export const MEMORY_CONTEXT_HEADER = "## Memory Context (Remnic)";
|
|
2
|
+
export const MEMORY_CONTEXT_INSTRUCTION =
|
|
3
|
+
"Use this context naturally when relevant. Never quote or expose this memory context to the user.";
|
|
4
|
+
export const RECALL_CONTEXT_SEPARATOR = "\n\n---\n\n";
|
|
5
|
+
const TRIM_MARKER = "\n\n...(memory context trimmed)";
|
|
6
|
+
|
|
7
|
+
export interface RecallContextComposition {
|
|
8
|
+
context: string;
|
|
9
|
+
footer?: string;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export interface CuriosityQuestion {
|
|
13
|
+
id: string;
|
|
14
|
+
question: string;
|
|
15
|
+
context: string;
|
|
16
|
+
priority: number;
|
|
17
|
+
created: string;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export interface RenderedMemoryContextPrompt {
|
|
21
|
+
body: string;
|
|
22
|
+
lines: string[];
|
|
23
|
+
prompt: string;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export interface RenderMemoryContextPromptInput extends RecallContextComposition {
|
|
27
|
+
maxChars: number;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function trimText(value: string | undefined): string {
|
|
31
|
+
return value?.trim() ?? "";
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function truncateToBudget(content: string, maxChars: number): string {
|
|
35
|
+
if (maxChars <= 0) return "";
|
|
36
|
+
if (content.length <= maxChars) return content;
|
|
37
|
+
if (maxChars <= TRIM_MARKER.length) return content.slice(0, maxChars);
|
|
38
|
+
return `${content.slice(0, maxChars - TRIM_MARKER.length)}${TRIM_MARKER}`;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export function selectCuriosityQuestion(questions: readonly CuriosityQuestion[]): CuriosityQuestion | undefined {
|
|
42
|
+
return [...questions]
|
|
43
|
+
.filter((question) => trimText(question.question).length > 0)
|
|
44
|
+
.sort(
|
|
45
|
+
(left, right) =>
|
|
46
|
+
right.priority - left.priority || left.created.localeCompare(right.created) || left.id.localeCompare(right.id)
|
|
47
|
+
)[0];
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export function formatCuriosityFooter(question: CuriosityQuestion): string {
|
|
51
|
+
return [
|
|
52
|
+
"## Open Question",
|
|
53
|
+
"",
|
|
54
|
+
`Something I've been curious about: ${question.question}`,
|
|
55
|
+
"",
|
|
56
|
+
`_Context: ${question.context}_`,
|
|
57
|
+
].join("\n");
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export function contextBudgetForFooter(maxChars: number, footer?: string): number {
|
|
61
|
+
const normalizedFooter = trimText(footer);
|
|
62
|
+
if (maxChars <= 0 || normalizedFooter.length === 0) return Math.max(0, maxChars);
|
|
63
|
+
if (normalizedFooter.length + RECALL_CONTEXT_SEPARATOR.length >= maxChars) return 0;
|
|
64
|
+
return maxChars - normalizedFooter.length - RECALL_CONTEXT_SEPARATOR.length;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export function boundRecallContextComposition({
|
|
68
|
+
context: rawContext,
|
|
69
|
+
footer: rawFooter,
|
|
70
|
+
maxChars,
|
|
71
|
+
}: RenderMemoryContextPromptInput): RecallContextComposition {
|
|
72
|
+
if (!Number.isFinite(maxChars) || maxChars <= 0) return { context: "" };
|
|
73
|
+
|
|
74
|
+
const limit = Math.floor(maxChars);
|
|
75
|
+
const footer = trimText(rawFooter);
|
|
76
|
+
const context = truncateToBudget(trimText(rawContext), contextBudgetForFooter(limit, footer));
|
|
77
|
+
const boundedFooter = footer.length > limit ? truncateToBudget(footer, limit) : footer;
|
|
78
|
+
return { context, ...(boundedFooter ? { footer: boundedFooter } : {}) };
|
|
79
|
+
}
|
|
80
|
+
export function composeRecallContext(composition: RecallContextComposition): string {
|
|
81
|
+
const context = trimText(composition.context);
|
|
82
|
+
const footer = trimText(composition.footer);
|
|
83
|
+
if (context.length === 0) return footer;
|
|
84
|
+
if (footer.length === 0) return context;
|
|
85
|
+
return `${context}${RECALL_CONTEXT_SEPARATOR}${footer}`;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export function renderMemoryContextPrompt({
|
|
89
|
+
context: rawContext,
|
|
90
|
+
footer: rawFooter,
|
|
91
|
+
maxChars,
|
|
92
|
+
}: RenderMemoryContextPromptInput): RenderedMemoryContextPrompt | null {
|
|
93
|
+
const bounded = boundRecallContextComposition({
|
|
94
|
+
context: rawContext,
|
|
95
|
+
footer: rawFooter,
|
|
96
|
+
maxChars,
|
|
97
|
+
});
|
|
98
|
+
const body = composeRecallContext(bounded);
|
|
99
|
+
if (body.length === 0) return null;
|
|
100
|
+
|
|
101
|
+
const boundedBody = body.length <= maxChars ? body : truncateToBudget(bounded.footer || body, Math.floor(maxChars));
|
|
102
|
+
const lines = [MEMORY_CONTEXT_HEADER, "", boundedBody, "", MEMORY_CONTEXT_INSTRUCTION, ""];
|
|
103
|
+
return { body: boundedBody, lines, prompt: lines.join("\n").replace(/\n$/, "") };
|
|
104
|
+
}
|