@remnic/core 9.3.741 → 9.3.743
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/access-boundary.d.ts +5 -5
- package/dist/access-boundary.js +10 -10
- package/dist/access-cli.js +32 -32
- package/dist/access-http.d.ts +5 -5
- package/dist/access-http.js +15 -15
- package/dist/access-mcp.d.ts +5 -5
- package/dist/access-mcp.js +14 -14
- package/dist/access-operations-batch.js +12 -12
- package/dist/access-operations.d.ts +5 -5
- package/dist/access-operations.js +13 -13
- package/dist/{access-service-Cbk-Kv_A.d.ts → access-service-BeW5GOg1.d.ts} +3 -3
- package/dist/access-service.d.ts +5 -5
- package/dist/access-service.js +9 -9
- package/dist/access-surface-catalog.d.ts +5 -5
- package/dist/action-confidence.d.ts +1 -1
- package/dist/active-memory-bridge.d.ts +1 -1
- package/dist/active-memory-bridge.js +3 -3
- package/dist/active-recall.d.ts +1 -1
- package/dist/{auto-sync-G3V5AN4C.js → auto-sync-XHSKKQAH.js} +2 -2
- package/dist/behavior-learner.d.ts +1 -1
- package/dist/behavior-signals.d.ts +1 -1
- package/dist/bootstrap.d.ts +4 -4
- package/dist/briefing.d.ts +1 -1
- package/dist/buffer-surprise-report.d.ts +1 -1
- package/dist/buffer.d.ts +1 -1
- package/dist/buffer.js +2 -2
- package/dist/calibration.d.ts +1 -1
- package/dist/capabilities.d.ts +10 -5
- package/dist/capabilities.js +1 -1
- package/dist/{catalog-_Bap6vfD.d.ts → catalog-CX0CjOaf.d.ts} +1 -1
- package/dist/causal-behavior.d.ts +1 -1
- package/dist/causal-consolidation.d.ts +1 -1
- package/dist/causal-consolidation.js +2 -2
- package/dist/causal-trajectory-graph.d.ts +1 -1
- package/dist/{chunk-X5PMDVY4.js → chunk-3EA5LIFJ.js} +4 -4
- package/dist/{chunk-YNHRWFAP.js → chunk-4DLFJJOQ.js} +2 -2
- package/dist/{chunk-WIMKOTNY.js → chunk-5QANTTY2.js} +2 -2
- package/dist/{chunk-QCO2QFLZ.js → chunk-5UNSGRCR.js} +7 -6
- package/dist/{chunk-QCO2QFLZ.js.map → chunk-5UNSGRCR.js.map} +1 -1
- package/dist/{chunk-Y6PNYJVO.js → chunk-A2KKLCOS.js} +2 -2
- package/dist/{chunk-O4IWVWSW.js → chunk-AVBT5WEW.js} +3 -3
- package/dist/{chunk-M5KLYHHI.js → chunk-BYLC4DKI.js} +2 -2
- package/dist/{chunk-OZECYVGI.js → chunk-C7LDPZJJ.js} +6 -4
- package/dist/{chunk-OZECYVGI.js.map → chunk-C7LDPZJJ.js.map} +1 -1
- package/dist/{chunk-UOVDO6TC.js → chunk-CHELXDTO.js} +3 -3
- package/dist/{chunk-TQQN64J2.js → chunk-DBSMLRTO.js} +2 -2
- package/dist/{chunk-4J53ZVPQ.js → chunk-DYK27X7V.js} +3 -3
- package/dist/{chunk-K2N6WIZM.js → chunk-E7RGJQWP.js} +2 -2
- package/dist/{chunk-M4WI23X3.js → chunk-EEKDRAWX.js} +2 -2
- package/dist/{chunk-H3WSZWHK.js → chunk-G5FP7VSQ.js} +13 -12
- package/dist/chunk-G5FP7VSQ.js.map +1 -0
- package/dist/{chunk-BE6NEQLF.js → chunk-HAZVVOYT.js} +3 -3
- package/dist/{chunk-OT5K26NG.js → chunk-HM6UJPPO.js} +2 -2
- package/dist/{chunk-PI4JHLDD.js → chunk-IP5SANO2.js} +2 -2
- package/dist/{chunk-WHEF76BQ.js → chunk-JRZV3767.js} +2 -2
- package/dist/{chunk-OS5RKJOH.js → chunk-JZ7P26GF.js} +2 -2
- package/dist/{chunk-Y62QPRKV.js → chunk-K5LLP4CY.js} +2 -2
- package/dist/{chunk-C3Z5YJSM.js → chunk-LOPZ2DWR.js} +2 -2
- package/dist/{chunk-BJPL5WAL.js → chunk-MXDG6SRH.js} +3 -3
- package/dist/{chunk-UYYSOMS2.js → chunk-NBP3YHHS.js} +4 -4
- package/dist/{chunk-USHVHI6J.js → chunk-NNL4LJAD.js} +3 -3
- package/dist/{chunk-GPX5E36D.js → chunk-OSMBC3JU.js} +2 -2
- package/dist/{chunk-OUSOMUFV.js → chunk-PE6XR4GG.js} +2 -2
- package/dist/{chunk-DGVM5SFL.js → chunk-PHRLJFWZ.js} +3 -2
- package/dist/{chunk-DGVM5SFL.js.map → chunk-PHRLJFWZ.js.map} +1 -1
- package/dist/{chunk-CMPXLMC3.js → chunk-PI23H7FV.js} +3 -3
- package/dist/{chunk-WGDE2TJP.js → chunk-QOGXUNWL.js} +4 -4
- package/dist/{chunk-ELL5VYXC.js → chunk-RNWWAS5V.js} +3 -3
- package/dist/{chunk-LD6A7XG5.js → chunk-TQPSOTC7.js} +7 -7
- package/dist/{chunk-AX4TRSRE.js → chunk-U5WVRMCA.js} +2 -2
- package/dist/{chunk-773DPI6T.js → chunk-V5RVMULT.js} +11 -8
- package/dist/chunk-V5RVMULT.js.map +1 -0
- package/dist/{chunk-DBVBV2RF.js → chunk-VE54E6RP.js} +4 -4
- package/dist/{chunk-VC7QELR6.js → chunk-VO4VARZL.js} +1054 -869
- package/dist/chunk-VO4VARZL.js.map +1 -0
- package/dist/{chunk-G7Q4D2G3.js → chunk-VSF7AAGE.js} +1 -3
- package/dist/chunk-VSF7AAGE.js.map +1 -0
- package/dist/{chunk-OVYBENIJ.js → chunk-W3M34XT4.js} +3 -3
- package/dist/{chunk-XPOOY35N.js → chunk-W4H5A3TJ.js} +3 -2
- package/dist/chunk-W4H5A3TJ.js.map +1 -0
- package/dist/{chunk-7Y5KKMIP.js → chunk-WPLRJ4XM.js} +9 -8
- package/dist/{chunk-7Y5KKMIP.js.map → chunk-WPLRJ4XM.js.map} +1 -1
- package/dist/{chunk-3TUDKDTQ.js → chunk-XEADGIAA.js} +6 -6
- package/dist/{cli-BQW2xKdb.d.ts → cli-BYad9YYY.d.ts} +3 -3
- package/dist/cli.d.ts +6 -6
- package/dist/cli.js +21 -21
- package/dist/compounding/engine.d.ts +1 -1
- package/dist/compounding/engine.js +3 -3
- package/dist/compounding/preference-consolidator.d.ts +1 -1
- package/dist/compression-optimizer.d.ts +1 -1
- package/dist/config.d.ts +1 -1
- package/dist/connectors/codex-materialize-runner.d.ts +1 -1
- package/dist/connectors/codex-materialize.d.ts +1 -1
- package/dist/connectors/index.d.ts +1 -1
- package/dist/connectors/index.js +2 -2
- package/dist/consolidation-provenance-check.d.ts +1 -1
- package/dist/consolidation-undo.d.ts +1 -1
- package/dist/contradiction/index.d.ts +1 -1
- package/dist/contradiction/index.js +2 -2
- package/dist/{contradiction-scan-UERKJESC.js → contradiction-scan-3FJYWS3G.js} +3 -3
- package/dist/conversation-index/backend.d.ts +1 -1
- package/dist/conversation-index/chunker.d.ts +1 -1
- package/dist/conversation-index/faiss-adapter.d.ts +1 -1
- package/dist/conversation-index/indexer.d.ts +1 -1
- package/dist/conversation-index/search.d.ts +1 -1
- package/dist/day-summary.d.ts +1 -1
- package/dist/day-summary.js +2 -2
- package/dist/delinearize.d.ts +1 -1
- package/dist/direct-answer-wiring.d.ts +1 -1
- package/dist/direct-answer.d.ts +1 -1
- package/dist/embedding-fallback.d.ts +1 -1
- package/dist/embedding-fallback.js +2 -2
- package/dist/enrichment/index.d.ts +1 -1
- package/dist/entity-retrieval.d.ts +1 -1
- package/dist/entity-retrieval.js +2 -2
- package/dist/entity-schema.d.ts +1 -1
- package/dist/explicit-capture.d.ts +4 -4
- package/dist/explicit-capture.js +2 -2
- package/dist/extraction-faithfulness.d.ts +1 -1
- package/dist/extraction-judge-telemetry.d.ts +1 -1
- package/dist/extraction-judge-training.d.ts +1 -1
- package/dist/extraction-judge.d.ts +1 -1
- package/dist/extraction.d.ts +1 -1
- package/dist/extraction.js +4 -4
- package/dist/fallback-llm.d.ts +1 -1
- package/dist/{first-start-migration-GQ3UQNIL.js → first-start-migration-4I3VDSYS.js} +2 -2
- package/dist/graph-dashboard-diff.d.ts +1 -1
- package/dist/graph-dashboard-key.d.ts +1 -1
- package/dist/graph-dashboard-parser.d.ts +1 -1
- package/dist/graph-edge-reinforcement.d.ts +1 -1
- package/dist/graph-recall.js +1 -1
- package/dist/graph-snapshot.d.ts +1 -1
- package/dist/graph.d.ts +1 -1
- package/dist/identity-continuity.d.ts +1 -1
- package/dist/importance.d.ts +1 -1
- package/dist/index.d.ts +9 -9
- package/dist/index.js +40 -40
- package/dist/intent.d.ts +1 -1
- package/dist/lcm/engine.d.ts +1 -1
- package/dist/lcm/engine.js +2 -2
- package/dist/lcm/index.d.ts +1 -1
- package/dist/lcm/index.js +2 -2
- package/dist/lcm/summarizer.js +1 -1
- package/dist/lcm/tools.d.ts +1 -1
- package/dist/lifecycle.d.ts +1 -1
- package/dist/live-connectors-runner.d.ts +1 -1
- package/dist/local-llm.d.ts +1 -1
- package/dist/local-llm.js +2 -2
- package/dist/local-model-endpoint.d.ts +1 -1
- package/dist/maintenance/memory-governance.d.ts +1 -1
- package/dist/mcp-memory-inspector-app.d.ts +5 -5
- package/dist/memory-action-policy.d.ts +1 -1
- package/dist/memory-cache.d.ts +1 -1
- package/dist/memory-lifecycle-ledger-utils.d.ts +1 -1
- package/dist/memory-projection-store.d.ts +1 -1
- package/dist/memory-provenance.d.ts +1 -1
- package/dist/memory-worth-outcomes.d.ts +1 -1
- package/dist/models-json.d.ts +1 -1
- package/dist/namespaces/migrate.d.ts +2 -2
- package/dist/namespaces/migrate.js +6 -6
- package/dist/namespaces/principal.d.ts +1 -1
- package/dist/namespaces/principal.js +2 -2
- package/dist/namespaces/search.d.ts +1 -1
- package/dist/namespaces/search.js +4 -4
- package/dist/namespaces/storage.d.ts +2 -2
- package/dist/namespaces/storage.js +2 -2
- package/dist/native-knowledge.d.ts +1 -1
- package/dist/operator-toolkit.d.ts +1 -1
- package/dist/operator-toolkit.js +11 -11
- package/dist/orchestration/compression-guideline-coordinator.d.ts +1 -1
- package/dist/orchestration/compression-guideline-coordinator.js +2 -2
- package/dist/orchestration/maintenance.d.ts +2 -2
- package/dist/orchestration/maintenance.js +6 -6
- package/dist/{orchestrator-BOAFN_Yr.d.ts → orchestrator-CupigmWu.d.ts} +221 -7
- package/dist/orchestrator.d.ts +4 -4
- package/dist/orchestrator.js +27 -27
- package/dist/patterns-cli.d.ts +1 -1
- package/dist/policy-runtime.d.ts +1 -1
- package/dist/provenance.d.ts +1 -1
- package/dist/qmd-recall-cache.d.ts +1 -1
- package/dist/qmd.d.ts +1 -1
- package/dist/recall-disclosure-escalation.d.ts +1 -1
- package/dist/recall-explain-renderer.d.ts +1 -1
- package/dist/recall-planner-llm.d.ts +1 -1
- package/dist/recall-state.d.ts +1 -1
- package/dist/recall-tag-filter.d.ts +1 -1
- package/dist/recall-xray-cli.d.ts +1 -1
- package/dist/recall-xray-renderer.d.ts +1 -1
- package/dist/recall-xray.d.ts +1 -1
- package/dist/resolve-auth-token.d.ts +1 -1
- package/dist/retrieval-agents.d.ts +1 -1
- package/dist/retrieval-tiers.d.ts +1 -1
- package/dist/routing/engine.d.ts +1 -1
- package/dist/routing/store.d.ts +1 -1
- package/dist/search/embed-helper.d.ts +1 -1
- package/dist/search/embed-helper.js +2 -2
- package/dist/search/factory.d.ts +1 -1
- package/dist/search/factory.js +3 -3
- package/dist/search/index.d.ts +1 -1
- package/dist/search/index.js +3 -3
- package/dist/search/lancedb-backend.d.ts +1 -1
- package/dist/search/meilisearch-backend.d.ts +1 -1
- package/dist/search/noop-backend.d.ts +1 -1
- package/dist/search/orama-backend.d.ts +1 -1
- package/dist/search/port.d.ts +1 -1
- package/dist/search/remote-backend.d.ts +1 -1
- package/dist/{semantic-consolidation-DsIEiCka.d.ts → semantic-consolidation-ByzGwC9c.d.ts} +1 -1
- package/dist/semantic-consolidation.d.ts +2 -2
- package/dist/semantic-consolidation.js +2 -2
- package/dist/semantic-rule-verifier.d.ts +1 -1
- package/dist/session-observer-bands.d.ts +1 -1
- package/dist/session-observer-state.d.ts +1 -1
- package/dist/shared-context/manager.d.ts +1 -1
- package/dist/shared-context/manager.js +2 -2
- package/dist/signal.d.ts +1 -1
- package/dist/storage.d.ts +1 -1
- package/dist/summarizer.d.ts +1 -1
- package/dist/summarizer.js +3 -3
- package/dist/summary-snapshot.d.ts +1 -1
- package/dist/temporal-supersession.d.ts +1 -1
- package/dist/temporal-validity.d.ts +1 -1
- package/dist/threading.d.ts +1 -1
- package/dist/tier-migration.d.ts +1 -1
- package/dist/tier-routing.d.ts +1 -1
- package/dist/{tier-stats-CSKL7BDG.js → tier-stats-5XF4UBRQ.js} +2 -2
- package/dist/topics.d.ts +1 -1
- package/dist/transcript.d.ts +1 -1
- package/dist/trust-score-stage.d.ts +1 -1
- package/dist/trust-score.d.ts +1 -1
- package/dist/{types-CglNn2V-.d.ts → types-5Jik3r4G.d.ts} +1 -1
- package/dist/types.d.ts +1 -1
- package/dist/utility-runtime.d.ts +1 -1
- package/package.json +2 -2
- package/src/capabilities.test.ts +0 -2
- package/src/capabilities.ts +7 -6
- package/src/cli.ts +2 -1
- package/src/graph-recall.ts +2 -1
- package/src/lcm/engine.ts +9 -6
- package/src/lcm/summarizer.ts +2 -1
- package/src/operator-toolkit.ts +2 -1
- package/src/orchestration/contradiction-linking-coordinator.ts +336 -0
- package/src/orchestration/qmd-result-resolver.ts +377 -0
- package/src/orchestration/recall-section-coordinator.ts +349 -0
- package/src/orchestrator.ts +81 -679
- package/src/procedural/procedure-stats.ts +2 -1
- package/src/wearables/pipeline.ts +5 -3
- package/dist/chunk-773DPI6T.js.map +0 -1
- package/dist/chunk-G7Q4D2G3.js.map +0 -1
- package/dist/chunk-H3WSZWHK.js.map +0 -1
- package/dist/chunk-VC7QELR6.js.map +0 -1
- package/dist/chunk-XPOOY35N.js.map +0 -1
- /package/dist/{auto-sync-G3V5AN4C.js.map → auto-sync-XHSKKQAH.js.map} +0 -0
- /package/dist/{chunk-X5PMDVY4.js.map → chunk-3EA5LIFJ.js.map} +0 -0
- /package/dist/{chunk-YNHRWFAP.js.map → chunk-4DLFJJOQ.js.map} +0 -0
- /package/dist/{chunk-WIMKOTNY.js.map → chunk-5QANTTY2.js.map} +0 -0
- /package/dist/{chunk-Y6PNYJVO.js.map → chunk-A2KKLCOS.js.map} +0 -0
- /package/dist/{chunk-O4IWVWSW.js.map → chunk-AVBT5WEW.js.map} +0 -0
- /package/dist/{chunk-M5KLYHHI.js.map → chunk-BYLC4DKI.js.map} +0 -0
- /package/dist/{chunk-UOVDO6TC.js.map → chunk-CHELXDTO.js.map} +0 -0
- /package/dist/{chunk-TQQN64J2.js.map → chunk-DBSMLRTO.js.map} +0 -0
- /package/dist/{chunk-4J53ZVPQ.js.map → chunk-DYK27X7V.js.map} +0 -0
- /package/dist/{chunk-K2N6WIZM.js.map → chunk-E7RGJQWP.js.map} +0 -0
- /package/dist/{chunk-M4WI23X3.js.map → chunk-EEKDRAWX.js.map} +0 -0
- /package/dist/{chunk-BE6NEQLF.js.map → chunk-HAZVVOYT.js.map} +0 -0
- /package/dist/{chunk-OT5K26NG.js.map → chunk-HM6UJPPO.js.map} +0 -0
- /package/dist/{chunk-PI4JHLDD.js.map → chunk-IP5SANO2.js.map} +0 -0
- /package/dist/{chunk-WHEF76BQ.js.map → chunk-JRZV3767.js.map} +0 -0
- /package/dist/{chunk-OS5RKJOH.js.map → chunk-JZ7P26GF.js.map} +0 -0
- /package/dist/{chunk-Y62QPRKV.js.map → chunk-K5LLP4CY.js.map} +0 -0
- /package/dist/{chunk-C3Z5YJSM.js.map → chunk-LOPZ2DWR.js.map} +0 -0
- /package/dist/{chunk-BJPL5WAL.js.map → chunk-MXDG6SRH.js.map} +0 -0
- /package/dist/{chunk-UYYSOMS2.js.map → chunk-NBP3YHHS.js.map} +0 -0
- /package/dist/{chunk-USHVHI6J.js.map → chunk-NNL4LJAD.js.map} +0 -0
- /package/dist/{chunk-GPX5E36D.js.map → chunk-OSMBC3JU.js.map} +0 -0
- /package/dist/{chunk-OUSOMUFV.js.map → chunk-PE6XR4GG.js.map} +0 -0
- /package/dist/{chunk-CMPXLMC3.js.map → chunk-PI23H7FV.js.map} +0 -0
- /package/dist/{chunk-WGDE2TJP.js.map → chunk-QOGXUNWL.js.map} +0 -0
- /package/dist/{chunk-ELL5VYXC.js.map → chunk-RNWWAS5V.js.map} +0 -0
- /package/dist/{chunk-LD6A7XG5.js.map → chunk-TQPSOTC7.js.map} +0 -0
- /package/dist/{chunk-AX4TRSRE.js.map → chunk-U5WVRMCA.js.map} +0 -0
- /package/dist/{chunk-DBVBV2RF.js.map → chunk-VE54E6RP.js.map} +0 -0
- /package/dist/{chunk-OVYBENIJ.js.map → chunk-W3M34XT4.js.map} +0 -0
- /package/dist/{chunk-3TUDKDTQ.js.map → chunk-XEADGIAA.js.map} +0 -0
- /package/dist/{contradiction-scan-UERKJESC.js.map → contradiction-scan-3FJYWS3G.js.map} +0 -0
- /package/dist/{first-start-migration-GQ3UQNIL.js.map → first-start-migration-4I3VDSYS.js.map} +0 -0
- /package/dist/{tier-stats-CSKL7BDG.js.map → tier-stats-5XF4UBRQ.js.map} +0 -0
|
@@ -4,13 +4,13 @@ import {
|
|
|
4
4
|
loadSyncState,
|
|
5
5
|
syncWearableSource,
|
|
6
6
|
wearableSourceLabel
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-C7LDPZJJ.js";
|
|
8
8
|
import {
|
|
9
9
|
CompressionGuidelineCoordinator
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-5QANTTY2.js";
|
|
11
11
|
import {
|
|
12
12
|
MaintenanceScheduler
|
|
13
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-MXDG6SRH.js";
|
|
14
14
|
import {
|
|
15
15
|
runPeerProfileReasoner
|
|
16
16
|
} from "./chunk-I74SUMNI.js";
|
|
@@ -19,7 +19,7 @@ import {
|
|
|
19
19
|
} from "./chunk-7HYPN2GC.js";
|
|
20
20
|
import {
|
|
21
21
|
LcmEngine
|
|
22
|
-
} from "./chunk-
|
|
22
|
+
} from "./chunk-V5RVMULT.js";
|
|
23
23
|
import {
|
|
24
24
|
chunkTranscriptEntries
|
|
25
25
|
} from "./chunk-TECVW3JP.js";
|
|
@@ -29,10 +29,10 @@ import {
|
|
|
29
29
|
import {
|
|
30
30
|
CompoundingEngine,
|
|
31
31
|
defaultTierMigrationCycleBudget
|
|
32
|
-
} from "./chunk-
|
|
32
|
+
} from "./chunk-CHELXDTO.js";
|
|
33
33
|
import {
|
|
34
34
|
SharedContextManager
|
|
35
|
-
} from "./chunk-
|
|
35
|
+
} from "./chunk-JRZV3767.js";
|
|
36
36
|
import {
|
|
37
37
|
applyTrustScoreStage,
|
|
38
38
|
buildTrustSignalsForRerank,
|
|
@@ -63,7 +63,7 @@ import {
|
|
|
63
63
|
} from "./chunk-UHGBNIOS.js";
|
|
64
64
|
import {
|
|
65
65
|
HourlySummarizer
|
|
66
|
-
} from "./chunk-
|
|
66
|
+
} from "./chunk-NNL4LJAD.js";
|
|
67
67
|
import {
|
|
68
68
|
buildTargetedFactRecallSection,
|
|
69
69
|
shouldRecallTargetedFactEvidence
|
|
@@ -160,7 +160,7 @@ import {
|
|
|
160
160
|
} from "./chunk-LTHVM4XN.js";
|
|
161
161
|
import {
|
|
162
162
|
ExtractionEngine
|
|
163
|
-
} from "./chunk-
|
|
163
|
+
} from "./chunk-QOGXUNWL.js";
|
|
164
164
|
import {
|
|
165
165
|
parseMemoryActionEligibilityContext
|
|
166
166
|
} from "./chunk-5GSUBCZM.js";
|
|
@@ -169,7 +169,7 @@ import {
|
|
|
169
169
|
} from "./chunk-PWFWCGOO.js";
|
|
170
170
|
import {
|
|
171
171
|
LocalLlmClient
|
|
172
|
-
} from "./chunk-
|
|
172
|
+
} from "./chunk-DBSMLRTO.js";
|
|
173
173
|
import {
|
|
174
174
|
buildFocusedListRecallSection,
|
|
175
175
|
shouldRecallFocusedListEvidence
|
|
@@ -187,18 +187,18 @@ import {
|
|
|
187
187
|
} from "./chunk-4463LUIE.js";
|
|
188
188
|
import {
|
|
189
189
|
formatDaySummaryMemories
|
|
190
|
-
} from "./chunk-
|
|
190
|
+
} from "./chunk-LOPZ2DWR.js";
|
|
191
191
|
import {
|
|
192
192
|
tryDirectAnswer
|
|
193
193
|
} from "./chunk-Q6IP2ARR.js";
|
|
194
194
|
import {
|
|
195
195
|
EmbeddingFallback
|
|
196
|
-
} from "./chunk-
|
|
196
|
+
} from "./chunk-OSMBC3JU.js";
|
|
197
197
|
import {
|
|
198
198
|
buildEntityRecallSection,
|
|
199
199
|
entityRecentTranscriptLookbackHours,
|
|
200
200
|
readRecentEntityTranscriptEntries
|
|
201
|
-
} from "./chunk-
|
|
201
|
+
} from "./chunk-E7RGJQWP.js";
|
|
202
202
|
import {
|
|
203
203
|
RoutingRulesStore
|
|
204
204
|
} from "./chunk-WIWPSQYU.js";
|
|
@@ -228,14 +228,14 @@ import {
|
|
|
228
228
|
import {
|
|
229
229
|
runNamespaceMaintenanceFanout,
|
|
230
230
|
summarizeNamespaceMaintenanceHealth
|
|
231
|
-
} from "./chunk-
|
|
231
|
+
} from "./chunk-AVBT5WEW.js";
|
|
232
232
|
import {
|
|
233
233
|
NamespaceCatalog,
|
|
234
234
|
planNamespaceMaintenance
|
|
235
|
-
} from "./chunk-
|
|
235
|
+
} from "./chunk-3EA5LIFJ.js";
|
|
236
236
|
import {
|
|
237
237
|
NamespaceStorageRouter
|
|
238
|
-
} from "./chunk-
|
|
238
|
+
} from "./chunk-U5WVRMCA.js";
|
|
239
239
|
import {
|
|
240
240
|
searchHarmonicRetrieval
|
|
241
241
|
} from "./chunk-AV5ZEH4M.js";
|
|
@@ -270,7 +270,7 @@ import {
|
|
|
270
270
|
materializeAfterSemanticConsolidation,
|
|
271
271
|
parseConsolidationResponse,
|
|
272
272
|
parseOperatorAwareConsolidationResponse
|
|
273
|
-
} from "./chunk-
|
|
273
|
+
} from "./chunk-IP5SANO2.js";
|
|
274
274
|
import {
|
|
275
275
|
buildRecallQueryPolicy
|
|
276
276
|
} from "./chunk-LBJBNWS2.js";
|
|
@@ -292,7 +292,7 @@ import {
|
|
|
292
292
|
} from "./chunk-UQ7RN5HK.js";
|
|
293
293
|
import {
|
|
294
294
|
SmartBuffer
|
|
295
|
-
} from "./chunk-
|
|
295
|
+
} from "./chunk-JZ7P26GF.js";
|
|
296
296
|
import {
|
|
297
297
|
isDisagreementPrompt
|
|
298
298
|
} from "./chunk-H3FZVNRN.js";
|
|
@@ -311,7 +311,7 @@ import {
|
|
|
311
311
|
clusterByKey,
|
|
312
312
|
createCorrectionService,
|
|
313
313
|
detectPassiveCorrections
|
|
314
|
-
} from "./chunk-
|
|
314
|
+
} from "./chunk-A2KKLCOS.js";
|
|
315
315
|
import {
|
|
316
316
|
listTrustZoneRecords,
|
|
317
317
|
searchTrustZoneRecords
|
|
@@ -333,14 +333,14 @@ import {
|
|
|
333
333
|
resolveNamespaceFromStorageDir,
|
|
334
334
|
resolveScopePlan,
|
|
335
335
|
resolveScopeProfilePlan
|
|
336
|
-
} from "./chunk-
|
|
336
|
+
} from "./chunk-W3M34XT4.js";
|
|
337
337
|
import {
|
|
338
338
|
NamespaceSearchRouter
|
|
339
|
-
} from "./chunk-
|
|
339
|
+
} from "./chunk-HAZVVOYT.js";
|
|
340
340
|
import {
|
|
341
341
|
createConversationIndexRuntime,
|
|
342
342
|
createSearchBackend
|
|
343
|
-
} from "./chunk-
|
|
343
|
+
} from "./chunk-RNWWAS5V.js";
|
|
344
344
|
import {
|
|
345
345
|
NoopSearchBackend
|
|
346
346
|
} from "./chunk-CYEPCZN5.js";
|
|
@@ -363,7 +363,7 @@ import {
|
|
|
363
363
|
} from "./chunk-QDW3E4RD.js";
|
|
364
364
|
import {
|
|
365
365
|
shouldSkipImplicitExtraction
|
|
366
|
-
} from "./chunk-
|
|
366
|
+
} from "./chunk-K5LLP4CY.js";
|
|
367
367
|
import {
|
|
368
368
|
searchCausalTrajectories
|
|
369
369
|
} from "./chunk-SQNED75R.js";
|
|
@@ -465,7 +465,7 @@ import {
|
|
|
465
465
|
defaultNamespaceForPrincipal,
|
|
466
466
|
recallNamespacesForPrincipal,
|
|
467
467
|
resolvePrincipal
|
|
468
|
-
} from "./chunk-
|
|
468
|
+
} from "./chunk-PE6XR4GG.js";
|
|
469
469
|
import {
|
|
470
470
|
isSafeRouteNamespace,
|
|
471
471
|
selectRouteRule
|
|
@@ -491,7 +491,7 @@ import {
|
|
|
491
491
|
resolveRecallEnhancementCapabilities,
|
|
492
492
|
resolveSecurityCapabilities,
|
|
493
493
|
resolveUtilityLearningCapabilities
|
|
494
|
-
} from "./chunk-
|
|
494
|
+
} from "./chunk-VSF7AAGE.js";
|
|
495
495
|
import {
|
|
496
496
|
sanitizeMemoryContent
|
|
497
497
|
} from "./chunk-5GKPFL3S.js";
|
|
@@ -512,7 +512,7 @@ import {
|
|
|
512
512
|
} from "./chunk-PVGDJXVK.js";
|
|
513
513
|
|
|
514
514
|
// src/orchestrator.ts
|
|
515
|
-
import
|
|
515
|
+
import path6 from "path";
|
|
516
516
|
import os2 from "os";
|
|
517
517
|
import { createHash as createHash2, randomBytes } from "crypto";
|
|
518
518
|
import { existsSync, readFileSync } from "fs";
|
|
@@ -2196,7 +2196,7 @@ var RecallRerankCoordinator = class _RecallRerankCoordinator {
|
|
|
2196
2196
|
nsMap = buildMemoryWorthCounterMap(memories);
|
|
2197
2197
|
this.memoryWorthCounterCache.set(ns, { at: nowMs, counters: nsMap });
|
|
2198
2198
|
}
|
|
2199
|
-
for (const [
|
|
2199
|
+
for (const [path7, c] of nsMap) counters.set(path7, c);
|
|
2200
2200
|
} catch (err) {
|
|
2201
2201
|
log.debug("memory-worth: failed to read namespace, skipping", {
|
|
2202
2202
|
namespace: ns,
|
|
@@ -2281,7 +2281,7 @@ var RecallRerankCoordinator = class _RecallRerankCoordinator {
|
|
|
2281
2281
|
namespaces,
|
|
2282
2282
|
{
|
|
2283
2283
|
readNamespaceMemories: async (ns) => (await this.getStorage(ns)).readAllMemories(),
|
|
2284
|
-
readMemoryFrontmatter: async (
|
|
2284
|
+
readMemoryFrontmatter: async (path7) => {
|
|
2285
2285
|
if (!fallbackReader) {
|
|
2286
2286
|
for (const ns of namespaces) {
|
|
2287
2287
|
try {
|
|
@@ -2292,7 +2292,7 @@ var RecallRerankCoordinator = class _RecallRerankCoordinator {
|
|
|
2292
2292
|
}
|
|
2293
2293
|
}
|
|
2294
2294
|
if (!fallbackReader) return null;
|
|
2295
|
-
const memory = await this.readQmdResultMemory(
|
|
2295
|
+
const memory = await this.readQmdResultMemory(path7, fallbackReader, namespaces);
|
|
2296
2296
|
return memory ? memory.frontmatter : null;
|
|
2297
2297
|
}
|
|
2298
2298
|
},
|
|
@@ -2391,214 +2391,839 @@ var RecallRerankCoordinator = class _RecallRerankCoordinator {
|
|
|
2391
2391
|
}
|
|
2392
2392
|
};
|
|
2393
2393
|
|
|
2394
|
-
// src/
|
|
2395
|
-
|
|
2396
|
-
|
|
2397
|
-
|
|
2398
|
-
|
|
2399
|
-
|
|
2400
|
-
|
|
2401
|
-
function pickCanonical(memories) {
|
|
2402
|
-
let best = memories[0];
|
|
2403
|
-
let bestInstant = memoryInstant(best);
|
|
2404
|
-
let bestStamp = memoryStamp(best);
|
|
2405
|
-
for (let i = 1; i < memories.length; i += 1) {
|
|
2406
|
-
const candidate = memories[i];
|
|
2407
|
-
const instant = memoryInstant(candidate);
|
|
2408
|
-
const stamp = memoryStamp(candidate);
|
|
2409
|
-
let cmp;
|
|
2410
|
-
if (instant !== null && bestInstant !== null) {
|
|
2411
|
-
cmp = instant - bestInstant;
|
|
2412
|
-
} else {
|
|
2413
|
-
cmp = stamp.localeCompare(bestStamp);
|
|
2414
|
-
}
|
|
2415
|
-
if (cmp > 0 || cmp === 0 && candidate.frontmatter.id > best.frontmatter.id) {
|
|
2416
|
-
best = candidate;
|
|
2417
|
-
bestInstant = instant;
|
|
2418
|
-
bestStamp = stamp;
|
|
2419
|
-
}
|
|
2420
|
-
}
|
|
2421
|
-
return best;
|
|
2422
|
-
}
|
|
2423
|
-
function memoryStamp(memory) {
|
|
2424
|
-
return memory.frontmatter.updated || memory.frontmatter.created || "";
|
|
2425
|
-
}
|
|
2426
|
-
function memoryInstant(memory) {
|
|
2427
|
-
const stamp = memoryStamp(memory);
|
|
2428
|
-
if (stamp.length === 0) return null;
|
|
2429
|
-
const parsed = Date.parse(stamp);
|
|
2430
|
-
return Number.isFinite(parsed) ? parsed : null;
|
|
2431
|
-
}
|
|
2432
|
-
var ACTIVE_STATUS = "active";
|
|
2433
|
-
async function runPatternReinforcement(storage, options) {
|
|
2434
|
-
const minCount = Math.max(2, Math.floor(options.minCount));
|
|
2435
|
-
const targetCategories = new Set(options.categories);
|
|
2436
|
-
const now = options.now ?? (() => /* @__PURE__ */ new Date());
|
|
2437
|
-
const nowIso = now().toISOString();
|
|
2438
|
-
if (targetCategories.size === 0) {
|
|
2439
|
-
return emptyResult();
|
|
2440
|
-
}
|
|
2441
|
-
const memories = await storage.readAllMemories();
|
|
2442
|
-
const eligible = memories.filter((m) => {
|
|
2443
|
-
if (!targetCategories.has(m.frontmatter.category)) return false;
|
|
2444
|
-
const status = m.frontmatter.status ?? ACTIVE_STATUS;
|
|
2445
|
-
return status === ACTIVE_STATUS || status === "superseded";
|
|
2446
|
-
});
|
|
2447
|
-
if (eligible.length === 0) return emptyResult();
|
|
2448
|
-
const clusters = clusterByKey(
|
|
2449
|
-
eligible,
|
|
2450
|
-
(m) => patternReinforcementClusterKey(m.frontmatter.category, m.content)
|
|
2451
|
-
);
|
|
2452
|
-
const result = {
|
|
2453
|
-
clustersFound: 0,
|
|
2454
|
-
canonicalsUpdated: 0,
|
|
2455
|
-
duplicatesSuperseded: 0,
|
|
2456
|
-
clusters: []
|
|
2457
|
-
};
|
|
2458
|
-
for (const cluster of clusters.values()) {
|
|
2459
|
-
if (cluster.length < minCount) continue;
|
|
2460
|
-
const activeMembers = cluster.filter((m) => {
|
|
2461
|
-
const status = m.frontmatter.status ?? ACTIVE_STATUS;
|
|
2462
|
-
return status === ACTIVE_STATUS;
|
|
2463
|
-
});
|
|
2464
|
-
if (activeMembers.length === 0) continue;
|
|
2465
|
-
result.clustersFound += 1;
|
|
2466
|
-
const canonical = pickCanonical(activeMembers);
|
|
2467
|
-
const activeDuplicates = activeMembers.filter((m) => m !== canonical);
|
|
2468
|
-
const sourceIds = [...cluster].map((m) => m.frontmatter.id).filter((id) => typeof id === "string" && id.length > 0).sort();
|
|
2469
|
-
const previousCount = canonical.frontmatter.reinforcement_count ?? 0;
|
|
2470
|
-
const newCount = sourceIds.length;
|
|
2471
|
-
const reinforcementBumped = newCount > previousCount;
|
|
2472
|
-
const previousDerivedFrom = Array.isArray(canonical.frontmatter.derived_from) ? [...canonical.frontmatter.derived_from].sort() : [];
|
|
2473
|
-
const sortedSourceIds = [...sourceIds].sort();
|
|
2474
|
-
const membershipChanged = previousDerivedFrom.length !== sortedSourceIds.length || previousDerivedFrom.some((id, i) => id !== sortedSourceIds[i]);
|
|
2475
|
-
const previousVia = canonical.frontmatter.derived_via;
|
|
2476
|
-
const viaChanged = previousVia !== "pattern-reinforcement";
|
|
2477
|
-
const canonicalNeedsRefresh = reinforcementBumped || membershipChanged || viaChanged;
|
|
2478
|
-
if (canonicalNeedsRefresh) {
|
|
2479
|
-
const patch = {
|
|
2480
|
-
derived_from: sourceIds,
|
|
2481
|
-
derived_via: "pattern-reinforcement",
|
|
2482
|
-
updated: nowIso
|
|
2483
|
-
};
|
|
2484
|
-
if (reinforcementBumped) {
|
|
2485
|
-
patch.reinforcement_count = newCount;
|
|
2486
|
-
patch.last_reinforced_at = nowIso;
|
|
2487
|
-
} else {
|
|
2488
|
-
patch.reinforcement_count = canonical.frontmatter.reinforcement_count ?? newCount;
|
|
2489
|
-
patch.last_reinforced_at = canonical.frontmatter.last_reinforced_at ?? nowIso;
|
|
2490
|
-
}
|
|
2491
|
-
await storage.writeMemoryFrontmatter(canonical, patch);
|
|
2492
|
-
result.canonicalsUpdated += 1;
|
|
2493
|
-
}
|
|
2494
|
-
const supersededIds = [];
|
|
2495
|
-
for (const dup of activeDuplicates) {
|
|
2496
|
-
const patch = {
|
|
2497
|
-
status: "superseded",
|
|
2498
|
-
supersededBy: canonical.frontmatter.id,
|
|
2499
|
-
supersededAt: nowIso,
|
|
2500
|
-
updated: nowIso
|
|
2501
|
-
};
|
|
2502
|
-
await storage.writeMemoryFrontmatter(dup, patch);
|
|
2503
|
-
supersededIds.push(dup.frontmatter.id);
|
|
2504
|
-
result.duplicatesSuperseded += 1;
|
|
2505
|
-
if (storage.appendTombstone) {
|
|
2506
|
-
for (const input of buildRetiredFactTombstoneInputs(
|
|
2507
|
-
{
|
|
2508
|
-
id: dup.frontmatter.id,
|
|
2509
|
-
content: dup.content,
|
|
2510
|
-
contentHash: dup.frontmatter.contentHash,
|
|
2511
|
-
entityRef: dup.frontmatter.entityRef,
|
|
2512
|
-
structuredAttributes: dup.frontmatter.structuredAttributes
|
|
2513
|
-
},
|
|
2514
|
-
{ reason: "supersession", createdBy: "supersession", createdAt: nowIso, supersessionKeysForFact }
|
|
2515
|
-
)) {
|
|
2516
|
-
try {
|
|
2517
|
-
await storage.appendTombstone(input);
|
|
2518
|
-
} catch {
|
|
2519
|
-
}
|
|
2520
|
-
}
|
|
2521
|
-
}
|
|
2522
|
-
}
|
|
2523
|
-
result.clusters.push({
|
|
2524
|
-
canonicalId: canonical.frontmatter.id,
|
|
2525
|
-
count: newCount,
|
|
2526
|
-
sourceIds,
|
|
2527
|
-
supersededIds,
|
|
2528
|
-
reinforcementBumped
|
|
2529
|
-
});
|
|
2530
|
-
}
|
|
2531
|
-
return result;
|
|
2532
|
-
}
|
|
2533
|
-
function emptyResult() {
|
|
2534
|
-
return {
|
|
2535
|
-
clustersFound: 0,
|
|
2536
|
-
canonicalsUpdated: 0,
|
|
2537
|
-
duplicatesSuperseded: 0,
|
|
2538
|
-
clusters: []
|
|
2539
|
-
};
|
|
2540
|
-
}
|
|
2541
|
-
|
|
2542
|
-
// src/dedup/semantic.ts
|
|
2543
|
-
var DEFAULT_SEMANTIC_THRESHOLD = 0.92;
|
|
2544
|
-
var DEFAULT_SEMANTIC_CANDIDATES = 5;
|
|
2545
|
-
function normalizeSemanticThreshold(value) {
|
|
2546
|
-
return Number.isFinite(value) ? Math.min(1, Math.max(0, value)) : DEFAULT_SEMANTIC_THRESHOLD;
|
|
2547
|
-
}
|
|
2548
|
-
function normalizeSemanticCandidates(value) {
|
|
2549
|
-
if (!Number.isFinite(value) || value < 0) {
|
|
2550
|
-
return DEFAULT_SEMANTIC_CANDIDATES;
|
|
2394
|
+
// src/orchestration/recall-section-coordinator.ts
|
|
2395
|
+
var RecallSectionCoordinator = class {
|
|
2396
|
+
getConfig;
|
|
2397
|
+
resolveSectionEnabled;
|
|
2398
|
+
constructor(options) {
|
|
2399
|
+
this.getConfig = options.getConfig;
|
|
2400
|
+
this.resolveSectionEnabled = options.resolveSectionEnabled ?? ((id, def) => this.isRecallSectionEnabled(id, def));
|
|
2551
2401
|
}
|
|
2552
|
-
|
|
2553
|
-
|
|
2554
|
-
|
|
2555
|
-
async function decideSemanticDedup(content, lookup, options) {
|
|
2556
|
-
if (!options.enabled) {
|
|
2557
|
-
return { action: "keep", reason: "disabled" };
|
|
2402
|
+
getRecallSectionEntry(sectionId) {
|
|
2403
|
+
const pipeline = Array.isArray(this.getConfig().recallPipeline) ? this.getConfig().recallPipeline : [];
|
|
2404
|
+
return pipeline.find((entry) => entry.id === sectionId);
|
|
2558
2405
|
}
|
|
2559
|
-
|
|
2560
|
-
|
|
2561
|
-
|
|
2562
|
-
return
|
|
2406
|
+
isRecallSectionEnabled(sectionId, defaultEnabled = true) {
|
|
2407
|
+
const entry = this.getRecallSectionEntry(sectionId);
|
|
2408
|
+
if (!entry) return defaultEnabled;
|
|
2409
|
+
return entry.enabled !== false;
|
|
2563
2410
|
}
|
|
2564
|
-
|
|
2565
|
-
|
|
2566
|
-
|
|
2411
|
+
isSpecializedRecallSectionEnabled(sectionId, topLevelEnabled) {
|
|
2412
|
+
const entry = this.getRecallSectionEntry(sectionId);
|
|
2413
|
+
if (!entry) return topLevelEnabled;
|
|
2414
|
+
return entry.enabled === true || topLevelEnabled && entry.enabled !== false;
|
|
2567
2415
|
}
|
|
2568
|
-
|
|
2569
|
-
|
|
2570
|
-
|
|
2571
|
-
|
|
2572
|
-
|
|
2416
|
+
getRecallSectionMaxChars(sectionId) {
|
|
2417
|
+
const entry = this.getRecallSectionEntry(sectionId);
|
|
2418
|
+
if (!entry) return void 0;
|
|
2419
|
+
if (entry.maxChars === null) return null;
|
|
2420
|
+
if (typeof entry.maxChars !== "number") return void 0;
|
|
2421
|
+
return Math.max(0, Math.floor(entry.maxChars));
|
|
2573
2422
|
}
|
|
2574
|
-
|
|
2575
|
-
|
|
2423
|
+
getRecallSectionNumber(sectionId, key) {
|
|
2424
|
+
const entry = this.getRecallSectionEntry(sectionId);
|
|
2425
|
+
if (!entry) return void 0;
|
|
2426
|
+
const value = entry[key];
|
|
2427
|
+
if (typeof value !== "number" || !Number.isFinite(value)) return void 0;
|
|
2428
|
+
return Math.max(0, Math.floor(value));
|
|
2576
2429
|
}
|
|
2577
|
-
|
|
2578
|
-
|
|
2579
|
-
|
|
2580
|
-
|
|
2430
|
+
appendRecallSection(sectionBuckets, sectionId, content) {
|
|
2431
|
+
if (!this.resolveSectionEnabled(sectionId, true)) return false;
|
|
2432
|
+
const trimmed = content.trim();
|
|
2433
|
+
if (trimmed.length === 0) return false;
|
|
2434
|
+
const maxChars = this.getRecallSectionMaxChars(sectionId);
|
|
2435
|
+
let finalContent = trimmed;
|
|
2436
|
+
if (maxChars === 0) return false;
|
|
2437
|
+
if (typeof maxChars === "number" && finalContent.length > maxChars) {
|
|
2438
|
+
finalContent = `${finalContent.slice(0, maxChars)}
|
|
2439
|
+
|
|
2440
|
+
...(trimmed)
|
|
2441
|
+
`;
|
|
2581
2442
|
}
|
|
2582
|
-
|
|
2583
|
-
|
|
2443
|
+
const existing = sectionBuckets.get(sectionId) ?? [];
|
|
2444
|
+
existing.push(finalContent);
|
|
2445
|
+
sectionBuckets.set(sectionId, existing);
|
|
2446
|
+
return true;
|
|
2447
|
+
}
|
|
2448
|
+
truncateRecallSectionToBudget(content, maxChars) {
|
|
2449
|
+
if (maxChars <= 0) return "";
|
|
2450
|
+
if (content.length <= maxChars) return content;
|
|
2451
|
+
const suffix = "\n\n...(memory context trimmed)";
|
|
2452
|
+
if (maxChars <= suffix.length) {
|
|
2453
|
+
return content.slice(0, maxChars);
|
|
2584
2454
|
}
|
|
2455
|
+
return `${content.slice(0, maxChars - suffix.length)}${suffix}`;
|
|
2585
2456
|
}
|
|
2586
|
-
|
|
2587
|
-
|
|
2457
|
+
protectedRecallSectionIds(sectionBuckets) {
|
|
2458
|
+
const protectedIds = /* @__PURE__ */ new Set();
|
|
2459
|
+
if ((sectionBuckets.get("memories")?.length ?? 0) > 0) {
|
|
2460
|
+
protectedIds.add("memories");
|
|
2461
|
+
}
|
|
2462
|
+
return protectedIds;
|
|
2588
2463
|
}
|
|
2589
|
-
|
|
2590
|
-
|
|
2591
|
-
|
|
2592
|
-
|
|
2593
|
-
topScore: top.score,
|
|
2594
|
-
topId: top.id,
|
|
2595
|
-
topPath: top.path
|
|
2596
|
-
};
|
|
2464
|
+
protectedRecallReservationChars(content) {
|
|
2465
|
+
const headingBoundary = content.indexOf("\n\n");
|
|
2466
|
+
const headingChars = headingBoundary >= 0 ? headingBoundary + 2 : Math.min(content.length, 24);
|
|
2467
|
+
return Math.min(content.length, Math.max(headingChars, 24));
|
|
2597
2468
|
}
|
|
2598
|
-
|
|
2599
|
-
|
|
2600
|
-
|
|
2601
|
-
|
|
2469
|
+
estimateReservedRecallBudget(entries, startIndex, protectedIds, alreadyIncludedCount) {
|
|
2470
|
+
const separatorLength = "\n\n---\n\n".length;
|
|
2471
|
+
let reserved = 0;
|
|
2472
|
+
let simulatedIncluded = alreadyIncludedCount;
|
|
2473
|
+
for (let i = startIndex; i < entries.length; i += 1) {
|
|
2474
|
+
const entry = entries[i];
|
|
2475
|
+
if (!entry || !protectedIds.has(entry.id)) continue;
|
|
2476
|
+
if (simulatedIncluded > 0) {
|
|
2477
|
+
reserved += separatorLength;
|
|
2478
|
+
}
|
|
2479
|
+
reserved += this.protectedRecallReservationChars(entry.content);
|
|
2480
|
+
simulatedIncluded += 1;
|
|
2481
|
+
}
|
|
2482
|
+
return reserved;
|
|
2483
|
+
}
|
|
2484
|
+
getRecallBudgetChars(override) {
|
|
2485
|
+
if (typeof override === "number" && Number.isFinite(override) && override >= 0) {
|
|
2486
|
+
return Math.floor(override);
|
|
2487
|
+
}
|
|
2488
|
+
const configuredBudget = this.getConfig().recallBudgetChars;
|
|
2489
|
+
if (typeof configuredBudget === "number" && Number.isFinite(configuredBudget) && configuredBudget >= 0) {
|
|
2490
|
+
return Math.floor(configuredBudget);
|
|
2491
|
+
}
|
|
2492
|
+
const tokenBudget = this.getConfig().maxMemoryTokens;
|
|
2493
|
+
if (typeof tokenBudget === "number" && Number.isFinite(tokenBudget) && tokenBudget >= 0) {
|
|
2494
|
+
return Math.floor(tokenBudget * 4);
|
|
2495
|
+
}
|
|
2496
|
+
return 0;
|
|
2497
|
+
}
|
|
2498
|
+
assembleRecallSections(sectionBuckets, budgetOverride) {
|
|
2499
|
+
const orderedEntries = [];
|
|
2500
|
+
const pipeline = Array.isArray(this.getConfig().recallPipeline) ? this.getConfig().recallPipeline : [];
|
|
2501
|
+
const orderedIds = pipeline.filter((entry) => entry.enabled !== false).map((entry) => entry.id);
|
|
2502
|
+
const seen = /* @__PURE__ */ new Set();
|
|
2503
|
+
for (const id of orderedIds) {
|
|
2504
|
+
const chunks = sectionBuckets.get(id);
|
|
2505
|
+
if (!chunks || chunks.length === 0) continue;
|
|
2506
|
+
orderedEntries.push({ id, content: chunks.join("\n\n") });
|
|
2507
|
+
seen.add(id);
|
|
2508
|
+
}
|
|
2509
|
+
for (const [id, chunks] of sectionBuckets.entries()) {
|
|
2510
|
+
if (seen.has(id)) continue;
|
|
2511
|
+
if (chunks.length === 0) continue;
|
|
2512
|
+
orderedEntries.push({ id, content: chunks.join("\n\n") });
|
|
2513
|
+
}
|
|
2514
|
+
const budget = this.getRecallBudgetChars(budgetOverride);
|
|
2515
|
+
if (budget === 0) {
|
|
2516
|
+
return {
|
|
2517
|
+
sections: [],
|
|
2518
|
+
includedIds: [],
|
|
2519
|
+
omittedIds: orderedEntries.map((entry) => entry.id),
|
|
2520
|
+
truncated: orderedEntries.length > 0,
|
|
2521
|
+
finalChars: 0
|
|
2522
|
+
};
|
|
2523
|
+
}
|
|
2524
|
+
const separator = "\n\n---\n\n";
|
|
2525
|
+
const protectedIds = this.protectedRecallSectionIds(sectionBuckets);
|
|
2526
|
+
const sections = [];
|
|
2527
|
+
const includedIds = [];
|
|
2528
|
+
const omittedIds = [];
|
|
2529
|
+
let usedChars = 0;
|
|
2530
|
+
let truncated = false;
|
|
2531
|
+
for (let index = 0; index < orderedEntries.length; index += 1) {
|
|
2532
|
+
const entry = orderedEntries[index];
|
|
2533
|
+
const separatorChars = sections.length > 0 ? separator.length : 0;
|
|
2534
|
+
const reserve = protectedIds.has(entry.id) ? 0 : this.estimateReservedRecallBudget(
|
|
2535
|
+
orderedEntries,
|
|
2536
|
+
index + 1,
|
|
2537
|
+
protectedIds,
|
|
2538
|
+
sections.length + 1
|
|
2539
|
+
);
|
|
2540
|
+
const availableForEntry = budget - usedChars - separatorChars - reserve;
|
|
2541
|
+
if (availableForEntry <= 0) {
|
|
2542
|
+
omittedIds.push(entry.id);
|
|
2543
|
+
truncated = true;
|
|
2544
|
+
continue;
|
|
2545
|
+
}
|
|
2546
|
+
const finalContent = this.truncateRecallSectionToBudget(
|
|
2547
|
+
entry.content,
|
|
2548
|
+
availableForEntry
|
|
2549
|
+
);
|
|
2550
|
+
if (!finalContent) {
|
|
2551
|
+
omittedIds.push(entry.id);
|
|
2552
|
+
truncated = true;
|
|
2553
|
+
continue;
|
|
2554
|
+
}
|
|
2555
|
+
if (finalContent.length < entry.content.length) {
|
|
2556
|
+
truncated = true;
|
|
2557
|
+
}
|
|
2558
|
+
sections.push(finalContent);
|
|
2559
|
+
includedIds.push(entry.id);
|
|
2560
|
+
usedChars += separatorChars + finalContent.length;
|
|
2561
|
+
}
|
|
2562
|
+
return {
|
|
2563
|
+
sections,
|
|
2564
|
+
includedIds,
|
|
2565
|
+
omittedIds,
|
|
2566
|
+
truncated,
|
|
2567
|
+
finalChars: usedChars
|
|
2568
|
+
};
|
|
2569
|
+
}
|
|
2570
|
+
buildLastRecallBudgetSummary(options) {
|
|
2571
|
+
return {
|
|
2572
|
+
requestedTopK: options.requestedTopK,
|
|
2573
|
+
appliedTopK: options.recallResultLimit,
|
|
2574
|
+
recallBudgetChars: this.getRecallBudgetChars(),
|
|
2575
|
+
maxMemoryTokens: this.getConfig().maxMemoryTokens,
|
|
2576
|
+
qmdFetchLimit: options.qmdFetchLimit,
|
|
2577
|
+
qmdHybridFetchLimit: options.qmdHybridFetchLimit,
|
|
2578
|
+
finalContextChars: options.finalContextChars,
|
|
2579
|
+
truncated: options.truncated,
|
|
2580
|
+
includedSections: [...options.includedSections ?? []],
|
|
2581
|
+
omittedSections: [...options.omittedSections ?? []]
|
|
2582
|
+
};
|
|
2583
|
+
}
|
|
2584
|
+
collectLastRecallSources(sectionBuckets, recallSource) {
|
|
2585
|
+
const used = /* @__PURE__ */ new Set();
|
|
2586
|
+
if (recallSource !== "none") {
|
|
2587
|
+
used.add(recallSource);
|
|
2588
|
+
}
|
|
2589
|
+
for (const [sectionId, chunks] of sectionBuckets.entries()) {
|
|
2590
|
+
if (chunks.length > 0) {
|
|
2591
|
+
used.add(sectionId);
|
|
2592
|
+
}
|
|
2593
|
+
}
|
|
2594
|
+
return [...used];
|
|
2595
|
+
}
|
|
2596
|
+
};
|
|
2597
|
+
|
|
2598
|
+
// src/orchestration/qmd-result-resolver.ts
|
|
2599
|
+
import path4 from "path";
|
|
2600
|
+
function qmdCollectionPathParts(resultPath) {
|
|
2601
|
+
if (!resultPath || path4.isAbsolute(resultPath)) return null;
|
|
2602
|
+
const normalized = resultPath.replace(/\\/g, "/").replace(/^\/+/, "");
|
|
2603
|
+
const slashIndex = normalized.indexOf("/");
|
|
2604
|
+
if (slashIndex <= 0 || slashIndex >= normalized.length - 1) return null;
|
|
2605
|
+
const collection = normalized.slice(0, slashIndex);
|
|
2606
|
+
if (/^\d{4}-\d{2}-\d{2}$/.test(collection)) return null;
|
|
2607
|
+
return {
|
|
2608
|
+
collection,
|
|
2609
|
+
relativePath: normalized.slice(slashIndex + 1)
|
|
2610
|
+
};
|
|
2611
|
+
}
|
|
2612
|
+
function qmdResultPathCandidates(storageDir, resultPath) {
|
|
2613
|
+
const candidates = /* @__PURE__ */ new Set();
|
|
2614
|
+
const storageRoot = path4.resolve(storageDir);
|
|
2615
|
+
const addCandidate = (candidate) => {
|
|
2616
|
+
const resolved = path4.resolve(candidate);
|
|
2617
|
+
if (isPathInsideStorageRoot(storageRoot, resolved)) {
|
|
2618
|
+
candidates.add(resolved);
|
|
2619
|
+
}
|
|
2620
|
+
};
|
|
2621
|
+
const addRelativeCandidates = (relativePath) => {
|
|
2622
|
+
const normalized = relativePath.replace(/\\/g, "/").replace(/^\/+/, "");
|
|
2623
|
+
if (!normalized) return;
|
|
2624
|
+
addCandidate(path4.join(storageRoot, normalized));
|
|
2625
|
+
if (/^\d{4}-\d{2}-\d{2}\//.test(normalized)) {
|
|
2626
|
+
addCandidate(path4.join(storageRoot, "facts", normalized));
|
|
2627
|
+
}
|
|
2628
|
+
};
|
|
2629
|
+
if (path4.isAbsolute(resultPath)) {
|
|
2630
|
+
addCandidate(resultPath);
|
|
2631
|
+
} else {
|
|
2632
|
+
addRelativeCandidates(resultPath);
|
|
2633
|
+
}
|
|
2634
|
+
return [...candidates];
|
|
2635
|
+
}
|
|
2636
|
+
function storageDirOrNull(storage) {
|
|
2637
|
+
const dir = storage.dir;
|
|
2638
|
+
return typeof dir === "string" && dir.length > 0 ? dir : null;
|
|
2639
|
+
}
|
|
2640
|
+
var QmdResultResolver = class {
|
|
2641
|
+
getConfig;
|
|
2642
|
+
storageFor;
|
|
2643
|
+
storageDirNamespace;
|
|
2644
|
+
qmdCollectionNamespaceFromPrefix;
|
|
2645
|
+
namespaceFromPath;
|
|
2646
|
+
constructor(options) {
|
|
2647
|
+
this.getConfig = options.getConfig;
|
|
2648
|
+
this.storageFor = options.storageFor;
|
|
2649
|
+
this.storageDirNamespace = options.storageDirNamespace;
|
|
2650
|
+
this.qmdCollectionNamespaceFromPrefix = options.qmdCollectionNamespaceFromPrefix;
|
|
2651
|
+
this.namespaceFromPath = options.namespaceFromPath;
|
|
2652
|
+
}
|
|
2653
|
+
async readQmdResultMemory(resultPath, fallbackStorage, recallNamespaces = []) {
|
|
2654
|
+
const parts = qmdCollectionPathParts(resultPath);
|
|
2655
|
+
const fallbackStorageDir = storageDirOrNull(fallbackStorage);
|
|
2656
|
+
const config = this.getConfig();
|
|
2657
|
+
const coldCollection = config.qmdColdCollection ?? "openclaw-engram-cold";
|
|
2658
|
+
if (parts && parts.collection === coldCollection) {
|
|
2659
|
+
const storages = [];
|
|
2660
|
+
const seenStorageDirs = /* @__PURE__ */ new Set();
|
|
2661
|
+
const addStorage = (storage) => {
|
|
2662
|
+
const storageDir = storageDirOrNull(storage);
|
|
2663
|
+
const storageKey = storageDir ? path4.resolve(storageDir) : `storage-without-dir-${storages.length}`;
|
|
2664
|
+
if (seenStorageDirs.has(storageKey)) return;
|
|
2665
|
+
seenStorageDirs.add(storageKey);
|
|
2666
|
+
storages.push(storage);
|
|
2667
|
+
};
|
|
2668
|
+
const fallbackNamespace = fallbackStorageDir !== null ? this.storageDirNamespace(fallbackStorageDir) : config.defaultNamespace;
|
|
2669
|
+
if (recallNamespaces.length === 0 || !resolveNamespaceCapabilities(config).namespaces || recallNamespaces.includes(fallbackNamespace)) {
|
|
2670
|
+
addStorage(fallbackStorage);
|
|
2671
|
+
}
|
|
2672
|
+
if (recallNamespaces.length > 0) {
|
|
2673
|
+
for (const namespace of recallNamespaces) {
|
|
2674
|
+
try {
|
|
2675
|
+
addStorage(await this.storageFor(namespace));
|
|
2676
|
+
} catch (err) {
|
|
2677
|
+
log.debug("qmd cold result namespace storage lookup skipped", {
|
|
2678
|
+
path: resultPath,
|
|
2679
|
+
namespace,
|
|
2680
|
+
error: err.message
|
|
2681
|
+
});
|
|
2682
|
+
}
|
|
2683
|
+
}
|
|
2684
|
+
}
|
|
2685
|
+
for (const storage of storages) {
|
|
2686
|
+
const storageDir = storageDirOrNull(storage);
|
|
2687
|
+
if (!storageDir) {
|
|
2688
|
+
const memory = await storage.readMemoryByPath(resultPath);
|
|
2689
|
+
if (memory) return memory;
|
|
2690
|
+
continue;
|
|
2691
|
+
}
|
|
2692
|
+
try {
|
|
2693
|
+
const coldRoot = path4.join(storageDir, "cold");
|
|
2694
|
+
for (const candidate of qmdResultPathCandidates(
|
|
2695
|
+
coldRoot,
|
|
2696
|
+
parts.relativePath
|
|
2697
|
+
)) {
|
|
2698
|
+
const memory = await storage.readMemoryByPath(candidate);
|
|
2699
|
+
if (memory) return memory;
|
|
2700
|
+
}
|
|
2701
|
+
} catch (err) {
|
|
2702
|
+
if (err instanceof SecureStoreLockedError) throw err;
|
|
2703
|
+
log.debug("qmd cold result path lookup failed open", {
|
|
2704
|
+
path: resultPath,
|
|
2705
|
+
collection: coldCollection,
|
|
2706
|
+
error: err.message
|
|
2707
|
+
});
|
|
2708
|
+
}
|
|
2709
|
+
}
|
|
2710
|
+
return null;
|
|
2711
|
+
}
|
|
2712
|
+
const collectionNamespace = parts ? this.qmdCollectionNamespaceFromPrefix(parts.collection) : null;
|
|
2713
|
+
if (parts && collectionNamespace) {
|
|
2714
|
+
try {
|
|
2715
|
+
const collectionStorage = await this.storageFor(collectionNamespace);
|
|
2716
|
+
for (const candidate of qmdResultPathCandidates(
|
|
2717
|
+
collectionStorage.dir,
|
|
2718
|
+
parts.relativePath
|
|
2719
|
+
)) {
|
|
2720
|
+
const memory = await collectionStorage.readMemoryByPath(candidate);
|
|
2721
|
+
if (memory) return memory;
|
|
2722
|
+
}
|
|
2723
|
+
return null;
|
|
2724
|
+
} catch (err) {
|
|
2725
|
+
if (err instanceof SecureStoreLockedError) throw err;
|
|
2726
|
+
log.debug("qmd result namespace path lookup failed open", {
|
|
2727
|
+
path: resultPath,
|
|
2728
|
+
namespace: collectionNamespace,
|
|
2729
|
+
error: err.message
|
|
2730
|
+
});
|
|
2731
|
+
return null;
|
|
2732
|
+
}
|
|
2733
|
+
}
|
|
2734
|
+
if (path4.isAbsolute(resultPath)) {
|
|
2735
|
+
if (!fallbackStorageDir) {
|
|
2736
|
+
return await fallbackStorage.readMemoryByPath(resultPath);
|
|
2737
|
+
}
|
|
2738
|
+
const ownerStorage = await this.storageForAbsoluteQmdResultPath(
|
|
2739
|
+
resultPath,
|
|
2740
|
+
fallbackStorage,
|
|
2741
|
+
recallNamespaces
|
|
2742
|
+
);
|
|
2743
|
+
if (!ownerStorage) return null;
|
|
2744
|
+
for (const candidate of qmdResultPathCandidates(
|
|
2745
|
+
ownerStorage.dir,
|
|
2746
|
+
resultPath
|
|
2747
|
+
)) {
|
|
2748
|
+
const memory = await ownerStorage.storage.readMemoryByPath(candidate);
|
|
2749
|
+
if (memory) return memory;
|
|
2750
|
+
}
|
|
2751
|
+
return null;
|
|
2752
|
+
}
|
|
2753
|
+
if (!fallbackStorageDir) {
|
|
2754
|
+
return await fallbackStorage.readMemoryByPath(resultPath);
|
|
2755
|
+
}
|
|
2756
|
+
for (const candidate of qmdResultPathCandidates(
|
|
2757
|
+
fallbackStorageDir,
|
|
2758
|
+
resultPath
|
|
2759
|
+
)) {
|
|
2760
|
+
const memory = await fallbackStorage.readMemoryByPath(candidate);
|
|
2761
|
+
if (memory) return memory;
|
|
2762
|
+
}
|
|
2763
|
+
return null;
|
|
2764
|
+
}
|
|
2765
|
+
async resolveColdQmdResultForRecall(result, fallbackStorage, recallNamespaces = []) {
|
|
2766
|
+
const memory = await this.readQmdResultMemory(
|
|
2767
|
+
result.path,
|
|
2768
|
+
fallbackStorage,
|
|
2769
|
+
recallNamespaces
|
|
2770
|
+
);
|
|
2771
|
+
if (!memory) return null;
|
|
2772
|
+
let ownerNamespace = null;
|
|
2773
|
+
if (path4.isAbsolute(memory.path)) {
|
|
2774
|
+
const ownerStorage = await this.storageForAbsoluteQmdResultPath(
|
|
2775
|
+
memory.path,
|
|
2776
|
+
fallbackStorage,
|
|
2777
|
+
recallNamespaces
|
|
2778
|
+
);
|
|
2779
|
+
ownerNamespace = ownerStorage?.namespace ?? null;
|
|
2780
|
+
if (!ownerNamespace && resolveNamespaceCapabilities(this.getConfig()).namespaces) return null;
|
|
2781
|
+
}
|
|
2782
|
+
ownerNamespace ??= this.namespaceFromPath(memory.path);
|
|
2783
|
+
if (recallNamespaces.length > 0 && !recallNamespaces.includes(ownerNamespace)) {
|
|
2784
|
+
return null;
|
|
2785
|
+
}
|
|
2786
|
+
return {
|
|
2787
|
+
namespace: ownerNamespace,
|
|
2788
|
+
result: {
|
|
2789
|
+
...result,
|
|
2790
|
+
docid: result.docid || memory.frontmatter.id,
|
|
2791
|
+
path: memory.path,
|
|
2792
|
+
snippet: result.snippet || memory.content.slice(0, 400)
|
|
2793
|
+
}
|
|
2794
|
+
};
|
|
2795
|
+
}
|
|
2796
|
+
async storageForAbsoluteQmdResultPath(resultPath, fallbackStorage, recallNamespaces = []) {
|
|
2797
|
+
const resolvedPath = path4.resolve(resultPath);
|
|
2798
|
+
const config = this.getConfig();
|
|
2799
|
+
const memoryRoot = path4.resolve(config.memoryDir);
|
|
2800
|
+
const namespacesRoot = path4.join(memoryRoot, "namespaces");
|
|
2801
|
+
const fallbackStorageDir = storageDirOrNull(fallbackStorage);
|
|
2802
|
+
const matches = [];
|
|
2803
|
+
const seenDirs = /* @__PURE__ */ new Set();
|
|
2804
|
+
const maybeAddStorage = (storage, namespace) => {
|
|
2805
|
+
const storageDir = storageDirOrNull(storage);
|
|
2806
|
+
if (!storageDir) return;
|
|
2807
|
+
const candidateRoot = path4.resolve(storageDir);
|
|
2808
|
+
if (seenDirs.has(candidateRoot)) return;
|
|
2809
|
+
if (!isPathInsideStorageRoot(candidateRoot, resolvedPath)) return;
|
|
2810
|
+
if (candidateRoot === memoryRoot && isPathInsideStorageRoot(namespacesRoot, resolvedPath)) {
|
|
2811
|
+
return;
|
|
2812
|
+
}
|
|
2813
|
+
seenDirs.add(candidateRoot);
|
|
2814
|
+
matches.push({ storage, dir: candidateRoot, namespace });
|
|
2815
|
+
};
|
|
2816
|
+
const fallbackNamespace = fallbackStorageDir !== null ? this.storageDirNamespace(fallbackStorageDir) : config.defaultNamespace;
|
|
2817
|
+
maybeAddStorage(fallbackStorage, fallbackNamespace);
|
|
2818
|
+
const candidateNamespaces = /* @__PURE__ */ new Set();
|
|
2819
|
+
candidateNamespaces.add(config.defaultNamespace);
|
|
2820
|
+
candidateNamespaces.add(config.sharedNamespace);
|
|
2821
|
+
for (const ns of recallNamespaces) {
|
|
2822
|
+
candidateNamespaces.add(ns);
|
|
2823
|
+
}
|
|
2824
|
+
if (isPathInsideStorageRoot(namespacesRoot, resolvedPath)) {
|
|
2825
|
+
const relativeToNamespaces = path4.relative(namespacesRoot, resolvedPath);
|
|
2826
|
+
const [namespaceSegment] = relativeToNamespaces.split(/[\\/]/);
|
|
2827
|
+
if (namespaceSegment) {
|
|
2828
|
+
candidateNamespaces.add(
|
|
2829
|
+
namespaceIdentityFromToken(namespaceSegment) ?? namespaceSegment
|
|
2830
|
+
);
|
|
2831
|
+
}
|
|
2832
|
+
}
|
|
2833
|
+
for (const policy of config.namespacePolicies ?? []) {
|
|
2834
|
+
candidateNamespaces.add(policy.name);
|
|
2835
|
+
}
|
|
2836
|
+
for (const ns of candidateNamespaces) {
|
|
2837
|
+
if (!ns) continue;
|
|
2838
|
+
try {
|
|
2839
|
+
maybeAddStorage(await this.storageFor(ns), ns);
|
|
2840
|
+
} catch {
|
|
2841
|
+
continue;
|
|
2842
|
+
}
|
|
2843
|
+
}
|
|
2844
|
+
matches.sort((a, b) => b.dir.length - a.dir.length);
|
|
2845
|
+
return matches[0] ?? null;
|
|
2846
|
+
}
|
|
2847
|
+
};
|
|
2848
|
+
|
|
2849
|
+
// src/orchestration/contradiction-linking-coordinator.ts
|
|
2850
|
+
var ContradictionLinkingCoordinator = class {
|
|
2851
|
+
getConfig;
|
|
2852
|
+
isSearchAvailable;
|
|
2853
|
+
searchAcrossNamespaces;
|
|
2854
|
+
extractMemoryIdsFromResults;
|
|
2855
|
+
namespaceFromPath;
|
|
2856
|
+
storageForNamespace;
|
|
2857
|
+
getExtraction;
|
|
2858
|
+
constructor(options) {
|
|
2859
|
+
this.getConfig = options.getConfig;
|
|
2860
|
+
this.isSearchAvailable = options.isSearchAvailable;
|
|
2861
|
+
this.searchAcrossNamespaces = options.searchAcrossNamespaces;
|
|
2862
|
+
this.extractMemoryIdsFromResults = options.extractMemoryIdsFromResults;
|
|
2863
|
+
this.namespaceFromPath = options.namespaceFromPath;
|
|
2864
|
+
this.storageForNamespace = options.storageForNamespace;
|
|
2865
|
+
this.getExtraction = options.getExtraction;
|
|
2866
|
+
}
|
|
2867
|
+
/**
|
|
2868
|
+
* Check if a new memory contradicts an existing one.
|
|
2869
|
+
* Uses QMD to find similar memories, then LLM to verify contradiction.
|
|
2870
|
+
*/
|
|
2871
|
+
async checkForContradiction(content, category, namespaceScope) {
|
|
2872
|
+
if (!this.isSearchAvailable()) return null;
|
|
2873
|
+
const config = this.getConfig();
|
|
2874
|
+
const results = await this.searchAcrossNamespaces({
|
|
2875
|
+
query: content,
|
|
2876
|
+
namespaces: [namespaceScope],
|
|
2877
|
+
maxResults: 5,
|
|
2878
|
+
mode: "search"
|
|
2879
|
+
});
|
|
2880
|
+
for (const result of results) {
|
|
2881
|
+
if (result.score < config.contradictionSimilarityThreshold) {
|
|
2882
|
+
continue;
|
|
2883
|
+
}
|
|
2884
|
+
const memoryId = this.extractMemoryIdsFromResults([result])[0];
|
|
2885
|
+
if (!memoryId) continue;
|
|
2886
|
+
const resultNamespace = this.namespaceFromPath(result.path);
|
|
2887
|
+
if (resultNamespace !== namespaceScope) continue;
|
|
2888
|
+
const resultStorage = await this.storageForNamespace(resultNamespace);
|
|
2889
|
+
const existingMemory = await resultStorage.getMemoryById(memoryId);
|
|
2890
|
+
if (!existingMemory) continue;
|
|
2891
|
+
if (existingMemory.frontmatter.status === "superseded" || existingMemory.frontmatter.status === "forgotten") {
|
|
2892
|
+
continue;
|
|
2893
|
+
}
|
|
2894
|
+
const extraction = this.getExtraction();
|
|
2895
|
+
const verification = await extraction.verifyContradiction(
|
|
2896
|
+
{ content, category },
|
|
2897
|
+
{
|
|
2898
|
+
id: existingMemory.frontmatter.id,
|
|
2899
|
+
content: existingMemory.content,
|
|
2900
|
+
category: existingMemory.frontmatter.category,
|
|
2901
|
+
created: existingMemory.frontmatter.created
|
|
2902
|
+
}
|
|
2903
|
+
);
|
|
2904
|
+
if (!verification) continue;
|
|
2905
|
+
if (verification.isContradiction && verification.confidence >= config.contradictionMinConfidence) {
|
|
2906
|
+
if (verification.whichIsNewer === "first") {
|
|
2907
|
+
log.info(
|
|
2908
|
+
`detected contradiction (confidence: ${verification.confidence}): ${existingMemory.frontmatter.id} vs new memory \u2014 existing is newer, incoming fact is stale`
|
|
2909
|
+
);
|
|
2910
|
+
continue;
|
|
2911
|
+
}
|
|
2912
|
+
log.info(
|
|
2913
|
+
`detected contradiction (confidence: ${verification.confidence}): ${existingMemory.frontmatter.id} vs new memory${config.contradictionAutoResolve ? " (auto-resolved)" : " (queued for manual review)"}`
|
|
2914
|
+
);
|
|
2915
|
+
return {
|
|
2916
|
+
supersededId: existingMemory.frontmatter.id,
|
|
2917
|
+
confidence: verification.confidence,
|
|
2918
|
+
reason: verification.reasoning,
|
|
2919
|
+
supersededPath: existingMemory.path,
|
|
2920
|
+
supersededCreated: existingMemory.frontmatter.created,
|
|
2921
|
+
supersededTags: existingMemory.frontmatter.tags ?? []
|
|
2922
|
+
};
|
|
2923
|
+
}
|
|
2924
|
+
}
|
|
2925
|
+
return null;
|
|
2926
|
+
}
|
|
2927
|
+
/**
|
|
2928
|
+
* #1645: Complete the deferred contradiction auto-resolve after writeMemory
|
|
2929
|
+
* returns and the new write's tombstone status is known. Retires the old
|
|
2930
|
+
* memory + deindexes it ONLY when the new write is genuinely active (not
|
|
2931
|
+
* tombstone-blocked / pending_review). A blocked write must not retire the
|
|
2932
|
+
* only active copy — deferring here closes the "contradictionAutoResolve
|
|
2933
|
+
* supersedes before tombstone status is known" defect class.
|
|
2934
|
+
*/
|
|
2935
|
+
async applyDeferredContradictionResolve(contradiction, storage, newMemoryId, postWriteGuard) {
|
|
2936
|
+
const config = this.getConfig();
|
|
2937
|
+
if (postWriteGuard && contradiction && config.contradictionAutoResolve) {
|
|
2938
|
+
try {
|
|
2939
|
+
const blockedRow = await storage.getMemoryById(newMemoryId);
|
|
2940
|
+
if (blockedRow?.frontmatter?.supersedes) {
|
|
2941
|
+
await storage.writeMemoryFrontmatter(blockedRow, { supersedes: void 0 });
|
|
2942
|
+
}
|
|
2943
|
+
} catch (err) {
|
|
2944
|
+
log.warn(
|
|
2945
|
+
`contradiction auto-resolve supersedes clear failed for blocked ${newMemoryId}: ${err}`
|
|
2946
|
+
);
|
|
2947
|
+
}
|
|
2948
|
+
}
|
|
2949
|
+
if (!contradiction || !config.contradictionAutoResolve || postWriteGuard) {
|
|
2950
|
+
return;
|
|
2951
|
+
}
|
|
2952
|
+
try {
|
|
2953
|
+
await storage.supersedeMemory(
|
|
2954
|
+
contradiction.supersededId,
|
|
2955
|
+
newMemoryId,
|
|
2956
|
+
contradiction.reason
|
|
2957
|
+
);
|
|
2958
|
+
if (resolveIndexingCapabilities(config).queryAwareIndexing && contradiction.supersededPath) {
|
|
2959
|
+
deindexMemory(
|
|
2960
|
+
config.memoryDir,
|
|
2961
|
+
contradiction.supersededPath,
|
|
2962
|
+
contradiction.supersededCreated,
|
|
2963
|
+
contradiction.supersededTags
|
|
2964
|
+
);
|
|
2965
|
+
}
|
|
2966
|
+
} catch (err) {
|
|
2967
|
+
log.warn(
|
|
2968
|
+
`contradiction auto-resolve supersede failed for ${contradiction.supersededId}: ${err}`
|
|
2969
|
+
);
|
|
2970
|
+
}
|
|
2971
|
+
}
|
|
2972
|
+
// ---------------------------------------------------------------------------
|
|
2973
|
+
// Memory Linking (Phase 3A)
|
|
2974
|
+
// ---------------------------------------------------------------------------
|
|
2975
|
+
/**
|
|
2976
|
+
* Suggest links for a new memory based on similar existing memories.
|
|
2977
|
+
*/
|
|
2978
|
+
async suggestLinksForMemory(content, category, namespaceScope) {
|
|
2979
|
+
if (!this.isSearchAvailable()) return [];
|
|
2980
|
+
const results = await this.searchAcrossNamespaces({
|
|
2981
|
+
query: content,
|
|
2982
|
+
namespaces: [namespaceScope],
|
|
2983
|
+
maxResults: 5,
|
|
2984
|
+
mode: "search"
|
|
2985
|
+
});
|
|
2986
|
+
if (results.length === 0) return [];
|
|
2987
|
+
const candidates = [];
|
|
2988
|
+
for (const result of results) {
|
|
2989
|
+
const memoryId = this.extractMemoryIdsFromResults([result])[0];
|
|
2990
|
+
if (!memoryId) continue;
|
|
2991
|
+
const resultNamespace = this.namespaceFromPath(result.path);
|
|
2992
|
+
if (resultNamespace !== namespaceScope) continue;
|
|
2993
|
+
const resultStorage = await this.storageForNamespace(resultNamespace);
|
|
2994
|
+
const memory = await resultStorage.getMemoryById(memoryId);
|
|
2995
|
+
if (memory && memory.frontmatter.status !== "superseded" && memory.frontmatter.status !== "forgotten") {
|
|
2996
|
+
candidates.push({
|
|
2997
|
+
id: memory.frontmatter.id,
|
|
2998
|
+
content: memory.content,
|
|
2999
|
+
category: memory.frontmatter.category
|
|
3000
|
+
});
|
|
3001
|
+
}
|
|
3002
|
+
}
|
|
3003
|
+
if (candidates.length === 0) return [];
|
|
3004
|
+
const extraction = this.getExtraction();
|
|
3005
|
+
const suggestions = await extraction.suggestLinks(
|
|
3006
|
+
{ content, category },
|
|
3007
|
+
candidates
|
|
3008
|
+
);
|
|
3009
|
+
if (!suggestions || suggestions.links.length === 0) return [];
|
|
3010
|
+
return suggestions.links.map((link) => ({
|
|
3011
|
+
targetId: link.targetId,
|
|
3012
|
+
linkType: link.linkType,
|
|
3013
|
+
strength: link.strength,
|
|
3014
|
+
reason: link.reason || void 0
|
|
3015
|
+
}));
|
|
3016
|
+
}
|
|
3017
|
+
};
|
|
3018
|
+
|
|
3019
|
+
// src/maintenance/pattern-reinforcement.ts
|
|
3020
|
+
function patternReinforcementKey(content) {
|
|
3021
|
+
return content.trim().toLowerCase().replace(/\s+/g, " ").slice(0, 200);
|
|
3022
|
+
}
|
|
3023
|
+
function patternReinforcementClusterKey(category, content) {
|
|
3024
|
+
return `${category}::${patternReinforcementKey(content)}`;
|
|
3025
|
+
}
|
|
3026
|
+
function pickCanonical(memories) {
|
|
3027
|
+
let best = memories[0];
|
|
3028
|
+
let bestInstant = memoryInstant(best);
|
|
3029
|
+
let bestStamp = memoryStamp(best);
|
|
3030
|
+
for (let i = 1; i < memories.length; i += 1) {
|
|
3031
|
+
const candidate = memories[i];
|
|
3032
|
+
const instant = memoryInstant(candidate);
|
|
3033
|
+
const stamp = memoryStamp(candidate);
|
|
3034
|
+
let cmp;
|
|
3035
|
+
if (instant !== null && bestInstant !== null) {
|
|
3036
|
+
cmp = instant - bestInstant;
|
|
3037
|
+
} else {
|
|
3038
|
+
cmp = stamp.localeCompare(bestStamp);
|
|
3039
|
+
}
|
|
3040
|
+
if (cmp > 0 || cmp === 0 && candidate.frontmatter.id > best.frontmatter.id) {
|
|
3041
|
+
best = candidate;
|
|
3042
|
+
bestInstant = instant;
|
|
3043
|
+
bestStamp = stamp;
|
|
3044
|
+
}
|
|
3045
|
+
}
|
|
3046
|
+
return best;
|
|
3047
|
+
}
|
|
3048
|
+
function memoryStamp(memory) {
|
|
3049
|
+
return memory.frontmatter.updated || memory.frontmatter.created || "";
|
|
3050
|
+
}
|
|
3051
|
+
function memoryInstant(memory) {
|
|
3052
|
+
const stamp = memoryStamp(memory);
|
|
3053
|
+
if (stamp.length === 0) return null;
|
|
3054
|
+
const parsed = Date.parse(stamp);
|
|
3055
|
+
return Number.isFinite(parsed) ? parsed : null;
|
|
3056
|
+
}
|
|
3057
|
+
var ACTIVE_STATUS = "active";
|
|
3058
|
+
async function runPatternReinforcement(storage, options) {
|
|
3059
|
+
const minCount = Math.max(2, Math.floor(options.minCount));
|
|
3060
|
+
const targetCategories = new Set(options.categories);
|
|
3061
|
+
const now = options.now ?? (() => /* @__PURE__ */ new Date());
|
|
3062
|
+
const nowIso = now().toISOString();
|
|
3063
|
+
if (targetCategories.size === 0) {
|
|
3064
|
+
return emptyResult();
|
|
3065
|
+
}
|
|
3066
|
+
const memories = await storage.readAllMemories();
|
|
3067
|
+
const eligible = memories.filter((m) => {
|
|
3068
|
+
if (!targetCategories.has(m.frontmatter.category)) return false;
|
|
3069
|
+
const status = m.frontmatter.status ?? ACTIVE_STATUS;
|
|
3070
|
+
return status === ACTIVE_STATUS || status === "superseded";
|
|
3071
|
+
});
|
|
3072
|
+
if (eligible.length === 0) return emptyResult();
|
|
3073
|
+
const clusters = clusterByKey(
|
|
3074
|
+
eligible,
|
|
3075
|
+
(m) => patternReinforcementClusterKey(m.frontmatter.category, m.content)
|
|
3076
|
+
);
|
|
3077
|
+
const result = {
|
|
3078
|
+
clustersFound: 0,
|
|
3079
|
+
canonicalsUpdated: 0,
|
|
3080
|
+
duplicatesSuperseded: 0,
|
|
3081
|
+
clusters: []
|
|
3082
|
+
};
|
|
3083
|
+
for (const cluster of clusters.values()) {
|
|
3084
|
+
if (cluster.length < minCount) continue;
|
|
3085
|
+
const activeMembers = cluster.filter((m) => {
|
|
3086
|
+
const status = m.frontmatter.status ?? ACTIVE_STATUS;
|
|
3087
|
+
return status === ACTIVE_STATUS;
|
|
3088
|
+
});
|
|
3089
|
+
if (activeMembers.length === 0) continue;
|
|
3090
|
+
result.clustersFound += 1;
|
|
3091
|
+
const canonical = pickCanonical(activeMembers);
|
|
3092
|
+
const activeDuplicates = activeMembers.filter((m) => m !== canonical);
|
|
3093
|
+
const sourceIds = [...cluster].map((m) => m.frontmatter.id).filter((id) => typeof id === "string" && id.length > 0).sort();
|
|
3094
|
+
const previousCount = canonical.frontmatter.reinforcement_count ?? 0;
|
|
3095
|
+
const newCount = sourceIds.length;
|
|
3096
|
+
const reinforcementBumped = newCount > previousCount;
|
|
3097
|
+
const previousDerivedFrom = Array.isArray(canonical.frontmatter.derived_from) ? [...canonical.frontmatter.derived_from].sort() : [];
|
|
3098
|
+
const sortedSourceIds = [...sourceIds].sort();
|
|
3099
|
+
const membershipChanged = previousDerivedFrom.length !== sortedSourceIds.length || previousDerivedFrom.some((id, i) => id !== sortedSourceIds[i]);
|
|
3100
|
+
const previousVia = canonical.frontmatter.derived_via;
|
|
3101
|
+
const viaChanged = previousVia !== "pattern-reinforcement";
|
|
3102
|
+
const canonicalNeedsRefresh = reinforcementBumped || membershipChanged || viaChanged;
|
|
3103
|
+
if (canonicalNeedsRefresh) {
|
|
3104
|
+
const patch = {
|
|
3105
|
+
derived_from: sourceIds,
|
|
3106
|
+
derived_via: "pattern-reinforcement",
|
|
3107
|
+
updated: nowIso
|
|
3108
|
+
};
|
|
3109
|
+
if (reinforcementBumped) {
|
|
3110
|
+
patch.reinforcement_count = newCount;
|
|
3111
|
+
patch.last_reinforced_at = nowIso;
|
|
3112
|
+
} else {
|
|
3113
|
+
patch.reinforcement_count = canonical.frontmatter.reinforcement_count ?? newCount;
|
|
3114
|
+
patch.last_reinforced_at = canonical.frontmatter.last_reinforced_at ?? nowIso;
|
|
3115
|
+
}
|
|
3116
|
+
await storage.writeMemoryFrontmatter(canonical, patch);
|
|
3117
|
+
result.canonicalsUpdated += 1;
|
|
3118
|
+
}
|
|
3119
|
+
const supersededIds = [];
|
|
3120
|
+
for (const dup of activeDuplicates) {
|
|
3121
|
+
const patch = {
|
|
3122
|
+
status: "superseded",
|
|
3123
|
+
supersededBy: canonical.frontmatter.id,
|
|
3124
|
+
supersededAt: nowIso,
|
|
3125
|
+
updated: nowIso
|
|
3126
|
+
};
|
|
3127
|
+
await storage.writeMemoryFrontmatter(dup, patch);
|
|
3128
|
+
supersededIds.push(dup.frontmatter.id);
|
|
3129
|
+
result.duplicatesSuperseded += 1;
|
|
3130
|
+
if (storage.appendTombstone) {
|
|
3131
|
+
for (const input of buildRetiredFactTombstoneInputs(
|
|
3132
|
+
{
|
|
3133
|
+
id: dup.frontmatter.id,
|
|
3134
|
+
content: dup.content,
|
|
3135
|
+
contentHash: dup.frontmatter.contentHash,
|
|
3136
|
+
entityRef: dup.frontmatter.entityRef,
|
|
3137
|
+
structuredAttributes: dup.frontmatter.structuredAttributes
|
|
3138
|
+
},
|
|
3139
|
+
{ reason: "supersession", createdBy: "supersession", createdAt: nowIso, supersessionKeysForFact }
|
|
3140
|
+
)) {
|
|
3141
|
+
try {
|
|
3142
|
+
await storage.appendTombstone(input);
|
|
3143
|
+
} catch {
|
|
3144
|
+
}
|
|
3145
|
+
}
|
|
3146
|
+
}
|
|
3147
|
+
}
|
|
3148
|
+
result.clusters.push({
|
|
3149
|
+
canonicalId: canonical.frontmatter.id,
|
|
3150
|
+
count: newCount,
|
|
3151
|
+
sourceIds,
|
|
3152
|
+
supersededIds,
|
|
3153
|
+
reinforcementBumped
|
|
3154
|
+
});
|
|
3155
|
+
}
|
|
3156
|
+
return result;
|
|
3157
|
+
}
|
|
3158
|
+
function emptyResult() {
|
|
3159
|
+
return {
|
|
3160
|
+
clustersFound: 0,
|
|
3161
|
+
canonicalsUpdated: 0,
|
|
3162
|
+
duplicatesSuperseded: 0,
|
|
3163
|
+
clusters: []
|
|
3164
|
+
};
|
|
3165
|
+
}
|
|
3166
|
+
|
|
3167
|
+
// src/dedup/semantic.ts
|
|
3168
|
+
var DEFAULT_SEMANTIC_THRESHOLD = 0.92;
|
|
3169
|
+
var DEFAULT_SEMANTIC_CANDIDATES = 5;
|
|
3170
|
+
function normalizeSemanticThreshold(value) {
|
|
3171
|
+
return Number.isFinite(value) ? Math.min(1, Math.max(0, value)) : DEFAULT_SEMANTIC_THRESHOLD;
|
|
3172
|
+
}
|
|
3173
|
+
function normalizeSemanticCandidates(value) {
|
|
3174
|
+
if (!Number.isFinite(value) || value < 0) {
|
|
3175
|
+
return DEFAULT_SEMANTIC_CANDIDATES;
|
|
3176
|
+
}
|
|
3177
|
+
const normalized = Math.floor(value);
|
|
3178
|
+
return value > 0 && normalized === 0 ? 1 : normalized;
|
|
3179
|
+
}
|
|
3180
|
+
async function decideSemanticDedup(content, lookup, options) {
|
|
3181
|
+
if (!options.enabled) {
|
|
3182
|
+
return { action: "keep", reason: "disabled" };
|
|
3183
|
+
}
|
|
3184
|
+
const threshold = normalizeSemanticThreshold(options.threshold);
|
|
3185
|
+
const candidates = normalizeSemanticCandidates(options.candidates);
|
|
3186
|
+
if (candidates === 0) {
|
|
3187
|
+
return { action: "keep", reason: "disabled" };
|
|
3188
|
+
}
|
|
3189
|
+
const trimmed = typeof content === "string" ? content.trim() : "";
|
|
3190
|
+
if (!trimmed) {
|
|
3191
|
+
return { action: "keep", reason: "no_near_duplicate" };
|
|
3192
|
+
}
|
|
3193
|
+
let hits = [];
|
|
3194
|
+
try {
|
|
3195
|
+
hits = await lookup(trimmed, candidates);
|
|
3196
|
+
} catch {
|
|
3197
|
+
return { action: "keep", reason: "backend_unavailable" };
|
|
3198
|
+
}
|
|
3199
|
+
if (!Array.isArray(hits) || hits.length === 0) {
|
|
3200
|
+
return { action: "keep", reason: "no_candidates" };
|
|
3201
|
+
}
|
|
3202
|
+
let top;
|
|
3203
|
+
for (const hit of hits) {
|
|
3204
|
+
if (!hit || typeof hit.id !== "string" || hit.id.trim().length === 0 || typeof hit.score !== "number" || !Number.isFinite(hit.score)) {
|
|
3205
|
+
continue;
|
|
3206
|
+
}
|
|
3207
|
+
if (!top || hit.score > top.score) {
|
|
3208
|
+
top = hit;
|
|
3209
|
+
}
|
|
3210
|
+
}
|
|
3211
|
+
if (!top) {
|
|
3212
|
+
return { action: "keep", reason: "no_near_duplicate" };
|
|
3213
|
+
}
|
|
3214
|
+
if (top.score >= threshold) {
|
|
3215
|
+
return {
|
|
3216
|
+
action: "skip",
|
|
3217
|
+
reason: "near_duplicate",
|
|
3218
|
+
topScore: top.score,
|
|
3219
|
+
topId: top.id,
|
|
3220
|
+
topPath: top.path
|
|
3221
|
+
};
|
|
3222
|
+
}
|
|
3223
|
+
return {
|
|
3224
|
+
action: "keep",
|
|
3225
|
+
reason: "no_near_duplicate",
|
|
3226
|
+
topScore: top.score,
|
|
2602
3227
|
topId: top.id
|
|
2603
3228
|
};
|
|
2604
3229
|
}
|
|
@@ -2724,7 +3349,7 @@ function generateResolverDocument(taxonomy) {
|
|
|
2724
3349
|
|
|
2725
3350
|
// src/taxonomy/taxonomy-loader.ts
|
|
2726
3351
|
import { readFile, mkdir as mkdir2, writeFile as writeFile2 } from "fs/promises";
|
|
2727
|
-
import
|
|
3352
|
+
import path5 from "path";
|
|
2728
3353
|
var TAXONOMY_DIR = ".taxonomy";
|
|
2729
3354
|
var TAXONOMY_FILE = "taxonomy.json";
|
|
2730
3355
|
var MAX_SLUG_LENGTH = 32;
|
|
@@ -2822,7 +3447,7 @@ function validateTaxonomy(taxonomy) {
|
|
|
2822
3447
|
}
|
|
2823
3448
|
}
|
|
2824
3449
|
async function loadTaxonomy(memoryDir) {
|
|
2825
|
-
const taxonomyPath =
|
|
3450
|
+
const taxonomyPath = path5.join(memoryDir, TAXONOMY_DIR, TAXONOMY_FILE);
|
|
2826
3451
|
let raw;
|
|
2827
3452
|
try {
|
|
2828
3453
|
raw = await readFile(taxonomyPath, "utf-8");
|
|
@@ -2872,16 +3497,16 @@ async function loadTaxonomy(memoryDir) {
|
|
|
2872
3497
|
}
|
|
2873
3498
|
async function saveTaxonomy(memoryDir, taxonomy) {
|
|
2874
3499
|
validateTaxonomy(taxonomy);
|
|
2875
|
-
const dir =
|
|
3500
|
+
const dir = path5.join(memoryDir, TAXONOMY_DIR);
|
|
2876
3501
|
await mkdir2(dir, { recursive: true });
|
|
2877
|
-
const filePath =
|
|
3502
|
+
const filePath = path5.join(dir, TAXONOMY_FILE);
|
|
2878
3503
|
await writeFile2(filePath, JSON.stringify(taxonomy, null, 2) + "\n", "utf-8");
|
|
2879
3504
|
}
|
|
2880
3505
|
function getTaxonomyDir(memoryDir) {
|
|
2881
|
-
return
|
|
3506
|
+
return path5.join(memoryDir, TAXONOMY_DIR);
|
|
2882
3507
|
}
|
|
2883
3508
|
function getTaxonomyFilePath(memoryDir) {
|
|
2884
|
-
return
|
|
3509
|
+
return path5.join(memoryDir, TAXONOMY_DIR, TAXONOMY_FILE);
|
|
2885
3510
|
}
|
|
2886
3511
|
|
|
2887
3512
|
// src/wearables/registry.ts
|
|
@@ -3781,42 +4406,6 @@ async function raceRecallAbort(promise, signal, message = "recall aborted") {
|
|
|
3781
4406
|
}
|
|
3782
4407
|
}
|
|
3783
4408
|
}
|
|
3784
|
-
function qmdCollectionPathParts(resultPath) {
|
|
3785
|
-
if (!resultPath || path5.isAbsolute(resultPath)) return null;
|
|
3786
|
-
const normalized = resultPath.replace(/\\/g, "/").replace(/^\/+/, "");
|
|
3787
|
-
const slashIndex = normalized.indexOf("/");
|
|
3788
|
-
if (slashIndex <= 0 || slashIndex >= normalized.length - 1) return null;
|
|
3789
|
-
const collection = normalized.slice(0, slashIndex);
|
|
3790
|
-
if (/^\d{4}-\d{2}-\d{2}$/.test(collection)) return null;
|
|
3791
|
-
return {
|
|
3792
|
-
collection,
|
|
3793
|
-
relativePath: normalized.slice(slashIndex + 1)
|
|
3794
|
-
};
|
|
3795
|
-
}
|
|
3796
|
-
function qmdResultPathCandidates(storageDir, resultPath) {
|
|
3797
|
-
const candidates = /* @__PURE__ */ new Set();
|
|
3798
|
-
const storageRoot = path5.resolve(storageDir);
|
|
3799
|
-
const addCandidate = (candidate) => {
|
|
3800
|
-
const resolved = path5.resolve(candidate);
|
|
3801
|
-
if (isPathInsideStorageRoot(storageRoot, resolved)) {
|
|
3802
|
-
candidates.add(resolved);
|
|
3803
|
-
}
|
|
3804
|
-
};
|
|
3805
|
-
const addRelativeCandidates = (relativePath) => {
|
|
3806
|
-
const normalized = relativePath.replace(/\\/g, "/").replace(/^\/+/, "");
|
|
3807
|
-
if (!normalized) return;
|
|
3808
|
-
addCandidate(path5.join(storageRoot, normalized));
|
|
3809
|
-
if (/^\d{4}-\d{2}-\d{2}\//.test(normalized)) {
|
|
3810
|
-
addCandidate(path5.join(storageRoot, "facts", normalized));
|
|
3811
|
-
}
|
|
3812
|
-
};
|
|
3813
|
-
if (path5.isAbsolute(resultPath)) {
|
|
3814
|
-
addCandidate(resultPath);
|
|
3815
|
-
} else {
|
|
3816
|
-
addRelativeCandidates(resultPath);
|
|
3817
|
-
}
|
|
3818
|
-
return [...candidates];
|
|
3819
|
-
}
|
|
3820
4409
|
var COMPACTION_SIGNAL_MAX_AGE_MS = 60 * 60 * 1e3;
|
|
3821
4410
|
var DEFAULT_QMD_STARTUP_COLLECTION_CHECK_TIMEOUT_MS = 1e4;
|
|
3822
4411
|
function normalizeIanaTimeZone(value) {
|
|
@@ -3927,7 +4516,7 @@ async function qmdStartupCollectionCheckWithTimeout(promise, controller, label)
|
|
|
3927
4516
|
return await Promise.race([checkedPromise, timeoutPromise]);
|
|
3928
4517
|
}
|
|
3929
4518
|
function defaultWorkspaceDir() {
|
|
3930
|
-
return
|
|
4519
|
+
return path6.join(os2.homedir(), ".openclaw", "workspace");
|
|
3931
4520
|
}
|
|
3932
4521
|
function sanitizeSessionKeyForFilename(sessionKey) {
|
|
3933
4522
|
const readable = sessionKey.replace(/[^a-zA-Z0-9._-]/g, "_");
|
|
@@ -4204,11 +4793,11 @@ function mergeGraphExpandedResults(primary, expanded) {
|
|
|
4204
4793
|
return Array.from(mergedByPath.values());
|
|
4205
4794
|
}
|
|
4206
4795
|
function graphPathRelativeToStorage(storageDir, candidatePath) {
|
|
4207
|
-
const absolutePath =
|
|
4208
|
-
const rel =
|
|
4796
|
+
const absolutePath = path6.isAbsolute(candidatePath) ? candidatePath : path6.resolve(storageDir, candidatePath);
|
|
4797
|
+
const rel = path6.relative(storageDir, absolutePath);
|
|
4209
4798
|
if (!rel || rel === ".") return null;
|
|
4210
4799
|
if (rel.startsWith("..")) return null;
|
|
4211
|
-
return rel.split(
|
|
4800
|
+
return rel.split(path6.sep).join("/");
|
|
4212
4801
|
}
|
|
4213
4802
|
function normalizeGraphActivationScore(score) {
|
|
4214
4803
|
const bounded = Number.isFinite(score) && score > 0 ? score : 0;
|
|
@@ -4353,7 +4942,7 @@ function buildMemoryPathById(allMemsForGraph, storageDir) {
|
|
|
4353
4942
|
for (const mem of allMemsForGraph ?? []) {
|
|
4354
4943
|
const id = mem.frontmatter.id;
|
|
4355
4944
|
if (!id) continue;
|
|
4356
|
-
pathById.set(id,
|
|
4945
|
+
pathById.set(id, path6.relative(storageDir, mem.path));
|
|
4357
4946
|
}
|
|
4358
4947
|
return pathById;
|
|
4359
4948
|
}
|
|
@@ -4361,7 +4950,7 @@ function appendMemoryToGraphContext(options) {
|
|
|
4361
4950
|
if (!Array.isArray(options.allMemsForGraph)) return;
|
|
4362
4951
|
const nowIso = (/* @__PURE__ */ new Date()).toISOString();
|
|
4363
4952
|
options.allMemsForGraph.push({
|
|
4364
|
-
path:
|
|
4953
|
+
path: path6.join(options.storageDir, options.memoryRelPath),
|
|
4365
4954
|
content: options.content,
|
|
4366
4955
|
frontmatter: {
|
|
4367
4956
|
id: options.memoryId,
|
|
@@ -4381,16 +4970,16 @@ function resolvePersistedMemoryRelativePath(options) {
|
|
|
4381
4970
|
const persisted = options.pathById.get(options.memoryId);
|
|
4382
4971
|
if (persisted) return persisted;
|
|
4383
4972
|
if (options.category === "correction") {
|
|
4384
|
-
return
|
|
4973
|
+
return path6.join("corrections", `${options.memoryId}.md`);
|
|
4385
4974
|
}
|
|
4386
4975
|
const subtree = categoryDirName(options.category);
|
|
4387
4976
|
const idParts = options.memoryId.split("-");
|
|
4388
4977
|
const maybeTimestamp = Number(idParts[1]);
|
|
4389
4978
|
if (Number.isFinite(maybeTimestamp) && maybeTimestamp > 0) {
|
|
4390
4979
|
const day = new Date(maybeTimestamp).toISOString().slice(0, 10);
|
|
4391
|
-
return
|
|
4980
|
+
return path6.join(subtree, day, `${options.memoryId}.md`);
|
|
4392
4981
|
}
|
|
4393
|
-
return
|
|
4982
|
+
return path6.join(subtree, `${options.memoryId}.md`);
|
|
4394
4983
|
}
|
|
4395
4984
|
var Orchestrator = class _Orchestrator {
|
|
4396
4985
|
storage;
|
|
@@ -4552,6 +5141,9 @@ var Orchestrator = class _Orchestrator {
|
|
|
4552
5141
|
*/
|
|
4553
5142
|
conversationIndexCoordinator;
|
|
4554
5143
|
recallRerankCoordinator;
|
|
5144
|
+
recallSectionCoordinator;
|
|
5145
|
+
qmdResultResolver;
|
|
5146
|
+
contradictionLinkingCoordinator;
|
|
4555
5147
|
heartbeatObserverChains = /* @__PURE__ */ new Map();
|
|
4556
5148
|
recentExtractionFingerprints = /* @__PURE__ */ new Map();
|
|
4557
5149
|
consolidationObservers = /* @__PURE__ */ new Set();
|
|
@@ -4844,7 +5436,7 @@ var Orchestrator = class _Orchestrator {
|
|
|
4844
5436
|
const defaultNs = normalizeNamespaceIdentity(this.config.defaultNamespace);
|
|
4845
5437
|
if (ns !== defaultNs && !isSafeRouteNamespace(ns)) return;
|
|
4846
5438
|
if (!this.storageDirMatchesNamespaceHint(ns, storageDir)) return;
|
|
4847
|
-
const resolvedStorageDir =
|
|
5439
|
+
const resolvedStorageDir = path6.resolve(storageDir);
|
|
4848
5440
|
let hints = this.namespaceStorageDirHints.get(resolvedStorageDir);
|
|
4849
5441
|
if (!hints) {
|
|
4850
5442
|
hints = /* @__PURE__ */ new Set();
|
|
@@ -4855,21 +5447,21 @@ var Orchestrator = class _Orchestrator {
|
|
|
4855
5447
|
storageDirMatchesNamespaceHint(namespace, storageDir) {
|
|
4856
5448
|
const ns = normalizeNamespaceIdentity(namespace);
|
|
4857
5449
|
if (!ns) return false;
|
|
4858
|
-
const resolvedStorageDir =
|
|
4859
|
-
const resolvedMemoryDir =
|
|
5450
|
+
const resolvedStorageDir = path6.resolve(storageDir);
|
|
5451
|
+
const resolvedMemoryDir = path6.resolve(this.config.memoryDir);
|
|
4860
5452
|
const defaultNs = normalizeNamespaceIdentity(this.config.defaultNamespace);
|
|
4861
5453
|
if (resolvedStorageDir === resolvedMemoryDir) return ns === defaultNs;
|
|
4862
|
-
const resolvedNamespacesDir =
|
|
5454
|
+
const resolvedNamespacesDir = path6.join(resolvedMemoryDir, "namespaces");
|
|
4863
5455
|
if (!isPathInsideStorageRoot(resolvedNamespacesDir, resolvedStorageDir)) return false;
|
|
4864
|
-
const rawRoot =
|
|
4865
|
-
const tokenRoot =
|
|
5456
|
+
const rawRoot = path6.resolve(resolvedNamespacesDir, ns);
|
|
5457
|
+
const tokenRoot = path6.resolve(resolvedNamespacesDir, namespaceIdentityToken(ns));
|
|
4866
5458
|
return resolvedStorageDir === rawRoot || resolvedStorageDir === tokenRoot;
|
|
4867
5459
|
}
|
|
4868
5460
|
namespaceStorageDirHintOwnershipRank(record, resolvedStorageDir, configured) {
|
|
4869
|
-
if (resolvedStorageDir ===
|
|
5461
|
+
if (resolvedStorageDir === path6.resolve(this.config.memoryDir)) {
|
|
4870
5462
|
return record.namespace === normalizeNamespaceIdentity(this.config.defaultNamespace) ? 0 : 3;
|
|
4871
5463
|
}
|
|
4872
|
-
const leaf =
|
|
5464
|
+
const leaf = path6.basename(resolvedStorageDir);
|
|
4873
5465
|
const tokenOwnsRoot = namespaceIdentityToken(record.namespace) === leaf;
|
|
4874
5466
|
if (tokenOwnsRoot && configured.has(record.namespace)) return 0;
|
|
4875
5467
|
if (record.namespace === leaf) return 1;
|
|
@@ -4897,7 +5489,7 @@ var Orchestrator = class _Orchestrator {
|
|
|
4897
5489
|
loadNamespaceStorageDirHintsFromCatalog() {
|
|
4898
5490
|
if (this.namespaceStorageDirHintsLoaded || !this.namespaceCatalog.enabled) return;
|
|
4899
5491
|
this.namespaceStorageDirHintsLoaded = true;
|
|
4900
|
-
const catalogPath =
|
|
5492
|
+
const catalogPath = path6.join(this.config.memoryDir, "state", "namespaces.jsonl");
|
|
4901
5493
|
if (!existsSync(catalogPath)) return;
|
|
4902
5494
|
let body;
|
|
4903
5495
|
try {
|
|
@@ -4934,7 +5526,7 @@ var Orchestrator = class _Orchestrator {
|
|
|
4934
5526
|
if (!this.storageDirMatchesNamespaceHint(record.namespace, record.storageDir)) {
|
|
4935
5527
|
continue;
|
|
4936
5528
|
}
|
|
4937
|
-
const resolvedStorageDir =
|
|
5529
|
+
const resolvedStorageDir = path6.resolve(record.storageDir);
|
|
4938
5530
|
const current = preferredByStorageDir.get(resolvedStorageDir);
|
|
4939
5531
|
preferredByStorageDir.set(
|
|
4940
5532
|
resolvedStorageDir,
|
|
@@ -5198,7 +5790,7 @@ var Orchestrator = class _Orchestrator {
|
|
|
5198
5790
|
this.config = config;
|
|
5199
5791
|
this.profiler = new ProfilingCollector({
|
|
5200
5792
|
enabled: resolvePipelineProcessingCapabilities(this.config).profiling,
|
|
5201
|
-
storageDir: config.profilingStorageDir ||
|
|
5793
|
+
storageDir: config.profilingStorageDir || path6.join(config.memoryDir, "profiling"),
|
|
5202
5794
|
maxTraces: config.profilingMaxTraces
|
|
5203
5795
|
});
|
|
5204
5796
|
this.namespaceCatalog = new NamespaceCatalog(config);
|
|
@@ -5268,7 +5860,7 @@ var Orchestrator = class _Orchestrator {
|
|
|
5268
5860
|
this.compounding = resolveConsolidationCapabilities(config).compounding ? new CompoundingEngine(config, this.storage) : void 0;
|
|
5269
5861
|
this.buffer = new SmartBuffer(config, this.storage);
|
|
5270
5862
|
this.transcript = new TranscriptManager(config);
|
|
5271
|
-
this.conversationIndexDir =
|
|
5863
|
+
this.conversationIndexDir = path6.join(
|
|
5272
5864
|
config.memoryDir,
|
|
5273
5865
|
"conversation-index",
|
|
5274
5866
|
"chunks"
|
|
@@ -5284,6 +5876,19 @@ var Orchestrator = class _Orchestrator {
|
|
|
5284
5876
|
getStorage: (namespace) => this.getStorage(namespace),
|
|
5285
5877
|
readQmdResultMemory: (resultPath, fallbackStorage, recallNamespaces) => this.readQmdResultMemory(resultPath, fallbackStorage, recallNamespaces)
|
|
5286
5878
|
});
|
|
5879
|
+
this.recallSectionCoordinator = new RecallSectionCoordinator({
|
|
5880
|
+
getConfig: () => this.config,
|
|
5881
|
+
resolveSectionEnabled: (id, def) => this.isRecallSectionEnabled(id, def)
|
|
5882
|
+
});
|
|
5883
|
+
this.contradictionLinkingCoordinator = new ContradictionLinkingCoordinator({
|
|
5884
|
+
getConfig: () => this.config,
|
|
5885
|
+
isSearchAvailable: () => this.isSearchAvailableForNamespaceRouting(),
|
|
5886
|
+
searchAcrossNamespaces: (options) => this.searchAcrossNamespaces(options),
|
|
5887
|
+
extractMemoryIdsFromResults: (results) => this.extractMemoryIdsFromResults(results),
|
|
5888
|
+
namespaceFromPath: (p) => this.namespaceFromPath(p),
|
|
5889
|
+
storageForNamespace: (namespace) => this.storageRouter.storageFor(namespace),
|
|
5890
|
+
getExtraction: () => this.extraction
|
|
5891
|
+
});
|
|
5287
5892
|
this.modelRegistry = new ModelRegistry(config.memoryDir);
|
|
5288
5893
|
this.relevance = new RelevanceStore(config.memoryDir);
|
|
5289
5894
|
this.negatives = new NegativeExampleStore(config.memoryDir);
|
|
@@ -5310,6 +5915,13 @@ var Orchestrator = class _Orchestrator {
|
|
|
5310
5915
|
getStorage: (namespace) => this.getStorage(namespace),
|
|
5311
5916
|
fastChatCompletion: (messages, options) => this.fastChatCompletion(messages, options)
|
|
5312
5917
|
});
|
|
5918
|
+
this.qmdResultResolver = new QmdResultResolver({
|
|
5919
|
+
getConfig: () => this.config,
|
|
5920
|
+
storageFor: (namespace) => this.storageRouter.storageFor(namespace),
|
|
5921
|
+
storageDirNamespace: (storageDir) => this.storageDirNamespace(storageDir),
|
|
5922
|
+
qmdCollectionNamespaceFromPrefix: (prefix) => this.qmdCollectionNamespaceFromPrefix(prefix),
|
|
5923
|
+
namespaceFromPath: (p) => this.namespaceFromPath(p)
|
|
5924
|
+
});
|
|
5313
5925
|
this.sessionObserver = new SessionObserverState({
|
|
5314
5926
|
memoryDir: config.memoryDir,
|
|
5315
5927
|
debounceMs: config.sessionObserverDebounceMs ?? 12e4,
|
|
@@ -5374,7 +5986,7 @@ var Orchestrator = class _Orchestrator {
|
|
|
5374
5986
|
saveContentHashIndexes: () => this.saveContentHashIndexes()
|
|
5375
5987
|
});
|
|
5376
5988
|
this.threading = new ThreadingManager(
|
|
5377
|
-
|
|
5989
|
+
path6.join(config.memoryDir, "threads"),
|
|
5378
5990
|
config.threadingGapMinutes
|
|
5379
5991
|
);
|
|
5380
5992
|
const lifecycleCaps = resolveMemoryLifecycleCapabilities(config);
|
|
@@ -5697,7 +6309,7 @@ var Orchestrator = class _Orchestrator {
|
|
|
5697
6309
|
const files = await readdir2(wsDir).catch(() => []);
|
|
5698
6310
|
for (const f of files) {
|
|
5699
6311
|
if (!f.startsWith(".compaction-reset-signal-")) continue;
|
|
5700
|
-
const fp =
|
|
6312
|
+
const fp = path6.join(wsDir, f);
|
|
5701
6313
|
const s = await stat(fp).catch(() => null);
|
|
5702
6314
|
if (s && Date.now() - s.mtimeMs >= COMPACTION_SIGNAL_MAX_AGE_MS) {
|
|
5703
6315
|
await unlink(fp).catch(() => {
|
|
@@ -5892,7 +6504,7 @@ var Orchestrator = class _Orchestrator {
|
|
|
5892
6504
|
if (signal.aborted) return;
|
|
5893
6505
|
if (lifecycleCaps.lifecyclePolicy && resolveQmdCapabilities(this.config).qmdTierMigration) {
|
|
5894
6506
|
try {
|
|
5895
|
-
const { runFirstStartMigration } = await import("./first-start-migration-
|
|
6507
|
+
const { runFirstStartMigration } = await import("./first-start-migration-4I3VDSYS.js");
|
|
5896
6508
|
const result = await runFirstStartMigration({
|
|
5897
6509
|
storage: this.storage,
|
|
5898
6510
|
config: this.config,
|
|
@@ -5915,7 +6527,7 @@ var Orchestrator = class _Orchestrator {
|
|
|
5915
6527
|
if (signal.aborted) return;
|
|
5916
6528
|
if (!this.wearablesAutoSyncHandle && this.config.wearables.enabled && this.config.wearables.autoSyncEnabled && Object.values(this.config.wearables.sources).some((source) => source.enabled)) {
|
|
5917
6529
|
try {
|
|
5918
|
-
const { startWearablesAutoSync } = await import("./auto-sync-
|
|
6530
|
+
const { startWearablesAutoSync } = await import("./auto-sync-XHSKKQAH.js");
|
|
5919
6531
|
if (signal.aborted) return;
|
|
5920
6532
|
this.wearablesAutoSyncHandle = startWearablesAutoSync(
|
|
5921
6533
|
{
|
|
@@ -6206,15 +6818,15 @@ ${doc.content}` : doc.content,
|
|
|
6206
6818
|
this.lastFileHygieneRunAtMs = now;
|
|
6207
6819
|
if (hygiene.rotateEnabled) {
|
|
6208
6820
|
for (const rel of hygiene.rotatePaths) {
|
|
6209
|
-
const abs =
|
|
6821
|
+
const abs = path6.isAbsolute(rel) ? rel : path6.join(this.config.workspaceDir, rel);
|
|
6210
6822
|
try {
|
|
6211
6823
|
const raw = await readFile2(abs, "utf-8");
|
|
6212
6824
|
if (raw.length > hygiene.rotateMaxBytes) {
|
|
6213
|
-
const archiveDir =
|
|
6825
|
+
const archiveDir = path6.join(
|
|
6214
6826
|
this.config.workspaceDir,
|
|
6215
6827
|
hygiene.archiveDir
|
|
6216
6828
|
);
|
|
6217
|
-
const base =
|
|
6829
|
+
const base = path6.basename(abs);
|
|
6218
6830
|
const prefix = base.toUpperCase().replace(/\.MD$/i, "").replace(/[^A-Z0-9]+/g, "-") || "FILE";
|
|
6219
6831
|
const { newContent } = await rotateMarkdownFileToArchive({
|
|
6220
6832
|
filePath: abs,
|
|
@@ -6239,8 +6851,8 @@ ${doc.content}` : doc.content,
|
|
|
6239
6851
|
log.warn(w.message);
|
|
6240
6852
|
}
|
|
6241
6853
|
if (hygiene.warningsLogEnabled && warnings.length > 0) {
|
|
6242
|
-
const fp =
|
|
6243
|
-
await mkdir3(
|
|
6854
|
+
const fp = path6.join(this.config.memoryDir, hygiene.warningsLogPath);
|
|
6855
|
+
await mkdir3(path6.dirname(fp), { recursive: true });
|
|
6244
6856
|
const stamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
6245
6857
|
const block = `
|
|
6246
6858
|
|
|
@@ -6379,7 +6991,7 @@ ${doc.content}` : doc.content,
|
|
|
6379
6991
|
for (const categoryDir of RECALL_FALLBACK_DIRS) {
|
|
6380
6992
|
if (memoryRootReal === null) break;
|
|
6381
6993
|
for (const date of datesToScan) {
|
|
6382
|
-
const dateDir =
|
|
6994
|
+
const dateDir = path6.join(storage.dir, categoryDir, date);
|
|
6383
6995
|
try {
|
|
6384
6996
|
const dirStat = await lstat(dateDir);
|
|
6385
6997
|
if (dirStat.isSymbolicLink() || !dirStat.isDirectory()) continue;
|
|
@@ -6388,7 +7000,7 @@ ${doc.content}` : doc.content,
|
|
|
6388
7000
|
for (const entry of entries) {
|
|
6389
7001
|
if (entry.isSymbolicLink()) continue;
|
|
6390
7002
|
if (!entry.name.endsWith(".md")) continue;
|
|
6391
|
-
const fullPath =
|
|
7003
|
+
const fullPath = path6.join(dateDir, entry.name);
|
|
6392
7004
|
try {
|
|
6393
7005
|
assertPathInsideRoot(memoryRootReal, await realpath(fullPath), fullPath);
|
|
6394
7006
|
const raw = await readFile2(fullPath, "utf-8");
|
|
@@ -6410,7 +7022,7 @@ ${doc.content}` : doc.content,
|
|
|
6410
7022
|
facts.push({
|
|
6411
7023
|
path: fullPath,
|
|
6412
7024
|
frontmatter: {
|
|
6413
|
-
id: fm.id ||
|
|
7025
|
+
id: fm.id || path6.basename(entry.name, ".md"),
|
|
6414
7026
|
category: fm.category || "fact",
|
|
6415
7027
|
created,
|
|
6416
7028
|
updated: fm.updated || created,
|
|
@@ -6433,13 +7045,13 @@ ${doc.content}` : doc.content,
|
|
|
6433
7045
|
return a.frontmatter.created < b.frontmatter.created ? -1 : 1;
|
|
6434
7046
|
});
|
|
6435
7047
|
const hourlySummaries = [];
|
|
6436
|
-
const hourlyBaseDir =
|
|
7048
|
+
const hourlyBaseDir = path6.join(storage.dir, "summaries", "hourly");
|
|
6437
7049
|
try {
|
|
6438
7050
|
const sessionKeys = await readdir2(hourlyBaseDir, { withFileTypes: true });
|
|
6439
7051
|
for (const sk of sessionKeys) {
|
|
6440
7052
|
if (!sk.isDirectory()) continue;
|
|
6441
7053
|
for (const date of datesToScan) {
|
|
6442
|
-
const summaryFile =
|
|
7054
|
+
const summaryFile = path6.join(hourlyBaseDir, sk.name, `${date}.md`);
|
|
6443
7055
|
try {
|
|
6444
7056
|
const raw = await readFile2(summaryFile, "utf-8");
|
|
6445
7057
|
const filtered = filterHourlySummaryMarkdownForLocalDay(
|
|
@@ -6543,7 +7155,7 @@ ${doc.content}` : doc.content,
|
|
|
6543
7155
|
}
|
|
6544
7156
|
async getLastGraphRecallSnapshot(namespace) {
|
|
6545
7157
|
const storage = await this.getStorage(namespace);
|
|
6546
|
-
const snapshotPath =
|
|
7158
|
+
const snapshotPath = path6.join(
|
|
6547
7159
|
storage.dir,
|
|
6548
7160
|
"state",
|
|
6549
7161
|
"last_graph_recall.json"
|
|
@@ -6582,7 +7194,7 @@ ${doc.content}` : doc.content,
|
|
|
6582
7194
|
}
|
|
6583
7195
|
async getLastIntentSnapshot(namespace) {
|
|
6584
7196
|
const storage = await this.getStorage(namespace);
|
|
6585
|
-
const snapshotPath =
|
|
7197
|
+
const snapshotPath = path6.join(storage.dir, "state", "last_intent.json");
|
|
6586
7198
|
try {
|
|
6587
7199
|
const raw = await readFile2(snapshotPath, "utf-8");
|
|
6588
7200
|
const parsed = JSON.parse(raw);
|
|
@@ -6615,7 +7227,7 @@ ${doc.content}` : doc.content,
|
|
|
6615
7227
|
}
|
|
6616
7228
|
async getLastQmdRecallSnapshot(namespace) {
|
|
6617
7229
|
const storage = await this.getStorage(namespace);
|
|
6618
|
-
const snapshotPath =
|
|
7230
|
+
const snapshotPath = path6.join(
|
|
6619
7231
|
storage.dir,
|
|
6620
7232
|
"state",
|
|
6621
7233
|
"last_qmd_recall.json"
|
|
@@ -7499,7 +8111,7 @@ ${doc.content}` : doc.content,
|
|
|
7499
8111
|
resolvedPath = resolvedCold.result.path;
|
|
7500
8112
|
resolvedResult = resolvedCold.result;
|
|
7501
8113
|
}
|
|
7502
|
-
if (!
|
|
8114
|
+
if (!path6.isAbsolute(resolvedPath)) {
|
|
7503
8115
|
resolvedAmbiguousSeeds.set(result.path, null);
|
|
7504
8116
|
return null;
|
|
7505
8117
|
}
|
|
@@ -7524,7 +8136,7 @@ ${doc.content}` : doc.content,
|
|
|
7524
8136
|
}
|
|
7525
8137
|
continue;
|
|
7526
8138
|
}
|
|
7527
|
-
if (
|
|
8139
|
+
if (path6.isAbsolute(result.path)) {
|
|
7528
8140
|
const resolved = await resolveAmbiguousSeedOwner(result, null);
|
|
7529
8141
|
if (resolved) {
|
|
7530
8142
|
addResultForNamespace(resolved.namespace, resolved.result);
|
|
@@ -7567,7 +8179,7 @@ ${doc.content}` : doc.content,
|
|
|
7567
8179
|
0
|
|
7568
8180
|
);
|
|
7569
8181
|
seedPaths.push(
|
|
7570
|
-
...seedRelativePaths.map((rel) =>
|
|
8182
|
+
...seedRelativePaths.map((rel) => path6.join(storage.dir, rel))
|
|
7571
8183
|
);
|
|
7572
8184
|
const seedSet = new Set(seedRelativePaths);
|
|
7573
8185
|
const expanded = await this.graphIndexFor(storage).spreadingActivation(
|
|
@@ -7583,7 +8195,7 @@ ${doc.content}` : doc.content,
|
|
|
7583
8195
|
for (const candidate of expanded.slice(0, perNamespaceExpandedCap)) {
|
|
7584
8196
|
if (deadlineExpired()) break;
|
|
7585
8197
|
if (seedSet.has(candidate.path)) continue;
|
|
7586
|
-
const memoryPath =
|
|
8198
|
+
const memoryPath = path6.resolve(storage.dir, candidate.path);
|
|
7587
8199
|
const memory = await storage.readMemoryByPath(memoryPath);
|
|
7588
8200
|
if (deadlineExpired()) break;
|
|
7589
8201
|
if (!memory) continue;
|
|
@@ -7608,7 +8220,7 @@ ${doc.content}` : doc.content,
|
|
|
7608
8220
|
path: memory.path,
|
|
7609
8221
|
score,
|
|
7610
8222
|
namespace,
|
|
7611
|
-
seed:
|
|
8223
|
+
seed: path6.resolve(storage.dir, candidate.seed),
|
|
7612
8224
|
hopDepth: candidate.hopDepth,
|
|
7613
8225
|
decayedWeight: candidate.decayedWeight,
|
|
7614
8226
|
graphType: candidate.graphType,
|
|
@@ -7629,12 +8241,12 @@ ${doc.content}` : doc.content,
|
|
|
7629
8241
|
}
|
|
7630
8242
|
async recordLastGraphRecallSnapshot(options) {
|
|
7631
8243
|
try {
|
|
7632
|
-
const snapshotPath =
|
|
8244
|
+
const snapshotPath = path6.join(
|
|
7633
8245
|
options.storage.dir,
|
|
7634
8246
|
"state",
|
|
7635
8247
|
"last_graph_recall.json"
|
|
7636
8248
|
);
|
|
7637
|
-
await mkdir3(
|
|
8249
|
+
await mkdir3(path6.dirname(snapshotPath), { recursive: true });
|
|
7638
8250
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
7639
8251
|
const totalSeedCount = options.seedPaths.length;
|
|
7640
8252
|
const totalExpandedCount = options.expandedPaths.length;
|
|
@@ -7668,12 +8280,12 @@ ${doc.content}` : doc.content,
|
|
|
7668
8280
|
}
|
|
7669
8281
|
async recordLastIntentSnapshot(options) {
|
|
7670
8282
|
try {
|
|
7671
|
-
const snapshotPath =
|
|
8283
|
+
const snapshotPath = path6.join(
|
|
7672
8284
|
options.storage.dir,
|
|
7673
8285
|
"state",
|
|
7674
8286
|
"last_intent.json"
|
|
7675
8287
|
);
|
|
7676
|
-
await mkdir3(
|
|
8288
|
+
await mkdir3(path6.dirname(snapshotPath), { recursive: true });
|
|
7677
8289
|
await writeFile3(
|
|
7678
8290
|
snapshotPath,
|
|
7679
8291
|
JSON.stringify(options.snapshot, null, 2),
|
|
@@ -7685,12 +8297,12 @@ ${doc.content}` : doc.content,
|
|
|
7685
8297
|
}
|
|
7686
8298
|
async recordLastQmdRecallSnapshot(options) {
|
|
7687
8299
|
try {
|
|
7688
|
-
const snapshotPath =
|
|
8300
|
+
const snapshotPath = path6.join(
|
|
7689
8301
|
options.storage.dir,
|
|
7690
8302
|
"state",
|
|
7691
8303
|
"last_qmd_recall.json"
|
|
7692
8304
|
);
|
|
7693
|
-
await mkdir3(
|
|
8305
|
+
await mkdir3(path6.dirname(snapshotPath), { recursive: true });
|
|
7694
8306
|
await writeFile3(
|
|
7695
8307
|
snapshotPath,
|
|
7696
8308
|
JSON.stringify(options.snapshot, null, 2),
|
|
@@ -7705,8 +8317,8 @@ ${doc.content}` : doc.content,
|
|
|
7705
8317
|
const stateDir = await this.resolveStateDirForNamespace(
|
|
7706
8318
|
options.namespace
|
|
7707
8319
|
);
|
|
7708
|
-
const snapshotPath =
|
|
7709
|
-
await mkdir3(
|
|
8320
|
+
const snapshotPath = path6.join(stateDir, "last_intent.json");
|
|
8321
|
+
await mkdir3(path6.dirname(snapshotPath), { recursive: true });
|
|
7710
8322
|
await writeFile3(
|
|
7711
8323
|
snapshotPath,
|
|
7712
8324
|
JSON.stringify(options.snapshot, null, 2),
|
|
@@ -7718,12 +8330,12 @@ ${doc.content}` : doc.content,
|
|
|
7718
8330
|
}
|
|
7719
8331
|
async resolveStateDirForNamespace(namespace) {
|
|
7720
8332
|
if (!resolveNamespaceCapabilities(this.config).namespaces) {
|
|
7721
|
-
return
|
|
8333
|
+
return path6.join(this.config.memoryDir, "state");
|
|
7722
8334
|
}
|
|
7723
8335
|
if (namespace !== this.config.defaultNamespace) {
|
|
7724
|
-
return
|
|
8336
|
+
return path6.join(this.config.memoryDir, "namespaces", namespace, "state");
|
|
7725
8337
|
}
|
|
7726
|
-
const candidate =
|
|
8338
|
+
const candidate = path6.join(
|
|
7727
8339
|
this.config.memoryDir,
|
|
7728
8340
|
"namespaces",
|
|
7729
8341
|
this.config.defaultNamespace
|
|
@@ -7731,11 +8343,11 @@ ${doc.content}` : doc.content,
|
|
|
7731
8343
|
try {
|
|
7732
8344
|
const candidateStat = await stat(candidate);
|
|
7733
8345
|
if (candidateStat.isDirectory()) {
|
|
7734
|
-
return
|
|
8346
|
+
return path6.join(candidate, "state");
|
|
7735
8347
|
}
|
|
7736
8348
|
} catch {
|
|
7737
8349
|
}
|
|
7738
|
-
return
|
|
8350
|
+
return path6.join(this.config.memoryDir, "state");
|
|
7739
8351
|
}
|
|
7740
8352
|
buildGraphRecallRankedResults(results, sourceLabelResolver, limit = 64) {
|
|
7741
8353
|
return results.slice(0, limit).map((result) => ({
|
|
@@ -7745,173 +8357,51 @@ ${doc.content}` : doc.content,
|
|
|
7745
8357
|
sourceLabels: sourceLabelResolver(result.path)
|
|
7746
8358
|
}));
|
|
7747
8359
|
}
|
|
8360
|
+
// Issue #1526 (seam 13): recall section budgeting/assembly moved to
|
|
8361
|
+
// RecallSectionCoordinator. Thin delegation keeps the orchestrator's
|
|
8362
|
+
// recallInternal call sites stable.
|
|
7748
8363
|
getRecallSectionEntry(sectionId) {
|
|
7749
|
-
|
|
7750
|
-
return pipeline.find((entry) => entry.id === sectionId);
|
|
8364
|
+
return this.recallSectionCoordinator.getRecallSectionEntry(sectionId);
|
|
7751
8365
|
}
|
|
7752
8366
|
isRecallSectionEnabled(sectionId, defaultEnabled = true) {
|
|
7753
|
-
|
|
7754
|
-
|
|
7755
|
-
|
|
8367
|
+
return this.recallSectionCoordinator.isRecallSectionEnabled(
|
|
8368
|
+
sectionId,
|
|
8369
|
+
defaultEnabled
|
|
8370
|
+
);
|
|
7756
8371
|
}
|
|
7757
8372
|
isSpecializedRecallSectionEnabled(sectionId, topLevelEnabled) {
|
|
7758
|
-
|
|
7759
|
-
|
|
7760
|
-
|
|
7761
|
-
|
|
7762
|
-
getRecallSectionMaxChars(sectionId) {
|
|
7763
|
-
const entry = this.getRecallSectionEntry(sectionId);
|
|
7764
|
-
if (!entry) return void 0;
|
|
7765
|
-
if (entry.maxChars === null) return null;
|
|
7766
|
-
if (typeof entry.maxChars !== "number") return void 0;
|
|
7767
|
-
return Math.max(0, Math.floor(entry.maxChars));
|
|
7768
|
-
}
|
|
7769
|
-
getRecallSectionNumber(sectionId, key) {
|
|
7770
|
-
const entry = this.getRecallSectionEntry(sectionId);
|
|
7771
|
-
if (!entry) return void 0;
|
|
7772
|
-
const value = entry[key];
|
|
7773
|
-
if (typeof value !== "number" || !Number.isFinite(value)) return void 0;
|
|
7774
|
-
return Math.max(0, Math.floor(value));
|
|
7775
|
-
}
|
|
7776
|
-
appendRecallSection(sectionBuckets, sectionId, content) {
|
|
7777
|
-
if (!this.isRecallSectionEnabled(sectionId)) return false;
|
|
7778
|
-
const trimmed = content.trim();
|
|
7779
|
-
if (trimmed.length === 0) return false;
|
|
7780
|
-
const maxChars = this.getRecallSectionMaxChars(sectionId);
|
|
7781
|
-
let finalContent = trimmed;
|
|
7782
|
-
if (maxChars === 0) return false;
|
|
7783
|
-
if (typeof maxChars === "number" && finalContent.length > maxChars) {
|
|
7784
|
-
finalContent = `${finalContent.slice(0, maxChars)}
|
|
7785
|
-
|
|
7786
|
-
...(trimmed)
|
|
7787
|
-
`;
|
|
7788
|
-
}
|
|
7789
|
-
const existing = sectionBuckets.get(sectionId) ?? [];
|
|
7790
|
-
existing.push(finalContent);
|
|
7791
|
-
sectionBuckets.set(sectionId, existing);
|
|
7792
|
-
return true;
|
|
8373
|
+
return this.recallSectionCoordinator.isSpecializedRecallSectionEnabled(
|
|
8374
|
+
sectionId,
|
|
8375
|
+
topLevelEnabled
|
|
8376
|
+
);
|
|
7793
8377
|
}
|
|
7794
|
-
|
|
7795
|
-
|
|
7796
|
-
if (content.length <= maxChars) return content;
|
|
7797
|
-
const suffix = "\n\n...(memory context trimmed)";
|
|
7798
|
-
if (maxChars <= suffix.length) {
|
|
7799
|
-
return content.slice(0, maxChars);
|
|
7800
|
-
}
|
|
7801
|
-
return `${content.slice(0, maxChars - suffix.length)}${suffix}`;
|
|
8378
|
+
getRecallSectionMaxChars(sectionId) {
|
|
8379
|
+
return this.recallSectionCoordinator.getRecallSectionMaxChars(sectionId);
|
|
7802
8380
|
}
|
|
7803
|
-
|
|
7804
|
-
|
|
7805
|
-
if ((sectionBuckets.get("memories")?.length ?? 0) > 0) {
|
|
7806
|
-
protectedIds.add("memories");
|
|
7807
|
-
}
|
|
7808
|
-
return protectedIds;
|
|
8381
|
+
getRecallSectionNumber(sectionId, key) {
|
|
8382
|
+
return this.recallSectionCoordinator.getRecallSectionNumber(sectionId, key);
|
|
7809
8383
|
}
|
|
7810
|
-
|
|
7811
|
-
|
|
7812
|
-
|
|
7813
|
-
|
|
8384
|
+
appendRecallSection(sectionBuckets, sectionId, content) {
|
|
8385
|
+
return this.recallSectionCoordinator.appendRecallSection(
|
|
8386
|
+
sectionBuckets,
|
|
8387
|
+
sectionId,
|
|
8388
|
+
content
|
|
8389
|
+
);
|
|
7814
8390
|
}
|
|
7815
|
-
|
|
7816
|
-
|
|
7817
|
-
|
|
7818
|
-
|
|
7819
|
-
|
|
7820
|
-
const entry = entries[i];
|
|
7821
|
-
if (!entry || !protectedIds.has(entry.id)) continue;
|
|
7822
|
-
if (simulatedIncluded > 0) {
|
|
7823
|
-
reserved += separatorLength;
|
|
7824
|
-
}
|
|
7825
|
-
reserved += this.protectedRecallReservationChars(entry.content);
|
|
7826
|
-
simulatedIncluded += 1;
|
|
7827
|
-
}
|
|
7828
|
-
return reserved;
|
|
8391
|
+
truncateRecallSectionToBudget(content, maxChars) {
|
|
8392
|
+
return this.recallSectionCoordinator.truncateRecallSectionToBudget(
|
|
8393
|
+
content,
|
|
8394
|
+
maxChars
|
|
8395
|
+
);
|
|
7829
8396
|
}
|
|
7830
8397
|
getRecallBudgetChars(override) {
|
|
7831
|
-
|
|
7832
|
-
return Math.floor(override);
|
|
7833
|
-
}
|
|
7834
|
-
const configuredBudget = this.config.recallBudgetChars;
|
|
7835
|
-
if (typeof configuredBudget === "number" && Number.isFinite(configuredBudget) && configuredBudget >= 0) {
|
|
7836
|
-
return Math.floor(configuredBudget);
|
|
7837
|
-
}
|
|
7838
|
-
const tokenBudget = this.config.maxMemoryTokens;
|
|
7839
|
-
if (typeof tokenBudget === "number" && Number.isFinite(tokenBudget) && tokenBudget >= 0) {
|
|
7840
|
-
return Math.floor(tokenBudget * 4);
|
|
7841
|
-
}
|
|
7842
|
-
return 0;
|
|
8398
|
+
return this.recallSectionCoordinator.getRecallBudgetChars(override);
|
|
7843
8399
|
}
|
|
7844
8400
|
assembleRecallSections(sectionBuckets, budgetOverride) {
|
|
7845
|
-
|
|
7846
|
-
|
|
7847
|
-
|
|
7848
|
-
|
|
7849
|
-
for (const id of orderedIds) {
|
|
7850
|
-
const chunks = sectionBuckets.get(id);
|
|
7851
|
-
if (!chunks || chunks.length === 0) continue;
|
|
7852
|
-
orderedEntries.push({ id, content: chunks.join("\n\n") });
|
|
7853
|
-
seen.add(id);
|
|
7854
|
-
}
|
|
7855
|
-
for (const [id, chunks] of sectionBuckets.entries()) {
|
|
7856
|
-
if (seen.has(id)) continue;
|
|
7857
|
-
if (chunks.length === 0) continue;
|
|
7858
|
-
orderedEntries.push({ id, content: chunks.join("\n\n") });
|
|
7859
|
-
}
|
|
7860
|
-
const budget = this.getRecallBudgetChars(budgetOverride);
|
|
7861
|
-
if (budget === 0) {
|
|
7862
|
-
return {
|
|
7863
|
-
sections: [],
|
|
7864
|
-
includedIds: [],
|
|
7865
|
-
omittedIds: orderedEntries.map((entry) => entry.id),
|
|
7866
|
-
truncated: orderedEntries.length > 0,
|
|
7867
|
-
finalChars: 0
|
|
7868
|
-
};
|
|
7869
|
-
}
|
|
7870
|
-
const separator = "\n\n---\n\n";
|
|
7871
|
-
const protectedIds = this.protectedRecallSectionIds(sectionBuckets);
|
|
7872
|
-
const sections = [];
|
|
7873
|
-
const includedIds = [];
|
|
7874
|
-
const omittedIds = [];
|
|
7875
|
-
let usedChars = 0;
|
|
7876
|
-
let truncated = false;
|
|
7877
|
-
for (let index = 0; index < orderedEntries.length; index += 1) {
|
|
7878
|
-
const entry = orderedEntries[index];
|
|
7879
|
-
const separatorChars = sections.length > 0 ? separator.length : 0;
|
|
7880
|
-
const reserve = protectedIds.has(entry.id) ? 0 : this.estimateReservedRecallBudget(
|
|
7881
|
-
orderedEntries,
|
|
7882
|
-
index + 1,
|
|
7883
|
-
protectedIds,
|
|
7884
|
-
sections.length + 1
|
|
7885
|
-
);
|
|
7886
|
-
const availableForEntry = budget - usedChars - separatorChars - reserve;
|
|
7887
|
-
if (availableForEntry <= 0) {
|
|
7888
|
-
omittedIds.push(entry.id);
|
|
7889
|
-
truncated = true;
|
|
7890
|
-
continue;
|
|
7891
|
-
}
|
|
7892
|
-
const finalContent = this.truncateRecallSectionToBudget(
|
|
7893
|
-
entry.content,
|
|
7894
|
-
availableForEntry
|
|
7895
|
-
);
|
|
7896
|
-
if (!finalContent) {
|
|
7897
|
-
omittedIds.push(entry.id);
|
|
7898
|
-
truncated = true;
|
|
7899
|
-
continue;
|
|
7900
|
-
}
|
|
7901
|
-
if (finalContent.length < entry.content.length) {
|
|
7902
|
-
truncated = true;
|
|
7903
|
-
}
|
|
7904
|
-
sections.push(finalContent);
|
|
7905
|
-
includedIds.push(entry.id);
|
|
7906
|
-
usedChars += separatorChars + finalContent.length;
|
|
7907
|
-
}
|
|
7908
|
-
return {
|
|
7909
|
-
sections,
|
|
7910
|
-
includedIds,
|
|
7911
|
-
omittedIds,
|
|
7912
|
-
truncated,
|
|
7913
|
-
finalChars: usedChars
|
|
7914
|
-
};
|
|
8401
|
+
return this.recallSectionCoordinator.assembleRecallSections(
|
|
8402
|
+
sectionBuckets,
|
|
8403
|
+
budgetOverride
|
|
8404
|
+
);
|
|
7915
8405
|
}
|
|
7916
8406
|
/**
|
|
7917
8407
|
* Clock source for the shared post-retrieval assembly/enrichment budget. The
|
|
@@ -8137,7 +8627,7 @@ ${doc.content}` : doc.content,
|
|
|
8137
8627
|
const graphExpandedResultPaths = /* @__PURE__ */ new Set();
|
|
8138
8628
|
const graphSourceLabelsForPath = (resultPath) => {
|
|
8139
8629
|
const labels = [];
|
|
8140
|
-
const normalizedPath = resultPath.split(
|
|
8630
|
+
const normalizedPath = resultPath.split(path6.sep).join("/");
|
|
8141
8631
|
const isEntityPath = normalizedPath.startsWith("entities/") || normalizedPath.includes("/entities/");
|
|
8142
8632
|
if (graphBaselinePaths.has(resultPath)) labels.push("baseline");
|
|
8143
8633
|
if (graphExpandedResultPaths.has(resultPath))
|
|
@@ -8287,7 +8777,7 @@ ${doc.content}` : doc.content,
|
|
|
8287
8777
|
profileStorageNamespaces.map((namespace) => this.storageRouter.storageFor(namespace))
|
|
8288
8778
|
);
|
|
8289
8779
|
const emptyProfileStorage = new Proxy(
|
|
8290
|
-
{ dir:
|
|
8780
|
+
{ dir: path6.join(this.config.memoryDir, ".empty-scope-profile") },
|
|
8291
8781
|
{
|
|
8292
8782
|
get(target, prop) {
|
|
8293
8783
|
if (prop in target) return target[prop];
|
|
@@ -9763,11 +10253,11 @@ ${formatted}`;
|
|
|
9763
10253
|
if (!resolveRecallAuxiliaryCapabilities(this.config).compactionReset) return null;
|
|
9764
10254
|
const workspaceDir = compactionWorkspaceDir || this.config.workspaceDir || defaultWorkspaceDir();
|
|
9765
10255
|
const safeSessionKey = sanitizeSessionKeyForFilename(effectiveSessionKey);
|
|
9766
|
-
const signalPath =
|
|
10256
|
+
const signalPath = path6.join(
|
|
9767
10257
|
workspaceDir,
|
|
9768
10258
|
`.compaction-reset-signal-${safeSessionKey}`
|
|
9769
10259
|
);
|
|
9770
|
-
const bootPath =
|
|
10260
|
+
const bootPath = path6.join(workspaceDir, "BOOT.md");
|
|
9771
10261
|
try {
|
|
9772
10262
|
const signalStat = await stat(signalPath).catch(() => null);
|
|
9773
10263
|
if (!signalStat) return null;
|
|
@@ -14369,7 +14859,7 @@ ${normalized}`).digest("hex");
|
|
|
14369
14859
|
const allMems = allMemsForGraph ?? [];
|
|
14370
14860
|
for (const m of allMems) {
|
|
14371
14861
|
if (m.frontmatter.entityRef === entityRef) {
|
|
14372
|
-
const rel =
|
|
14862
|
+
const rel = path6.relative(storage.dir, m.path);
|
|
14373
14863
|
if (rel !== memoryRelPath) entitySiblings.push(rel);
|
|
14374
14864
|
}
|
|
14375
14865
|
}
|
|
@@ -14693,7 +15183,7 @@ ${normalized}`).digest("hex");
|
|
|
14693
15183
|
}
|
|
14694
15184
|
if (resolveConsolidationCapabilities(this.config).semanticConsolidation) {
|
|
14695
15185
|
try {
|
|
14696
|
-
const stateFilePath =
|
|
15186
|
+
const stateFilePath = path6.join(
|
|
14697
15187
|
this.config.memoryDir,
|
|
14698
15188
|
"state",
|
|
14699
15189
|
"semantic-consolidation-last-run.json"
|
|
@@ -14741,7 +15231,7 @@ ${normalized}`).digest("hex");
|
|
|
14741
15231
|
);
|
|
14742
15232
|
}
|
|
14743
15233
|
if (semResult.errors === 0 || semResult.memoriesArchived > 0) {
|
|
14744
|
-
const stateDir =
|
|
15234
|
+
const stateDir = path6.join(this.config.memoryDir, "state");
|
|
14745
15235
|
await mkdir3(stateDir, { recursive: true });
|
|
14746
15236
|
await writeFile3(
|
|
14747
15237
|
stateFilePath,
|
|
@@ -15003,247 +15493,65 @@ ${reflectionsContent.trim()}
|
|
|
15003
15493
|
if (!resolveEvalCapabilities(this.config).evalHarness || !resolveEvalCapabilities(this.config).evalShadowMode)
|
|
15004
15494
|
return;
|
|
15005
15495
|
this.evalShadowWriteChain = this.evalShadowWriteChain.catch(() => void 0).then(async () => {
|
|
15006
|
-
try {
|
|
15007
|
-
await recordEvalShadowRecall({
|
|
15008
|
-
memoryDir: this.config.memoryDir,
|
|
15009
|
-
evalStoreDir: this.config.evalStoreDir,
|
|
15010
|
-
record: {
|
|
15011
|
-
schemaVersion: 1,
|
|
15012
|
-
...record
|
|
15013
|
-
}
|
|
15014
|
-
});
|
|
15015
|
-
} catch (err) {
|
|
15016
|
-
log.debug(`eval shadow recall write failed: ${err}`);
|
|
15017
|
-
}
|
|
15018
|
-
});
|
|
15019
|
-
}
|
|
15020
|
-
publishRecallResults(options) {
|
|
15021
|
-
const sectionId = "memories";
|
|
15022
|
-
const trustByPath = options.trustByPath ?? null;
|
|
15023
|
-
const injectable = trustByPath ? options.results.filter((r) => !trustByPath.get(r.path)?.quarantined) : options.results;
|
|
15024
|
-
const memoryIds = this.extractMemoryIdsFromResults(injectable);
|
|
15025
|
-
this.trackMemoryAccess(memoryIds);
|
|
15026
|
-
this.appendRecallSection(
|
|
15027
|
-
options.sectionBuckets,
|
|
15028
|
-
sectionId,
|
|
15029
|
-
this.formatQmdResults(options.title, injectable, options.sessionKey, trustByPath)
|
|
15030
|
-
);
|
|
15031
|
-
}
|
|
15032
|
-
/**
|
|
15033
|
-
* Apply MMR over the pre-truncation recall candidate pool and then slice
|
|
15034
|
-
* the result to `limit`. This is the single place in the pipeline where
|
|
15035
|
-
* MMR runs, and it must be called *before* callers throw away candidates
|
|
15036
|
-
* that would otherwise sit below the final cutoff. Running MMR post-slice
|
|
15037
|
-
* is a no-op in the cases we care about — diverse candidates just below
|
|
15038
|
-
* the cutoff are already gone and can never be promoted.
|
|
15039
|
-
*
|
|
15040
|
-
* Callers must pass the full candidate pool (post-rerank, pre-slice).
|
|
15041
|
-
*/
|
|
15042
|
-
qmdCollectionNamespaceFromPrefix(collectionPrefix) {
|
|
15043
|
-
const baseCollection = this.config.qmdCollection;
|
|
15044
|
-
if (collectionPrefix === baseCollection) return this.config.defaultNamespace;
|
|
15045
|
-
const namespaceSuffix = collectionPrefix.startsWith(`${baseCollection}--`) ? collectionPrefix.slice(baseCollection.length + 2) : "";
|
|
15046
|
-
if (!namespaceSuffix) return null;
|
|
15047
|
-
const decoded = namespaceIdentityFromToken(namespaceSuffix);
|
|
15048
|
-
if (decoded !== null) return decoded || this.config.defaultNamespace;
|
|
15049
|
-
if (namespaceSuffix.startsWith("ns--")) {
|
|
15050
|
-
const legacyNamespace = namespaceSuffix.slice("ns--".length).trim();
|
|
15051
|
-
return legacyNamespace || null;
|
|
15052
|
-
}
|
|
15053
|
-
return null;
|
|
15054
|
-
}
|
|
15055
|
-
async readQmdResultMemory(resultPath, fallbackStorage, recallNamespaces = []) {
|
|
15056
|
-
const parts = qmdCollectionPathParts(resultPath);
|
|
15057
|
-
const storageDirFor = (storage) => typeof storage.dir === "string" && storage.dir ? storage.dir : null;
|
|
15058
|
-
const fallbackStorageDir = storageDirFor(fallbackStorage);
|
|
15059
|
-
const coldCollection = this.config.qmdColdCollection ?? "openclaw-engram-cold";
|
|
15060
|
-
if (parts && parts.collection === coldCollection) {
|
|
15061
|
-
const storages = [];
|
|
15062
|
-
const seenStorageDirs = /* @__PURE__ */ new Set();
|
|
15063
|
-
const addStorage = (storage) => {
|
|
15064
|
-
const storageDir = storageDirFor(storage);
|
|
15065
|
-
const storageKey = storageDir ? path5.resolve(storageDir) : `storage-without-dir-${storages.length}`;
|
|
15066
|
-
if (seenStorageDirs.has(storageKey)) return;
|
|
15067
|
-
seenStorageDirs.add(storageKey);
|
|
15068
|
-
storages.push(storage);
|
|
15069
|
-
};
|
|
15070
|
-
const fallbackNamespace = fallbackStorageDir !== null ? this.storageDirNamespace(fallbackStorageDir) : this.config.defaultNamespace;
|
|
15071
|
-
if (recallNamespaces.length === 0 || !resolveNamespaceCapabilities(this.config).namespaces || recallNamespaces.includes(fallbackNamespace)) {
|
|
15072
|
-
addStorage(fallbackStorage);
|
|
15073
|
-
}
|
|
15074
|
-
if (recallNamespaces.length > 0) {
|
|
15075
|
-
for (const namespace of recallNamespaces) {
|
|
15076
|
-
try {
|
|
15077
|
-
addStorage(await this.storageRouter.storageFor(namespace));
|
|
15078
|
-
} catch (err) {
|
|
15079
|
-
log.debug("qmd cold result namespace storage lookup skipped", {
|
|
15080
|
-
path: resultPath,
|
|
15081
|
-
namespace,
|
|
15082
|
-
error: err.message
|
|
15083
|
-
});
|
|
15084
|
-
}
|
|
15085
|
-
}
|
|
15086
|
-
}
|
|
15087
|
-
for (const storage of storages) {
|
|
15088
|
-
const storageDir = storageDirFor(storage);
|
|
15089
|
-
if (!storageDir) {
|
|
15090
|
-
const memory = await storage.readMemoryByPath(resultPath);
|
|
15091
|
-
if (memory) return memory;
|
|
15092
|
-
continue;
|
|
15093
|
-
}
|
|
15094
|
-
try {
|
|
15095
|
-
const coldRoot = path5.join(storageDir, "cold");
|
|
15096
|
-
for (const candidate of qmdResultPathCandidates(
|
|
15097
|
-
coldRoot,
|
|
15098
|
-
parts.relativePath
|
|
15099
|
-
)) {
|
|
15100
|
-
const memory = await storage.readMemoryByPath(candidate);
|
|
15101
|
-
if (memory) return memory;
|
|
15102
|
-
}
|
|
15103
|
-
} catch (err) {
|
|
15104
|
-
if (err instanceof SecureStoreLockedError) throw err;
|
|
15105
|
-
log.debug("qmd cold result path lookup failed open", {
|
|
15106
|
-
path: resultPath,
|
|
15107
|
-
collection: coldCollection,
|
|
15108
|
-
error: err.message
|
|
15109
|
-
});
|
|
15110
|
-
}
|
|
15111
|
-
}
|
|
15112
|
-
return null;
|
|
15113
|
-
}
|
|
15114
|
-
const collectionNamespace = parts ? this.qmdCollectionNamespaceFromPrefix(parts.collection) : null;
|
|
15115
|
-
if (parts && collectionNamespace) {
|
|
15116
|
-
try {
|
|
15117
|
-
const collectionStorage = await this.storageRouter.storageFor(collectionNamespace);
|
|
15118
|
-
for (const candidate of qmdResultPathCandidates(
|
|
15119
|
-
collectionStorage.dir,
|
|
15120
|
-
parts.relativePath
|
|
15121
|
-
)) {
|
|
15122
|
-
const memory = await collectionStorage.readMemoryByPath(candidate);
|
|
15123
|
-
if (memory) return memory;
|
|
15124
|
-
}
|
|
15125
|
-
return null;
|
|
15126
|
-
} catch (err) {
|
|
15127
|
-
if (err instanceof SecureStoreLockedError) throw err;
|
|
15128
|
-
log.debug("qmd result namespace path lookup failed open", {
|
|
15129
|
-
path: resultPath,
|
|
15130
|
-
namespace: collectionNamespace,
|
|
15131
|
-
error: err.message
|
|
15132
|
-
});
|
|
15133
|
-
return null;
|
|
15134
|
-
}
|
|
15135
|
-
}
|
|
15136
|
-
if (path5.isAbsolute(resultPath)) {
|
|
15137
|
-
if (!fallbackStorageDir) {
|
|
15138
|
-
return await fallbackStorage.readMemoryByPath(resultPath);
|
|
15139
|
-
}
|
|
15140
|
-
const ownerStorage = await this.storageForAbsoluteQmdResultPath(
|
|
15141
|
-
resultPath,
|
|
15142
|
-
fallbackStorage,
|
|
15143
|
-
recallNamespaces
|
|
15144
|
-
);
|
|
15145
|
-
if (!ownerStorage) return null;
|
|
15146
|
-
for (const candidate of qmdResultPathCandidates(
|
|
15147
|
-
ownerStorage.dir,
|
|
15148
|
-
resultPath
|
|
15149
|
-
)) {
|
|
15150
|
-
const memory = await ownerStorage.storage.readMemoryByPath(candidate);
|
|
15151
|
-
if (memory) return memory;
|
|
15496
|
+
try {
|
|
15497
|
+
await recordEvalShadowRecall({
|
|
15498
|
+
memoryDir: this.config.memoryDir,
|
|
15499
|
+
evalStoreDir: this.config.evalStoreDir,
|
|
15500
|
+
record: {
|
|
15501
|
+
schemaVersion: 1,
|
|
15502
|
+
...record
|
|
15503
|
+
}
|
|
15504
|
+
});
|
|
15505
|
+
} catch (err) {
|
|
15506
|
+
log.debug(`eval shadow recall write failed: ${err}`);
|
|
15152
15507
|
}
|
|
15153
|
-
|
|
15154
|
-
|
|
15155
|
-
|
|
15156
|
-
|
|
15157
|
-
|
|
15158
|
-
|
|
15159
|
-
|
|
15160
|
-
|
|
15161
|
-
|
|
15162
|
-
|
|
15163
|
-
|
|
15508
|
+
});
|
|
15509
|
+
}
|
|
15510
|
+
publishRecallResults(options) {
|
|
15511
|
+
const sectionId = "memories";
|
|
15512
|
+
const trustByPath = options.trustByPath ?? null;
|
|
15513
|
+
const injectable = trustByPath ? options.results.filter((r) => !trustByPath.get(r.path)?.quarantined) : options.results;
|
|
15514
|
+
const memoryIds = this.extractMemoryIdsFromResults(injectable);
|
|
15515
|
+
this.trackMemoryAccess(memoryIds);
|
|
15516
|
+
this.appendRecallSection(
|
|
15517
|
+
options.sectionBuckets,
|
|
15518
|
+
sectionId,
|
|
15519
|
+
this.formatQmdResults(options.title, injectable, options.sessionKey, trustByPath)
|
|
15520
|
+
);
|
|
15521
|
+
}
|
|
15522
|
+
/**
|
|
15523
|
+
* Apply MMR over the pre-truncation recall candidate pool and then slice
|
|
15524
|
+
* the result to `limit`. This is the single place in the pipeline where
|
|
15525
|
+
* MMR runs, and it must be called *before* callers throw away candidates
|
|
15526
|
+
* that would otherwise sit below the final cutoff. Running MMR post-slice
|
|
15527
|
+
* is a no-op in the cases we care about — diverse candidates just below
|
|
15528
|
+
* the cutoff are already gone and can never be promoted.
|
|
15529
|
+
*
|
|
15530
|
+
* Callers must pass the full candidate pool (post-rerank, pre-slice).
|
|
15531
|
+
*/
|
|
15532
|
+
qmdCollectionNamespaceFromPrefix(collectionPrefix) {
|
|
15533
|
+
const baseCollection = this.config.qmdCollection;
|
|
15534
|
+
if (collectionPrefix === baseCollection) return this.config.defaultNamespace;
|
|
15535
|
+
const namespaceSuffix = collectionPrefix.startsWith(`${baseCollection}--`) ? collectionPrefix.slice(baseCollection.length + 2) : "";
|
|
15536
|
+
if (!namespaceSuffix) return null;
|
|
15537
|
+
const decoded = namespaceIdentityFromToken(namespaceSuffix);
|
|
15538
|
+
if (decoded !== null) return decoded || this.config.defaultNamespace;
|
|
15539
|
+
if (namespaceSuffix.startsWith("ns--")) {
|
|
15540
|
+
const legacyNamespace = namespaceSuffix.slice("ns--".length).trim();
|
|
15541
|
+
return legacyNamespace || null;
|
|
15164
15542
|
}
|
|
15165
15543
|
return null;
|
|
15166
15544
|
}
|
|
15545
|
+
// Issue #1526 seam 11: QMD result-resolution methods moved to QmdResultResolver.
|
|
15546
|
+
// Thin delegation keeps the private API stable for callers + tests.
|
|
15547
|
+
async readQmdResultMemory(resultPath, fallbackStorage, recallNamespaces = []) {
|
|
15548
|
+
return this.qmdResultResolver.readQmdResultMemory(resultPath, fallbackStorage, recallNamespaces);
|
|
15549
|
+
}
|
|
15167
15550
|
async resolveColdQmdResultForRecall(result, fallbackStorage, recallNamespaces = []) {
|
|
15168
|
-
|
|
15169
|
-
result.path,
|
|
15170
|
-
fallbackStorage,
|
|
15171
|
-
recallNamespaces
|
|
15172
|
-
);
|
|
15173
|
-
if (!memory) return null;
|
|
15174
|
-
let ownerNamespace = null;
|
|
15175
|
-
if (path5.isAbsolute(memory.path)) {
|
|
15176
|
-
const ownerStorage = await this.storageForAbsoluteQmdResultPath(
|
|
15177
|
-
memory.path,
|
|
15178
|
-
fallbackStorage,
|
|
15179
|
-
recallNamespaces
|
|
15180
|
-
);
|
|
15181
|
-
ownerNamespace = ownerStorage?.namespace ?? null;
|
|
15182
|
-
if (!ownerNamespace && resolveNamespaceCapabilities(this.config).namespaces) return null;
|
|
15183
|
-
}
|
|
15184
|
-
ownerNamespace ??= this.namespaceFromPath(memory.path);
|
|
15185
|
-
if (recallNamespaces.length > 0 && !recallNamespaces.includes(ownerNamespace)) {
|
|
15186
|
-
return null;
|
|
15187
|
-
}
|
|
15188
|
-
return {
|
|
15189
|
-
namespace: ownerNamespace,
|
|
15190
|
-
result: {
|
|
15191
|
-
...result,
|
|
15192
|
-
docid: result.docid || memory.frontmatter.id,
|
|
15193
|
-
path: memory.path,
|
|
15194
|
-
snippet: result.snippet || memory.content.slice(0, 400)
|
|
15195
|
-
}
|
|
15196
|
-
};
|
|
15551
|
+
return this.qmdResultResolver.resolveColdQmdResultForRecall(result, fallbackStorage, recallNamespaces);
|
|
15197
15552
|
}
|
|
15198
15553
|
async storageForAbsoluteQmdResultPath(resultPath, fallbackStorage, recallNamespaces = []) {
|
|
15199
|
-
|
|
15200
|
-
const memoryRoot = path5.resolve(this.config.memoryDir);
|
|
15201
|
-
const namespacesRoot = path5.join(memoryRoot, "namespaces");
|
|
15202
|
-
const fallbackStorageDir = typeof fallbackStorage.dir === "string" && fallbackStorage.dir ? fallbackStorage.dir : null;
|
|
15203
|
-
const matches = [];
|
|
15204
|
-
const seenDirs = /* @__PURE__ */ new Set();
|
|
15205
|
-
const maybeAddStorage = (storage, namespace) => {
|
|
15206
|
-
const storageDir = typeof storage.dir === "string" && storage.dir ? storage.dir : null;
|
|
15207
|
-
if (!storageDir) return;
|
|
15208
|
-
const candidateRoot = path5.resolve(storageDir);
|
|
15209
|
-
if (seenDirs.has(candidateRoot)) return;
|
|
15210
|
-
if (!isPathInsideStorageRoot(candidateRoot, resolvedPath)) return;
|
|
15211
|
-
if (candidateRoot === memoryRoot && isPathInsideStorageRoot(namespacesRoot, resolvedPath)) {
|
|
15212
|
-
return;
|
|
15213
|
-
}
|
|
15214
|
-
seenDirs.add(candidateRoot);
|
|
15215
|
-
matches.push({ storage, dir: candidateRoot, namespace });
|
|
15216
|
-
};
|
|
15217
|
-
const fallbackNamespace = fallbackStorageDir !== null ? this.storageDirNamespace(fallbackStorageDir) : this.config.defaultNamespace;
|
|
15218
|
-
maybeAddStorage(fallbackStorage, fallbackNamespace);
|
|
15219
|
-
const candidateNamespaces = /* @__PURE__ */ new Set();
|
|
15220
|
-
candidateNamespaces.add(this.config.defaultNamespace);
|
|
15221
|
-
candidateNamespaces.add(this.config.sharedNamespace);
|
|
15222
|
-
for (const ns of recallNamespaces) {
|
|
15223
|
-
candidateNamespaces.add(ns);
|
|
15224
|
-
}
|
|
15225
|
-
if (isPathInsideStorageRoot(namespacesRoot, resolvedPath)) {
|
|
15226
|
-
const relativeToNamespaces = path5.relative(namespacesRoot, resolvedPath);
|
|
15227
|
-
const [namespaceSegment] = relativeToNamespaces.split(/[\\/]/);
|
|
15228
|
-
if (namespaceSegment) {
|
|
15229
|
-
candidateNamespaces.add(
|
|
15230
|
-
namespaceIdentityFromToken(namespaceSegment) ?? namespaceSegment
|
|
15231
|
-
);
|
|
15232
|
-
}
|
|
15233
|
-
}
|
|
15234
|
-
for (const policy of this.config.namespacePolicies ?? []) {
|
|
15235
|
-
candidateNamespaces.add(policy.name);
|
|
15236
|
-
}
|
|
15237
|
-
for (const ns of candidateNamespaces) {
|
|
15238
|
-
if (!ns) continue;
|
|
15239
|
-
try {
|
|
15240
|
-
maybeAddStorage(await this.storageRouter.storageFor(ns), ns);
|
|
15241
|
-
} catch {
|
|
15242
|
-
continue;
|
|
15243
|
-
}
|
|
15244
|
-
}
|
|
15245
|
-
matches.sort((a, b) => b.dir.length - a.dir.length);
|
|
15246
|
-
return matches[0] ?? null;
|
|
15554
|
+
return this.qmdResultResolver.storageForAbsoluteQmdResultPath(resultPath, fallbackStorage, recallNamespaces);
|
|
15247
15555
|
}
|
|
15248
15556
|
// Issue #1526: recall-rerank methods moved to RecallRerankCoordinator.
|
|
15249
15557
|
// Thin delegation keeps the private API stable for callers + tests.
|
|
@@ -15263,30 +15571,13 @@ ${reflectionsContent.trim()}
|
|
|
15263
15571
|
return this.recallRerankCoordinator.applyMmrToQmdResults(sectionId, results, caps);
|
|
15264
15572
|
}
|
|
15265
15573
|
buildLastRecallBudgetSummary(options) {
|
|
15266
|
-
return
|
|
15267
|
-
requestedTopK: options.requestedTopK,
|
|
15268
|
-
appliedTopK: options.recallResultLimit,
|
|
15269
|
-
recallBudgetChars: this.getRecallBudgetChars(),
|
|
15270
|
-
maxMemoryTokens: this.config.maxMemoryTokens,
|
|
15271
|
-
qmdFetchLimit: options.qmdFetchLimit,
|
|
15272
|
-
qmdHybridFetchLimit: options.qmdHybridFetchLimit,
|
|
15273
|
-
finalContextChars: options.finalContextChars,
|
|
15274
|
-
truncated: options.truncated,
|
|
15275
|
-
includedSections: [...options.includedSections ?? []],
|
|
15276
|
-
omittedSections: [...options.omittedSections ?? []]
|
|
15277
|
-
};
|
|
15574
|
+
return this.recallSectionCoordinator.buildLastRecallBudgetSummary(options);
|
|
15278
15575
|
}
|
|
15279
15576
|
collectLastRecallSources(sectionBuckets, recallSource) {
|
|
15280
|
-
|
|
15281
|
-
|
|
15282
|
-
|
|
15283
|
-
|
|
15284
|
-
for (const [sectionId, chunks] of sectionBuckets.entries()) {
|
|
15285
|
-
if (chunks.length > 0) {
|
|
15286
|
-
used.add(sectionId);
|
|
15287
|
-
}
|
|
15288
|
-
}
|
|
15289
|
-
return [...used];
|
|
15577
|
+
return this.recallSectionCoordinator.collectLastRecallSources(
|
|
15578
|
+
sectionBuckets,
|
|
15579
|
+
recallSource
|
|
15580
|
+
);
|
|
15290
15581
|
}
|
|
15291
15582
|
/**
|
|
15292
15583
|
* Issue #373 — nearest-neighbor lookup for the write-time semantic dedup
|
|
@@ -15336,12 +15627,12 @@ ${reflectionsContent.trim()}
|
|
|
15336
15627
|
*/
|
|
15337
15628
|
semanticDedupScopeFor(targetStorage) {
|
|
15338
15629
|
if (!resolveNamespaceCapabilities(this.config).namespaces) return {};
|
|
15339
|
-
const memoryDir =
|
|
15340
|
-
const storageDir =
|
|
15630
|
+
const memoryDir = path6.resolve(this.config.memoryDir);
|
|
15631
|
+
const storageDir = path6.resolve(targetStorage.dir);
|
|
15341
15632
|
if (storageDir === memoryDir) {
|
|
15342
15633
|
return { pathExcludePrefixes: ["namespaces/"] };
|
|
15343
15634
|
}
|
|
15344
|
-
let rel =
|
|
15635
|
+
let rel = path6.relative(memoryDir, storageDir);
|
|
15345
15636
|
if (!rel || rel.startsWith("..")) {
|
|
15346
15637
|
log.debug(
|
|
15347
15638
|
`semantic dedup: target storage dir ${storageDir} is outside memoryDir ${memoryDir}; scoping lookup to absolute path prefix`
|
|
@@ -15360,7 +15651,7 @@ ${reflectionsContent.trim()}
|
|
|
15360
15651
|
if (hits.length === 0) return [];
|
|
15361
15652
|
const results = [];
|
|
15362
15653
|
for (const hit of hits) {
|
|
15363
|
-
const fullPath =
|
|
15654
|
+
const fullPath = path6.isAbsolute(hit.path) ? hit.path : path6.join(this.config.memoryDir, hit.path);
|
|
15364
15655
|
const memory = await this.storage.readMemoryByPath(fullPath);
|
|
15365
15656
|
if (!memory) continue;
|
|
15366
15657
|
results.push({
|
|
@@ -15557,7 +15848,7 @@ ${reflectionsContent.trim()}
|
|
|
15557
15848
|
const storage = await this.storageRouter.storageFor(namespace);
|
|
15558
15849
|
const storageDir = typeof storage.dir === "string" && storage.dir ? storage.dir : null;
|
|
15559
15850
|
if (!storageDir) continue;
|
|
15560
|
-
const recallRoot =
|
|
15851
|
+
const recallRoot = path6.resolve(storageDir);
|
|
15561
15852
|
if (seenRecallRoots.has(recallRoot)) continue;
|
|
15562
15853
|
seenRecallRoots.add(recallRoot);
|
|
15563
15854
|
recallRoots.push(recallRoot);
|
|
@@ -15581,8 +15872,8 @@ ${reflectionsContent.trim()}
|
|
|
15581
15872
|
if (resolvedCold) scopedResults.push(resolvedCold.result);
|
|
15582
15873
|
continue;
|
|
15583
15874
|
}
|
|
15584
|
-
if (
|
|
15585
|
-
const resolvedPath =
|
|
15875
|
+
if (path6.isAbsolute(result.path)) {
|
|
15876
|
+
const resolvedPath = path6.resolve(result.path);
|
|
15586
15877
|
if (recallRoots.some(
|
|
15587
15878
|
(recallRoot) => isPathInsideStorageRoot(recallRoot, resolvedPath)
|
|
15588
15879
|
)) {
|
|
@@ -16248,58 +16539,11 @@ ${reflectionsContent.trim()}
|
|
|
16248
16539
|
* Uses QMD to find similar memories, then LLM to verify contradiction.
|
|
16249
16540
|
*/
|
|
16250
16541
|
async checkForContradiction(content, category, namespaceScope) {
|
|
16251
|
-
|
|
16252
|
-
|
|
16253
|
-
|
|
16254
|
-
|
|
16255
|
-
|
|
16256
|
-
mode: "search"
|
|
16257
|
-
});
|
|
16258
|
-
for (const result of results) {
|
|
16259
|
-
if (result.score < this.config.contradictionSimilarityThreshold) {
|
|
16260
|
-
continue;
|
|
16261
|
-
}
|
|
16262
|
-
const memoryId = this.extractMemoryIdsFromResults([result])[0];
|
|
16263
|
-
if (!memoryId) continue;
|
|
16264
|
-
const resultNamespace = this.namespaceFromPath(result.path);
|
|
16265
|
-
if (resultNamespace !== namespaceScope) continue;
|
|
16266
|
-
const resultStorage = await this.storageRouter.storageFor(resultNamespace);
|
|
16267
|
-
const existingMemory = await resultStorage.getMemoryById(memoryId);
|
|
16268
|
-
if (!existingMemory) continue;
|
|
16269
|
-
if (existingMemory.frontmatter.status === "superseded" || existingMemory.frontmatter.status === "forgotten") {
|
|
16270
|
-
continue;
|
|
16271
|
-
}
|
|
16272
|
-
const verification = await this.extraction.verifyContradiction(
|
|
16273
|
-
{ content, category },
|
|
16274
|
-
{
|
|
16275
|
-
id: existingMemory.frontmatter.id,
|
|
16276
|
-
content: existingMemory.content,
|
|
16277
|
-
category: existingMemory.frontmatter.category,
|
|
16278
|
-
created: existingMemory.frontmatter.created
|
|
16279
|
-
}
|
|
16280
|
-
);
|
|
16281
|
-
if (!verification) continue;
|
|
16282
|
-
if (verification.isContradiction && verification.confidence >= this.config.contradictionMinConfidence) {
|
|
16283
|
-
if (verification.whichIsNewer === "first") {
|
|
16284
|
-
log.info(
|
|
16285
|
-
`detected contradiction (confidence: ${verification.confidence}): ${existingMemory.frontmatter.id} vs new memory \u2014 existing is newer, incoming fact is stale`
|
|
16286
|
-
);
|
|
16287
|
-
continue;
|
|
16288
|
-
}
|
|
16289
|
-
log.info(
|
|
16290
|
-
`detected contradiction (confidence: ${verification.confidence}): ${existingMemory.frontmatter.id} vs new memory${this.config.contradictionAutoResolve ? " (auto-resolved)" : " (queued for manual review)"}`
|
|
16291
|
-
);
|
|
16292
|
-
return {
|
|
16293
|
-
supersededId: existingMemory.frontmatter.id,
|
|
16294
|
-
confidence: verification.confidence,
|
|
16295
|
-
reason: verification.reasoning,
|
|
16296
|
-
supersededPath: existingMemory.path,
|
|
16297
|
-
supersededCreated: existingMemory.frontmatter.created,
|
|
16298
|
-
supersededTags: existingMemory.frontmatter.tags ?? []
|
|
16299
|
-
};
|
|
16300
|
-
}
|
|
16301
|
-
}
|
|
16302
|
-
return null;
|
|
16542
|
+
return this.contradictionLinkingCoordinator.checkForContradiction(
|
|
16543
|
+
content,
|
|
16544
|
+
category,
|
|
16545
|
+
namespaceScope
|
|
16546
|
+
);
|
|
16303
16547
|
}
|
|
16304
16548
|
/**
|
|
16305
16549
|
* #1645: Complete the deferred contradiction auto-resolve after writeMemory
|
|
@@ -16310,40 +16554,12 @@ ${reflectionsContent.trim()}
|
|
|
16310
16554
|
* supersedes before tombstone status is known" defect class.
|
|
16311
16555
|
*/
|
|
16312
16556
|
async applyDeferredContradictionResolve(contradiction, storage, newMemoryId, postWriteGuard) {
|
|
16313
|
-
|
|
16314
|
-
|
|
16315
|
-
|
|
16316
|
-
|
|
16317
|
-
|
|
16318
|
-
|
|
16319
|
-
} catch (err) {
|
|
16320
|
-
log.warn(
|
|
16321
|
-
`contradiction auto-resolve supersedes clear failed for blocked ${newMemoryId}: ${err}`
|
|
16322
|
-
);
|
|
16323
|
-
}
|
|
16324
|
-
}
|
|
16325
|
-
if (!contradiction || !this.config.contradictionAutoResolve || postWriteGuard) {
|
|
16326
|
-
return;
|
|
16327
|
-
}
|
|
16328
|
-
try {
|
|
16329
|
-
await storage.supersedeMemory(
|
|
16330
|
-
contradiction.supersededId,
|
|
16331
|
-
newMemoryId,
|
|
16332
|
-
contradiction.reason
|
|
16333
|
-
);
|
|
16334
|
-
if (resolveIndexingCapabilities(this.config).queryAwareIndexing && contradiction.supersededPath) {
|
|
16335
|
-
deindexMemory(
|
|
16336
|
-
this.config.memoryDir,
|
|
16337
|
-
contradiction.supersededPath,
|
|
16338
|
-
contradiction.supersededCreated,
|
|
16339
|
-
contradiction.supersededTags
|
|
16340
|
-
);
|
|
16341
|
-
}
|
|
16342
|
-
} catch (err) {
|
|
16343
|
-
log.warn(
|
|
16344
|
-
`contradiction auto-resolve supersede failed for ${contradiction.supersededId}: ${err}`
|
|
16345
|
-
);
|
|
16346
|
-
}
|
|
16557
|
+
return this.contradictionLinkingCoordinator.applyDeferredContradictionResolve(
|
|
16558
|
+
contradiction,
|
|
16559
|
+
storage,
|
|
16560
|
+
newMemoryId,
|
|
16561
|
+
postWriteGuard
|
|
16562
|
+
);
|
|
16347
16563
|
}
|
|
16348
16564
|
// ---------------------------------------------------------------------------
|
|
16349
16565
|
// Memory Linking (Phase 3A)
|
|
@@ -16352,42 +16568,11 @@ ${reflectionsContent.trim()}
|
|
|
16352
16568
|
* Suggest links for a new memory based on similar existing memories.
|
|
16353
16569
|
*/
|
|
16354
16570
|
async suggestLinksForMemory(content, category, namespaceScope) {
|
|
16355
|
-
|
|
16356
|
-
|
|
16357
|
-
|
|
16358
|
-
|
|
16359
|
-
maxResults: 5,
|
|
16360
|
-
mode: "search"
|
|
16361
|
-
});
|
|
16362
|
-
if (results.length === 0) return [];
|
|
16363
|
-
const candidates = [];
|
|
16364
|
-
for (const result of results) {
|
|
16365
|
-
const memoryId = this.extractMemoryIdsFromResults([result])[0];
|
|
16366
|
-
if (!memoryId) continue;
|
|
16367
|
-
const resultNamespace = this.namespaceFromPath(result.path);
|
|
16368
|
-
if (resultNamespace !== namespaceScope) continue;
|
|
16369
|
-
const resultStorage = await this.storageRouter.storageFor(resultNamespace);
|
|
16370
|
-
const memory = await resultStorage.getMemoryById(memoryId);
|
|
16371
|
-
if (memory && memory.frontmatter.status !== "superseded" && memory.frontmatter.status !== "forgotten") {
|
|
16372
|
-
candidates.push({
|
|
16373
|
-
id: memory.frontmatter.id,
|
|
16374
|
-
content: memory.content,
|
|
16375
|
-
category: memory.frontmatter.category
|
|
16376
|
-
});
|
|
16377
|
-
}
|
|
16378
|
-
}
|
|
16379
|
-
if (candidates.length === 0) return [];
|
|
16380
|
-
const suggestions = await this.extraction.suggestLinks(
|
|
16381
|
-
{ content, category },
|
|
16382
|
-
candidates
|
|
16571
|
+
return this.contradictionLinkingCoordinator.suggestLinksForMemory(
|
|
16572
|
+
content,
|
|
16573
|
+
category,
|
|
16574
|
+
namespaceScope
|
|
16383
16575
|
);
|
|
16384
|
-
if (!suggestions || suggestions.links.length === 0) return [];
|
|
16385
|
-
return suggestions.links.map((link) => ({
|
|
16386
|
-
targetId: link.targetId,
|
|
16387
|
-
linkType: link.linkType,
|
|
16388
|
-
strength: link.strength,
|
|
16389
|
-
reason: link.reason || void 0
|
|
16390
|
-
}));
|
|
16391
16576
|
}
|
|
16392
16577
|
async graphSeedPathRelativeToStorage(storage, result, recallNamespaces = []) {
|
|
16393
16578
|
const parts = qmdCollectionPathParts(result.path);
|
|
@@ -16516,4 +16701,4 @@ export {
|
|
|
16516
16701
|
resolvePersistedMemoryRelativePath,
|
|
16517
16702
|
Orchestrator
|
|
16518
16703
|
};
|
|
16519
|
-
//# sourceMappingURL=chunk-
|
|
16704
|
+
//# sourceMappingURL=chunk-VO4VARZL.js.map
|