@remnic/core 9.50.0 → 9.50.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/access-admin-ops-surface.d.ts +10 -10
- package/dist/access-admin-ops-surface.js +15 -15
- package/dist/access-authorization-probe.d.ts +10 -10
- package/dist/access-authorization-probe.js +16 -16
- package/dist/access-boundary.d.ts +10 -10
- package/dist/access-boundary.js +15 -15
- package/dist/access-cli.js +39 -39
- package/dist/access-coding-context-resolution.d.ts +1 -1
- package/dist/access-extraction-force-flush.d.ts +10 -10
- package/dist/access-extraction-force-flush.js +15 -15
- package/dist/access-health-types.d.ts +1 -1
- package/dist/access-http-lcm-compaction.d.ts +10 -10
- package/dist/access-http-lifecycle-flush.d.ts +10 -10
- package/dist/access-http-offline-stream.d.ts +10 -10
- package/dist/access-http-query.js +15 -15
- package/dist/access-http.d.ts +10 -10
- package/dist/access-http.js +21 -21
- package/dist/access-identity-continuity-surface.d.ts +8 -8
- package/dist/access-identity-continuity-surface.js +15 -15
- package/dist/access-lcm-surface.d.ts +10 -10
- package/dist/access-lcm-surface.js +15 -15
- package/dist/access-mcp.d.ts +10 -10
- package/dist/access-mcp.js +19 -19
- package/dist/access-memory-search-fanout.d.ts +2 -2
- package/dist/{access-namespace-preflight-DuDU301-.d.ts → access-namespace-preflight-Dj2QolFE.d.ts} +1 -1
- package/dist/access-namespace-preflight.d.ts +3 -3
- package/dist/access-namespace-preflight.js +15 -15
- package/dist/access-observe-write-surface.d.ts +10 -10
- package/dist/access-observe-write-surface.js +15 -15
- package/dist/access-offline-manifest.d.ts +8 -8
- package/dist/access-operations-batch.js +16 -16
- package/dist/access-operations.d.ts +10 -10
- package/dist/access-operations.js +18 -18
- package/dist/access-recall-concurrency.d.ts +10 -10
- package/dist/access-recall-concurrency.js +15 -15
- package/dist/access-recall-response.d.ts +10 -10
- package/dist/access-recall-response.js +15 -15
- package/dist/access-recall-surface.d.ts +10 -10
- package/dist/access-recall-surface.js +15 -15
- package/dist/{access-service--_3T_v23.d.ts → access-service-DesbnTSa.d.ts} +7 -7
- package/dist/access-service-helpers.d.ts +10 -10
- package/dist/access-service.d.ts +10 -10
- package/dist/access-service.js +15 -15
- package/dist/access-surface-catalog.d.ts +10 -10
- package/dist/access-wearables-meetings-surface.d.ts +3 -3
- package/dist/action-confidence.d.ts +1 -1
- package/dist/active-memory-bridge.d.ts +1 -1
- package/dist/active-recall.d.ts +1 -1
- package/dist/ambient-provenance.d.ts +1 -1
- package/dist/artifact-search.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 +8 -8
- package/dist/briefing.d.ts +2 -2
- package/dist/briefing.js +6 -6
- package/dist/buffer-surprise-report.d.ts +1 -1
- package/dist/buffer-turn-helpers.d.ts +1 -1
- package/dist/buffer.d.ts +2 -2
- package/dist/bulk-import/index.d.ts +3 -3
- package/dist/calibration.d.ts +1 -1
- package/dist/capabilities.d.ts +1 -1
- package/dist/{capsule-merge-KXTRZ23Z.js → capsule-merge-XMFBXVDP.js} +4 -4
- package/dist/{catalog-DjUmUIal.d.ts → catalog-D-G7RgXR.d.ts} +1 -1
- package/dist/causal-behavior.d.ts +1 -1
- package/dist/causal-consolidation.d.ts +1 -1
- package/dist/causal-consolidation.js +7 -7
- package/dist/causal-trajectory-graph.d.ts +1 -1
- package/dist/{chunk-N3CXAYPJ.js → chunk-2HGUDBRJ.js} +2 -2
- package/dist/{chunk-FV7YQTN3.js → chunk-2S72LWKX.js} +2 -2
- package/dist/{chunk-NKL25FCF.js → chunk-4MBPIL4V.js} +2 -2
- package/dist/{chunk-ZN4EYMKJ.js → chunk-67QG75MJ.js} +2 -2
- package/dist/{chunk-JI62YGPI.js → chunk-6QPHF6RR.js} +2 -2
- package/dist/{chunk-4EABKPZS.js → chunk-75XOWNRS.js} +4 -4
- package/dist/{chunk-O76MWTVS.js → chunk-7BAYBYY5.js} +2 -2
- package/dist/{chunk-4JWJMRPJ.js → chunk-7PKFPLLZ.js} +2 -2
- package/dist/{chunk-24BKGKGO.js → chunk-BOFVT6P3.js} +5 -5
- package/dist/{chunk-3LD4N2TF.js → chunk-D73B6HMN.js} +67 -81
- package/dist/chunk-D73B6HMN.js.map +1 -0
- package/dist/{chunk-SHYIMIX5.js → chunk-ESG7Z255.js} +2 -2
- package/dist/{chunk-P26YHAQH.js → chunk-EWMTOVMY.js} +51 -27
- package/dist/chunk-EWMTOVMY.js.map +1 -0
- package/dist/{chunk-WPZX7MEA.js → chunk-FXX6RQYC.js} +3 -3
- package/dist/{chunk-S75UQ3T3.js → chunk-GDDGZVFI.js} +2 -2
- package/dist/{chunk-S2SJEOTM.js → chunk-GFIKG4FR.js} +2 -2
- package/dist/{chunk-7NDM2PNK.js → chunk-GZICBRWK.js} +2 -2
- package/dist/{chunk-LQKXVQZR.js → chunk-HS4M6BZM.js} +5 -5
- package/dist/{chunk-7BLWBSRL.js → chunk-IB25FBMX.js} +2 -2
- package/dist/{chunk-GKEYXXKX.js → chunk-IXXABW5A.js} +2 -2
- package/dist/{chunk-GGBSF2X7.js → chunk-JB6D7EFB.js} +2 -2
- package/dist/{chunk-T35UJI5R.js → chunk-JFNRA7YJ.js} +18 -18
- package/dist/{chunk-E633OXMH.js → chunk-JPHEOE6Z.js} +8 -8
- package/dist/{chunk-ELQCS47S.js → chunk-LOW66JRO.js} +3 -3
- package/dist/{chunk-JDCQK3C5.js → chunk-M4A44LUA.js} +2 -2
- package/dist/{chunk-RBPH3GZV.js → chunk-NZ6UDRUA.js} +26 -29
- package/dist/chunk-NZ6UDRUA.js.map +1 -0
- package/dist/{chunk-PWLB4TRK.js → chunk-OQAL6SIR.js} +2 -2
- package/dist/{chunk-6XGEBQ3R.js → chunk-P7ADRREJ.js} +3 -3
- package/dist/{chunk-EURCX6PS.js → chunk-PWN32TAG.js} +2 -2
- package/dist/{chunk-P4QOYG52.js → chunk-QN7NTKRC.js} +1 -1
- package/dist/{chunk-ZJIFYUJI.js → chunk-SV3PSA7Y.js} +2 -2
- package/dist/{chunk-7VWZ4LRW.js → chunk-T6RATUV2.js} +2 -2
- package/dist/{chunk-GSEPRIZC.js → chunk-TS4AJ2GI.js} +2 -2
- package/dist/{chunk-PWIMF7LP.js → chunk-UWIDGVQM.js} +10 -10
- package/dist/{chunk-VFS3MK5F.js → chunk-V5H6OJCR.js} +2 -2
- package/dist/{chunk-4S3ECH3U.js → chunk-VJXY5ZCT.js} +2 -2
- package/dist/{chunk-PLCHU56K.js → chunk-YQ4IQ2GA.js} +2 -2
- package/dist/{chunk-LTOAJXZB.js → chunk-Z3RHPGSY.js} +3 -3
- package/dist/{chunk-QWLW3VQH.js → chunk-ZCO5F5FW.js} +2 -2
- package/dist/{chunk-5XCN4XBU.js → chunk-ZQOCRIGA.js} +3 -3
- package/dist/{cli-BLNmNEMT.d.ts → cli-D4vvtxjY.d.ts} +5 -5
- package/dist/cli.d.ts +12 -12
- package/dist/cli.js +32 -32
- package/dist/coding/pre-action-gate.d.ts +1 -1
- package/dist/compounding/engine.d.ts +2 -2
- package/dist/compounding/engine.js +6 -6
- 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-runner.js +6 -6
- package/dist/connectors/codex-materialize.d.ts +1 -1
- package/dist/connectors/index.d.ts +1 -1
- package/dist/connectors/index.js +6 -6
- package/dist/consolidation-provenance-check.d.ts +2 -2
- package/dist/consolidation-provenance-check.js +4 -4
- package/dist/consolidation-undo.d.ts +2 -2
- package/dist/consolidation-undo.js +3 -3
- package/dist/contradiction/index.d.ts +2 -2
- package/dist/converge-config.d.ts +1 -1
- package/dist/convergence-refresh.d.ts +2 -2
- package/dist/convergence-refresh.js +8 -8
- 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/corpus-watermark.d.ts +1 -1
- package/dist/corpus-watermark.js +8 -8
- package/dist/day-summary.d.ts +1 -1
- package/dist/delinearize.d.ts +1 -1
- package/dist/dependency-propagation-config.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/enrichment/index.d.ts +1 -1
- package/dist/entity-retrieval.d.ts +2 -2
- package/dist/entity-retrieval.js +6 -6
- package/dist/entity-schema.d.ts +1 -1
- package/dist/explicit-capture.d.ts +8 -8
- package/dist/explicit-capture.js +4 -4
- package/dist/external-wiki-access.d.ts +10 -10
- package/dist/external-wiki-access.js +16 -16
- package/dist/external-wiki-collection-registration.d.ts +1 -1
- package/dist/external-wiki-collection.d.ts +1 -1
- package/dist/external-wiki-mcp-tools.d.ts +10 -10
- package/dist/extraction-error-classification.d.ts +1 -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-liveness.d.ts +1 -1
- package/dist/extraction-normalization.d.ts +1 -1
- package/dist/extraction-prompt.d.ts +1 -1
- package/dist/extraction-source-grounding-rules.d.ts +1 -1
- package/dist/extraction-source-grounding.d.ts +1 -1
- package/dist/extraction.d.ts +17 -18
- package/dist/extraction.js +7 -7
- package/dist/fallback-llm.d.ts +1 -1
- package/dist/{forget-GJ42LCBW.js → forget-UJDJHG6R.js} +2 -2
- package/dist/graph-dashboard-diff.d.ts +1 -1
- package/dist/graph-dashboard-key.d.ts +1 -1
- package/dist/graph-dashboard-parser.d.ts +1 -1
- package/dist/graph-edge-reinforcement.d.ts +1 -1
- package/dist/graph-snapshot.d.ts +1 -1
- package/dist/graph.d.ts +1 -1
- package/dist/harmonic-retrieval.js +1 -1
- package/dist/importance.d.ts +1 -1
- package/dist/importers/index.d.ts +1 -1
- package/dist/in-flight-reads.d.ts +1 -1
- package/dist/index.d.ts +19 -19
- package/dist/index.js +39 -39
- 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-model-endpoint.d.ts +1 -1
- package/dist/maintenance/memory-governance.d.ts +1 -1
- package/dist/maintenance/memory-governance.js +6 -6
- package/dist/maintenance/rebuild-memory-lifecycle-ledger.d.ts +2 -2
- package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +6 -6
- package/dist/maintenance/rebuild-memory-projection.d.ts +2 -2
- package/dist/maintenance/rebuild-memory-projection.js +7 -7
- package/dist/{maintenance-DKbKZi3u.d.ts → maintenance-ClmUVpGI.d.ts} +3 -3
- package/dist/mcp-memory-inspector-app.d.ts +10 -10
- 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-snapshot.d.ts +1 -1
- package/dist/memory-worth-outcomes.d.ts +2 -2
- package/dist/models-json.d.ts +1 -1
- package/dist/namespaces/migrate.d.ts +3 -3
- package/dist/namespaces/migrate.js +7 -7
- package/dist/namespaces/principal.d.ts +1 -1
- package/dist/namespaces/search.d.ts +1 -1
- package/dist/namespaces/storage.d.ts +3 -3
- package/dist/namespaces/storage.js +6 -6
- package/dist/native-knowledge.d.ts +1 -1
- package/dist/offline-sync-impression-drain.d.ts +1 -1
- package/dist/operator-doctor-corpus.d.ts +1 -1
- package/dist/operator-doctor-corpus.js +9 -9
- package/dist/operator-doctor-replica.d.ts +1 -1
- package/dist/operator-toolkit.d.ts +3 -3
- package/dist/operator-toolkit.js +14 -14
- package/dist/orchestration/compression-guideline-coordinator.d.ts +2 -2
- package/dist/orchestration/maintenance.d.ts +4 -4
- package/dist/orchestration/maintenance.js +11 -11
- package/dist/{orchestrator-BRwD7ceU.d.ts → orchestrator-qJ07zI8H.d.ts} +8 -12
- package/dist/orchestrator.d.ts +8 -8
- package/dist/orchestrator.js +39 -39
- package/dist/page-versioning.js +3 -3
- package/dist/patterns-cli.d.ts +1 -1
- package/dist/{pipeline-DC-1C9T8.d.ts → pipeline-WFCxhHOn.d.ts} +1 -1
- package/dist/policy-runtime.d.ts +1 -1
- package/dist/proactive-contention.d.ts +1 -1
- package/dist/provenance.d.ts +1 -1
- package/dist/{qmd-DdeCEZdb.d.ts → qmd-5tzkQ44y.d.ts} +1 -1
- package/dist/qmd-preflight.d.ts +2 -2
- package/dist/qmd-recall-cache.d.ts +1 -1
- package/dist/qmd.d.ts +2 -2
- package/dist/recall-concurrency-config.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-memory-map.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-timings.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/reconcile/cursor.d.ts +1 -1
- package/dist/reconcile/manifest.d.ts +1 -1
- package/dist/reconcile/plan.d.ts +1 -1
- package/dist/replay/normalizers/chatgpt.d.ts +1 -1
- package/dist/replay/normalizers/claude.d.ts +1 -1
- package/dist/replay/normalizers/openclaw.d.ts +1 -1
- package/dist/replay/normalizers/shared.d.ts +1 -1
- package/dist/replay/runner.d.ts +1 -1
- package/dist/replay/types.d.ts +1 -1
- package/dist/replica-divergence.d.ts +1 -1
- package/dist/replica-peers-config.d.ts +1 -1
- package/dist/resolve-auth-token.d.ts +1 -1
- package/dist/retrieval-agents.d.ts +2 -2
- 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/salvage-envelope.d.ts +1 -1
- package/dist/{scope-profiles-BXVq4Jv0.d.ts → scope-profiles--vfXPl3X.d.ts} +1 -1
- package/dist/search/embed-helper.d.ts +1 -1
- package/dist/search/factory.d.ts +1 -1
- package/dist/search/index.d.ts +1 -1
- package/dist/search/lancedb-backend.d.ts +1 -1
- package/dist/search/meilisearch-backend.d.ts +1 -1
- package/dist/search/noop-backend.d.ts +1 -1
- package/dist/search/orama-backend.d.ts +1 -1
- package/dist/search/port.d.ts +1 -1
- package/dist/search/remote-backend.d.ts +1 -1
- package/dist/{semantic-consolidation-CGYxfa8F.d.ts → semantic-consolidation-BBDuP9nJ.d.ts} +1 -1
- package/dist/semantic-consolidation.d.ts +2 -2
- package/dist/semantic-consolidation.js +7 -7
- package/dist/semantic-rule-promotion.js +6 -6
- package/dist/semantic-rule-verifier.d.ts +1 -1
- package/dist/semantic-rule-verifier.js +6 -6
- package/dist/{service-CBDBQFCN.d.ts → service-B8DtbpCM.d.ts} +2 -2
- package/dist/session-observer-bands.d.ts +1 -1
- package/dist/session-observer-state.d.ts +1 -1
- package/dist/shared-context/manager.d.ts +1 -1
- package/dist/signal.d.ts +1 -1
- package/dist/source-agent-qualifier.d.ts +1 -1
- package/dist/source-agent-qualifier.js +6 -6
- package/dist/{storage-V--MQi7w.d.ts → storage-BkYN1RIy.d.ts} +1 -1
- package/dist/storage.d.ts +2 -2
- package/dist/storage.js +5 -5
- package/dist/summarizer.d.ts +1 -1
- package/dist/summary-snapshot.d.ts +1 -1
- package/dist/temporal-supersession.d.ts +2 -2
- package/dist/temporal-supersession.js +1 -1
- package/dist/temporal-timeline-recall.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 +2 -2
- package/dist/tier-routing.d.ts +1 -1
- package/dist/topics.d.ts +1 -1
- package/dist/transcript.d.ts +1 -1
- package/dist/transfer/capsule-import.js +4 -4
- package/dist/trust-score-stage.d.ts +1 -1
- package/dist/trust-score.d.ts +1 -1
- package/dist/{types-D_a6Sqjz.d.ts → types-u2s9j1uD.d.ts} +1 -1
- package/dist/types.d.ts +1 -1
- package/dist/utility-runtime.d.ts +1 -1
- package/dist/verified-recall.js +6 -6
- package/dist/write-envelope.d.ts +1 -1
- package/package.json +2 -2
- package/src/dependency-revalidation-routing.test.ts +165 -0
- package/src/extraction.ts +46 -31
- package/src/orchestration/dependency-propagation.test.ts +89 -8
- package/src/orchestration/dependency-propagation.ts +60 -27
- package/src/orchestration/dependency-revalidation.test.ts +119 -0
- package/src/orchestration/dependency-revalidation.ts +31 -82
- package/src/orchestrator.ts +5 -7
- package/src/testing/subjects/dependency-propagation.test.ts +367 -0
- package/dist/chunk-3LD4N2TF.js.map +0 -1
- package/dist/chunk-P26YHAQH.js.map +0 -1
- package/dist/chunk-RBPH3GZV.js.map +0 -1
- /package/dist/{capsule-merge-KXTRZ23Z.js.map → capsule-merge-XMFBXVDP.js.map} +0 -0
- /package/dist/{chunk-N3CXAYPJ.js.map → chunk-2HGUDBRJ.js.map} +0 -0
- /package/dist/{chunk-FV7YQTN3.js.map → chunk-2S72LWKX.js.map} +0 -0
- /package/dist/{chunk-NKL25FCF.js.map → chunk-4MBPIL4V.js.map} +0 -0
- /package/dist/{chunk-ZN4EYMKJ.js.map → chunk-67QG75MJ.js.map} +0 -0
- /package/dist/{chunk-JI62YGPI.js.map → chunk-6QPHF6RR.js.map} +0 -0
- /package/dist/{chunk-4EABKPZS.js.map → chunk-75XOWNRS.js.map} +0 -0
- /package/dist/{chunk-O76MWTVS.js.map → chunk-7BAYBYY5.js.map} +0 -0
- /package/dist/{chunk-4JWJMRPJ.js.map → chunk-7PKFPLLZ.js.map} +0 -0
- /package/dist/{chunk-24BKGKGO.js.map → chunk-BOFVT6P3.js.map} +0 -0
- /package/dist/{chunk-SHYIMIX5.js.map → chunk-ESG7Z255.js.map} +0 -0
- /package/dist/{chunk-WPZX7MEA.js.map → chunk-FXX6RQYC.js.map} +0 -0
- /package/dist/{chunk-S75UQ3T3.js.map → chunk-GDDGZVFI.js.map} +0 -0
- /package/dist/{chunk-S2SJEOTM.js.map → chunk-GFIKG4FR.js.map} +0 -0
- /package/dist/{chunk-7NDM2PNK.js.map → chunk-GZICBRWK.js.map} +0 -0
- /package/dist/{chunk-LQKXVQZR.js.map → chunk-HS4M6BZM.js.map} +0 -0
- /package/dist/{chunk-7BLWBSRL.js.map → chunk-IB25FBMX.js.map} +0 -0
- /package/dist/{chunk-GKEYXXKX.js.map → chunk-IXXABW5A.js.map} +0 -0
- /package/dist/{chunk-GGBSF2X7.js.map → chunk-JB6D7EFB.js.map} +0 -0
- /package/dist/{chunk-T35UJI5R.js.map → chunk-JFNRA7YJ.js.map} +0 -0
- /package/dist/{chunk-E633OXMH.js.map → chunk-JPHEOE6Z.js.map} +0 -0
- /package/dist/{chunk-ELQCS47S.js.map → chunk-LOW66JRO.js.map} +0 -0
- /package/dist/{chunk-JDCQK3C5.js.map → chunk-M4A44LUA.js.map} +0 -0
- /package/dist/{chunk-PWLB4TRK.js.map → chunk-OQAL6SIR.js.map} +0 -0
- /package/dist/{chunk-6XGEBQ3R.js.map → chunk-P7ADRREJ.js.map} +0 -0
- /package/dist/{chunk-EURCX6PS.js.map → chunk-PWN32TAG.js.map} +0 -0
- /package/dist/{chunk-P4QOYG52.js.map → chunk-QN7NTKRC.js.map} +0 -0
- /package/dist/{chunk-ZJIFYUJI.js.map → chunk-SV3PSA7Y.js.map} +0 -0
- /package/dist/{chunk-7VWZ4LRW.js.map → chunk-T6RATUV2.js.map} +0 -0
- /package/dist/{chunk-GSEPRIZC.js.map → chunk-TS4AJ2GI.js.map} +0 -0
- /package/dist/{chunk-PWIMF7LP.js.map → chunk-UWIDGVQM.js.map} +0 -0
- /package/dist/{chunk-VFS3MK5F.js.map → chunk-V5H6OJCR.js.map} +0 -0
- /package/dist/{chunk-4S3ECH3U.js.map → chunk-VJXY5ZCT.js.map} +0 -0
- /package/dist/{chunk-PLCHU56K.js.map → chunk-YQ4IQ2GA.js.map} +0 -0
- /package/dist/{chunk-LTOAJXZB.js.map → chunk-Z3RHPGSY.js.map} +0 -0
- /package/dist/{chunk-QWLW3VQH.js.map → chunk-ZCO5F5FW.js.map} +0 -0
- /package/dist/{chunk-5XCN4XBU.js.map → chunk-ZQOCRIGA.js.map} +0 -0
- /package/dist/{forget-GJ42LCBW.js.map → forget-UJDJHG6R.js.map} +0 -0
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
import assert from "node:assert/strict";
|
|
2
|
+
import test from "node:test";
|
|
3
|
+
import { parseConfig } from "./config.js";
|
|
4
|
+
import { ExtractionEngine } from "./extraction.js";
|
|
5
|
+
|
|
6
|
+
type TestMessage = { role: "system" | "user" | "assistant"; content: string };
|
|
7
|
+
type TestOptions = { maxTokens?: number; signal?: AbortSignal };
|
|
8
|
+
|
|
9
|
+
const superseded = { id: "support-old", content: "The service uses port 4000." };
|
|
10
|
+
const replacement = { id: "support-new", content: "The service uses port 5000." };
|
|
11
|
+
const dependents = [{ id: "dependent", category: "fact", content: "Port 4000 must be open." }];
|
|
12
|
+
const response = {
|
|
13
|
+
content: JSON.stringify({
|
|
14
|
+
verdicts: [{ memoryId: "dependent", verdict: "invalidated", reason: "The port changed." }],
|
|
15
|
+
}),
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
function assertInvalidated(result: Awaited<ReturnType<ExtractionEngine["revalidateDependents"]>>): void {
|
|
19
|
+
assert.deepEqual(result, {
|
|
20
|
+
verdicts: [{ memoryId: "dependent", verdict: "invalidated", reason: "The port changed." }],
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
test("revalidation keeps the official OpenAI base URL on the Responses API", async () => {
|
|
25
|
+
const engine = new ExtractionEngine(
|
|
26
|
+
parseConfig({ openaiApiKey: "fixture-key", openaiBaseUrl: "https://api.openai.com/v1" }),
|
|
27
|
+
);
|
|
28
|
+
const signal = new AbortController().signal;
|
|
29
|
+
let calls = 0;
|
|
30
|
+
let request: Record<string, unknown> | undefined;
|
|
31
|
+
let requestOptions: { signal?: AbortSignal } | undefined;
|
|
32
|
+
Reflect.set(engine, "client", {
|
|
33
|
+
baseURL: "https://api.openai.com/v1",
|
|
34
|
+
responses: {
|
|
35
|
+
async create(body: Record<string, unknown>, options: { signal?: AbortSignal }) {
|
|
36
|
+
calls += 1;
|
|
37
|
+
request = body;
|
|
38
|
+
requestOptions = options;
|
|
39
|
+
return { output_text: response.content };
|
|
40
|
+
},
|
|
41
|
+
},
|
|
42
|
+
});
|
|
43
|
+
assertInvalidated(await engine.revalidateDependents(superseded, replacement, dependents, signal));
|
|
44
|
+
assert.equal(calls, 1);
|
|
45
|
+
assert.equal(request?.model, "gpt-5.5");
|
|
46
|
+
assert.equal(request?.max_output_tokens, 1024);
|
|
47
|
+
assert.match(String(request?.instructions), /revalidate dependent memory claims/i);
|
|
48
|
+
assert.match(String(request?.input), /SUPERSEDED MEMORY.*support-old/s);
|
|
49
|
+
assert.equal(requestOptions?.signal, signal);
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
test("revalidation uses the client's effective custom base URL", async () => {
|
|
53
|
+
const engine = new ExtractionEngine(
|
|
54
|
+
parseConfig({
|
|
55
|
+
openaiApiKey: "fixture-key",
|
|
56
|
+
openaiBaseUrl: "https://api.openai.com/v1",
|
|
57
|
+
}),
|
|
58
|
+
);
|
|
59
|
+
const signal = new AbortController().signal;
|
|
60
|
+
let chatRequest: Record<string, unknown> | undefined;
|
|
61
|
+
let chatOptions: { signal?: AbortSignal } | undefined;
|
|
62
|
+
let responsesCalls = 0;
|
|
63
|
+
Reflect.set(engine, "client", {
|
|
64
|
+
baseURL: "https://inference.example.test/v1",
|
|
65
|
+
chat: {
|
|
66
|
+
completions: {
|
|
67
|
+
async create(body: Record<string, unknown>, options: { signal?: AbortSignal }) {
|
|
68
|
+
chatRequest = body;
|
|
69
|
+
chatOptions = options;
|
|
70
|
+
return { choices: [{ message: response }] };
|
|
71
|
+
},
|
|
72
|
+
},
|
|
73
|
+
},
|
|
74
|
+
responses: {
|
|
75
|
+
async create() {
|
|
76
|
+
responsesCalls += 1;
|
|
77
|
+
throw new Error("custom endpoint does not implement /responses");
|
|
78
|
+
},
|
|
79
|
+
},
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
assertInvalidated(await engine.revalidateDependents(superseded, replacement, dependents, signal));
|
|
83
|
+
assert.equal(responsesCalls, 0);
|
|
84
|
+
assert.equal(chatRequest?.model, "gpt-5.5");
|
|
85
|
+
assert.equal(chatRequest?.max_tokens, 1024);
|
|
86
|
+
assert.ok(Array.isArray(chatRequest?.messages));
|
|
87
|
+
assert.equal(chatOptions?.signal, signal);
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
test("revalidation falls back to the direct route when the injected fast route rejects", async () => {
|
|
91
|
+
const engine = new ExtractionEngine(
|
|
92
|
+
parseConfig({ openaiApiKey: "fixture-key", openaiBaseUrl: "https://api.openai.com/v1" }),
|
|
93
|
+
undefined,
|
|
94
|
+
undefined,
|
|
95
|
+
undefined,
|
|
96
|
+
undefined,
|
|
97
|
+
async () => null,
|
|
98
|
+
);
|
|
99
|
+
const signal = new AbortController().signal;
|
|
100
|
+
let fastCalls = 0;
|
|
101
|
+
let directCalls = 0;
|
|
102
|
+
let fastMessages: TestMessage[] | undefined;
|
|
103
|
+
let fastOptions: TestOptions | undefined;
|
|
104
|
+
let request: Record<string, unknown> | undefined;
|
|
105
|
+
let requestOptions: { signal?: AbortSignal } | undefined;
|
|
106
|
+
Reflect.set(engine, "fastChatCompletion", async (messages: TestMessage[], options: TestOptions) => {
|
|
107
|
+
fastCalls += 1;
|
|
108
|
+
fastMessages = messages;
|
|
109
|
+
fastOptions = options;
|
|
110
|
+
throw new Error("fast route unavailable");
|
|
111
|
+
});
|
|
112
|
+
Reflect.set(engine, "client", {
|
|
113
|
+
baseURL: "https://api.openai.com/v1",
|
|
114
|
+
responses: {
|
|
115
|
+
async create(body: Record<string, unknown>, options: { signal?: AbortSignal }) {
|
|
116
|
+
directCalls += 1;
|
|
117
|
+
request = body;
|
|
118
|
+
requestOptions = options;
|
|
119
|
+
return { output_text: response.content };
|
|
120
|
+
},
|
|
121
|
+
},
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
assertInvalidated(await engine.revalidateDependents(superseded, replacement, dependents, signal));
|
|
125
|
+
assert.equal(fastCalls, 1);
|
|
126
|
+
assert.equal(directCalls, 1);
|
|
127
|
+
assert.equal(fastMessages?.[0]?.role, "system");
|
|
128
|
+
assert.match(fastMessages?.[1]?.content ?? "", /support-new/);
|
|
129
|
+
assert.equal(fastOptions?.maxTokens, 1024);
|
|
130
|
+
assert.equal(fastOptions?.signal, signal);
|
|
131
|
+
assert.equal(request?.max_output_tokens, 1024);
|
|
132
|
+
assert.equal(requestOptions?.signal, signal);
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
test("revalidation preserves the gateway fallback route for the legacy constructor", async () => {
|
|
136
|
+
const engine = new ExtractionEngine(parseConfig({ modelSource: "gateway" }));
|
|
137
|
+
const signal = new AbortController().signal;
|
|
138
|
+
let fastCalls = 0;
|
|
139
|
+
let fallbackCalls = 0;
|
|
140
|
+
let fallbackMessages: TestMessage[] | undefined;
|
|
141
|
+
let fallbackOptions: TestOptions | undefined;
|
|
142
|
+
Reflect.set(engine, "fastChatCompletion", async () => {
|
|
143
|
+
fastCalls += 1;
|
|
144
|
+
return null;
|
|
145
|
+
});
|
|
146
|
+
Reflect.set(engine, "fallbackLlm", {
|
|
147
|
+
async chatCompletion(
|
|
148
|
+
messages: TestMessage[],
|
|
149
|
+
options: TestOptions,
|
|
150
|
+
) {
|
|
151
|
+
fallbackCalls += 1;
|
|
152
|
+
fallbackMessages = messages;
|
|
153
|
+
fallbackOptions = options;
|
|
154
|
+
return response;
|
|
155
|
+
},
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
assertInvalidated(await engine.revalidateDependents(superseded, replacement, dependents, signal));
|
|
159
|
+
assert.equal(fastCalls, 1);
|
|
160
|
+
assert.equal(fallbackCalls, 1);
|
|
161
|
+
assert.equal(fallbackMessages?.[0]?.role, "system");
|
|
162
|
+
assert.match(fallbackMessages?.[1]?.content ?? "", /dependent/);
|
|
163
|
+
assert.equal(fallbackOptions?.maxTokens, 1024);
|
|
164
|
+
assert.equal(fallbackOptions?.signal, signal);
|
|
165
|
+
});
|
package/src/extraction.ts
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import OpenAI from "openai";
|
|
2
|
+
import { isAbortError } from "./abort-error.js";
|
|
2
3
|
import { log } from "./logger.js";
|
|
3
4
|
import { delinearize } from "./delinearize.js";
|
|
4
5
|
import { LocalLlmClient } from "./local-llm.js";
|
|
5
6
|
import { shouldRunProactivePass } from "./proactive-contention.js";
|
|
6
7
|
import { FallbackLlmClient, fallbackLlmRuntimeContextFromConfig, gatewayTaskChainOptions } from "./fallback-llm.js";
|
|
7
|
-
import { revalidateDependentsViaLlm } from "./orchestration/dependency-revalidation.js";
|
|
8
|
+
import { revalidateDependentsViaLlm, type RevalidationFastChatCompletion } from "./orchestration/dependency-revalidation.js";
|
|
8
9
|
import {
|
|
9
10
|
ExtractionResultSchema,
|
|
10
11
|
ConsolidationResultSchema,
|
|
@@ -79,7 +80,6 @@ const CONSOLIDATION_RESPONSE_SCHEMA = `{
|
|
|
79
80
|
"entityUpdates": [{"name": "person-jane-doe", "type": "person", "facts": ["Now leads the backend team", "Recently migrated the user service to TypeScript"]}]
|
|
80
81
|
}`;
|
|
81
82
|
|
|
82
|
-
|
|
83
83
|
function extractionEntityType(value: unknown): ExtractedEntityResult["type"] | undefined {
|
|
84
84
|
const type = extractionText(value);
|
|
85
85
|
if (
|
|
@@ -152,6 +152,7 @@ export class ExtractionEngine {
|
|
|
152
152
|
localLlm?: LocalLlmClient,
|
|
153
153
|
gatewayConfig?: GatewayConfig,
|
|
154
154
|
modelRegistry?: ModelRegistry,
|
|
155
|
+
private readonly fastChatCompletion?: RevalidationFastChatCompletion,
|
|
155
156
|
) {
|
|
156
157
|
this.profiler = profilerArg ?? new ProfilingCollector({ enabled: false, storageDir: "/tmp/engram-profiler-disabled", maxTraces: 0 });
|
|
157
158
|
if (config.openaiApiKey) {
|
|
@@ -186,26 +187,14 @@ export class ExtractionEngine {
|
|
|
186
187
|
}
|
|
187
188
|
}
|
|
188
189
|
|
|
189
|
-
/**
|
|
190
|
-
* Whether LLM calls should be routed through the gateway model chain
|
|
191
|
-
* instead of the plugin's own local/OpenAI clients.
|
|
192
|
-
*/
|
|
193
190
|
private get useGatewayModelSource(): boolean {
|
|
194
191
|
return this.config.modelSource === "gateway";
|
|
195
192
|
}
|
|
196
193
|
|
|
197
|
-
/**
|
|
198
|
-
* Whether the local LLM path should be attempted.
|
|
199
|
-
* Disabled when gateway model source is active (gateway chain replaces local).
|
|
200
|
-
*/
|
|
201
194
|
private get shouldUseLocalLlm(): boolean {
|
|
202
195
|
return resolveLocalLlmCapabilities(this.config).localLlm && !this.useGatewayModelSource;
|
|
203
196
|
}
|
|
204
197
|
|
|
205
|
-
/**
|
|
206
|
-
* Whether the direct OpenAI client should be used.
|
|
207
|
-
* Disabled when gateway model source is active.
|
|
208
|
-
*/
|
|
209
198
|
private get shouldUseDirectClient(): boolean {
|
|
210
199
|
return !this.useGatewayModelSource && this.client !== null;
|
|
211
200
|
}
|
|
@@ -2453,29 +2442,55 @@ Respond with valid JSON matching this schema:
|
|
|
2453
2442
|
reason?: string;
|
|
2454
2443
|
}>;
|
|
2455
2444
|
}> {
|
|
2445
|
+
const complete: RevalidationFastChatCompletion = async (messages, options) => {
|
|
2446
|
+
try {
|
|
2447
|
+
const fast = await this.fastChatCompletion?.(messages, options);
|
|
2448
|
+
if (fast) return fast;
|
|
2449
|
+
} catch (error) {
|
|
2450
|
+
if (isAbortError(error) || options.signal?.aborted) throw error;
|
|
2451
|
+
log.warn(`dependency revalidation fast route failed: ${error}`);
|
|
2452
|
+
}
|
|
2453
|
+
if (this.shouldUseLocalLlm) {
|
|
2454
|
+
try {
|
|
2455
|
+
const local = await this.localLlm.chatCompletion(messages, options);
|
|
2456
|
+
if (local || !this.config.localLlmFallback) return local;
|
|
2457
|
+
} catch (error) {
|
|
2458
|
+
if (!this.config.localLlmFallback) throw error;
|
|
2459
|
+
}
|
|
2460
|
+
}
|
|
2461
|
+
if (!this.shouldUseDirectClient) {
|
|
2462
|
+
return this.fallbackLlm.chatCompletion(messages, this.withGatewayAgent(options));
|
|
2463
|
+
}
|
|
2464
|
+
const client = this.client;
|
|
2465
|
+
if (!client) return null;
|
|
2466
|
+
if (!shouldAssumeOpenAiChatCompletions(client.baseURL ?? this.config.openaiBaseUrl)) {
|
|
2467
|
+
const response = await client.chat.completions.create(
|
|
2468
|
+
{
|
|
2469
|
+
model: this.config.model,
|
|
2470
|
+
messages,
|
|
2471
|
+
max_tokens: options.maxTokens,
|
|
2472
|
+
},
|
|
2473
|
+
{ signal: options.signal },
|
|
2474
|
+
);
|
|
2475
|
+
const content = response.choices[0]?.message?.content;
|
|
2476
|
+
return typeof content === "string" ? { content } : null;
|
|
2477
|
+
}
|
|
2478
|
+
const response = await client.responses.create({
|
|
2479
|
+
model: this.config.model,
|
|
2480
|
+
instructions: messages.find((message) => message.role === "system")?.content,
|
|
2481
|
+
input: messages.filter((message) => message.role !== "system").map((message) => message.content).join("\n\n"),
|
|
2482
|
+
max_output_tokens: options.maxTokens,
|
|
2483
|
+
}, { signal: options.signal });
|
|
2484
|
+
return typeof response.output_text === "string" ? { content: response.output_text } : null;
|
|
2485
|
+
};
|
|
2456
2486
|
return revalidateDependentsViaLlm(
|
|
2457
|
-
{
|
|
2458
|
-
shouldUseLocalLlm: this.shouldUseLocalLlm,
|
|
2459
|
-
shouldUseDirectClient: this.shouldUseDirectClient,
|
|
2460
|
-
localLlm: this.localLlm,
|
|
2461
|
-
fallbackLlm: this.fallbackLlm,
|
|
2462
|
-
client: this.client,
|
|
2463
|
-
config: this.config,
|
|
2464
|
-
withGatewayAgent: this.withGatewayAgent.bind(this),
|
|
2465
|
-
parseJsonObject: this.parseJsonObject,
|
|
2466
|
-
},
|
|
2487
|
+
{ fastChatCompletion: complete, parseJsonObject: this.parseJsonObject },
|
|
2467
2488
|
superseded,
|
|
2468
2489
|
replacement,
|
|
2469
2490
|
dependents,
|
|
2470
|
-
signal,
|
|
2491
|
+
{ signal, timeoutMs: this.config.dependencyPropagation.timeoutMs },
|
|
2471
2492
|
);
|
|
2472
2493
|
}
|
|
2473
|
-
|
|
2474
|
-
|
|
2475
|
-
/**
|
|
2476
|
-
* Suggest links between a new memory and existing memories (Phase 3A).
|
|
2477
|
-
* Called during extraction to build the knowledge graph.
|
|
2478
|
-
*/
|
|
2479
2494
|
async suggestLinks(
|
|
2480
2495
|
newMemory: { content: string; category: string },
|
|
2481
2496
|
candidateMemories: Array<{ id: string; content: string; category: string }>,
|
|
@@ -79,7 +79,7 @@ function config(overrides: Record<string, unknown> = {}): PluginConfig {
|
|
|
79
79
|
|
|
80
80
|
function fixture(
|
|
81
81
|
initial: MemoryFile[],
|
|
82
|
-
verdicts: Verdict[] | Error | ((signal?: AbortSignal) => Promise<
|
|
82
|
+
verdicts: Verdict[] | Error | ((signal?: AbortSignal) => Promise<{ verdicts: Verdict[] }>),
|
|
83
83
|
): Fixture {
|
|
84
84
|
const memories = new Map(initial.map((item) => [item.frontmatter.id, item]));
|
|
85
85
|
const calls: Fixture["calls"] = { revalidate: [], supersede: [], frontmatter: [] };
|
|
@@ -267,13 +267,24 @@ test("disabled propagation is an immediate no-op for boolean and string false",
|
|
|
267
267
|
},
|
|
268
268
|
);
|
|
269
269
|
|
|
270
|
-
assert.deepEqual(
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
270
|
+
assert.deepEqual(
|
|
271
|
+
{
|
|
272
|
+
dependentsFound: result.dependentsFound,
|
|
273
|
+
invalidated: result.invalidated,
|
|
274
|
+
stillValid: result.stillValid,
|
|
275
|
+
uncertain: result.uncertain,
|
|
276
|
+
skipped: result.skipped,
|
|
277
|
+
},
|
|
278
|
+
{
|
|
279
|
+
dependentsFound: 0,
|
|
280
|
+
invalidated: 0,
|
|
281
|
+
stillValid: 0,
|
|
282
|
+
uncertain: 0,
|
|
283
|
+
skipped: "disabled",
|
|
284
|
+
},
|
|
285
|
+
);
|
|
286
|
+
assert.equal(result.route, null);
|
|
287
|
+
assert.equal(typeof result.durationMs, "number");
|
|
277
288
|
assert.equal(fixtureValue.calls.revalidate.length, 0);
|
|
278
289
|
}
|
|
279
290
|
});
|
|
@@ -295,6 +306,12 @@ test("invalidated verdict supersedes the dependent and persists dependency front
|
|
|
295
306
|
);
|
|
296
307
|
|
|
297
308
|
assert.equal(result.invalidated, 1);
|
|
309
|
+
assert.equal(result.dependentsFound, 1);
|
|
310
|
+
assert.equal(result.stillValid, 0);
|
|
311
|
+
assert.equal(result.uncertain, 0);
|
|
312
|
+
assert.equal(result.skipped, null);
|
|
313
|
+
assert.equal(result.route, "fast-completion");
|
|
314
|
+
assert.equal(typeof result.durationMs, "number");
|
|
298
315
|
assert.deepEqual(fixtureValue.calls.supersede, [
|
|
299
316
|
{
|
|
300
317
|
id: "dep",
|
|
@@ -387,6 +404,12 @@ test("LLM errors skip the event and perform zero writes", async () => {
|
|
|
387
404
|
},
|
|
388
405
|
);
|
|
389
406
|
|
|
407
|
+
assert.equal(result.dependentsFound, 1);
|
|
408
|
+
assert.equal(result.invalidated, 0);
|
|
409
|
+
assert.equal(result.stillValid, 0);
|
|
410
|
+
assert.equal(result.uncertain, 0);
|
|
411
|
+
assert.equal(result.route, "fast-completion");
|
|
412
|
+
assert.equal(typeof result.durationMs, "number");
|
|
390
413
|
assert.equal(result.skipped, "llm_error");
|
|
391
414
|
assert.equal(fixtureValue.calls.supersede.length, 0);
|
|
392
415
|
assert.equal(fixtureValue.calls.frontmatter.length, 0);
|
|
@@ -411,11 +434,69 @@ test("LLM timeout aborts the batch and performs zero writes", async () => {
|
|
|
411
434
|
},
|
|
412
435
|
);
|
|
413
436
|
|
|
437
|
+
assert.equal(result.dependentsFound, 1);
|
|
438
|
+
assert.equal(result.route, "fast-completion");
|
|
439
|
+
assert.equal(typeof result.durationMs, "number");
|
|
414
440
|
assert.equal(result.skipped, "timeout");
|
|
415
441
|
assert.equal(fixtureValue.calls.supersede.length, 0);
|
|
416
442
|
assert.equal(fixtureValue.calls.frontmatter.length, 0);
|
|
417
443
|
});
|
|
418
444
|
|
|
445
|
+
test("a completion that ignores AbortSignal returns at the shared deadline", async (t) => {
|
|
446
|
+
t.mock.timers.enable({ apis: ["setTimeout", "Date"], now: 0 });
|
|
447
|
+
try {
|
|
448
|
+
const old = memory("old", { links: [{ targetId: "dep", linkType: "supports" }] });
|
|
449
|
+
const fixtureValue = fixture([old, memory("dep")], () => new Promise<never>(() => {}));
|
|
450
|
+
const resultPromise = propagateInvalidation(
|
|
451
|
+
deps(fixtureValue, { dependencyPropagation: { timeoutMs: 20 } }),
|
|
452
|
+
{
|
|
453
|
+
oldMemory: old,
|
|
454
|
+
replacementId: "new",
|
|
455
|
+
replacementContent: "replacement",
|
|
456
|
+
cause: "contradiction",
|
|
457
|
+
namespaceScope: "namespace-a",
|
|
458
|
+
},
|
|
459
|
+
);
|
|
460
|
+
|
|
461
|
+
await Promise.resolve();
|
|
462
|
+
t.mock.timers.tick(20);
|
|
463
|
+
const result = await resultPromise;
|
|
464
|
+
|
|
465
|
+
assert.equal(result.dependentsFound, 1);
|
|
466
|
+
assert.equal(result.invalidated, 0);
|
|
467
|
+
assert.equal(result.stillValid, 0);
|
|
468
|
+
assert.equal(result.uncertain, 0);
|
|
469
|
+
assert.equal(result.skipped, "timeout");
|
|
470
|
+
assert.equal(result.route, "fast-completion");
|
|
471
|
+
assert.equal(result.durationMs, 20);
|
|
472
|
+
assert.equal(fixtureValue.calls.supersede.length, 0);
|
|
473
|
+
assert.equal(fixtureValue.calls.frontmatter.length, 0);
|
|
474
|
+
} finally {
|
|
475
|
+
t.mock.timers.reset();
|
|
476
|
+
}
|
|
477
|
+
});
|
|
478
|
+
|
|
479
|
+
test("a zero timeout disables the deadline", async () => {
|
|
480
|
+
const old = memory("old", { links: [{ targetId: "dep", linkType: "supports" }] });
|
|
481
|
+
const fixtureValue = fixture([old, memory("dep")], () =>
|
|
482
|
+
new Promise((resolve) => setTimeout(() => resolve({
|
|
483
|
+
verdicts: [{ memoryId: "dep", verdict: "invalidated" }],
|
|
484
|
+
}), 5)),
|
|
485
|
+
);
|
|
486
|
+
const result = await propagateInvalidation(
|
|
487
|
+
deps(fixtureValue, { dependencyPropagation: { timeoutMs: 0 } }),
|
|
488
|
+
{
|
|
489
|
+
oldMemory: old,
|
|
490
|
+
replacementId: "new",
|
|
491
|
+
replacementContent: "replacement",
|
|
492
|
+
cause: "contradiction",
|
|
493
|
+
namespaceScope: "namespace-a",
|
|
494
|
+
},
|
|
495
|
+
);
|
|
496
|
+
assert.equal(result.invalidated, 1);
|
|
497
|
+
assert.equal(result.skipped, null);
|
|
498
|
+
});
|
|
499
|
+
|
|
419
500
|
test("dryRun computes invalidation verdicts without writing", async () => {
|
|
420
501
|
const old = memory("old", { links: [{ targetId: "dep", linkType: "supports" }] });
|
|
421
502
|
const fixtureValue = fixture([old, memory("dep")], [{ memoryId: "dep", verdict: "invalidated" }]);
|
|
@@ -34,6 +34,8 @@ export interface PropagationResult {
|
|
|
34
34
|
stillValid: number;
|
|
35
35
|
uncertain: number;
|
|
36
36
|
skipped: "disabled" | "no_dependents" | "llm_error" | "timeout" | null;
|
|
37
|
+
route: "fast-completion" | null;
|
|
38
|
+
durationMs: number;
|
|
37
39
|
}
|
|
38
40
|
|
|
39
41
|
function propagationConfig(config: PluginConfig): DependencyPropagationConfig {
|
|
@@ -96,8 +98,13 @@ export function findDependents(
|
|
|
96
98
|
});
|
|
97
99
|
}
|
|
98
100
|
|
|
99
|
-
function emptyResult(
|
|
100
|
-
|
|
101
|
+
function emptyResult(
|
|
102
|
+
skipped: PropagationResult["skipped"],
|
|
103
|
+
durationMs: number,
|
|
104
|
+
route: PropagationResult["route"] = null,
|
|
105
|
+
dependentsFound = 0,
|
|
106
|
+
): PropagationResult {
|
|
107
|
+
return { dependentsFound, invalidated: 0, stillValid: 0, uncertain: 0, skipped, route, durationMs };
|
|
101
108
|
}
|
|
102
109
|
|
|
103
110
|
function logResult(event: PropagationEvent, result: PropagationResult): void {
|
|
@@ -111,6 +118,8 @@ function logResult(event: PropagationEvent, result: PropagationResult): void {
|
|
|
111
118
|
stillValid: result.stillValid,
|
|
112
119
|
uncertain: result.uncertain,
|
|
113
120
|
skipped: result.skipped,
|
|
121
|
+
route: result.route,
|
|
122
|
+
durationMs: result.durationMs,
|
|
114
123
|
})}`,
|
|
115
124
|
);
|
|
116
125
|
}
|
|
@@ -136,16 +145,17 @@ export async function propagateInvalidation(
|
|
|
136
145
|
deps: { storage: StorageManager; extraction: ExtractionEngine; config: PluginConfig },
|
|
137
146
|
event: PropagationEvent,
|
|
138
147
|
): Promise<PropagationResult> {
|
|
148
|
+
const startedAt = Date.now();
|
|
139
149
|
const config = propagationConfig(deps.config);
|
|
140
150
|
if (!isEnabled(config.enabled)) {
|
|
141
|
-
const result = emptyResult("disabled");
|
|
151
|
+
const result = emptyResult("disabled", Date.now() - startedAt);
|
|
142
152
|
logResult(event, result);
|
|
143
153
|
return result;
|
|
144
154
|
}
|
|
145
155
|
|
|
146
156
|
const maxDependents = config.maxDependents;
|
|
147
157
|
if (maxDependents <= 0) {
|
|
148
|
-
const result = emptyResult("no_dependents");
|
|
158
|
+
const result = emptyResult("no_dependents", Date.now() - startedAt);
|
|
149
159
|
logResult(event, result);
|
|
150
160
|
return result;
|
|
151
161
|
}
|
|
@@ -155,7 +165,7 @@ export async function propagateInvalidation(
|
|
|
155
165
|
memories = await deps.storage.readAllMemories();
|
|
156
166
|
} catch (error) {
|
|
157
167
|
log.warn(`dependency propagation discovery failed for ${event.oldMemory.frontmatter.id}: ${error}`);
|
|
158
|
-
const result = emptyResult("llm_error");
|
|
168
|
+
const result = emptyResult("llm_error", Date.now() - startedAt);
|
|
159
169
|
logResult(event, result);
|
|
160
170
|
return result;
|
|
161
171
|
}
|
|
@@ -171,46 +181,67 @@ export async function propagateInvalidation(
|
|
|
171
181
|
const dependents = discovered.slice(0, Math.max(0, Math.floor(maxDependents)));
|
|
172
182
|
|
|
173
183
|
if (dependents.length === 0) {
|
|
174
|
-
const result = emptyResult("no_dependents");
|
|
184
|
+
const result = emptyResult("no_dependents", Date.now() - startedAt);
|
|
175
185
|
logResult(event, result);
|
|
176
186
|
return result;
|
|
177
187
|
}
|
|
178
188
|
|
|
179
189
|
const controller = new AbortController();
|
|
180
190
|
const timeoutMs = config.timeoutMs;
|
|
181
|
-
|
|
182
|
-
|
|
191
|
+
let timedOut = false;
|
|
192
|
+
let timeout: ReturnType<typeof setTimeout> | undefined;
|
|
193
|
+
const deadline = Number.isFinite(timeoutMs) && timeoutMs > 0
|
|
194
|
+
? new Promise<never>((_, reject) => {
|
|
195
|
+
timeout = setTimeout(() => {
|
|
196
|
+
timedOut = true;
|
|
197
|
+
const error = new PropagationTimeoutError();
|
|
198
|
+
controller.abort(error);
|
|
199
|
+
reject(error);
|
|
200
|
+
}, timeoutMs);
|
|
201
|
+
})
|
|
183
202
|
: undefined;
|
|
203
|
+
const revalidation = Promise.resolve().then(() => deps.extraction.revalidateDependents(
|
|
204
|
+
{ id: event.oldMemory.frontmatter.id, content: event.oldMemory.content },
|
|
205
|
+
event.replacementId && event.replacementContent !== null
|
|
206
|
+
? { id: event.replacementId, content: event.replacementContent }
|
|
207
|
+
: null,
|
|
208
|
+
dependents.map((memory) => ({
|
|
209
|
+
id: memory.frontmatter.id,
|
|
210
|
+
category: memory.frontmatter.category,
|
|
211
|
+
content: memory.content,
|
|
212
|
+
})),
|
|
213
|
+
controller.signal,
|
|
214
|
+
));
|
|
184
215
|
|
|
185
216
|
let verdicts: Array<{ memoryId: string; verdict: "still_valid" | "invalidated" | "uncertain"; reason?: string }>;
|
|
186
217
|
try {
|
|
187
|
-
const response =
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
controller.signal,
|
|
198
|
-
);
|
|
199
|
-
verdicts = response.verdicts;
|
|
200
|
-
if (controller.signal.aborted) {
|
|
201
|
-
if (timeout !== undefined) clearTimeout(timeout);
|
|
202
|
-
const result = emptyResult("timeout");
|
|
218
|
+
const response = deadline
|
|
219
|
+
? await Promise.race([revalidation, deadline])
|
|
220
|
+
: await revalidation;
|
|
221
|
+
if (timedOut || controller.signal.aborted) {
|
|
222
|
+
const result = emptyResult(
|
|
223
|
+
"timeout",
|
|
224
|
+
Date.now() - startedAt,
|
|
225
|
+
"fast-completion",
|
|
226
|
+
dependents.length,
|
|
227
|
+
);
|
|
203
228
|
logResult(event, result);
|
|
204
229
|
return result;
|
|
205
230
|
}
|
|
231
|
+
verdicts = response.verdicts;
|
|
206
232
|
} catch (error) {
|
|
207
|
-
const result = emptyResult(
|
|
233
|
+
const result = emptyResult(
|
|
234
|
+
timedOut || isTimeoutError(error, controller.signal) ? "timeout" : "llm_error",
|
|
235
|
+
Date.now() - startedAt,
|
|
236
|
+
"fast-completion",
|
|
237
|
+
dependents.length,
|
|
238
|
+
);
|
|
208
239
|
log.warn(`dependency propagation revalidation failed for ${event.oldMemory.frontmatter.id}: ${error}`);
|
|
209
240
|
logResult(event, result);
|
|
210
|
-
if (timeout !== undefined) clearTimeout(timeout);
|
|
211
241
|
return result;
|
|
242
|
+
} finally {
|
|
243
|
+
clearTimeout(timeout!);
|
|
212
244
|
}
|
|
213
|
-
if (timeout !== undefined) clearTimeout(timeout);
|
|
214
245
|
|
|
215
246
|
let invalidated = 0;
|
|
216
247
|
let stillValid = 0;
|
|
@@ -257,6 +288,8 @@ export async function propagateInvalidation(
|
|
|
257
288
|
stillValid,
|
|
258
289
|
uncertain,
|
|
259
290
|
skipped: null,
|
|
291
|
+
route: "fast-completion",
|
|
292
|
+
durationMs: Date.now() - startedAt,
|
|
260
293
|
};
|
|
261
294
|
logResult(event, result);
|
|
262
295
|
return result;
|