@remnic/core 1.0.3 → 1.1.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/dist/abort-error.d.ts +32 -0
- package/dist/abort-error.js +11 -0
- package/dist/access-audit.d.ts +56 -0
- package/dist/access-audit.js +9 -0
- package/dist/access-audit.js.map +1 -0
- package/dist/access-cli.js +72 -54
- package/dist/access-cli.js.map +1 -1
- package/dist/access-http.d.ts +16 -8
- package/dist/access-http.js +25 -17
- package/dist/access-mcp.d.ts +16 -8
- package/dist/access-mcp.js +28 -6
- package/dist/access-schema.d.ts +130 -39
- package/dist/access-schema.js +5 -1
- package/dist/access-service-Br8ZydTK.d.ts +827 -0
- package/dist/access-service.d.ts +20 -660
- package/dist/access-service.js +22 -14
- package/dist/bootstrap.d.ts +6 -3
- package/dist/briefing.d.ts +1 -0
- package/dist/briefing.js +6 -5
- package/dist/buffer-surprise-report.d.ts +70 -0
- package/dist/buffer-surprise-report.js +7 -0
- package/dist/buffer-surprise-report.js.map +1 -0
- package/dist/buffer-surprise.d.ts +98 -0
- package/dist/buffer-surprise.js +11 -0
- package/dist/buffer-surprise.js.map +1 -0
- package/dist/buffer.d.ts +100 -2
- package/dist/buffer.js +1 -1
- package/dist/calibration.js +5 -5
- package/dist/causal-behavior.js +4 -4
- package/dist/causal-chain.js +2 -2
- package/dist/causal-consolidation.js +17 -16
- package/dist/causal-consolidation.js.map +1 -1
- package/dist/causal-retrieval.js +4 -4
- package/dist/causal-trajectory.js +1 -1
- package/dist/{chunk-QNJMBKFK.js → chunk-2LGMW3DJ.js} +3 -2
- package/dist/chunk-2LGMW3DJ.js.map +1 -0
- package/dist/{chunk-QDYXG4CS.js → chunk-3FPTCC3Z.js} +4 -3
- package/dist/chunk-3FPTCC3Z.js.map +1 -0
- package/dist/chunk-3GPTTA4J.js +57 -0
- package/dist/chunk-3GPTTA4J.js.map +1 -0
- package/dist/{chunk-QKAH5B6E.js → chunk-3GXCSUXR.js} +94 -6
- package/dist/chunk-3GXCSUXR.js.map +1 -0
- package/dist/{chunk-POBPGDWI.js → chunk-3OGMS3PE.js} +2 -2
- package/dist/chunk-54V4BZWP.js +139 -0
- package/dist/chunk-54V4BZWP.js.map +1 -0
- package/dist/chunk-5JRF2PZA.js +67 -0
- package/dist/chunk-5JRF2PZA.js.map +1 -0
- package/dist/chunk-64NJRYU2.js +332 -0
- package/dist/chunk-64NJRYU2.js.map +1 -0
- package/dist/chunk-6AUUAZEX.js +150 -0
- package/dist/chunk-6AUUAZEX.js.map +1 -0
- package/dist/{chunk-HITJFT7E.js → chunk-7I7FKFZH.js} +28 -21
- package/dist/chunk-7I7FKFZH.js.map +1 -0
- package/dist/chunk-AJU4PJGY.js +126 -0
- package/dist/chunk-AJU4PJGY.js.map +1 -0
- package/dist/chunk-ASAITVLA.js +64 -0
- package/dist/chunk-ASAITVLA.js.map +1 -0
- package/dist/{chunk-X4WESCKA.js → chunk-B5WXLVDY.js} +187 -6
- package/dist/chunk-B5WXLVDY.js.map +1 -0
- package/dist/{chunk-RCICHSHL.js → chunk-BGJGXLZ7.js} +111 -2
- package/dist/{chunk-RCICHSHL.js.map → chunk-BGJGXLZ7.js.map} +1 -1
- package/dist/{chunk-OJFGVJS6.js → chunk-BK2EFTE2.js} +319 -18
- package/dist/chunk-BK2EFTE2.js.map +1 -0
- package/dist/chunk-C4SQJZAF.js +486 -0
- package/dist/chunk-C4SQJZAF.js.map +1 -0
- package/dist/{chunk-GJQPH5G3.js → chunk-CUPFXL3J.js} +2 -2
- package/dist/chunk-DF3RVK3X.js +119 -0
- package/dist/chunk-DF3RVK3X.js.map +1 -0
- package/dist/{chunk-PMB3WGDL.js → chunk-DFTTJYSO.js} +167 -7
- package/dist/chunk-DFTTJYSO.js.map +1 -0
- package/dist/chunk-DGVM5SFL.js +69 -0
- package/dist/chunk-DGVM5SFL.js.map +1 -0
- package/dist/chunk-EIR5VLIH.js +90 -0
- package/dist/chunk-EIR5VLIH.js.map +1 -0
- package/dist/{chunk-PAORGQRI.js → chunk-EPQJM2GC.js} +37 -23
- package/dist/chunk-EPQJM2GC.js.map +1 -0
- package/dist/{chunk-POMSFKTB.js → chunk-F5VP6YCB.js} +368 -10
- package/dist/chunk-F5VP6YCB.js.map +1 -0
- package/dist/{chunk-6ZH4TU6I.js → chunk-FAAFWE4G.js} +2 -1
- package/dist/chunk-FAAFWE4G.js.map +1 -0
- package/dist/{chunk-74JR4N5J.js → chunk-FVA6TGI3.js} +2 -2
- package/dist/chunk-GDFS42HT.js +206 -0
- package/dist/chunk-GDFS42HT.js.map +1 -0
- package/dist/{chunk-BKQJBXXX.js → chunk-GGD5W7TB.js} +2 -2
- package/dist/chunk-GGD5W7TB.js.map +1 -0
- package/dist/{chunk-V7XCAHIB.js → chunk-GKFXUTJ2.js} +508 -26
- package/dist/chunk-GKFXUTJ2.js.map +1 -0
- package/dist/{chunk-NSB3WSYS.js → chunk-HK3FGIEW.js} +278 -3
- package/dist/chunk-HK3FGIEW.js.map +1 -0
- package/dist/{chunk-AAI7JARD.js → chunk-HMDCOMYU.js} +8 -11
- package/dist/chunk-HMDCOMYU.js.map +1 -0
- package/dist/chunk-IISBCCWR.js +52 -0
- package/dist/chunk-IISBCCWR.js.map +1 -0
- package/dist/{chunk-YFYL2SIJ.js → chunk-INXV5JBT.js} +290 -46
- package/dist/chunk-INXV5JBT.js.map +1 -0
- package/dist/chunk-JBMSGZEQ.js +441 -0
- package/dist/chunk-JBMSGZEQ.js.map +1 -0
- package/dist/{chunk-UPMD5XND.js → chunk-JL2PU6AI.js} +16 -5
- package/dist/chunk-JL2PU6AI.js.map +1 -0
- package/dist/{chunk-J4IYOZZ5.js → chunk-JXS5PDQ7.js} +3 -1
- package/dist/chunk-JXS5PDQ7.js.map +1 -0
- package/dist/{chunk-AYPYCLR7.js → chunk-KUB6JU6H.js} +4 -4
- package/dist/chunk-KVBLZUKV.js +173 -0
- package/dist/chunk-KVBLZUKV.js.map +1 -0
- package/dist/chunk-LBLXEFWK.js +51 -0
- package/dist/chunk-LBLXEFWK.js.map +1 -0
- package/dist/{chunk-U2IQTSBY.js → chunk-LTCGGW2D.js} +1 -1
- package/dist/chunk-LTCGGW2D.js.map +1 -0
- package/dist/{chunk-UEYA6UC7.js → chunk-NZLQTHS5.js} +25 -2
- package/dist/chunk-NZLQTHS5.js.map +1 -0
- package/dist/chunk-PVGDJXVK.js +21 -0
- package/dist/chunk-PVGDJXVK.js.map +1 -0
- package/dist/chunk-PVPWZSSI.js +37 -0
- package/dist/chunk-PVPWZSSI.js.map +1 -0
- package/dist/{chunk-4NRAJUDS.js → chunk-RBBWYEFJ.js} +1 -1
- package/dist/chunk-RFYAYKTD.js +146 -0
- package/dist/chunk-RFYAYKTD.js.map +1 -0
- package/dist/{chunk-JROGC36Y.js → chunk-RGLL5SPU.js} +2 -2
- package/dist/{chunk-2VFW5K5U.js → chunk-S3EEFKNY.js} +103 -65
- package/dist/chunk-S3EEFKNY.js.map +1 -0
- package/dist/chunk-SOBJ6NEY.js +18 -0
- package/dist/chunk-SOBJ6NEY.js.map +1 -0
- package/dist/{chunk-MYQWXITD.js → chunk-SPI27QT6.js} +2 -2
- package/dist/chunk-TVVEYCNW.js +65 -0
- package/dist/chunk-TVVEYCNW.js.map +1 -0
- package/dist/chunk-ULYOGL6R.js +322 -0
- package/dist/chunk-ULYOGL6R.js.map +1 -0
- package/dist/{chunk-S4LX5EBI.js → chunk-VBVG2M5G.js} +64 -10
- package/dist/chunk-VBVG2M5G.js.map +1 -0
- package/dist/{chunk-KWP7T3DP.js → chunk-VDX363PS.js} +2 -2
- package/dist/{chunk-XMGSSBFX.js → chunk-VYM3VWOF.js} +1560 -244
- package/dist/chunk-VYM3VWOF.js.map +1 -0
- package/dist/{chunk-MTLYEMJB.js → chunk-WCLICCGB.js} +18 -3
- package/dist/chunk-WCLICCGB.js.map +1 -0
- package/dist/{chunk-ECKDIK5F.js → chunk-WVVA7F5A.js} +2 -2
- package/dist/chunk-X6GF3FX2.js +26 -0
- package/dist/chunk-X6GF3FX2.js.map +1 -0
- package/dist/{chunk-3QFQGRHO.js → chunk-XMHBH5H6.js} +4 -4
- package/dist/{chunk-KEG4GNGI.js → chunk-XZ2TIKGC.js} +38 -8
- package/dist/chunk-XZ2TIKGC.js.map +1 -0
- package/dist/chunk-Y4FHOFJ2.js +140 -0
- package/dist/chunk-Y4FHOFJ2.js.map +1 -0
- package/dist/chunk-YNB73F22.js +137 -0
- package/dist/chunk-YNB73F22.js.map +1 -0
- package/dist/{chunk-7PA4OZEU.js → chunk-YNQKWQT4.js} +55 -30
- package/dist/chunk-YNQKWQT4.js.map +1 -0
- package/dist/chunk-ZAIM4TUE.js +488 -0
- package/dist/chunk-ZAIM4TUE.js.map +1 -0
- package/dist/{chunk-BTY5RRRF.js → chunk-ZEM3OK2K.js} +5 -5
- package/dist/chunk-ZZTOURJI.js +91 -0
- package/dist/chunk-ZZTOURJI.js.map +1 -0
- package/dist/{cli-DwIBnp2g.d.ts → cli-BkeRaYfk.d.ts} +2 -2
- package/dist/cli.d.ts +13 -5
- package/dist/cli.js +45 -33
- package/dist/config.js +1 -1
- package/dist/consolidation-operator.d.ts +41 -0
- package/dist/consolidation-operator.js +11 -0
- package/dist/consolidation-operator.js.map +1 -0
- package/dist/consolidation-provenance-check.d.ts +68 -0
- package/dist/consolidation-provenance-check.js +9 -0
- package/dist/consolidation-provenance-check.js.map +1 -0
- package/dist/consolidation-undo.d.ts +123 -0
- package/dist/consolidation-undo.js +426 -0
- package/dist/consolidation-undo.js.map +1 -0
- package/dist/contradiction-review-WIUBAR52.js +21 -0
- package/dist/contradiction-review-WIUBAR52.js.map +1 -0
- package/dist/contradiction-scan-E3GJTI4F.js +412 -0
- package/dist/contradiction-scan-E3GJTI4F.js.map +1 -0
- package/dist/cross-namespace-budget.d.ts +133 -0
- package/dist/cross-namespace-budget.js +9 -0
- package/dist/cross-namespace-budget.js.map +1 -0
- package/dist/direct-answer-wiring.d.ts +77 -0
- package/dist/direct-answer-wiring.js +10 -0
- package/dist/direct-answer-wiring.js.map +1 -0
- package/dist/direct-answer.d.ts +106 -0
- package/dist/direct-answer.js +10 -0
- package/dist/direct-answer.js.map +1 -0
- package/dist/{engine-X7X3AAG3.js → engine-F3GOXGE5.js} +7 -6
- package/dist/engine-F3GOXGE5.js.map +1 -0
- package/dist/entity-retrieval.d.ts +1 -0
- package/dist/entity-retrieval.js +6 -5
- package/dist/explicit-capture.d.ts +6 -3
- package/dist/explicit-capture.js +2 -2
- package/dist/extraction-judge-telemetry.d.ts +113 -0
- package/dist/extraction-judge-telemetry.js +14 -0
- package/dist/extraction-judge-telemetry.js.map +1 -0
- package/dist/extraction-judge-training.d.ts +85 -0
- package/dist/extraction-judge-training.js +16 -0
- package/dist/extraction-judge-training.js.map +1 -0
- package/dist/extraction-judge.d.ts +124 -2
- package/dist/extraction-judge.js +11 -1
- package/dist/extraction.js +7 -6
- package/dist/fallback-llm.d.ts +11 -2
- package/dist/fallback-llm.js +2 -2
- package/dist/graph-recall.d.ts +100 -0
- package/dist/graph-recall.js +8 -0
- package/dist/graph-recall.js.map +1 -0
- package/dist/graph-retrieval.d.ts +271 -0
- package/dist/graph-retrieval.js +21 -0
- package/dist/graph-retrieval.js.map +1 -0
- package/dist/harmonic-retrieval.js +2 -1
- package/dist/importance.js +1 -1
- package/dist/index.d.ts +589 -138
- package/dist/index.js +531 -403
- package/dist/index.js.map +1 -1
- package/dist/intent.js +1 -1
- package/dist/local-llm.d.ts +10 -3
- package/dist/local-llm.js +1 -1
- package/dist/memory-worth-bench.d.ts +51 -0
- package/dist/memory-worth-bench.js +131 -0
- package/dist/memory-worth-bench.js.map +1 -0
- package/dist/memory-worth-filter.d.ts +128 -0
- package/dist/memory-worth-filter.js +10 -0
- package/dist/memory-worth-filter.js.map +1 -0
- package/dist/memory-worth-outcomes.d.ts +118 -0
- package/dist/memory-worth-outcomes.js +9 -0
- package/dist/memory-worth-outcomes.js.map +1 -0
- package/dist/memory-worth.d.ts +102 -0
- package/dist/memory-worth.js +7 -0
- package/dist/memory-worth.js.map +1 -0
- package/dist/operator-toolkit.d.ts +40 -1
- package/dist/operator-toolkit.js +24 -14
- package/dist/{orchestrator-B9kwlCep.d.ts → orchestrator-CmJ-NTdJ.d.ts} +254 -10
- package/dist/orchestrator.d.ts +6 -3
- package/dist/orchestrator.js +59 -48
- package/dist/page-versioning.d.ts +12 -1
- package/dist/page-versioning.js +5 -3
- package/dist/{port-C1GZFv8h.d.ts → port-BADbLZU5.d.ts} +2 -2
- package/dist/qmd-recall-cache.d.ts +1 -1
- package/dist/qmd.d.ts +5 -3
- package/dist/qmd.js +2 -1
- package/dist/reasoning-trace-recall.d.ts +90 -0
- package/dist/reasoning-trace-recall.js +13 -0
- package/dist/reasoning-trace-recall.js.map +1 -0
- package/dist/reasoning-trace-types.d.ts +54 -0
- package/dist/reasoning-trace-types.js +17 -0
- package/dist/reasoning-trace-types.js.map +1 -0
- package/dist/recall-audit-anomaly.d.ts +112 -0
- package/dist/recall-audit-anomaly.js +11 -0
- package/dist/recall-audit-anomaly.js.map +1 -0
- package/dist/recall-audit.js +5 -44
- package/dist/recall-audit.js.map +1 -1
- package/dist/recall-explain-renderer.d.ts +49 -0
- package/dist/recall-explain-renderer.js +18 -0
- package/dist/recall-explain-renderer.js.map +1 -0
- package/dist/recall-state.d.ts +39 -1
- package/dist/recall-state.js +1 -1
- package/dist/recall-xray-cli.d.ts +40 -0
- package/dist/recall-xray-cli.js +11 -0
- package/dist/recall-xray-cli.js.map +1 -0
- package/dist/recall-xray-renderer.d.ts +44 -0
- package/dist/recall-xray-renderer.js +18 -0
- package/dist/recall-xray-renderer.js.map +1 -0
- package/dist/recall-xray.d.ts +179 -0
- package/dist/recall-xray.js +13 -0
- package/dist/recall-xray.js.map +1 -0
- package/dist/resolution-QBTDHTG7.js +100 -0
- package/dist/resolution-QBTDHTG7.js.map +1 -0
- package/dist/resolve-provider-secret.d.ts +24 -1
- package/dist/resolve-provider-secret.js +3 -1
- package/dist/resume-bundles.js +6 -6
- package/dist/retrieval-agents.d.ts +1 -1
- package/dist/retrieval-tiers.d.ts +17 -0
- package/dist/retrieval-tiers.js +9 -0
- package/dist/retrieval-tiers.js.map +1 -0
- package/dist/schemas.d.ts +301 -45
- package/dist/schemas.js +1 -1
- package/dist/{semantic-consolidation-DrvSYRdB.d.ts → semantic-consolidation-CxJU6MJk.d.ts} +62 -1
- package/dist/semantic-consolidation.d.ts +2 -1
- package/dist/semantic-consolidation.js +20 -6
- package/dist/semantic-rule-promotion.js +6 -5
- package/dist/semantic-rule-verifier.js +6 -5
- package/dist/storage.d.ts +82 -1
- package/dist/storage.js +5 -4
- package/dist/summarizer.js +4 -4
- package/dist/temporal-supersession.d.ts +1 -0
- package/dist/tier-migration.d.ts +2 -1
- package/dist/types-DJhqDJUV.d.ts +50 -0
- package/dist/types.d.ts +309 -3
- package/dist/types.js +1 -1
- package/dist/verified-recall.js +6 -5
- package/package.json +1 -1
- package/dist/chunk-2VFW5K5U.js.map +0 -1
- package/dist/chunk-6ZH4TU6I.js.map +0 -1
- package/dist/chunk-7PA4OZEU.js.map +0 -1
- package/dist/chunk-AAI7JARD.js.map +0 -1
- package/dist/chunk-BKQJBXXX.js.map +0 -1
- package/dist/chunk-HITJFT7E.js.map +0 -1
- package/dist/chunk-J4IYOZZ5.js.map +0 -1
- package/dist/chunk-KEG4GNGI.js.map +0 -1
- package/dist/chunk-LAYN4LDC.js +0 -267
- package/dist/chunk-LAYN4LDC.js.map +0 -1
- package/dist/chunk-MTLYEMJB.js.map +0 -1
- package/dist/chunk-NSB3WSYS.js.map +0 -1
- package/dist/chunk-OJFGVJS6.js.map +0 -1
- package/dist/chunk-PAORGQRI.js.map +0 -1
- package/dist/chunk-PMB3WGDL.js.map +0 -1
- package/dist/chunk-POMSFKTB.js.map +0 -1
- package/dist/chunk-QDYXG4CS.js.map +0 -1
- package/dist/chunk-QKAH5B6E.js.map +0 -1
- package/dist/chunk-QNJMBKFK.js.map +0 -1
- package/dist/chunk-S4LX5EBI.js.map +0 -1
- package/dist/chunk-U2IQTSBY.js.map +0 -1
- package/dist/chunk-UEYA6UC7.js.map +0 -1
- package/dist/chunk-UPMD5XND.js.map +0 -1
- package/dist/chunk-UVJFDP7P.js +0 -202
- package/dist/chunk-UVJFDP7P.js.map +0 -1
- package/dist/chunk-V7XCAHIB.js.map +0 -1
- package/dist/chunk-X4WESCKA.js.map +0 -1
- package/dist/chunk-XMGSSBFX.js.map +0 -1
- package/dist/chunk-YFYL2SIJ.js.map +0 -1
- /package/dist/{engine-X7X3AAG3.js.map → abort-error.js.map} +0 -0
- /package/dist/{chunk-POBPGDWI.js.map → chunk-3OGMS3PE.js.map} +0 -0
- /package/dist/{chunk-GJQPH5G3.js.map → chunk-CUPFXL3J.js.map} +0 -0
- /package/dist/{chunk-74JR4N5J.js.map → chunk-FVA6TGI3.js.map} +0 -0
- /package/dist/{chunk-AYPYCLR7.js.map → chunk-KUB6JU6H.js.map} +0 -0
- /package/dist/{chunk-4NRAJUDS.js.map → chunk-RBBWYEFJ.js.map} +0 -0
- /package/dist/{chunk-JROGC36Y.js.map → chunk-RGLL5SPU.js.map} +0 -0
- /package/dist/{chunk-MYQWXITD.js.map → chunk-SPI27QT6.js.map} +0 -0
- /package/dist/{chunk-KWP7T3DP.js.map → chunk-VDX363PS.js.map} +0 -0
- /package/dist/{chunk-ECKDIK5F.js.map → chunk-WVVA7F5A.js.map} +0 -0
- /package/dist/{chunk-3QFQGRHO.js.map → chunk-XMHBH5H6.js.map} +0 -0
- /package/dist/{chunk-BTY5RRRF.js.map → chunk-ZEM3OK2K.js.map} +0 -0
|
@@ -2,7 +2,10 @@ import {
|
|
|
2
2
|
CompoundingEngine,
|
|
3
3
|
SharedContextManager,
|
|
4
4
|
defaultTierMigrationCycleBudget
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-RGLL5SPU.js";
|
|
6
|
+
import {
|
|
7
|
+
extractTopics
|
|
8
|
+
} from "./chunk-UHGBNIOS.js";
|
|
6
9
|
import {
|
|
7
10
|
applyUtilityPromotionRuntimePolicy,
|
|
8
11
|
applyUtilityRankingRuntimeDelta,
|
|
@@ -23,17 +26,14 @@ import {
|
|
|
23
26
|
TmtBuilder
|
|
24
27
|
} from "./chunk-TPB3I2AC.js";
|
|
25
28
|
import {
|
|
26
|
-
|
|
27
|
-
} from "./chunk-
|
|
29
|
+
SessionObserverState
|
|
30
|
+
} from "./chunk-JR4ZC3G4.js";
|
|
28
31
|
import {
|
|
29
32
|
HourlySummarizer
|
|
30
|
-
} from "./chunk-
|
|
31
|
-
import {
|
|
32
|
-
semanticChunkContent
|
|
33
|
-
} from "./chunk-KVE7R4CG.js";
|
|
33
|
+
} from "./chunk-ZEM3OK2K.js";
|
|
34
34
|
import {
|
|
35
|
-
|
|
36
|
-
} from "./chunk-
|
|
35
|
+
RelevanceStore
|
|
36
|
+
} from "./chunk-5NPGSAVB.js";
|
|
37
37
|
import {
|
|
38
38
|
RerankCache,
|
|
39
39
|
rerankLocalOrNoop
|
|
@@ -59,23 +59,26 @@ import {
|
|
|
59
59
|
import {
|
|
60
60
|
applyRuntimeRetrievalPolicy
|
|
61
61
|
} from "./chunk-5IZL4DCV.js";
|
|
62
|
-
import {
|
|
63
|
-
reorderRecallResultsWithMmr
|
|
64
|
-
} from "./chunk-YDBIWGNI.js";
|
|
65
|
-
import {
|
|
66
|
-
createRecallSectionMetricRecorder
|
|
67
|
-
} from "./chunk-7DHTMOND.js";
|
|
68
62
|
import {
|
|
69
63
|
LastRecallStore,
|
|
70
64
|
TierMigrationStatusStore,
|
|
71
65
|
clampGraphRecallExpandedEntries
|
|
72
|
-
} from "./chunk-
|
|
66
|
+
} from "./chunk-VBVG2M5G.js";
|
|
67
|
+
import {
|
|
68
|
+
buildXraySnapshot
|
|
69
|
+
} from "./chunk-KVBLZUKV.js";
|
|
73
70
|
import {
|
|
74
71
|
findUnresolvedEntityRefs
|
|
75
72
|
} from "./chunk-X7XN6YU4.js";
|
|
76
73
|
import {
|
|
77
|
-
|
|
78
|
-
} from "./chunk-
|
|
74
|
+
applyReasoningTraceBoost
|
|
75
|
+
} from "./chunk-ZZTOURJI.js";
|
|
76
|
+
import {
|
|
77
|
+
reorderRecallResultsWithMmr
|
|
78
|
+
} from "./chunk-YDBIWGNI.js";
|
|
79
|
+
import {
|
|
80
|
+
createRecallSectionMetricRecorder
|
|
81
|
+
} from "./chunk-7DHTMOND.js";
|
|
79
82
|
import {
|
|
80
83
|
buildQmdRecallCacheKey,
|
|
81
84
|
getCachedQmdRecall,
|
|
@@ -87,69 +90,83 @@ import {
|
|
|
87
90
|
import {
|
|
88
91
|
evaluateMemoryActionPolicy
|
|
89
92
|
} from "./chunk-H63EDPFJ.js";
|
|
93
|
+
import {
|
|
94
|
+
applyMemoryWorthFilter,
|
|
95
|
+
buildMemoryWorthCounterMap
|
|
96
|
+
} from "./chunk-3GPTTA4J.js";
|
|
90
97
|
import {
|
|
91
98
|
hasBroadGraphIntent,
|
|
92
99
|
inferIntentFromText,
|
|
93
100
|
intentCompatibilityScore,
|
|
94
101
|
isTaskInitiationIntent,
|
|
95
102
|
planRecallMode
|
|
96
|
-
} from "./chunk-
|
|
103
|
+
} from "./chunk-GGD5W7TB.js";
|
|
97
104
|
import {
|
|
98
105
|
classifyMemoryKind
|
|
99
106
|
} from "./chunk-YAZNBMNF.js";
|
|
100
107
|
import {
|
|
101
|
-
|
|
102
|
-
|
|
108
|
+
EXTRACTION_JUDGE_VERDICT_CATEGORY,
|
|
109
|
+
recordJudgeVerdict
|
|
110
|
+
} from "./chunk-AJU4PJGY.js";
|
|
103
111
|
import {
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
readRecentEntityTranscriptEntries
|
|
107
|
-
} from "./chunk-74JR4N5J.js";
|
|
112
|
+
recordJudgeTrainingPair
|
|
113
|
+
} from "./chunk-DF3RVK3X.js";
|
|
108
114
|
import {
|
|
115
|
+
createDeferCountMap,
|
|
109
116
|
createVerdictCache,
|
|
117
|
+
getVerdictKind,
|
|
110
118
|
judgeFactDurability,
|
|
111
119
|
validateProcedureExtraction
|
|
112
|
-
} from "./chunk-
|
|
120
|
+
} from "./chunk-C4SQJZAF.js";
|
|
113
121
|
import {
|
|
114
122
|
ExtractionEngine
|
|
115
|
-
} from "./chunk-
|
|
123
|
+
} from "./chunk-S3EEFKNY.js";
|
|
116
124
|
import {
|
|
117
125
|
parseMemoryActionEligibilityContext
|
|
118
|
-
} from "./chunk-
|
|
126
|
+
} from "./chunk-NZLQTHS5.js";
|
|
119
127
|
import {
|
|
120
128
|
ProfilingCollector
|
|
121
129
|
} from "./chunk-NBNN5GOB.js";
|
|
122
|
-
import {
|
|
123
|
-
LocalLlmClient
|
|
124
|
-
} from "./chunk-UPMD5XND.js";
|
|
125
130
|
import {
|
|
126
131
|
ModelRegistry
|
|
127
132
|
} from "./chunk-FEMOX5AD.js";
|
|
133
|
+
import {
|
|
134
|
+
LocalLlmClient
|
|
135
|
+
} from "./chunk-JL2PU6AI.js";
|
|
136
|
+
import {
|
|
137
|
+
tryDirectAnswer
|
|
138
|
+
} from "./chunk-6AUUAZEX.js";
|
|
139
|
+
import {
|
|
140
|
+
EmbeddingFallback
|
|
141
|
+
} from "./chunk-ALXMCZEU.js";
|
|
142
|
+
import {
|
|
143
|
+
buildEntityRecallSection,
|
|
144
|
+
entityRecentTranscriptLookbackHours,
|
|
145
|
+
readRecentEntityTranscriptEntries
|
|
146
|
+
} from "./chunk-FVA6TGI3.js";
|
|
147
|
+
import {
|
|
148
|
+
formatDaySummaryMemories
|
|
149
|
+
} from "./chunk-GZCUW5IC.js";
|
|
128
150
|
import {
|
|
129
151
|
RoutingRulesStore,
|
|
152
|
+
expandTildePath,
|
|
130
153
|
normalizeReplaySessionKey
|
|
131
|
-
} from "./chunk-
|
|
154
|
+
} from "./chunk-EPQJM2GC.js";
|
|
132
155
|
import {
|
|
133
156
|
searchVerifiedEpisodes
|
|
134
|
-
} from "./chunk-
|
|
157
|
+
} from "./chunk-CUPFXL3J.js";
|
|
135
158
|
import {
|
|
136
159
|
ThreadingManager
|
|
137
160
|
} from "./chunk-JRNQ3RNA.js";
|
|
138
161
|
import {
|
|
139
162
|
searchVerifiedSemanticRules
|
|
140
|
-
} from "./chunk-
|
|
163
|
+
} from "./chunk-SPI27QT6.js";
|
|
141
164
|
import {
|
|
142
165
|
searchWorkProductLedgerEntries
|
|
143
166
|
} from "./chunk-CULXMQJH.js";
|
|
144
167
|
import {
|
|
145
168
|
TranscriptManager
|
|
146
169
|
} from "./chunk-E6K4NIEU.js";
|
|
147
|
-
import {
|
|
148
|
-
PolicyRuntimeManager
|
|
149
|
-
} from "./chunk-EABGC2TL.js";
|
|
150
|
-
import {
|
|
151
|
-
searchObjectiveStateSnapshots
|
|
152
|
-
} from "./chunk-LOBRX7VD.js";
|
|
153
170
|
import {
|
|
154
171
|
NamespaceSearchRouter,
|
|
155
172
|
NamespaceStorageRouter,
|
|
@@ -157,17 +174,26 @@ import {
|
|
|
157
174
|
createConversationIndexRuntime,
|
|
158
175
|
createSearchBackend,
|
|
159
176
|
writeConversationChunks
|
|
160
|
-
} from "./chunk-
|
|
177
|
+
} from "./chunk-7I7FKFZH.js";
|
|
161
178
|
import {
|
|
162
179
|
parseQmdExplain
|
|
163
|
-
} from "./chunk-
|
|
180
|
+
} from "./chunk-YNQKWQT4.js";
|
|
181
|
+
import {
|
|
182
|
+
PolicyRuntimeManager
|
|
183
|
+
} from "./chunk-EABGC2TL.js";
|
|
184
|
+
import {
|
|
185
|
+
searchObjectiveStateSnapshots
|
|
186
|
+
} from "./chunk-LOBRX7VD.js";
|
|
187
|
+
import {
|
|
188
|
+
searchHarmonicRetrieval
|
|
189
|
+
} from "./chunk-HMDCOMYU.js";
|
|
164
190
|
import {
|
|
165
191
|
isAboveImportanceThreshold,
|
|
166
192
|
scoreImportance
|
|
167
|
-
} from "./chunk-
|
|
193
|
+
} from "./chunk-JXS5PDQ7.js";
|
|
168
194
|
import {
|
|
169
|
-
|
|
170
|
-
} from "./chunk-
|
|
195
|
+
launchProcessSync
|
|
196
|
+
} from "./chunk-LK6SGL53.js";
|
|
171
197
|
import {
|
|
172
198
|
collectNativeKnowledgeChunks,
|
|
173
199
|
formatNativeKnowledgeSection,
|
|
@@ -176,6 +202,9 @@ import {
|
|
|
176
202
|
import {
|
|
177
203
|
recordEvalShadowRecall
|
|
178
204
|
} from "./chunk-K6WK37A6.js";
|
|
205
|
+
import {
|
|
206
|
+
GraphIndex
|
|
207
|
+
} from "./chunk-C2EFFULQ.js";
|
|
179
208
|
import {
|
|
180
209
|
CODEX_THREAD_KEY_PREFIX
|
|
181
210
|
} from "./chunk-3PG3H5TD.js";
|
|
@@ -189,21 +218,27 @@ import {
|
|
|
189
218
|
renderCompressionGuidelinesMarkdown
|
|
190
219
|
} from "./chunk-2NMMFZ5T.js";
|
|
191
220
|
import {
|
|
192
|
-
|
|
193
|
-
} from "./chunk-
|
|
221
|
+
semanticChunkContent
|
|
222
|
+
} from "./chunk-KVE7R4CG.js";
|
|
223
|
+
import {
|
|
224
|
+
chunkContent
|
|
225
|
+
} from "./chunk-4WMCPJWX.js";
|
|
226
|
+
import {
|
|
227
|
+
SmartBuffer
|
|
228
|
+
} from "./chunk-JBMSGZEQ.js";
|
|
194
229
|
import {
|
|
195
230
|
buildConsolidationPrompt,
|
|
196
231
|
buildExtensionsBlockForConsolidation,
|
|
232
|
+
buildOperatorAwareConsolidationPrompt,
|
|
233
|
+
chooseConsolidationOperator,
|
|
197
234
|
findSimilarClusters,
|
|
198
235
|
materializeAfterSemanticConsolidation,
|
|
199
|
-
parseConsolidationResponse
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
GraphIndex
|
|
203
|
-
} from "./chunk-C2EFFULQ.js";
|
|
236
|
+
parseConsolidationResponse,
|
|
237
|
+
parseOperatorAwareConsolidationResponse
|
|
238
|
+
} from "./chunk-BGJGXLZ7.js";
|
|
204
239
|
import {
|
|
205
|
-
|
|
206
|
-
} from "./chunk-
|
|
240
|
+
FallbackLlmClient
|
|
241
|
+
} from "./chunk-3GXCSUXR.js";
|
|
207
242
|
import {
|
|
208
243
|
buildRecallQueryPolicy
|
|
209
244
|
} from "./chunk-6HZ6AO2P.js";
|
|
@@ -214,36 +249,42 @@ import {
|
|
|
214
249
|
import {
|
|
215
250
|
BootstrapEngine
|
|
216
251
|
} from "./chunk-N53K2EXC.js";
|
|
217
|
-
import {
|
|
218
|
-
BoxBuilder
|
|
219
|
-
} from "./chunk-URB2WSKZ.js";
|
|
220
|
-
import {
|
|
221
|
-
SmartBuffer
|
|
222
|
-
} from "./chunk-UVJFDP7P.js";
|
|
223
252
|
import {
|
|
224
253
|
isDisagreementPrompt
|
|
225
254
|
} from "./chunk-XYIK4LF6.js";
|
|
226
255
|
import {
|
|
227
|
-
|
|
228
|
-
} from "./chunk-
|
|
256
|
+
BoxBuilder
|
|
257
|
+
} from "./chunk-URB2WSKZ.js";
|
|
258
|
+
import {
|
|
259
|
+
abortError,
|
|
260
|
+
isAbortError,
|
|
261
|
+
throwIfAborted
|
|
262
|
+
} from "./chunk-PVGDJXVK.js";
|
|
229
263
|
import {
|
|
230
264
|
resolveHomeDir
|
|
231
265
|
} from "./chunk-MARWOCVP.js";
|
|
232
266
|
import {
|
|
267
|
+
listTrustZoneRecords,
|
|
233
268
|
searchTrustZoneRecords
|
|
234
269
|
} from "./chunk-EQINRHYR.js";
|
|
270
|
+
import {
|
|
271
|
+
buildProcedurePersistBody
|
|
272
|
+
} from "./chunk-QDW3E4RD.js";
|
|
235
273
|
import {
|
|
236
274
|
shouldSkipImplicitExtraction
|
|
237
|
-
} from "./chunk-
|
|
275
|
+
} from "./chunk-3FPTCC3Z.js";
|
|
238
276
|
import {
|
|
239
277
|
selectRouteRule
|
|
240
|
-
} from "./chunk-
|
|
241
|
-
import {
|
|
242
|
-
buildProcedurePersistBody
|
|
243
|
-
} from "./chunk-QDW3E4RD.js";
|
|
278
|
+
} from "./chunk-2LGMW3DJ.js";
|
|
244
279
|
import {
|
|
245
280
|
searchCausalTrajectories
|
|
246
|
-
} from "./chunk-
|
|
281
|
+
} from "./chunk-RBBWYEFJ.js";
|
|
282
|
+
import {
|
|
283
|
+
canReadNamespace,
|
|
284
|
+
defaultNamespaceForPrincipal,
|
|
285
|
+
recallNamespacesForPrincipal,
|
|
286
|
+
resolvePrincipal
|
|
287
|
+
} from "./chunk-N5AKDXAI.js";
|
|
247
288
|
import {
|
|
248
289
|
decideLifecycleTransition,
|
|
249
290
|
resolveLifecycleState
|
|
@@ -256,10 +297,10 @@ import {
|
|
|
256
297
|
normalizeAttributePairs,
|
|
257
298
|
normalizeEntityName,
|
|
258
299
|
parseEntityFile
|
|
259
|
-
} from "./chunk-
|
|
300
|
+
} from "./chunk-F5VP6YCB.js";
|
|
260
301
|
import {
|
|
261
302
|
confidenceTier
|
|
262
|
-
} from "./chunk-
|
|
303
|
+
} from "./chunk-LTCGGW2D.js";
|
|
263
304
|
import {
|
|
264
305
|
attachCitation,
|
|
265
306
|
hasCitationForTemplate,
|
|
@@ -278,25 +319,19 @@ import {
|
|
|
278
319
|
import {
|
|
279
320
|
log
|
|
280
321
|
} from "./chunk-2ODBA7MQ.js";
|
|
281
|
-
import {
|
|
282
|
-
canReadNamespace,
|
|
283
|
-
defaultNamespaceForPrincipal,
|
|
284
|
-
recallNamespacesForPrincipal,
|
|
285
|
-
resolvePrincipal
|
|
286
|
-
} from "./chunk-N5AKDXAI.js";
|
|
287
322
|
|
|
288
323
|
// src/orchestrator.ts
|
|
289
|
-
import
|
|
324
|
+
import path7 from "path";
|
|
290
325
|
import os from "os";
|
|
291
326
|
import { createHash as createHash2, randomBytes } from "crypto";
|
|
292
327
|
import { existsSync as existsSync2 } from "fs";
|
|
293
328
|
import {
|
|
294
|
-
mkdir as
|
|
329
|
+
mkdir as mkdir5,
|
|
295
330
|
readdir as readdir3,
|
|
296
|
-
readFile as
|
|
331
|
+
readFile as readFile4,
|
|
297
332
|
stat as stat3,
|
|
298
333
|
unlink as unlink2,
|
|
299
|
-
writeFile as
|
|
334
|
+
writeFile as writeFile4
|
|
300
335
|
} from "fs/promises";
|
|
301
336
|
|
|
302
337
|
// src/migrate/from-engram.ts
|
|
@@ -873,7 +908,7 @@ async function buildProcedureRecallSection(storage, prompt, config) {
|
|
|
873
908
|
10,
|
|
874
909
|
Math.max(
|
|
875
910
|
1,
|
|
876
|
-
typeof config.procedural.recallMaxProcedures === "number" && Number.isFinite(config.procedural.recallMaxProcedures) ? Math.floor(config.procedural.recallMaxProcedures) :
|
|
911
|
+
typeof config.procedural.recallMaxProcedures === "number" && Number.isFinite(config.procedural.recallMaxProcedures) ? Math.floor(config.procedural.recallMaxProcedures) : 2
|
|
877
912
|
)
|
|
878
913
|
);
|
|
879
914
|
const all = await storage.readAllMemories();
|
|
@@ -901,6 +936,7 @@ import path2 from "path";
|
|
|
901
936
|
var DAY_SUMMARY_CRON_ID = "engram-day-summary";
|
|
902
937
|
var GOVERNANCE_CRON_ID = "engram-nightly-governance";
|
|
903
938
|
var PROCEDURAL_MINING_CRON_ID = "engram-procedural-mining";
|
|
939
|
+
var CONTRADICTION_SCAN_CRON_ID = "engram-contradiction-scan";
|
|
904
940
|
async function acquireCronJobsLock(jobsPath) {
|
|
905
941
|
const lockPath2 = `${jobsPath}.lock`;
|
|
906
942
|
const start = Date.now();
|
|
@@ -1037,6 +1073,30 @@ async function ensureProceduralMiningCron(jobsPath, options) {
|
|
|
1037
1073
|
delivery: { mode: "none" }
|
|
1038
1074
|
}));
|
|
1039
1075
|
}
|
|
1076
|
+
async function ensureContradictionScanCron(jobsPath, options) {
|
|
1077
|
+
const scheduleExpr = typeof options.scheduleExpr === "string" && options.scheduleExpr.trim().length > 0 ? options.scheduleExpr.trim() : "37 3 * * *";
|
|
1078
|
+
const agentId = typeof options.agentId === "string" && options.agentId.trim().length > 0 ? options.agentId.trim() : "main";
|
|
1079
|
+
return ensureCronJob(jobsPath, CONTRADICTION_SCAN_CRON_ID, () => ({
|
|
1080
|
+
id: CONTRADICTION_SCAN_CRON_ID,
|
|
1081
|
+
agentId,
|
|
1082
|
+
name: "Remnic Contradiction Scan (nightly)",
|
|
1083
|
+
enabled: true,
|
|
1084
|
+
schedule: {
|
|
1085
|
+
kind: "cron",
|
|
1086
|
+
expr: scheduleExpr,
|
|
1087
|
+
tz: options.timezone
|
|
1088
|
+
},
|
|
1089
|
+
sessionTarget: "isolated",
|
|
1090
|
+
wakeMode: "now",
|
|
1091
|
+
payload: {
|
|
1092
|
+
kind: "agentTurn",
|
|
1093
|
+
timeoutSeconds: 900,
|
|
1094
|
+
thinking: "off",
|
|
1095
|
+
message: "You are OpenClaw automation. Call tool `engram.contradiction_scan_run` with empty params. If successful output exactly NO_REPLY. On error output one concise line. Do NOT use message tool."
|
|
1096
|
+
},
|
|
1097
|
+
delivery: { mode: "none" }
|
|
1098
|
+
}));
|
|
1099
|
+
}
|
|
1040
1100
|
|
|
1041
1101
|
// src/dedup/semantic.ts
|
|
1042
1102
|
async function decideSemanticDedup(content, lookup, options) {
|
|
@@ -1089,12 +1149,253 @@ async function decideSemanticDedup(content, lookup, options) {
|
|
|
1089
1149
|
};
|
|
1090
1150
|
}
|
|
1091
1151
|
|
|
1092
|
-
// src/
|
|
1152
|
+
// src/taxonomy/default-taxonomy.ts
|
|
1153
|
+
var DEFAULT_TAXONOMY = {
|
|
1154
|
+
version: 1,
|
|
1155
|
+
categories: [
|
|
1156
|
+
{
|
|
1157
|
+
id: "corrections",
|
|
1158
|
+
name: "Corrections",
|
|
1159
|
+
description: "Corrections to previously stored information",
|
|
1160
|
+
filingRules: ["Any update that supersedes a prior fact"],
|
|
1161
|
+
priority: 10,
|
|
1162
|
+
memoryCategories: ["correction"]
|
|
1163
|
+
},
|
|
1164
|
+
{
|
|
1165
|
+
id: "principles",
|
|
1166
|
+
name: "Principles",
|
|
1167
|
+
description: "Rules, guidelines, and recurring patterns",
|
|
1168
|
+
filingRules: ["A guiding principle, rule, or skill"],
|
|
1169
|
+
priority: 20,
|
|
1170
|
+
memoryCategories: ["principle", "rule", "skill"]
|
|
1171
|
+
},
|
|
1172
|
+
{
|
|
1173
|
+
id: "procedures",
|
|
1174
|
+
name: "Procedures",
|
|
1175
|
+
description: "Ordered multi-step workflows the user repeats",
|
|
1176
|
+
filingRules: ["A repeatable sequence of steps or commands for a task"],
|
|
1177
|
+
priority: 25,
|
|
1178
|
+
memoryCategories: ["procedure"]
|
|
1179
|
+
},
|
|
1180
|
+
{
|
|
1181
|
+
id: "entities",
|
|
1182
|
+
name: "Entities",
|
|
1183
|
+
description: "People, organizations, places, projects",
|
|
1184
|
+
filingRules: ["Named entity with attributes"],
|
|
1185
|
+
priority: 30,
|
|
1186
|
+
memoryCategories: ["entity", "relationship"]
|
|
1187
|
+
},
|
|
1188
|
+
{
|
|
1189
|
+
id: "decisions",
|
|
1190
|
+
name: "Decisions",
|
|
1191
|
+
description: "Choices made and their rationale",
|
|
1192
|
+
filingRules: ["A decision or commitment with reasoning"],
|
|
1193
|
+
priority: 35,
|
|
1194
|
+
memoryCategories: ["decision", "commitment"]
|
|
1195
|
+
},
|
|
1196
|
+
{
|
|
1197
|
+
id: "preferences",
|
|
1198
|
+
name: "Preferences",
|
|
1199
|
+
description: "User likes, dislikes, and style choices",
|
|
1200
|
+
filingRules: ["Anything expressing a preference or taste"],
|
|
1201
|
+
priority: 40,
|
|
1202
|
+
memoryCategories: ["preference"]
|
|
1203
|
+
},
|
|
1204
|
+
{
|
|
1205
|
+
id: "facts",
|
|
1206
|
+
name: "Facts",
|
|
1207
|
+
description: "Objective statements about the world",
|
|
1208
|
+
filingRules: ["Any factual claim or piece of information"],
|
|
1209
|
+
priority: 50,
|
|
1210
|
+
memoryCategories: ["fact"]
|
|
1211
|
+
},
|
|
1212
|
+
{
|
|
1213
|
+
id: "moments",
|
|
1214
|
+
name: "Moments",
|
|
1215
|
+
description: "Significant events or experiences",
|
|
1216
|
+
filingRules: ["A specific event worth remembering"],
|
|
1217
|
+
priority: 60,
|
|
1218
|
+
memoryCategories: ["moment"]
|
|
1219
|
+
},
|
|
1220
|
+
{
|
|
1221
|
+
id: "reasoning-traces",
|
|
1222
|
+
name: "Reasoning Traces",
|
|
1223
|
+
description: "Stored intermediate reasoning / solution chains for a problem the agent previously solved",
|
|
1224
|
+
filingRules: [
|
|
1225
|
+
"A multi-step reasoning chain or solution walkthrough the agent can replay for a similar problem"
|
|
1226
|
+
],
|
|
1227
|
+
priority: 55,
|
|
1228
|
+
memoryCategories: ["reasoning_trace"]
|
|
1229
|
+
}
|
|
1230
|
+
]
|
|
1231
|
+
};
|
|
1232
|
+
|
|
1233
|
+
// src/taxonomy/resolver-doc-generator.ts
|
|
1234
|
+
function generateResolverDocument(taxonomy) {
|
|
1235
|
+
const sorted = [...taxonomy.categories].sort((a, b) => {
|
|
1236
|
+
if (a.priority !== b.priority) return a.priority - b.priority;
|
|
1237
|
+
return a.id.localeCompare(b.id);
|
|
1238
|
+
});
|
|
1239
|
+
const lines = [
|
|
1240
|
+
"# Memory Filing Resolver",
|
|
1241
|
+
"",
|
|
1242
|
+
"Given a new piece of knowledge, follow this tree to determine where it belongs.",
|
|
1243
|
+
""
|
|
1244
|
+
];
|
|
1245
|
+
let step = 1;
|
|
1246
|
+
for (const cat of sorted) {
|
|
1247
|
+
lines.push(`## Step ${step}: ${cat.description}?`);
|
|
1248
|
+
lines.push("");
|
|
1249
|
+
for (const rule of cat.filingRules) {
|
|
1250
|
+
lines.push(`- ${rule}`);
|
|
1251
|
+
}
|
|
1252
|
+
lines.push("");
|
|
1253
|
+
lines.push(
|
|
1254
|
+
`> YES: File under **${cat.id}/** (priority ${cat.priority})`
|
|
1255
|
+
);
|
|
1256
|
+
lines.push("");
|
|
1257
|
+
step++;
|
|
1258
|
+
}
|
|
1259
|
+
lines.push("## Tie-breaking");
|
|
1260
|
+
lines.push("");
|
|
1261
|
+
lines.push(
|
|
1262
|
+
"If a fact could go in multiple categories, file under the one with the **lowest priority number**."
|
|
1263
|
+
);
|
|
1264
|
+
lines.push("");
|
|
1265
|
+
lines.push(`---`);
|
|
1266
|
+
lines.push(`*Generated from taxonomy v${taxonomy.version}*`);
|
|
1267
|
+
lines.push("");
|
|
1268
|
+
return lines.join("\n");
|
|
1269
|
+
}
|
|
1270
|
+
|
|
1271
|
+
// src/taxonomy/taxonomy-loader.ts
|
|
1272
|
+
import { readFile as readFile3, mkdir as mkdir3, writeFile as writeFile3 } from "fs/promises";
|
|
1093
1273
|
import path3 from "path";
|
|
1094
|
-
|
|
1274
|
+
var TAXONOMY_DIR = ".taxonomy";
|
|
1275
|
+
var TAXONOMY_FILE = "taxonomy.json";
|
|
1276
|
+
var MAX_SLUG_LENGTH = 32;
|
|
1277
|
+
var SLUG_RE = /^[a-z][a-z0-9-]*$/;
|
|
1278
|
+
function validateSlug(slug) {
|
|
1279
|
+
if (slug.length === 0) {
|
|
1280
|
+
throw new Error("Taxonomy category ID must not be empty");
|
|
1281
|
+
}
|
|
1282
|
+
if (slug.length > MAX_SLUG_LENGTH) {
|
|
1283
|
+
throw new Error(
|
|
1284
|
+
`Taxonomy category ID "${slug}" exceeds ${MAX_SLUG_LENGTH} characters`
|
|
1285
|
+
);
|
|
1286
|
+
}
|
|
1287
|
+
if (!SLUG_RE.test(slug)) {
|
|
1288
|
+
throw new Error(
|
|
1289
|
+
`Taxonomy category ID "${slug}" is invalid: must be lowercase letters, digits, and hyphens, starting with a letter`
|
|
1290
|
+
);
|
|
1291
|
+
}
|
|
1292
|
+
}
|
|
1293
|
+
function validateTaxonomy(taxonomy) {
|
|
1294
|
+
if (typeof taxonomy.version !== "number" || taxonomy.version < 1) {
|
|
1295
|
+
throw new Error("Taxonomy version must be a positive integer");
|
|
1296
|
+
}
|
|
1297
|
+
if (!Array.isArray(taxonomy.categories)) {
|
|
1298
|
+
throw new Error("Taxonomy categories must be an array");
|
|
1299
|
+
}
|
|
1300
|
+
const seenIds = /* @__PURE__ */ new Set();
|
|
1301
|
+
for (const cat of taxonomy.categories) {
|
|
1302
|
+
validateSlug(cat.id);
|
|
1303
|
+
if (seenIds.has(cat.id)) {
|
|
1304
|
+
throw new Error(`Duplicate taxonomy category ID: "${cat.id}"`);
|
|
1305
|
+
}
|
|
1306
|
+
seenIds.add(cat.id);
|
|
1307
|
+
if (typeof cat.name !== "string" || cat.name.trim().length === 0) {
|
|
1308
|
+
throw new Error(`Taxonomy category "${cat.id}" must have a non-empty name`);
|
|
1309
|
+
}
|
|
1310
|
+
if (typeof cat.description !== "string" || cat.description.trim().length === 0) {
|
|
1311
|
+
throw new Error(`Taxonomy category "${cat.id}" must have a non-empty description`);
|
|
1312
|
+
}
|
|
1313
|
+
if (!Array.isArray(cat.filingRules)) {
|
|
1314
|
+
throw new Error(`Taxonomy category "${cat.id}" filingRules must be an array`);
|
|
1315
|
+
}
|
|
1316
|
+
if (typeof cat.priority !== "number" || !Number.isFinite(cat.priority)) {
|
|
1317
|
+
throw new Error(`Taxonomy category "${cat.id}" must have a finite numeric priority`);
|
|
1318
|
+
}
|
|
1319
|
+
if (!Array.isArray(cat.memoryCategories)) {
|
|
1320
|
+
throw new Error(`Taxonomy category "${cat.id}" memoryCategories must be an array`);
|
|
1321
|
+
}
|
|
1322
|
+
if (cat.parentId !== void 0) {
|
|
1323
|
+
if (typeof cat.parentId !== "string") {
|
|
1324
|
+
throw new Error(`Taxonomy category "${cat.id}" parentId must be a string if set`);
|
|
1325
|
+
}
|
|
1326
|
+
}
|
|
1327
|
+
}
|
|
1328
|
+
for (const cat of taxonomy.categories) {
|
|
1329
|
+
if (cat.parentId !== void 0 && !seenIds.has(cat.parentId)) {
|
|
1330
|
+
throw new Error(
|
|
1331
|
+
`Taxonomy category "${cat.id}" references unknown parentId "${cat.parentId}"`
|
|
1332
|
+
);
|
|
1333
|
+
}
|
|
1334
|
+
}
|
|
1335
|
+
}
|
|
1336
|
+
async function loadTaxonomy(memoryDir) {
|
|
1337
|
+
const taxonomyPath = path3.join(memoryDir, TAXONOMY_DIR, TAXONOMY_FILE);
|
|
1338
|
+
let raw;
|
|
1339
|
+
try {
|
|
1340
|
+
raw = await readFile3(taxonomyPath, "utf-8");
|
|
1341
|
+
} catch (err) {
|
|
1342
|
+
if (err instanceof Error && err.code === "ENOENT") {
|
|
1343
|
+
return structuredClone(DEFAULT_TAXONOMY);
|
|
1344
|
+
}
|
|
1345
|
+
throw err;
|
|
1346
|
+
}
|
|
1347
|
+
const parsed = JSON.parse(raw);
|
|
1348
|
+
if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
|
|
1349
|
+
throw new Error("taxonomy.json must be a JSON object");
|
|
1350
|
+
}
|
|
1351
|
+
const obj = parsed;
|
|
1352
|
+
const userVersion = typeof obj.version === "number" ? obj.version : DEFAULT_TAXONOMY.version;
|
|
1353
|
+
const userCategories = Array.isArray(obj.categories) ? obj.categories : [];
|
|
1354
|
+
const userIdCounts = /* @__PURE__ */ new Map();
|
|
1355
|
+
for (const cat of userCategories) {
|
|
1356
|
+
const id = typeof cat.id === "string" ? cat.id : String(cat.id);
|
|
1357
|
+
userIdCounts.set(id, (userIdCounts.get(id) ?? 0) + 1);
|
|
1358
|
+
}
|
|
1359
|
+
const duplicateIds = [...userIdCounts.entries()].filter(([, count]) => count > 1).map(([id]) => id);
|
|
1360
|
+
if (duplicateIds.length > 0) {
|
|
1361
|
+
throw new Error(
|
|
1362
|
+
`Duplicate category IDs in taxonomy.json: ${duplicateIds.map((id) => `"${id}"`).join(", ")}`
|
|
1363
|
+
);
|
|
1364
|
+
}
|
|
1365
|
+
const mergedMap = /* @__PURE__ */ new Map();
|
|
1366
|
+
for (const cat of DEFAULT_TAXONOMY.categories) {
|
|
1367
|
+
mergedMap.set(cat.id, { ...cat });
|
|
1368
|
+
}
|
|
1369
|
+
for (const cat of userCategories) {
|
|
1370
|
+
mergedMap.set(cat.id, cat);
|
|
1371
|
+
}
|
|
1372
|
+
const merged = {
|
|
1373
|
+
version: userVersion,
|
|
1374
|
+
categories: [...mergedMap.values()]
|
|
1375
|
+
};
|
|
1376
|
+
validateTaxonomy(merged);
|
|
1377
|
+
return merged;
|
|
1378
|
+
}
|
|
1379
|
+
async function saveTaxonomy(memoryDir, taxonomy) {
|
|
1380
|
+
validateTaxonomy(taxonomy);
|
|
1381
|
+
const dir = path3.join(memoryDir, TAXONOMY_DIR);
|
|
1382
|
+
await mkdir3(dir, { recursive: true });
|
|
1383
|
+
const filePath = path3.join(dir, TAXONOMY_FILE);
|
|
1384
|
+
await writeFile3(filePath, JSON.stringify(taxonomy, null, 2) + "\n", "utf-8");
|
|
1385
|
+
}
|
|
1386
|
+
function getTaxonomyDir(memoryDir) {
|
|
1387
|
+
return path3.join(memoryDir, TAXONOMY_DIR);
|
|
1388
|
+
}
|
|
1389
|
+
function getTaxonomyFilePath(memoryDir) {
|
|
1390
|
+
return path3.join(memoryDir, TAXONOMY_DIR, TAXONOMY_FILE);
|
|
1391
|
+
}
|
|
1392
|
+
|
|
1393
|
+
// src/lcm/schema.ts
|
|
1394
|
+
import path4 from "path";
|
|
1395
|
+
import { mkdir as mkdir4 } from "fs/promises";
|
|
1095
1396
|
var LCM_SCHEMA_VERSION = 1;
|
|
1096
1397
|
function openLcmDatabase(memoryDir) {
|
|
1097
|
-
const dbPath =
|
|
1398
|
+
const dbPath = path4.join(memoryDir, "state", "lcm.sqlite");
|
|
1098
1399
|
const db = openBetterSqlite3(dbPath);
|
|
1099
1400
|
db.pragma("journal_mode = WAL");
|
|
1100
1401
|
db.pragma("busy_timeout = 5000");
|
|
@@ -1103,7 +1404,7 @@ function openLcmDatabase(memoryDir) {
|
|
|
1103
1404
|
return db;
|
|
1104
1405
|
}
|
|
1105
1406
|
async function ensureLcmStateDir(memoryDir) {
|
|
1106
|
-
await
|
|
1407
|
+
await mkdir4(path4.join(memoryDir, "state"), { recursive: true });
|
|
1107
1408
|
}
|
|
1108
1409
|
function applySchema(db) {
|
|
1109
1410
|
const versionRow = db.prepare("SELECT name FROM sqlite_master WHERE type='table' AND name='lcm_meta'").get();
|
|
@@ -2367,7 +2668,7 @@ function chunkTranscriptEntries(sessionKey, entries, opts) {
|
|
|
2367
2668
|
|
|
2368
2669
|
// src/conversation-index/cleanup.ts
|
|
2369
2670
|
import { readdir as readdir2, rm as rm3 } from "fs/promises";
|
|
2370
|
-
import
|
|
2671
|
+
import path5 from "path";
|
|
2371
2672
|
async function cleanupConversationChunks(rootDir, retentionDays) {
|
|
2372
2673
|
if (!Number.isFinite(retentionDays) || retentionDays <= 0) return;
|
|
2373
2674
|
const cutoffMs = Date.now() - retentionDays * 24 * 60 * 60 * 1e3;
|
|
@@ -2375,7 +2676,7 @@ async function cleanupConversationChunks(rootDir, retentionDays) {
|
|
|
2375
2676
|
const sessions = await readdir2(rootDir, { withFileTypes: true });
|
|
2376
2677
|
for (const s of sessions) {
|
|
2377
2678
|
if (!s.isDirectory()) continue;
|
|
2378
|
-
const sessionDir =
|
|
2679
|
+
const sessionDir = path5.join(rootDir, s.name);
|
|
2379
2680
|
const dayDirs = await readdir2(sessionDir, { withFileTypes: true });
|
|
2380
2681
|
for (const d of dayDirs) {
|
|
2381
2682
|
if (!d.isDirectory()) continue;
|
|
@@ -2383,7 +2684,7 @@ async function cleanupConversationChunks(rootDir, retentionDays) {
|
|
|
2383
2684
|
const dayMs = (/* @__PURE__ */ new Date(d.name + "T00:00:00.000Z")).getTime();
|
|
2384
2685
|
if (!Number.isFinite(dayMs)) continue;
|
|
2385
2686
|
if (dayMs < cutoffMs) {
|
|
2386
|
-
await rm3(
|
|
2687
|
+
await rm3(path5.join(sessionDir, d.name), { recursive: true, force: true });
|
|
2387
2688
|
}
|
|
2388
2689
|
}
|
|
2389
2690
|
try {
|
|
@@ -2399,6 +2700,264 @@ async function cleanupConversationChunks(rootDir, retentionDays) {
|
|
|
2399
2700
|
}
|
|
2400
2701
|
}
|
|
2401
2702
|
|
|
2703
|
+
// src/coding/git-context.ts
|
|
2704
|
+
import path6 from "path";
|
|
2705
|
+
var DEFAULT_GIT_TIMEOUT_MS = 2e3;
|
|
2706
|
+
function defaultGitInvoker() {
|
|
2707
|
+
return (cwd, args) => {
|
|
2708
|
+
const result = launchProcessSync("git", args, {
|
|
2709
|
+
cwd,
|
|
2710
|
+
encoding: "utf-8",
|
|
2711
|
+
timeout: DEFAULT_GIT_TIMEOUT_MS,
|
|
2712
|
+
shell: false
|
|
2713
|
+
});
|
|
2714
|
+
if (result.error) {
|
|
2715
|
+
return { stdout: "", exitCode: 127 };
|
|
2716
|
+
}
|
|
2717
|
+
return {
|
|
2718
|
+
stdout: typeof result.stdout === "string" ? result.stdout : "",
|
|
2719
|
+
exitCode: typeof result.status === "number" ? result.status : 1
|
|
2720
|
+
};
|
|
2721
|
+
};
|
|
2722
|
+
}
|
|
2723
|
+
function stableHash(input) {
|
|
2724
|
+
let hash = 2166136261;
|
|
2725
|
+
for (let i = 0; i < input.length; i++) {
|
|
2726
|
+
hash ^= input.charCodeAt(i);
|
|
2727
|
+
hash = Math.imul(hash, 16777619) >>> 0;
|
|
2728
|
+
}
|
|
2729
|
+
return hash.toString(16).padStart(8, "0");
|
|
2730
|
+
}
|
|
2731
|
+
function normalizeOriginUrl(rawUrl) {
|
|
2732
|
+
let url = rawUrl.trim();
|
|
2733
|
+
if (!url) return "";
|
|
2734
|
+
if (/\.git$/i.test(url)) url = url.slice(0, -4);
|
|
2735
|
+
if (/^[A-Za-z]:[\\/]/.test(url)) {
|
|
2736
|
+
return url.toLowerCase();
|
|
2737
|
+
}
|
|
2738
|
+
const protoMatch = /^[a-z][a-z0-9+.-]*:\/\/(?:[^@/]+@)?(\[[^\]]+\]|[^/:]*)(?::(\d+))?(\/.*)?$/i.exec(url);
|
|
2739
|
+
if (protoMatch) {
|
|
2740
|
+
let host = protoMatch[1] ?? "";
|
|
2741
|
+
const wasBracketed = host.startsWith("[") && host.endsWith("]");
|
|
2742
|
+
if (wasBracketed) host = host.slice(1, -1);
|
|
2743
|
+
const port = protoMatch[2];
|
|
2744
|
+
const repoPath = (protoMatch[3] ?? "").replace(/^\/+/, "");
|
|
2745
|
+
const hostPort = port ? wasBracketed ? `[${host}]:${port}` : `${host}:${port}` : host;
|
|
2746
|
+
const prefix = hostPort.length > 0 ? hostPort : "localhost";
|
|
2747
|
+
return `${prefix}/${repoPath}`.toLowerCase();
|
|
2748
|
+
}
|
|
2749
|
+
const scpMatch = /^(?:([^@\s/]+)@)?(\[[^\]]+\]|[^:@\s/]+):(.+)$/.exec(url);
|
|
2750
|
+
if (scpMatch) {
|
|
2751
|
+
let host = scpMatch[2] ?? "";
|
|
2752
|
+
if (host.startsWith("[") && host.endsWith("]")) host = host.slice(1, -1);
|
|
2753
|
+
const repoPath = scpMatch[3] ?? "";
|
|
2754
|
+
if (repoPath.startsWith("//")) {
|
|
2755
|
+
return url.toLowerCase();
|
|
2756
|
+
}
|
|
2757
|
+
return `${host}/${repoPath.replace(/^\/+/, "")}`.toLowerCase();
|
|
2758
|
+
}
|
|
2759
|
+
return url.toLowerCase();
|
|
2760
|
+
}
|
|
2761
|
+
async function resolveGitContext(cwd, options = {}) {
|
|
2762
|
+
try {
|
|
2763
|
+
if (typeof cwd !== "string" || cwd.length === 0) return null;
|
|
2764
|
+
const expanded = expandTildePath(cwd);
|
|
2765
|
+
if (!path6.isAbsolute(expanded)) return null;
|
|
2766
|
+
const invoker = options.invoker ?? defaultGitInvoker();
|
|
2767
|
+
const topLevel = invoker(expanded, ["rev-parse", "--show-toplevel"]);
|
|
2768
|
+
if (topLevel.exitCode !== 0) return null;
|
|
2769
|
+
const rootPath = topLevel.stdout.trim();
|
|
2770
|
+
if (!rootPath) return null;
|
|
2771
|
+
const branchResult = invoker(rootPath, ["rev-parse", "--abbrev-ref", "HEAD"]);
|
|
2772
|
+
let branch = null;
|
|
2773
|
+
if (branchResult.exitCode === 0) {
|
|
2774
|
+
const raw = branchResult.stdout.trim();
|
|
2775
|
+
branch = raw && raw !== "HEAD" ? raw : null;
|
|
2776
|
+
} else {
|
|
2777
|
+
const unbornRef = invoker(rootPath, ["symbolic-ref", "--quiet", "HEAD"]);
|
|
2778
|
+
if (unbornRef.exitCode === 0) {
|
|
2779
|
+
const raw = unbornRef.stdout.trim();
|
|
2780
|
+
const prefix = "refs/heads/";
|
|
2781
|
+
if (raw.startsWith(prefix)) {
|
|
2782
|
+
const candidate = raw.slice(prefix.length);
|
|
2783
|
+
if (candidate) branch = candidate;
|
|
2784
|
+
}
|
|
2785
|
+
}
|
|
2786
|
+
}
|
|
2787
|
+
const originResult = invoker(rootPath, ["remote", "get-url", "origin"]);
|
|
2788
|
+
let projectId;
|
|
2789
|
+
if (originResult.exitCode === 0) {
|
|
2790
|
+
const normalized = normalizeOriginUrl(originResult.stdout);
|
|
2791
|
+
projectId = normalized ? `origin:${stableHash(normalized)}` : `root:${stableHash(rootPath)}`;
|
|
2792
|
+
} else {
|
|
2793
|
+
projectId = `root:${stableHash(rootPath)}`;
|
|
2794
|
+
}
|
|
2795
|
+
const headRef = invoker(rootPath, ["symbolic-ref", "--quiet", "refs/remotes/origin/HEAD"]);
|
|
2796
|
+
let defaultBranch = null;
|
|
2797
|
+
if (headRef.exitCode === 0) {
|
|
2798
|
+
const raw = headRef.stdout.trim();
|
|
2799
|
+
const prefix = "refs/remotes/origin/";
|
|
2800
|
+
if (raw.startsWith(prefix)) {
|
|
2801
|
+
const candidate = raw.slice(prefix.length);
|
|
2802
|
+
if (candidate) defaultBranch = candidate;
|
|
2803
|
+
}
|
|
2804
|
+
}
|
|
2805
|
+
return {
|
|
2806
|
+
projectId,
|
|
2807
|
+
branch,
|
|
2808
|
+
rootPath,
|
|
2809
|
+
defaultBranch
|
|
2810
|
+
};
|
|
2811
|
+
} catch {
|
|
2812
|
+
return null;
|
|
2813
|
+
}
|
|
2814
|
+
}
|
|
2815
|
+
|
|
2816
|
+
// src/coding/coding-namespace.ts
|
|
2817
|
+
function sanitizeFragment(input) {
|
|
2818
|
+
if (typeof input !== "string") return "";
|
|
2819
|
+
const trimmed = input.trim().toLowerCase();
|
|
2820
|
+
let out = "";
|
|
2821
|
+
let prevIsDash = true;
|
|
2822
|
+
for (let i = 0; i < trimmed.length; i += 1) {
|
|
2823
|
+
const c = trimmed[i];
|
|
2824
|
+
const cc = trimmed.charCodeAt(i);
|
|
2825
|
+
const isSafe = cc >= 48 && cc <= 57 || cc >= 97 && cc <= 122 || cc === 46 || cc === 95;
|
|
2826
|
+
if (isSafe) {
|
|
2827
|
+
out += c;
|
|
2828
|
+
prevIsDash = false;
|
|
2829
|
+
} else if (!prevIsDash) {
|
|
2830
|
+
out += "-";
|
|
2831
|
+
prevIsDash = true;
|
|
2832
|
+
}
|
|
2833
|
+
}
|
|
2834
|
+
if (out.endsWith("-")) out = out.slice(0, -1);
|
|
2835
|
+
return out;
|
|
2836
|
+
}
|
|
2837
|
+
var MAX_NAMESPACE_LEN = 64;
|
|
2838
|
+
var HASH_SUFFIX_LEN = 9;
|
|
2839
|
+
function capLength(value) {
|
|
2840
|
+
if (value.length <= MAX_NAMESPACE_LEN) return value;
|
|
2841
|
+
const hash = stableHash(value);
|
|
2842
|
+
let end = MAX_NAMESPACE_LEN - HASH_SUFFIX_LEN;
|
|
2843
|
+
while (end > 0 && value.charCodeAt(end - 1) === 45) end -= 1;
|
|
2844
|
+
return `${value.slice(0, end)}-${hash}`;
|
|
2845
|
+
}
|
|
2846
|
+
function projectNamespaceName(projectId) {
|
|
2847
|
+
const frag = sanitizeFragment(projectId);
|
|
2848
|
+
return capLength(`project-${frag || "unknown"}`);
|
|
2849
|
+
}
|
|
2850
|
+
function sanitizeBaseFragment(input) {
|
|
2851
|
+
if (typeof input !== "string") return "";
|
|
2852
|
+
const trimmed = input.trim();
|
|
2853
|
+
let out = "";
|
|
2854
|
+
let prevIsDash = true;
|
|
2855
|
+
for (let i = 0; i < trimmed.length; i += 1) {
|
|
2856
|
+
const c = trimmed[i];
|
|
2857
|
+
const cc = trimmed.charCodeAt(i);
|
|
2858
|
+
const isSafe = cc >= 48 && cc <= 57 || cc >= 65 && cc <= 90 || cc >= 97 && cc <= 122 || cc === 46 || cc === 95;
|
|
2859
|
+
if (isSafe) {
|
|
2860
|
+
out += c;
|
|
2861
|
+
prevIsDash = false;
|
|
2862
|
+
} else if (!prevIsDash) {
|
|
2863
|
+
out += "-";
|
|
2864
|
+
prevIsDash = true;
|
|
2865
|
+
}
|
|
2866
|
+
}
|
|
2867
|
+
if (out.endsWith("-")) out = out.slice(0, -1);
|
|
2868
|
+
return out;
|
|
2869
|
+
}
|
|
2870
|
+
function combineNamespaces(base, overlay) {
|
|
2871
|
+
const baseFrag = sanitizeBaseFragment(base);
|
|
2872
|
+
const overlayFrag = sanitizeFragment(overlay);
|
|
2873
|
+
if (!baseFrag) return capLength(overlayFrag || "unknown");
|
|
2874
|
+
if (!overlayFrag) return capLength(baseFrag);
|
|
2875
|
+
return capLength(`${baseFrag}-${overlayFrag}`);
|
|
2876
|
+
}
|
|
2877
|
+
function branchNamespaceName(projectId, branch) {
|
|
2878
|
+
const projectFrag = sanitizeFragment(projectId);
|
|
2879
|
+
const trimmedBranch = branch.trim();
|
|
2880
|
+
const branchFrag = sanitizeFragment(trimmedBranch);
|
|
2881
|
+
const disambig = trimmedBranch.length > 0 && branchFrag !== trimmedBranch;
|
|
2882
|
+
const base = `project-${projectFrag || "unknown"}-branch-${branchFrag || "unknown"}`;
|
|
2883
|
+
const suffixed = disambig ? `${base}-${stableHash(trimmedBranch)}` : base;
|
|
2884
|
+
return capLength(suffixed);
|
|
2885
|
+
}
|
|
2886
|
+
function resolveCodingNamespaceOverlay(codingContext, config) {
|
|
2887
|
+
if (!codingContext) return null;
|
|
2888
|
+
if (!config.projectScope) return null;
|
|
2889
|
+
const projectId = typeof codingContext.projectId === "string" ? codingContext.projectId.trim() : "";
|
|
2890
|
+
if (!projectId) return null;
|
|
2891
|
+
const projectNs = projectNamespaceName(projectId);
|
|
2892
|
+
if (config.branchScope && typeof codingContext.branch === "string" && codingContext.branch.length > 0) {
|
|
2893
|
+
const branchNs = branchNamespaceName(projectId, codingContext.branch);
|
|
2894
|
+
return {
|
|
2895
|
+
namespace: branchNs,
|
|
2896
|
+
readFallbacks: [projectNs],
|
|
2897
|
+
scope: "branch"
|
|
2898
|
+
};
|
|
2899
|
+
}
|
|
2900
|
+
return {
|
|
2901
|
+
namespace: projectNs,
|
|
2902
|
+
readFallbacks: [],
|
|
2903
|
+
scope: "project"
|
|
2904
|
+
};
|
|
2905
|
+
}
|
|
2906
|
+
function describeCodingScope(codingContext, config) {
|
|
2907
|
+
const projectId = codingContext?.projectId ?? null;
|
|
2908
|
+
const branch = codingContext?.branch ?? null;
|
|
2909
|
+
if (!codingContext) {
|
|
2910
|
+
return {
|
|
2911
|
+
scope: "none",
|
|
2912
|
+
projectId: null,
|
|
2913
|
+
branch: null,
|
|
2914
|
+
effectiveNamespace: null,
|
|
2915
|
+
readFallbacks: [],
|
|
2916
|
+
disabledReason: "no-context"
|
|
2917
|
+
};
|
|
2918
|
+
}
|
|
2919
|
+
if (!config.projectScope) {
|
|
2920
|
+
return {
|
|
2921
|
+
scope: "none",
|
|
2922
|
+
projectId,
|
|
2923
|
+
branch,
|
|
2924
|
+
effectiveNamespace: null,
|
|
2925
|
+
readFallbacks: [],
|
|
2926
|
+
disabledReason: "disabled"
|
|
2927
|
+
};
|
|
2928
|
+
}
|
|
2929
|
+
const trimmedId = typeof projectId === "string" ? projectId.trim() : "";
|
|
2930
|
+
if (!trimmedId) {
|
|
2931
|
+
return {
|
|
2932
|
+
scope: "none",
|
|
2933
|
+
projectId,
|
|
2934
|
+
branch,
|
|
2935
|
+
effectiveNamespace: null,
|
|
2936
|
+
readFallbacks: [],
|
|
2937
|
+
disabledReason: "empty-project"
|
|
2938
|
+
};
|
|
2939
|
+
}
|
|
2940
|
+
const overlay = resolveCodingNamespaceOverlay(codingContext, config);
|
|
2941
|
+
if (!overlay) {
|
|
2942
|
+
return {
|
|
2943
|
+
scope: "none",
|
|
2944
|
+
projectId,
|
|
2945
|
+
branch,
|
|
2946
|
+
effectiveNamespace: null,
|
|
2947
|
+
readFallbacks: [],
|
|
2948
|
+
disabledReason: "disabled"
|
|
2949
|
+
};
|
|
2950
|
+
}
|
|
2951
|
+
return {
|
|
2952
|
+
scope: overlay.scope,
|
|
2953
|
+
projectId,
|
|
2954
|
+
branch,
|
|
2955
|
+
effectiveNamespace: overlay.namespace,
|
|
2956
|
+
readFallbacks: overlay.readFallbacks,
|
|
2957
|
+
disabledReason: null
|
|
2958
|
+
};
|
|
2959
|
+
}
|
|
2960
|
+
|
|
2402
2961
|
// src/orchestrator.ts
|
|
2403
2962
|
function dedupeEntitySynthesisEvidenceEntries(entries) {
|
|
2404
2963
|
const dedupedEvidenceEntries = [];
|
|
@@ -2463,15 +3022,23 @@ function fingerprintEntitySynthesisEvidence(entity) {
|
|
|
2463
3022
|
fingerprint.update(fingerprintEntityStructuredFacts(entity) ?? "");
|
|
2464
3023
|
return fingerprint.digest("hex");
|
|
2465
3024
|
}
|
|
2466
|
-
function
|
|
2467
|
-
|
|
2468
|
-
|
|
2469
|
-
|
|
3025
|
+
function mapRecallSourceToXrayServedBy(source) {
|
|
3026
|
+
switch (source) {
|
|
3027
|
+
case "recent_scan":
|
|
3028
|
+
return "recent-scan";
|
|
3029
|
+
case "hot_qmd":
|
|
3030
|
+
case "hot_embedding":
|
|
3031
|
+
case "cold_fallback":
|
|
3032
|
+
case "none":
|
|
3033
|
+
return "hybrid";
|
|
3034
|
+
}
|
|
3035
|
+
const _exhaustive = source;
|
|
3036
|
+
void _exhaustive;
|
|
3037
|
+
return "hybrid";
|
|
2470
3038
|
}
|
|
3039
|
+
var abortRecallError = abortError;
|
|
2471
3040
|
function throwIfRecallAborted(signal, message = "recall aborted") {
|
|
2472
|
-
|
|
2473
|
-
throw abortRecallError(message);
|
|
2474
|
-
}
|
|
3041
|
+
throwIfAborted(signal, message);
|
|
2475
3042
|
}
|
|
2476
3043
|
async function raceRecallAbort(promise, signal, message = "recall aborted") {
|
|
2477
3044
|
throwIfRecallAborted(signal, message);
|
|
@@ -2491,7 +3058,7 @@ async function raceRecallAbort(promise, signal, message = "recall aborted") {
|
|
|
2491
3058
|
}
|
|
2492
3059
|
var COMPACTION_SIGNAL_MAX_AGE_MS = 60 * 60 * 1e3;
|
|
2493
3060
|
function defaultWorkspaceDir() {
|
|
2494
|
-
return
|
|
3061
|
+
return path7.join(os.homedir(), ".openclaw", "workspace");
|
|
2495
3062
|
}
|
|
2496
3063
|
function sanitizeSessionKeyForFilename(sessionKey) {
|
|
2497
3064
|
const readable = sessionKey.replace(/[^a-zA-Z0-9._-]/g, "_");
|
|
@@ -2659,11 +3226,11 @@ function mergeGraphExpandedResults(primary, expanded) {
|
|
|
2659
3226
|
return Array.from(mergedByPath.values());
|
|
2660
3227
|
}
|
|
2661
3228
|
function graphPathRelativeToStorage(storageDir, candidatePath) {
|
|
2662
|
-
const absolutePath =
|
|
2663
|
-
const rel =
|
|
3229
|
+
const absolutePath = path7.isAbsolute(candidatePath) ? candidatePath : path7.resolve(storageDir, candidatePath);
|
|
3230
|
+
const rel = path7.relative(storageDir, absolutePath);
|
|
2664
3231
|
if (!rel || rel === ".") return null;
|
|
2665
3232
|
if (rel.startsWith("..")) return null;
|
|
2666
|
-
return rel.split(
|
|
3233
|
+
return rel.split(path7.sep).join("/");
|
|
2667
3234
|
}
|
|
2668
3235
|
function normalizeGraphActivationScore(score) {
|
|
2669
3236
|
const bounded = Number.isFinite(score) && score > 0 ? score : 0;
|
|
@@ -2805,7 +3372,7 @@ function buildMemoryPathById(allMemsForGraph, storageDir) {
|
|
|
2805
3372
|
for (const mem of allMemsForGraph ?? []) {
|
|
2806
3373
|
const id = mem.frontmatter.id;
|
|
2807
3374
|
if (!id) continue;
|
|
2808
|
-
pathById.set(id,
|
|
3375
|
+
pathById.set(id, path7.relative(storageDir, mem.path));
|
|
2809
3376
|
}
|
|
2810
3377
|
return pathById;
|
|
2811
3378
|
}
|
|
@@ -2813,7 +3380,7 @@ function appendMemoryToGraphContext(options) {
|
|
|
2813
3380
|
if (!Array.isArray(options.allMemsForGraph)) return;
|
|
2814
3381
|
const nowIso = (/* @__PURE__ */ new Date()).toISOString();
|
|
2815
3382
|
options.allMemsForGraph.push({
|
|
2816
|
-
path:
|
|
3383
|
+
path: path7.join(options.storageDir, options.memoryRelPath),
|
|
2817
3384
|
content: options.content,
|
|
2818
3385
|
frontmatter: {
|
|
2819
3386
|
id: options.memoryId,
|
|
@@ -2833,15 +3400,16 @@ function resolvePersistedMemoryRelativePath(options) {
|
|
|
2833
3400
|
const persisted = options.pathById.get(options.memoryId);
|
|
2834
3401
|
if (persisted) return persisted;
|
|
2835
3402
|
if (options.category === "correction") {
|
|
2836
|
-
return
|
|
3403
|
+
return path7.join("corrections", `${options.memoryId}.md`);
|
|
2837
3404
|
}
|
|
3405
|
+
const subtree = options.category === "procedure" ? "procedures" : options.category === "reasoning_trace" ? "reasoning-traces" : "facts";
|
|
2838
3406
|
const idParts = options.memoryId.split("-");
|
|
2839
3407
|
const maybeTimestamp = Number(idParts[1]);
|
|
2840
3408
|
if (Number.isFinite(maybeTimestamp) && maybeTimestamp > 0) {
|
|
2841
3409
|
const day = new Date(maybeTimestamp).toISOString().slice(0, 10);
|
|
2842
|
-
return
|
|
3410
|
+
return path7.join(subtree, day, `${options.memoryId}.md`);
|
|
2843
3411
|
}
|
|
2844
|
-
return
|
|
3412
|
+
return path7.join(subtree, `${options.memoryId}.md`);
|
|
2845
3413
|
}
|
|
2846
3414
|
var Orchestrator = class _Orchestrator {
|
|
2847
3415
|
storage;
|
|
@@ -2860,12 +3428,39 @@ var Orchestrator = class _Orchestrator {
|
|
|
2860
3428
|
localLlm;
|
|
2861
3429
|
fastLlm;
|
|
2862
3430
|
judgeVerdictCache;
|
|
2863
|
-
|
|
3431
|
+
/**
|
|
3432
|
+
* Per-orchestrator defer-counter map (issue #562, PR 2). Tracks how many
|
|
3433
|
+
* times the judge has returned `"defer"` for a given candidate content
|
|
3434
|
+
* hash so the defer cap can be enforced.
|
|
3435
|
+
*/
|
|
3436
|
+
judgeDeferCounts;
|
|
3437
|
+
/**
|
|
3438
|
+
* Side-channel: number of facts deferred in the most recent
|
|
3439
|
+
* `persistExtraction` call (issue #562, PR 2). The caller reads this after
|
|
3440
|
+
* `persistExtraction` returns to decide whether to retain buffer turns for
|
|
3441
|
+
* the next extraction pass. Not part of the return signature because many
|
|
3442
|
+
* callers already destructure `persistedIds` by position.
|
|
3443
|
+
*/
|
|
3444
|
+
lastPersistExtractionDeferredCount = 0;
|
|
3445
|
+
_fastGatewayLlm;
|
|
3446
|
+
get fastGatewayLlm() {
|
|
3447
|
+
return this._fastGatewayLlm;
|
|
3448
|
+
}
|
|
2864
3449
|
modelRegistry;
|
|
2865
3450
|
relevance;
|
|
2866
3451
|
negatives;
|
|
2867
3452
|
lastRecall;
|
|
2868
3453
|
tierMigrationStatus;
|
|
3454
|
+
/**
|
|
3455
|
+
* In-memory X-ray snapshot from the most recent `recall()` call that
|
|
3456
|
+
* was invoked with `xrayCapture: true` (issue #570 PR 1). Scope is
|
|
3457
|
+
* per-process; later slices add CLI/HTTP/MCP surfaces that consume
|
|
3458
|
+
* this via the shared renderer. `null` until the first capture, and
|
|
3459
|
+
* NEVER overwritten by a recall that did not request capture —
|
|
3460
|
+
* requests without the flag leave prior captures intact so the
|
|
3461
|
+
* capturing caller can still read their snapshot back.
|
|
3462
|
+
*/
|
|
3463
|
+
lastXraySnapshot = null;
|
|
2869
3464
|
embeddingFallback;
|
|
2870
3465
|
conversationIndexDir;
|
|
2871
3466
|
extraction;
|
|
@@ -2881,6 +3476,16 @@ var Orchestrator = class _Orchestrator {
|
|
|
2881
3476
|
/** Lossless Context Management engine — proactive session archive + DAG summarization. */
|
|
2882
3477
|
lcmEngine = null;
|
|
2883
3478
|
rerankCache = new RerankCache();
|
|
3479
|
+
/**
|
|
3480
|
+
* Short-TTL cache for Memory Worth counter lookups so interactive recall
|
|
3481
|
+
* doesn't trigger a full `readAllMemories` scan per query. Keyed by
|
|
3482
|
+
* namespace; the filter unions across namespaces at query time. The TTL
|
|
3483
|
+
* is intentionally short (seconds, not minutes) because counters are
|
|
3484
|
+
* mutated by `recordMemoryOutcome` asynchronously and we'd rather serve
|
|
3485
|
+
* a 30-second-stale worth score than a stable-but-wrong one.
|
|
3486
|
+
*/
|
|
3487
|
+
memoryWorthCounterCache = /* @__PURE__ */ new Map();
|
|
3488
|
+
static MEMORY_WORTH_CACHE_TTL_MS = 3e4;
|
|
2884
3489
|
/**
|
|
2885
3490
|
* Per-session workspace overrides keyed by sessionKey.
|
|
2886
3491
|
* Set by the before_agent_start hook so recall() uses the correct
|
|
@@ -2888,6 +3493,14 @@ var Orchestrator = class _Orchestrator {
|
|
|
2888
3493
|
* Using a Map prevents concurrent sessions from overwriting each other.
|
|
2889
3494
|
*/
|
|
2890
3495
|
_recallWorkspaceOverrides = /* @__PURE__ */ new Map();
|
|
3496
|
+
/**
|
|
3497
|
+
* Per-session coding-agent context (issue #569). Populated by connectors at
|
|
3498
|
+
* session-start (PRs 5/6/7) via `setCodingContextForSession`. Used by both
|
|
3499
|
+
* the recall path and the write path so that memory routing respects the
|
|
3500
|
+
* project/branch scope a session is operating in (rule 42 — read + write
|
|
3501
|
+
* through the same namespace layer).
|
|
3502
|
+
*/
|
|
3503
|
+
_codingContextBySession = /* @__PURE__ */ new Map();
|
|
2891
3504
|
routingRulesStore = null;
|
|
2892
3505
|
contentHashIndex = null;
|
|
2893
3506
|
artifactSourceStatusCache = /* @__PURE__ */ new WeakMap();
|
|
@@ -2921,6 +3534,10 @@ var Orchestrator = class _Orchestrator {
|
|
|
2921
3534
|
runtimePolicyValues = null;
|
|
2922
3535
|
utilityRuntimeValues = null;
|
|
2923
3536
|
evalShadowWriteChain = Promise.resolve();
|
|
3537
|
+
// Pending background observation-mode direct-answer annotations (#518).
|
|
3538
|
+
// Tracks fire-and-forget `annotateDirectAnswerTier` calls so callers (tests,
|
|
3539
|
+
// waitForDirectAnswerObservationIdle) can await settlement.
|
|
3540
|
+
directAnswerObservationChain = Promise.resolve();
|
|
2924
3541
|
// Initialization gate: recall() awaits this before proceeding
|
|
2925
3542
|
initPromise = null;
|
|
2926
3543
|
resolveInit = null;
|
|
@@ -2959,6 +3576,9 @@ var Orchestrator = class _Orchestrator {
|
|
|
2959
3576
|
this.deferredInitAbort = null;
|
|
2960
3577
|
}
|
|
2961
3578
|
}
|
|
3579
|
+
async disposeSearchBackendIfNeeded() {
|
|
3580
|
+
await this.qmd.dispose?.();
|
|
3581
|
+
}
|
|
2962
3582
|
/** Set per-session workspace for the next recall() call (compaction reset). @internal */
|
|
2963
3583
|
setRecallWorkspaceOverride(sessionKey, dir) {
|
|
2964
3584
|
this._recallWorkspaceOverrides.set(sessionKey, dir);
|
|
@@ -2971,10 +3591,96 @@ var Orchestrator = class _Orchestrator {
|
|
|
2971
3591
|
return resolvePrincipal(sessionKey, this.config);
|
|
2972
3592
|
}
|
|
2973
3593
|
resolveSelfNamespace(sessionKey) {
|
|
2974
|
-
|
|
3594
|
+
const base = defaultNamespaceForPrincipal(
|
|
2975
3595
|
this.resolvePrincipal(sessionKey),
|
|
2976
3596
|
this.config
|
|
2977
3597
|
);
|
|
3598
|
+
return this.applyCodingNamespaceOverlay(sessionKey, base);
|
|
3599
|
+
}
|
|
3600
|
+
/**
|
|
3601
|
+
* Attach a coding-agent context to a session (issue #569). Called by the
|
|
3602
|
+
* Claude Code / Codex / Cursor connectors at session start after
|
|
3603
|
+
* `resolveGitContext(cwd)`. The context is consulted by the recall path
|
|
3604
|
+
* and the write path so that memories route to a project- (and optionally
|
|
3605
|
+
* branch-) scoped namespace.
|
|
3606
|
+
*
|
|
3607
|
+
* Pass `null` to clear.
|
|
3608
|
+
*/
|
|
3609
|
+
setCodingContextForSession(sessionKey, codingContext) {
|
|
3610
|
+
if (typeof sessionKey !== "string" || sessionKey.length === 0) return;
|
|
3611
|
+
if (!this._codingContextBySession) {
|
|
3612
|
+
this._codingContextBySession = /* @__PURE__ */ new Map();
|
|
3613
|
+
}
|
|
3614
|
+
if (codingContext === null) {
|
|
3615
|
+
this._codingContextBySession.delete(sessionKey);
|
|
3616
|
+
return;
|
|
3617
|
+
}
|
|
3618
|
+
this._codingContextBySession.set(sessionKey, codingContext);
|
|
3619
|
+
}
|
|
3620
|
+
/**
|
|
3621
|
+
* Read-only accessor for the coding context attached to a session. Returns
|
|
3622
|
+
* `null` when none is set. Used by `remnic doctor` and by tests.
|
|
3623
|
+
*
|
|
3624
|
+
* Defensive `_codingContextBySession` lookup — legacy orchestrator-flush
|
|
3625
|
+
* tests use `Object.create(Orchestrator.prototype)` which does not run
|
|
3626
|
+
* class-field initializers, so the Map may be undefined on stubs.
|
|
3627
|
+
*/
|
|
3628
|
+
getCodingContextForSession(sessionKey) {
|
|
3629
|
+
if (typeof sessionKey !== "string" || sessionKey.length === 0) return null;
|
|
3630
|
+
return this._codingContextBySession?.get(sessionKey) ?? null;
|
|
3631
|
+
}
|
|
3632
|
+
/**
|
|
3633
|
+
* Shared helper used by both the recall path and the write path (rule 42).
|
|
3634
|
+
*
|
|
3635
|
+
* Given a base namespace computed from the principal, returns the overlaid
|
|
3636
|
+
* coding namespace when the session has a coding context AND
|
|
3637
|
+
* `codingMode.projectScope` is true AND `namespacesEnabled` is true.
|
|
3638
|
+
* Otherwise returns `baseNamespace` unchanged — CLAUDE.md #30 escape hatch.
|
|
3639
|
+
*
|
|
3640
|
+
* Principal isolation (CLAUDE.md rule 42): the overlay is COMBINED with
|
|
3641
|
+
* the principal-derived `baseNamespace` rather than replacing it, so two
|
|
3642
|
+
* principals working in the same repository do not share memories through
|
|
3643
|
+
* a common `project-*` namespace.
|
|
3644
|
+
*
|
|
3645
|
+
* Namespaces-disabled gate: when `namespacesEnabled` is false, the
|
|
3646
|
+
* storage router maps every namespace to the same `memoryDir`. Returning
|
|
3647
|
+
* `project-*` in that mode would create apparent route separation with
|
|
3648
|
+
* no actual storage isolation — a false-isolation trap. In that mode we
|
|
3649
|
+
* return `baseNamespace` unchanged so coding mode degrades to the existing
|
|
3650
|
+
* unscoped behavior.
|
|
3651
|
+
*
|
|
3652
|
+
* @internal
|
|
3653
|
+
*/
|
|
3654
|
+
applyCodingNamespaceOverlay(sessionKey, baseNamespace) {
|
|
3655
|
+
if (!this.config.namespacesEnabled) return baseNamespace;
|
|
3656
|
+
const codingContext = this.getCodingContextForSession(sessionKey);
|
|
3657
|
+
const overlay = resolveCodingNamespaceOverlay(codingContext, this.config.codingMode);
|
|
3658
|
+
if (!overlay) return baseNamespace;
|
|
3659
|
+
return combineNamespaces(baseNamespace, overlay.namespace);
|
|
3660
|
+
}
|
|
3661
|
+
/**
|
|
3662
|
+
* Read-side overlay: returns the list of namespaces a session should read
|
|
3663
|
+
* from, including any read fallbacks (branch → project asymmetry lands in
|
|
3664
|
+
* PR 3; PR 2 returns an empty fallbacks list).
|
|
3665
|
+
*
|
|
3666
|
+
* Returns `null` when:
|
|
3667
|
+
* - `namespacesEnabled` is false (overlay would create false isolation)
|
|
3668
|
+
* - no context attached to the session
|
|
3669
|
+
* - `codingMode.projectScope` is false (CLAUDE.md #30 escape hatch)
|
|
3670
|
+
*
|
|
3671
|
+
* The returned `namespace` / `readFallbacks` are RAW overlay fragments
|
|
3672
|
+
* (e.g. `project-origin-ab12`). Callers MUST combine them with the
|
|
3673
|
+
* principal-derived base through `combineNamespaces()` before passing to
|
|
3674
|
+
* storage, so principal isolation is preserved (rule 42).
|
|
3675
|
+
*
|
|
3676
|
+
* @internal
|
|
3677
|
+
*/
|
|
3678
|
+
applyCodingRecallOverlay(sessionKey) {
|
|
3679
|
+
if (!this.config.namespacesEnabled) return null;
|
|
3680
|
+
const codingContext = this.getCodingContextForSession(sessionKey);
|
|
3681
|
+
const overlay = resolveCodingNamespaceOverlay(codingContext, this.config.codingMode);
|
|
3682
|
+
if (!overlay) return null;
|
|
3683
|
+
return { namespace: overlay.namespace, readFallbacks: overlay.readFallbacks };
|
|
2978
3684
|
}
|
|
2979
3685
|
async getStorageForNamespace(namespace) {
|
|
2980
3686
|
const ns = typeof namespace === "string" && namespace.trim().length > 0 ? namespace.trim() : this.config.defaultNamespace;
|
|
@@ -3059,7 +3765,7 @@ var Orchestrator = class _Orchestrator {
|
|
|
3059
3765
|
this.config = config;
|
|
3060
3766
|
this.profiler = new ProfilingCollector({
|
|
3061
3767
|
enabled: config.profilingEnabled,
|
|
3062
|
-
storageDir: config.profilingStorageDir ||
|
|
3768
|
+
storageDir: config.profilingStorageDir || path7.join(config.memoryDir, "profiling"),
|
|
3063
3769
|
maxTraces: config.profilingMaxTraces
|
|
3064
3770
|
});
|
|
3065
3771
|
this.storageRouter = new NamespaceStorageRouter(config);
|
|
@@ -3086,7 +3792,7 @@ var Orchestrator = class _Orchestrator {
|
|
|
3086
3792
|
this.compounding = config.compoundingEnabled ? new CompoundingEngine(config) : void 0;
|
|
3087
3793
|
this.buffer = new SmartBuffer(config, this.storage);
|
|
3088
3794
|
this.transcript = new TranscriptManager(config);
|
|
3089
|
-
this.conversationIndexDir =
|
|
3795
|
+
this.conversationIndexDir = path7.join(
|
|
3090
3796
|
config.memoryDir,
|
|
3091
3797
|
"conversation-index",
|
|
3092
3798
|
"chunks"
|
|
@@ -3110,7 +3816,9 @@ var Orchestrator = class _Orchestrator {
|
|
|
3110
3816
|
this.transcript
|
|
3111
3817
|
);
|
|
3112
3818
|
this.judgeVerdictCache = createVerdictCache();
|
|
3819
|
+
this.judgeDeferCounts = createDeferCountMap();
|
|
3113
3820
|
this.localLlm = new LocalLlmClient(config, this.modelRegistry);
|
|
3821
|
+
this.localLlm.disableThinking = config.localLlmDisableThinking;
|
|
3114
3822
|
this.fastLlm = config.localLlmFastEnabled ? (() => {
|
|
3115
3823
|
const client = new LocalLlmClient(
|
|
3116
3824
|
{
|
|
@@ -3124,7 +3832,7 @@ var Orchestrator = class _Orchestrator {
|
|
|
3124
3832
|
client.disableThinking = true;
|
|
3125
3833
|
return client;
|
|
3126
3834
|
})() : this.localLlm;
|
|
3127
|
-
this.
|
|
3835
|
+
this._fastGatewayLlm = config.modelSource === "gateway" ? new FallbackLlmClient(config.gatewayConfig) : null;
|
|
3128
3836
|
if (config.modelSource === "gateway") {
|
|
3129
3837
|
log.debug(
|
|
3130
3838
|
`orchestrator: gateway model source active` + (config.gatewayAgentId ? ` (primary: ${config.gatewayAgentId})` : "") + (config.fastGatewayAgentId ? ` (fast: ${config.fastGatewayAgentId})` : "")
|
|
@@ -3138,7 +3846,7 @@ var Orchestrator = class _Orchestrator {
|
|
|
3138
3846
|
this.modelRegistry
|
|
3139
3847
|
);
|
|
3140
3848
|
this.threading = new ThreadingManager(
|
|
3141
|
-
|
|
3849
|
+
path7.join(config.memoryDir, "threads"),
|
|
3142
3850
|
config.threadingGapMinutes
|
|
3143
3851
|
);
|
|
3144
3852
|
this.tmtBuilder = new TmtBuilder(config.memoryDir, {
|
|
@@ -3324,9 +4032,9 @@ var Orchestrator = class _Orchestrator {
|
|
|
3324
4032
|
* routes through the gateway chain. Otherwise uses the local fast LLM.
|
|
3325
4033
|
*/
|
|
3326
4034
|
async fastChatCompletion(messages, options) {
|
|
3327
|
-
if (this.
|
|
4035
|
+
if (this._fastGatewayLlm && this.config.modelSource === "gateway") {
|
|
3328
4036
|
const agentId = this.config.fastGatewayAgentId || this.config.gatewayAgentId || void 0;
|
|
3329
|
-
const result2 = await this.
|
|
4037
|
+
const result2 = await this._fastGatewayLlm.chatCompletion(
|
|
3330
4038
|
messages,
|
|
3331
4039
|
{ temperature: options.temperature, maxTokens: options.maxTokens, timeoutMs: options.timeoutMs, agentId }
|
|
3332
4040
|
);
|
|
@@ -3341,7 +4049,7 @@ var Orchestrator = class _Orchestrator {
|
|
|
3341
4049
|
* Otherwise returns the local fast LLM directly.
|
|
3342
4050
|
*/
|
|
3343
4051
|
get fastLlmForRerank() {
|
|
3344
|
-
if (this.
|
|
4052
|
+
if (this._fastGatewayLlm && this.config.modelSource === "gateway") {
|
|
3345
4053
|
return {
|
|
3346
4054
|
chatCompletion: (messages, options) => this.fastChatCompletion(messages, options ?? {})
|
|
3347
4055
|
};
|
|
@@ -3383,7 +4091,7 @@ var Orchestrator = class _Orchestrator {
|
|
|
3383
4091
|
promotionByOutcomeEnabled: this.config.promotionByOutcomeEnabled
|
|
3384
4092
|
});
|
|
3385
4093
|
if (this.config.factDeduplicationEnabled) {
|
|
3386
|
-
const stateDir =
|
|
4094
|
+
const stateDir = path7.join(this.config.memoryDir, "state");
|
|
3387
4095
|
this.contentHashIndex = new ContentHashIndex(stateDir);
|
|
3388
4096
|
await this.contentHashIndex.load();
|
|
3389
4097
|
log.info(
|
|
@@ -3412,7 +4120,7 @@ var Orchestrator = class _Orchestrator {
|
|
|
3412
4120
|
const files = await readdir3(wsDir).catch(() => []);
|
|
3413
4121
|
for (const f of files) {
|
|
3414
4122
|
if (!f.startsWith(".compaction-reset-signal-")) continue;
|
|
3415
|
-
const fp =
|
|
4123
|
+
const fp = path7.join(wsDir, f);
|
|
3416
4124
|
const s = await stat3(fp).catch(() => null);
|
|
3417
4125
|
if (s && Date.now() - s.mtimeMs >= COMPACTION_SIGNAL_MAX_AGE_MS) {
|
|
3418
4126
|
await unlink2(fp).catch(() => {
|
|
@@ -3441,6 +4149,7 @@ var Orchestrator = class _Orchestrator {
|
|
|
3441
4149
|
(entry) => entry.namespace === this.config.defaultNamespace
|
|
3442
4150
|
)?.state ?? "unknown";
|
|
3443
4151
|
if (defaultState === "missing") {
|
|
4152
|
+
await this.disposeSearchBackendIfNeeded();
|
|
3444
4153
|
this.qmd = new NoopSearchBackend();
|
|
3445
4154
|
log.warn(
|
|
3446
4155
|
"Search collection missing for Remnic memory store; disabling search retrieval for this runtime (fallback retrieval remains enabled)"
|
|
@@ -3501,10 +4210,11 @@ var Orchestrator = class _Orchestrator {
|
|
|
3501
4210
|
log.info("QMD startup sync: updating index to match current disk state");
|
|
3502
4211
|
if (this.config.namespacesEnabled) {
|
|
3503
4212
|
await this.namespaceSearchRouter.updateNamespaces(
|
|
3504
|
-
this.configuredNamespaces()
|
|
4213
|
+
this.configuredNamespaces(),
|
|
4214
|
+
{ signal }
|
|
3505
4215
|
);
|
|
3506
4216
|
} else {
|
|
3507
|
-
await this.qmd.update();
|
|
4217
|
+
await this.qmd.update({ signal });
|
|
3508
4218
|
}
|
|
3509
4219
|
log.info("QMD startup sync: complete");
|
|
3510
4220
|
this.deferredSyncSucceeded = true;
|
|
@@ -3521,7 +4231,7 @@ var Orchestrator = class _Orchestrator {
|
|
|
3521
4231
|
const warmupNs = this.config.defaultNamespace;
|
|
3522
4232
|
log.info("QMD warmup: pre-loading models with a test search");
|
|
3523
4233
|
warmupPromises.push(
|
|
3524
|
-
this.qmd.search("warmup", warmupNs, 1).then(() => {
|
|
4234
|
+
this.qmd.search("warmup", warmupNs, 1, void 0, { signal }).then(() => {
|
|
3525
4235
|
log.info("QMD warmup: complete");
|
|
3526
4236
|
}).catch((err) => {
|
|
3527
4237
|
log.debug(`QMD warmup search failed (non-fatal): ${err}`);
|
|
@@ -3611,6 +4321,13 @@ var Orchestrator = class _Orchestrator {
|
|
|
3611
4321
|
log.debug(`procedural mining cron auto-register failed (non-fatal): ${err}`);
|
|
3612
4322
|
}
|
|
3613
4323
|
}
|
|
4324
|
+
if (this.config.contradictionScan?.enabled) {
|
|
4325
|
+
try {
|
|
4326
|
+
await this.autoRegisterContradictionScanCron();
|
|
4327
|
+
} catch (err) {
|
|
4328
|
+
log.debug(`contradiction scan cron auto-register failed (non-fatal): ${err}`);
|
|
4329
|
+
}
|
|
4330
|
+
}
|
|
3614
4331
|
log.info("orchestrator initialized (full \u2014 deferred steps complete)");
|
|
3615
4332
|
}
|
|
3616
4333
|
/**
|
|
@@ -3654,6 +4371,7 @@ var Orchestrator = class _Orchestrator {
|
|
|
3654
4371
|
if ("available" in this.qmd) {
|
|
3655
4372
|
this.qmd.available = false;
|
|
3656
4373
|
}
|
|
4374
|
+
await this.disposeSearchBackendIfNeeded();
|
|
3657
4375
|
this.qmd = new NoopSearchBackend();
|
|
3658
4376
|
log.warn("startupSearchSync: search collection missing; disabling search (fallback retrieval remains enabled)");
|
|
3659
4377
|
return false;
|
|
@@ -3668,9 +4386,12 @@ var Orchestrator = class _Orchestrator {
|
|
|
3668
4386
|
log.info("startupSearchSync: updating index to match current disk state");
|
|
3669
4387
|
let namespacesUpdated = 0;
|
|
3670
4388
|
if (this.config.namespacesEnabled) {
|
|
3671
|
-
namespacesUpdated = await this.namespaceSearchRouter.updateNamespaces(
|
|
4389
|
+
namespacesUpdated = await this.namespaceSearchRouter.updateNamespaces(
|
|
4390
|
+
namespaces,
|
|
4391
|
+
{ signal }
|
|
4392
|
+
);
|
|
3672
4393
|
} else {
|
|
3673
|
-
await this.qmd.update(signal);
|
|
4394
|
+
await this.qmd.update({ signal });
|
|
3674
4395
|
}
|
|
3675
4396
|
if (signal?.aborted) {
|
|
3676
4397
|
log.debug("startupSearchSync: aborted after update");
|
|
@@ -3714,7 +4435,7 @@ var Orchestrator = class _Orchestrator {
|
|
|
3714
4435
|
*/
|
|
3715
4436
|
async autoRegisterDaySummaryCron() {
|
|
3716
4437
|
const home = resolveHomeDir();
|
|
3717
|
-
const jobsPath =
|
|
4438
|
+
const jobsPath = path7.join(home, ".openclaw", "cron", "jobs.json");
|
|
3718
4439
|
try {
|
|
3719
4440
|
if (!existsSync2(jobsPath)) {
|
|
3720
4441
|
log.debug(
|
|
@@ -3738,7 +4459,7 @@ var Orchestrator = class _Orchestrator {
|
|
|
3738
4459
|
}
|
|
3739
4460
|
async autoRegisterNightlyGovernanceCron() {
|
|
3740
4461
|
const home = process.env.HOME || os.homedir();
|
|
3741
|
-
const jobsPath =
|
|
4462
|
+
const jobsPath = path7.join(home, ".openclaw", "cron", "jobs.json");
|
|
3742
4463
|
try {
|
|
3743
4464
|
if (!existsSync2(jobsPath)) {
|
|
3744
4465
|
log.debug("nightly governance cron: jobs.json not found, skipping auto-register");
|
|
@@ -3760,7 +4481,7 @@ var Orchestrator = class _Orchestrator {
|
|
|
3760
4481
|
}
|
|
3761
4482
|
async autoRegisterProceduralMiningCron() {
|
|
3762
4483
|
const home = resolveHomeDir();
|
|
3763
|
-
const jobsPath =
|
|
4484
|
+
const jobsPath = path7.join(home, ".openclaw", "cron", "jobs.json");
|
|
3764
4485
|
try {
|
|
3765
4486
|
if (!existsSync2(jobsPath)) {
|
|
3766
4487
|
log.debug("procedural mining cron: jobs.json not found, skipping auto-register");
|
|
@@ -3778,6 +4499,26 @@ var Orchestrator = class _Orchestrator {
|
|
|
3778
4499
|
log.debug(`procedural mining cron auto-register error: ${err}`);
|
|
3779
4500
|
}
|
|
3780
4501
|
}
|
|
4502
|
+
async autoRegisterContradictionScanCron() {
|
|
4503
|
+
const home = resolveHomeDir();
|
|
4504
|
+
const jobsPath = path7.join(home, ".openclaw", "cron", "jobs.json");
|
|
4505
|
+
try {
|
|
4506
|
+
if (!existsSync2(jobsPath)) {
|
|
4507
|
+
log.debug("contradiction scan cron: jobs.json not found, skipping auto-register");
|
|
4508
|
+
return;
|
|
4509
|
+
}
|
|
4510
|
+
const created = await ensureContradictionScanCron(jobsPath, {
|
|
4511
|
+
timezone: Intl.DateTimeFormat().resolvedOptions().timeZone
|
|
4512
|
+
});
|
|
4513
|
+
if (created.created) {
|
|
4514
|
+
log.info(`contradiction scan cron auto-registered (${created.jobId})`);
|
|
4515
|
+
} else {
|
|
4516
|
+
log.debug("contradiction scan cron already exists, skipping auto-register");
|
|
4517
|
+
}
|
|
4518
|
+
} catch (err) {
|
|
4519
|
+
log.debug(`contradiction scan cron auto-register error: ${err}`);
|
|
4520
|
+
}
|
|
4521
|
+
}
|
|
3781
4522
|
async applyBehaviorRuntimePolicy(state) {
|
|
3782
4523
|
const result = await this.policyRuntime.applyFromBehaviorState(state);
|
|
3783
4524
|
this.runtimePolicyValues = await this.policyRuntime.loadRuntimeValues();
|
|
@@ -3796,15 +4537,15 @@ var Orchestrator = class _Orchestrator {
|
|
|
3796
4537
|
this.lastFileHygieneRunAtMs = now;
|
|
3797
4538
|
if (hygiene.rotateEnabled) {
|
|
3798
4539
|
for (const rel of hygiene.rotatePaths) {
|
|
3799
|
-
const abs =
|
|
4540
|
+
const abs = path7.isAbsolute(rel) ? rel : path7.join(this.config.workspaceDir, rel);
|
|
3800
4541
|
try {
|
|
3801
|
-
const raw = await
|
|
4542
|
+
const raw = await readFile4(abs, "utf-8");
|
|
3802
4543
|
if (raw.length > hygiene.rotateMaxBytes) {
|
|
3803
|
-
const archiveDir =
|
|
4544
|
+
const archiveDir = path7.join(
|
|
3804
4545
|
this.config.workspaceDir,
|
|
3805
4546
|
hygiene.archiveDir
|
|
3806
4547
|
);
|
|
3807
|
-
const base =
|
|
4548
|
+
const base = path7.basename(abs);
|
|
3808
4549
|
const prefix = base.toUpperCase().replace(/\.MD$/i, "").replace(/[^A-Z0-9]+/g, "-") || "FILE";
|
|
3809
4550
|
const { newContent } = await rotateMarkdownFileToArchive({
|
|
3810
4551
|
filePath: abs,
|
|
@@ -3812,7 +4553,7 @@ var Orchestrator = class _Orchestrator {
|
|
|
3812
4553
|
archivePrefix: prefix,
|
|
3813
4554
|
keepTailChars: hygiene.rotateKeepTailChars
|
|
3814
4555
|
});
|
|
3815
|
-
await
|
|
4556
|
+
await writeFile4(abs, newContent, "utf-8");
|
|
3816
4557
|
}
|
|
3817
4558
|
} catch {
|
|
3818
4559
|
}
|
|
@@ -3829,8 +4570,8 @@ var Orchestrator = class _Orchestrator {
|
|
|
3829
4570
|
log.warn(w.message);
|
|
3830
4571
|
}
|
|
3831
4572
|
if (hygiene.warningsLogEnabled && warnings.length > 0) {
|
|
3832
|
-
const fp =
|
|
3833
|
-
await
|
|
4573
|
+
const fp = path7.join(this.config.memoryDir, hygiene.warningsLogPath);
|
|
4574
|
+
await mkdir5(path7.dirname(fp), { recursive: true });
|
|
3834
4575
|
const stamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
3835
4576
|
const block = `
|
|
3836
4577
|
|
|
@@ -3839,11 +4580,11 @@ var Orchestrator = class _Orchestrator {
|
|
|
3839
4580
|
` + warnings.map((w) => `- ${w.message}`).join("\n") + "\n";
|
|
3840
4581
|
let existing = "";
|
|
3841
4582
|
try {
|
|
3842
|
-
existing = await
|
|
4583
|
+
existing = await readFile4(fp, "utf-8");
|
|
3843
4584
|
} catch {
|
|
3844
4585
|
existing = "# Engram File Hygiene Warnings\n";
|
|
3845
4586
|
}
|
|
3846
|
-
await
|
|
4587
|
+
await writeFile4(fp, existing + block, "utf-8");
|
|
3847
4588
|
}
|
|
3848
4589
|
}
|
|
3849
4590
|
}
|
|
@@ -3927,14 +4668,15 @@ var Orchestrator = class _Orchestrator {
|
|
|
3927
4668
|
}
|
|
3928
4669
|
for (const cluster of clusters) {
|
|
3929
4670
|
try {
|
|
3930
|
-
|
|
4671
|
+
const operatorAwareEnabled = this.config.operatorAwareConsolidationEnabled === true;
|
|
4672
|
+
let prompt = operatorAwareEnabled ? buildOperatorAwareConsolidationPrompt(cluster) : buildConsolidationPrompt(cluster);
|
|
3931
4673
|
if (extensionsBlock.length > 0) {
|
|
3932
4674
|
prompt += "\n\n" + extensionsBlock;
|
|
3933
4675
|
}
|
|
3934
4676
|
const messages = [
|
|
3935
4677
|
{
|
|
3936
4678
|
role: "system",
|
|
3937
|
-
content: "You are a memory consolidation system. Output only the consolidated memory text."
|
|
4679
|
+
content: operatorAwareEnabled ? 'You are a memory consolidation system. Return ONLY a JSON object with two keys, "operator" and "output". The "operator" value MUST be one of the exact strings "merge", "update", or "split" \u2014 never a pipe-separated placeholder, never prose. The "output" value is the canonical memory text.' : "You are a memory consolidation system. Output only the consolidated memory text."
|
|
3938
4680
|
},
|
|
3939
4681
|
{ role: "user", content: prompt }
|
|
3940
4682
|
];
|
|
@@ -3960,13 +4702,31 @@ var Orchestrator = class _Orchestrator {
|
|
|
3960
4702
|
result.errors++;
|
|
3961
4703
|
continue;
|
|
3962
4704
|
}
|
|
3963
|
-
|
|
4705
|
+
let canonicalContent;
|
|
4706
|
+
let operator;
|
|
4707
|
+
if (operatorAwareEnabled) {
|
|
4708
|
+
const parsed = parseOperatorAwareConsolidationResponse(
|
|
4709
|
+
response.content,
|
|
4710
|
+
cluster
|
|
4711
|
+
);
|
|
4712
|
+
canonicalContent = parsed.output;
|
|
4713
|
+
operator = parsed.operator;
|
|
4714
|
+
} else {
|
|
4715
|
+
canonicalContent = parseConsolidationResponse(response.content);
|
|
4716
|
+
operator = chooseConsolidationOperator(cluster);
|
|
4717
|
+
}
|
|
3964
4718
|
cluster.canonicalContent = canonicalContent;
|
|
3965
4719
|
const sorted = [...cluster.memories].sort(
|
|
3966
4720
|
(a, b) => new Date(b.frontmatter.created).getTime() - new Date(a.frontmatter.created).getTime()
|
|
3967
4721
|
);
|
|
3968
4722
|
const newest = sorted[0];
|
|
3969
4723
|
const lineageIds = cluster.memories.map((m) => m.frontmatter.id);
|
|
4724
|
+
const derivedFromEntries = [];
|
|
4725
|
+
for (const m of cluster.memories) {
|
|
4726
|
+
if (!m.path) continue;
|
|
4727
|
+
const entry = await this.storage.snapshotForProvenance(m.path);
|
|
4728
|
+
if (entry) derivedFromEntries.push(entry);
|
|
4729
|
+
}
|
|
3970
4730
|
const canonicalId = await this.storage.writeMemory(
|
|
3971
4731
|
newest.frontmatter.category,
|
|
3972
4732
|
canonicalContent,
|
|
@@ -3979,7 +4739,9 @@ var Orchestrator = class _Orchestrator {
|
|
|
3979
4739
|
)
|
|
3980
4740
|
],
|
|
3981
4741
|
source: "semantic-consolidation",
|
|
3982
|
-
lineage: lineageIds
|
|
4742
|
+
lineage: lineageIds,
|
|
4743
|
+
derivedFrom: derivedFromEntries.length > 0 ? derivedFromEntries : void 0,
|
|
4744
|
+
derivedVia: operator
|
|
3983
4745
|
}
|
|
3984
4746
|
);
|
|
3985
4747
|
result.memoriesConsolidated++;
|
|
@@ -4221,18 +4983,18 @@ ${evidenceText}`
|
|
|
4221
4983
|
const datesToScan = [yesterday, utcToday].filter(
|
|
4222
4984
|
(v, i, a) => a.indexOf(v) === i
|
|
4223
4985
|
);
|
|
4224
|
-
const factsBaseDir =
|
|
4986
|
+
const factsBaseDir = path7.join(storage.dir, "facts");
|
|
4225
4987
|
const MAX_CHARS = 1e5;
|
|
4226
4988
|
const facts = [];
|
|
4227
4989
|
for (const date of datesToScan) {
|
|
4228
|
-
const factsDir =
|
|
4990
|
+
const factsDir = path7.join(factsBaseDir, date);
|
|
4229
4991
|
try {
|
|
4230
4992
|
const entries = await readdir3(factsDir, { withFileTypes: true });
|
|
4231
4993
|
for (const entry of entries) {
|
|
4232
4994
|
if (!entry.name.endsWith(".md")) continue;
|
|
4233
|
-
const fullPath =
|
|
4995
|
+
const fullPath = path7.join(factsDir, entry.name);
|
|
4234
4996
|
try {
|
|
4235
|
-
const raw = await
|
|
4997
|
+
const raw = await readFile4(fullPath, "utf-8");
|
|
4236
4998
|
const fmMatch = raw.match(/^---\n([\s\S]*?)\n---\n?([\s\S]*)$/);
|
|
4237
4999
|
if (!fmMatch) continue;
|
|
4238
5000
|
const fmBlock = fmMatch[1];
|
|
@@ -4246,7 +5008,7 @@ ${evidenceText}`
|
|
|
4246
5008
|
facts.push({
|
|
4247
5009
|
path: fullPath,
|
|
4248
5010
|
frontmatter: {
|
|
4249
|
-
id: fm.id ||
|
|
5011
|
+
id: fm.id || path7.basename(entry.name, ".md"),
|
|
4250
5012
|
category: fm.category || "fact",
|
|
4251
5013
|
created: fm.created || "unknown",
|
|
4252
5014
|
updated: fm.updated || fm.created || "unknown",
|
|
@@ -4267,15 +5029,15 @@ ${evidenceText}`
|
|
|
4267
5029
|
(a, b) => a.frontmatter.created < b.frontmatter.created ? -1 : 1
|
|
4268
5030
|
);
|
|
4269
5031
|
const hourlySummaries = [];
|
|
4270
|
-
const hourlyBaseDir =
|
|
5032
|
+
const hourlyBaseDir = path7.join(storage.dir, "summaries", "hourly");
|
|
4271
5033
|
try {
|
|
4272
5034
|
const sessionKeys = await readdir3(hourlyBaseDir, { withFileTypes: true });
|
|
4273
5035
|
for (const sk of sessionKeys) {
|
|
4274
5036
|
if (!sk.isDirectory()) continue;
|
|
4275
5037
|
for (const date of datesToScan) {
|
|
4276
|
-
const summaryFile =
|
|
5038
|
+
const summaryFile = path7.join(hourlyBaseDir, sk.name, `${date}.md`);
|
|
4277
5039
|
try {
|
|
4278
|
-
const raw = await
|
|
5040
|
+
const raw = await readFile4(summaryFile, "utf-8");
|
|
4279
5041
|
if (raw.trim().length > 0) {
|
|
4280
5042
|
hourlySummaries.push(raw.trim());
|
|
4281
5043
|
}
|
|
@@ -4371,13 +5133,13 @@ ${evidenceText}`
|
|
|
4371
5133
|
}
|
|
4372
5134
|
async getLastGraphRecallSnapshot(namespace) {
|
|
4373
5135
|
const storage = await this.getStorage(namespace);
|
|
4374
|
-
const snapshotPath =
|
|
5136
|
+
const snapshotPath = path7.join(
|
|
4375
5137
|
storage.dir,
|
|
4376
5138
|
"state",
|
|
4377
5139
|
"last_graph_recall.json"
|
|
4378
5140
|
);
|
|
4379
5141
|
try {
|
|
4380
|
-
const raw = await
|
|
5142
|
+
const raw = await readFile4(snapshotPath, "utf-8");
|
|
4381
5143
|
const parsed = JSON.parse(raw);
|
|
4382
5144
|
if (!parsed || typeof parsed !== "object") return null;
|
|
4383
5145
|
return {
|
|
@@ -4410,9 +5172,9 @@ ${evidenceText}`
|
|
|
4410
5172
|
}
|
|
4411
5173
|
async getLastIntentSnapshot(namespace) {
|
|
4412
5174
|
const storage = await this.getStorage(namespace);
|
|
4413
|
-
const snapshotPath =
|
|
5175
|
+
const snapshotPath = path7.join(storage.dir, "state", "last_intent.json");
|
|
4414
5176
|
try {
|
|
4415
|
-
const raw = await
|
|
5177
|
+
const raw = await readFile4(snapshotPath, "utf-8");
|
|
4416
5178
|
const parsed = JSON.parse(raw);
|
|
4417
5179
|
if (!parsed || typeof parsed !== "object") return null;
|
|
4418
5180
|
const graphDecision = parsed.graphDecision && typeof parsed.graphDecision === "object" ? parsed.graphDecision : void 0;
|
|
@@ -4443,13 +5205,13 @@ ${evidenceText}`
|
|
|
4443
5205
|
}
|
|
4444
5206
|
async getLastQmdRecallSnapshot(namespace) {
|
|
4445
5207
|
const storage = await this.getStorage(namespace);
|
|
4446
|
-
const snapshotPath =
|
|
5208
|
+
const snapshotPath = path7.join(
|
|
4447
5209
|
storage.dir,
|
|
4448
5210
|
"state",
|
|
4449
5211
|
"last_qmd_recall.json"
|
|
4450
5212
|
);
|
|
4451
5213
|
try {
|
|
4452
|
-
const raw = await
|
|
5214
|
+
const raw = await readFile4(snapshotPath, "utf-8");
|
|
4453
5215
|
const parsed = JSON.parse(raw);
|
|
4454
5216
|
if (!parsed || typeof parsed !== "object") return null;
|
|
4455
5217
|
return {
|
|
@@ -4595,7 +5357,7 @@ ${r.snippet.trim()}
|
|
|
4595
5357
|
const entries = await readdir3(dir, { withFileTypes: true });
|
|
4596
5358
|
let total = 0;
|
|
4597
5359
|
for (const entry of entries) {
|
|
4598
|
-
const fullPath =
|
|
5360
|
+
const fullPath = path7.join(dir, entry.name);
|
|
4599
5361
|
if (entry.isDirectory()) {
|
|
4600
5362
|
total += await this.countConversationChunkDocs(fullPath);
|
|
4601
5363
|
continue;
|
|
@@ -4866,11 +5628,24 @@ ${r.snippet.trim()}
|
|
|
4866
5628
|
reject(new Error("recall timeout"));
|
|
4867
5629
|
}, RECALL_TIMEOUT_MS);
|
|
4868
5630
|
});
|
|
5631
|
+
let recallResult;
|
|
4869
5632
|
try {
|
|
4870
|
-
|
|
5633
|
+
recallResult = await Promise.race([recallPromise, timeoutPromise]);
|
|
4871
5634
|
} finally {
|
|
4872
5635
|
if (timeoutHandle) clearTimeout(timeoutHandle);
|
|
4873
5636
|
}
|
|
5637
|
+
if (this.config.recallDirectAnswerEnabled && sessionKey) {
|
|
5638
|
+
try {
|
|
5639
|
+
this.enqueueDirectAnswerObservation(
|
|
5640
|
+
prompt,
|
|
5641
|
+
sessionKey,
|
|
5642
|
+
options.namespace?.trim() || void 0
|
|
5643
|
+
);
|
|
5644
|
+
} catch (err) {
|
|
5645
|
+
log.debug(`direct-answer observation setup failed: ${err}`);
|
|
5646
|
+
}
|
|
5647
|
+
}
|
|
5648
|
+
return recallResult;
|
|
4874
5649
|
} catch (err) {
|
|
4875
5650
|
this.logRecallFailure(err);
|
|
4876
5651
|
this.profiler.endTrace();
|
|
@@ -4879,6 +5654,183 @@ ${r.snippet.trim()}
|
|
|
4879
5654
|
options.abortSignal?.removeEventListener("abort", onAbort);
|
|
4880
5655
|
}
|
|
4881
5656
|
}
|
|
5657
|
+
/**
|
|
5658
|
+
* Return the most recent X-ray snapshot captured during a
|
|
5659
|
+
* `recall()` call that passed `xrayCapture: true` (issue #570 PR 1).
|
|
5660
|
+
* Returns `null` when no such capture has occurred on this
|
|
5661
|
+
* orchestrator instance. Returned snapshot is a deep copy so
|
|
5662
|
+
* caller mutation cannot tear the stored value.
|
|
5663
|
+
*/
|
|
5664
|
+
getLastXraySnapshot() {
|
|
5665
|
+
if (!this.lastXraySnapshot) return null;
|
|
5666
|
+
return structuredClone(this.lastXraySnapshot);
|
|
5667
|
+
}
|
|
5668
|
+
/** Clear the captured X-ray snapshot. Exposed for tests / explicit reset. */
|
|
5669
|
+
clearLastXraySnapshot() {
|
|
5670
|
+
this.lastXraySnapshot = null;
|
|
5671
|
+
}
|
|
5672
|
+
/**
|
|
5673
|
+
* Await the in-flight observation-mode direct-answer annotation chain.
|
|
5674
|
+
* Resolves to true when settled, false on timeout.
|
|
5675
|
+
*/
|
|
5676
|
+
async waitForDirectAnswerObservationIdle(timeoutMs = 6e4) {
|
|
5677
|
+
let timeoutHandle = null;
|
|
5678
|
+
try {
|
|
5679
|
+
const timeoutPromise = new Promise((resolve) => {
|
|
5680
|
+
timeoutHandle = setTimeout(() => resolve("timeout"), timeoutMs);
|
|
5681
|
+
});
|
|
5682
|
+
const result = await Promise.race([
|
|
5683
|
+
this.directAnswerObservationChain.then(() => "ok"),
|
|
5684
|
+
timeoutPromise
|
|
5685
|
+
]);
|
|
5686
|
+
if (result === "timeout") {
|
|
5687
|
+
log.warn(
|
|
5688
|
+
`waitForDirectAnswerObservationIdle timed out after ${timeoutMs}ms`
|
|
5689
|
+
);
|
|
5690
|
+
return false;
|
|
5691
|
+
}
|
|
5692
|
+
return true;
|
|
5693
|
+
} finally {
|
|
5694
|
+
if (timeoutHandle) clearTimeout(timeoutHandle);
|
|
5695
|
+
}
|
|
5696
|
+
}
|
|
5697
|
+
enqueueDirectAnswerObservation(prompt, sessionKey, namespaceOverride) {
|
|
5698
|
+
const expectedSnapshot = this.lastRecall.get(sessionKey);
|
|
5699
|
+
if (expectedSnapshot === null) return;
|
|
5700
|
+
if (expectedSnapshot.plannerMode === "no_recall") return;
|
|
5701
|
+
const principal = resolvePrincipal(sessionKey, this.config);
|
|
5702
|
+
const observationCodingOverlay = namespaceOverride && canReadNamespace(principal, namespaceOverride, this.config) ? null : this.applyCodingRecallOverlay(sessionKey);
|
|
5703
|
+
const observationPrincipalSelf = defaultNamespaceForPrincipal(principal, this.config);
|
|
5704
|
+
const observationCodingSelf = observationCodingOverlay ? combineNamespaces(observationPrincipalSelf, observationCodingOverlay.namespace) : null;
|
|
5705
|
+
let observationNamespaces;
|
|
5706
|
+
if (namespaceOverride && canReadNamespace(principal, namespaceOverride, this.config)) {
|
|
5707
|
+
observationNamespaces = [namespaceOverride];
|
|
5708
|
+
} else if (observationCodingOverlay && observationCodingSelf) {
|
|
5709
|
+
const base = recallNamespacesForPrincipal(principal, this.config);
|
|
5710
|
+
const mapped = base.map(
|
|
5711
|
+
(ns) => ns === observationPrincipalSelf ? observationCodingSelf : ns
|
|
5712
|
+
);
|
|
5713
|
+
const fallbackNs = observationCodingOverlay.readFallbacks.map(
|
|
5714
|
+
(fallback) => combineNamespaces(observationPrincipalSelf, fallback)
|
|
5715
|
+
);
|
|
5716
|
+
observationNamespaces = Array.from(/* @__PURE__ */ new Set([...mapped, ...fallbackNs]));
|
|
5717
|
+
} else {
|
|
5718
|
+
observationNamespaces = recallNamespacesForPrincipal(principal, this.config);
|
|
5719
|
+
}
|
|
5720
|
+
const observationQueryPolicy = buildRecallQueryPolicy(prompt, sessionKey, {
|
|
5721
|
+
cronRecallPolicyEnabled: this.config.cronRecallPolicyEnabled,
|
|
5722
|
+
cronRecallNormalizedQueryMaxChars: this.config.cronRecallNormalizedQueryMaxChars,
|
|
5723
|
+
cronRecallInstructionHeavyTokenCap: this.effectiveCronRecallInstructionHeavyTokenCap(),
|
|
5724
|
+
cronConversationRecallMode: this.config.cronConversationRecallMode
|
|
5725
|
+
});
|
|
5726
|
+
const observationQuery = observationQueryPolicy.retrievalQuery || prompt;
|
|
5727
|
+
const expectedIdentity = {
|
|
5728
|
+
writeNonce: expectedSnapshot.writeNonce,
|
|
5729
|
+
traceId: expectedSnapshot.traceId,
|
|
5730
|
+
recordedAt: expectedSnapshot.recordedAt
|
|
5731
|
+
};
|
|
5732
|
+
const previous = this.directAnswerObservationChain;
|
|
5733
|
+
this.directAnswerObservationChain = previous.catch(() => void 0).then(async () => {
|
|
5734
|
+
try {
|
|
5735
|
+
await this.annotateDirectAnswerTier(
|
|
5736
|
+
observationQuery,
|
|
5737
|
+
sessionKey,
|
|
5738
|
+
observationNamespaces,
|
|
5739
|
+
expectedIdentity,
|
|
5740
|
+
void 0
|
|
5741
|
+
);
|
|
5742
|
+
} catch (err) {
|
|
5743
|
+
log.debug(`direct-answer observation chain error: ${err}`);
|
|
5744
|
+
}
|
|
5745
|
+
});
|
|
5746
|
+
}
|
|
5747
|
+
async annotateDirectAnswerTier(prompt, sessionKey, namespaces, expectedIdentity, _parentAbortSignal) {
|
|
5748
|
+
const tierStart = Date.now();
|
|
5749
|
+
try {
|
|
5750
|
+
if (namespaces.length === 0) return;
|
|
5751
|
+
const trustZoneByNsAndRecordId = /* @__PURE__ */ new Map();
|
|
5752
|
+
const trustZoneKey = (ns, recordId) => `${ns}\0${recordId}`;
|
|
5753
|
+
const scopedStorages = /* @__PURE__ */ new Map();
|
|
5754
|
+
for (const ns of namespaces) {
|
|
5755
|
+
const storage = await this.storageRouter.storageFor(ns);
|
|
5756
|
+
scopedStorages.set(ns, storage);
|
|
5757
|
+
const trustZones = await listTrustZoneRecords({
|
|
5758
|
+
memoryDir: storage.dir,
|
|
5759
|
+
trustZoneStoreDir: this.config.trustZoneStoreDir,
|
|
5760
|
+
limit: 200
|
|
5761
|
+
}).catch(() => ({
|
|
5762
|
+
allRecords: []
|
|
5763
|
+
}));
|
|
5764
|
+
for (const record of trustZones.allRecords ?? []) {
|
|
5765
|
+
trustZoneByNsAndRecordId.set(
|
|
5766
|
+
trustZoneKey(ns, record.recordId),
|
|
5767
|
+
record.zone
|
|
5768
|
+
);
|
|
5769
|
+
}
|
|
5770
|
+
}
|
|
5771
|
+
const memoryNamespaceByPath = /* @__PURE__ */ new Map();
|
|
5772
|
+
const memoryNamespaceById = /* @__PURE__ */ new Map();
|
|
5773
|
+
let candidatesConsidered = 0;
|
|
5774
|
+
const sources = {
|
|
5775
|
+
taxonomy: DEFAULT_TAXONOMY,
|
|
5776
|
+
listCandidateMemories: async (options) => {
|
|
5777
|
+
const targetNs = options.namespace;
|
|
5778
|
+
const storage = scopedStorages.get(targetNs) ?? await this.storageRouter.storageFor(targetNs);
|
|
5779
|
+
const all = await storage.readAllMemories();
|
|
5780
|
+
const active = [];
|
|
5781
|
+
for (const m of all) {
|
|
5782
|
+
if ((m.frontmatter.status ?? "active") === "active") {
|
|
5783
|
+
active.push(m);
|
|
5784
|
+
memoryNamespaceByPath.set(m.path, targetNs);
|
|
5785
|
+
if (m.frontmatter.id) {
|
|
5786
|
+
memoryNamespaceById.set(m.frontmatter.id, targetNs);
|
|
5787
|
+
}
|
|
5788
|
+
}
|
|
5789
|
+
}
|
|
5790
|
+
candidatesConsidered += active.length;
|
|
5791
|
+
return active;
|
|
5792
|
+
},
|
|
5793
|
+
trustZoneFor: async (memoryId) => {
|
|
5794
|
+
const ns = memoryNamespaceById.get(memoryId);
|
|
5795
|
+
if (!ns) return null;
|
|
5796
|
+
return trustZoneByNsAndRecordId.get(
|
|
5797
|
+
trustZoneKey(ns, memoryId)
|
|
5798
|
+
) ?? null;
|
|
5799
|
+
},
|
|
5800
|
+
importanceFor: (memory) => typeof memory.frontmatter.importance?.score === "number" ? memory.frontmatter.importance.score : 0
|
|
5801
|
+
};
|
|
5802
|
+
let result;
|
|
5803
|
+
for (const ns of namespaces) {
|
|
5804
|
+
const r = await tryDirectAnswer({
|
|
5805
|
+
query: prompt,
|
|
5806
|
+
namespace: ns,
|
|
5807
|
+
config: this.config,
|
|
5808
|
+
sources
|
|
5809
|
+
});
|
|
5810
|
+
if (r.eligible && r.winner) {
|
|
5811
|
+
result = r;
|
|
5812
|
+
break;
|
|
5813
|
+
}
|
|
5814
|
+
}
|
|
5815
|
+
if (!result?.eligible || !result?.winner) return;
|
|
5816
|
+
const explain = {
|
|
5817
|
+
tier: "direct-answer",
|
|
5818
|
+
tierReason: result.narrative,
|
|
5819
|
+
filteredBy: result.filteredBy,
|
|
5820
|
+
candidatesConsidered,
|
|
5821
|
+
latencyMs: Date.now() - tierStart,
|
|
5822
|
+
sourceAnchors: [{ path: result.winner.memory.path }]
|
|
5823
|
+
};
|
|
5824
|
+
await this.lastRecall.annotateTierExplain(
|
|
5825
|
+
sessionKey,
|
|
5826
|
+
explain,
|
|
5827
|
+
expectedIdentity
|
|
5828
|
+
);
|
|
5829
|
+
} catch (err) {
|
|
5830
|
+
if (err instanceof Error && err.name === "AbortError") return;
|
|
5831
|
+
log.debug(`direct-answer observation failed: ${err}`);
|
|
5832
|
+
}
|
|
5833
|
+
}
|
|
4882
5834
|
logRecallFailure(err) {
|
|
4883
5835
|
const now = Date.now();
|
|
4884
5836
|
const errorMsg = err instanceof Error ? err.message : String(err);
|
|
@@ -5282,7 +6234,7 @@ ${r.snippet.trim()}
|
|
|
5282
6234
|
0
|
|
5283
6235
|
);
|
|
5284
6236
|
seedPaths.push(
|
|
5285
|
-
...seedRelativePaths.map((rel) =>
|
|
6237
|
+
...seedRelativePaths.map((rel) => path7.join(storage.dir, rel))
|
|
5286
6238
|
);
|
|
5287
6239
|
const seedSet = new Set(seedRelativePaths);
|
|
5288
6240
|
const expanded = await this.graphIndexFor(storage).spreadingActivation(
|
|
@@ -5292,7 +6244,7 @@ ${r.snippet.trim()}
|
|
|
5292
6244
|
if (expanded.length === 0) continue;
|
|
5293
6245
|
for (const candidate of expanded.slice(0, perNamespaceExpandedCap)) {
|
|
5294
6246
|
if (seedSet.has(candidate.path)) continue;
|
|
5295
|
-
const memoryPath =
|
|
6247
|
+
const memoryPath = path7.resolve(storage.dir, candidate.path);
|
|
5296
6248
|
const memory = await storage.readMemoryByPath(memoryPath);
|
|
5297
6249
|
if (!memory) continue;
|
|
5298
6250
|
if (isArtifactMemoryPath(memory.path)) continue;
|
|
@@ -5316,7 +6268,7 @@ ${r.snippet.trim()}
|
|
|
5316
6268
|
path: memory.path,
|
|
5317
6269
|
score,
|
|
5318
6270
|
namespace,
|
|
5319
|
-
seed:
|
|
6271
|
+
seed: path7.resolve(storage.dir, candidate.seed),
|
|
5320
6272
|
hopDepth: candidate.hopDepth,
|
|
5321
6273
|
decayedWeight: candidate.decayedWeight,
|
|
5322
6274
|
graphType: candidate.graphType
|
|
@@ -5332,12 +6284,12 @@ ${r.snippet.trim()}
|
|
|
5332
6284
|
}
|
|
5333
6285
|
async recordLastGraphRecallSnapshot(options) {
|
|
5334
6286
|
try {
|
|
5335
|
-
const snapshotPath =
|
|
6287
|
+
const snapshotPath = path7.join(
|
|
5336
6288
|
options.storage.dir,
|
|
5337
6289
|
"state",
|
|
5338
6290
|
"last_graph_recall.json"
|
|
5339
6291
|
);
|
|
5340
|
-
await
|
|
6292
|
+
await mkdir5(path7.dirname(snapshotPath), { recursive: true });
|
|
5341
6293
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
5342
6294
|
const totalSeedCount = options.seedPaths.length;
|
|
5343
6295
|
const totalExpandedCount = options.expandedPaths.length;
|
|
@@ -5364,20 +6316,20 @@ ${r.snippet.trim()}
|
|
|
5364
6316
|
finalResults: (options.finalResults ?? []).slice(0, 64),
|
|
5365
6317
|
shadowComparison: options.shadowComparison
|
|
5366
6318
|
};
|
|
5367
|
-
await
|
|
6319
|
+
await writeFile4(snapshotPath, JSON.stringify(payload, null, 2), "utf-8");
|
|
5368
6320
|
} catch (err) {
|
|
5369
6321
|
log.debug(`last graph recall write failed: ${err}`);
|
|
5370
6322
|
}
|
|
5371
6323
|
}
|
|
5372
6324
|
async recordLastIntentSnapshot(options) {
|
|
5373
6325
|
try {
|
|
5374
|
-
const snapshotPath =
|
|
6326
|
+
const snapshotPath = path7.join(
|
|
5375
6327
|
options.storage.dir,
|
|
5376
6328
|
"state",
|
|
5377
6329
|
"last_intent.json"
|
|
5378
6330
|
);
|
|
5379
|
-
await
|
|
5380
|
-
await
|
|
6331
|
+
await mkdir5(path7.dirname(snapshotPath), { recursive: true });
|
|
6332
|
+
await writeFile4(
|
|
5381
6333
|
snapshotPath,
|
|
5382
6334
|
JSON.stringify(options.snapshot, null, 2),
|
|
5383
6335
|
"utf-8"
|
|
@@ -5388,13 +6340,13 @@ ${r.snippet.trim()}
|
|
|
5388
6340
|
}
|
|
5389
6341
|
async recordLastQmdRecallSnapshot(options) {
|
|
5390
6342
|
try {
|
|
5391
|
-
const snapshotPath =
|
|
6343
|
+
const snapshotPath = path7.join(
|
|
5392
6344
|
options.storage.dir,
|
|
5393
6345
|
"state",
|
|
5394
6346
|
"last_qmd_recall.json"
|
|
5395
6347
|
);
|
|
5396
|
-
await
|
|
5397
|
-
await
|
|
6348
|
+
await mkdir5(path7.dirname(snapshotPath), { recursive: true });
|
|
6349
|
+
await writeFile4(
|
|
5398
6350
|
snapshotPath,
|
|
5399
6351
|
JSON.stringify(options.snapshot, null, 2),
|
|
5400
6352
|
"utf-8"
|
|
@@ -5408,9 +6360,9 @@ ${r.snippet.trim()}
|
|
|
5408
6360
|
const stateDir = await this.resolveStateDirForNamespace(
|
|
5409
6361
|
options.namespace
|
|
5410
6362
|
);
|
|
5411
|
-
const snapshotPath =
|
|
5412
|
-
await
|
|
5413
|
-
await
|
|
6363
|
+
const snapshotPath = path7.join(stateDir, "last_intent.json");
|
|
6364
|
+
await mkdir5(path7.dirname(snapshotPath), { recursive: true });
|
|
6365
|
+
await writeFile4(
|
|
5414
6366
|
snapshotPath,
|
|
5415
6367
|
JSON.stringify(options.snapshot, null, 2),
|
|
5416
6368
|
"utf-8"
|
|
@@ -5421,12 +6373,12 @@ ${r.snippet.trim()}
|
|
|
5421
6373
|
}
|
|
5422
6374
|
async resolveStateDirForNamespace(namespace) {
|
|
5423
6375
|
if (!this.config.namespacesEnabled) {
|
|
5424
|
-
return
|
|
6376
|
+
return path7.join(this.config.memoryDir, "state");
|
|
5425
6377
|
}
|
|
5426
6378
|
if (namespace !== this.config.defaultNamespace) {
|
|
5427
|
-
return
|
|
6379
|
+
return path7.join(this.config.memoryDir, "namespaces", namespace, "state");
|
|
5428
6380
|
}
|
|
5429
|
-
const candidate =
|
|
6381
|
+
const candidate = path7.join(
|
|
5430
6382
|
this.config.memoryDir,
|
|
5431
6383
|
"namespaces",
|
|
5432
6384
|
this.config.defaultNamespace
|
|
@@ -5434,11 +6386,11 @@ ${r.snippet.trim()}
|
|
|
5434
6386
|
try {
|
|
5435
6387
|
const candidateStat = await stat3(candidate);
|
|
5436
6388
|
if (candidateStat.isDirectory()) {
|
|
5437
|
-
return
|
|
6389
|
+
return path7.join(candidate, "state");
|
|
5438
6390
|
}
|
|
5439
6391
|
} catch {
|
|
5440
6392
|
}
|
|
5441
|
-
return
|
|
6393
|
+
return path7.join(this.config.memoryDir, "state");
|
|
5442
6394
|
}
|
|
5443
6395
|
buildGraphRecallRankedResults(results, sourceLabelResolver, limit = 64) {
|
|
5444
6396
|
return results.slice(0, limit).map((result) => ({
|
|
@@ -5524,7 +6476,10 @@ ${r.snippet.trim()}
|
|
|
5524
6476
|
}
|
|
5525
6477
|
return reserved;
|
|
5526
6478
|
}
|
|
5527
|
-
getRecallBudgetChars() {
|
|
6479
|
+
getRecallBudgetChars(override) {
|
|
6480
|
+
if (typeof override === "number" && Number.isFinite(override) && override >= 0) {
|
|
6481
|
+
return Math.floor(override);
|
|
6482
|
+
}
|
|
5528
6483
|
const configuredBudget = this.config.recallBudgetChars;
|
|
5529
6484
|
if (typeof configuredBudget === "number" && Number.isFinite(configuredBudget) && configuredBudget >= 0) {
|
|
5530
6485
|
return Math.floor(configuredBudget);
|
|
@@ -5535,7 +6490,7 @@ ${r.snippet.trim()}
|
|
|
5535
6490
|
}
|
|
5536
6491
|
return 0;
|
|
5537
6492
|
}
|
|
5538
|
-
assembleRecallSections(sectionBuckets) {
|
|
6493
|
+
assembleRecallSections(sectionBuckets, budgetOverride) {
|
|
5539
6494
|
const orderedEntries = [];
|
|
5540
6495
|
const pipeline = Array.isArray(this.config.recallPipeline) ? this.config.recallPipeline : [];
|
|
5541
6496
|
const orderedIds = pipeline.filter((entry) => entry.enabled !== false).map((entry) => entry.id);
|
|
@@ -5551,7 +6506,7 @@ ${r.snippet.trim()}
|
|
|
5551
6506
|
if (chunks.length === 0) continue;
|
|
5552
6507
|
orderedEntries.push({ id, content: chunks.join("\n\n") });
|
|
5553
6508
|
}
|
|
5554
|
-
const budget = this.getRecallBudgetChars();
|
|
6509
|
+
const budget = this.getRecallBudgetChars(budgetOverride);
|
|
5555
6510
|
if (budget === 0) {
|
|
5556
6511
|
return {
|
|
5557
6512
|
sections: [],
|
|
@@ -5683,6 +6638,13 @@ ${r.snippet.trim()}
|
|
|
5683
6638
|
let recalledMemoryCount = 0;
|
|
5684
6639
|
let recalledMemoryIds = [];
|
|
5685
6640
|
let recalledMemoryPaths = [];
|
|
6641
|
+
const xrayBranchPoolSize = {
|
|
6642
|
+
hot_qmd: 0,
|
|
6643
|
+
hot_embedding: 0,
|
|
6644
|
+
cold_fallback: 0,
|
|
6645
|
+
recent_scan: 0
|
|
6646
|
+
};
|
|
6647
|
+
const xrayColdPoolSink = { size: 0 };
|
|
5686
6648
|
let identityInjectionModeUsed = "none";
|
|
5687
6649
|
let identityInjectedChars = 0;
|
|
5688
6650
|
let identityInjectionTruncated = false;
|
|
@@ -5743,7 +6705,7 @@ ${r.snippet.trim()}
|
|
|
5743
6705
|
this.config.verbatimArtifactsMaxRecall
|
|
5744
6706
|
);
|
|
5745
6707
|
const embeddingFetchLimit = computedFetchLimit;
|
|
5746
|
-
const principal = resolvePrincipal(sessionKey, this.config);
|
|
6708
|
+
const principal = typeof options.principalOverride === "string" && options.principalOverride.length > 0 ? options.principalOverride : resolvePrincipal(sessionKey, this.config);
|
|
5747
6709
|
const namespaceOverride = options.namespace?.trim() || void 0;
|
|
5748
6710
|
const readableRecallNamespaces = recallNamespacesForPrincipal(
|
|
5749
6711
|
principal,
|
|
@@ -5754,8 +6716,24 @@ ${r.snippet.trim()}
|
|
|
5754
6716
|
`namespace override is not readable: ${namespaceOverride}`
|
|
5755
6717
|
);
|
|
5756
6718
|
}
|
|
5757
|
-
const
|
|
5758
|
-
const
|
|
6719
|
+
const codingOverlay = namespaceOverride ? null : this.applyCodingRecallOverlay(sessionKey);
|
|
6720
|
+
const principalSelfNamespace = defaultNamespaceForPrincipal(principal, this.config);
|
|
6721
|
+
const codingSelfNamespace = codingOverlay ? combineNamespaces(principalSelfNamespace, codingOverlay.namespace) : null;
|
|
6722
|
+
const selfNamespace = namespaceOverride ?? codingSelfNamespace ?? principalSelfNamespace;
|
|
6723
|
+
let recallNamespaces;
|
|
6724
|
+
if (namespaceOverride) {
|
|
6725
|
+
recallNamespaces = [namespaceOverride];
|
|
6726
|
+
} else if (codingOverlay && codingSelfNamespace) {
|
|
6727
|
+
const mapped = readableRecallNamespaces.map(
|
|
6728
|
+
(ns) => ns === principalSelfNamespace ? codingSelfNamespace : ns
|
|
6729
|
+
);
|
|
6730
|
+
const fallbackNs = codingOverlay.readFallbacks.map(
|
|
6731
|
+
(fallback) => combineNamespaces(principalSelfNamespace, fallback)
|
|
6732
|
+
);
|
|
6733
|
+
recallNamespaces = Array.from(/* @__PURE__ */ new Set([...mapped, ...fallbackNs]));
|
|
6734
|
+
} else {
|
|
6735
|
+
recallNamespaces = readableRecallNamespaces;
|
|
6736
|
+
}
|
|
5759
6737
|
const qmdAvailable = this.qmd.isAvailable();
|
|
5760
6738
|
let graphDecisionStatus = recallDecision.plannedMode === "graph_mode" ? "skipped" : "not_requested";
|
|
5761
6739
|
let graphDecisionReason = recallDecision.graphReason;
|
|
@@ -5772,7 +6750,7 @@ ${r.snippet.trim()}
|
|
|
5772
6750
|
const graphExpandedResultPaths = /* @__PURE__ */ new Set();
|
|
5773
6751
|
const graphSourceLabelsForPath = (resultPath) => {
|
|
5774
6752
|
const labels = [];
|
|
5775
|
-
const normalizedPath = resultPath.split(
|
|
6753
|
+
const normalizedPath = resultPath.split(path7.sep).join("/");
|
|
5776
6754
|
const isEntityPath = normalizedPath.startsWith("entities/") || normalizedPath.includes("/entities/");
|
|
5777
6755
|
if (graphBaselinePaths.has(resultPath)) labels.push("baseline");
|
|
5778
6756
|
if (graphExpandedResultPaths.has(resultPath))
|
|
@@ -5810,6 +6788,32 @@ ${r.snippet.trim()}
|
|
|
5810
6788
|
const earlySessionKey = sessionKey ?? "default";
|
|
5811
6789
|
this._recallWorkspaceOverrides.delete(earlySessionKey);
|
|
5812
6790
|
timings.total = `${Date.now() - recallStart}ms`;
|
|
6791
|
+
if (options.xrayCapture === true && !options.abortSignal?.aborted) {
|
|
6792
|
+
try {
|
|
6793
|
+
this.lastXraySnapshot = buildXraySnapshot({
|
|
6794
|
+
query: retrievalQuery,
|
|
6795
|
+
tierExplain: null,
|
|
6796
|
+
results: [],
|
|
6797
|
+
filters: [
|
|
6798
|
+
{
|
|
6799
|
+
name: "planner-mode",
|
|
6800
|
+
considered: 0,
|
|
6801
|
+
admitted: 0,
|
|
6802
|
+
reason: "no_recall"
|
|
6803
|
+
}
|
|
6804
|
+
],
|
|
6805
|
+
budget: {
|
|
6806
|
+
chars: this.getRecallBudgetChars(options.budgetCharsOverride),
|
|
6807
|
+
used: 0
|
|
6808
|
+
},
|
|
6809
|
+
sessionKey,
|
|
6810
|
+
namespace: selfNamespace,
|
|
6811
|
+
traceId
|
|
6812
|
+
});
|
|
6813
|
+
} catch (err) {
|
|
6814
|
+
log.debug(`x-ray capture (no_recall) failed: ${err}`);
|
|
6815
|
+
}
|
|
6816
|
+
}
|
|
5813
6817
|
if (sessionKey) {
|
|
5814
6818
|
this.lastRecall.record({
|
|
5815
6819
|
sessionKey,
|
|
@@ -6959,16 +7963,16 @@ ${formatted}`;
|
|
|
6959
7963
|
if (!this.config.compactionResetEnabled) return null;
|
|
6960
7964
|
const workspaceDir = compactionWorkspaceDir || this.config.workspaceDir || defaultWorkspaceDir();
|
|
6961
7965
|
const safeSessionKey = sanitizeSessionKeyForFilename(effectiveSessionKey);
|
|
6962
|
-
const signalPath =
|
|
7966
|
+
const signalPath = path7.join(
|
|
6963
7967
|
workspaceDir,
|
|
6964
7968
|
`.compaction-reset-signal-${safeSessionKey}`
|
|
6965
7969
|
);
|
|
6966
|
-
const bootPath =
|
|
7970
|
+
const bootPath = path7.join(workspaceDir, "BOOT.md");
|
|
6967
7971
|
try {
|
|
6968
7972
|
const signalStat = await stat3(signalPath).catch(() => null);
|
|
6969
7973
|
if (!signalStat) return null;
|
|
6970
7974
|
const signalAge = Date.now() - signalStat.mtimeMs;
|
|
6971
|
-
const signalData = JSON.parse(await
|
|
7975
|
+
const signalData = JSON.parse(await readFile4(signalPath, "utf-8"));
|
|
6972
7976
|
if (signalData.sessionKey !== effectiveSessionKey) {
|
|
6973
7977
|
log.debug(
|
|
6974
7978
|
`recall: compaction signal is for ${signalData.sessionKey}, not ${effectiveSessionKey} \u2014 skipping`
|
|
@@ -6988,7 +7992,7 @@ ${formatted}`;
|
|
|
6988
7992
|
|
|
6989
7993
|
`;
|
|
6990
7994
|
try {
|
|
6991
|
-
const bootContent = await
|
|
7995
|
+
const bootContent = await readFile4(bootPath, "utf-8");
|
|
6992
7996
|
section += "### BOOT.md (working state before compaction)\n\n";
|
|
6993
7997
|
section += bootContent + "\n";
|
|
6994
7998
|
} catch {
|
|
@@ -7182,7 +8186,7 @@ ${formatted}`;
|
|
|
7182
8186
|
if (!this.isRecallSectionEnabled("procedure-recall", true)) return null;
|
|
7183
8187
|
try {
|
|
7184
8188
|
return await buildProcedureRecallSection(
|
|
7185
|
-
|
|
8189
|
+
profileStorage,
|
|
7186
8190
|
retrievalQuery,
|
|
7187
8191
|
this.config
|
|
7188
8192
|
);
|
|
@@ -7695,7 +8699,18 @@ ${tmtNode.summary}`
|
|
|
7695
8699
|
"rerankProvider=cloud is reserved/experimental in v2.2.0; skipping rerank"
|
|
7696
8700
|
);
|
|
7697
8701
|
}
|
|
8702
|
+
if (this.config.recallMemoryWorthFilterEnabled && memoryResults.length > 0) {
|
|
8703
|
+
try {
|
|
8704
|
+
memoryResults = await this.applyMemoryWorthRerank(memoryResults, recallNamespaces);
|
|
8705
|
+
} catch (err) {
|
|
8706
|
+
log.debug("memory-worth filter failed open", { error: err.message });
|
|
8707
|
+
}
|
|
8708
|
+
}
|
|
7698
8709
|
const effectiveGateScore = preAugmentTopScore > 0 ? Math.max(preAugmentTopScore, maxSpecializedScore) : 0;
|
|
8710
|
+
xrayBranchPoolSize.hot_qmd = Math.max(
|
|
8711
|
+
xrayBranchPoolSize.hot_qmd,
|
|
8712
|
+
memoryResults.length
|
|
8713
|
+
);
|
|
7699
8714
|
let confidenceGateRejected = false;
|
|
7700
8715
|
if (this.config.recallConfidenceGateEnabled && effectiveGateScore > 0) {
|
|
7701
8716
|
if (effectiveGateScore < this.config.recallConfidenceGateThreshold) {
|
|
@@ -7709,7 +8724,8 @@ ${tmtNode.summary}`
|
|
|
7709
8724
|
memoryResults = this.diversifyAndLimitRecallResults(
|
|
7710
8725
|
"memories",
|
|
7711
8726
|
memoryResults,
|
|
7712
|
-
recallResultLimit
|
|
8727
|
+
recallResultLimit,
|
|
8728
|
+
retrievalQuery
|
|
7713
8729
|
);
|
|
7714
8730
|
if (this.config.memoryReconstructionEnabled && memoryResults.length > 0) {
|
|
7715
8731
|
try {
|
|
@@ -7794,10 +8810,15 @@ ${tmtNode.summary}`
|
|
|
7794
8810
|
recallNamespaces,
|
|
7795
8811
|
retrievalQuery
|
|
7796
8812
|
);
|
|
8813
|
+
xrayBranchPoolSize.hot_embedding = Math.max(
|
|
8814
|
+
xrayBranchPoolSize.hot_embedding,
|
|
8815
|
+
boostedScoped.length
|
|
8816
|
+
);
|
|
7797
8817
|
const scoped = this.diversifyAndLimitRecallResults(
|
|
7798
8818
|
"memories",
|
|
7799
8819
|
boostedScoped,
|
|
7800
|
-
recallResultLimit
|
|
8820
|
+
recallResultLimit,
|
|
8821
|
+
retrievalQuery
|
|
7801
8822
|
);
|
|
7802
8823
|
if (scoped.length > 0) {
|
|
7803
8824
|
if (shouldPersistGraphSnapshot) {
|
|
@@ -7830,7 +8851,8 @@ ${tmtNode.summary}`
|
|
|
7830
8851
|
recallResultLimit,
|
|
7831
8852
|
recallMode,
|
|
7832
8853
|
queryAwarePrefilter,
|
|
7833
|
-
abortSignal: options.abortSignal
|
|
8854
|
+
abortSignal: options.abortSignal,
|
|
8855
|
+
xrayPoolSizeSink: xrayColdPoolSink
|
|
7834
8856
|
});
|
|
7835
8857
|
if (longTerm.length > 0) {
|
|
7836
8858
|
if (shouldPersistGraphSnapshot) {
|
|
@@ -7914,10 +8936,15 @@ ${tmtNode.summary}`
|
|
|
7914
8936
|
recallNamespaces,
|
|
7915
8937
|
retrievalQuery
|
|
7916
8938
|
);
|
|
8939
|
+
xrayBranchPoolSize.hot_embedding = Math.max(
|
|
8940
|
+
xrayBranchPoolSize.hot_embedding,
|
|
8941
|
+
boostedScoped.length
|
|
8942
|
+
);
|
|
7917
8943
|
const scoped = this.diversifyAndLimitRecallResults(
|
|
7918
8944
|
"memories",
|
|
7919
8945
|
boostedScoped,
|
|
7920
|
-
recallResultLimit
|
|
8946
|
+
recallResultLimit,
|
|
8947
|
+
retrievalQuery
|
|
7921
8948
|
);
|
|
7922
8949
|
if (scoped.length > 0) {
|
|
7923
8950
|
if (shouldPersistGraphSnapshot) {
|
|
@@ -7971,7 +8998,8 @@ ${tmtNode.summary}`
|
|
|
7971
8998
|
recallResultLimit,
|
|
7972
8999
|
recallMode,
|
|
7973
9000
|
queryAwarePrefilter,
|
|
7974
|
-
abortSignal: options.abortSignal
|
|
9001
|
+
abortSignal: options.abortSignal,
|
|
9002
|
+
xrayPoolSizeSink: xrayColdPoolSink
|
|
7975
9003
|
});
|
|
7976
9004
|
if (longTerm.length > 0) {
|
|
7977
9005
|
recallSource = "cold_fallback";
|
|
@@ -8013,10 +9041,15 @@ ${tmtNode.summary}`
|
|
|
8013
9041
|
retrievalQuery,
|
|
8014
9042
|
preloadedMap
|
|
8015
9043
|
)).sort((a, b) => b.score - a.score);
|
|
9044
|
+
xrayBranchPoolSize.recent_scan = Math.max(
|
|
9045
|
+
xrayBranchPoolSize.recent_scan,
|
|
9046
|
+
boostedRecent.length
|
|
9047
|
+
);
|
|
8016
9048
|
const recent = this.diversifyAndLimitRecallResults(
|
|
8017
9049
|
"memories",
|
|
8018
9050
|
boostedRecent,
|
|
8019
|
-
recallResultLimit
|
|
9051
|
+
recallResultLimit,
|
|
9052
|
+
retrievalQuery
|
|
8020
9053
|
);
|
|
8021
9054
|
if (recent.length > 0) {
|
|
8022
9055
|
if (shouldPersistGraphSnapshot) {
|
|
@@ -8049,7 +9082,8 @@ ${tmtNode.summary}`
|
|
|
8049
9082
|
recallResultLimit,
|
|
8050
9083
|
recallMode,
|
|
8051
9084
|
queryAwarePrefilter,
|
|
8052
|
-
abortSignal: options.abortSignal
|
|
9085
|
+
abortSignal: options.abortSignal,
|
|
9086
|
+
xrayPoolSizeSink: xrayColdPoolSink
|
|
8053
9087
|
});
|
|
8054
9088
|
if (longTerm.length > 0) {
|
|
8055
9089
|
if (shouldPersistGraphSnapshot) {
|
|
@@ -8085,7 +9119,8 @@ ${tmtNode.summary}`
|
|
|
8085
9119
|
recallResultLimit,
|
|
8086
9120
|
recallMode,
|
|
8087
9121
|
queryAwarePrefilter,
|
|
8088
|
-
abortSignal: options.abortSignal
|
|
9122
|
+
abortSignal: options.abortSignal,
|
|
9123
|
+
xrayPoolSizeSink: xrayColdPoolSink
|
|
8089
9124
|
});
|
|
8090
9125
|
if (longTerm.length > 0) {
|
|
8091
9126
|
if (shouldPersistGraphSnapshot) {
|
|
@@ -8244,7 +9279,10 @@ _Context: ${topQuestion.context}_`
|
|
|
8244
9279
|
);
|
|
8245
9280
|
const timingParts = Object.entries(timings).map(([k, v]) => `${k}=${v}`).join(", ");
|
|
8246
9281
|
log.info(`recall timings: ${timingParts}`);
|
|
8247
|
-
const assembledRecall = this.assembleRecallSections(
|
|
9282
|
+
const assembledRecall = this.assembleRecallSections(
|
|
9283
|
+
sectionBuckets,
|
|
9284
|
+
options.budgetCharsOverride
|
|
9285
|
+
);
|
|
8248
9286
|
const context = assembledRecall.sections.length === 0 ? "" : assembledRecall.sections.join("\n\n---\n\n");
|
|
8249
9287
|
const sourcesUsed = this.collectLastRecallSources(
|
|
8250
9288
|
sectionBuckets,
|
|
@@ -8260,6 +9298,73 @@ _Context: ${topQuestion.context}_`
|
|
|
8260
9298
|
includedSections: assembledRecall.includedIds,
|
|
8261
9299
|
omittedSections: assembledRecall.omittedIds
|
|
8262
9300
|
});
|
|
9301
|
+
if (options.xrayCapture === true && !options.abortSignal?.aborted) {
|
|
9302
|
+
try {
|
|
9303
|
+
const servedBy = mapRecallSourceToXrayServedBy(recallSource);
|
|
9304
|
+
const idFromPath = (p) => {
|
|
9305
|
+
const match = p.match(/([^/]+)\.md$/);
|
|
9306
|
+
return match ? match[1] ?? null : null;
|
|
9307
|
+
};
|
|
9308
|
+
const results = [];
|
|
9309
|
+
for (const recalledPath of recalledMemoryPaths) {
|
|
9310
|
+
const derivedId = idFromPath(recalledPath);
|
|
9311
|
+
if (!derivedId) continue;
|
|
9312
|
+
results.push({
|
|
9313
|
+
memoryId: derivedId,
|
|
9314
|
+
path: recalledPath,
|
|
9315
|
+
servedBy,
|
|
9316
|
+
scoreDecomposition: { final: 0 },
|
|
9317
|
+
admittedBy: []
|
|
9318
|
+
});
|
|
9319
|
+
}
|
|
9320
|
+
let xrayConsidered;
|
|
9321
|
+
switch (recallSource) {
|
|
9322
|
+
case "hot_qmd":
|
|
9323
|
+
xrayConsidered = xrayBranchPoolSize.hot_qmd;
|
|
9324
|
+
break;
|
|
9325
|
+
case "hot_embedding":
|
|
9326
|
+
xrayConsidered = xrayBranchPoolSize.hot_embedding;
|
|
9327
|
+
break;
|
|
9328
|
+
case "cold_fallback":
|
|
9329
|
+
xrayConsidered = xrayColdPoolSink.size;
|
|
9330
|
+
break;
|
|
9331
|
+
case "recent_scan":
|
|
9332
|
+
xrayConsidered = xrayBranchPoolSize.recent_scan;
|
|
9333
|
+
break;
|
|
9334
|
+
case "none":
|
|
9335
|
+
xrayConsidered = recalledMemoryCount;
|
|
9336
|
+
break;
|
|
9337
|
+
default: {
|
|
9338
|
+
const _exhaustive = recallSource;
|
|
9339
|
+
void _exhaustive;
|
|
9340
|
+
xrayConsidered = recalledMemoryCount;
|
|
9341
|
+
}
|
|
9342
|
+
}
|
|
9343
|
+
xrayConsidered = Math.max(xrayConsidered, recalledMemoryIds.length);
|
|
9344
|
+
const filters = [
|
|
9345
|
+
{
|
|
9346
|
+
name: "recall-result-limit",
|
|
9347
|
+
considered: xrayConsidered,
|
|
9348
|
+
admitted: recalledMemoryIds.length
|
|
9349
|
+
}
|
|
9350
|
+
];
|
|
9351
|
+
this.lastXraySnapshot = buildXraySnapshot({
|
|
9352
|
+
query: retrievalQuery,
|
|
9353
|
+
tierExplain: null,
|
|
9354
|
+
results,
|
|
9355
|
+
filters,
|
|
9356
|
+
budget: {
|
|
9357
|
+
chars: this.getRecallBudgetChars(options.budgetCharsOverride),
|
|
9358
|
+
used: assembledRecall.finalChars
|
|
9359
|
+
},
|
|
9360
|
+
sessionKey,
|
|
9361
|
+
namespace: selfNamespace,
|
|
9362
|
+
traceId
|
|
9363
|
+
});
|
|
9364
|
+
} catch (err) {
|
|
9365
|
+
log.debug(`x-ray capture failed: ${err}`);
|
|
9366
|
+
}
|
|
9367
|
+
}
|
|
8263
9368
|
if (sessionKey) {
|
|
8264
9369
|
throwIfRecallAborted(options.abortSignal);
|
|
8265
9370
|
this.lastRecall.record({
|
|
@@ -8595,7 +9700,7 @@ _Context: ${topQuestion.context}_`
|
|
|
8595
9700
|
if (!this.queueProcessing) {
|
|
8596
9701
|
this.queueProcessing = true;
|
|
8597
9702
|
this.processQueue().catch((err) => {
|
|
8598
|
-
|
|
9703
|
+
this.logExtractionQueueFailure(err, "processor");
|
|
8599
9704
|
this.queueProcessing = false;
|
|
8600
9705
|
});
|
|
8601
9706
|
}
|
|
@@ -8653,12 +9758,38 @@ ${normalized}`).digest("hex");
|
|
|
8653
9758
|
try {
|
|
8654
9759
|
await task();
|
|
8655
9760
|
} catch (err) {
|
|
8656
|
-
|
|
9761
|
+
this.logExtractionQueueFailure(err, "task");
|
|
8657
9762
|
}
|
|
8658
9763
|
}
|
|
8659
9764
|
}
|
|
8660
9765
|
this.queueProcessing = false;
|
|
8661
9766
|
}
|
|
9767
|
+
/**
|
|
9768
|
+
* Classify + log a failure from either the per-task catch inside
|
|
9769
|
+
* `processQueue()` or the outer `processQueue().catch(...)` in
|
|
9770
|
+
* `queueBufferedExtraction()`. Issue #549: `throwIfRecallAborted`
|
|
9771
|
+
* (used throughout `runExtraction`) raises an Error whose `name` is
|
|
9772
|
+
* `"AbortError"`. That path fires when `before_reset` aborts a
|
|
9773
|
+
* queued task to avoid duplicate extraction — it is intentional
|
|
9774
|
+
* cancellation, not a failure. Downgrading the log to debug
|
|
9775
|
+
* prevents spurious `error`-level lines that routinely appear
|
|
9776
|
+
* right next to a successful `persisted: N facts, M entities` log
|
|
9777
|
+
* and that confuse operators into thinking extraction is broken.
|
|
9778
|
+
* Genuine extraction failures (network, parse, I/O) still log at
|
|
9779
|
+
* `error`.
|
|
9780
|
+
*
|
|
9781
|
+
* Source differentiates the two call sites so the log message
|
|
9782
|
+
* names the right layer (`task` vs `processor`).
|
|
9783
|
+
*/
|
|
9784
|
+
logExtractionQueueFailure(err, source) {
|
|
9785
|
+
const aborted = source === "task" ? "background extraction task aborted (session transition)" : "background extraction queue processor aborted (session transition)";
|
|
9786
|
+
const failed = source === "task" ? "background extraction task failed" : "background extraction queue processor failed";
|
|
9787
|
+
if (isAbortError(err)) {
|
|
9788
|
+
log.debug(aborted);
|
|
9789
|
+
} else {
|
|
9790
|
+
log.error(failed, err);
|
|
9791
|
+
}
|
|
9792
|
+
}
|
|
8662
9793
|
async runExtraction(turns, options = {}) {
|
|
8663
9794
|
log.debug(`running extraction on ${turns.length} turns`);
|
|
8664
9795
|
const clearBufferAfterExtraction = options.clearBufferAfterExtraction ?? true;
|
|
@@ -8670,12 +9801,12 @@ ${normalized}`).digest("hex");
|
|
|
8670
9801
|
throw new Error(`replay extraction deadline exceeded (${stage})`);
|
|
8671
9802
|
}
|
|
8672
9803
|
};
|
|
8673
|
-
const
|
|
9804
|
+
const throwIfAborted2 = (stage) => {
|
|
8674
9805
|
throwIfRecallAborted(options.abortSignal, `extraction aborted (${stage})`);
|
|
8675
9806
|
};
|
|
8676
9807
|
const clearBuffer = async (options2) => {
|
|
8677
9808
|
if (options2?.ignoreAbort !== true) {
|
|
8678
|
-
|
|
9809
|
+
throwIfAborted2("before_clear_buffer");
|
|
8679
9810
|
}
|
|
8680
9811
|
if (clearBufferAfterExtraction) {
|
|
8681
9812
|
await this.buffer.clearAfterExtraction(bufferKey);
|
|
@@ -8694,7 +9825,7 @@ ${normalized}`).digest("hex");
|
|
|
8694
9825
|
content: t.content.trim().slice(0, this.config.extractionMaxTurnChars)
|
|
8695
9826
|
})).filter((t) => t.content.length > 0);
|
|
8696
9827
|
throwIfDeadlineExceeded("before_extract");
|
|
8697
|
-
|
|
9828
|
+
throwIfAborted2("before_extract");
|
|
8698
9829
|
const userTurns = normalizedTurns.filter((t) => t.role === "user");
|
|
8699
9830
|
const totalChars = normalizedTurns.reduce(
|
|
8700
9831
|
(sum, t) => sum + t.content.length,
|
|
@@ -8710,7 +9841,10 @@ ${normalized}`).digest("hex");
|
|
|
8710
9841
|
return;
|
|
8711
9842
|
}
|
|
8712
9843
|
const principal = resolvePrincipal(sessionKey, this.config);
|
|
8713
|
-
const selfNamespace = typeof options.writeNamespaceOverride === "string" && options.writeNamespaceOverride.length > 0 ? options.writeNamespaceOverride :
|
|
9844
|
+
const selfNamespace = typeof options.writeNamespaceOverride === "string" && options.writeNamespaceOverride.length > 0 ? options.writeNamespaceOverride : this.applyCodingNamespaceOverlay(
|
|
9845
|
+
sessionKey,
|
|
9846
|
+
defaultNamespaceForPrincipal(principal, this.config)
|
|
9847
|
+
);
|
|
8714
9848
|
const storage = await this.storageRouter.storageFor(selfNamespace);
|
|
8715
9849
|
const shouldPersistProcessedFingerprint = normalizedTurns.some(
|
|
8716
9850
|
(turn) => turn.persistProcessedFingerprint === true
|
|
@@ -8739,7 +9873,7 @@ ${normalized}`).digest("hex");
|
|
|
8739
9873
|
"extraction aborted (during_extract)"
|
|
8740
9874
|
);
|
|
8741
9875
|
throwIfDeadlineExceeded("before_persist");
|
|
8742
|
-
|
|
9876
|
+
throwIfAborted2("before_persist");
|
|
8743
9877
|
if (!result) {
|
|
8744
9878
|
log.warn("runExtraction: extraction returned null/undefined");
|
|
8745
9879
|
await clearBuffer();
|
|
@@ -8803,6 +9937,24 @@ ${normalized}`).digest("hex");
|
|
|
8803
9937
|
} catch (error) {
|
|
8804
9938
|
postPersistMetaError = error;
|
|
8805
9939
|
}
|
|
9940
|
+
try {
|
|
9941
|
+
if (clearBufferAfterExtraction && !this.config.extractionJudgeShadow) {
|
|
9942
|
+
const deferredCount = this.lastPersistExtractionDeferredCount;
|
|
9943
|
+
if (deferredCount > 0 && normalizedTurns.length > 0) {
|
|
9944
|
+
await this.buffer.retainDeferredTurns(
|
|
9945
|
+
bufferKey,
|
|
9946
|
+
normalizedTurns,
|
|
9947
|
+
10
|
|
9948
|
+
);
|
|
9949
|
+
} else {
|
|
9950
|
+
await this.buffer.retainDeferredTurns(bufferKey, [], 0);
|
|
9951
|
+
}
|
|
9952
|
+
}
|
|
9953
|
+
} catch (err) {
|
|
9954
|
+
log.debug(
|
|
9955
|
+
`extraction-judge: defer retention failed (non-fatal): ${err instanceof Error ? err.message : String(err)}`
|
|
9956
|
+
);
|
|
9957
|
+
}
|
|
8806
9958
|
await clearBuffer({ ignoreAbort: true });
|
|
8807
9959
|
if (this.config.memoryBoxesEnabled && persistedIds.length > 0) {
|
|
8808
9960
|
const extractionTopics = deriveTopicsFromExtraction(result);
|
|
@@ -8935,7 +10087,7 @@ ${normalized}`).digest("hex");
|
|
|
8935
10087
|
);
|
|
8936
10088
|
this.tierMigrationInFlight = true;
|
|
8937
10089
|
try {
|
|
8938
|
-
const coldStorage = new StorageManager(
|
|
10090
|
+
const coldStorage = new StorageManager(path7.join(storage.dir, "cold"));
|
|
8939
10091
|
const [hotMemories, coldMemories] = await Promise.all([
|
|
8940
10092
|
storage.readAllMemories(),
|
|
8941
10093
|
coldStorage.readAllMemories()
|
|
@@ -9384,6 +10536,7 @@ ${normalized}`).digest("hex");
|
|
|
9384
10536
|
}
|
|
9385
10537
|
let judgeVerdictsByFactIndex = null;
|
|
9386
10538
|
let judgeGatedCount = 0;
|
|
10539
|
+
this.lastPersistExtractionDeferredCount = 0;
|
|
9387
10540
|
if (this.config.extractionJudgeEnabled) {
|
|
9388
10541
|
try {
|
|
9389
10542
|
const judgeCandidates = [];
|
|
@@ -9418,12 +10571,56 @@ ${normalized}`).digest("hex");
|
|
|
9418
10571
|
});
|
|
9419
10572
|
candidateToFactIndex.push(fi);
|
|
9420
10573
|
}
|
|
10574
|
+
const judgeTelemetryOpts = {
|
|
10575
|
+
enabled: this.config.extractionJudgeTelemetryEnabled === true,
|
|
10576
|
+
memoryDir: this.config.memoryDir
|
|
10577
|
+
};
|
|
10578
|
+
const judgeTrainingOpts = {
|
|
10579
|
+
enabled: this.config.collectJudgeTrainingPairs === true,
|
|
10580
|
+
...this.config.judgeTrainingDir ? { directory: this.config.judgeTrainingDir } : {}
|
|
10581
|
+
};
|
|
10582
|
+
const judgeTelemetryHandler = judgeTelemetryOpts.enabled || judgeTrainingOpts.enabled ? (obs) => {
|
|
10583
|
+
const ts = (/* @__PURE__ */ new Date()).toISOString();
|
|
10584
|
+
const verdictKind = getVerdictKind(obs.verdict);
|
|
10585
|
+
if (judgeTelemetryOpts.enabled) {
|
|
10586
|
+
const event = {
|
|
10587
|
+
version: 1,
|
|
10588
|
+
category: EXTRACTION_JUDGE_VERDICT_CATEGORY,
|
|
10589
|
+
ts,
|
|
10590
|
+
verdictKind,
|
|
10591
|
+
reason: obs.verdict.reason,
|
|
10592
|
+
deferrals: obs.priorDeferrals,
|
|
10593
|
+
elapsedMs: obs.elapsedMs,
|
|
10594
|
+
candidateCategory: obs.candidate.category,
|
|
10595
|
+
confidence: obs.candidate.confidence,
|
|
10596
|
+
contentHash: obs.contentHash,
|
|
10597
|
+
fromCache: obs.source === "cache",
|
|
10598
|
+
...obs.source === "llm-cap-rejected" ? { deferCapTriggered: true } : {}
|
|
10599
|
+
};
|
|
10600
|
+
void recordJudgeVerdict(event, judgeTelemetryOpts);
|
|
10601
|
+
}
|
|
10602
|
+
if (judgeTrainingOpts.enabled) {
|
|
10603
|
+
const pair = {
|
|
10604
|
+
version: 1,
|
|
10605
|
+
ts,
|
|
10606
|
+
candidateText: obs.candidate.text,
|
|
10607
|
+
candidateCategory: obs.candidate.category,
|
|
10608
|
+
...typeof obs.candidate.confidence === "number" ? { candidateConfidence: obs.candidate.confidence } : {},
|
|
10609
|
+
verdictKind,
|
|
10610
|
+
reason: obs.verdict.reason,
|
|
10611
|
+
priorDeferrals: obs.priorDeferrals
|
|
10612
|
+
};
|
|
10613
|
+
void recordJudgeTrainingPair(pair, judgeTrainingOpts);
|
|
10614
|
+
}
|
|
10615
|
+
} : void 0;
|
|
9421
10616
|
const judgeResult = await judgeFactDurability(
|
|
9422
10617
|
judgeCandidates,
|
|
9423
10618
|
this.config,
|
|
9424
10619
|
this.localLlm,
|
|
9425
10620
|
new FallbackLlmClient(this.config.gatewayConfig),
|
|
9426
|
-
this.judgeVerdictCache
|
|
10621
|
+
this.judgeVerdictCache,
|
|
10622
|
+
this.judgeDeferCounts,
|
|
10623
|
+
judgeTelemetryHandler
|
|
9427
10624
|
);
|
|
9428
10625
|
judgeVerdictsByFactIndex = /* @__PURE__ */ new Map();
|
|
9429
10626
|
for (const [candidateIdx, verdict] of judgeResult.verdicts) {
|
|
@@ -9433,8 +10630,9 @@ ${normalized}`).digest("hex");
|
|
|
9433
10630
|
}
|
|
9434
10631
|
}
|
|
9435
10632
|
log.info(
|
|
9436
|
-
`extraction-judge: ${judgeResult.verdicts.size}/${judgeCandidates.length} facts evaluated, ${judgeResult.cached} cached, ${judgeResult.judged} judged, ${judgeResult.elapsed}ms`
|
|
10633
|
+
`extraction-judge: ${judgeResult.verdicts.size}/${judgeCandidates.length} facts evaluated, ${judgeResult.cached} cached, ${judgeResult.judged} judged, ${judgeResult.deferred} deferred` + (judgeResult.deferredCappedToReject > 0 ? ` (${judgeResult.deferredCappedToReject} cap-rejected)` : "") + `, ${judgeResult.elapsed}ms`
|
|
9437
10634
|
);
|
|
10635
|
+
this.lastPersistExtractionDeferredCount = judgeResult.deferred;
|
|
9438
10636
|
} catch (err) {
|
|
9439
10637
|
log.warn(
|
|
9440
10638
|
`extraction-judge: pipeline error, proceeding without filtering (fail-open): ${err instanceof Error ? err.message : String(err)}`
|
|
@@ -9452,16 +10650,6 @@ ${normalized}`).digest("hex");
|
|
|
9452
10650
|
}
|
|
9453
10651
|
fact.tags = Array.isArray(fact.tags) ? fact.tags.filter((t) => typeof t === "string") : [];
|
|
9454
10652
|
fact.confidence = typeof fact.confidence === "number" ? fact.confidence : 0.7;
|
|
9455
|
-
if (this.contentHashIndex) {
|
|
9456
|
-
const canonicalContent = citationEnabled && hasCitationForTemplate(fact.content, citationTemplate) ? stripCitationForTemplate(fact.content, citationTemplate) : fact.content;
|
|
9457
|
-
if (this.contentHashIndex.has(canonicalContent)) {
|
|
9458
|
-
log.debug(
|
|
9459
|
-
`dedup: skipping duplicate fact "${fact.content.slice(0, 60)}\u2026"`
|
|
9460
|
-
);
|
|
9461
|
-
dedupedCount++;
|
|
9462
|
-
continue;
|
|
9463
|
-
}
|
|
9464
|
-
}
|
|
9465
10653
|
let writeCategory = fact.category;
|
|
9466
10654
|
let targetStorage = storage;
|
|
9467
10655
|
let routedRuleId;
|
|
@@ -9486,6 +10674,15 @@ ${normalized}`).digest("hex");
|
|
|
9486
10674
|
);
|
|
9487
10675
|
}
|
|
9488
10676
|
}
|
|
10677
|
+
const canonicalContentForHash = citationEnabled && hasCitationForTemplate(fact.content, citationTemplate) ? stripCitationForTemplate(fact.content, citationTemplate) : fact.content;
|
|
10678
|
+
const contentHashDedupKey = writeCategory === "procedure" ? buildProcedurePersistBody(fact.content, fact.procedureSteps) : canonicalContentForHash;
|
|
10679
|
+
if (this.contentHashIndex && this.contentHashIndex.has(contentHashDedupKey)) {
|
|
10680
|
+
log.debug(
|
|
10681
|
+
`dedup: skipping duplicate fact "${fact.content.slice(0, 60)}\u2026"`
|
|
10682
|
+
);
|
|
10683
|
+
dedupedCount++;
|
|
10684
|
+
continue;
|
|
10685
|
+
}
|
|
9489
10686
|
const importance = scoreImportance(
|
|
9490
10687
|
fact.content,
|
|
9491
10688
|
writeCategory,
|
|
@@ -9510,10 +10707,17 @@ ${normalized}`).digest("hex");
|
|
|
9510
10707
|
if (judgeVerdictsByFactIndex) {
|
|
9511
10708
|
const verdict = judgeVerdictsByFactIndex.get(factLoopIndex);
|
|
9512
10709
|
if (verdict && !verdict.durable) {
|
|
10710
|
+
const verdictKind = getVerdictKind(verdict);
|
|
9513
10711
|
if (this.config.extractionJudgeShadow) {
|
|
9514
10712
|
log.info(
|
|
9515
|
-
`extraction-judge[shadow]: would
|
|
10713
|
+
`extraction-judge[shadow]: would ${verdictKind} "${fact.content.slice(0, 60)}\u2026" reason="${verdict.reason}"`
|
|
10714
|
+
);
|
|
10715
|
+
} else if (verdictKind === "defer") {
|
|
10716
|
+
judgeGatedCount++;
|
|
10717
|
+
log.debug(
|
|
10718
|
+
`extraction-judge: deferred "${fact.content.slice(0, 60)}\u2026" reason="${verdict.reason}"`
|
|
9516
10719
|
);
|
|
10720
|
+
continue;
|
|
9517
10721
|
} else {
|
|
9518
10722
|
judgeGatedCount++;
|
|
9519
10723
|
log.debug(
|
|
@@ -9529,16 +10733,10 @@ ${normalized}`).digest("hex");
|
|
|
9529
10733
|
procedureSteps: fact.procedureSteps
|
|
9530
10734
|
});
|
|
9531
10735
|
if (!procGate.durable) {
|
|
9532
|
-
|
|
9533
|
-
|
|
9534
|
-
|
|
9535
|
-
|
|
9536
|
-
} else {
|
|
9537
|
-
log.debug(
|
|
9538
|
-
`extraction-procedure-gate: rejected "${fact.content.slice(0, 60)}\u2026" reason="${procGate.reason}"`
|
|
9539
|
-
);
|
|
9540
|
-
continue;
|
|
9541
|
-
}
|
|
10736
|
+
log.debug(
|
|
10737
|
+
`extraction-procedure-gate: rejected "${fact.content.slice(0, 60)}\u2026" reason="${procGate.reason}"`
|
|
10738
|
+
);
|
|
10739
|
+
continue;
|
|
9542
10740
|
}
|
|
9543
10741
|
}
|
|
9544
10742
|
let pendingSemanticSkip = null;
|
|
@@ -9935,7 +11133,8 @@ ${normalized}`).digest("hex");
|
|
|
9935
11133
|
}
|
|
9936
11134
|
if (this.contentHashIndex) {
|
|
9937
11135
|
const canonicalFactContent = citationEnabled && hasCitationForTemplate(fact.content, citationTemplate) ? stripCitationForTemplate(fact.content, citationTemplate) : fact.content;
|
|
9938
|
-
|
|
11136
|
+
const hashRegisterKey = writeCategory === "procedure" ? buildProcedurePersistBody(fact.content, fact.procedureSteps) : canonicalFactContent;
|
|
11137
|
+
this.contentHashIndex.add(hashRegisterKey);
|
|
9939
11138
|
}
|
|
9940
11139
|
}
|
|
9941
11140
|
for (const entity of entities) {
|
|
@@ -10061,7 +11260,7 @@ ${normalized}`).digest("hex");
|
|
|
10061
11260
|
const allMems = allMemsForGraph ?? [];
|
|
10062
11261
|
for (const m of allMems) {
|
|
10063
11262
|
if (m.frontmatter.entityRef === entityRef) {
|
|
10064
|
-
const rel =
|
|
11263
|
+
const rel = path7.relative(storage.dir, m.path);
|
|
10065
11264
|
if (rel !== memoryRelPath) entitySiblings.push(rel);
|
|
10066
11265
|
}
|
|
10067
11266
|
}
|
|
@@ -10332,14 +11531,14 @@ ${normalized}`).digest("hex");
|
|
|
10332
11531
|
}
|
|
10333
11532
|
if (this.config.semanticConsolidationEnabled) {
|
|
10334
11533
|
try {
|
|
10335
|
-
const stateFilePath =
|
|
11534
|
+
const stateFilePath = path7.join(
|
|
10336
11535
|
this.config.memoryDir,
|
|
10337
11536
|
"state",
|
|
10338
11537
|
"semantic-consolidation-last-run.json"
|
|
10339
11538
|
);
|
|
10340
11539
|
let shouldRun = true;
|
|
10341
11540
|
try {
|
|
10342
|
-
const stateRaw = await
|
|
11541
|
+
const stateRaw = await readFile4(stateFilePath, "utf-8");
|
|
10343
11542
|
const stateData = JSON.parse(stateRaw);
|
|
10344
11543
|
if (stateData.lastRunAt) {
|
|
10345
11544
|
const lastRunMs = new Date(stateData.lastRunAt).getTime();
|
|
@@ -10362,9 +11561,9 @@ ${normalized}`).digest("hex");
|
|
|
10362
11561
|
allMemories = await this.storage.readAllMemories();
|
|
10363
11562
|
}
|
|
10364
11563
|
if (semResult.errors === 0 || semResult.memoriesArchived > 0) {
|
|
10365
|
-
const stateDir =
|
|
10366
|
-
await
|
|
10367
|
-
await
|
|
11564
|
+
const stateDir = path7.join(this.config.memoryDir, "state");
|
|
11565
|
+
await mkdir5(stateDir, { recursive: true });
|
|
11566
|
+
await writeFile4(
|
|
10368
11567
|
stateFilePath,
|
|
10369
11568
|
JSON.stringify({ lastRunAt: (/* @__PURE__ */ new Date()).toISOString() }),
|
|
10370
11569
|
"utf-8"
|
|
@@ -10836,13 +12035,13 @@ ${texts.map((t, i) => `[${i + 1}] ${t}`).join("\n\n")}`;
|
|
|
10836
12035
|
protectedCategories: this.config.lifecycleProtectedCategories
|
|
10837
12036
|
}
|
|
10838
12037
|
};
|
|
10839
|
-
const metricsPath =
|
|
12038
|
+
const metricsPath = path7.join(
|
|
10840
12039
|
this.storage.dir,
|
|
10841
12040
|
"state",
|
|
10842
12041
|
"lifecycle-metrics.json"
|
|
10843
12042
|
);
|
|
10844
|
-
await
|
|
10845
|
-
await
|
|
12043
|
+
await mkdir5(path7.dirname(metricsPath), { recursive: true });
|
|
12044
|
+
await writeFile4(metricsPath, JSON.stringify(metrics, null, 2), "utf-8");
|
|
10846
12045
|
}
|
|
10847
12046
|
/**
|
|
10848
12047
|
* Archive old, low-importance, rarely-accessed facts (v6.0).
|
|
@@ -11345,11 +12544,97 @@ ${lines.join("\n\n")}`;
|
|
|
11345
12544
|
*
|
|
11346
12545
|
* Callers must pass the full candidate pool (post-rerank, pre-slice).
|
|
11347
12546
|
*/
|
|
11348
|
-
|
|
12547
|
+
async applyMemoryWorthRerank(results, namespaces) {
|
|
12548
|
+
const counters = /* @__PURE__ */ new Map();
|
|
12549
|
+
const seenNamespaces = /* @__PURE__ */ new Set();
|
|
12550
|
+
const nowMs = Date.now();
|
|
12551
|
+
for (const [key, entry] of this.memoryWorthCounterCache) {
|
|
12552
|
+
if (nowMs - entry.at >= _Orchestrator.MEMORY_WORTH_CACHE_TTL_MS) {
|
|
12553
|
+
this.memoryWorthCounterCache.delete(key);
|
|
12554
|
+
}
|
|
12555
|
+
}
|
|
12556
|
+
for (const ns of namespaces) {
|
|
12557
|
+
if (seenNamespaces.has(ns)) continue;
|
|
12558
|
+
seenNamespaces.add(ns);
|
|
12559
|
+
try {
|
|
12560
|
+
const cached = this.memoryWorthCounterCache.get(ns);
|
|
12561
|
+
let nsMap;
|
|
12562
|
+
if (cached && nowMs - cached.at < _Orchestrator.MEMORY_WORTH_CACHE_TTL_MS) {
|
|
12563
|
+
nsMap = cached.counters;
|
|
12564
|
+
} else {
|
|
12565
|
+
const storage = await this.getStorage(ns);
|
|
12566
|
+
const memories = await storage.readAllMemories();
|
|
12567
|
+
nsMap = buildMemoryWorthCounterMap(memories);
|
|
12568
|
+
this.memoryWorthCounterCache.set(ns, { at: nowMs, counters: nsMap });
|
|
12569
|
+
}
|
|
12570
|
+
for (const [path8, c] of nsMap) counters.set(path8, c);
|
|
12571
|
+
} catch (err) {
|
|
12572
|
+
log.debug("memory-worth: failed to read namespace, skipping", {
|
|
12573
|
+
namespace: ns,
|
|
12574
|
+
error: err.message
|
|
12575
|
+
});
|
|
12576
|
+
}
|
|
12577
|
+
}
|
|
12578
|
+
const missing = results.filter((r) => !counters.has(r.path));
|
|
12579
|
+
if (missing.length > 0) {
|
|
12580
|
+
let reader = null;
|
|
12581
|
+
for (const ns of namespaces) {
|
|
12582
|
+
try {
|
|
12583
|
+
reader = await this.getStorage(ns);
|
|
12584
|
+
break;
|
|
12585
|
+
} catch {
|
|
12586
|
+
}
|
|
12587
|
+
}
|
|
12588
|
+
if (reader) {
|
|
12589
|
+
for (const r of missing) {
|
|
12590
|
+
try {
|
|
12591
|
+
const memory = await reader.readMemoryByPath(r.path);
|
|
12592
|
+
if (!memory) continue;
|
|
12593
|
+
const fm = memory.frontmatter;
|
|
12594
|
+
if (fm.mw_success === void 0 && fm.mw_fail === void 0) continue;
|
|
12595
|
+
counters.set(r.path, {
|
|
12596
|
+
mw_success: fm.mw_success,
|
|
12597
|
+
mw_fail: fm.mw_fail,
|
|
12598
|
+
lastAccessed: fm.lastAccessed
|
|
12599
|
+
});
|
|
12600
|
+
} catch (err) {
|
|
12601
|
+
log.debug("memory-worth: direct path lookup failed", {
|
|
12602
|
+
path: r.path,
|
|
12603
|
+
error: err.message
|
|
12604
|
+
});
|
|
12605
|
+
}
|
|
12606
|
+
}
|
|
12607
|
+
}
|
|
12608
|
+
}
|
|
12609
|
+
if (counters.size === 0) return results;
|
|
12610
|
+
const rankedInputs = results.map((r, i) => ({
|
|
12611
|
+
path: r.path,
|
|
12612
|
+
// Large positive rank score so multiplier math stays well-scaled and
|
|
12613
|
+
// we never hit zero; descending so earlier items rank higher.
|
|
12614
|
+
score: results.length - i
|
|
12615
|
+
}));
|
|
12616
|
+
const filtered = applyMemoryWorthFilter(rankedInputs, {
|
|
12617
|
+
counters,
|
|
12618
|
+
now: /* @__PURE__ */ new Date(),
|
|
12619
|
+
halfLifeMs: this.config.recallMemoryWorthHalfLifeMs > 0 ? this.config.recallMemoryWorthHalfLifeMs : void 0
|
|
12620
|
+
});
|
|
12621
|
+
const byPath = new Map(results.map((r) => [r.path, r]));
|
|
12622
|
+
const reordered = [];
|
|
12623
|
+
for (const item of filtered) {
|
|
12624
|
+
const original = byPath.get(item.path);
|
|
12625
|
+
if (original) reordered.push(original);
|
|
12626
|
+
}
|
|
12627
|
+
return reordered;
|
|
12628
|
+
}
|
|
12629
|
+
diversifyAndLimitRecallResults(sectionId, results, limit, retrievalQuery) {
|
|
11349
12630
|
const safeLimit = typeof limit === "number" && Number.isFinite(limit) ? Math.max(0, Math.floor(limit)) : 0;
|
|
11350
12631
|
if (!Array.isArray(results) || results.length === 0) return [];
|
|
11351
12632
|
if (safeLimit === 0) return [];
|
|
11352
|
-
const
|
|
12633
|
+
const boosted = this.config.recallReasoningTraceBoostEnabled && typeof retrievalQuery === "string" ? applyReasoningTraceBoost(results, {
|
|
12634
|
+
enabled: true,
|
|
12635
|
+
query: retrievalQuery
|
|
12636
|
+
}) : results;
|
|
12637
|
+
const diversified = this.applyMmrToQmdResults(sectionId, boosted);
|
|
11353
12638
|
return diversified.slice(0, safeLimit);
|
|
11354
12639
|
}
|
|
11355
12640
|
/**
|
|
@@ -11453,12 +12738,12 @@ ${lines.join("\n\n")}`;
|
|
|
11453
12738
|
*/
|
|
11454
12739
|
semanticDedupScopeFor(targetStorage) {
|
|
11455
12740
|
if (!this.config.namespacesEnabled) return {};
|
|
11456
|
-
const memoryDir =
|
|
11457
|
-
const storageDir =
|
|
12741
|
+
const memoryDir = path7.resolve(this.config.memoryDir);
|
|
12742
|
+
const storageDir = path7.resolve(targetStorage.dir);
|
|
11458
12743
|
if (storageDir === memoryDir) {
|
|
11459
12744
|
return { pathExcludePrefixes: ["namespaces/"] };
|
|
11460
12745
|
}
|
|
11461
|
-
let rel =
|
|
12746
|
+
let rel = path7.relative(memoryDir, storageDir);
|
|
11462
12747
|
if (!rel || rel.startsWith("..")) {
|
|
11463
12748
|
log.debug(
|
|
11464
12749
|
`semantic dedup: target storage dir ${storageDir} is outside memoryDir ${memoryDir}; scoping lookup to absolute path prefix`
|
|
@@ -11477,7 +12762,7 @@ ${lines.join("\n\n")}`;
|
|
|
11477
12762
|
if (hits.length === 0) return [];
|
|
11478
12763
|
const results = [];
|
|
11479
12764
|
for (const hit of hits) {
|
|
11480
|
-
const fullPath =
|
|
12765
|
+
const fullPath = path7.isAbsolute(hit.path) ? hit.path : path7.join(this.config.memoryDir, hit.path);
|
|
11481
12766
|
const memory = await this.storage.readMemoryByPath(fullPath);
|
|
11482
12767
|
if (!memory) continue;
|
|
11483
12768
|
results.push({
|
|
@@ -11654,10 +12939,26 @@ ${lines.join("\n\n")}`;
|
|
|
11654
12939
|
"rerankProvider=cloud is reserved/experimental in v2.2.0; skipping rerank"
|
|
11655
12940
|
);
|
|
11656
12941
|
}
|
|
12942
|
+
if (this.config.recallMemoryWorthFilterEnabled && results.length > 0) {
|
|
12943
|
+
try {
|
|
12944
|
+
results = await this.applyMemoryWorthRerank(results, options.recallNamespaces);
|
|
12945
|
+
} catch (err) {
|
|
12946
|
+
log.debug("memory-worth filter (cold) failed open", {
|
|
12947
|
+
error: err.message
|
|
12948
|
+
});
|
|
12949
|
+
}
|
|
12950
|
+
}
|
|
12951
|
+
if (options.xrayPoolSizeSink) {
|
|
12952
|
+
options.xrayPoolSizeSink.size = Math.max(
|
|
12953
|
+
options.xrayPoolSizeSink.size,
|
|
12954
|
+
results.length
|
|
12955
|
+
);
|
|
12956
|
+
}
|
|
11657
12957
|
return this.diversifyAndLimitRecallResults(
|
|
11658
12958
|
"memories",
|
|
11659
12959
|
results,
|
|
11660
|
-
options.recallResultLimit
|
|
12960
|
+
options.recallResultLimit,
|
|
12961
|
+
options.prompt
|
|
11661
12962
|
);
|
|
11662
12963
|
}
|
|
11663
12964
|
// ---------------------------------------------------------------------------
|
|
@@ -12051,8 +13352,8 @@ ${lines.join("\n\n")}`;
|
|
|
12051
13352
|
}
|
|
12052
13353
|
namespaceFromStorageDir(storageDir) {
|
|
12053
13354
|
if (!this.config.namespacesEnabled) return this.config.defaultNamespace;
|
|
12054
|
-
const resolvedStorageDir =
|
|
12055
|
-
const resolvedMemoryDir =
|
|
13355
|
+
const resolvedStorageDir = path7.resolve(storageDir);
|
|
13356
|
+
const resolvedMemoryDir = path7.resolve(this.config.memoryDir);
|
|
12056
13357
|
if (resolvedStorageDir === resolvedMemoryDir)
|
|
12057
13358
|
return this.config.defaultNamespace;
|
|
12058
13359
|
const m = resolvedStorageDir.match(/[\\/]namespaces[\\/]([^\\/]+)$/);
|
|
@@ -12085,6 +13386,21 @@ export {
|
|
|
12085
13386
|
migrateFromEngram,
|
|
12086
13387
|
buildProcedureRecallSection,
|
|
12087
13388
|
decideSemanticDedup,
|
|
13389
|
+
DEFAULT_TAXONOMY,
|
|
13390
|
+
generateResolverDocument,
|
|
13391
|
+
validateSlug,
|
|
13392
|
+
validateTaxonomy,
|
|
13393
|
+
loadTaxonomy,
|
|
13394
|
+
saveTaxonomy,
|
|
13395
|
+
getTaxonomyDir,
|
|
13396
|
+
getTaxonomyFilePath,
|
|
13397
|
+
stableHash,
|
|
13398
|
+
normalizeOriginUrl,
|
|
13399
|
+
resolveGitContext,
|
|
13400
|
+
projectNamespaceName,
|
|
13401
|
+
branchNamespaceName,
|
|
13402
|
+
resolveCodingNamespaceOverlay,
|
|
13403
|
+
describeCodingScope,
|
|
12088
13404
|
dedupeEntitySynthesisEvidenceEntries,
|
|
12089
13405
|
defaultWorkspaceDir,
|
|
12090
13406
|
sanitizeSessionKeyForFilename,
|
|
@@ -12113,4 +13429,4 @@ export {
|
|
|
12113
13429
|
resolvePersistedMemoryRelativePath,
|
|
12114
13430
|
Orchestrator
|
|
12115
13431
|
};
|
|
12116
|
-
//# sourceMappingURL=chunk-
|
|
13432
|
+
//# sourceMappingURL=chunk-VYM3VWOF.js.map
|