@remnic/core 9.25.6 → 9.26.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/dist/access-admin-ops-surface.d.ts +2 -2
- package/dist/access-admin-ops-surface.js +41 -41
- package/dist/access-audit.js +2 -2
- package/dist/access-authorization-probe.d.ts +2 -2
- package/dist/access-authorization-probe.js +42 -42
- package/dist/access-boundary.d.ts +2 -2
- package/dist/access-boundary.js +41 -41
- package/dist/access-cli.js +98 -97
- package/dist/access-cli.js.map +1 -1
- package/dist/access-http-lcm-compaction.d.ts +130 -0
- package/dist/access-http-lcm-compaction.js +10 -0
- package/dist/access-http.d.ts +2 -2
- package/dist/access-http.js +53 -52
- package/dist/access-identity-continuity-surface.d.ts +1 -1
- package/dist/access-identity-continuity-surface.js +41 -41
- package/dist/access-lcm-surface.d.ts +2 -2
- package/dist/access-lcm-surface.js +41 -41
- package/dist/access-mcp.d.ts +2 -2
- package/dist/access-mcp.js +47 -47
- package/dist/access-namespace-preflight.js +41 -41
- package/dist/access-observe-write-surface.d.ts +2 -2
- package/dist/access-observe-write-surface.js +41 -41
- package/dist/access-operations-batch.js +43 -43
- package/dist/access-operations.d.ts +2 -2
- package/dist/access-operations.js +45 -45
- package/dist/access-recall-concurrency.d.ts +2 -2
- package/dist/access-recall-concurrency.js +41 -41
- package/dist/access-recall-response.d.ts +2 -2
- package/dist/access-recall-response.js +41 -41
- package/dist/access-recall-surface.d.ts +2 -2
- package/dist/access-recall-surface.js +41 -41
- package/dist/access-schema.d.ts +16 -1
- package/dist/access-schema.js +8 -8
- package/dist/{access-service-BJQ22URi.d.ts → access-service-DL8FJnTj.d.ts} +2 -2
- package/dist/access-service.d.ts +2 -2
- package/dist/access-service.js +41 -41
- package/dist/access-surface-catalog.d.ts +2 -2
- package/dist/adapters/index.js +7 -7
- package/dist/adapters/registry.js +3 -3
- package/dist/{auto-sync-5OE5QOZB.js → auto-sync-UPTUVE4X.js} +3 -3
- package/dist/bootstrap.d.ts +1 -1
- package/dist/briefing.js +5 -5
- package/dist/{capsule-crypto-7FJQINUR.js → capsule-crypto-YO5QJ6L3.js} +2 -2
- package/dist/capsule-crypto-YO5QJ6L3.js.map +1 -0
- package/dist/causal-behavior.js +2 -2
- package/dist/causal-chain.js +2 -2
- package/dist/causal-consolidation.js +11 -11
- package/dist/causal-retrieval.js +2 -2
- package/dist/causal-trajectory.js +1 -1
- package/dist/{chunk-JBPKEARU.js → chunk-2QSZNTDO.js} +7 -7
- package/dist/{chunk-BL4JHZSO.js → chunk-2XP3PWL3.js} +40 -40
- package/dist/{chunk-AQ2ZQYDI.js → chunk-4KKV7W62.js} +6 -6
- package/dist/chunk-4Z4XNEWZ.js +86 -0
- package/dist/chunk-4Z4XNEWZ.js.map +1 -0
- package/dist/{chunk-32XTXKIA.js → chunk-67DSDRUB.js} +22 -14
- package/dist/chunk-67DSDRUB.js.map +1 -0
- package/dist/{chunk-2PHX3I5C.js → chunk-6NNNURLK.js} +8 -8
- package/dist/{chunk-BLAKS3CP.js → chunk-77CNV7DY.js} +4 -4
- package/dist/{chunk-TVVEYCNW.js → chunk-7K5Q6COX.js} +4 -4
- package/dist/{chunk-227UFSEQ.js → chunk-7RZJWZ46.js} +5 -5
- package/dist/{chunk-WIGBTWXA.js → chunk-7XXCIO6X.js} +2 -2
- package/dist/{chunk-7CPOZH6Y.js → chunk-AJ7QCSIS.js} +2 -2
- package/dist/{chunk-2NLLXCJG.js → chunk-BXLOS5AJ.js} +2 -2
- package/dist/{chunk-X7Y7WX73.js → chunk-DQEMWVMT.js} +1 -1
- package/dist/{chunk-UMFLAACL.js → chunk-E6EAB4J6.js} +9 -9
- package/dist/{chunk-WSEA52RI.js → chunk-EXM2Q555.js} +2 -2
- package/dist/{chunk-G6MGAE36.js → chunk-F6LSNPPB.js} +5 -5
- package/dist/{chunk-7KXQ44PA.js → chunk-FE5FKTCI.js} +5 -5
- package/dist/{chunk-5J7HJ7RT.js → chunk-H2PBM562.js} +2 -2
- package/dist/{chunk-OIE242WM.js → chunk-HBVOJNV4.js} +3 -3
- package/dist/{chunk-PS5OG75R.js → chunk-IHMXPG4P.js} +2 -2
- package/dist/{chunk-3UOSVTFR.js → chunk-JCVQV6QX.js} +11 -11
- package/dist/{chunk-P25IPRXP.js → chunk-KGTD2KZJ.js} +28 -8
- package/dist/chunk-KGTD2KZJ.js.map +1 -0
- package/dist/{chunk-NY6W6CJW.js → chunk-KPWLZBXZ.js} +2 -2
- package/dist/{chunk-W33DEUKR.js → chunk-LIIQPDFN.js} +2 -2
- package/dist/{chunk-D7MAWMMK.js → chunk-M2KGXXTL.js} +2 -2
- package/dist/{chunk-UOURUMBN.js → chunk-MIFF37NN.js} +2 -2
- package/dist/{chunk-37VPMR4E.js → chunk-NKDVXEFU.js} +6 -6
- package/dist/{chunk-ZPUFQGUF.js → chunk-PQPSZICJ.js} +5 -5
- package/dist/{chunk-ES36HTSC.js → chunk-PTN6UAUA.js} +4 -4
- package/dist/{chunk-FR75B4UU.js → chunk-PX7VDW7R.js} +408 -721
- package/dist/chunk-PX7VDW7R.js.map +1 -0
- package/dist/{chunk-S2BBISHU.js → chunk-RYHWZ52A.js} +4 -4
- package/dist/{chunk-ZN4UZWMT.js → chunk-SK3EYPKC.js} +2 -2
- package/dist/{chunk-TPYZ727G.js → chunk-SN3ZESWQ.js} +6 -6
- package/dist/{chunk-BUK2FXOL.js → chunk-TKBDJTXG.js} +4 -4
- package/dist/{chunk-4B77XSG5.js → chunk-UV72DEZD.js} +5 -5
- package/dist/{chunk-K4DP5KZA.js → chunk-UZK7VVPD.js} +14 -14
- package/dist/{chunk-KQAFEZQX.js → chunk-VDX2J7OX.js} +2 -2
- package/dist/{chunk-SSYBI43M.js → chunk-VGEH3STZ.js} +6 -6
- package/dist/{chunk-NRV4Y3PM.js → chunk-W4FBGYGK.js} +1 -1
- package/dist/{chunk-IR4LGIH6.js → chunk-WMDRLTNA.js} +2 -2
- package/dist/{chunk-MU7ZHSZE.js → chunk-WZFAPHIK.js} +2 -2
- package/dist/{chunk-JA4HEXV7.js → chunk-XAAIUXJO.js} +2 -2
- package/dist/{chunk-VPSAVXHM.js → chunk-XNUBF6RF.js} +7 -7
- package/dist/{chunk-3CHQZVAL.js → chunk-Y6E37WRG.js} +5 -5
- package/dist/{chunk-E5A6C4A5.js → chunk-YN4AUGNF.js} +48 -48
- package/dist/{chunk-EZ25VE3G.js → chunk-YNDLCWXS.js} +4 -4
- package/dist/{chunk-7IGWPXVC.js → chunk-ZHP4SUPB.js} +2 -2
- package/dist/{cli-1W7cNjJJ.d.ts → cli-BoouX6LX.d.ts} +2 -2
- package/dist/cli.d.ts +3 -3
- package/dist/cli.js +75 -74
- package/dist/compounding/engine.js +5 -5
- package/dist/connectors/codex-materialize-runner.js +5 -5
- package/dist/connectors/index.js +5 -5
- package/dist/conversation-index/backend.js +2 -2
- package/dist/corpus-watermark.js +16 -16
- package/dist/dashboard-runtime.js +2 -2
- package/dist/entity-retrieval.js +5 -5
- package/dist/explicit-capture.d.ts +1 -1
- package/dist/extraction.js +3 -3
- package/dist/{first-start-migration-BKNGOFED.js → first-start-migration-LEXL3XYL.js} +4 -4
- package/dist/index.d.ts +4 -4
- package/dist/index.js +177 -176
- package/dist/lcm/engine.js +3 -3
- package/dist/lcm/index.js +9 -9
- package/dist/maintenance/memory-governance.js +6 -6
- package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +5 -5
- package/dist/maintenance/rebuild-memory-projection.js +7 -7
- package/dist/mcp-memory-inspector-app.d.ts +2 -2
- package/dist/namespaces/migrate.js +15 -15
- package/dist/namespaces/search.js +9 -9
- package/dist/namespaces/storage.js +5 -5
- package/dist/operator-doctor-corpus.js +17 -17
- package/dist/operator-toolkit.js +28 -28
- package/dist/orchestration/maintenance.js +11 -11
- package/dist/{orchestrator-BtA1wC5K.d.ts → orchestrator-CFJ_TG6D.d.ts} +15 -10
- package/dist/orchestrator.d.ts +1 -1
- package/dist/orchestrator.js +98 -97
- package/dist/resume-bundles.js +1 -1
- package/dist/search/factory.js +8 -8
- package/dist/search/index.js +13 -13
- package/dist/search/lancedb-backend.js +2 -2
- package/dist/search/meilisearch-backend.js +2 -2
- package/dist/search/orama-backend.js +2 -2
- package/dist/semantic-consolidation.js +7 -7
- package/dist/semantic-rule-promotion.js +5 -5
- package/dist/semantic-rule-verifier.js +6 -6
- package/dist/session-namespace-bindings.d.ts +27 -0
- package/dist/session-namespace-bindings.js +243 -0
- package/dist/session-namespace-bindings.js.map +1 -0
- package/dist/storage.js +4 -4
- package/dist/testing/lifecycle-matrix.d.ts +100 -0
- package/dist/testing/lifecycle-matrix.js +149 -0
- package/dist/testing/lifecycle-matrix.js.map +1 -0
- package/dist/transfer/backup.js +4 -4
- package/dist/transfer/capsule-export.js +4 -4
- package/dist/transfer/capsule-import.js +3 -3
- package/dist/verified-recall.js +6 -6
- package/package.json +22 -2
- package/src/access-http-lcm-compaction.ts +116 -0
- package/src/access-http.test.ts +218 -0
- package/src/access-http.ts +8 -8
- package/src/access-schema-pi.test.ts +9 -0
- package/src/access-schema.ts +29 -4
- package/src/access-surface-catalog.test.ts +1 -0
- package/src/meetings/recall-exclusion.test.ts +4 -2
- package/src/orchestration/generic-recall-paths.ts +119 -0
- package/src/orchestration/namespace-read-fanout.ts +0 -12
- package/src/orchestration/orchestrator-helpers.ts +0 -35
- package/src/orchestration/recall-internal.ts +6 -6
- package/src/orchestration/recall-search-pipeline.test.ts +194 -28
- package/src/orchestration/recall-search-pipeline.ts +39 -89
- package/src/orchestrator.ts +5 -17
- package/src/recall-cold-deadline.test.ts +11 -13
- package/src/session-namespace-bindings.test.ts +358 -0
- package/src/session-namespace-bindings.ts +301 -0
- package/src/testing/lifecycle-matrix.ts +17 -7
- package/src/testing/subjects/generic-recall-paths.test.ts +157 -0
- package/dist/chunk-32XTXKIA.js.map +0 -1
- package/dist/chunk-FR75B4UU.js.map +0 -1
- package/dist/chunk-P25IPRXP.js.map +0 -1
- package/src/recall/archive-scoring.ts +0 -544
- /package/dist/{capsule-crypto-7FJQINUR.js.map → access-http-lcm-compaction.js.map} +0 -0
- /package/dist/{auto-sync-5OE5QOZB.js.map → auto-sync-UPTUVE4X.js.map} +0 -0
- /package/dist/{chunk-JBPKEARU.js.map → chunk-2QSZNTDO.js.map} +0 -0
- /package/dist/{chunk-BL4JHZSO.js.map → chunk-2XP3PWL3.js.map} +0 -0
- /package/dist/{chunk-AQ2ZQYDI.js.map → chunk-4KKV7W62.js.map} +0 -0
- /package/dist/{chunk-2PHX3I5C.js.map → chunk-6NNNURLK.js.map} +0 -0
- /package/dist/{chunk-BLAKS3CP.js.map → chunk-77CNV7DY.js.map} +0 -0
- /package/dist/{chunk-TVVEYCNW.js.map → chunk-7K5Q6COX.js.map} +0 -0
- /package/dist/{chunk-227UFSEQ.js.map → chunk-7RZJWZ46.js.map} +0 -0
- /package/dist/{chunk-WIGBTWXA.js.map → chunk-7XXCIO6X.js.map} +0 -0
- /package/dist/{chunk-7CPOZH6Y.js.map → chunk-AJ7QCSIS.js.map} +0 -0
- /package/dist/{chunk-2NLLXCJG.js.map → chunk-BXLOS5AJ.js.map} +0 -0
- /package/dist/{chunk-X7Y7WX73.js.map → chunk-DQEMWVMT.js.map} +0 -0
- /package/dist/{chunk-UMFLAACL.js.map → chunk-E6EAB4J6.js.map} +0 -0
- /package/dist/{chunk-WSEA52RI.js.map → chunk-EXM2Q555.js.map} +0 -0
- /package/dist/{chunk-G6MGAE36.js.map → chunk-F6LSNPPB.js.map} +0 -0
- /package/dist/{chunk-7KXQ44PA.js.map → chunk-FE5FKTCI.js.map} +0 -0
- /package/dist/{chunk-5J7HJ7RT.js.map → chunk-H2PBM562.js.map} +0 -0
- /package/dist/{chunk-OIE242WM.js.map → chunk-HBVOJNV4.js.map} +0 -0
- /package/dist/{chunk-PS5OG75R.js.map → chunk-IHMXPG4P.js.map} +0 -0
- /package/dist/{chunk-3UOSVTFR.js.map → chunk-JCVQV6QX.js.map} +0 -0
- /package/dist/{chunk-NY6W6CJW.js.map → chunk-KPWLZBXZ.js.map} +0 -0
- /package/dist/{chunk-W33DEUKR.js.map → chunk-LIIQPDFN.js.map} +0 -0
- /package/dist/{chunk-D7MAWMMK.js.map → chunk-M2KGXXTL.js.map} +0 -0
- /package/dist/{chunk-UOURUMBN.js.map → chunk-MIFF37NN.js.map} +0 -0
- /package/dist/{chunk-37VPMR4E.js.map → chunk-NKDVXEFU.js.map} +0 -0
- /package/dist/{chunk-ZPUFQGUF.js.map → chunk-PQPSZICJ.js.map} +0 -0
- /package/dist/{chunk-ES36HTSC.js.map → chunk-PTN6UAUA.js.map} +0 -0
- /package/dist/{chunk-S2BBISHU.js.map → chunk-RYHWZ52A.js.map} +0 -0
- /package/dist/{chunk-ZN4UZWMT.js.map → chunk-SK3EYPKC.js.map} +0 -0
- /package/dist/{chunk-TPYZ727G.js.map → chunk-SN3ZESWQ.js.map} +0 -0
- /package/dist/{chunk-BUK2FXOL.js.map → chunk-TKBDJTXG.js.map} +0 -0
- /package/dist/{chunk-4B77XSG5.js.map → chunk-UV72DEZD.js.map} +0 -0
- /package/dist/{chunk-K4DP5KZA.js.map → chunk-UZK7VVPD.js.map} +0 -0
- /package/dist/{chunk-KQAFEZQX.js.map → chunk-VDX2J7OX.js.map} +0 -0
- /package/dist/{chunk-SSYBI43M.js.map → chunk-VGEH3STZ.js.map} +0 -0
- /package/dist/{chunk-NRV4Y3PM.js.map → chunk-W4FBGYGK.js.map} +0 -0
- /package/dist/{chunk-IR4LGIH6.js.map → chunk-WMDRLTNA.js.map} +0 -0
- /package/dist/{chunk-MU7ZHSZE.js.map → chunk-WZFAPHIK.js.map} +0 -0
- /package/dist/{chunk-JA4HEXV7.js.map → chunk-XAAIUXJO.js.map} +0 -0
- /package/dist/{chunk-VPSAVXHM.js.map → chunk-XNUBF6RF.js.map} +0 -0
- /package/dist/{chunk-3CHQZVAL.js.map → chunk-Y6E37WRG.js.map} +0 -0
- /package/dist/{chunk-E5A6C4A5.js.map → chunk-YN4AUGNF.js.map} +0 -0
- /package/dist/{chunk-EZ25VE3G.js.map → chunk-YNDLCWXS.js.map} +0 -0
- /package/dist/{chunk-7IGWPXVC.js.map → chunk-ZHP4SUPB.js.map} +0 -0
- /package/dist/{first-start-migration-BKNGOFED.js.map → first-start-migration-LEXL3XYL.js.map} +0 -0
|
@@ -28,7 +28,6 @@ import { NamespaceStorageRouter } from "../namespaces/storage.js";
|
|
|
28
28
|
import { NegativeExampleStore } from "../negative.js";
|
|
29
29
|
import { qmdCollectionPathParts } from "./qmd-result-resolver.js";
|
|
30
30
|
import type { GraphRecallExpandedEntry } from "../recall-state.js";
|
|
31
|
-
import { getDefaultArchiveScoring, memoryFileToScoreItem } from "../recall/archive-scoring.js";
|
|
32
31
|
import { RelevanceStore } from "../relevance.js";
|
|
33
32
|
import { RerankCache, rerankLocalOrNoop, reorderByRankedKeys } from "../rerank.js";
|
|
34
33
|
import type { SearchBackend, SearchDegradation, SearchExecutionOptions, SearchQueryOptions } from "../search/port.js";
|
|
@@ -55,11 +54,11 @@ import {
|
|
|
55
54
|
computeQmdHybridFetchLimit,
|
|
56
55
|
filterRecallCandidates,
|
|
57
56
|
throwIfRecallAborted,
|
|
58
|
-
tokenizeRecallQuery,
|
|
59
57
|
type QmdRecallSnapshot,
|
|
60
58
|
type QueryAwarePrefilter,
|
|
61
59
|
} from "../orchestrator.js";
|
|
62
|
-
import { isActivityDigestPath
|
|
60
|
+
import { isActivityDigestPath } from "./orchestrator-helpers.js";
|
|
61
|
+
import { isGenericRecallExcludedPath, isTopLevelArchivePath } from "./generic-recall-paths.js";
|
|
63
62
|
|
|
64
63
|
export interface RecallSearchPipelineDeps {
|
|
65
64
|
applyMemoryWorthRerank(
|
|
@@ -185,7 +184,6 @@ export interface RecallSearchPipelineDeps {
|
|
|
185
184
|
namespaceFromPath(p: string): string;
|
|
186
185
|
readonly negatives: NegativeExampleStore;
|
|
187
186
|
readonly qmd: SearchBackend;
|
|
188
|
-
readArchivedMemoriesForNamespaces(namespaces: string[]): Promise<MemoryFile[]>;
|
|
189
187
|
readQmdResultMemory(
|
|
190
188
|
resultPath: string,
|
|
191
189
|
fallbackStorage: StorageManager,
|
|
@@ -215,9 +213,8 @@ export interface RecallSearchPipelineDeps {
|
|
|
215
213
|
searchOptions?: SearchQueryOptions;
|
|
216
214
|
execution?: SearchExecutionOptions;
|
|
217
215
|
}): Promise<QmdSearchResult[]>;
|
|
218
|
-
|
|
216
|
+
searchQueryAwareFallback(
|
|
219
217
|
prompt: string,
|
|
220
|
-
recallNamespaces: string[],
|
|
221
218
|
limit: number,
|
|
222
219
|
queryAwarePrefilter?: QueryAwarePrefilter,
|
|
223
220
|
abortSignal?: AbortSignal,
|
|
@@ -422,26 +419,19 @@ export class RecallSearchPipelineCoordinator {
|
|
|
422
419
|
? await this.deps.searchScopedMemoryCandidates(
|
|
423
420
|
queryAwarePrefilter.candidatePaths,
|
|
424
421
|
prompt,
|
|
425
|
-
//
|
|
426
|
-
// exclusion `filterRecallCandidates` applies below (L464). Capping to
|
|
427
|
-
// `qmdFetchLimit` here lets excluded paths (artifacts, activity digests,
|
|
428
|
-
// meeting records) consume the caller's budget and drop legitimate hits
|
|
429
|
-
// with no refill — the hot-path mirror of the archive-fallback fix. The
|
|
430
|
-
// candidate set is an already-bounded prefilter, so its size is the
|
|
431
|
-
// natural ceiling; the post-exclusion cap is applied by filterRecallCandidates.
|
|
422
|
+
// Exclude dedicated surfaces before capping the bounded prefilter set.
|
|
432
423
|
queryAwarePrefilter.candidatePaths.size,
|
|
433
424
|
{ allowArchived: options.collection !== undefined },
|
|
434
425
|
)
|
|
435
426
|
: [];
|
|
436
427
|
// Drop generic-recall-excluded records before the fetchLimit cap so they can't starve valid memories (#1995).
|
|
437
|
-
const recallable = (r: QmdSearchResult) => !isGenericRecallExcludedPath(r.path, this.deps.config
|
|
428
|
+
const recallable = (r: QmdSearchResult) => !isGenericRecallExcludedPath(r.path, this.deps.config, "qmd");
|
|
438
429
|
|
|
439
430
|
let fetchLimit = Math.max(qmdFetchLimit, qmdHybridFetchLimit);
|
|
440
431
|
const maxFetchLimit = Math.min(
|
|
441
432
|
320,
|
|
442
433
|
Math.max(fetchLimit, qmdFetchLimit * 5),
|
|
443
434
|
);
|
|
444
|
-
const MAX_ATTEMPTS = 2;
|
|
445
435
|
const qmdRecallBudgetMs = this.deps.config.recallEnrichmentDeadlineMs ?? 25_000;
|
|
446
436
|
const qmdRecallBudgetEnabled = qmdRecallBudgetMs > 0;
|
|
447
437
|
const startedAtMs = Date.now();
|
|
@@ -475,7 +465,7 @@ export class RecallSearchPipelineCoordinator {
|
|
|
475
465
|
recallNamespaces: options.recallNamespaces,
|
|
476
466
|
resolveNamespace: options.resolveNamespace,
|
|
477
467
|
limit: qmdFetchLimit,
|
|
478
|
-
|
|
468
|
+
pathPolicy: this.deps.config,
|
|
479
469
|
});
|
|
480
470
|
const emitDebugSnapshot = async (
|
|
481
471
|
results: QmdSearchResult[],
|
|
@@ -508,7 +498,7 @@ export class RecallSearchPipelineCoordinator {
|
|
|
508
498
|
return [];
|
|
509
499
|
}
|
|
510
500
|
|
|
511
|
-
for (
|
|
501
|
+
for (;;) {
|
|
512
502
|
throwIfRecallAborted(options.abortSignal);
|
|
513
503
|
if (
|
|
514
504
|
qmdRecallBudgetEnabled &&
|
|
@@ -554,10 +544,15 @@ export class RecallSearchPipelineCoordinator {
|
|
|
554
544
|
lastHybridTopUpUsed = false;
|
|
555
545
|
lastHybridTopUpSkippedReason = undefined;
|
|
556
546
|
let mergedResults = primaryResults;
|
|
547
|
+
const primaryRecallableCount = primaryResults.filter(recallable).length;
|
|
548
|
+
const primaryIncludesArchivePath = primaryResults.some((result) =>
|
|
549
|
+
isTopLevelArchivePath(result.path, this.deps.config, "qmd"),
|
|
550
|
+
);
|
|
557
551
|
|
|
558
|
-
// Backfill with hybrid results
|
|
552
|
+
// Backfill with hybrid results when the recallable primary page underfills.
|
|
559
553
|
if (
|
|
560
|
-
|
|
554
|
+
primaryRecallableCount < qmdFetchLimit &&
|
|
555
|
+
(primaryResults.length < qmdFetchLimit || primaryIncludesArchivePath) &&
|
|
561
556
|
(!qmdRecallBudgetEnabled ||
|
|
562
557
|
Date.now() - startedAtMs < qmdRecallBudgetMs)
|
|
563
558
|
) {
|
|
@@ -620,7 +615,7 @@ export class RecallSearchPipelineCoordinator {
|
|
|
620
615
|
recallNamespaces: options.recallNamespaces,
|
|
621
616
|
resolveNamespace: options.resolveNamespace,
|
|
622
617
|
limit: fetchLimit,
|
|
623
|
-
|
|
618
|
+
pathPolicy: this.deps.config,
|
|
624
619
|
});
|
|
625
620
|
|
|
626
621
|
if (filteredResults.length >= qmdFetchLimit) {
|
|
@@ -631,11 +626,9 @@ export class RecallSearchPipelineCoordinator {
|
|
|
631
626
|
if (filteredResults.length > bestFiltered.length) {
|
|
632
627
|
bestFiltered = filteredResults;
|
|
633
628
|
}
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
}
|
|
638
|
-
if (mergedResults.length < fetchLimit && filteredResults.length > 0) {
|
|
629
|
+
// A full raw page may filter down to nothing (for example, archive-only
|
|
630
|
+
// hits). Keep widening until the backend itself underfills the page.
|
|
631
|
+
if (primaryResults.length < fetchLimit) {
|
|
639
632
|
await emitDebugSnapshot(filteredResults, fetchLimit);
|
|
640
633
|
return filteredResults;
|
|
641
634
|
}
|
|
@@ -679,20 +672,18 @@ export class RecallSearchPipelineCoordinator {
|
|
|
679
672
|
}
|
|
680
673
|
|
|
681
674
|
/**
|
|
682
|
-
*
|
|
683
|
-
*
|
|
675
|
+
* Cold fallback retains qualifying query-aware candidates. Archive records
|
|
676
|
+
* belong to dedicated surfaces and never re-enter generic recall.
|
|
684
677
|
*/
|
|
685
|
-
async
|
|
678
|
+
async searchQueryAwareFallback(
|
|
686
679
|
prompt: string,
|
|
687
|
-
recallNamespaces: string[],
|
|
688
680
|
limit: number,
|
|
689
681
|
queryAwarePrefilter?: QueryAwarePrefilter,
|
|
690
682
|
abortSignal?: AbortSignal,
|
|
691
683
|
): Promise<QmdSearchResult[]> {
|
|
692
684
|
throwIfRecallAborted(abortSignal);
|
|
693
685
|
const cappedLimit = Math.max(0, limit);
|
|
694
|
-
if (cappedLimit === 0) return [];
|
|
695
|
-
if (queryAwarePrefilter?.candidatePaths?.size === 0) return [];
|
|
686
|
+
if (cappedLimit === 0 || queryAwarePrefilter?.candidatePaths?.size === 0) return [];
|
|
696
687
|
|
|
697
688
|
const candidatePaths = queryAwarePrefilter?.candidatePaths;
|
|
698
689
|
const scopedSeedResults = (
|
|
@@ -700,57 +691,12 @@ export class RecallSearchPipelineCoordinator {
|
|
|
700
691
|
? await this.deps.searchScopedMemoryCandidates(
|
|
701
692
|
candidatePaths,
|
|
702
693
|
prompt,
|
|
703
|
-
// Overfetch the FULL scoped candidate set BEFORE the generic-recall
|
|
704
|
-
// exclusion below. Capping to `cappedLimit` first lets excluded paths
|
|
705
|
-
// (artifacts, activity digests, meeting records) consume the caller's
|
|
706
|
-
// budget and drop legitimate hits with no refill — e.g. a prefilter of
|
|
707
|
-
// [meetingRecord, facts/a.md] at limit 1 would return nothing. The
|
|
708
|
-
// candidate set is an already-bounded prefilter, so its size is the
|
|
709
|
-
// natural ceiling; the post-exclusion cap is applied below.
|
|
710
694
|
candidatePaths.size,
|
|
711
695
|
{ allowArchived: true },
|
|
712
696
|
)
|
|
713
697
|
: []
|
|
714
|
-
).filter((result) => !isGenericRecallExcludedPath(result.path, this.deps.config
|
|
715
|
-
|
|
716
|
-
// excluded above AFTER an unconstrained candidate fetch, so the cap here counts
|
|
717
|
-
// only recallable seeds — and EVERY early-return / direct-caller path below
|
|
718
|
-
// returns already-filtered, budget-honoring seeds.
|
|
719
|
-
if (scopedSeedResults.length >= cappedLimit) {
|
|
720
|
-
return scopedSeedResults.slice(0, cappedLimit);
|
|
721
|
-
}
|
|
722
|
-
|
|
723
|
-
const tokens = Array.from(new Set(tokenizeRecallQuery(prompt)));
|
|
724
|
-
if (tokens.length === 0) return scopedSeedResults;
|
|
725
|
-
|
|
726
|
-
throwIfRecallAborted(abortSignal);
|
|
727
|
-
const archivedMemories =
|
|
728
|
-
await this.deps.readArchivedMemoriesForNamespaces(recallNamespaces);
|
|
729
|
-
if (archivedMemories.length === 0) return scopedSeedResults;
|
|
730
|
-
|
|
731
|
-
// Issue #1674: off-load the CPU-bound archive-scoring loop to a
|
|
732
|
-
// worker_threads pool so concurrent recall requests run on separate
|
|
733
|
-
// cores instead of serializing on the main JS thread. The pure scoring
|
|
734
|
-
// function is identical to the old inline loop — only the execution
|
|
735
|
-
// context changed. Aborts are checked at the boundaries (before submit
|
|
736
|
-
// and after result); the worker's work is bounded by the file count.
|
|
737
|
-
throwIfRecallAborted(abortSignal);
|
|
738
|
-
const scoring = getDefaultArchiveScoring();
|
|
739
|
-
const scoredResults = await scoring.score(archivedMemories.map(memoryFileToScoreItem), tokens, abortSignal);
|
|
740
|
-
throwIfRecallAborted(abortSignal);
|
|
741
|
-
const scored: QmdSearchResult[] = scoredResults.map((r) => ({
|
|
742
|
-
docid: r.docid,
|
|
743
|
-
path: r.path,
|
|
744
|
-
score: r.score,
|
|
745
|
-
snippet: r.snippet,
|
|
746
|
-
}));
|
|
747
|
-
|
|
748
|
-
return dedupeResultsByNamespace(
|
|
749
|
-
[...scopedSeedResults, ...scored],
|
|
750
|
-
this.deps.namespaceFromPath,
|
|
751
|
-
cappedLimit,
|
|
752
|
-
{ filter: (result) => !isGenericRecallExcludedPath(result.path, this.deps.config.memoryDir) },
|
|
753
|
-
);
|
|
698
|
+
).filter((result) => !isGenericRecallExcludedPath(result.path, this.deps.config, "qmd"));
|
|
699
|
+
return scopedSeedResults.slice(0, cappedLimit);
|
|
754
700
|
}
|
|
755
701
|
|
|
756
702
|
async applyColdFallbackPipeline(options: {
|
|
@@ -935,17 +881,19 @@ export class RecallSearchPipelineCoordinator {
|
|
|
935
881
|
}
|
|
936
882
|
}
|
|
937
883
|
if (longTerm.length === 0) {
|
|
938
|
-
// The archive-scan scoring worker terminates when EITHER the caller
|
|
939
|
-
// aborts or this step's own deadline wins — both flow through the
|
|
940
|
-
// step signal injected by runColdStepWithinDeadline (#1674, #1907).
|
|
941
884
|
longTerm = await runColdStepWithinDeadline(
|
|
942
|
-
"
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
885
|
+
"query-aware fallback",
|
|
886
|
+
[],
|
|
887
|
+
(stepSignal) =>
|
|
888
|
+
this.deps.searchQueryAwareFallback(
|
|
889
|
+
options.prompt,
|
|
890
|
+
options.recallResultLimit,
|
|
891
|
+
options.queryAwarePrefilter,
|
|
892
|
+
stepSignal,
|
|
893
|
+
),
|
|
946
894
|
);
|
|
947
895
|
if (longTerm.length > 0) {
|
|
948
|
-
log.debug("cold-tier recall source=
|
|
896
|
+
log.debug("cold-tier recall source=query-aware-fallback");
|
|
949
897
|
}
|
|
950
898
|
}
|
|
951
899
|
if (longTerm.length === 0) return [];
|
|
@@ -997,9 +945,8 @@ export class RecallSearchPipelineCoordinator {
|
|
|
997
945
|
}
|
|
998
946
|
results = scopedResults;
|
|
999
947
|
}
|
|
1000
|
-
// Dedicated-surface isolation
|
|
1001
|
-
|
|
1002
|
-
results = results.filter((r) => !isGenericRecallExcludedPath(r.path, this.deps.config.memoryDir));
|
|
948
|
+
// Dedicated-surface isolation keeps generic recall out of artifacts, activity digests, and archives.
|
|
949
|
+
results = results.filter((r) => !isGenericRecallExcludedPath(r.path, this.deps.config, "qmd"));
|
|
1003
950
|
if (results.length === 0) return [];
|
|
1004
951
|
|
|
1005
952
|
const isFullModeGraphAssist =
|
|
@@ -1022,6 +969,9 @@ export class RecallSearchPipelineCoordinator {
|
|
|
1022
969
|
});
|
|
1023
970
|
results = merged;
|
|
1024
971
|
}
|
|
972
|
+
results = results.filter(
|
|
973
|
+
(result) => !isGenericRecallExcludedPath(result.path, this.deps.config, "qmd"),
|
|
974
|
+
);
|
|
1025
975
|
|
|
1026
976
|
const boostInput = await this.deps.filterSearchResultsForRecall(
|
|
1027
977
|
results,
|
package/src/orchestrator.ts
CHANGED
|
@@ -134,11 +134,11 @@ import {
|
|
|
134
134
|
computeSemanticDedupScope,
|
|
135
135
|
qmdCollectionNamespaceFromPrefix as computeQmdCollectionNamespaceFromPrefix,
|
|
136
136
|
} from "./orchestration/orchestrator-namespace-scope.js";
|
|
137
|
+
import { isGenericRecallExcludedPath } from "./orchestration/generic-recall-paths.js";
|
|
137
138
|
import {
|
|
138
139
|
abortRecallError,
|
|
139
140
|
buildCompressionGuidelinesMarkdown,
|
|
140
141
|
buildQmdIntentHint,
|
|
141
|
-
isGenericRecallExcludedPath,
|
|
142
142
|
mergeArtifactRecallCandidates,
|
|
143
143
|
tokenizeRecallQuery,
|
|
144
144
|
type BulkImportBatchIngestResult,
|
|
@@ -163,7 +163,6 @@ export {
|
|
|
163
163
|
computeQmdHybridFetchLimit,
|
|
164
164
|
defaultWorkspaceDir,
|
|
165
165
|
filterHourlySummaryMarkdownForLocalDay,
|
|
166
|
-
filterRecallCandidates,
|
|
167
166
|
formatDateInTimeZone,
|
|
168
167
|
isArtifactMemoryPath,
|
|
169
168
|
lifecycleRecallScoreAdjustment,
|
|
@@ -198,6 +197,7 @@ export {
|
|
|
198
197
|
type RecallInvocationOptions,
|
|
199
198
|
type RecallModeDecision,
|
|
200
199
|
} from "./orchestration/orchestrator-helpers.js";
|
|
200
|
+
export { filterRecallCandidates } from "./orchestration/generic-recall-paths.js";
|
|
201
201
|
|
|
202
202
|
export { hasIdentityRecoveryIntent, resolveEffectiveIdentityInjectionMode } from "./orchestration/recall-result-formatter.js";
|
|
203
203
|
import {
|
|
@@ -541,7 +541,6 @@ import type {
|
|
|
541
541
|
RecallSectionConfig,
|
|
542
542
|
RecallTierExplain,
|
|
543
543
|
} from "./types.js";
|
|
544
|
-
import { disposeDefaultArchiveScoring, getDefaultArchiveScoring, memoryFileToScoreItem } from "./recall/archive-scoring.js";
|
|
545
544
|
|
|
546
545
|
// Issue #1526 seam 15: ExtractionRunResult moved to orchestration/extraction-run.ts.
|
|
547
546
|
export type { ExtractionRunResult } from "./orchestration/extraction-run.js";
|
|
@@ -997,8 +996,6 @@ export class Orchestrator {
|
|
|
997
996
|
if (this.conversationQmd && this.conversationQmd !== this.qmd) {
|
|
998
997
|
await (this.conversationQmd as { dispose?: () => void | Promise<void> }).dispose?.();
|
|
999
998
|
}
|
|
1000
|
-
// Issue #1674: terminate archive-scoring worker threads on destroy.
|
|
1001
|
-
await disposeDefaultArchiveScoring();
|
|
1002
999
|
} finally {
|
|
1003
1000
|
if (bufferFlushError !== undefined) {
|
|
1004
1001
|
log.warn(
|
|
@@ -2483,7 +2480,7 @@ export class Orchestrator {
|
|
|
2483
2480
|
if (!paths) return null;
|
|
2484
2481
|
const scoped = new Set<string>();
|
|
2485
2482
|
for (const memoryPath of paths) {
|
|
2486
|
-
if (!memoryPath || isGenericRecallExcludedPath(memoryPath, this.config
|
|
2483
|
+
if (!memoryPath || isGenericRecallExcludedPath(memoryPath, this.config, "qmd")) continue;
|
|
2487
2484
|
if (
|
|
2488
2485
|
resolveNamespaceCapabilities(this.config).namespaces &&
|
|
2489
2486
|
!recallNamespaces.includes(this.namespaceFromPath(memoryPath))
|
|
@@ -3600,16 +3597,14 @@ export class Orchestrator {
|
|
|
3600
3597
|
);
|
|
3601
3598
|
}
|
|
3602
3599
|
|
|
3603
|
-
private async
|
|
3600
|
+
private async searchQueryAwareFallback(
|
|
3604
3601
|
prompt: string,
|
|
3605
|
-
recallNamespaces: string[],
|
|
3606
3602
|
limit: number,
|
|
3607
3603
|
queryAwarePrefilter?: QueryAwarePrefilter,
|
|
3608
3604
|
abortSignal?: AbortSignal,
|
|
3609
3605
|
): Promise<QmdSearchResult[]> {
|
|
3610
|
-
return this.recallSearchPipelineCoordinator.
|
|
3606
|
+
return this.recallSearchPipelineCoordinator.searchQueryAwareFallback(
|
|
3611
3607
|
prompt,
|
|
3612
|
-
recallNamespaces,
|
|
3613
3608
|
limit,
|
|
3614
3609
|
queryAwarePrefilter,
|
|
3615
3610
|
abortSignal,
|
|
@@ -3968,11 +3963,4 @@ export class Orchestrator {
|
|
|
3968
3963
|
namespaces,
|
|
3969
3964
|
);
|
|
3970
3965
|
}
|
|
3971
|
-
private async readArchivedMemoriesForNamespaces(
|
|
3972
|
-
namespaces: string[],
|
|
3973
|
-
): Promise<MemoryFile[]> {
|
|
3974
|
-
return this.namespaceReadFanoutCoordinator.readArchivedMemoriesForNamespaces(
|
|
3975
|
-
namespaces,
|
|
3976
|
-
);
|
|
3977
|
-
}
|
|
3978
3966
|
}
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* Pins the task-level cancellation contract of runColdStepWithinDeadline
|
|
5
5
|
* inside RecallSearchPipelineCoordinator.applyColdFallbackPipeline:
|
|
6
6
|
* - when the per-step deadline wins, the losing cold task's INJECTED signal
|
|
7
|
-
* is aborted
|
|
7
|
+
* is aborted so an orphaned query-aware fallback stops cooperatively; the
|
|
8
8
|
* step returns its fallback (fail-open);
|
|
9
9
|
* - a task-level deadline must NOT abort the request-level signal;
|
|
10
10
|
* - a task that completes normally (no deadline) never aborts the injected
|
|
@@ -37,24 +37,22 @@ async function coldConfig() {
|
|
|
37
37
|
}
|
|
38
38
|
|
|
39
39
|
/**
|
|
40
|
-
* Minimal
|
|
41
|
-
* the cold-
|
|
42
|
-
* an empty archive result returns [] before any namespace/storage-router work,
|
|
43
|
-
* keeping the stub surface tight. The cast is a deliberate test double.
|
|
40
|
+
* Minimal dependencies for the query-aware fallback. QMD is unavailable, so
|
|
41
|
+
* the cold-QMD branch is skipped and the injected fallback step is observed.
|
|
44
42
|
*/
|
|
45
43
|
function coldDeps(
|
|
46
44
|
config: PluginConfig,
|
|
47
|
-
|
|
45
|
+
searchQueryAwareFallback: RecallSearchPipelineDeps["searchQueryAwareFallback"],
|
|
48
46
|
): RecallSearchPipelineDeps {
|
|
49
47
|
return {
|
|
50
48
|
config,
|
|
51
49
|
qmd: { isAvailable: () => false },
|
|
52
50
|
namespaceFromPath: () => "default",
|
|
53
|
-
|
|
51
|
+
searchQueryAwareFallback,
|
|
54
52
|
} as unknown as RecallSearchPipelineDeps;
|
|
55
53
|
}
|
|
56
54
|
|
|
57
|
-
test("#1907:
|
|
55
|
+
test("#1907: query-aware fallback deadline aborts the injected step signal, returns fallback, leaves the request signal intact", async () => {
|
|
58
56
|
const { memoryDir, config } = await coldConfig();
|
|
59
57
|
try {
|
|
60
58
|
const stuck = Promise.withResolvers<QmdSearchResult[]>();
|
|
@@ -65,7 +63,7 @@ test("#1907: cold archive-scan deadline aborts the injected step signal, returns
|
|
|
65
63
|
// so the late completion leaks "late" here and the assertion below fails.
|
|
66
64
|
const lateWrites: string[] = [];
|
|
67
65
|
const abandonedTaskSettled = Promise.withResolvers<void>();
|
|
68
|
-
const deps = coldDeps(config, async (_prompt,
|
|
66
|
+
const deps = coldDeps(config, async (_prompt, _limit, _prefilter, abortSignal) => {
|
|
69
67
|
capturedStepSignal = abortSignal;
|
|
70
68
|
const late = await stuck.promise; // does not settle before the deadline wins
|
|
71
69
|
if (!abortSignal?.aborted) {
|
|
@@ -87,7 +85,7 @@ test("#1907: cold archive-scan deadline aborts the injected step signal, returns
|
|
|
87
85
|
});
|
|
88
86
|
|
|
89
87
|
assert.deepEqual(result, [], "the step returns its fallback when the deadline wins");
|
|
90
|
-
assert.ok(capturedStepSignal, "
|
|
88
|
+
assert.ok(capturedStepSignal, "query-aware fallback received an injected step signal");
|
|
91
89
|
assert.equal(
|
|
92
90
|
capturedStepSignal!.aborted,
|
|
93
91
|
true,
|
|
@@ -119,7 +117,7 @@ test("#1907: a cold step that completes before its deadline never aborts the inj
|
|
|
119
117
|
const { memoryDir, config } = await coldConfig();
|
|
120
118
|
try {
|
|
121
119
|
let capturedStepSignal: AbortSignal | undefined;
|
|
122
|
-
const deps = coldDeps(config, async (_prompt,
|
|
120
|
+
const deps = coldDeps(config, async (_prompt, _limit, _prefilter, abortSignal) => {
|
|
123
121
|
capturedStepSignal = abortSignal;
|
|
124
122
|
return []; // resolves immediately, well within the deadline
|
|
125
123
|
});
|
|
@@ -135,8 +133,8 @@ test("#1907: a cold step that completes before its deadline never aborts the inj
|
|
|
135
133
|
abortSignal: requestController.signal,
|
|
136
134
|
});
|
|
137
135
|
|
|
138
|
-
assert.deepEqual(result, [], "empty
|
|
139
|
-
assert.ok(capturedStepSignal, "
|
|
136
|
+
assert.deepEqual(result, [], "empty query-aware fallback returns []");
|
|
137
|
+
assert.ok(capturedStepSignal, "query-aware fallback received an injected step signal");
|
|
140
138
|
assert.equal(
|
|
141
139
|
capturedStepSignal!.aborted,
|
|
142
140
|
false,
|