@remnic/core 9.30.1 → 9.32.0
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 +55 -44
- package/dist/access-authorization-probe.d.ts +10 -10
- package/dist/access-authorization-probe.js +56 -45
- package/dist/access-boundary.d.ts +13 -11
- package/dist/access-boundary.js +55 -44
- package/dist/access-cli.js +170 -126
- package/dist/access-cli.js.map +1 -1
- package/dist/access-extraction-force-flush.d.ts +119 -0
- package/dist/access-extraction-force-flush.js +171 -0
- package/dist/access-health-types.d.ts +1 -1
- package/dist/access-http-lcm-compaction.d.ts +47 -13
- package/dist/access-http-lcm-compaction.js +7 -3
- package/dist/access-http-lifecycle-flush.d.ts +132 -0
- package/dist/access-http-lifecycle-flush.js +9 -0
- package/dist/access-http-lifecycle-flush.js.map +1 -0
- package/dist/access-http.d.ts +11 -10
- package/dist/access-http.js +71 -59
- package/dist/access-identity-continuity-surface.d.ts +8 -8
- package/dist/access-identity-continuity-surface.js +55 -44
- package/dist/access-lcm-surface.d.ts +10 -10
- package/dist/access-lcm-surface.js +55 -44
- package/dist/access-mcp-output-schemas.js +1 -1
- package/dist/access-mcp.d.ts +16 -10
- package/dist/access-mcp.js +63 -52
- package/dist/access-memory-search-fanout.d.ts +2 -2
- package/dist/{access-namespace-preflight-VfXssvoI.d.ts → access-namespace-preflight-COhbXBqS.d.ts} +1 -1
- package/dist/access-namespace-preflight.d.ts +3 -3
- package/dist/access-namespace-preflight.js +55 -44
- package/dist/access-observe-helpers.d.ts +22 -0
- package/dist/access-observe-helpers.js +10 -0
- package/dist/access-observe-helpers.js.map +1 -0
- package/dist/access-observe-write-surface.d.ts +51 -47
- package/dist/access-observe-write-surface.js +55 -44
- package/dist/access-operations-batch.js +58 -47
- package/dist/access-operations.d.ts +11 -11
- package/dist/access-operations.js +60 -49
- package/dist/access-recall-concurrency.d.ts +10 -10
- package/dist/access-recall-concurrency.js +55 -44
- package/dist/access-recall-response.d.ts +10 -10
- package/dist/access-recall-response.js +55 -44
- package/dist/access-recall-surface.d.ts +10 -10
- package/dist/access-recall-surface.js +55 -44
- package/dist/access-schema.d.ts +37 -7
- package/dist/access-schema.js +5 -3
- package/dist/{access-service-B5RwVsTV.d.ts → access-service-BmBTtEKO.d.ts} +44 -20
- package/dist/access-service-helpers.d.ts +113 -0
- package/dist/access-service-helpers.js +8 -0
- package/dist/access-service-helpers.js.map +1 -0
- package/dist/access-service.d.ts +10 -10
- package/dist/access-service.js +55 -44
- package/dist/access-surface-catalog.d.ts +10 -10
- package/dist/access-surface-catalog.js +2 -0
- package/dist/access-surface-catalog.js.map +1 -1
- 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/active-recall.js +2 -2
- package/dist/adapters/index.js +7 -7
- package/dist/adapters/registry.js +3 -3
- 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 +14 -14
- package/dist/buffer-surprise-report.d.ts +1 -1
- package/dist/buffer-turn-helpers.d.ts +5 -0
- package/dist/buffer-turn-helpers.js +24 -0
- package/dist/buffer-turn-helpers.js.map +1 -0
- package/dist/buffer.d.ts +17 -4
- package/dist/buffer.js +21 -1
- 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-crypto-GWVG7LGC.js → capsule-crypto-7FJQINUR.js} +2 -2
- package/dist/capsule-crypto-7FJQINUR.js.map +1 -0
- package/dist/{capsule-merge-5KKJQBWQ.js → capsule-merge-2H2IUTBT.js} +4 -4
- package/dist/{catalog-V7inUQdp.d.ts → catalog-Dm-DvNBY.d.ts} +1 -1
- package/dist/causal-behavior.d.ts +1 -1
- package/dist/causal-behavior.js +2 -2
- package/dist/causal-chain.js +2 -2
- package/dist/causal-consolidation.d.ts +1 -1
- package/dist/causal-consolidation.js +21 -22
- package/dist/causal-consolidation.js.map +1 -1
- package/dist/causal-retrieval.js +2 -2
- package/dist/causal-trajectory-graph.d.ts +1 -1
- package/dist/causal-trajectory.js +1 -1
- package/dist/{chunk-LEPOP46W.js → chunk-227UFSEQ.js} +4 -4
- package/dist/{chunk-I5NLEENJ.js → chunk-27HHNYSQ.js} +3 -3
- package/dist/{chunk-2SA56WMI.js → chunk-2LTDWSR6.js} +4 -4
- package/dist/{chunk-OWHERGF2.js → chunk-2NLLXCJG.js} +2 -2
- package/dist/{chunk-SPJXKAVF.js → chunk-2NTGBZLZ.js} +14 -13
- package/dist/chunk-2NTGBZLZ.js.map +1 -0
- package/dist/{chunk-P5PXWTW7.js → chunk-2Q4JJ3FZ.js} +3 -3
- package/dist/{chunk-G5R3D5UP.js → chunk-2QIMTVEJ.js} +6 -5
- package/dist/chunk-2QIMTVEJ.js.map +1 -0
- package/dist/{chunk-H5CPS5JP.js → chunk-35IVNNRK.js} +3 -3
- package/dist/{chunk-LBOD4U5B.js → chunk-3EQ2XB3W.js} +6 -6
- package/dist/{chunk-YTSNAUXN.js → chunk-3F2LKUMU.js} +22 -8
- package/dist/chunk-3F2LKUMU.js.map +1 -0
- package/dist/chunk-3QL24R5Y.js +9 -0
- package/dist/chunk-3QL24R5Y.js.map +1 -0
- package/dist/chunk-4RNZMRAV.js +60 -0
- package/dist/chunk-4RNZMRAV.js.map +1 -0
- package/dist/chunk-5IVLTFOV.js +65 -0
- package/dist/chunk-5IVLTFOV.js.map +1 -0
- package/dist/{chunk-2EUVEDF5.js → chunk-5WZVQRHV.js} +2 -2
- package/dist/{chunk-ALSGMEJR.js → chunk-65ZPVYTA.js} +7 -7
- package/dist/{chunk-GIBMDSJ2.js → chunk-6P7MTSU5.js} +2 -2
- package/dist/{chunk-5VQJBH2G.js → chunk-6TAUHL33.js} +2 -2
- package/dist/{chunk-WVO4G37W.js → chunk-7TEZUUGM.js} +3 -3
- package/dist/{chunk-MJCGLM25.js → chunk-7VUAG236.js} +5 -5
- package/dist/{chunk-CZRYLSSW.js → chunk-AJL6NNX6.js} +2 -2
- package/dist/{chunk-LGHKJABJ.js → chunk-AQEJE3WO.js} +40 -18
- package/dist/chunk-AQEJE3WO.js.map +1 -0
- package/dist/{chunk-66772WBP.js → chunk-AQWVJURR.js} +5 -5
- package/dist/{chunk-RKNJBZ55.js → chunk-AU7Q3LSC.js} +7 -7
- package/dist/{chunk-IYZ5K7MU.js → chunk-BUE5E2HL.js} +4 -187
- package/dist/chunk-BUE5E2HL.js.map +1 -0
- package/dist/{chunk-NHWB6HG2.js → chunk-CE5355TT.js} +21 -5
- package/dist/chunk-CE5355TT.js.map +1 -0
- package/dist/{chunk-M3C2V3PV.js → chunk-CJDNT45S.js} +12 -12
- package/dist/{chunk-D2ANTDGO.js → chunk-E6BMSH7U.js} +2 -2
- package/dist/{chunk-CKMO4RDY.js → chunk-EMDLM3LW.js} +4 -4
- package/dist/chunk-ER7W6H4T.js +112 -0
- package/dist/chunk-ER7W6H4T.js.map +1 -0
- package/dist/{chunk-RGIWINDN.js → chunk-FHBITMRY.js} +30 -30
- package/dist/{chunk-6FUPCJUL.js → chunk-FMFLGS5Z.js} +54 -54
- package/dist/chunk-FMFLGS5Z.js.map +1 -0
- package/dist/{chunk-FDAMS4PK.js → chunk-G2YQ57YO.js} +4 -4
- package/dist/{chunk-6U7F52DE.js → chunk-HFQQWAMS.js} +62 -62
- package/dist/{chunk-5W4ZLBEZ.js → chunk-HKPJPOW7.js} +2 -2
- package/dist/{chunk-JCBWCYEJ.js → chunk-IGWFKW4B.js} +2 -2
- package/dist/{chunk-AITCS2RC.js → chunk-IJ7HK452.js} +4 -4
- package/dist/{chunk-4WKA6I65.js → chunk-J3ZGPYXB.js} +1135 -311
- package/dist/chunk-J3ZGPYXB.js.map +1 -0
- package/dist/{chunk-D3LMYTBV.js → chunk-J7WZUL2K.js} +9 -9
- package/dist/{chunk-5W7CTZ2E.js → chunk-KQAFEZQX.js} +4 -4
- package/dist/{chunk-YNQBRLC5.js → chunk-LUQ443JP.js} +520 -2011
- package/dist/chunk-LUQ443JP.js.map +1 -0
- package/dist/{chunk-Z54EM5YZ.js → chunk-MAXVH44E.js} +7 -7
- package/dist/{chunk-WZFAPHIK.js → chunk-MU7ZHSZE.js} +2 -2
- package/dist/chunk-N5Z4EVOR.js +123 -0
- package/dist/chunk-N5Z4EVOR.js.map +1 -0
- package/dist/{chunk-AZ5BTEKX.js → chunk-NQUF7XKR.js} +2 -2
- package/dist/{chunk-W4FBGYGK.js → chunk-NRV4Y3PM.js} +1 -1
- package/dist/{chunk-62U4J2GN.js → chunk-ODGOP7P2.js} +2 -2
- package/dist/{chunk-QJAQNXWI.js → chunk-ONHRRJZM.js} +6 -6
- package/dist/{chunk-ACXPX4AG.js → chunk-OPBTPRGY.js} +2 -2
- package/dist/{chunk-XOZ4ALGB.js → chunk-QDTZ2HF7.js} +3 -3
- package/dist/{chunk-GBJ4RDFR.js → chunk-QIHIHZYC.js} +66 -91
- package/dist/chunk-QIHIHZYC.js.map +1 -0
- package/dist/{chunk-ZPSVBSOF.js → chunk-QMWFQBIL.js} +3 -3
- package/dist/{chunk-W5EG6LE3.js → chunk-THCPRMRF.js} +3 -3
- package/dist/{chunk-4A6YGWQN.js → chunk-TL4TO3EA.js} +115 -120
- package/dist/chunk-TL4TO3EA.js.map +1 -0
- package/dist/{chunk-VI2JQPNQ.js → chunk-U7QYBSQJ.js} +2 -2
- package/dist/chunk-ULARSG5Z.js +203 -0
- package/dist/chunk-ULARSG5Z.js.map +1 -0
- package/dist/{chunk-TH2LSRMG.js → chunk-UORKJ34C.js} +2 -2
- package/dist/{chunk-4Z4XNEWZ.js → chunk-VCD4PSK2.js} +56 -12
- package/dist/chunk-VCD4PSK2.js.map +1 -0
- package/dist/{chunk-K5GB36ME.js → chunk-VMZ56EE3.js} +2 -2
- package/dist/{chunk-HUHX2OCX.js → chunk-VVDPPDDF.js} +1 -1
- package/dist/chunk-VVDPPDDF.js.map +1 -0
- package/dist/{chunk-RMMVQQA6.js → chunk-WDISJRMG.js} +2 -2
- package/dist/{chunk-B6JDYXL7.js → chunk-WWUVONGW.js} +7 -1
- package/dist/chunk-WWUVONGW.js.map +1 -0
- package/dist/{chunk-UVYI6VIX.js → chunk-X7Y7WX73.js} +1 -1
- package/dist/{chunk-CVILPI77.js → chunk-XOQSEF7X.js} +6 -6
- package/dist/{chunk-RPW2NOU6.js → chunk-YIAA2X3D.js} +41 -1
- package/dist/chunk-YIAA2X3D.js.map +1 -0
- package/dist/chunk-YPC7W6GA.js +1604 -0
- package/dist/chunk-YPC7W6GA.js.map +1 -0
- package/dist/{chunk-YTQNQ4KB.js → chunk-YX5LN6JR.js} +3 -3
- package/dist/{chunk-IC6CBHCA.js → chunk-Z7XKUWYS.js} +2 -2
- package/dist/{chunk-PHWUFPCO.js → chunk-ZCPP5OW6.js} +61 -53
- package/dist/chunk-ZCPP5OW6.js.map +1 -0
- package/dist/{cli-C4GbETPC.d.ts → cli-DRJLv1Xt.d.ts} +5 -5
- package/dist/cli.d.ts +12 -12
- package/dist/cli.js +96 -86
- package/dist/compounding/engine.d.ts +2 -2
- package/dist/compounding/engine.js +14 -14
- 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/config.js +2 -2
- package/dist/connectors/codex-materialize-runner.d.ts +1 -1
- package/dist/connectors/codex-materialize-runner.js +14 -15
- package/dist/connectors/codex-materialize.d.ts +1 -1
- package/dist/connectors/index.d.ts +3 -2
- package/dist/connectors/index.js +24 -23
- package/dist/consolidation-provenance-check.d.ts +2 -2
- package/dist/consolidation-provenance-check.js +5 -5
- 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/contradiction/index.js +4 -4
- package/dist/conversation-index/backend.d.ts +1 -1
- package/dist/conversation-index/backend.js +2 -2
- 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 +26 -26
- 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/enrichment/index.d.ts +1 -1
- package/dist/entity-retrieval.d.ts +2 -2
- package/dist/entity-retrieval.js +14 -14
- package/dist/entity-schema.d.ts +1 -1
- package/dist/explicit-capture.d.ts +8 -8
- 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-source-grounding-rules.d.ts +1 -1
- package/dist/extraction-source-grounding.d.ts +15 -2
- package/dist/extraction-source-grounding.js +10 -1
- package/dist/extraction.d.ts +2 -15
- package/dist/extraction.js +5 -4
- package/dist/fallback-llm.d.ts +1 -1
- 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/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 +253 -246
- package/dist/intent.d.ts +1 -1
- package/dist/lcm/engine.d.ts +1 -1
- package/dist/lcm/engine.js +3 -3
- package/dist/lcm/index.d.ts +1 -1
- package/dist/lcm/index.js +6 -6
- 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-helpers.d.ts +7 -0
- package/dist/local-llm-helpers.js +16 -0
- package/dist/local-llm-helpers.js.map +1 -0
- package/dist/local-llm.d.ts +3 -6
- 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/maintenance/memory-governance.js +14 -14
- package/dist/maintenance/rebuild-memory-lifecycle-ledger.d.ts +2 -2
- package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +14 -14
- package/dist/maintenance/rebuild-memory-projection.d.ts +2 -2
- package/dist/maintenance/rebuild-memory-projection.js +15 -15
- package/dist/{maintenance-CL30NWtc.d.ts → maintenance-C6Pffz30.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-corpus-version.js +2 -2
- 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 +2 -2
- package/dist/models-json.d.ts +1 -1
- package/dist/namespaces/migrate.d.ts +3 -3
- package/dist/namespaces/migrate.js +24 -24
- package/dist/namespaces/principal.d.ts +1 -1
- package/dist/namespaces/search.d.ts +1 -1
- package/dist/namespaces/search.js +9 -9
- package/dist/namespaces/storage.d.ts +3 -3
- package/dist/namespaces/storage.js +14 -14
- package/dist/native-knowledge.d.ts +1 -1
- package/dist/offline-sync-impression-drain.d.ts +1 -1
- package/dist/offline-sync-impression-drain.js +6 -5
- package/dist/operator-doctor-corpus.d.ts +1 -1
- package/dist/operator-doctor-corpus.js +29 -29
- package/dist/operator-doctor-replica.d.ts +1 -1
- package/dist/operator-doctor-replica.js +3 -3
- package/dist/operator-toolkit.d.ts +3 -3
- package/dist/operator-toolkit.js +39 -38
- package/dist/orchestration/compression-guideline-coordinator.d.ts +2 -2
- package/dist/orchestration/maintenance.d.ts +4 -4
- package/dist/orchestration/maintenance.js +22 -21
- package/dist/{orchestrator-CKTCRwWV.d.ts → orchestrator-eQlmasno.d.ts} +72 -34
- package/dist/orchestrator.d.ts +8 -8
- package/dist/orchestrator.js +169 -162
- package/dist/page-versioning.js +3 -3
- package/dist/patterns-cli.d.ts +1 -1
- package/dist/{pipeline-B7wj4rRZ.d.ts → pipeline-CZGmAMQ2.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-q9tg4dHp.d.ts → qmd-DBj4MF8T.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/qmd.js +4 -4
- 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-explain-renderer.js +3 -3
- 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-cli.js +4 -4
- package/dist/recall-xray-renderer.d.ts +1 -1
- package/dist/recall-xray-renderer.js +3 -3
- package/dist/recall-xray.d.ts +1 -1
- package/dist/recall-xray.js +2 -2
- 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-divergence.js +2 -2
- package/dist/replica-peers-config.d.ts +1 -1
- package/dist/resolve-auth-token.d.ts +1 -1
- package/dist/resume-bundles.js +2 -2
- 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-CWDyglPM.d.ts → scope-profiles-S85lrsUn.d.ts} +1 -1
- package/dist/search/embed-helper.d.ts +1 -1
- package/dist/search/factory.d.ts +1 -1
- package/dist/search/factory.js +8 -8
- package/dist/search/index.d.ts +1 -1
- package/dist/search/index.js +12 -12
- 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-BUE3deLn.d.ts → semantic-consolidation-DVzDcV6x.d.ts} +1 -1
- package/dist/semantic-consolidation.d.ts +2 -2
- package/dist/semantic-consolidation.js +17 -18
- package/dist/semantic-rule-promotion.js +14 -14
- package/dist/semantic-rule-verifier.d.ts +1 -1
- package/dist/semantic-rule-verifier.js +14 -14
- package/dist/{service-CXgM0bQG.d.ts → service-C2M-wD4W.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/{storage-DysJq-XH.d.ts → storage-dyBC3Q84.d.ts} +1 -1
- package/dist/storage.d.ts +2 -2
- package/dist/storage.js +13 -13
- 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 +2 -2
- 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/tokens.js +2 -2
- package/dist/topics.d.ts +1 -1
- package/dist/transcript.d.ts +1 -1
- package/dist/transfer/backup.js +2 -2
- package/dist/transfer/capsule-export.js +2 -2
- package/dist/transfer/capsule-import.js +5 -5
- package/dist/trust-score-stage.d.ts +1 -1
- package/dist/trust-score.d.ts +1 -1
- package/dist/{types-aPPzhnjT.d.ts → types-D63ZI--P.d.ts} +23 -2
- package/dist/types.d.ts +1 -1
- package/dist/types.js +1 -1
- package/dist/utility-runtime.d.ts +1 -1
- package/dist/verified-recall.js +14 -14
- package/dist/write-envelope.d.ts +1 -1
- package/package.json +2 -2
- package/src/access-boundary.ts +3 -0
- package/src/access-cli.test.ts +93 -0
- package/src/access-cli.ts +56 -2
- package/src/access-extraction-force-flush.ts +177 -0
- package/src/access-http-extraction-force-flush.test.ts +132 -0
- package/src/access-http-lcm-compaction.ts +99 -22
- package/src/access-http-lifecycle-flush.ts +81 -0
- package/src/access-http.test.ts +227 -0
- package/src/access-http.ts +33 -40
- package/src/access-mcp-output-schemas.ts +6 -0
- package/src/access-mcp.test.ts +40 -0
- package/src/access-mcp.ts +32 -1
- package/src/access-observe-helpers.ts +180 -0
- package/src/access-observe-write-surface.ts +78 -19
- package/src/access-operations-batch.ts +2 -1
- package/src/access-schema-pi.test.ts +17 -0
- package/src/access-schema.ts +28 -11
- package/src/access-service-helpers.ts +46 -0
- package/src/access-service-observe-lcm-parity.test.ts +781 -31
- package/src/access-service-observe-scope.test.ts +88 -0
- package/src/access-service.ts +46 -128
- package/src/access-surface-catalog.test.ts +32 -0
- package/src/access-surface-catalog.ts +2 -0
- package/src/buffer-session.test.ts +148 -0
- package/src/buffer-turn-helpers.ts +152 -0
- package/src/buffer.ts +126 -201
- package/src/connectors/index.ts +1 -1
- package/src/connectors/label.ts +18 -0
- package/src/correction/correction-access-wiring.ts +79 -27
- package/src/correction/correction-executor.test.ts +542 -1
- package/src/correction/correction-executor.ts +309 -89
- package/src/correction/correction-planner.test.ts +35 -1
- package/src/correction/correction-planner.ts +50 -3
- package/src/correction/correction-service.ts +12 -7
- package/src/correction/correction-storage-integration.test.ts +172 -1
- package/src/correction/passive-capture.test.ts +35 -0
- package/src/correction/passive-capture.ts +17 -3
- package/src/extraction-source-grounding.ts +55 -1
- package/src/extraction-timeout.test.ts +51 -0
- package/src/extraction.ts +64 -90
- package/src/local-llm-headers-timeout.test.ts +48 -0
- package/src/local-llm-helpers.ts +58 -0
- package/src/local-llm.ts +62 -58
- package/src/orchestration/extraction-run-helpers.ts +309 -0
- package/src/orchestration/extraction-run.test.ts +350 -7
- package/src/orchestration/extraction-run.ts +327 -250
- package/src/orchestration/recall-result-formatter.ts +21 -2
- package/src/orchestration/recall-search-pipeline.test.ts +34 -0
- package/src/orchestration/recall-search-pipeline.ts +9 -1
- package/src/orchestration/session-context.ts +193 -18
- package/src/orchestration/turn-ingestion.ts +61 -11
- package/src/orchestrator-flush.test.ts +511 -5
- package/src/orchestrator.ts +8 -6
- package/src/recall-source-connector-label.test.ts +300 -0
- package/src/types.ts +3 -3
- package/dist/chunk-3UXOZBHV.js +0 -20
- package/dist/chunk-3UXOZBHV.js.map +0 -1
- package/dist/chunk-4A6YGWQN.js.map +0 -1
- package/dist/chunk-4WKA6I65.js.map +0 -1
- package/dist/chunk-4Z4XNEWZ.js.map +0 -1
- package/dist/chunk-6FUPCJUL.js.map +0 -1
- package/dist/chunk-B6JDYXL7.js.map +0 -1
- package/dist/chunk-G5R3D5UP.js.map +0 -1
- package/dist/chunk-GBJ4RDFR.js.map +0 -1
- package/dist/chunk-HUHX2OCX.js.map +0 -1
- package/dist/chunk-IYZ5K7MU.js.map +0 -1
- package/dist/chunk-LGHKJABJ.js.map +0 -1
- package/dist/chunk-NHWB6HG2.js.map +0 -1
- package/dist/chunk-PHWUFPCO.js.map +0 -1
- package/dist/chunk-RPW2NOU6.js.map +0 -1
- package/dist/chunk-SPJXKAVF.js.map +0 -1
- package/dist/chunk-YNQBRLC5.js.map +0 -1
- package/dist/chunk-YTSNAUXN.js.map +0 -1
- /package/dist/{capsule-crypto-GWVG7LGC.js.map → access-extraction-force-flush.js.map} +0 -0
- /package/dist/{capsule-merge-5KKJQBWQ.js.map → capsule-merge-2H2IUTBT.js.map} +0 -0
- /package/dist/{chunk-LEPOP46W.js.map → chunk-227UFSEQ.js.map} +0 -0
- /package/dist/{chunk-I5NLEENJ.js.map → chunk-27HHNYSQ.js.map} +0 -0
- /package/dist/{chunk-2SA56WMI.js.map → chunk-2LTDWSR6.js.map} +0 -0
- /package/dist/{chunk-OWHERGF2.js.map → chunk-2NLLXCJG.js.map} +0 -0
- /package/dist/{chunk-P5PXWTW7.js.map → chunk-2Q4JJ3FZ.js.map} +0 -0
- /package/dist/{chunk-H5CPS5JP.js.map → chunk-35IVNNRK.js.map} +0 -0
- /package/dist/{chunk-LBOD4U5B.js.map → chunk-3EQ2XB3W.js.map} +0 -0
- /package/dist/{chunk-2EUVEDF5.js.map → chunk-5WZVQRHV.js.map} +0 -0
- /package/dist/{chunk-ALSGMEJR.js.map → chunk-65ZPVYTA.js.map} +0 -0
- /package/dist/{chunk-GIBMDSJ2.js.map → chunk-6P7MTSU5.js.map} +0 -0
- /package/dist/{chunk-5VQJBH2G.js.map → chunk-6TAUHL33.js.map} +0 -0
- /package/dist/{chunk-WVO4G37W.js.map → chunk-7TEZUUGM.js.map} +0 -0
- /package/dist/{chunk-MJCGLM25.js.map → chunk-7VUAG236.js.map} +0 -0
- /package/dist/{chunk-CZRYLSSW.js.map → chunk-AJL6NNX6.js.map} +0 -0
- /package/dist/{chunk-66772WBP.js.map → chunk-AQWVJURR.js.map} +0 -0
- /package/dist/{chunk-RKNJBZ55.js.map → chunk-AU7Q3LSC.js.map} +0 -0
- /package/dist/{chunk-M3C2V3PV.js.map → chunk-CJDNT45S.js.map} +0 -0
- /package/dist/{chunk-D2ANTDGO.js.map → chunk-E6BMSH7U.js.map} +0 -0
- /package/dist/{chunk-CKMO4RDY.js.map → chunk-EMDLM3LW.js.map} +0 -0
- /package/dist/{chunk-RGIWINDN.js.map → chunk-FHBITMRY.js.map} +0 -0
- /package/dist/{chunk-FDAMS4PK.js.map → chunk-G2YQ57YO.js.map} +0 -0
- /package/dist/{chunk-6U7F52DE.js.map → chunk-HFQQWAMS.js.map} +0 -0
- /package/dist/{chunk-5W4ZLBEZ.js.map → chunk-HKPJPOW7.js.map} +0 -0
- /package/dist/{chunk-JCBWCYEJ.js.map → chunk-IGWFKW4B.js.map} +0 -0
- /package/dist/{chunk-AITCS2RC.js.map → chunk-IJ7HK452.js.map} +0 -0
- /package/dist/{chunk-D3LMYTBV.js.map → chunk-J7WZUL2K.js.map} +0 -0
- /package/dist/{chunk-5W7CTZ2E.js.map → chunk-KQAFEZQX.js.map} +0 -0
- /package/dist/{chunk-Z54EM5YZ.js.map → chunk-MAXVH44E.js.map} +0 -0
- /package/dist/{chunk-WZFAPHIK.js.map → chunk-MU7ZHSZE.js.map} +0 -0
- /package/dist/{chunk-AZ5BTEKX.js.map → chunk-NQUF7XKR.js.map} +0 -0
- /package/dist/{chunk-W4FBGYGK.js.map → chunk-NRV4Y3PM.js.map} +0 -0
- /package/dist/{chunk-62U4J2GN.js.map → chunk-ODGOP7P2.js.map} +0 -0
- /package/dist/{chunk-QJAQNXWI.js.map → chunk-ONHRRJZM.js.map} +0 -0
- /package/dist/{chunk-ACXPX4AG.js.map → chunk-OPBTPRGY.js.map} +0 -0
- /package/dist/{chunk-XOZ4ALGB.js.map → chunk-QDTZ2HF7.js.map} +0 -0
- /package/dist/{chunk-ZPSVBSOF.js.map → chunk-QMWFQBIL.js.map} +0 -0
- /package/dist/{chunk-W5EG6LE3.js.map → chunk-THCPRMRF.js.map} +0 -0
- /package/dist/{chunk-VI2JQPNQ.js.map → chunk-U7QYBSQJ.js.map} +0 -0
- /package/dist/{chunk-TH2LSRMG.js.map → chunk-UORKJ34C.js.map} +0 -0
- /package/dist/{chunk-K5GB36ME.js.map → chunk-VMZ56EE3.js.map} +0 -0
- /package/dist/{chunk-RMMVQQA6.js.map → chunk-WDISJRMG.js.map} +0 -0
- /package/dist/{chunk-UVYI6VIX.js.map → chunk-X7Y7WX73.js.map} +0 -0
- /package/dist/{chunk-CVILPI77.js.map → chunk-XOQSEF7X.js.map} +0 -0
- /package/dist/{chunk-YTQNQ4KB.js.map → chunk-YX5LN6JR.js.map} +0 -0
- /package/dist/{chunk-IC6CBHCA.js.map → chunk-Z7XKUWYS.js.map} +0 -0
|
@@ -51,6 +51,17 @@ export interface ExtractionRunResult {
|
|
|
51
51
|
postPersistMetadataFailed?: boolean;
|
|
52
52
|
}
|
|
53
53
|
|
|
54
|
+
export class ExtractionDeadlineError extends Error {
|
|
55
|
+
readonly stage: string;
|
|
56
|
+
|
|
57
|
+
constructor(stage: string) {
|
|
58
|
+
super(`replay extraction deadline exceeded (${stage})`);
|
|
59
|
+
this.name = "ExtractionDeadlineError";
|
|
60
|
+
this.stage = stage;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
|
|
54
65
|
/** Dependencies injected by the orchestrator. All stable references or
|
|
55
66
|
* live accessors — lazy getters for anything tests reassign
|
|
56
67
|
* post-construction (buffer, extraction, storageRouter, threading). */
|
|
@@ -81,6 +92,7 @@ export interface ExtractionRunCoordinatorDeps {
|
|
|
81
92
|
namespace: string;
|
|
82
93
|
bufferKey: string;
|
|
83
94
|
isLiveSession: boolean;
|
|
95
|
+
abortSignal?: AbortSignal;
|
|
84
96
|
}
|
|
85
97
|
) => Promise<void>;
|
|
86
98
|
|
|
@@ -112,83 +124,25 @@ export interface ExtractionRunCoordinatorDeps {
|
|
|
112
124
|
// #1526 seam 25; this file previously carried duplicate copies
|
|
113
125
|
// (AGENTS.md rule 8 — no duplicated helpers).
|
|
114
126
|
import { raceRecallAbort, throwIfRecallAborted } from "./orchestrator-helpers.js";
|
|
127
|
+
import {
|
|
128
|
+
capExtractionRetryStateEntries,
|
|
129
|
+
combineExtractionAbortSignals,
|
|
130
|
+
computeExtractionRetryNextEligibleMs,
|
|
131
|
+
deriveSourceConnector,
|
|
132
|
+
deriveTopicsFromExtraction,
|
|
133
|
+
runExtractionPostPersist,
|
|
134
|
+
runExtractionPostPersistBestEffort,
|
|
135
|
+
EXTRACTION_RETRY_STATE_MAX_ENTRIES,
|
|
136
|
+
} from "./extraction-run-helpers.js";
|
|
137
|
+
import type { ExtractionResilienceStatus, ExtractionRetryStateEntry } from "./extraction-run-helpers.js";
|
|
115
138
|
|
|
116
|
-
export
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
if (fact.category) topics.add(fact.category);
|
|
124
|
-
}
|
|
125
|
-
for (const entity of (result as any).entities ?? []) {
|
|
126
|
-
if (typeof entity.name === "string" && entity.name.length >= 2) {
|
|
127
|
-
topics.add(entity.name.toLowerCase());
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
return [...topics].slice(0, 16);
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
/** Bounded cap on persisted per-fingerprint retry-state entries (per namespace meta). */
|
|
134
|
-
const EXTRACTION_RETRY_STATE_MAX_ENTRIES = 500;
|
|
135
|
-
|
|
136
|
-
interface ExtractionRetryStateEntry {
|
|
137
|
-
attempts: number;
|
|
138
|
-
nextEligibleAtMs: number;
|
|
139
|
-
firstFailedAtMs: number;
|
|
140
|
-
lastFailureClass: ExtractionFailureClass;
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
export interface ExtractionResilienceStatus {
|
|
144
|
-
breaker: {
|
|
145
|
-
state: "closed" | "open" | "half_open";
|
|
146
|
-
openUntilMs: number;
|
|
147
|
-
consecutiveFailures: number;
|
|
148
|
-
lastReason: string;
|
|
149
|
-
};
|
|
150
|
-
backoffFingerprintCount: number;
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
/**
|
|
154
|
-
* Pure backoff scheduler. Returns the absolute ms timestamp at which a
|
|
155
|
-
* fingerprint that has failed `attempts` times becomes eligible again:
|
|
156
|
-
* exponential via the configured schedule, clamped to `maxBackoffMs`, with
|
|
157
|
-
* ±`jitterRatio` multiplicative jitter. `rng` is injectable for deterministic
|
|
158
|
-
* tests. Never returns a timestamp before `now`.
|
|
159
|
-
*/
|
|
160
|
-
export function computeExtractionRetryNextEligibleMs(
|
|
161
|
-
attempts: number,
|
|
162
|
-
scheduleMs: readonly number[],
|
|
163
|
-
maxBackoffMs: number,
|
|
164
|
-
jitterRatio: number,
|
|
165
|
-
now: number,
|
|
166
|
-
rng: () => number = Math.random,
|
|
167
|
-
): number {
|
|
168
|
-
const cap = Number.isFinite(maxBackoffMs) && maxBackoffMs > 0 ? maxBackoffMs : 0;
|
|
169
|
-
if (!Array.isArray(scheduleMs) || scheduleMs.length === 0) {
|
|
170
|
-
return now + cap;
|
|
171
|
-
}
|
|
172
|
-
const idx = Math.min(Math.max(attempts - 1, 0), scheduleMs.length - 1);
|
|
173
|
-
const step = scheduleMs[idx];
|
|
174
|
-
const base = Math.min(typeof step === "number" && step > 0 ? step : cap, cap);
|
|
175
|
-
const jitter = 1 + (rng() * 2 - 1) * jitterRatio;
|
|
176
|
-
return now + Math.max(0, Math.round(base * jitter));
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
/**
|
|
180
|
-
* Cap the persisted retry-state array to the newest `maxEntries` by
|
|
181
|
-
* firstFailedAt. Guards `maxEntries <= 0` so a zero cap returns [] rather than
|
|
182
|
-
* `slice(-0)`, which returns ALL entries (AGENTS.md rule 17).
|
|
183
|
-
*/
|
|
184
|
-
export function capExtractionRetryStateEntries<T extends { firstFailedAt: string }>(
|
|
185
|
-
entries: readonly T[],
|
|
186
|
-
maxEntries: number,
|
|
187
|
-
): T[] {
|
|
188
|
-
if (maxEntries <= 0) return [];
|
|
189
|
-
const sorted = [...entries].sort((a, b) => a.firstFailedAt.localeCompare(b.firstFailedAt));
|
|
190
|
-
return sorted.slice(-maxEntries);
|
|
191
|
-
}
|
|
139
|
+
export {
|
|
140
|
+
capExtractionRetryStateEntries,
|
|
141
|
+
computeExtractionRetryNextEligibleMs,
|
|
142
|
+
deriveSourceConnector,
|
|
143
|
+
deriveTopicsFromExtraction,
|
|
144
|
+
};
|
|
145
|
+
export type { ExtractionResilienceStatus };
|
|
192
146
|
|
|
193
147
|
/**
|
|
194
148
|
* Coordinates the extraction run pipeline. Holds the dedupe fingerprint
|
|
@@ -496,6 +450,7 @@ export class ExtractionRunCoordinator {
|
|
|
496
450
|
turns: BufferTurn[],
|
|
497
451
|
options: {
|
|
498
452
|
clearBufferAfterExtraction?: boolean;
|
|
453
|
+
clearMatchingTurns?: boolean;
|
|
499
454
|
skipCharThreshold?: boolean;
|
|
500
455
|
skipUserTurnThreshold?: boolean;
|
|
501
456
|
deadlineMs?: number;
|
|
@@ -503,52 +458,118 @@ export class ExtractionRunCoordinator {
|
|
|
503
458
|
abortSignal?: AbortSignal;
|
|
504
459
|
failOnExtractionFailure?: boolean;
|
|
505
460
|
/**
|
|
506
|
-
*
|
|
507
|
-
*
|
|
461
|
+
* Called immediately after durable extraction persistence returns, before
|
|
462
|
+
* any metadata, retention, or helper work. Lifecycle callers use this
|
|
463
|
+
* as the write-rate-limit commit boundary.
|
|
464
|
+
*/
|
|
465
|
+
onDurableCommit?: () => void;
|
|
466
|
+
/**
|
|
467
|
+
* Explicit namespace override for the write path (#460). When set, this
|
|
468
|
+
* is the namespace where extraction writes go instead of the one derived
|
|
508
469
|
* from `defaultNamespaceForPrincipal(resolvePrincipal(sessionKey))`.
|
|
509
|
-
* The resolved `principal` is still threaded into memory metadata
|
|
510
|
-
*
|
|
470
|
+
* The resolved `principal` is still threaded into memory metadata for
|
|
471
|
+
* provenance; only the storage target is overridden.
|
|
511
472
|
*/
|
|
512
473
|
writeNamespaceOverride?: string;
|
|
513
474
|
/**
|
|
514
475
|
* Pin the provenance principal instead of deriving it from
|
|
515
|
-
* `resolvePrincipal(sessionKey)
|
|
516
|
-
*
|
|
517
|
-
*
|
|
518
|
-
* (un-prefixed) key and storage is pinned via `writeNamespaceOverride`.
|
|
476
|
+
* `resolvePrincipal(sessionKey)`. When set, this is the identity an
|
|
477
|
+
* access surface already authenticated; used so observed-turn provenance
|
|
478
|
+
* is correct even though `turn.sessionKey` is the original key.
|
|
519
479
|
*/
|
|
520
480
|
principalOverride?: string;
|
|
481
|
+
/**
|
|
482
|
+
* Access scope resolution may already have selected a profile while the
|
|
483
|
+
* session context remains intentionally unbound. Reuse that plan for
|
|
484
|
+
* persistence instead of deriving it from shared session state.
|
|
485
|
+
*/
|
|
486
|
+
scopeProfileWritePlan?: ResolvedScopeProfilePlan | null;
|
|
521
487
|
/**
|
|
522
488
|
* Force the extractor call, bypassing the retry-backoff / circuit-breaker
|
|
523
|
-
* gate (extraction hot-loop hardening). Set by explicit flush paths
|
|
524
|
-
* (before_reset / session flush / replay / bulk import) that already pass
|
|
525
|
-
* `skipDedupeCheck: true` — AGENTS.md rule 18. A forced attempt still
|
|
526
|
-
* records its failure into retry-state/breaker.
|
|
489
|
+
* gate (extraction hot-loop hardening). Set by explicit flush paths.
|
|
527
490
|
*/
|
|
528
491
|
forceExtractionAttempt?: boolean;
|
|
529
492
|
} = {}
|
|
530
493
|
): Promise<ExtractionRunResult> {
|
|
531
494
|
log.debug(`running extraction on ${turns.length} turns`);
|
|
532
495
|
const clearBufferAfterExtraction = options.clearBufferAfterExtraction ?? true;
|
|
496
|
+
const clearMatchingTurns = options.clearMatchingTurns === true;
|
|
533
497
|
const skipCharThreshold = options.skipCharThreshold ?? false;
|
|
534
498
|
const skipUserTurnThreshold = options.skipUserTurnThreshold ?? false;
|
|
535
499
|
const deadlineMs =
|
|
536
500
|
typeof options.deadlineMs === "number" && Number.isFinite(options.deadlineMs) ? options.deadlineMs : undefined;
|
|
537
501
|
const bufferKey = options.bufferKey ?? turns[0]?.sessionKey ?? "default";
|
|
538
502
|
const throwIfDeadlineExceeded = (stage: string): void => {
|
|
539
|
-
if (typeof deadlineMs === "number" && Date.now()
|
|
540
|
-
throw new
|
|
503
|
+
if (typeof deadlineMs === "number" && Date.now() >= deadlineMs) {
|
|
504
|
+
throw new ExtractionDeadlineError(stage);
|
|
541
505
|
}
|
|
542
506
|
};
|
|
543
507
|
const throwIfAborted = (stage: string): void => {
|
|
544
508
|
throwIfRecallAborted(options.abortSignal, `extraction aborted (${stage})`);
|
|
545
509
|
};
|
|
510
|
+
const runPassiveCapture = async (
|
|
511
|
+
captureTurns: readonly BufferTurn[],
|
|
512
|
+
captureOptions: {
|
|
513
|
+
sessionKey: string;
|
|
514
|
+
principal?: string;
|
|
515
|
+
namespace: string;
|
|
516
|
+
bufferKey: string;
|
|
517
|
+
isLiveSession: boolean;
|
|
518
|
+
abortSignal?: AbortSignal;
|
|
519
|
+
},
|
|
520
|
+
): Promise<void> => {
|
|
521
|
+
const deadlineController =
|
|
522
|
+
typeof deadlineMs === "number" && Number.isFinite(deadlineMs) ? new AbortController() : undefined;
|
|
523
|
+
const captureSignal = combineExtractionAbortSignals(captureOptions.abortSignal ?? options.abortSignal,
|
|
524
|
+
deadlineController);
|
|
525
|
+
let deadlineTimer: NodeJS.Timeout | undefined;
|
|
526
|
+
if (deadlineController && typeof deadlineMs === "number") {
|
|
527
|
+
const scheduleDeadlineAbort = (): void => {
|
|
528
|
+
const remainingMs = deadlineMs - Date.now();
|
|
529
|
+
if (remainingMs <= 0) {
|
|
530
|
+
deadlineController.abort();
|
|
531
|
+
return;
|
|
532
|
+
}
|
|
533
|
+
deadlineTimer = setTimeout(
|
|
534
|
+
() => {
|
|
535
|
+
if (Date.now() >= deadlineMs) {
|
|
536
|
+
deadlineController.abort();
|
|
537
|
+
} else {
|
|
538
|
+
scheduleDeadlineAbort();
|
|
539
|
+
}
|
|
540
|
+
},
|
|
541
|
+
Math.min(remainingMs, 2_147_483_647),
|
|
542
|
+
);
|
|
543
|
+
};
|
|
544
|
+
scheduleDeadlineAbort();
|
|
545
|
+
}
|
|
546
|
+
try {
|
|
547
|
+
await raceRecallAbort(
|
|
548
|
+
this.deps.maybeCapturePassiveCorrections(captureTurns, {
|
|
549
|
+
...captureOptions,
|
|
550
|
+
...(captureSignal ? { abortSignal: captureSignal } : {}),
|
|
551
|
+
}),
|
|
552
|
+
captureSignal,
|
|
553
|
+
"extraction aborted (during_passive_capture)",
|
|
554
|
+
);
|
|
555
|
+
} catch (error) {
|
|
556
|
+
if (typeof deadlineMs === "number" && Date.now() >= deadlineMs) {
|
|
557
|
+
throw new ExtractionDeadlineError("during_passive_capture");
|
|
558
|
+
}
|
|
559
|
+
throw error;
|
|
560
|
+
} finally {
|
|
561
|
+
if (deadlineTimer) clearTimeout(deadlineTimer);
|
|
562
|
+
}
|
|
563
|
+
};
|
|
546
564
|
const clearBuffer = async (options?: { ignoreAbort?: boolean }) => {
|
|
547
565
|
if (options?.ignoreAbort !== true) {
|
|
566
|
+
throwIfDeadlineExceeded("before_clear_buffer");
|
|
548
567
|
throwIfAborted("before_clear_buffer");
|
|
549
568
|
}
|
|
550
569
|
if (clearBufferAfterExtraction) {
|
|
551
|
-
await this.deps
|
|
570
|
+
await this.deps
|
|
571
|
+
.getBuffer()
|
|
572
|
+
.clearAfterExtraction(bufferKey, turns, clearMatchingTurns ? { allowNonPrefix: true } : undefined);
|
|
552
573
|
}
|
|
553
574
|
};
|
|
554
575
|
|
|
@@ -578,13 +599,23 @@ export class ExtractionRunCoordinator {
|
|
|
578
599
|
// Context-only turns may still contain corrections (review: "context-only
|
|
579
600
|
// turns skip capture"). Scan normalizedTurns before clearing the buffer.
|
|
580
601
|
if (normalizedTurns.length > 0) {
|
|
581
|
-
|
|
602
|
+
throwIfDeadlineExceeded("before_context_only_capture");
|
|
603
|
+
const capturePrincipal =
|
|
604
|
+
typeof options.principalOverride === "string" && options.principalOverride.length > 0
|
|
605
|
+
? options.principalOverride
|
|
606
|
+
: resolvePrincipal(sessionKey, this.config);
|
|
607
|
+
const captureNamespace =
|
|
608
|
+
typeof options.writeNamespaceOverride === "string" && options.writeNamespaceOverride.length > 0
|
|
609
|
+
? options.writeNamespaceOverride
|
|
610
|
+
: this.deps.resolveSelfNamespace(sessionKey);
|
|
611
|
+
await runPassiveCapture(normalizedTurns as BufferTurn[], {
|
|
582
612
|
sessionKey,
|
|
583
|
-
principal:
|
|
584
|
-
namespace:
|
|
613
|
+
principal: capturePrincipal,
|
|
614
|
+
namespace: captureNamespace,
|
|
585
615
|
bufferKey,
|
|
586
616
|
isLiveSession: clearBufferAfterExtraction,
|
|
587
617
|
});
|
|
618
|
+
throwIfDeadlineExceeded("before_context_only_clear");
|
|
588
619
|
}
|
|
589
620
|
await clearBuffer();
|
|
590
621
|
return { status: "skipped", reason: "empty_normalized_turns", persistedCount: 0, durableOutputCount: 0 };
|
|
@@ -599,7 +630,6 @@ export class ExtractionRunCoordinator {
|
|
|
599
630
|
const belowUserTurnThreshold = !skipUserTurnThreshold && userTurns.length < this.config.extractionMinUserTurns;
|
|
600
631
|
if ((!skipCharThreshold && belowCharThreshold) || belowUserTurnThreshold) {
|
|
601
632
|
log.debug(`skipping extraction: below threshold (totalChars=${totalChars}, userTurns=${userTurns.length})`);
|
|
602
|
-
await clearBuffer();
|
|
603
633
|
// Passive correction capture runs even when extraction is skipped for
|
|
604
634
|
// being below the char/user-turn threshold (review: "skipped extraction
|
|
605
635
|
// skips capture"). A short correction like "stop using Vim" is under
|
|
@@ -632,7 +662,7 @@ export class ExtractionRunCoordinator {
|
|
|
632
662
|
});
|
|
633
663
|
const captureNamespace =
|
|
634
664
|
captureWO ?? captureScopePlan?.writeNamespace ?? this.deps.resolveSelfNamespace(sessionKey);
|
|
635
|
-
await
|
|
665
|
+
await runPassiveCapture(normalizedTurns as BufferTurn[], {
|
|
636
666
|
sessionKey,
|
|
637
667
|
principal: capturePrincipal,
|
|
638
668
|
namespace: captureNamespace,
|
|
@@ -640,6 +670,7 @@ export class ExtractionRunCoordinator {
|
|
|
640
670
|
isLiveSession: clearBufferAfterExtraction,
|
|
641
671
|
});
|
|
642
672
|
}
|
|
673
|
+
await clearBuffer();
|
|
643
674
|
return {
|
|
644
675
|
status: "skipped",
|
|
645
676
|
reason: "below_threshold",
|
|
@@ -673,13 +704,19 @@ export class ExtractionRunCoordinator {
|
|
|
673
704
|
this.config.codingMode,
|
|
674
705
|
this.config.defaultNamespace
|
|
675
706
|
);
|
|
676
|
-
const scopeProfileGatePlan =
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
707
|
+
const scopeProfileGatePlan =
|
|
708
|
+
options.scopeProfileWritePlan !== undefined
|
|
709
|
+
? options.scopeProfileWritePlan
|
|
710
|
+
: resolveScopeProfilePlan({
|
|
711
|
+
config: this.config,
|
|
712
|
+
principal,
|
|
713
|
+
codingContext: codingContextForWrite,
|
|
714
|
+
codingOverlay: codingOverlayForWrite,
|
|
715
|
+
});
|
|
716
|
+
const scopeProfileWritePlan =
|
|
717
|
+
explicitWriteNamespace && options.scopeProfileWritePlan === undefined
|
|
718
|
+
? null
|
|
719
|
+
: scopeProfileGatePlan;
|
|
683
720
|
if (scopeProfileWritePlan) {
|
|
684
721
|
const selectedLayer = scopeProfileWritePlan.layers.find((layer) => layer.id === scopeProfileWritePlan.writeLayer);
|
|
685
722
|
const writeNamespaceReadable = scopeProfileWritePlan.readNamespaces.includes(
|
|
@@ -702,17 +739,84 @@ export class ExtractionRunCoordinator {
|
|
|
702
739
|
explicitWriteNamespace ??
|
|
703
740
|
scopeProfileWritePlan?.writeNamespace ??
|
|
704
741
|
this.deps.applyCodingNamespaceOverlay(sessionKey, defaultNamespaceForPrincipal(principal, this.config));
|
|
705
|
-
const
|
|
742
|
+
const extractionDeadlineController =
|
|
743
|
+
typeof deadlineMs === "number" && Number.isFinite(deadlineMs)
|
|
744
|
+
? new AbortController()
|
|
745
|
+
: undefined;
|
|
746
|
+
const extractionAbortSignal = extractionDeadlineController
|
|
747
|
+
? options.abortSignal
|
|
748
|
+
? AbortSignal.any([options.abortSignal, extractionDeadlineController.signal])
|
|
749
|
+
: extractionDeadlineController.signal
|
|
750
|
+
: options.abortSignal;
|
|
751
|
+
let extractionDeadlineTimer: NodeJS.Timeout | undefined;
|
|
752
|
+
const clearExtractionDeadlineTimer = (): void => {
|
|
753
|
+
if (extractionDeadlineTimer) {
|
|
754
|
+
clearTimeout(extractionDeadlineTimer);
|
|
755
|
+
extractionDeadlineTimer = undefined;
|
|
756
|
+
}
|
|
757
|
+
};
|
|
758
|
+
const runDeadlineAware = async <T>(
|
|
759
|
+
operation: () => Promise<T>,
|
|
760
|
+
phase: string,
|
|
761
|
+
clearTimerOnError = true,
|
|
762
|
+
options: { ignoreAbort?: boolean; ignoreDeadline?: boolean } = {},
|
|
763
|
+
): Promise<T> => {
|
|
764
|
+
const operationSignal = options.ignoreAbort ? undefined : extractionAbortSignal;
|
|
765
|
+
try {
|
|
766
|
+
if (!options.ignoreDeadline && typeof deadlineMs === "number" && Date.now() >= deadlineMs) {
|
|
767
|
+
throwIfDeadlineExceeded(phase);
|
|
768
|
+
}
|
|
769
|
+
if (operationSignal?.aborted) {
|
|
770
|
+
throwIfAborted(phase);
|
|
771
|
+
}
|
|
772
|
+
return await raceRecallAbort(
|
|
773
|
+
operation(),
|
|
774
|
+
operationSignal,
|
|
775
|
+
`extraction aborted (${phase})`,
|
|
776
|
+
);
|
|
777
|
+
} catch (error) {
|
|
778
|
+
if (clearTimerOnError) clearExtractionDeadlineTimer();
|
|
779
|
+
if (!options.ignoreDeadline && typeof deadlineMs === "number" && Date.now() >= deadlineMs) {
|
|
780
|
+
throw new ExtractionDeadlineError(phase);
|
|
781
|
+
}
|
|
782
|
+
throw error;
|
|
783
|
+
}
|
|
784
|
+
};
|
|
785
|
+
if (extractionDeadlineController && typeof deadlineMs === "number") {
|
|
786
|
+
const deadline = deadlineMs;
|
|
787
|
+
const maxTimerDelayMs = 2_147_483_647;
|
|
788
|
+
const scheduleDeadlineAbort = (): void => {
|
|
789
|
+
const remainingMs = deadline - Date.now();
|
|
790
|
+
if (remainingMs <= 0) {
|
|
791
|
+
extractionDeadlineController.abort();
|
|
792
|
+
return;
|
|
793
|
+
}
|
|
794
|
+
extractionDeadlineTimer = setTimeout(() => {
|
|
795
|
+
if (Date.now() >= deadline) {
|
|
796
|
+
extractionDeadlineController.abort();
|
|
797
|
+
} else {
|
|
798
|
+
scheduleDeadlineAbort();
|
|
799
|
+
}
|
|
800
|
+
}, Math.min(remainingMs, maxTimerDelayMs));
|
|
801
|
+
};
|
|
802
|
+
scheduleDeadlineAbort();
|
|
803
|
+
}
|
|
804
|
+
const storage = await runDeadlineAware(
|
|
805
|
+
() => this.deps.getStorageRouter().storageFor(selfNamespace),
|
|
806
|
+
"during_storage",
|
|
807
|
+
);
|
|
706
808
|
const shouldPersistProcessedFingerprint = targetTurns.some((turn) => turn.persistProcessedFingerprint === true);
|
|
707
809
|
const extractionFingerprint = this.buildExtractionFingerprint(targetTurns, bufferKey);
|
|
708
|
-
let meta = extractionFingerprint && shouldPersistProcessedFingerprint
|
|
810
|
+
let meta = extractionFingerprint && shouldPersistProcessedFingerprint
|
|
811
|
+
? await runDeadlineAware(() => storage.loadMeta(), "during_load_meta")
|
|
812
|
+
: null;
|
|
709
813
|
if (
|
|
710
814
|
extractionFingerprint &&
|
|
711
815
|
shouldPersistProcessedFingerprint &&
|
|
712
816
|
(meta?.processedExtractionFingerprints ?? []).some((entry) => entry.fingerprint === extractionFingerprint)
|
|
713
817
|
) {
|
|
714
|
-
|
|
715
|
-
|
|
818
|
+
await runDeadlineAware(() => clearBuffer(), "during_clear_buffer");
|
|
819
|
+
clearExtractionDeadlineTimer();
|
|
716
820
|
return {
|
|
717
821
|
status: "skipped",
|
|
718
822
|
reason: "processed_fingerprint",
|
|
@@ -735,7 +839,7 @@ export class ExtractionRunCoordinator {
|
|
|
735
839
|
const extractionRetryEnabled = resolveMemoryLifecycleCapabilities(this.config).extractionRetry;
|
|
736
840
|
if (extractionFingerprint && !forcedExtractionAttempt && extractionRetryEnabled) {
|
|
737
841
|
try {
|
|
738
|
-
meta ??= await storage.loadMeta();
|
|
842
|
+
meta ??= await runDeadlineAware(() => storage.loadMeta(), "during_retry_gate");
|
|
739
843
|
this.hydrateRetryStateFromMeta(selfNamespace, meta);
|
|
740
844
|
const nowMs = Date.now();
|
|
741
845
|
let suppressReason: "provider_circuit_open" | "extraction_backoff" | null = null;
|
|
@@ -746,38 +850,55 @@ export class ExtractionRunCoordinator {
|
|
|
746
850
|
if (st && nowMs < st.nextEligibleAtMs) suppressReason = "extraction_backoff";
|
|
747
851
|
}
|
|
748
852
|
if (suppressReason) {
|
|
749
|
-
//
|
|
750
|
-
//
|
|
751
|
-
// cooldown — "stop calling me X" style turns should register during
|
|
752
|
-
// a 30-minute breaker window too (codex review). Fail-open.
|
|
853
|
+
// Passive correction capture is local and must not be delayed by a
|
|
854
|
+
// provider cooldown. It remains fail-open.
|
|
753
855
|
try {
|
|
754
|
-
await
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
856
|
+
await runDeadlineAware(
|
|
857
|
+
() => runPassiveCapture(normalizedTurns as BufferTurn[], {
|
|
858
|
+
sessionKey,
|
|
859
|
+
principal,
|
|
860
|
+
namespace: selfNamespace,
|
|
861
|
+
bufferKey,
|
|
862
|
+
isLiveSession: clearBufferAfterExtraction,
|
|
863
|
+
}),
|
|
864
|
+
"during_passive_capture",
|
|
865
|
+
);
|
|
761
866
|
} catch (captureErr) {
|
|
867
|
+
if (captureErr instanceof ExtractionDeadlineError) throw captureErr;
|
|
762
868
|
log.warn("runExtraction: passive correction capture failed on suppressed attempt (non-fatal)", captureErr);
|
|
763
869
|
}
|
|
870
|
+
clearExtractionDeadlineTimer();
|
|
764
871
|
return { status: "skipped", reason: suppressReason, persistedCount: 0, durableOutputCount: 0 };
|
|
765
872
|
}
|
|
766
873
|
} catch (err) {
|
|
874
|
+
if (err instanceof ExtractionDeadlineError) throw err;
|
|
767
875
|
// Fail-open: a gate error must never block extraction.
|
|
768
876
|
log.warn("runExtraction: extraction retry gate check failed; proceeding (fail-open)", err);
|
|
769
877
|
}
|
|
770
878
|
}
|
|
771
879
|
|
|
772
|
-
// Pass existing entity names so the LLM can reuse them instead of inventing variants
|
|
773
|
-
const existingEntities = await
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
options.abortSignal,
|
|
777
|
-
"extraction aborted (during_extract)"
|
|
880
|
+
// Pass existing entity names so the LLM can reuse them instead of inventing variants.
|
|
881
|
+
const existingEntities = await runDeadlineAware(
|
|
882
|
+
() => storage.listEntityNames(),
|
|
883
|
+
"during_list_entity_names",
|
|
778
884
|
);
|
|
779
|
-
|
|
780
|
-
|
|
885
|
+
let result: ExtractionResult;
|
|
886
|
+
try {
|
|
887
|
+
result = await raceRecallAbort(
|
|
888
|
+
this.deps.getExtraction().extract(normalizedTurns, existingEntities, extractionAbortSignal),
|
|
889
|
+
extractionAbortSignal,
|
|
890
|
+
"extraction aborted (during_extract)",
|
|
891
|
+
);
|
|
892
|
+
} catch (error) {
|
|
893
|
+
clearExtractionDeadlineTimer();
|
|
894
|
+
if (typeof deadlineMs === "number" && Date.now() >= deadlineMs) {
|
|
895
|
+
throw new ExtractionDeadlineError("during_extract");
|
|
896
|
+
}
|
|
897
|
+
throw error;
|
|
898
|
+
}
|
|
899
|
+
try {
|
|
900
|
+
throwIfDeadlineExceeded("before_persist");
|
|
901
|
+
throwIfAborted("before_persist");
|
|
781
902
|
|
|
782
903
|
// Defensive: validate extraction result before processing. Explicit
|
|
783
904
|
// fail-closed callers, such as flush-plan import, must not observe
|
|
@@ -831,20 +952,26 @@ export class ExtractionRunCoordinator {
|
|
|
831
952
|
if (extractionFingerprint && extractionRetryEnabled) {
|
|
832
953
|
if (extractionFailure) {
|
|
833
954
|
try {
|
|
834
|
-
meta ??= await storage.loadMeta();
|
|
835
|
-
await
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
955
|
+
meta ??= await runDeadlineAware(() => storage.loadMeta(), "during_retry_bookkeeping_load", false);
|
|
956
|
+
await runDeadlineAware(
|
|
957
|
+
() =>
|
|
958
|
+
this.recordExtractionFailure(
|
|
959
|
+
storage,
|
|
960
|
+
selfNamespace,
|
|
961
|
+
extractionFingerprint,
|
|
962
|
+
result.extractionFailureClass ?? "provider_retryable",
|
|
963
|
+
meta!,
|
|
964
|
+
Date.now(),
|
|
965
|
+
),
|
|
966
|
+
"during_retry_bookkeeping_save",
|
|
967
|
+
false,
|
|
842
968
|
);
|
|
843
969
|
// The buffer is retained below so the backoff gate can re-attempt
|
|
844
970
|
// these turns after nextEligibleAt — clearing would orphan the
|
|
845
971
|
// retry state.
|
|
846
972
|
recordedRetryFailure = true;
|
|
847
973
|
} catch (err) {
|
|
974
|
+
if (err instanceof ExtractionDeadlineError) throw err;
|
|
848
975
|
// Fail-open (codex review): retry bookkeeping is best-effort — a
|
|
849
976
|
// corrupt or locked meta store must not reject the extraction task.
|
|
850
977
|
// With no backoff recorded there is nothing to retain for, so the
|
|
@@ -856,7 +983,7 @@ export class ExtractionRunCoordinator {
|
|
|
856
983
|
// parked backoff for this fingerprint so it proceeds normally.
|
|
857
984
|
this.resetProviderBreakerOnSuccess();
|
|
858
985
|
try {
|
|
859
|
-
meta ??= await storage.loadMeta();
|
|
986
|
+
meta ??= await runDeadlineAware(() => storage.loadMeta(), "during_retry_bookkeeping_load", false);
|
|
860
987
|
// Hydrate the in-memory mirror from persisted meta before clearing.
|
|
861
988
|
// A forced flush (forceExtractionAttempt) bypasses the retry gate and
|
|
862
989
|
// never hydrated, so without this a stale persisted backoff entry
|
|
@@ -864,9 +991,10 @@ export class ExtractionRunCoordinator {
|
|
|
864
991
|
// extraction until the timer expired (cursor/codex review).
|
|
865
992
|
this.hydrateRetryStateFromMeta(selfNamespace, meta);
|
|
866
993
|
if (this.clearExtractionRetryEntry(selfNamespace, extractionFingerprint, meta)) {
|
|
867
|
-
await storage.saveMeta(meta);
|
|
994
|
+
await runDeadlineAware(() => storage.saveMeta(meta!), "during_retry_bookkeeping_save", false);
|
|
868
995
|
}
|
|
869
996
|
} catch (err) {
|
|
997
|
+
if (err instanceof ExtractionDeadlineError) throw err;
|
|
870
998
|
log.warn("runExtraction: failed to persist cleared retry state (non-fatal)", err);
|
|
871
999
|
}
|
|
872
1000
|
}
|
|
@@ -897,7 +1025,7 @@ export class ExtractionRunCoordinator {
|
|
|
897
1025
|
// Correction-only turns that meet char/user-turn thresholds but yield
|
|
898
1026
|
// zero facts still need passive capture (review: "empty extraction skips
|
|
899
1027
|
// capture"). selfNamespace/principal already resolved above.
|
|
900
|
-
await
|
|
1028
|
+
await runPassiveCapture(normalizedTurns as BufferTurn[], {
|
|
901
1029
|
sessionKey,
|
|
902
1030
|
principal,
|
|
903
1031
|
namespace: selfNamespace,
|
|
@@ -922,12 +1050,18 @@ export class ExtractionRunCoordinator {
|
|
|
922
1050
|
if (resolvePresentationCapabilities(this.config).threading && turns.length > 0) {
|
|
923
1051
|
const lastTurn = turns[turns.length - 1];
|
|
924
1052
|
try {
|
|
925
|
-
threadIdForExtraction = await
|
|
1053
|
+
threadIdForExtraction = await runDeadlineAware(
|
|
1054
|
+
() => this.deps.getThreading().processTurn(lastTurn, []),
|
|
1055
|
+
"during_threading",
|
|
1056
|
+
);
|
|
926
1057
|
} catch (err) {
|
|
1058
|
+
if (err instanceof ExtractionDeadlineError) throw err;
|
|
927
1059
|
// Fail-open: threading errors must not block memory persistence.
|
|
928
1060
|
log.warn("[threading] processTurn failed before persistence (non-fatal)", err);
|
|
929
1061
|
}
|
|
930
1062
|
}
|
|
1063
|
+
throwIfDeadlineExceeded("before_persist");
|
|
1064
|
+
throwIfAborted("before_persist");
|
|
931
1065
|
|
|
932
1066
|
const { persistedIds } = await this.deps.persistExtraction(
|
|
933
1067
|
result,
|
|
@@ -937,94 +1071,61 @@ export class ExtractionRunCoordinator {
|
|
|
937
1071
|
// Pass the KNOWN base namespace (NHIdx) so the catalog write touch records the
|
|
938
1072
|
// real namespace rather than a guess decoded from the storage dir.
|
|
939
1073
|
selfNamespace,
|
|
940
|
-
|
|
1074
|
+
scopeProfileWritePlan,
|
|
941
1075
|
// Verbatim source turns for the faithfulness gate (#1576) so it can
|
|
942
1076
|
// locate a quote per fact when #1575 spans are absent.
|
|
943
1077
|
normalizedTurns
|
|
944
1078
|
.map((t) => t.content)
|
|
945
1079
|
.join("\n\n")
|
|
946
1080
|
);
|
|
947
|
-
let postPersistMetadataFailed = false;
|
|
948
|
-
meta ??= await storage.loadMeta();
|
|
949
|
-
if (extractionFingerprint && shouldPersistProcessedFingerprint) {
|
|
950
|
-
try {
|
|
951
|
-
await this.deps.recordProcessedExtractionFingerprint(storage, extractionFingerprint, meta);
|
|
952
|
-
} catch (error) {
|
|
953
|
-
log.warn(
|
|
954
|
-
"runExtraction: failed to persist processed extraction fingerprint; continuing with buffer clear",
|
|
955
|
-
error
|
|
956
|
-
);
|
|
957
|
-
postPersistMetadataFailed = true;
|
|
958
|
-
}
|
|
959
|
-
}
|
|
960
|
-
// Persist extraction counters and processed fingerprints before running
|
|
961
|
-
// follow-on helpers so replay dedupe survives any later non-essential
|
|
962
|
-
// failure. If this aggregate meta write fails, still clear the buffer:
|
|
963
|
-
// the durable memories are already written and replaying the same turns
|
|
964
|
-
// would duplicate them.
|
|
965
|
-
meta.extractionCount += 1;
|
|
966
|
-
meta.lastExtractionAt = new Date().toISOString();
|
|
967
|
-
meta.totalMemories += Array.isArray(result?.facts) ? result.facts.length : 0;
|
|
968
|
-
meta.totalEntities += Array.isArray(result?.entities) ? result.entities.length : 0;
|
|
969
|
-
try {
|
|
970
|
-
await storage.saveMeta(meta);
|
|
971
|
-
} catch (error) {
|
|
972
|
-
log.warn(
|
|
973
|
-
"runExtraction: failed to save extraction metadata after durable persistence; continuing with buffer clear",
|
|
974
|
-
error
|
|
975
|
-
);
|
|
976
|
-
postPersistMetadataFailed = true;
|
|
977
|
-
}
|
|
978
|
-
|
|
979
1081
|
const durableOutputCount =
|
|
980
1082
|
result.facts.length + result.entities.length + result.questions.length + result.profileUpdates.length;
|
|
981
|
-
|
|
982
|
-
// Buffer retention for defer verdicts (issue #562, PR 2). When the judge
|
|
983
|
-
// deferred at least one candidate, retain the tail of the current turn
|
|
984
|
-
// window so the next extraction pass has the surrounding context that
|
|
985
|
-
// may disambiguate the deferred fact. Non-defer runs clear the slot.
|
|
986
|
-
//
|
|
987
|
-
// Gated on:
|
|
988
|
-
// - `clearBufferAfterExtraction` — replay / bulk-import paths call
|
|
989
|
-
// `runExtraction` with this false and do not operate on live buffer
|
|
990
|
-
// state. Writing retention there would create synthetic buffer
|
|
991
|
-
// entries and cross-contaminate future live extractions.
|
|
992
|
-
// - NOT `extractionJudgeShadow` — in shadow mode the judge is only
|
|
993
|
-
// advisory; facts are still persisted regardless of verdict, so
|
|
994
|
-
// retaining the turn window on top of a persisted write would both
|
|
995
|
-
// waste buffer space and cause the same facts to re-enter the
|
|
996
|
-
// pipeline on the next pass.
|
|
997
1083
|
try {
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
await this.deps.getBuffer().retainDeferredTurns(bufferKey, normalizedTurns as BufferTurn[], 10);
|
|
1002
|
-
} else {
|
|
1003
|
-
await this.deps.getBuffer().retainDeferredTurns(bufferKey, [], 0);
|
|
1004
|
-
}
|
|
1005
|
-
}
|
|
1006
|
-
} catch (err) {
|
|
1007
|
-
// Fail-open: retention is a nice-to-have. If it fails the judge will
|
|
1008
|
-
// still cap deferrals and convert to reject on the next pass.
|
|
1009
|
-
log.debug(
|
|
1010
|
-
`extraction-judge: defer retention failed (non-fatal): ${err instanceof Error ? err.message : String(err)}`
|
|
1011
|
-
);
|
|
1084
|
+
options.onDurableCommit?.();
|
|
1085
|
+
} catch (error) {
|
|
1086
|
+
log.warn("runExtraction: durable-commit callback failed", error);
|
|
1012
1087
|
}
|
|
1013
|
-
|
|
1014
|
-
await
|
|
1088
|
+
const runPostPersistBestEffort = runExtractionPostPersistBestEffort.bind(null, runDeadlineAware);
|
|
1089
|
+
const postPersist = await runExtractionPostPersist({
|
|
1090
|
+
result,
|
|
1091
|
+
storage,
|
|
1092
|
+
meta: meta ?? undefined,
|
|
1093
|
+
extractionFingerprint: extractionFingerprint ?? undefined,
|
|
1094
|
+
shouldPersistProcessedFingerprint,
|
|
1095
|
+
recordProcessedExtractionFingerprint: this.deps.recordProcessedExtractionFingerprint,
|
|
1096
|
+
runDeadlineAware,
|
|
1097
|
+
isDeadlineError: (error) => error instanceof ExtractionDeadlineError,
|
|
1098
|
+
createDeadlineError: (stage) => new ExtractionDeadlineError(stage),
|
|
1099
|
+
deadlineMs,
|
|
1100
|
+
clearBufferAfterExtraction,
|
|
1101
|
+
runPostPersistBestEffort,
|
|
1102
|
+
extractionJudgeShadow: this.config.extractionJudgeShadow,
|
|
1103
|
+
getDeferredCount: () => this.deps.getLastPersistExtractionDeferredCount(),
|
|
1104
|
+
normalizedTurns: normalizedTurns as BufferTurn[],
|
|
1105
|
+
bufferKey,
|
|
1106
|
+
retainDeferredTurns: (key, retainedTurns, max) =>
|
|
1107
|
+
this.deps.getBuffer().retainDeferredTurns(key, retainedTurns, max),
|
|
1108
|
+
clearBuffer,
|
|
1109
|
+
failOnExtractionFailure: options.failOnExtractionFailure === true,
|
|
1110
|
+
});
|
|
1111
|
+
meta = postPersist.meta ?? null;
|
|
1112
|
+
const postPersistMetadataFailed = postPersist.metadataFailed;
|
|
1015
1113
|
|
|
1016
1114
|
// Passive correction capture (issue #1581) — detect corrections expressed
|
|
1017
1115
|
// passively in the extracted turns and route to the Correction Contract.
|
|
1018
1116
|
// Runs AFTER persistence + buffer clear so a capture failure never blocks
|
|
1019
1117
|
// the extraction return. `clearBufferAfterExtraction` gates live-session
|
|
1020
1118
|
// auto-apply (replay/import → queue-only).
|
|
1021
|
-
await
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1119
|
+
await runPostPersistBestEffort("during_post_persist_passive_capture", () =>
|
|
1120
|
+
runPassiveCapture(normalizedTurns as BufferTurn[], {
|
|
1121
|
+
sessionKey,
|
|
1122
|
+
principal,
|
|
1123
|
+
namespace: selfNamespace,
|
|
1124
|
+
bufferKey,
|
|
1125
|
+
isLiveSession: clearBufferAfterExtraction,
|
|
1126
|
+
abortSignal: extractionAbortSignal,
|
|
1127
|
+
}),
|
|
1128
|
+
);
|
|
1028
1129
|
|
|
1029
1130
|
// Build memory box from this extraction (v8.0 Phase 2A)
|
|
1030
1131
|
// Topics are derived from the current extraction's facts and entities only —
|
|
@@ -1035,31 +1136,30 @@ export class ExtractionRunCoordinator {
|
|
|
1035
1136
|
// Derive episodic metadata from buffer turns (REMem-inspired)
|
|
1036
1137
|
const firstUserTurn = turns.find((t) => t.role === "user");
|
|
1037
1138
|
const boxGoal = firstUserTurn?.content?.slice(0, 100)?.trim() || undefined;
|
|
1038
|
-
await
|
|
1039
|
-
.boxBuilderFor(storage)
|
|
1040
|
-
.onExtraction({
|
|
1139
|
+
await runPostPersistBestEffort("during_memory_box", () =>
|
|
1140
|
+
this.deps.boxBuilderFor(storage).onExtraction({
|
|
1041
1141
|
topics: extractionTopics,
|
|
1042
1142
|
memoryIds: persistedIds,
|
|
1043
1143
|
timestamp: new Date().toISOString(),
|
|
1044
1144
|
goal: boxGoal,
|
|
1045
|
-
})
|
|
1046
|
-
|
|
1145
|
+
}),
|
|
1146
|
+
);
|
|
1047
1147
|
}
|
|
1048
1148
|
|
|
1049
1149
|
// Batch-append persisted IDs so non-fact memories (entities/questions) are
|
|
1050
1150
|
// always attached to the thread. The helper excludes pending_review ids (#1635).
|
|
1051
1151
|
if (resolvePresentationCapabilities(this.config).threading && threadIdForExtraction && persistedIds.length > 0) {
|
|
1052
|
-
await
|
|
1152
|
+
await runPostPersistBestEffort("during_thread_episode_append", () =>
|
|
1153
|
+
this.deps.appendPersistedThreadEpisodes(threadIdForExtraction, persistedIds),
|
|
1154
|
+
);
|
|
1053
1155
|
}
|
|
1054
1156
|
|
|
1055
1157
|
// Thread title update for the already-established thread context.
|
|
1056
1158
|
if (resolvePresentationCapabilities(this.config).threading && threadIdForExtraction) {
|
|
1057
1159
|
const conversationContent = turns.map((t) => t.content).join(" ");
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
log.warn("[threading] updateThreadTitle failed after persistence (non-fatal)", err);
|
|
1062
|
-
}
|
|
1160
|
+
await runPostPersistBestEffort("during_thread_title_update", () =>
|
|
1161
|
+
this.deps.getThreading().updateThreadTitle(threadIdForExtraction, conversationContent),
|
|
1162
|
+
);
|
|
1063
1163
|
}
|
|
1064
1164
|
|
|
1065
1165
|
// Check if consolidation is needed (debounced + non-zero gated).
|
|
@@ -1078,11 +1178,9 @@ export class ExtractionRunCoordinator {
|
|
|
1078
1178
|
log.warn("runExtraction: QMD maintenance scheduling failed after persistence (non-fatal)", err);
|
|
1079
1179
|
}
|
|
1080
1180
|
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
log.warn("runExtraction: tier migration failed after persistence (non-fatal)", err);
|
|
1085
|
-
}
|
|
1181
|
+
await runPostPersistBestEffort("during_tier_migration", () =>
|
|
1182
|
+
this.deps.runTierMigrationCycle(storage, "extraction"),
|
|
1183
|
+
);
|
|
1086
1184
|
|
|
1087
1185
|
return {
|
|
1088
1186
|
status: "completed",
|
|
@@ -1090,29 +1188,8 @@ export class ExtractionRunCoordinator {
|
|
|
1090
1188
|
durableOutputCount,
|
|
1091
1189
|
postPersistMetadataFailed,
|
|
1092
1190
|
};
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
/**
|
|
1097
|
-
* Derive a single `sourceConnector` from a batch of turns.
|
|
1098
|
-
* Returns the connector ONLY when ALL turns carry the same connector.
|
|
1099
|
-
* Mixed tagged/untagged batches return undefined — extraction facts are
|
|
1100
|
-
* persisted at batch level, so attributing them to the single tagged
|
|
1101
|
-
* connector would falsely label facts from untagged turns.
|
|
1102
|
-
* Conflicting connectors (different values) also return undefined.
|
|
1103
|
-
*/
|
|
1104
|
-
export function deriveSourceConnector(turns: readonly BufferTurn[]): string | undefined {
|
|
1105
|
-
if (turns.length === 0) return undefined;
|
|
1106
|
-
const connectors = new Set<string>();
|
|
1107
|
-
let untaggedCount = 0;
|
|
1108
|
-
for (const turn of turns) {
|
|
1109
|
-
if (typeof turn.sourceConnector === "string" && turn.sourceConnector.length > 0) {
|
|
1110
|
-
connectors.add(turn.sourceConnector);
|
|
1111
|
-
} else {
|
|
1112
|
-
untaggedCount += 1;
|
|
1191
|
+
} finally {
|
|
1192
|
+
clearExtractionDeadlineTimer();
|
|
1113
1193
|
}
|
|
1114
1194
|
}
|
|
1115
|
-
// All turns must agree on the same connector — no untagged turns mixed in.
|
|
1116
|
-
if (untaggedCount > 0) return undefined;
|
|
1117
|
-
return connectors.size === 1 ? [...connectors][0] : undefined;
|
|
1118
1195
|
}
|