@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
|
@@ -24,6 +24,7 @@
|
|
|
24
24
|
*/
|
|
25
25
|
|
|
26
26
|
import { createHash } from "node:crypto";
|
|
27
|
+
import { resolveCompressionCapabilities } from "../capabilities.js";
|
|
27
28
|
|
|
28
29
|
// StorageManager type comes from the package barrel (type-only) so this
|
|
29
30
|
// module does not add a direct storage.ts import (#1533 ratchet).
|
|
@@ -103,7 +104,7 @@ export class CompressionGuidelineCoordinator {
|
|
|
103
104
|
? draftState
|
|
104
105
|
: activeState;
|
|
105
106
|
|
|
106
|
-
if (!this.config.
|
|
107
|
+
if (!resolveCompressionCapabilities(this.config).compressionGuidelineLearning) {
|
|
107
108
|
return {
|
|
108
109
|
enabled: false,
|
|
109
110
|
dryRun,
|
|
@@ -152,7 +153,7 @@ export class CompressionGuidelineCoordinator {
|
|
|
152
153
|
}
|
|
153
154
|
const refinedCandidate =
|
|
154
155
|
await refineCompressionGuidelineCandidateSemantically(candidate, {
|
|
155
|
-
enabled: this.config.
|
|
156
|
+
enabled: resolveCompressionCapabilities(this.config).compressionGuidelineSemanticRefinement,
|
|
156
157
|
timeoutMs: this.config.compressionGuidelineSemanticTimeoutMs,
|
|
157
158
|
runRefinement: async (baseline) => {
|
|
158
159
|
const prompt = [
|
|
@@ -241,7 +242,7 @@ export class CompressionGuidelineCoordinator {
|
|
|
241
242
|
| "guideline_version_mismatch"
|
|
242
243
|
| "draft_changed";
|
|
243
244
|
}> {
|
|
244
|
-
if (!this.config.
|
|
245
|
+
if (!resolveCompressionCapabilities(this.config).compressionGuidelineLearning) {
|
|
245
246
|
return {
|
|
246
247
|
enabled: false,
|
|
247
248
|
activated: false,
|
|
@@ -312,7 +313,7 @@ export class CompressionGuidelineCoordinator {
|
|
|
312
313
|
|
|
313
314
|
/** Consolidation-time hook: recompute the draft from recent events. */
|
|
314
315
|
async runCompressionGuidelineLearningPass(): Promise<void> {
|
|
315
|
-
if (!this.config.
|
|
316
|
+
if (!resolveCompressionCapabilities(this.config).compressionGuidelineLearning) return;
|
|
316
317
|
try {
|
|
317
318
|
const result = await this.optimizeCompressionGuidelines({
|
|
318
319
|
dryRun: false,
|
|
@@ -328,8 +329,8 @@ export class CompressionGuidelineCoordinator {
|
|
|
328
329
|
|
|
329
330
|
/** Recall-time hook: surface active guidelines as a recall section. */
|
|
330
331
|
async buildCompressionGuidelineRecallSection(): Promise<string | null> {
|
|
331
|
-
if (!this.config.
|
|
332
|
-
if (!this.config.
|
|
332
|
+
if (!resolveCompressionCapabilities(this.config).contextCompressionActions) return null;
|
|
333
|
+
if (!resolveCompressionCapabilities(this.config).compressionGuidelineLearning) return null;
|
|
333
334
|
|
|
334
335
|
const state = await this.storage
|
|
335
336
|
.readCompressionGuidelineOptimizerState()
|
|
@@ -0,0 +1,504 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Lifecycle-policy coordinator — extracted from the orchestrator
|
|
3
|
+
* (issue #1526, seam 6).
|
|
4
|
+
*
|
|
5
|
+
* Owns the deterministic memory-lifecycle pipeline: heat/decay scoring
|
|
6
|
+
* (`runLifecyclePolicyPass`), fact archival (`runFactArchival`),
|
|
7
|
+
* summarization (`runSummarization`), and topic extraction
|
|
8
|
+
* (`runTopicExtraction`). Also owns the action-outcome prior builder
|
|
9
|
+
* (`buildLifecycleActionPriors` / `actionOutcomePriorDelta`) that feeds
|
|
10
|
+
* the lifecycle transition decider.
|
|
11
|
+
*
|
|
12
|
+
* The orchestrator constructs one instance and delegates the internal
|
|
13
|
+
* entrypoints to it. The public wrapper (`runLifecyclePolicyNow`)
|
|
14
|
+
* remains on the orchestrator as a thin pass-through. Storage is the
|
|
15
|
+
* orchestrator's stable `this.storage` (or a per-namespace override
|
|
16
|
+
* passed via options); the extraction engine, embedding-fallback, and
|
|
17
|
+
* content-hash callbacks arrive as deps so the orchestrator keeps
|
|
18
|
+
* ownership of gateway routing and cross-subsystem persistence.
|
|
19
|
+
*
|
|
20
|
+
* Behavior-preserving move from orchestrator.ts. No logic changes — the
|
|
21
|
+
* orchestrator keeps thin delegating methods so existing call sites
|
|
22
|
+
* and tests that exercise the public API continue to work.
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
import {
|
|
26
|
+
decideLifecycleTransition,
|
|
27
|
+
resolveLifecycleState,
|
|
28
|
+
type LifecycleSignals,
|
|
29
|
+
} from "../lifecycle.js";
|
|
30
|
+
import type { LifecycleState } from "../types.js";
|
|
31
|
+
import {
|
|
32
|
+
resolveIndexingCapabilities,
|
|
33
|
+
resolveMemoryLifecycleCapabilities,
|
|
34
|
+
resolveCreationMemoryCapabilities,
|
|
35
|
+
} from "../capabilities.js";
|
|
36
|
+
import { isActiveMemoryStatus } from "../memory-lifecycle-ledger-utils.js";
|
|
37
|
+
import { deindexMemory } from "../temporal-index.js";
|
|
38
|
+
import { extractTopics } from "../topics.js";
|
|
39
|
+
import { log } from "../logger.js";
|
|
40
|
+
import path from "node:path";
|
|
41
|
+
import { mkdir, writeFile } from "node:fs/promises";
|
|
42
|
+
import type { StorageManager } from "../index.js";
|
|
43
|
+
import type { ExtractionEngine } from "../extraction.js";
|
|
44
|
+
import type { EmbeddingFallback } from "../embedding-fallback.js";
|
|
45
|
+
import type {
|
|
46
|
+
PluginConfig,
|
|
47
|
+
MemoryFile,
|
|
48
|
+
MemoryActionEvent,
|
|
49
|
+
MemorySummary,
|
|
50
|
+
} from "../types.js";
|
|
51
|
+
|
|
52
|
+
/** Dependencies injected by the orchestrator. All stable references or
|
|
53
|
+
* live accessors. */
|
|
54
|
+
export interface LifecyclePolicyCoordinatorDeps {
|
|
55
|
+
config: PluginConfig;
|
|
56
|
+
/** Live accessor: the orchestrator's storage manager (stable post-ctor). */
|
|
57
|
+
getStorage: () => StorageManager;
|
|
58
|
+
/** The extraction engine — used for summarization. */
|
|
59
|
+
extraction: ExtractionEngine;
|
|
60
|
+
/** The embedding-fallback manager used for index cleanup on archival. */
|
|
61
|
+
embeddingFallback: EmbeddingFallback;
|
|
62
|
+
/** Effective lifecycle thresholds (promote/stale/archive). Delegated to
|
|
63
|
+
* the orchestrator which owns runtime-policy-values overlay. */
|
|
64
|
+
getEffectiveLifecycleThresholds: () => {
|
|
65
|
+
promoteHeatThreshold: number;
|
|
66
|
+
staleDecayThreshold: number;
|
|
67
|
+
archiveDecayThreshold: number;
|
|
68
|
+
};
|
|
69
|
+
/** Remove a memory's content-hash entry from the storage-scoped index.
|
|
70
|
+
* Delegated to the orchestrator which owns the per-storage index map. */
|
|
71
|
+
removeContentHashForMemory: (
|
|
72
|
+
targetStorage: StorageManager,
|
|
73
|
+
memory: MemoryFile,
|
|
74
|
+
context: string,
|
|
75
|
+
) => Promise<void>;
|
|
76
|
+
/** Persist all dirty content-hash indexes to disk. */
|
|
77
|
+
saveContentHashIndexes: () => Promise<void>;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Coordinates the memory-lifecycle policy pipeline. Holds no mutable
|
|
82
|
+
* state of its own — all persistence flows through the injected storage
|
|
83
|
+
* managers and callbacks.
|
|
84
|
+
*/
|
|
85
|
+
export class LifecyclePolicyCoordinator {
|
|
86
|
+
constructor(
|
|
87
|
+
private readonly deps: LifecyclePolicyCoordinatorDeps,
|
|
88
|
+
) {}
|
|
89
|
+
|
|
90
|
+
private get config(): PluginConfig {
|
|
91
|
+
return this.deps.config;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// -------------------------------------------------------------------------
|
|
95
|
+
// Action-outcome priors (feeds lifecycle transition decisions)
|
|
96
|
+
// -------------------------------------------------------------------------
|
|
97
|
+
|
|
98
|
+
actionOutcomePriorDelta(event: MemoryActionEvent): number {
|
|
99
|
+
if (event.outcome === "failed") return -0.3;
|
|
100
|
+
if (event.policyDecision === "deny") return -0.22;
|
|
101
|
+
if (event.policyDecision === "defer") return -0.14;
|
|
102
|
+
if (event.outcome === "skipped") return -0.1;
|
|
103
|
+
|
|
104
|
+
if (event.outcome !== "applied") return 0;
|
|
105
|
+
switch (event.action) {
|
|
106
|
+
case "store_episode":
|
|
107
|
+
case "store_note":
|
|
108
|
+
case "update_note":
|
|
109
|
+
return 0.08;
|
|
110
|
+
case "create_artifact":
|
|
111
|
+
case "summarize_node":
|
|
112
|
+
case "link_graph":
|
|
113
|
+
return 0.04;
|
|
114
|
+
case "discard":
|
|
115
|
+
return -0.03;
|
|
116
|
+
default:
|
|
117
|
+
return 0;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
async buildLifecycleActionPriors(
|
|
122
|
+
storage: StorageManager = this.deps.getStorage(),
|
|
123
|
+
): Promise<Map<string, number>> {
|
|
124
|
+
const events = await storage.readMemoryActionEvents(1200);
|
|
125
|
+
if (events.length === 0) return new Map<string, number>();
|
|
126
|
+
|
|
127
|
+
const nowMs = Date.now();
|
|
128
|
+
const windowMs = 14 * 24 * 60 * 60 * 1000;
|
|
129
|
+
const byMemory = new Map<
|
|
130
|
+
string,
|
|
131
|
+
Array<{ weightedDelta: number; weight: number }>
|
|
132
|
+
>();
|
|
133
|
+
|
|
134
|
+
for (const event of events) {
|
|
135
|
+
if (
|
|
136
|
+
typeof event.memoryId !== "string" ||
|
|
137
|
+
event.memoryId.trim().length === 0
|
|
138
|
+
)
|
|
139
|
+
continue;
|
|
140
|
+
const ts = Date.parse(event.timestamp);
|
|
141
|
+
if (!Number.isFinite(ts)) continue;
|
|
142
|
+
const ageMs = nowMs - ts;
|
|
143
|
+
if (ageMs < 0 || ageMs > windowMs) continue;
|
|
144
|
+
|
|
145
|
+
const delta = this.actionOutcomePriorDelta(event);
|
|
146
|
+
if (delta === 0) continue;
|
|
147
|
+
|
|
148
|
+
const recencyWeight = Math.max(0.2, 1 - ageMs / windowMs);
|
|
149
|
+
const list = byMemory.get(event.memoryId) ?? [];
|
|
150
|
+
if (list.length >= 8) list.shift();
|
|
151
|
+
list.push({
|
|
152
|
+
weightedDelta: delta * recencyWeight,
|
|
153
|
+
weight: recencyWeight,
|
|
154
|
+
});
|
|
155
|
+
byMemory.set(event.memoryId, list);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
const out = new Map<string, number>();
|
|
159
|
+
for (const [memoryId, deltas] of byMemory.entries()) {
|
|
160
|
+
if (deltas.length === 0) continue;
|
|
161
|
+
const weightedSum = deltas.reduce(
|
|
162
|
+
(sum, item) => sum + item.weightedDelta,
|
|
163
|
+
0,
|
|
164
|
+
);
|
|
165
|
+
const weightTotal = deltas.reduce((sum, item) => sum + item.weight, 0);
|
|
166
|
+
if (weightTotal <= 0) continue;
|
|
167
|
+
const score = weightedSum / weightTotal;
|
|
168
|
+
out.set(memoryId, Math.max(-0.25, Math.min(0.15, score)));
|
|
169
|
+
}
|
|
170
|
+
return out;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// -------------------------------------------------------------------------
|
|
174
|
+
// Lifecycle policy pass (heat/decay scoring + transition)
|
|
175
|
+
// -------------------------------------------------------------------------
|
|
176
|
+
|
|
177
|
+
async runLifecyclePolicyPass(
|
|
178
|
+
allMemories: MemoryFile[],
|
|
179
|
+
storage: StorageManager = this.deps.getStorage(),
|
|
180
|
+
): Promise<number> {
|
|
181
|
+
const now = new Date();
|
|
182
|
+
const nowIso = now.toISOString();
|
|
183
|
+
const countsByState: Record<LifecycleState, number> = {
|
|
184
|
+
candidate: 0,
|
|
185
|
+
validated: 0,
|
|
186
|
+
active: 0,
|
|
187
|
+
stale: 0,
|
|
188
|
+
archived: 0,
|
|
189
|
+
};
|
|
190
|
+
const transitionCounts: Record<string, number> = {};
|
|
191
|
+
let updatedCount = 0;
|
|
192
|
+
let disputedCount = 0;
|
|
193
|
+
let evaluatedCount = 0;
|
|
194
|
+
const lifecycleCaps = resolveMemoryLifecycleCapabilities(this.config);
|
|
195
|
+
|
|
196
|
+
const thresholds = this.deps.getEffectiveLifecycleThresholds();
|
|
197
|
+
const policy = {
|
|
198
|
+
promoteHeatThreshold: thresholds.promoteHeatThreshold,
|
|
199
|
+
staleDecayThreshold: thresholds.staleDecayThreshold,
|
|
200
|
+
archiveDecayThreshold: thresholds.archiveDecayThreshold,
|
|
201
|
+
protectedCategories: this.config.lifecycleProtectedCategories,
|
|
202
|
+
};
|
|
203
|
+
const actionPriors = await this.buildLifecycleActionPriors(storage);
|
|
204
|
+
|
|
205
|
+
for (const memory of allMemories) {
|
|
206
|
+
if (
|
|
207
|
+
memory.frontmatter.status === "superseded" ||
|
|
208
|
+
memory.frontmatter.status === "forgotten"
|
|
209
|
+
) {
|
|
210
|
+
continue;
|
|
211
|
+
}
|
|
212
|
+
evaluatedCount += 1;
|
|
213
|
+
const currentState = resolveLifecycleState(memory.frontmatter);
|
|
214
|
+
const actionPriorScore = actionPriors.get(memory.frontmatter.id);
|
|
215
|
+
const signals: LifecycleSignals | undefined =
|
|
216
|
+
typeof actionPriorScore === "number" &&
|
|
217
|
+
Number.isFinite(actionPriorScore)
|
|
218
|
+
? { actionPriorScore }
|
|
219
|
+
: undefined;
|
|
220
|
+
const decision = decideLifecycleTransition(memory, policy, now, signals);
|
|
221
|
+
const nextState: LifecycleState =
|
|
222
|
+
memory.frontmatter.status === "archived"
|
|
223
|
+
? "archived"
|
|
224
|
+
: decision.nextState;
|
|
225
|
+
|
|
226
|
+
countsByState[nextState] += 1;
|
|
227
|
+
if (memory.frontmatter.verificationState === "disputed") {
|
|
228
|
+
disputedCount += 1;
|
|
229
|
+
}
|
|
230
|
+
if (nextState !== currentState) {
|
|
231
|
+
const key = `${currentState}->${nextState}`;
|
|
232
|
+
transitionCounts[key] = (transitionCounts[key] ?? 0) + 1;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
const prevHeat = memory.frontmatter.heatScore;
|
|
236
|
+
const prevDecay = memory.frontmatter.decayScore;
|
|
237
|
+
const scoreDelta =
|
|
238
|
+
Math.abs((prevHeat ?? -1) - decision.heatScore) +
|
|
239
|
+
Math.abs((prevDecay ?? -1) - decision.decayScore);
|
|
240
|
+
const shouldPersist =
|
|
241
|
+
memory.frontmatter.lifecycleState !== nextState ||
|
|
242
|
+
memory.frontmatter.heatScore === undefined ||
|
|
243
|
+
memory.frontmatter.decayScore === undefined ||
|
|
244
|
+
memory.frontmatter.lastValidatedAt === undefined ||
|
|
245
|
+
scoreDelta >= 0.01;
|
|
246
|
+
|
|
247
|
+
if (!shouldPersist) continue;
|
|
248
|
+
|
|
249
|
+
const wrote = await storage.writeMemoryFrontmatter(memory, {
|
|
250
|
+
lifecycleState: nextState,
|
|
251
|
+
heatScore: decision.heatScore,
|
|
252
|
+
decayScore: decision.decayScore,
|
|
253
|
+
lastValidatedAt: nowIso,
|
|
254
|
+
});
|
|
255
|
+
if (wrote) updatedCount += 1;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
// Report how many memories had frontmatter rewritten so callers can record a
|
|
259
|
+
// catalog write touch for lifecycle-only passes (codex NR-tS).
|
|
260
|
+
if (!lifecycleCaps.lifecycleMetrics) return updatedCount;
|
|
261
|
+
|
|
262
|
+
const total = evaluatedCount;
|
|
263
|
+
const metrics = {
|
|
264
|
+
generatedAt: nowIso,
|
|
265
|
+
memoriesEvaluated: total,
|
|
266
|
+
memoriesUpdated: updatedCount,
|
|
267
|
+
countsByLifecycleState: countsByState,
|
|
268
|
+
transitionCounts,
|
|
269
|
+
staleRatio: total > 0 ? countsByState.stale / total : 0,
|
|
270
|
+
disputedRatio: total > 0 ? disputedCount / total : 0,
|
|
271
|
+
policy: {
|
|
272
|
+
promoteHeatThreshold: thresholds.promoteHeatThreshold,
|
|
273
|
+
staleDecayThreshold: thresholds.staleDecayThreshold,
|
|
274
|
+
archiveDecayThreshold: thresholds.archiveDecayThreshold,
|
|
275
|
+
protectedCategories: this.config.lifecycleProtectedCategories,
|
|
276
|
+
},
|
|
277
|
+
};
|
|
278
|
+
const metricsPath = path.join(
|
|
279
|
+
storage.dir,
|
|
280
|
+
"state",
|
|
281
|
+
"lifecycle-metrics.json",
|
|
282
|
+
);
|
|
283
|
+
await mkdir(path.dirname(metricsPath), { recursive: true });
|
|
284
|
+
await writeFile(metricsPath, JSON.stringify(metrics, null, 2), "utf-8");
|
|
285
|
+
return updatedCount;
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
// -------------------------------------------------------------------------
|
|
289
|
+
// Fact archival
|
|
290
|
+
// -------------------------------------------------------------------------
|
|
291
|
+
|
|
292
|
+
/**
|
|
293
|
+
* Archive old, low-importance, rarely-accessed facts (v6.0).
|
|
294
|
+
* Moves eligible facts from facts/ to archive/YYYY-MM-DD/.
|
|
295
|
+
* Returns the number of archived facts.
|
|
296
|
+
*/
|
|
297
|
+
async runFactArchival(
|
|
298
|
+
allMemories: MemoryFile[],
|
|
299
|
+
): Promise<number> {
|
|
300
|
+
const storage = this.deps.getStorage();
|
|
301
|
+
const now = Date.now();
|
|
302
|
+
const ageCutoffMs = this.config.factArchivalAgeDays * 24 * 60 * 60 * 1000;
|
|
303
|
+
const protectedCategories = new Set(
|
|
304
|
+
this.config.factArchivalProtectedCategories,
|
|
305
|
+
);
|
|
306
|
+
let archivedCount = 0;
|
|
307
|
+
|
|
308
|
+
for (const memory of allMemories) {
|
|
309
|
+
const fm = memory.frontmatter;
|
|
310
|
+
|
|
311
|
+
// Skip already-archived or superseded
|
|
312
|
+
if (fm.status && fm.status !== "active") continue;
|
|
313
|
+
|
|
314
|
+
// Skip protected categories
|
|
315
|
+
if (protectedCategories.has(fm.category)) continue;
|
|
316
|
+
|
|
317
|
+
// Skip corrections (always keep)
|
|
318
|
+
if (fm.category === "correction") continue;
|
|
319
|
+
|
|
320
|
+
// Check age requirement
|
|
321
|
+
const createdMs = new Date(fm.created).getTime();
|
|
322
|
+
if (now - createdMs < ageCutoffMs) continue;
|
|
323
|
+
|
|
324
|
+
// Check importance (only archive low-importance facts)
|
|
325
|
+
const importanceScore = fm.importance?.score ?? 0.5;
|
|
326
|
+
if (importanceScore >= this.config.factArchivalMaxImportance) continue;
|
|
327
|
+
|
|
328
|
+
// Check access count
|
|
329
|
+
const accessCount = fm.accessCount ?? 0;
|
|
330
|
+
if (accessCount > this.config.factArchivalMaxAccessCount) continue;
|
|
331
|
+
|
|
332
|
+
// All criteria met — archive
|
|
333
|
+
const result = await storage.archiveMemory(memory);
|
|
334
|
+
if (result) {
|
|
335
|
+
// Remove from the same storage-scoped content-hash index since it is
|
|
336
|
+
// no longer in hot search.
|
|
337
|
+
await this.deps.removeContentHashForMemory(
|
|
338
|
+
storage,
|
|
339
|
+
memory,
|
|
340
|
+
"fact-archival",
|
|
341
|
+
);
|
|
342
|
+
await this.deps.embeddingFallback.removeFromIndex(memory.frontmatter.id);
|
|
343
|
+
if (
|
|
344
|
+
resolveIndexingCapabilities(this.config).queryAwareIndexing &&
|
|
345
|
+
memory.path &&
|
|
346
|
+
memory.frontmatter?.created
|
|
347
|
+
) {
|
|
348
|
+
deindexMemory(
|
|
349
|
+
this.config.memoryDir,
|
|
350
|
+
memory.path,
|
|
351
|
+
memory.frontmatter.created,
|
|
352
|
+
memory.frontmatter.tags ?? [],
|
|
353
|
+
);
|
|
354
|
+
}
|
|
355
|
+
archivedCount++;
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
// Save hash indexes if we removed any entries.
|
|
360
|
+
if (archivedCount > 0) {
|
|
361
|
+
await this.deps.saveContentHashIndexes().catch((err) =>
|
|
362
|
+
log.warn(`content-hash index save failed during archival: ${err}`),
|
|
363
|
+
);
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
return archivedCount;
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
// -------------------------------------------------------------------------
|
|
370
|
+
// Summarization (Phase 4A)
|
|
371
|
+
// -------------------------------------------------------------------------
|
|
372
|
+
|
|
373
|
+
/**
|
|
374
|
+
* Run memory summarization if memory count exceeds threshold (Phase 4A).
|
|
375
|
+
*/
|
|
376
|
+
async runSummarization(
|
|
377
|
+
allMemories: MemoryFile[],
|
|
378
|
+
): Promise<void> {
|
|
379
|
+
const storage = this.deps.getStorage();
|
|
380
|
+
// Only active memories count toward the threshold
|
|
381
|
+
const activeMemories = allMemories.filter(
|
|
382
|
+
(m) => isActiveMemoryStatus(m.frontmatter.status),
|
|
383
|
+
);
|
|
384
|
+
|
|
385
|
+
if (activeMemories.length < this.config.summarizationTriggerCount) {
|
|
386
|
+
return;
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
log.info(
|
|
390
|
+
`memory count (${activeMemories.length}) exceeds threshold (${this.config.summarizationTriggerCount}) — running summarization`,
|
|
391
|
+
);
|
|
392
|
+
|
|
393
|
+
// Sort by creation date, oldest first
|
|
394
|
+
const sorted = activeMemories.sort(
|
|
395
|
+
(a, b) =>
|
|
396
|
+
new Date(a.frontmatter.created).getTime() -
|
|
397
|
+
new Date(b.frontmatter.created).getTime(),
|
|
398
|
+
);
|
|
399
|
+
|
|
400
|
+
// Keep recent memories, with explicit zero handling so `slice(-0)` does not
|
|
401
|
+
// accidentally keep every memory out of the summarization candidate set.
|
|
402
|
+
const recentToKeep = Math.max(0, this.config.summarizationRecentToKeep);
|
|
403
|
+
const toSummarize = recentToKeep > 0 ? sorted.slice(0, -recentToKeep) : sorted;
|
|
404
|
+
|
|
405
|
+
// Filter candidates for summarization
|
|
406
|
+
const candidates = toSummarize.filter((m) => {
|
|
407
|
+
// Skip if protected by entity reference
|
|
408
|
+
if (m.frontmatter.entityRef) return false;
|
|
409
|
+
|
|
410
|
+
// Skip if protected by tag
|
|
411
|
+
const protectedTags = this.config.summarizationProtectedTags;
|
|
412
|
+
if (m.frontmatter.tags.some((t) => protectedTags.includes(t)))
|
|
413
|
+
return false;
|
|
414
|
+
|
|
415
|
+
// Skip if importance is above threshold
|
|
416
|
+
const importance = m.frontmatter.importance?.score ?? 0.5;
|
|
417
|
+
if (importance >= this.config.summarizationImportanceThreshold)
|
|
418
|
+
return false;
|
|
419
|
+
|
|
420
|
+
return true;
|
|
421
|
+
});
|
|
422
|
+
|
|
423
|
+
if (candidates.length < 50) {
|
|
424
|
+
log.debug(
|
|
425
|
+
`only ${candidates.length} candidates for summarization — skipping`,
|
|
426
|
+
);
|
|
427
|
+
return;
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
// Summarize in batches of 50
|
|
431
|
+
const batchSize = 50;
|
|
432
|
+
for (let i = 0; i < candidates.length; i += batchSize) {
|
|
433
|
+
const batch = candidates.slice(i, i + batchSize);
|
|
434
|
+
const batchData = batch.map((m) => ({
|
|
435
|
+
id: m.frontmatter.id,
|
|
436
|
+
content: m.content,
|
|
437
|
+
category: m.frontmatter.category,
|
|
438
|
+
created: m.frontmatter.created,
|
|
439
|
+
}));
|
|
440
|
+
|
|
441
|
+
const result = await this.deps.extraction.summarizeMemories(batchData);
|
|
442
|
+
if (!result) continue;
|
|
443
|
+
|
|
444
|
+
// Create summary
|
|
445
|
+
const summary: MemorySummary = {
|
|
446
|
+
id: `summary-${Date.now()}-${Math.random().toString(36).slice(2, 6)}`,
|
|
447
|
+
createdAt: new Date().toISOString(),
|
|
448
|
+
timeRangeStart: batch[0].frontmatter.created,
|
|
449
|
+
timeRangeEnd: batch[batch.length - 1].frontmatter.created,
|
|
450
|
+
summaryText: result.summaryText,
|
|
451
|
+
keyFacts: result.keyFacts,
|
|
452
|
+
keyEntities: result.keyEntities,
|
|
453
|
+
sourceEpisodeIds: batch.map((m) => m.frontmatter.id),
|
|
454
|
+
};
|
|
455
|
+
|
|
456
|
+
await storage.writeSummary(summary);
|
|
457
|
+
|
|
458
|
+
// Archive source memories
|
|
459
|
+
const archived = await storage.archiveMemories(
|
|
460
|
+
batch.map((m) => m.frontmatter.id),
|
|
461
|
+
summary.id,
|
|
462
|
+
);
|
|
463
|
+
|
|
464
|
+
// Catalog write touch (issue #1499 sweep): summarization writes a durable
|
|
465
|
+
// summary and then rewrites source-memory archive status, bypassing the
|
|
466
|
+
// extraction write path. Record the touch after both mutations complete so
|
|
467
|
+
// `lastWriteAt` covers the final archived-state write.
|
|
468
|
+
// #1522: catalog touch handled at the storage chokepoint.
|
|
469
|
+
|
|
470
|
+
log.info(
|
|
471
|
+
`created summary ${summary.id} from ${batch.length} memories, archived ${archived}`,
|
|
472
|
+
);
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
// -------------------------------------------------------------------------
|
|
477
|
+
// Topic extraction (Phase 4B)
|
|
478
|
+
// -------------------------------------------------------------------------
|
|
479
|
+
|
|
480
|
+
/**
|
|
481
|
+
* Run topic extraction on all memories (Phase 4B).
|
|
482
|
+
*/
|
|
483
|
+
async runTopicExtraction(
|
|
484
|
+
allMemories: MemoryFile[],
|
|
485
|
+
): Promise<void> {
|
|
486
|
+
const storage = this.deps.getStorage();
|
|
487
|
+
// Only extract from active memories
|
|
488
|
+
const activeMemories = allMemories.filter(
|
|
489
|
+
(m) => isActiveMemoryStatus(m.frontmatter.status),
|
|
490
|
+
);
|
|
491
|
+
|
|
492
|
+
if (activeMemories.length === 0) return;
|
|
493
|
+
|
|
494
|
+
const topics = extractTopics(
|
|
495
|
+
activeMemories,
|
|
496
|
+
this.config.topicExtractionTopN,
|
|
497
|
+
);
|
|
498
|
+
await storage.saveTopics(topics);
|
|
499
|
+
|
|
500
|
+
log.debug(
|
|
501
|
+
`extracted ${topics.length} topics from ${activeMemories.length} memories`,
|
|
502
|
+
);
|
|
503
|
+
}
|
|
504
|
+
}
|
|
@@ -19,6 +19,10 @@
|
|
|
19
19
|
* `orchestrator.requestQmdMaintenance` etc. continue to work.
|
|
20
20
|
*/
|
|
21
21
|
|
|
22
|
+
import {
|
|
23
|
+
resolveNamespaceCapabilities,
|
|
24
|
+
resolveQmdCapabilities,
|
|
25
|
+
} from "../capabilities.js";
|
|
22
26
|
import { existsSync } from "node:fs";
|
|
23
27
|
import path from "node:path";
|
|
24
28
|
|
|
@@ -403,7 +407,7 @@ export class MaintenanceScheduler {
|
|
|
403
407
|
/** Internal: queue a debounced QMD maintenance pass. */
|
|
404
408
|
private requestQmdMaintenance(): void {
|
|
405
409
|
if (!this.deps.getQmd().isAvailable()) return;
|
|
406
|
-
if (!this.deps.config.
|
|
410
|
+
if (!resolveQmdCapabilities(this.deps.config).qmdMaintenance) return;
|
|
407
411
|
|
|
408
412
|
this.qmdMaintenancePending = true;
|
|
409
413
|
if (this.qmdMaintenanceTimer) return;
|
|
@@ -437,7 +441,7 @@ export class MaintenanceScheduler {
|
|
|
437
441
|
this.qmdMaintenancePending = false;
|
|
438
442
|
|
|
439
443
|
try {
|
|
440
|
-
if (this.deps.config.
|
|
444
|
+
if (resolveNamespaceCapabilities(this.deps.config).namespaces) {
|
|
441
445
|
// Include cataloged dynamic namespaces, not just the configured set
|
|
442
446
|
// (NGnei), but run through the namespace-aware maintenance planner so
|
|
443
447
|
// each namespace is budgeted, lock-protected, and status-recorded
|
|
@@ -446,7 +450,7 @@ export class MaintenanceScheduler {
|
|
|
446
450
|
const now = Date.now();
|
|
447
451
|
const lastEmbedAtByNamespace = this.lastQmdEmbedAtMsByNamespace;
|
|
448
452
|
const dueEmbedNamespaces = (namespaces: string[]): string[] => {
|
|
449
|
-
if (!this.deps.config.
|
|
453
|
+
if (!resolveQmdCapabilities(this.deps.config).qmdAutoEmbed) return [];
|
|
450
454
|
return namespaces.filter(
|
|
451
455
|
(namespace) =>
|
|
452
456
|
now - (lastEmbedAtByNamespace.get(namespace) ?? 0) >=
|
|
@@ -514,7 +518,7 @@ export class MaintenanceScheduler {
|
|
|
514
518
|
await this.deps.getQmd().update();
|
|
515
519
|
const now = Date.now();
|
|
516
520
|
if (
|
|
517
|
-
this.deps.config.
|
|
521
|
+
resolveQmdCapabilities(this.deps.config).qmdAutoEmbed &&
|
|
518
522
|
now - this.lastQmdEmbedAtMs >= this.deps.config.qmdEmbedMinIntervalMs
|
|
519
523
|
) {
|
|
520
524
|
await this.deps.getQmd().embed();
|