@remnic/core 9.3.733 → 9.3.735
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 +13 -11
- package/dist/access-boundary.js +9 -9
- package/dist/access-cli.js +26 -24
- package/dist/access-cli.js.map +1 -1
- package/dist/access-http.d.ts +13 -11
- package/dist/access-http.js +14 -14
- package/dist/access-mcp.d.ts +13 -11
- package/dist/access-mcp.js +13 -13
- package/dist/access-operations-batch.js +11 -11
- package/dist/access-operations.d.ts +13 -11
- package/dist/access-operations.js +12 -12
- package/dist/access-schema.d.ts +4 -4
- package/dist/{access-service-Byoe3HsT.d.ts → access-service-CVx7mmvK.d.ts} +4 -4
- package/dist/access-service.d.ts +13 -11
- package/dist/access-service.js +8 -8
- package/dist/access-surface-catalog.d.ts +13 -11
- package/dist/action-confidence.d.ts +1 -1
- package/dist/active-memory-bridge.d.ts +1 -1
- package/dist/active-memory-bridge.js +3 -2
- package/dist/active-recall.d.ts +1 -1
- package/dist/behavior-learner.d.ts +1 -1
- package/dist/behavior-signals.d.ts +1 -1
- package/dist/bootstrap.d.ts +12 -10
- 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/calibration.d.ts +1 -1
- package/dist/capabilities.d.ts +196 -2
- package/dist/capabilities.js +21 -3
- package/dist/{catalog-DM1nk7cM.d.ts → catalog-BVhDEUhT.d.ts} +2 -2
- package/dist/causal-behavior.d.ts +1 -1
- package/dist/causal-consolidation.d.ts +1 -1
- package/dist/causal-trajectory-graph.d.ts +1 -1
- package/dist/{chunk-CX77GNMB.js → chunk-2T2N7ISV.js} +6 -3
- package/dist/chunk-2T2N7ISV.js.map +1 -0
- package/dist/{chunk-HHNSLPX7.js → chunk-5BOQNB2K.js} +10 -9
- package/dist/chunk-5BOQNB2K.js.map +1 -0
- package/dist/{chunk-QZHF4BWN.js → chunk-AAIHDIMD.js} +6 -6
- package/dist/{chunk-H3MB3F62.js → chunk-AB2E5DCN.js} +4 -3
- package/dist/chunk-AB2E5DCN.js.map +1 -0
- package/dist/{chunk-KSJCXXOU.js → chunk-AE7NTZ75.js} +6 -3
- package/dist/chunk-AE7NTZ75.js.map +1 -0
- package/dist/{chunk-OTQE66IX.js → chunk-AESC5OQJ.js} +6 -3
- package/dist/chunk-AESC5OQJ.js.map +1 -0
- package/dist/{chunk-FFUCCKPN.js → chunk-BXPG5AVX.js} +10 -7
- package/dist/chunk-BXPG5AVX.js.map +1 -0
- package/dist/{chunk-P3VJCTVE.js → chunk-CHJIWG2H.js} +4 -3
- package/dist/chunk-CHJIWG2H.js.map +1 -0
- package/dist/{chunk-FYWUNVFZ.js → chunk-E4LYJ7PY.js} +6 -6
- package/dist/{chunk-NIZQH6AU.js → chunk-FF36YNKY.js} +8 -7
- package/dist/chunk-FF36YNKY.js.map +1 -0
- package/dist/{chunk-OUITHS6V.js → chunk-FLCYY5JX.js} +801 -711
- package/dist/chunk-FLCYY5JX.js.map +1 -0
- package/dist/{chunk-PLBIPT6I.js → chunk-FLPKEMSO.js} +7 -4
- package/dist/chunk-FLPKEMSO.js.map +1 -0
- package/dist/{chunk-6TUWSUUD.js → chunk-G54IDCD3.js} +59 -53
- package/dist/chunk-G54IDCD3.js.map +1 -0
- package/dist/{chunk-J6BH2OBA.js → chunk-GB2FZOWB.js} +8 -5
- package/dist/chunk-GB2FZOWB.js.map +1 -0
- package/dist/{chunk-CGPHMNL4.js → chunk-GYICIICQ.js} +10 -6
- package/dist/chunk-GYICIICQ.js.map +1 -0
- package/dist/{chunk-DKT3X5C3.js → chunk-HFXZIF3V.js} +7 -4
- package/dist/chunk-HFXZIF3V.js.map +1 -0
- package/dist/{chunk-646B5ERJ.js → chunk-HLPYL6LC.js} +71 -65
- package/dist/chunk-HLPYL6LC.js.map +1 -0
- package/dist/{chunk-ZVHRSR2R.js → chunk-IPI45Q4S.js} +6 -3
- package/dist/chunk-IPI45Q4S.js.map +1 -0
- package/dist/{chunk-24D66MMN.js → chunk-IX4L7E5G.js} +7 -4
- package/dist/chunk-IX4L7E5G.js.map +1 -0
- package/dist/{chunk-SYX73XD7.js → chunk-IXGXALRV.js} +10 -7
- package/dist/chunk-IXGXALRV.js.map +1 -0
- package/dist/{chunk-ESF7TRYJ.js → chunk-JWDE7OVJ.js} +79 -2
- package/dist/chunk-JWDE7OVJ.js.map +1 -0
- package/dist/{chunk-GGL34GCW.js → chunk-K3Y2SJTN.js} +7 -4
- package/dist/chunk-K3Y2SJTN.js.map +1 -0
- package/dist/{chunk-PMAQRUN4.js → chunk-NDKW67ER.js} +5 -2
- package/dist/chunk-NDKW67ER.js.map +1 -0
- package/dist/{chunk-ZQUAVZNG.js → chunk-NNJKEAP2.js} +7 -4
- package/dist/chunk-NNJKEAP2.js.map +1 -0
- package/dist/{chunk-UZYLX7M6.js → chunk-OYHYBHHI.js} +9 -6
- package/dist/chunk-OYHYBHHI.js.map +1 -0
- package/dist/{chunk-NOU77OHX.js → chunk-P6VLG7KE.js} +2 -2
- package/dist/{chunk-O4ZIBPIW.js → chunk-QNTLWH3T.js} +3 -3
- package/dist/{chunk-LUCARK4W.js → chunk-UO6MPN77.js} +37 -35
- package/dist/chunk-UO6MPN77.js.map +1 -0
- package/dist/{chunk-HJWQJUKQ.js → chunk-VOEVVIP3.js} +3 -3
- package/dist/{chunk-KQYGNGON.js → chunk-ZBZ4XULO.js} +6 -3
- package/dist/chunk-ZBZ4XULO.js.map +1 -0
- package/dist/{cli-Dt-tuiYH.d.ts → cli-Cx5Mxwk7.d.ts} +3 -3
- package/dist/cli.d.ts +14 -12
- package/dist/cli.js +20 -20
- package/dist/compounding/engine.d.ts +3 -2
- package/dist/compounding/engine.js +2 -1
- 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/consolidation-provenance-check.d.ts +1 -1
- package/dist/consolidation-undo.d.ts +1 -1
- package/dist/contradiction/index.d.ts +2 -2
- package/dist/contradiction/index.js +2 -1
- package/dist/{contradiction-scan-HWGEOUDS.js → contradiction-scan-2B4AE4TI.js} +3 -2
- 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/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 -1
- package/dist/entity-schema.d.ts +1 -1
- package/dist/explicit-capture.d.ts +12 -10
- package/dist/explicit-capture.js +2 -1
- 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 +3 -3
- package/dist/fallback-llm.d.ts +1 -1
- package/dist/{first-start-migration-OOR57AYR.js → first-start-migration-2RQYDIZ7.js} +10 -8
- package/dist/first-start-migration-2RQYDIZ7.js.map +1 -0
- 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-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 +12 -12
- package/dist/index.js +44 -44
- package/dist/intent.d.ts +1 -1
- package/dist/lcm/engine.d.ts +1 -1
- package/dist/lcm/index.d.ts +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 -1
- 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 +13 -11
- 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 -1
- 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 -1
- 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 -1
- package/dist/orchestration/maintenance.d.ts +2 -2
- package/dist/orchestration/maintenance.js +6 -5
- package/dist/{orchestrator-B4KjaOtY.d.ts → orchestrator-oF0cceBX.d.ts} +143 -18
- package/dist/orchestrator.d.ts +8 -6
- package/dist/orchestrator.js +21 -19
- 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/schemas.d.ts +2 -2
- 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-SLAa_prH.d.ts → semantic-DJR8_DMQ.d.ts} +1 -1
- package/dist/{semantic-consolidation-CstTvHPo.d.ts → semantic-consolidation-DKGbufYO.d.ts} +1 -1
- package/dist/semantic-consolidation.d.ts +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 +3 -3
- 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 -2
- 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-3LYQ3VV5.js → tier-stats-KPDIISG7.js} +8 -4
- package/dist/tier-stats-KPDIISG7.js.map +1 -0
- package/dist/topics.d.ts +1 -1
- package/dist/transcript.d.ts +1 -1
- package/dist/transfer/types.d.ts +30 -30
- package/dist/trust-score-stage.d.ts +1 -1
- package/dist/trust-score.d.ts +1 -1
- package/dist/{types-VkxElCHR.d.ts → types-C7UCxpuO.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/access-service.ts +61 -56
- package/src/active-memory-bridge.ts +2 -1
- package/src/admin/admin-surfaces.ts +2 -1
- package/src/capabilities.test.ts +375 -0
- package/src/capabilities.ts +403 -0
- package/src/cli/creation-ledger-commands.ts +2 -2
- package/src/cli/research-status-commands.ts +13 -13
- package/src/cli.ts +29 -25
- package/src/compounding/engine.ts +4 -3
- package/src/contradiction/contradiction-scan.ts +4 -3
- package/src/embedding-fallback.ts +5 -2
- package/src/entity-retrieval.ts +3 -2
- package/src/explicit-capture.ts +2 -1
- package/src/extraction.ts +6 -3
- package/src/local-llm.ts +4 -3
- package/src/maintenance/first-start-migration.ts +8 -5
- package/src/maintenance/namespace-maintenance-fanout.ts +2 -1
- package/src/maintenance/namespace-planner.ts +4 -3
- package/src/maintenance/tier-stats.ts +4 -3
- package/src/namespaces/catalog.ts +2 -1
- package/src/namespaces/migrate.ts +2 -1
- package/src/namespaces/principal.ts +6 -5
- package/src/namespaces/scope-profiles.ts +2 -1
- package/src/namespaces/search.ts +2 -1
- package/src/namespaces/storage.ts +4 -3
- package/src/operator-toolkit.ts +27 -26
- package/src/orchestration/compression-guideline-coordinator.ts +7 -6
- package/src/orchestration/lifecycle-policy-coordinator.ts +504 -0
- package/src/orchestration/maintenance.ts +8 -4
- package/src/orchestration/semantic-consolidation-coordinator.ts +454 -0
- package/src/orchestration/tier-migration-coordinator.ts +5 -4
- package/src/orchestrator.ts +106 -800
- package/src/scopes/scope-plan.ts +3 -2
- package/src/search/embed-helper.ts +5 -2
- package/src/search/factory.ts +9 -6
- package/src/summarizer.ts +3 -2
- package/dist/chunk-24D66MMN.js.map +0 -1
- package/dist/chunk-646B5ERJ.js.map +0 -1
- package/dist/chunk-6TUWSUUD.js.map +0 -1
- package/dist/chunk-CGPHMNL4.js.map +0 -1
- package/dist/chunk-CX77GNMB.js.map +0 -1
- package/dist/chunk-DKT3X5C3.js.map +0 -1
- package/dist/chunk-ESF7TRYJ.js.map +0 -1
- package/dist/chunk-FFUCCKPN.js.map +0 -1
- package/dist/chunk-GGL34GCW.js.map +0 -1
- package/dist/chunk-H3MB3F62.js.map +0 -1
- package/dist/chunk-HHNSLPX7.js.map +0 -1
- package/dist/chunk-J6BH2OBA.js.map +0 -1
- package/dist/chunk-KQYGNGON.js.map +0 -1
- package/dist/chunk-KSJCXXOU.js.map +0 -1
- package/dist/chunk-LUCARK4W.js.map +0 -1
- package/dist/chunk-NIZQH6AU.js.map +0 -1
- package/dist/chunk-OTQE66IX.js.map +0 -1
- package/dist/chunk-OUITHS6V.js.map +0 -1
- package/dist/chunk-P3VJCTVE.js.map +0 -1
- package/dist/chunk-PLBIPT6I.js.map +0 -1
- package/dist/chunk-PMAQRUN4.js.map +0 -1
- package/dist/chunk-SYX73XD7.js.map +0 -1
- package/dist/chunk-UZYLX7M6.js.map +0 -1
- package/dist/chunk-ZQUAVZNG.js.map +0 -1
- package/dist/chunk-ZVHRSR2R.js.map +0 -1
- package/dist/first-start-migration-OOR57AYR.js.map +0 -1
- package/dist/tier-stats-3LYQ3VV5.js.map +0 -1
- /package/dist/{chunk-QZHF4BWN.js.map → chunk-AAIHDIMD.js.map} +0 -0
- /package/dist/{chunk-FYWUNVFZ.js.map → chunk-E4LYJ7PY.js.map} +0 -0
- /package/dist/{chunk-NOU77OHX.js.map → chunk-P6VLG7KE.js.map} +0 -0
- /package/dist/{chunk-O4ZIBPIW.js.map → chunk-QNTLWH3T.js.map} +0 -0
- /package/dist/{chunk-HJWQJUKQ.js.map → chunk-VOEVVIP3.js.map} +0 -0
- /package/dist/{contradiction-scan-HWGEOUDS.js.map → contradiction-scan-2B4AE4TI.js.map} +0 -0
package/src/orchestrator.ts
CHANGED
|
@@ -101,6 +101,8 @@ import { MaintenanceScheduler } from "./orchestration/maintenance.js";
|
|
|
101
101
|
import { TierMigrationCoordinator } from "./orchestration/tier-migration-coordinator.js";
|
|
102
102
|
import { ExtractionQueueCoordinator } from "./orchestration/extraction-queue-coordinator.js";
|
|
103
103
|
import { CompressionGuidelineCoordinator } from "./orchestration/compression-guideline-coordinator.js";
|
|
104
|
+
import { SemanticConsolidationCoordinator } from "./orchestration/semantic-consolidation-coordinator.js";
|
|
105
|
+
import { LifecyclePolicyCoordinator } from "./orchestration/lifecycle-policy-coordinator.js";
|
|
104
106
|
import {
|
|
105
107
|
runLiveConnectorsOnce,
|
|
106
108
|
type LiveConnectorsRunSummary,
|
|
@@ -266,6 +268,7 @@ import {
|
|
|
266
268
|
} from "./trust-zones.js";
|
|
267
269
|
import { tryDirectAnswer, type DirectAnswerSources } from "./direct-answer-wiring.js";
|
|
268
270
|
import {
|
|
271
|
+
resolveNamespaceCapabilities,
|
|
269
272
|
resolveCapabilities,
|
|
270
273
|
resolveGraphConstructionCapabilities,
|
|
271
274
|
resolveMemoryLifecycleCapabilities,
|
|
@@ -276,7 +279,10 @@ import {
|
|
|
276
279
|
type MemoryLifecycleCapabilitySet,
|
|
277
280
|
type IndexingCapabilitySet,
|
|
278
281
|
type CreationMemoryCapabilitySet,
|
|
279
|
-
|
|
282
|
+
resolveQmdCapabilities,
|
|
283
|
+
resolveIdentityContinuityCapabilities,
|
|
284
|
+
resolveLocalLlmCapabilities,
|
|
285
|
+
resolveSecurityCapabilities, resolveEvalCapabilities, resolveUtilityLearningCapabilities, resolveObjectiveStateCapabilities, resolveCompressionCapabilities} from "./capabilities.js";
|
|
280
286
|
import { DEFAULT_TAXONOMY } from "./taxonomy/index.js";
|
|
281
287
|
import {
|
|
282
288
|
searchHarmonicRetrieval,
|
|
@@ -1896,6 +1902,8 @@ export class Orchestrator {
|
|
|
1896
1902
|
readonly tierMigrationStatus: TierMigrationStatusStore;
|
|
1897
1903
|
readonly tierMigrationCoordinator: TierMigrationCoordinator;
|
|
1898
1904
|
readonly compressionGuidelineCoordinator: CompressionGuidelineCoordinator;
|
|
1905
|
+
readonly semanticConsolidationCoordinator: SemanticConsolidationCoordinator;
|
|
1906
|
+
readonly lifecyclePolicyCoordinator: LifecyclePolicyCoordinator;
|
|
1899
1907
|
/**
|
|
1900
1908
|
* In-memory X-ray snapshot from the most recent `recall()` call that
|
|
1901
1909
|
* was invoked with `xrayCapture: true` (issue #570 PR 1). Scope is
|
|
@@ -2251,7 +2259,7 @@ export class Orchestrator {
|
|
|
2251
2259
|
* @internal
|
|
2252
2260
|
*/
|
|
2253
2261
|
applyCodingNamespaceOverlay(sessionKey: string | undefined, baseNamespace: string): string {
|
|
2254
|
-
if (!this.config.
|
|
2262
|
+
if (!resolveNamespaceCapabilities(this.config).namespaces) return baseNamespace;
|
|
2255
2263
|
const codingContext = this.getCodingContextForSession(sessionKey);
|
|
2256
2264
|
const overlay = resolveCodingNamespaceOverlay(codingContext, this.config.codingMode, this.config.defaultNamespace);
|
|
2257
2265
|
if (!overlay) return baseNamespace;
|
|
@@ -2331,7 +2339,7 @@ export class Orchestrator {
|
|
|
2331
2339
|
* @internal
|
|
2332
2340
|
*/
|
|
2333
2341
|
applyCodingRecallOverlay(sessionKey: string | undefined): { namespace: string; readFallbacks: string[] } | null {
|
|
2334
|
-
if (!this.config.
|
|
2342
|
+
if (!resolveNamespaceCapabilities(this.config).namespaces) return null;
|
|
2335
2343
|
const codingContext = this.getCodingContextForSession(sessionKey);
|
|
2336
2344
|
const overlay = resolveCodingNamespaceOverlay(codingContext, this.config.codingMode, this.config.defaultNamespace);
|
|
2337
2345
|
if (!overlay) return null;
|
|
@@ -2354,7 +2362,7 @@ export class Orchestrator {
|
|
|
2354
2362
|
}
|
|
2355
2363
|
|
|
2356
2364
|
private rememberNamespaceStorageDirHint(namespace: string, storageDir?: string): void {
|
|
2357
|
-
if (!this.config.
|
|
2365
|
+
if (!resolveNamespaceCapabilities(this.config).namespaces || !storageDir) return;
|
|
2358
2366
|
const ns = normalizeNamespaceIdentity(namespace);
|
|
2359
2367
|
if (!ns) return;
|
|
2360
2368
|
const defaultNs = normalizeNamespaceIdentity(this.config.defaultNamespace);
|
|
@@ -2558,10 +2566,10 @@ export class Orchestrator {
|
|
|
2558
2566
|
private buildConfiguredQmdSearchOptions(
|
|
2559
2567
|
queryText: string,
|
|
2560
2568
|
): SearchQueryOptions | undefined {
|
|
2561
|
-
const intentHint = this.config.
|
|
2569
|
+
const intentHint = resolveQmdCapabilities(this.config).qmdIntentHints
|
|
2562
2570
|
? buildQmdIntentHint(inferIntentFromText(queryText))
|
|
2563
2571
|
: undefined;
|
|
2564
|
-
const explain = this.config.
|
|
2572
|
+
const explain = resolveQmdCapabilities(this.config).qmdExplain === true;
|
|
2565
2573
|
const searchOptions: SearchQueryOptions = {};
|
|
2566
2574
|
if (intentHint) {
|
|
2567
2575
|
searchOptions.intent = intentHint;
|
|
@@ -2581,13 +2589,13 @@ export class Orchestrator {
|
|
|
2581
2589
|
execution?: SearchExecutionOptions;
|
|
2582
2590
|
}): Promise<QmdSearchResult[]> {
|
|
2583
2591
|
if (
|
|
2584
|
-
this.config.
|
|
2592
|
+
resolveNamespaceCapabilities(this.config).namespaces &&
|
|
2585
2593
|
options.namespaces !== undefined &&
|
|
2586
2594
|
options.namespaces.length === 0
|
|
2587
2595
|
) {
|
|
2588
2596
|
return [];
|
|
2589
2597
|
}
|
|
2590
|
-
const namespaces = this.config.
|
|
2598
|
+
const namespaces = resolveNamespaceCapabilities(this.config).namespaces
|
|
2591
2599
|
? Array.from(
|
|
2592
2600
|
new Set(
|
|
2593
2601
|
(options.namespaces?.length
|
|
@@ -2600,7 +2608,7 @@ export class Orchestrator {
|
|
|
2600
2608
|
)
|
|
2601
2609
|
: [this.config.defaultNamespace];
|
|
2602
2610
|
|
|
2603
|
-
if (!this.config.
|
|
2611
|
+
if (!resolveNamespaceCapabilities(this.config).namespaces) {
|
|
2604
2612
|
switch (options.mode) {
|
|
2605
2613
|
case "hybrid":
|
|
2606
2614
|
return await this.qmd.hybridSearch(
|
|
@@ -2652,7 +2660,7 @@ export class Orchestrator {
|
|
|
2652
2660
|
}
|
|
2653
2661
|
|
|
2654
2662
|
private isSearchAvailableForNamespaceRouting(): boolean {
|
|
2655
|
-
if (this.config.
|
|
2663
|
+
if (resolveNamespaceCapabilities(this.config).namespaces) return true;
|
|
2656
2664
|
return this.qmd.isAvailable();
|
|
2657
2665
|
}
|
|
2658
2666
|
|
|
@@ -3019,6 +3027,7 @@ export class Orchestrator {
|
|
|
3019
3027
|
fastChatCompletion: (messages, options) =>
|
|
3020
3028
|
this.fastChatCompletion(messages, options),
|
|
3021
3029
|
});
|
|
3030
|
+
|
|
3022
3031
|
this.sessionObserver = new SessionObserverState({
|
|
3023
3032
|
memoryDir: config.memoryDir,
|
|
3024
3033
|
debounceMs: config.sessionObserverDebounceMs ?? 120_000,
|
|
@@ -3061,6 +3070,15 @@ export class Orchestrator {
|
|
|
3061
3070
|
return client;
|
|
3062
3071
|
})()
|
|
3063
3072
|
: this.localLlm;
|
|
3073
|
+
this.semanticConsolidationCoordinator = new SemanticConsolidationCoordinator({
|
|
3074
|
+
config,
|
|
3075
|
+
getStorage: () => this.storage,
|
|
3076
|
+
getFastLlm: () => this.fastLlm,
|
|
3077
|
+
embeddingFallback: this.embeddingFallback,
|
|
3078
|
+
removeContentHashForMemory: (targetStorage, memory, context) =>
|
|
3079
|
+
this.removeContentHashForMemory(targetStorage, memory, context),
|
|
3080
|
+
saveContentHashIndexes: () => this.saveContentHashIndexes(),
|
|
3081
|
+
});
|
|
3064
3082
|
// Initialize gateway fast LLM for fast-tier ops when modelSource is "gateway"
|
|
3065
3083
|
this._fastGatewayLlm = config.modelSource === "gateway"
|
|
3066
3084
|
? new FallbackLlmClient(
|
|
@@ -3082,6 +3100,16 @@ export class Orchestrator {
|
|
|
3082
3100
|
config.gatewayConfig,
|
|
3083
3101
|
this.modelRegistry,
|
|
3084
3102
|
);
|
|
3103
|
+
this.lifecyclePolicyCoordinator = new LifecyclePolicyCoordinator({
|
|
3104
|
+
config,
|
|
3105
|
+
getStorage: () => this.storage,
|
|
3106
|
+
extraction: this.extraction,
|
|
3107
|
+
embeddingFallback: this.embeddingFallback,
|
|
3108
|
+
getEffectiveLifecycleThresholds: () => this.effectiveLifecycleThresholds(),
|
|
3109
|
+
removeContentHashForMemory: (targetStorage, memory, context) =>
|
|
3110
|
+
this.removeContentHashForMemory(targetStorage, memory, context),
|
|
3111
|
+
saveContentHashIndexes: () => this.saveContentHashIndexes(),
|
|
3112
|
+
});
|
|
3085
3113
|
this.threading = new ThreadingManager(
|
|
3086
3114
|
path.join(config.memoryDir, "threads"),
|
|
3087
3115
|
config.threadingGapMinutes,
|
|
@@ -3224,7 +3252,7 @@ export class Orchestrator {
|
|
|
3224
3252
|
}
|
|
3225
3253
|
|
|
3226
3254
|
private routeEngineOptions(): RoutingEngineOptions {
|
|
3227
|
-
const allowedNamespaces = this.config.
|
|
3255
|
+
const allowedNamespaces = resolveNamespaceCapabilities(this.config).namespaces
|
|
3228
3256
|
? Array.from(
|
|
3229
3257
|
new Set([
|
|
3230
3258
|
this.config.defaultNamespace,
|
|
@@ -3418,7 +3446,7 @@ export class Orchestrator {
|
|
|
3418
3446
|
? this._fastGatewayLlm?.isAvailable(
|
|
3419
3447
|
this.config.fastGatewayAgentId || this.config.gatewayAgentId || undefined,
|
|
3420
3448
|
) === true
|
|
3421
|
-
: this.config.
|
|
3449
|
+
: resolveLocalLlmCapabilities(this.config).localLlm;
|
|
3422
3450
|
if (!chainAvailable) return undefined;
|
|
3423
3451
|
return buildChainFollowupGenerator(this.fastLlmForRerank);
|
|
3424
3452
|
}
|
|
@@ -3440,7 +3468,7 @@ export class Orchestrator {
|
|
|
3440
3468
|
});
|
|
3441
3469
|
await this.storage.ensureDirectories();
|
|
3442
3470
|
await this.storage.loadAliases();
|
|
3443
|
-
if (this.config.
|
|
3471
|
+
if (resolveNamespaceCapabilities(this.config).namespaces) {
|
|
3444
3472
|
const namespaces = new Set<string>([
|
|
3445
3473
|
this.config.defaultNamespace,
|
|
3446
3474
|
this.config.sharedNamespace,
|
|
@@ -3494,8 +3522,8 @@ export class Orchestrator {
|
|
|
3494
3522
|
this.runtimePolicyValues = await this.policyRuntime.loadRuntimeValues();
|
|
3495
3523
|
this.utilityRuntimeValues = await loadUtilityRuntimeValues({
|
|
3496
3524
|
memoryDir: this.config.memoryDir,
|
|
3497
|
-
memoryUtilityLearningEnabled: this.config.
|
|
3498
|
-
promotionByOutcomeEnabled: this.config.
|
|
3525
|
+
memoryUtilityLearningEnabled: resolveUtilityLearningCapabilities(this.config).memoryUtilityLearning,
|
|
3526
|
+
promotionByOutcomeEnabled: resolveUtilityLearningCapabilities(this.config).promotionByOutcome,
|
|
3499
3527
|
});
|
|
3500
3528
|
|
|
3501
3529
|
// Initialize content-hash dedup index
|
|
@@ -3560,14 +3588,14 @@ export class Orchestrator {
|
|
|
3560
3588
|
// after a restart. `registerConfiguredNamespaces()` already seeded the
|
|
3561
3589
|
// catalog above, so `maintenanceNamespaces()` is readable here; it falls
|
|
3562
3590
|
// back to the configured set on any catalog read failure.
|
|
3563
|
-
const namespaces = this.config.
|
|
3591
|
+
const namespaces = resolveNamespaceCapabilities(this.config).namespaces
|
|
3564
3592
|
? await this.maintenanceNamespaces()
|
|
3565
3593
|
: [this.config.defaultNamespace];
|
|
3566
3594
|
const states = await Promise.all(
|
|
3567
3595
|
namespaces.map(async (namespace) => {
|
|
3568
3596
|
const collectionCheckAbort = new AbortController();
|
|
3569
3597
|
const state = await qmdStartupCollectionCheckWithTimeout(
|
|
3570
|
-
this.config.
|
|
3598
|
+
resolveNamespaceCapabilities(this.config).namespaces
|
|
3571
3599
|
? this.namespaceSearchRouter.ensureNamespaceCollection(
|
|
3572
3600
|
namespace,
|
|
3573
3601
|
{ signal: collectionCheckAbort.signal },
|
|
@@ -3681,10 +3709,10 @@ export class Orchestrator {
|
|
|
3681
3709
|
// triggered update — which can be days ago if the daemon restarted without
|
|
3682
3710
|
// new extractions. This is the root cause of "0 memories" recall results
|
|
3683
3711
|
// despite thousands of facts on disk.
|
|
3684
|
-
if (this.qmd.isAvailable() && this.config.
|
|
3712
|
+
if (this.qmd.isAvailable() && resolveQmdCapabilities(this.config).qmdMaintenance) {
|
|
3685
3713
|
try {
|
|
3686
3714
|
log.info("QMD startup sync: updating index to match current disk state");
|
|
3687
|
-
if (this.config.
|
|
3715
|
+
if (resolveNamespaceCapabilities(this.config).namespaces) {
|
|
3688
3716
|
// Cover cataloged dynamic namespaces at startup too (NHZEV, codex P2):
|
|
3689
3717
|
// a dynamic namespace written before a daemon restart must be synced on
|
|
3690
3718
|
// boot, not only by the debounced runQmdMaintenance() path. Same union +
|
|
@@ -3788,7 +3816,7 @@ export class Orchestrator {
|
|
|
3788
3816
|
|
|
3789
3817
|
if (signal.aborted) return;
|
|
3790
3818
|
|
|
3791
|
-
if (this.config.
|
|
3819
|
+
if (resolveLocalLlmCapabilities(this.config).localLlm) {
|
|
3792
3820
|
try {
|
|
3793
3821
|
await this.validateLocalLlmModel();
|
|
3794
3822
|
} catch (err) {
|
|
@@ -3813,7 +3841,7 @@ export class Orchestrator {
|
|
|
3813
3841
|
// sweep (capped at 50 demotions) so the hot tier isn't flooded on the
|
|
3814
3842
|
// first real cron pass. Non-fatal — a failure here must not break init.
|
|
3815
3843
|
if (signal.aborted) return;
|
|
3816
|
-
if (lifecycleCaps.lifecyclePolicy && this.config.
|
|
3844
|
+
if (lifecycleCaps.lifecyclePolicy && resolveQmdCapabilities(this.config).qmdTierMigration) {
|
|
3817
3845
|
try {
|
|
3818
3846
|
const { runFirstStartMigration } = await import(
|
|
3819
3847
|
"./maintenance/first-start-migration.js"
|
|
@@ -3918,7 +3946,7 @@ export class Orchestrator {
|
|
|
3918
3946
|
log.info(`startupSearchSync: backend now available ${this.qmd.debugStatus()}`);
|
|
3919
3947
|
|
|
3920
3948
|
// Clear namespace router cache so re-probe picks up newly available backends
|
|
3921
|
-
if (this.config.
|
|
3949
|
+
if (resolveNamespaceCapabilities(this.config).namespaces) {
|
|
3922
3950
|
this.namespaceSearchRouter.clearCache();
|
|
3923
3951
|
}
|
|
3924
3952
|
|
|
@@ -3930,14 +3958,14 @@ export class Orchestrator {
|
|
|
3930
3958
|
// re-synced here too, otherwise after a backend-was-unavailable-at-boot
|
|
3931
3959
|
// recovery its collection stays stale. Falls back to the configured set on any
|
|
3932
3960
|
// catalog read failure.
|
|
3933
|
-
const namespaces = this.config.
|
|
3961
|
+
const namespaces = resolveNamespaceCapabilities(this.config).namespaces
|
|
3934
3962
|
? await this.maintenanceNamespaces()
|
|
3935
3963
|
: [this.config.defaultNamespace];
|
|
3936
3964
|
|
|
3937
3965
|
const states = await Promise.all(
|
|
3938
3966
|
namespaces.map(async (namespace) => ({
|
|
3939
3967
|
namespace,
|
|
3940
|
-
state: this.config.
|
|
3968
|
+
state: resolveNamespaceCapabilities(this.config).namespaces
|
|
3941
3969
|
? await this.namespaceSearchRouter.ensureNamespaceCollection(namespace, { signal })
|
|
3942
3970
|
: await this.qmd.ensureCollection(this.config.memoryDir, this.config.qmdCollection, { signal }),
|
|
3943
3971
|
})),
|
|
@@ -3972,7 +4000,7 @@ export class Orchestrator {
|
|
|
3972
4000
|
// and didn't fail silently.
|
|
3973
4001
|
// The abort signal is forwarded into the QMD subprocess call so the
|
|
3974
4002
|
// long-running `qmd update` process is killed promptly on shutdown.
|
|
3975
|
-
if (this.config.
|
|
4003
|
+
if (resolveQmdCapabilities(this.config).qmdMaintenance) {
|
|
3976
4004
|
try {
|
|
3977
4005
|
const failTsBefore = "lastUpdateFailedAtMs" in this.qmd
|
|
3978
4006
|
? (this.qmd as any).lastUpdateFailedAtMs as number | null
|
|
@@ -3983,7 +4011,7 @@ export class Orchestrator {
|
|
|
3983
4011
|
}
|
|
3984
4012
|
log.info("startupSearchSync: updating index to match current disk state");
|
|
3985
4013
|
let namespacesUpdated = 0;
|
|
3986
|
-
if (this.config.
|
|
4014
|
+
if (resolveNamespaceCapabilities(this.config).namespaces) {
|
|
3987
4015
|
namespacesUpdated = await this.namespaceSearchRouter.updateNamespaces(
|
|
3988
4016
|
namespaces,
|
|
3989
4017
|
{ signal },
|
|
@@ -4005,7 +4033,7 @@ export class Orchestrator {
|
|
|
4005
4033
|
log.warn("startupSearchSync: update silently failed (detected via fail timestamp)");
|
|
4006
4034
|
return false;
|
|
4007
4035
|
}
|
|
4008
|
-
if (this.config.
|
|
4036
|
+
if (resolveNamespaceCapabilities(this.config).namespaces) {
|
|
4009
4037
|
if (namespacesUpdated === 0) {
|
|
4010
4038
|
log.warn("startupSearchSync: no namespace backends were eligible for update (all unavailable or collections missing)");
|
|
4011
4039
|
return false;
|
|
@@ -4374,372 +4402,17 @@ export class Orchestrator {
|
|
|
4374
4402
|
return summarizeGovernanceResultForDreams(govResult, options?.dryRun === true);
|
|
4375
4403
|
}
|
|
4376
4404
|
|
|
4405
|
+
// Issue #1526 (seam 5): semantic consolidation moved to
|
|
4406
|
+
// SemanticConsolidationCoordinator. Thin delegation keeps all
|
|
4407
|
+
// call sites (runConsolidation, runSemanticConsolidationNow,
|
|
4408
|
+
// runSemanticConsolidationFanout) stable.
|
|
4377
4409
|
private async runSemanticConsolidation(options?: {
|
|
4378
4410
|
dryRun?: boolean;
|
|
4379
4411
|
thresholdOverride?: number;
|
|
4380
4412
|
force?: boolean;
|
|
4381
4413
|
storage?: StorageManager;
|
|
4382
4414
|
}): Promise<SemanticConsolidationResult> {
|
|
4383
|
-
|
|
4384
|
-
const result: SemanticConsolidationResult = {
|
|
4385
|
-
clustersFound: 0,
|
|
4386
|
-
memoriesConsolidated: 0,
|
|
4387
|
-
memoriesArchived: 0,
|
|
4388
|
-
errors: 0,
|
|
4389
|
-
clusters: [],
|
|
4390
|
-
};
|
|
4391
|
-
|
|
4392
|
-
if (!this.config.semanticConsolidationEnabled && !options?.force) {
|
|
4393
|
-
log.debug("[semantic-consolidation] disabled in config");
|
|
4394
|
-
return result;
|
|
4395
|
-
}
|
|
4396
|
-
|
|
4397
|
-
log.info("[semantic-consolidation] starting run");
|
|
4398
|
-
|
|
4399
|
-
const allMemories = await targetStorage.readAllMemories();
|
|
4400
|
-
if (allMemories.length < 10) {
|
|
4401
|
-
log.debug("[semantic-consolidation] too few memories, skipping");
|
|
4402
|
-
return result;
|
|
4403
|
-
}
|
|
4404
|
-
|
|
4405
|
-
const threshold =
|
|
4406
|
-
options?.thresholdOverride ?? this.config.semanticConsolidationThreshold;
|
|
4407
|
-
const clusters = findSimilarClusters(allMemories, {
|
|
4408
|
-
threshold,
|
|
4409
|
-
minClusterSize: this.config.semanticConsolidationMinClusterSize,
|
|
4410
|
-
excludeCategories: this.config.semanticConsolidationExcludeCategories,
|
|
4411
|
-
maxPerRun: this.config.semanticConsolidationMaxPerRun,
|
|
4412
|
-
});
|
|
4413
|
-
|
|
4414
|
-
result.clustersFound = clusters.length;
|
|
4415
|
-
result.clusters = clusters;
|
|
4416
|
-
|
|
4417
|
-
if (clusters.length === 0) {
|
|
4418
|
-
log.info("[semantic-consolidation] no clusters found");
|
|
4419
|
-
return result;
|
|
4420
|
-
}
|
|
4421
|
-
|
|
4422
|
-
log.info(`[semantic-consolidation] found ${clusters.length} cluster(s)`);
|
|
4423
|
-
|
|
4424
|
-
if (options?.dryRun) {
|
|
4425
|
-
log.info(
|
|
4426
|
-
"[semantic-consolidation] dry run — skipping LLM synthesis and archival",
|
|
4427
|
-
);
|
|
4428
|
-
return result;
|
|
4429
|
-
}
|
|
4430
|
-
|
|
4431
|
-
// Use FallbackLlmClient for LLM calls (same pattern as causal-consolidation.ts)
|
|
4432
|
-
// Honor semanticConsolidationModel: "auto" = primary, "fast" = local fast, or specific model
|
|
4433
|
-
const { FallbackLlmClient, gatewayTaskChainOptions } = await import("./fallback-llm.js");
|
|
4434
|
-
const useGateway = this.config.modelSource === "gateway";
|
|
4435
|
-
const modelSetting = this.config.semanticConsolidationModel;
|
|
4436
|
-
if (modelSetting === "fast" && this.fastLlm && !useGateway) {
|
|
4437
|
-
log.info("[semantic-consolidation] using fast local LLM for synthesis");
|
|
4438
|
-
}
|
|
4439
|
-
// Gateway routing: an explicit "fast" setting keeps the fast persona chain
|
|
4440
|
-
// (the operator's deliberate fast-tier choice). Otherwise route through the
|
|
4441
|
-
// shared task-chain resolution so taskModelChain applies to semantic
|
|
4442
|
-
// consolidation like every other background task (gotcha #22). Issue #1365.
|
|
4443
|
-
const gatewayChainOptions: { modelChain?: AgentPersonaModelConfig; agentId?: string } =
|
|
4444
|
-
!useGateway
|
|
4445
|
-
? {}
|
|
4446
|
-
: modelSetting === "fast"
|
|
4447
|
-
? (this.config.fastGatewayAgentId
|
|
4448
|
-
? { agentId: this.config.fastGatewayAgentId }
|
|
4449
|
-
: this.config.gatewayAgentId
|
|
4450
|
-
? { agentId: this.config.gatewayAgentId }
|
|
4451
|
-
: {})
|
|
4452
|
-
: gatewayTaskChainOptions(this.config);
|
|
4453
|
-
const llm = new FallbackLlmClient(
|
|
4454
|
-
this.config.gatewayConfig,
|
|
4455
|
-
fallbackLlmRuntimeContextFromConfig(this.config),
|
|
4456
|
-
);
|
|
4457
|
-
if (!llm.isAvailable(gatewayChainOptions) && !(modelSetting === "fast" && this.fastLlm && !useGateway)) {
|
|
4458
|
-
log.warn(
|
|
4459
|
-
"[semantic-consolidation] no LLM available — skipping synthesis",
|
|
4460
|
-
);
|
|
4461
|
-
return result;
|
|
4462
|
-
}
|
|
4463
|
-
|
|
4464
|
-
// Discover memory extensions once for all clusters (#382)
|
|
4465
|
-
let extensionsBlock = "";
|
|
4466
|
-
try {
|
|
4467
|
-
extensionsBlock = await buildExtensionsBlockForConsolidation(this.config);
|
|
4468
|
-
} catch (err) {
|
|
4469
|
-
log.warn(`[semantic-consolidation] extension discovery failed (non-fatal): ${err instanceof Error ? err.message : String(err)}`);
|
|
4470
|
-
}
|
|
4471
|
-
|
|
4472
|
-
for (const cluster of clusters) {
|
|
4473
|
-
let canonicalWriteCompleted = false;
|
|
4474
|
-
try {
|
|
4475
|
-
// Operator-aware prompt (issue #561 PR 3): ask the LLM to pick the
|
|
4476
|
-
// SPLIT/MERGE/UPDATE operator alongside the canonical output. Falls
|
|
4477
|
-
// back to the legacy plain-blob prompt when operator-aware
|
|
4478
|
-
// consolidation is explicitly disabled via config, so rollbacks stay
|
|
4479
|
-
// clean.
|
|
4480
|
-
// Use the `=== true` idiom for default-false flags (PR #632
|
|
4481
|
-
// review, cursor Low): sibling disabled-by-default flags like
|
|
4482
|
-
// `semanticConsolidationEnabled` follow the same convention,
|
|
4483
|
-
// while `!== false` is reserved for default-on flags.
|
|
4484
|
-
const operatorAwareEnabled =
|
|
4485
|
-
this.config.operatorAwareConsolidationEnabled === true;
|
|
4486
|
-
let prompt = operatorAwareEnabled
|
|
4487
|
-
? buildOperatorAwareConsolidationPrompt(cluster)
|
|
4488
|
-
: buildConsolidationPrompt(cluster);
|
|
4489
|
-
if (extensionsBlock.length > 0) {
|
|
4490
|
-
prompt += "\n\n" + extensionsBlock;
|
|
4491
|
-
}
|
|
4492
|
-
const messages = [
|
|
4493
|
-
{
|
|
4494
|
-
role: "system" as const,
|
|
4495
|
-
content: operatorAwareEnabled
|
|
4496
|
-
? 'You are a memory consolidation system. Return ONLY a JSON object with two keys, "operator" and "output". The "operator" value MUST be one of the exact strings "merge", "update", or "split" — never a pipe-separated placeholder, never prose. The "output" value is the canonical memory text.'
|
|
4497
|
-
: "You are a memory consolidation system. Output only the consolidated memory text.",
|
|
4498
|
-
},
|
|
4499
|
-
{ role: "user" as const, content: prompt },
|
|
4500
|
-
];
|
|
4501
|
-
const llmOpts = { temperature: 0.2, maxTokens: 2000 };
|
|
4502
|
-
|
|
4503
|
-
// Route to the configured model
|
|
4504
|
-
let response: { content: string } | null = null;
|
|
4505
|
-
if (useGateway) {
|
|
4506
|
-
// Gateway model source — use the appropriate agent chain
|
|
4507
|
-
response = await llm.chatCompletion(messages, { ...llmOpts, ...gatewayChainOptions });
|
|
4508
|
-
} else if (modelSetting === "fast" && this.fastLlm) {
|
|
4509
|
-
const fastResult = await this.fastLlm.chatCompletion(messages, {
|
|
4510
|
-
operation: "semantic-consolidation",
|
|
4511
|
-
maxTokens: llmOpts.maxTokens,
|
|
4512
|
-
temperature: llmOpts.temperature,
|
|
4513
|
-
priority: "background",
|
|
4514
|
-
forceDisableThinking: true,
|
|
4515
|
-
});
|
|
4516
|
-
response = fastResult ? { content: fastResult.content } : null;
|
|
4517
|
-
} else {
|
|
4518
|
-
response = await llm.chatCompletion(messages, llmOpts);
|
|
4519
|
-
}
|
|
4520
|
-
|
|
4521
|
-
if (!response?.content) {
|
|
4522
|
-
log.warn(
|
|
4523
|
-
`[semantic-consolidation] empty LLM response for cluster in "${cluster.category}"`,
|
|
4524
|
-
);
|
|
4525
|
-
result.errors++;
|
|
4526
|
-
continue;
|
|
4527
|
-
}
|
|
4528
|
-
|
|
4529
|
-
// Operator-aware parse (issue #561 PR 3). In legacy mode we fall
|
|
4530
|
-
// back to the plain-text parser and derive the operator from the
|
|
4531
|
-
// cluster-shape heuristic so `derived_via` still lands.
|
|
4532
|
-
// Restricted to `SemanticConsolidationLlmOperator`
|
|
4533
|
-
// (split/merge/update) — `pattern-reinforcement` joined the
|
|
4534
|
-
// wider `ConsolidationOperator` type in #687 PR 2/4 but is
|
|
4535
|
-
// reserved for the maintenance job and must never be assignable
|
|
4536
|
-
// here (Cursor Bugbot review, PR #730).
|
|
4537
|
-
let canonicalContent: string;
|
|
4538
|
-
let operator: SemanticConsolidationLlmOperator;
|
|
4539
|
-
if (operatorAwareEnabled) {
|
|
4540
|
-
const parsed = parseOperatorAwareConsolidationResponse(
|
|
4541
|
-
response.content,
|
|
4542
|
-
cluster,
|
|
4543
|
-
);
|
|
4544
|
-
canonicalContent = parsed.output;
|
|
4545
|
-
operator = parsed.operator;
|
|
4546
|
-
} else {
|
|
4547
|
-
canonicalContent = parseConsolidationResponse(response.content);
|
|
4548
|
-
operator = chooseConsolidationOperator(cluster);
|
|
4549
|
-
}
|
|
4550
|
-
cluster.canonicalContent = canonicalContent;
|
|
4551
|
-
|
|
4552
|
-
// Pick the most recent memory's metadata as the basis for lineage
|
|
4553
|
-
const sorted = [...cluster.memories].sort(
|
|
4554
|
-
(a, b) =>
|
|
4555
|
-
new Date(b.frontmatter.created).getTime() -
|
|
4556
|
-
new Date(a.frontmatter.created).getTime(),
|
|
4557
|
-
);
|
|
4558
|
-
const newest = sorted[0];
|
|
4559
|
-
const lineageIds = cluster.memories.map((m) => m.frontmatter.id);
|
|
4560
|
-
|
|
4561
|
-
// Consolidation provenance (issue #561 PR 2+3): snapshot each
|
|
4562
|
-
// source memory BEFORE archiving it, collecting
|
|
4563
|
-
// "<relpath>:<versionId>" pointers for the new canonical memory's
|
|
4564
|
-
// `derived_from` frontmatter field. Snapshots are best-effort — if
|
|
4565
|
-
// page-versioning is disabled (default in `config.ts`) or a single
|
|
4566
|
-
// source fails to snapshot we simply omit that entry rather than
|
|
4567
|
-
// abort the consolidation. The `derived_via` operator is chosen
|
|
4568
|
-
// above (PR 3) from the LLM response or the cluster-shape
|
|
4569
|
-
// heuristic fallback and emitted unconditionally so consolidation
|
|
4570
|
-
// outputs stay identifiable even when no snapshots are captured
|
|
4571
|
-
// (PR #624 review feedback).
|
|
4572
|
-
const derivedFromEntries: string[] = [];
|
|
4573
|
-
for (const m of cluster.memories) {
|
|
4574
|
-
if (!m.path) continue;
|
|
4575
|
-
const entry = await targetStorage.snapshotForProvenance(m.path);
|
|
4576
|
-
if (entry) derivedFromEntries.push(entry);
|
|
4577
|
-
}
|
|
4578
|
-
|
|
4579
|
-
// Write the canonical memory
|
|
4580
|
-
const { id: canonicalId, tombstoneBlocked: canonicalBlocked } = await targetStorage.writeMemory(
|
|
4581
|
-
newest.frontmatter.category,
|
|
4582
|
-
canonicalContent,
|
|
4583
|
-
{
|
|
4584
|
-
actor: "semantic-consolidation",
|
|
4585
|
-
confidence: newest.frontmatter.confidence,
|
|
4586
|
-
tags: [
|
|
4587
|
-
...new Set(
|
|
4588
|
-
cluster.memories.flatMap((m) => m.frontmatter.tags ?? []),
|
|
4589
|
-
),
|
|
4590
|
-
],
|
|
4591
|
-
source: "semantic-consolidation",
|
|
4592
|
-
lineage: lineageIds,
|
|
4593
|
-
derivedFrom: derivedFromEntries.length > 0 ? derivedFromEntries : undefined,
|
|
4594
|
-
derivedVia: operator,
|
|
4595
|
-
},
|
|
4596
|
-
);
|
|
4597
|
-
if (canonicalBlocked) {
|
|
4598
|
-
// #1645: canonical matched a tombstone (pending_review). Don't archive
|
|
4599
|
-
// the sources — consolidation must never delete the only active copy.
|
|
4600
|
-
log.info(`[semantic-consolidation] cluster in "${cluster.category}" tombstone-blocked — keeping ${cluster.memories.length} source(s) active (pending_review ${canonicalId})`);
|
|
4601
|
-
continue;
|
|
4602
|
-
}
|
|
4603
|
-
canonicalWriteCompleted = true;
|
|
4604
|
-
|
|
4605
|
-
result.memoriesConsolidated++;
|
|
4606
|
-
|
|
4607
|
-
// Archive originals
|
|
4608
|
-
for (const m of cluster.memories) {
|
|
4609
|
-
const archiveResult = await targetStorage.archiveMemory(m, {
|
|
4610
|
-
actor: "semantic-consolidation",
|
|
4611
|
-
reasonCode: "semantic-consolidation",
|
|
4612
|
-
relatedMemoryIds: [canonicalId],
|
|
4613
|
-
});
|
|
4614
|
-
if (archiveResult) {
|
|
4615
|
-
// Remove from the same storage-scoped content-hash index that
|
|
4616
|
-
// originally deduped this memory.
|
|
4617
|
-
await this.removeContentHashForMemory(
|
|
4618
|
-
targetStorage,
|
|
4619
|
-
m,
|
|
4620
|
-
"semantic-consolidation",
|
|
4621
|
-
);
|
|
4622
|
-
// Best-effort index cleanup: a failure here (e.g. on-disk index save
|
|
4623
|
-
// under disk-full) must NOT abort the archival loop and thereby skip
|
|
4624
|
-
// the catalog write touch below for an already-durable canonical write
|
|
4625
|
-
// (kilo NV0mh).
|
|
4626
|
-
try {
|
|
4627
|
-
await this.embeddingFallback.removeFromIndex(m.frontmatter.id);
|
|
4628
|
-
if (
|
|
4629
|
-
resolveIndexingCapabilities(this.config).queryAwareIndexing &&
|
|
4630
|
-
m.path &&
|
|
4631
|
-
m.frontmatter?.created
|
|
4632
|
-
) {
|
|
4633
|
-
deindexMemory(
|
|
4634
|
-
targetStorage.dir,
|
|
4635
|
-
m.path,
|
|
4636
|
-
m.frontmatter.created,
|
|
4637
|
-
m.frontmatter.tags ?? [],
|
|
4638
|
-
);
|
|
4639
|
-
}
|
|
4640
|
-
} catch (cleanupErr) {
|
|
4641
|
-
log.warn(
|
|
4642
|
-
`[semantic-consolidation] index cleanup failed (non-fatal): ${cleanupErr}`,
|
|
4643
|
-
);
|
|
4644
|
-
}
|
|
4645
|
-
result.memoriesArchived++;
|
|
4646
|
-
}
|
|
4647
|
-
}
|
|
4648
|
-
|
|
4649
|
-
log.info(
|
|
4650
|
-
`[semantic-consolidation] consolidated ${cluster.memories.length} memories → ${canonicalId}`,
|
|
4651
|
-
);
|
|
4652
|
-
} catch (err) {
|
|
4653
|
-
log.warn(
|
|
4654
|
-
`[semantic-consolidation] cluster processing failed: ${err instanceof Error ? err.message : String(err)}`,
|
|
4655
|
-
);
|
|
4656
|
-
result.errors++;
|
|
4657
|
-
} finally {
|
|
4658
|
-
if (canonicalWriteCompleted) {
|
|
4659
|
-
// Catalog write touch (issue #1499 sweep): record after the canonical
|
|
4660
|
-
// write and, on the happy path, after archival of superseded cluster
|
|
4661
|
-
// memories, so `lastWriteAt` reflects every durable mutation in this
|
|
4662
|
-
// consolidation (cursor NUtCK). The `finally` also covers partial
|
|
4663
|
-
// failures where the canonical memory was written but a later archive
|
|
4664
|
-
// step throws and the cluster catch continues (codex NY-dK).
|
|
4665
|
-
// Best-effort; namespace decoded from the storage dir since this path
|
|
4666
|
-
// #1522: catalog touch handled at the storage chokepoint.
|
|
4667
|
-
}
|
|
4668
|
-
}
|
|
4669
|
-
}
|
|
4670
|
-
|
|
4671
|
-
// Save hash indexes if we modified them.
|
|
4672
|
-
if (result.memoriesArchived > 0) {
|
|
4673
|
-
await this.saveContentHashIndexes().catch((err) =>
|
|
4674
|
-
log.warn(
|
|
4675
|
-
`[semantic-consolidation] content-hash index save failed: ${err}`,
|
|
4676
|
-
),
|
|
4677
|
-
);
|
|
4678
|
-
}
|
|
4679
|
-
|
|
4680
|
-
log.info(
|
|
4681
|
-
`[semantic-consolidation] complete: clusters=${result.clustersFound}, consolidated=${result.memoriesConsolidated}, archived=${result.memoriesArchived}, errors=${result.errors}`,
|
|
4682
|
-
);
|
|
4683
|
-
|
|
4684
|
-
// #378: fire the Codex materialize post-hook so `codexMaterializeOnConsolidation`
|
|
4685
|
-
// actually has a runtime effect. The helper silently no-ops when the
|
|
4686
|
-
// feature flag or the per-trigger toggle is off, when the sentinel is
|
|
4687
|
-
// missing, or when nothing has changed since the previous run, so it's
|
|
4688
|
-
// safe to always call here. Wrapped in a try/catch because a failed
|
|
4689
|
-
// materialize must never abort the consolidation result — consolidation
|
|
4690
|
-
// is the load-bearing operation; materialization is an optional mirror.
|
|
4691
|
-
try {
|
|
4692
|
-
await materializeAfterSemanticConsolidation({
|
|
4693
|
-
config: this.config,
|
|
4694
|
-
memoryDir: targetStorage.dir,
|
|
4695
|
-
});
|
|
4696
|
-
} catch (err) {
|
|
4697
|
-
log.warn(
|
|
4698
|
-
`[semantic-consolidation] Codex materialize post-hook failed (non-fatal): ${
|
|
4699
|
-
err instanceof Error ? err.message : String(err)
|
|
4700
|
-
}`,
|
|
4701
|
-
);
|
|
4702
|
-
}
|
|
4703
|
-
|
|
4704
|
-
// Issue #679 PR 2/5 — async peer profile reasoner runs as part of
|
|
4705
|
-
// the REM phase, immediately after semantic consolidation. Gated
|
|
4706
|
-
// on `peerProfileReasonerEnabled` (default false, opt-in). Wrapped
|
|
4707
|
-
// in a try/catch because reasoner I/O (LLM call, peer-profile
|
|
4708
|
-
// writes) must never abort the consolidation result. The reasoner
|
|
4709
|
-
// itself also defends against partial failure — see profile-reasoner.ts.
|
|
4710
|
-
if (this.config.peerProfileReasonerEnabled) {
|
|
4711
|
-
try {
|
|
4712
|
-
const { runPeerProfileReasoner } = await import("./peers/index.js");
|
|
4713
|
-
const llm = new FallbackLlmClient(
|
|
4714
|
-
this.config.gatewayConfig,
|
|
4715
|
-
fallbackLlmRuntimeContextFromConfig(this.config),
|
|
4716
|
-
);
|
|
4717
|
-
const peerResult = await runPeerProfileReasoner({
|
|
4718
|
-
memoryDir: targetStorage.dir,
|
|
4719
|
-
enabled: true,
|
|
4720
|
-
llm,
|
|
4721
|
-
model: this.config.peerProfileReasonerModel,
|
|
4722
|
-
minInteractions: this.config.peerProfileReasonerMinInteractions,
|
|
4723
|
-
maxFieldsPerRun: this.config.peerProfileReasonerMaxFieldsPerRun,
|
|
4724
|
-
log: {
|
|
4725
|
-
debug: (msg) => log.debug(msg),
|
|
4726
|
-
info: (msg) => log.info(msg),
|
|
4727
|
-
warn: (msg) => log.warn(msg),
|
|
4728
|
-
},
|
|
4729
|
-
});
|
|
4730
|
-
log.info(
|
|
4731
|
-
`[peer-profile-reasoner] complete: peers=${peerResult.peersConsidered}, processed=${peerResult.peersProcessed}, fields=${peerResult.fieldsApplied}`,
|
|
4732
|
-
);
|
|
4733
|
-
} catch (err) {
|
|
4734
|
-
log.warn(
|
|
4735
|
-
`[peer-profile-reasoner] post-consolidation hook failed (non-fatal): ${
|
|
4736
|
-
err instanceof Error ? err.message : String(err)
|
|
4737
|
-
}`,
|
|
4738
|
-
);
|
|
4739
|
-
}
|
|
4740
|
-
}
|
|
4741
|
-
|
|
4742
|
-
return result;
|
|
4415
|
+
return this.semanticConsolidationCoordinator.runSemanticConsolidation(options);
|
|
4743
4416
|
}
|
|
4744
4417
|
|
|
4745
4418
|
async waitForExtractionIdle(timeoutMs: number = 60_000): Promise<boolean> {
|
|
@@ -5144,7 +4817,7 @@ export class Orchestrator {
|
|
|
5144
4817
|
action: event.action,
|
|
5145
4818
|
eligibility,
|
|
5146
4819
|
options: {
|
|
5147
|
-
actionsEnabled: this.config.
|
|
4820
|
+
actionsEnabled: resolveCompressionCapabilities(this.config).contextCompressionActions,
|
|
5148
4821
|
maxCompressionTokensPerHour: this.config.maxCompressionTokensPerHour,
|
|
5149
4822
|
},
|
|
5150
4823
|
});
|
|
@@ -5950,7 +5623,7 @@ export class Orchestrator {
|
|
|
5950
5623
|
options.principalOverride.length > 0
|
|
5951
5624
|
? options.principalOverride
|
|
5952
5625
|
: resolvePrincipal(sessionKey, this.config);
|
|
5953
|
-
const namespacesEnabled = this.config.
|
|
5626
|
+
const namespacesEnabled = resolveNamespaceCapabilities(this.config).namespaces;
|
|
5954
5627
|
if (namespacesEnabled && !principal) {
|
|
5955
5628
|
throw new Error("authentication required: namespaces are enabled and no principal was supplied");
|
|
5956
5629
|
}
|
|
@@ -6419,7 +6092,7 @@ export class Orchestrator {
|
|
|
6419
6092
|
for (const memoryPath of paths) {
|
|
6420
6093
|
if (!memoryPath || isArtifactMemoryPath(memoryPath)) continue;
|
|
6421
6094
|
if (
|
|
6422
|
-
this.config.
|
|
6095
|
+
resolveNamespaceCapabilities(this.config).namespaces &&
|
|
6423
6096
|
!recallNamespaces.includes(this.namespaceFromPath(memoryPath))
|
|
6424
6097
|
) {
|
|
6425
6098
|
continue;
|
|
@@ -6536,7 +6209,7 @@ export class Orchestrator {
|
|
|
6536
6209
|
const memories = (
|
|
6537
6210
|
await Promise.all(
|
|
6538
6211
|
Array.from(candidatePaths).map(async (memoryPath) => {
|
|
6539
|
-
const namespace = this.config.
|
|
6212
|
+
const namespace = resolveNamespaceCapabilities(this.config).namespaces
|
|
6540
6213
|
? this.namespaceFromPath(memoryPath)
|
|
6541
6214
|
: this.config.defaultNamespace;
|
|
6542
6215
|
const storage = await this.storageRouter.storageFor(namespace);
|
|
@@ -7160,7 +6833,7 @@ export class Orchestrator {
|
|
|
7160
6833
|
private async resolveStateDirForNamespace(
|
|
7161
6834
|
namespace: string,
|
|
7162
6835
|
): Promise<string> {
|
|
7163
|
-
if (!this.config.
|
|
6836
|
+
if (!resolveNamespaceCapabilities(this.config).namespaces) {
|
|
7164
6837
|
return path.join(this.config.memoryDir, "state");
|
|
7165
6838
|
}
|
|
7166
6839
|
if (namespace !== this.config.defaultNamespace) {
|
|
@@ -7480,7 +7153,7 @@ export class Orchestrator {
|
|
|
7480
7153
|
}
|
|
7481
7154
|
const timings: Record<string, string> = {};
|
|
7482
7155
|
const profileTraceId = this.profiler.startTrace("recall", sessionKey, {
|
|
7483
|
-
qmdEnabled: this.config.
|
|
7156
|
+
qmdEnabled: resolveQmdCapabilities(this.config).qmd,
|
|
7484
7157
|
rerankEnabled: caps.rerank,
|
|
7485
7158
|
parallelRetrieval: caps.parallelRetrieval,
|
|
7486
7159
|
});
|
|
@@ -7753,7 +7426,7 @@ export class Orchestrator {
|
|
|
7753
7426
|
&& options.principalOverride.length > 0
|
|
7754
7427
|
? options.principalOverride
|
|
7755
7428
|
: resolvePrincipal(sessionKey, this.config);
|
|
7756
|
-
const namespacesEnabled = this.config.
|
|
7429
|
+
const namespacesEnabled = resolveNamespaceCapabilities(this.config).namespaces;
|
|
7757
7430
|
if (namespacesEnabled && !principal) {
|
|
7758
7431
|
throw new Error("authentication required: namespaces are enabled and no principal was supplied");
|
|
7759
7432
|
}
|
|
@@ -7998,7 +7671,7 @@ export class Orchestrator {
|
|
|
7998
7671
|
retrievalQueryLength: retrievalQuery.length,
|
|
7999
7672
|
recallMode,
|
|
8000
7673
|
recallResultLimit,
|
|
8001
|
-
qmdEnabled: this.config.
|
|
7674
|
+
qmdEnabled: resolveQmdCapabilities(this.config).qmd,
|
|
8002
7675
|
qmdAvailable: this.qmd.isAvailable(),
|
|
8003
7676
|
recallNamespaces: [],
|
|
8004
7677
|
source: recallSource,
|
|
@@ -8404,7 +8077,7 @@ export class Orchestrator {
|
|
|
8404
8077
|
if (
|
|
8405
8078
|
!this.isRecallSectionEnabled(
|
|
8406
8079
|
"identity-continuity",
|
|
8407
|
-
this.config.
|
|
8080
|
+
resolveIdentityContinuityCapabilities(this.config).identityContinuity === true,
|
|
8408
8081
|
)
|
|
8409
8082
|
)
|
|
8410
8083
|
return null;
|
|
@@ -8644,11 +8317,11 @@ export class Orchestrator {
|
|
|
8644
8317
|
const objectiveStatePromise = (async (): Promise<string | null> => {
|
|
8645
8318
|
const t0 = Date.now();
|
|
8646
8319
|
if (
|
|
8647
|
-
!this.config.
|
|
8648
|
-
!this.config.
|
|
8320
|
+
!resolveObjectiveStateCapabilities(this.config).objectiveStateMemory ||
|
|
8321
|
+
!resolveObjectiveStateCapabilities(this.config).objectiveStateRecall ||
|
|
8649
8322
|
!this.isRecallSectionEnabled(
|
|
8650
8323
|
"objective-state",
|
|
8651
|
-
this.config.
|
|
8324
|
+
resolveObjectiveStateCapabilities(this.config).objectiveStateRecall === true,
|
|
8652
8325
|
)
|
|
8653
8326
|
) {
|
|
8654
8327
|
recordRecallSectionMetric({
|
|
@@ -8679,17 +8352,17 @@ export class Orchestrator {
|
|
|
8679
8352
|
|
|
8680
8353
|
const objectiveStateSearches = await Promise.all(
|
|
8681
8354
|
recallNamespaces.map(async (namespace) => {
|
|
8682
|
-
const storage = this.config.
|
|
8355
|
+
const storage = resolveNamespaceCapabilities(this.config).namespaces
|
|
8683
8356
|
? await this.getStorage(namespace)
|
|
8684
8357
|
: null;
|
|
8685
8358
|
return searchObjectiveStateSnapshots({
|
|
8686
|
-
memoryDir: this.config.
|
|
8359
|
+
memoryDir: resolveNamespaceCapabilities(this.config).namespaces
|
|
8687
8360
|
? storage!.dir
|
|
8688
8361
|
: this.config.memoryDir,
|
|
8689
8362
|
objectiveStateStoreDir: objectiveStateStoreOverrideForNamespace({
|
|
8690
8363
|
memoryDir: this.config.memoryDir,
|
|
8691
8364
|
configuredStoreDir: this.config.objectiveStateStoreDir,
|
|
8692
|
-
namespacesEnabled: this.config.
|
|
8365
|
+
namespacesEnabled: resolveNamespaceCapabilities(this.config).namespaces,
|
|
8693
8366
|
namespace,
|
|
8694
8367
|
}),
|
|
8695
8368
|
query: retrievalQuery,
|
|
@@ -8901,11 +8574,11 @@ export class Orchestrator {
|
|
|
8901
8574
|
const trustZonePromise = (async (): Promise<string | null> => {
|
|
8902
8575
|
const t0 = Date.now();
|
|
8903
8576
|
if (
|
|
8904
|
-
!this.config.
|
|
8905
|
-
!this.config.
|
|
8577
|
+
!resolveSecurityCapabilities(this.config).trustZones ||
|
|
8578
|
+
!resolveSecurityCapabilities(this.config).trustZoneRecall ||
|
|
8906
8579
|
!this.isRecallSectionEnabled(
|
|
8907
8580
|
"trust-zones",
|
|
8908
|
-
this.config.
|
|
8581
|
+
resolveSecurityCapabilities(this.config).trustZoneRecall === true,
|
|
8909
8582
|
)
|
|
8910
8583
|
) {
|
|
8911
8584
|
recordRecallSectionMetric({
|
|
@@ -9593,7 +9266,7 @@ export class Orchestrator {
|
|
|
9593
9266
|
qmdFetchLimit,
|
|
9594
9267
|
qmdHybridFetchLimit,
|
|
9595
9268
|
{
|
|
9596
|
-
namespacesEnabled: this.config.
|
|
9269
|
+
namespacesEnabled: resolveNamespaceCapabilities(this.config).namespaces,
|
|
9597
9270
|
recallNamespaces,
|
|
9598
9271
|
resolveNamespace: (p) => this.namespaceFromPath(p),
|
|
9599
9272
|
queryAwarePrefilter,
|
|
@@ -10011,7 +9684,7 @@ export class Orchestrator {
|
|
|
10011
9684
|
workspaceDir: this.config.workspaceDir,
|
|
10012
9685
|
memoryDir: this.config.memoryDir,
|
|
10013
9686
|
config: this.config.nativeKnowledge,
|
|
10014
|
-
recallNamespaces: this.config.
|
|
9687
|
+
recallNamespaces: resolveNamespaceCapabilities(this.config).namespaces
|
|
10015
9688
|
? recallNamespaces
|
|
10016
9689
|
: undefined,
|
|
10017
9690
|
defaultNamespace: this.config.defaultNamespace,
|
|
@@ -11085,7 +10758,7 @@ export class Orchestrator {
|
|
|
11085
10758
|
let memoryResults = memoryResultsRaw;
|
|
11086
10759
|
|
|
11087
10760
|
// Enforce namespace read policies by filtering paths.
|
|
11088
|
-
if (this.config.
|
|
10761
|
+
if (resolveNamespaceCapabilities(this.config).namespaces) {
|
|
11089
10762
|
memoryResults = memoryResults.filter((r) =>
|
|
11090
10763
|
recallNamespaces.includes(this.namespaceFromPath(r.path)),
|
|
11091
10764
|
);
|
|
@@ -11459,7 +11132,7 @@ export class Orchestrator {
|
|
|
11459
11132
|
const scopedCandidates = filterRecallCandidates(
|
|
11460
11133
|
prefilteredEmbeddingResults,
|
|
11461
11134
|
{
|
|
11462
|
-
namespacesEnabled: this.config.
|
|
11135
|
+
namespacesEnabled: resolveNamespaceCapabilities(this.config).namespaces,
|
|
11463
11136
|
recallNamespaces,
|
|
11464
11137
|
resolveNamespace: (p) => this.namespaceFromPath(p),
|
|
11465
11138
|
limit: embeddingFetchLimit,
|
|
@@ -11638,7 +11311,7 @@ export class Orchestrator {
|
|
|
11638
11311
|
const scopedCandidates = filterRecallCandidates(
|
|
11639
11312
|
prefilteredEmbeddingResults,
|
|
11640
11313
|
{
|
|
11641
|
-
namespacesEnabled: this.config.
|
|
11314
|
+
namespacesEnabled: resolveNamespaceCapabilities(this.config).namespaces,
|
|
11642
11315
|
recallNamespaces,
|
|
11643
11316
|
resolveNamespace: (p) => this.namespaceFromPath(p),
|
|
11644
11317
|
limit: embeddingFetchLimit,
|
|
@@ -12074,7 +11747,7 @@ export class Orchestrator {
|
|
|
12074
11747
|
if (
|
|
12075
11748
|
this.isRecallSectionEnabled(
|
|
12076
11749
|
"compression-guidelines",
|
|
12077
|
-
this.config.
|
|
11750
|
+
resolveCompressionCapabilities(this.config).compressionGuidelineLearning === true,
|
|
12078
11751
|
)
|
|
12079
11752
|
) {
|
|
12080
11753
|
const compressionGuidelineSection =
|
|
@@ -12476,7 +12149,7 @@ export class Orchestrator {
|
|
|
12476
12149
|
retrievalQueryLength: retrievalQuery.length,
|
|
12477
12150
|
recallMode,
|
|
12478
12151
|
recallResultLimit,
|
|
12479
|
-
qmdEnabled: this.config.
|
|
12152
|
+
qmdEnabled: resolveQmdCapabilities(this.config).qmd,
|
|
12480
12153
|
qmdAvailable: this.qmd.isAvailable(),
|
|
12481
12154
|
recallNamespaces,
|
|
12482
12155
|
source: recallSource,
|
|
@@ -14193,7 +13866,7 @@ export class Orchestrator {
|
|
|
14193
13866
|
// #1713: hoist namespaces-enabled once for the scope-routing mirrors
|
|
14194
13867
|
// (pre-judge + write-loop) so no new scattered config.*Enabled read is
|
|
14195
13868
|
// introduced (ratchet scatteredConfigFlagReads; see #1523).
|
|
14196
|
-
const namespacesEnabled = this.config.
|
|
13869
|
+
const namespacesEnabled = resolveNamespaceCapabilities(this.config).namespaces;
|
|
14197
13870
|
const profileAutoPromotionAllows = (
|
|
14198
13871
|
category: string,
|
|
14199
13872
|
confidence: number,
|
|
@@ -14235,7 +13908,7 @@ export class Orchestrator {
|
|
|
14235
13908
|
confidence: number,
|
|
14236
13909
|
): boolean => {
|
|
14237
13910
|
if (
|
|
14238
|
-
!this.config.
|
|
13911
|
+
!resolveNamespaceCapabilities(this.config).namespaces ||
|
|
14239
13912
|
!profileAllowsSharedWrites ||
|
|
14240
13913
|
!sharedAutoPromotionAllows(category, confidence)
|
|
14241
13914
|
)
|
|
@@ -16769,7 +16442,7 @@ export class Orchestrator {
|
|
|
16769
16442
|
// On full rebuild with namespaces enabled, span all configured namespaces so
|
|
16770
16443
|
// memories written to other namespaces before the index existed are also captured.
|
|
16771
16444
|
const allMemories =
|
|
16772
|
-
needsFullRebuild && this.config.
|
|
16445
|
+
needsFullRebuild && resolveNamespaceCapabilities(this.config).namespaces
|
|
16773
16446
|
? await this.readAllMemoriesForNamespaces(
|
|
16774
16447
|
Array.from(
|
|
16775
16448
|
new Set<string>([
|
|
@@ -17356,81 +17029,6 @@ export class Orchestrator {
|
|
|
17356
17029
|
return this.compressionGuidelineCoordinator.buildCompressionGuidelineRecallSection();
|
|
17357
17030
|
}
|
|
17358
17031
|
|
|
17359
|
-
private actionOutcomePriorDelta(event: MemoryActionEvent): number {
|
|
17360
|
-
if (event.outcome === "failed") return -0.3;
|
|
17361
|
-
if (event.policyDecision === "deny") return -0.22;
|
|
17362
|
-
if (event.policyDecision === "defer") return -0.14;
|
|
17363
|
-
if (event.outcome === "skipped") return -0.1;
|
|
17364
|
-
|
|
17365
|
-
if (event.outcome !== "applied") return 0;
|
|
17366
|
-
switch (event.action) {
|
|
17367
|
-
case "store_episode":
|
|
17368
|
-
case "store_note":
|
|
17369
|
-
case "update_note":
|
|
17370
|
-
return 0.08;
|
|
17371
|
-
case "create_artifact":
|
|
17372
|
-
case "summarize_node":
|
|
17373
|
-
case "link_graph":
|
|
17374
|
-
return 0.04;
|
|
17375
|
-
case "discard":
|
|
17376
|
-
return -0.03;
|
|
17377
|
-
default:
|
|
17378
|
-
return 0;
|
|
17379
|
-
}
|
|
17380
|
-
}
|
|
17381
|
-
|
|
17382
|
-
private async buildLifecycleActionPriors(
|
|
17383
|
-
storage: StorageManager = this.storage,
|
|
17384
|
-
): Promise<Map<string, number>> {
|
|
17385
|
-
const events = await storage.readMemoryActionEvents(1200);
|
|
17386
|
-
if (events.length === 0) return new Map<string, number>();
|
|
17387
|
-
|
|
17388
|
-
const nowMs = Date.now();
|
|
17389
|
-
const windowMs = 14 * 24 * 60 * 60 * 1000;
|
|
17390
|
-
const byMemory = new Map<
|
|
17391
|
-
string,
|
|
17392
|
-
Array<{ weightedDelta: number; weight: number }>
|
|
17393
|
-
>();
|
|
17394
|
-
|
|
17395
|
-
for (const event of events) {
|
|
17396
|
-
if (
|
|
17397
|
-
typeof event.memoryId !== "string" ||
|
|
17398
|
-
event.memoryId.trim().length === 0
|
|
17399
|
-
)
|
|
17400
|
-
continue;
|
|
17401
|
-
const ts = Date.parse(event.timestamp);
|
|
17402
|
-
if (!Number.isFinite(ts)) continue;
|
|
17403
|
-
const ageMs = nowMs - ts;
|
|
17404
|
-
if (ageMs < 0 || ageMs > windowMs) continue;
|
|
17405
|
-
|
|
17406
|
-
const delta = this.actionOutcomePriorDelta(event);
|
|
17407
|
-
if (delta === 0) continue;
|
|
17408
|
-
|
|
17409
|
-
const recencyWeight = Math.max(0.2, 1 - ageMs / windowMs);
|
|
17410
|
-
const list = byMemory.get(event.memoryId) ?? [];
|
|
17411
|
-
if (list.length >= 8) list.shift();
|
|
17412
|
-
list.push({
|
|
17413
|
-
weightedDelta: delta * recencyWeight,
|
|
17414
|
-
weight: recencyWeight,
|
|
17415
|
-
});
|
|
17416
|
-
byMemory.set(event.memoryId, list);
|
|
17417
|
-
}
|
|
17418
|
-
|
|
17419
|
-
const out = new Map<string, number>();
|
|
17420
|
-
for (const [memoryId, deltas] of byMemory.entries()) {
|
|
17421
|
-
if (deltas.length === 0) continue;
|
|
17422
|
-
const weightedSum = deltas.reduce(
|
|
17423
|
-
(sum, item) => sum + item.weightedDelta,
|
|
17424
|
-
0,
|
|
17425
|
-
);
|
|
17426
|
-
const weightTotal = deltas.reduce((sum, item) => sum + item.weight, 0);
|
|
17427
|
-
if (weightTotal <= 0) continue;
|
|
17428
|
-
const score = weightedSum / weightTotal;
|
|
17429
|
-
out.set(memoryId, Math.max(-0.25, Math.min(0.15, score)));
|
|
17430
|
-
}
|
|
17431
|
-
return out;
|
|
17432
|
-
}
|
|
17433
|
-
|
|
17434
17032
|
private async recordScheduledDreamsPhaseRun(
|
|
17435
17033
|
phase: "lightSleep" | "rem" | "deepSleep",
|
|
17436
17034
|
itemsProcessed: number,
|
|
@@ -17465,315 +17063,23 @@ export class Orchestrator {
|
|
|
17465
17063
|
allMemories: MemoryFile[],
|
|
17466
17064
|
storage: StorageManager = this.storage,
|
|
17467
17065
|
): Promise<number> {
|
|
17468
|
-
|
|
17469
|
-
const nowIso = now.toISOString();
|
|
17470
|
-
const countsByState: Record<LifecycleState, number> = {
|
|
17471
|
-
candidate: 0,
|
|
17472
|
-
validated: 0,
|
|
17473
|
-
active: 0,
|
|
17474
|
-
stale: 0,
|
|
17475
|
-
archived: 0,
|
|
17476
|
-
};
|
|
17477
|
-
const transitionCounts: Record<string, number> = {};
|
|
17478
|
-
let updatedCount = 0;
|
|
17479
|
-
let disputedCount = 0;
|
|
17480
|
-
let evaluatedCount = 0;
|
|
17481
|
-
const lifecycleCaps = resolveMemoryLifecycleCapabilities(this.config);
|
|
17482
|
-
|
|
17483
|
-
const thresholds = this.effectiveLifecycleThresholds();
|
|
17484
|
-
const policy = {
|
|
17485
|
-
promoteHeatThreshold: thresholds.promoteHeatThreshold,
|
|
17486
|
-
staleDecayThreshold: thresholds.staleDecayThreshold,
|
|
17487
|
-
archiveDecayThreshold: thresholds.archiveDecayThreshold,
|
|
17488
|
-
protectedCategories: this.config.lifecycleProtectedCategories,
|
|
17489
|
-
};
|
|
17490
|
-
const actionPriors = await this.buildLifecycleActionPriors(storage);
|
|
17491
|
-
|
|
17492
|
-
for (const memory of allMemories) {
|
|
17493
|
-
if (
|
|
17494
|
-
memory.frontmatter.status === "superseded" ||
|
|
17495
|
-
memory.frontmatter.status === "forgotten"
|
|
17496
|
-
) {
|
|
17497
|
-
continue;
|
|
17498
|
-
}
|
|
17499
|
-
evaluatedCount += 1;
|
|
17500
|
-
const currentState = resolveLifecycleState(memory.frontmatter);
|
|
17501
|
-
const actionPriorScore = actionPriors.get(memory.frontmatter.id);
|
|
17502
|
-
const signals: LifecycleSignals | undefined =
|
|
17503
|
-
typeof actionPriorScore === "number" &&
|
|
17504
|
-
Number.isFinite(actionPriorScore)
|
|
17505
|
-
? { actionPriorScore }
|
|
17506
|
-
: undefined;
|
|
17507
|
-
const decision = decideLifecycleTransition(memory, policy, now, signals);
|
|
17508
|
-
const nextState: LifecycleState =
|
|
17509
|
-
memory.frontmatter.status === "archived"
|
|
17510
|
-
? "archived"
|
|
17511
|
-
: decision.nextState;
|
|
17512
|
-
|
|
17513
|
-
countsByState[nextState] += 1;
|
|
17514
|
-
if (memory.frontmatter.verificationState === "disputed") {
|
|
17515
|
-
disputedCount += 1;
|
|
17516
|
-
}
|
|
17517
|
-
if (nextState !== currentState) {
|
|
17518
|
-
const key = `${currentState}->${nextState}`;
|
|
17519
|
-
transitionCounts[key] = (transitionCounts[key] ?? 0) + 1;
|
|
17520
|
-
}
|
|
17521
|
-
|
|
17522
|
-
const prevHeat = memory.frontmatter.heatScore;
|
|
17523
|
-
const prevDecay = memory.frontmatter.decayScore;
|
|
17524
|
-
const scoreDelta =
|
|
17525
|
-
Math.abs((prevHeat ?? -1) - decision.heatScore) +
|
|
17526
|
-
Math.abs((prevDecay ?? -1) - decision.decayScore);
|
|
17527
|
-
const shouldPersist =
|
|
17528
|
-
memory.frontmatter.lifecycleState !== nextState ||
|
|
17529
|
-
memory.frontmatter.heatScore === undefined ||
|
|
17530
|
-
memory.frontmatter.decayScore === undefined ||
|
|
17531
|
-
memory.frontmatter.lastValidatedAt === undefined ||
|
|
17532
|
-
scoreDelta >= 0.01;
|
|
17533
|
-
|
|
17534
|
-
if (!shouldPersist) continue;
|
|
17535
|
-
|
|
17536
|
-
const wrote = await storage.writeMemoryFrontmatter(memory, {
|
|
17537
|
-
lifecycleState: nextState,
|
|
17538
|
-
heatScore: decision.heatScore,
|
|
17539
|
-
decayScore: decision.decayScore,
|
|
17540
|
-
lastValidatedAt: nowIso,
|
|
17541
|
-
});
|
|
17542
|
-
if (wrote) updatedCount += 1;
|
|
17543
|
-
}
|
|
17544
|
-
|
|
17545
|
-
// Report how many memories had frontmatter rewritten so callers can record a
|
|
17546
|
-
// catalog write touch for lifecycle-only passes (codex NR-tS).
|
|
17547
|
-
if (!lifecycleCaps.lifecycleMetrics) return updatedCount;
|
|
17548
|
-
|
|
17549
|
-
const total = evaluatedCount;
|
|
17550
|
-
const metrics = {
|
|
17551
|
-
generatedAt: nowIso,
|
|
17552
|
-
memoriesEvaluated: total,
|
|
17553
|
-
memoriesUpdated: updatedCount,
|
|
17554
|
-
countsByLifecycleState: countsByState,
|
|
17555
|
-
transitionCounts,
|
|
17556
|
-
staleRatio: total > 0 ? countsByState.stale / total : 0,
|
|
17557
|
-
disputedRatio: total > 0 ? disputedCount / total : 0,
|
|
17558
|
-
policy: {
|
|
17559
|
-
promoteHeatThreshold: thresholds.promoteHeatThreshold,
|
|
17560
|
-
staleDecayThreshold: thresholds.staleDecayThreshold,
|
|
17561
|
-
archiveDecayThreshold: thresholds.archiveDecayThreshold,
|
|
17562
|
-
protectedCategories: this.config.lifecycleProtectedCategories,
|
|
17563
|
-
},
|
|
17564
|
-
};
|
|
17565
|
-
const metricsPath = path.join(
|
|
17566
|
-
storage.dir,
|
|
17567
|
-
"state",
|
|
17568
|
-
"lifecycle-metrics.json",
|
|
17569
|
-
);
|
|
17570
|
-
await mkdir(path.dirname(metricsPath), { recursive: true });
|
|
17571
|
-
await writeFile(metricsPath, JSON.stringify(metrics, null, 2), "utf-8");
|
|
17572
|
-
return updatedCount;
|
|
17066
|
+
return this.lifecyclePolicyCoordinator.runLifecyclePolicyPass(allMemories, storage);
|
|
17573
17067
|
}
|
|
17574
|
-
|
|
17575
|
-
/**
|
|
17576
|
-
* Archive old, low-importance, rarely-accessed facts (v6.0).
|
|
17577
|
-
* Moves eligible facts from facts/ to archive/YYYY-MM-DD/.
|
|
17578
|
-
* Returns the number of archived facts.
|
|
17579
|
-
*/
|
|
17580
17068
|
private async runFactArchival(
|
|
17581
17069
|
allMemories: import("./types.js").MemoryFile[],
|
|
17582
17070
|
): Promise<number> {
|
|
17583
|
-
|
|
17584
|
-
const ageCutoffMs = this.config.factArchivalAgeDays * 24 * 60 * 60 * 1000;
|
|
17585
|
-
const protectedCategories = new Set(
|
|
17586
|
-
this.config.factArchivalProtectedCategories,
|
|
17587
|
-
);
|
|
17588
|
-
let archivedCount = 0;
|
|
17589
|
-
|
|
17590
|
-
for (const memory of allMemories) {
|
|
17591
|
-
const fm = memory.frontmatter;
|
|
17592
|
-
|
|
17593
|
-
// Skip already-archived or superseded
|
|
17594
|
-
if (fm.status && fm.status !== "active") continue;
|
|
17595
|
-
|
|
17596
|
-
// Skip protected categories
|
|
17597
|
-
if (protectedCategories.has(fm.category)) continue;
|
|
17598
|
-
|
|
17599
|
-
// Skip corrections (always keep)
|
|
17600
|
-
if (fm.category === "correction") continue;
|
|
17601
|
-
|
|
17602
|
-
// Check age requirement
|
|
17603
|
-
const createdMs = new Date(fm.created).getTime();
|
|
17604
|
-
if (now - createdMs < ageCutoffMs) continue;
|
|
17605
|
-
|
|
17606
|
-
// Check importance (only archive low-importance facts)
|
|
17607
|
-
const importanceScore = fm.importance?.score ?? 0.5;
|
|
17608
|
-
if (importanceScore >= this.config.factArchivalMaxImportance) continue;
|
|
17609
|
-
|
|
17610
|
-
// Check access count
|
|
17611
|
-
const accessCount = fm.accessCount ?? 0;
|
|
17612
|
-
if (accessCount > this.config.factArchivalMaxAccessCount) continue;
|
|
17613
|
-
|
|
17614
|
-
// All criteria met — archive
|
|
17615
|
-
const result = await this.storage.archiveMemory(memory);
|
|
17616
|
-
if (result) {
|
|
17617
|
-
// Remove from the same storage-scoped content-hash index since it is
|
|
17618
|
-
// no longer in hot search.
|
|
17619
|
-
await this.removeContentHashForMemory(
|
|
17620
|
-
this.storage,
|
|
17621
|
-
memory,
|
|
17622
|
-
"fact-archival",
|
|
17623
|
-
);
|
|
17624
|
-
await this.embeddingFallback.removeFromIndex(memory.frontmatter.id);
|
|
17625
|
-
if (
|
|
17626
|
-
resolveIndexingCapabilities(this.config).queryAwareIndexing &&
|
|
17627
|
-
memory.path &&
|
|
17628
|
-
memory.frontmatter?.created
|
|
17629
|
-
) {
|
|
17630
|
-
deindexMemory(
|
|
17631
|
-
this.config.memoryDir,
|
|
17632
|
-
memory.path,
|
|
17633
|
-
memory.frontmatter.created,
|
|
17634
|
-
memory.frontmatter.tags ?? [],
|
|
17635
|
-
);
|
|
17636
|
-
}
|
|
17637
|
-
archivedCount++;
|
|
17638
|
-
}
|
|
17639
|
-
}
|
|
17640
|
-
|
|
17641
|
-
// Save hash indexes if we removed any entries.
|
|
17642
|
-
if (archivedCount > 0) {
|
|
17643
|
-
await this.saveContentHashIndexes().catch((err) =>
|
|
17644
|
-
log.warn(`content-hash index save failed during archival: ${err}`),
|
|
17645
|
-
);
|
|
17646
|
-
}
|
|
17647
|
-
|
|
17648
|
-
return archivedCount;
|
|
17071
|
+
return this.lifecyclePolicyCoordinator.runFactArchival(allMemories);
|
|
17649
17072
|
}
|
|
17650
|
-
|
|
17651
|
-
/**
|
|
17652
|
-
* Run memory summarization if memory count exceeds threshold (Phase 4A).
|
|
17653
|
-
*/
|
|
17654
17073
|
private async runSummarization(
|
|
17655
17074
|
allMemories: import("./types.js").MemoryFile[],
|
|
17656
17075
|
): Promise<void> {
|
|
17657
|
-
|
|
17658
|
-
const activeMemories = allMemories.filter(
|
|
17659
|
-
(m) => isActiveMemoryStatus(m.frontmatter.status),
|
|
17660
|
-
);
|
|
17661
|
-
|
|
17662
|
-
if (activeMemories.length < this.config.summarizationTriggerCount) {
|
|
17663
|
-
return;
|
|
17664
|
-
}
|
|
17665
|
-
|
|
17666
|
-
log.info(
|
|
17667
|
-
`memory count (${activeMemories.length}) exceeds threshold (${this.config.summarizationTriggerCount}) — running summarization`,
|
|
17668
|
-
);
|
|
17669
|
-
|
|
17670
|
-
// Sort by creation date, oldest first
|
|
17671
|
-
const sorted = activeMemories.sort(
|
|
17672
|
-
(a, b) =>
|
|
17673
|
-
new Date(a.frontmatter.created).getTime() -
|
|
17674
|
-
new Date(b.frontmatter.created).getTime(),
|
|
17675
|
-
);
|
|
17676
|
-
|
|
17677
|
-
// Keep recent memories, with explicit zero handling so `slice(-0)` does not
|
|
17678
|
-
// accidentally keep every memory out of the summarization candidate set.
|
|
17679
|
-
const recentToKeep = Math.max(0, this.config.summarizationRecentToKeep);
|
|
17680
|
-
const toSummarize = recentToKeep > 0 ? sorted.slice(0, -recentToKeep) : sorted;
|
|
17681
|
-
|
|
17682
|
-
// Filter candidates for summarization
|
|
17683
|
-
const candidates = toSummarize.filter((m) => {
|
|
17684
|
-
// Skip if protected by entity reference
|
|
17685
|
-
if (m.frontmatter.entityRef) return false;
|
|
17686
|
-
|
|
17687
|
-
// Skip if protected by tag
|
|
17688
|
-
const protectedTags = this.config.summarizationProtectedTags;
|
|
17689
|
-
if (m.frontmatter.tags.some((t) => protectedTags.includes(t)))
|
|
17690
|
-
return false;
|
|
17691
|
-
|
|
17692
|
-
// Skip if importance is above threshold
|
|
17693
|
-
const importance = m.frontmatter.importance?.score ?? 0.5;
|
|
17694
|
-
if (importance >= this.config.summarizationImportanceThreshold)
|
|
17695
|
-
return false;
|
|
17696
|
-
|
|
17697
|
-
return true;
|
|
17698
|
-
});
|
|
17699
|
-
|
|
17700
|
-
if (candidates.length < 50) {
|
|
17701
|
-
log.debug(
|
|
17702
|
-
`only ${candidates.length} candidates for summarization — skipping`,
|
|
17703
|
-
);
|
|
17704
|
-
return;
|
|
17705
|
-
}
|
|
17706
|
-
|
|
17707
|
-
// Summarize in batches of 50
|
|
17708
|
-
const batchSize = 50;
|
|
17709
|
-
for (let i = 0; i < candidates.length; i += batchSize) {
|
|
17710
|
-
const batch = candidates.slice(i, i + batchSize);
|
|
17711
|
-
const batchData = batch.map((m) => ({
|
|
17712
|
-
id: m.frontmatter.id,
|
|
17713
|
-
content: m.content,
|
|
17714
|
-
category: m.frontmatter.category,
|
|
17715
|
-
created: m.frontmatter.created,
|
|
17716
|
-
}));
|
|
17717
|
-
|
|
17718
|
-
const result = await this.extraction.summarizeMemories(batchData);
|
|
17719
|
-
if (!result) continue;
|
|
17720
|
-
|
|
17721
|
-
// Create summary
|
|
17722
|
-
const summary: MemorySummary = {
|
|
17723
|
-
id: `summary-${Date.now()}-${Math.random().toString(36).slice(2, 6)}`,
|
|
17724
|
-
createdAt: new Date().toISOString(),
|
|
17725
|
-
timeRangeStart: batch[0].frontmatter.created,
|
|
17726
|
-
timeRangeEnd: batch[batch.length - 1].frontmatter.created,
|
|
17727
|
-
summaryText: result.summaryText,
|
|
17728
|
-
keyFacts: result.keyFacts,
|
|
17729
|
-
keyEntities: result.keyEntities,
|
|
17730
|
-
sourceEpisodeIds: batch.map((m) => m.frontmatter.id),
|
|
17731
|
-
};
|
|
17732
|
-
|
|
17733
|
-
await this.storage.writeSummary(summary);
|
|
17734
|
-
|
|
17735
|
-
// Archive source memories
|
|
17736
|
-
const archived = await this.storage.archiveMemories(
|
|
17737
|
-
batch.map((m) => m.frontmatter.id),
|
|
17738
|
-
summary.id,
|
|
17739
|
-
);
|
|
17740
|
-
|
|
17741
|
-
// Catalog write touch (issue #1499 sweep): summarization writes a durable
|
|
17742
|
-
// summary and then rewrites source-memory archive status, bypassing the
|
|
17743
|
-
// extraction write path. Record the touch after both mutations complete so
|
|
17744
|
-
// `lastWriteAt` covers the final archived-state write.
|
|
17745
|
-
// #1522: catalog touch handled at the storage chokepoint.
|
|
17746
|
-
|
|
17747
|
-
log.info(
|
|
17748
|
-
`created summary ${summary.id} from ${batch.length} memories, archived ${archived}`,
|
|
17749
|
-
);
|
|
17750
|
-
}
|
|
17076
|
+
return this.lifecyclePolicyCoordinator.runSummarization(allMemories);
|
|
17751
17077
|
}
|
|
17752
|
-
|
|
17753
|
-
/**
|
|
17754
|
-
* Run topic extraction on all memories (Phase 4B).
|
|
17755
|
-
*/
|
|
17756
17078
|
private async runTopicExtraction(
|
|
17757
17079
|
allMemories: import("./types.js").MemoryFile[],
|
|
17758
17080
|
): Promise<void> {
|
|
17759
|
-
|
|
17760
|
-
const activeMemories = allMemories.filter(
|
|
17761
|
-
(m) => isActiveMemoryStatus(m.frontmatter.status),
|
|
17762
|
-
);
|
|
17763
|
-
|
|
17764
|
-
if (activeMemories.length === 0) return;
|
|
17765
|
-
|
|
17766
|
-
const topics = extractTopics(
|
|
17767
|
-
activeMemories,
|
|
17768
|
-
this.config.topicExtractionTopN,
|
|
17769
|
-
);
|
|
17770
|
-
await this.storage.saveTopics(topics);
|
|
17771
|
-
|
|
17772
|
-
log.debug(
|
|
17773
|
-
`extracted ${topics.length} topics from ${activeMemories.length} memories`,
|
|
17774
|
-
);
|
|
17081
|
+
return this.lifecyclePolicyCoordinator.runTopicExtraction(allMemories);
|
|
17775
17082
|
}
|
|
17776
|
-
|
|
17777
17083
|
/** Threshold (bytes) at which IDENTITY.md reflections get auto-consolidated */
|
|
17778
17084
|
private static readonly IDENTITY_CONSOLIDATE_THRESHOLD = 8_000;
|
|
17779
17085
|
|
|
@@ -17782,14 +17088,14 @@ export class Orchestrator {
|
|
|
17782
17088
|
// namespace that accumulated IDENTITY.md reflections must also be eligible for
|
|
17783
17089
|
// auto-consolidation, otherwise its identity file grows unbounded and is never
|
|
17784
17090
|
// consolidated. Falls back to the configured set on any catalog read failure.
|
|
17785
|
-
const namespaces = this.config.
|
|
17091
|
+
const namespaces = resolveNamespaceCapabilities(this.config).namespaces
|
|
17786
17092
|
? await this.maintenanceNamespaces()
|
|
17787
17093
|
: [this.config.defaultNamespace];
|
|
17788
17094
|
|
|
17789
17095
|
for (const namespace of namespaces) {
|
|
17790
17096
|
const storage = await this.storageRouter.storageFor(namespace);
|
|
17791
17097
|
const identityNamespace =
|
|
17792
|
-
this.config.
|
|
17098
|
+
resolveNamespaceCapabilities(this.config).namespaces &&
|
|
17793
17099
|
namespace !== this.config.defaultNamespace
|
|
17794
17100
|
? namespace
|
|
17795
17101
|
: undefined;
|
|
@@ -18138,7 +17444,7 @@ export class Orchestrator {
|
|
|
18138
17444
|
injectedChars: number;
|
|
18139
17445
|
truncated: boolean;
|
|
18140
17446
|
} | null> {
|
|
18141
|
-
if (!this.config.
|
|
17447
|
+
if (!resolveIdentityContinuityCapabilities(this.config).identityContinuity) return null;
|
|
18142
17448
|
if (this.config.identityMaxInjectChars <= 0) return null;
|
|
18143
17449
|
|
|
18144
17450
|
const resolved = resolveEffectiveIdentityInjectionMode({
|
|
@@ -18227,7 +17533,7 @@ export class Orchestrator {
|
|
|
18227
17533
|
private queueEvalShadowRecall(
|
|
18228
17534
|
record: Omit<EvalShadowRecallRecord, "schemaVersion">,
|
|
18229
17535
|
): void {
|
|
18230
|
-
if (!this.config.
|
|
17536
|
+
if (!resolveEvalCapabilities(this.config).evalHarness || !resolveEvalCapabilities(this.config).evalShadowMode)
|
|
18231
17537
|
return;
|
|
18232
17538
|
this.evalShadowWriteChain = this.evalShadowWriteChain
|
|
18233
17539
|
.catch(() => undefined)
|
|
@@ -18344,7 +17650,7 @@ export class Orchestrator {
|
|
|
18344
17650
|
: this.config.defaultNamespace;
|
|
18345
17651
|
if (
|
|
18346
17652
|
recallNamespaces.length === 0 ||
|
|
18347
|
-
!this.config.
|
|
17653
|
+
!resolveNamespaceCapabilities(this.config).namespaces ||
|
|
18348
17654
|
recallNamespaces.includes(fallbackNamespace)
|
|
18349
17655
|
) {
|
|
18350
17656
|
addStorage(fallbackStorage);
|
|
@@ -18471,7 +17777,7 @@ export class Orchestrator {
|
|
|
18471
17777
|
recallNamespaces,
|
|
18472
17778
|
);
|
|
18473
17779
|
ownerNamespace = ownerStorage?.namespace ?? null;
|
|
18474
|
-
if (!ownerNamespace && this.config.
|
|
17780
|
+
if (!ownerNamespace && resolveNamespaceCapabilities(this.config).namespaces) return null;
|
|
18475
17781
|
}
|
|
18476
17782
|
ownerNamespace ??= this.namespaceFromPath(memory.path);
|
|
18477
17783
|
if (
|
|
@@ -19030,7 +18336,7 @@ export class Orchestrator {
|
|
|
19030
18336
|
pathPrefix?: string;
|
|
19031
18337
|
pathExcludePrefixes?: readonly string[];
|
|
19032
18338
|
} {
|
|
19033
|
-
if (!this.config.
|
|
18339
|
+
if (!resolveNamespaceCapabilities(this.config).namespaces) return {};
|
|
19034
18340
|
const memoryDir = path.resolve(this.config.memoryDir);
|
|
19035
18341
|
const storageDir = path.resolve(targetStorage.dir);
|
|
19036
18342
|
if (storageDir === memoryDir) {
|
|
@@ -19267,7 +18573,7 @@ export class Orchestrator {
|
|
|
19267
18573
|
}
|
|
19268
18574
|
};
|
|
19269
18575
|
|
|
19270
|
-
const coldQmdEnabled = this.config.
|
|
18576
|
+
const coldQmdEnabled = resolveQmdCapabilities(this.config).qmdColdTier === true;
|
|
19271
18577
|
const coldCollection =
|
|
19272
18578
|
this.config.qmdColdCollection ?? "openclaw-engram-cold";
|
|
19273
18579
|
const coldMaxResults =
|
|
@@ -19312,7 +18618,7 @@ export class Orchestrator {
|
|
|
19312
18618
|
coldFetchLimit,
|
|
19313
18619
|
coldHybridLimit,
|
|
19314
18620
|
{
|
|
19315
|
-
namespacesEnabled: this.config.
|
|
18621
|
+
namespacesEnabled: resolveNamespaceCapabilities(this.config).namespaces,
|
|
19316
18622
|
recallNamespaces: options.recallNamespaces,
|
|
19317
18623
|
resolveNamespace: (p) => this.namespaceFromPath(p),
|
|
19318
18624
|
collection: coldCollection,
|
|
@@ -19359,7 +18665,7 @@ export class Orchestrator {
|
|
|
19359
18665
|
if (longTerm.length === 0) return [];
|
|
19360
18666
|
|
|
19361
18667
|
let results = longTerm;
|
|
19362
|
-
if (this.config.
|
|
18668
|
+
if (resolveNamespaceCapabilities(this.config).namespaces) {
|
|
19363
18669
|
const recallRoots: string[] = [];
|
|
19364
18670
|
const seenRecallRoots = new Set<string>();
|
|
19365
18671
|
for (const namespace of options.recallNamespaces) {
|
|
@@ -19417,13 +18723,13 @@ export class Orchestrator {
|
|
|
19417
18723
|
if (results.length === 0) return [];
|
|
19418
18724
|
|
|
19419
18725
|
const isFullModeGraphAssist =
|
|
19420
|
-
this.config.
|
|
18726
|
+
resolveQmdCapabilities(this.config).qmdTierParityGraph &&
|
|
19421
18727
|
graphCaps.multiGraphMemory &&
|
|
19422
18728
|
caps.graphAssistInFullMode &&
|
|
19423
18729
|
options.recallMode === "full" &&
|
|
19424
18730
|
results.length >= Math.max(1, this.config.graphAssistMinSeedResults ?? 3);
|
|
19425
18731
|
const shouldRunGraphExpansion =
|
|
19426
|
-
this.config.
|
|
18732
|
+
resolveQmdCapabilities(this.config).qmdTierParityGraph &&
|
|
19427
18733
|
(options.recallMode === "graph_mode" || isFullModeGraphAssist);
|
|
19428
18734
|
|
|
19429
18735
|
if (shouldRunGraphExpansion) {
|
|
@@ -19620,7 +18926,7 @@ export class Orchestrator {
|
|
|
19620
18926
|
|
|
19621
18927
|
// Build entries from buffer, merging with existing counts
|
|
19622
18928
|
const entries: AccessTrackingEntry[] = [];
|
|
19623
|
-
const namespaces = this.config.
|
|
18929
|
+
const namespaces = resolveNamespaceCapabilities(this.config).namespaces
|
|
19624
18930
|
? Array.from(
|
|
19625
18931
|
new Set<string>([
|
|
19626
18932
|
this.config.defaultNamespace,
|
|
@@ -20580,7 +19886,7 @@ export class Orchestrator {
|
|
|
20580
19886
|
}
|
|
20581
19887
|
|
|
20582
19888
|
private namespaceFromPath(p: string): string {
|
|
20583
|
-
if (!this.config.
|
|
19889
|
+
if (!resolveNamespaceCapabilities(this.config).namespaces) return this.config.defaultNamespace;
|
|
20584
19890
|
const parts = qmdCollectionPathParts(p);
|
|
20585
19891
|
const collectionNamespace = parts
|
|
20586
19892
|
? this.qmdCollectionNamespaceFromPrefix(parts.collection)
|