@remnic/core 9.3.725 → 9.3.727
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/access-boundary.d.ts +5 -5
- package/dist/access-boundary.js +28 -27
- package/dist/access-cli.js +65 -63
- package/dist/access-cli.js.map +1 -1
- package/dist/access-http.d.ts +20 -5
- package/dist/access-http.js +34 -33
- package/dist/access-mcp.d.ts +5 -5
- package/dist/access-mcp.js +31 -30
- package/dist/access-operations-batch.js +29 -28
- package/dist/access-operations.d.ts +5 -5
- package/dist/access-operations.js +30 -29
- package/dist/{access-service-B2PlPtxh.d.ts → access-service-Bgpjxo4f.d.ts} +36 -4
- package/dist/access-service.d.ts +5 -5
- package/dist/access-service.js +27 -26
- package/dist/access-surface-catalog.d.ts +5 -5
- package/dist/action-confidence.d.ts +1 -1
- package/dist/active-memory-bridge.d.ts +1 -1
- package/dist/active-recall.d.ts +1 -1
- package/dist/active-recall.js +3 -3
- package/dist/adapters/index.js +4 -4
- package/dist/adapters/registry.js +2 -2
- package/dist/behavior-learner.d.ts +1 -1
- package/dist/behavior-signals.d.ts +1 -1
- package/dist/bootstrap.d.ts +4 -4
- package/dist/briefing.d.ts +1 -1
- package/dist/briefing.js +9 -8
- package/dist/buffer-surprise-report.d.ts +1 -1
- package/dist/buffer.d.ts +1 -1
- package/dist/calibration.d.ts +1 -1
- package/dist/capabilities.d.ts +1 -1
- package/dist/{catalog-CzUb-GyD.d.ts → catalog-bMczlO2G.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 +10 -9
- package/dist/causal-consolidation.js.map +1 -1
- package/dist/causal-trajectory-graph.d.ts +1 -1
- package/dist/{chunk-KGZF2VO3.js → chunk-27QQC7ZX.js} +80 -19
- package/dist/{chunk-KGZF2VO3.js.map → chunk-27QQC7ZX.js.map} +1 -1
- package/dist/{chunk-HCVWF657.js → chunk-2KAYTPPT.js} +12 -12
- package/dist/{chunk-4SF232E6.js → chunk-36SEDFAU.js} +19 -7
- package/dist/chunk-36SEDFAU.js.map +1 -0
- package/dist/{chunk-ZK2L72VN.js → chunk-37436GML.js} +2 -2
- package/dist/{chunk-SC2YAWRF.js → chunk-3TSTGI6F.js} +2 -2
- package/dist/{chunk-FACTVMXQ.js → chunk-4H4F3BFL.js} +2 -2
- package/dist/{chunk-WAFDHKES.js → chunk-4NOI577P.js} +2 -2
- package/dist/{chunk-YQMPUYHE.js → chunk-4NR2PDZ5.js} +2 -2
- package/dist/{chunk-TAPSNIMA.js → chunk-5CEJH5ZN.js} +4 -4
- package/dist/{chunk-FN6QP7JQ.js → chunk-6PY5YJAV.js} +100 -14
- package/dist/{chunk-FN6QP7JQ.js.map → chunk-6PY5YJAV.js.map} +1 -1
- package/dist/{chunk-PKMQK2WY.js → chunk-773DPI6T.js} +4 -4
- package/dist/{chunk-4R3CGCI5.js → chunk-7RLCCNHU.js} +15 -12
- package/dist/chunk-7RLCCNHU.js.map +1 -0
- package/dist/{chunk-XGTBNVIU.js → chunk-AAD2ZS6P.js} +11 -1
- package/dist/chunk-AAD2ZS6P.js.map +1 -0
- package/dist/{chunk-Z3FGC3QE.js → chunk-AQLOP5F4.js} +139 -30
- package/dist/chunk-AQLOP5F4.js.map +1 -0
- package/dist/{chunk-FXCIOLRB.js → chunk-ASKXIAHD.js} +2 -2
- package/dist/{chunk-5OPYYPJN.js → chunk-CBWI22JN.js} +2 -2
- package/dist/{chunk-ZOHMPFOB.js → chunk-CKFLLAIS.js} +3 -3
- package/dist/{chunk-GZQXOQQ2.js → chunk-CSRXQ6NB.js} +5 -5
- package/dist/{chunk-QR67FU5G.js → chunk-CTOQEZSN.js} +2 -2
- package/dist/{chunk-ZUDM75KG.js → chunk-DCWIQFNA.js} +4 -4
- package/dist/{chunk-6CWGS2LY.js → chunk-DKJCRGWM.js} +3 -3
- package/dist/{chunk-JJJCVCCQ.js → chunk-DMQWV6SQ.js} +2 -2
- package/dist/{chunk-F3XZN24Z.js → chunk-DRUDC2UX.js} +2 -2
- package/dist/{chunk-4WZ3J7M6.js → chunk-EY6MDMHK.js} +2 -2
- package/dist/{chunk-YNDLCWXS.js → chunk-EZ25VE3G.js} +4 -4
- package/dist/{chunk-C4X4QGIO.js → chunk-G6NKALRN.js} +5 -2
- package/dist/chunk-G6NKALRN.js.map +1 -0
- package/dist/{chunk-6SQQOJ4U.js → chunk-GKRLPHPU.js} +2 -2
- package/dist/{chunk-D7EBTQ24.js → chunk-HOHVIVDR.js} +2 -2
- package/dist/{chunk-RKNJBZ55.js → chunk-JBPKEARU.js} +4 -4
- package/dist/{chunk-UBHVAGO7.js → chunk-JYLFZWUX.js} +2 -2
- package/dist/{chunk-LD53WPMU.js → chunk-LQ6JI4VH.js} +4 -4
- package/dist/chunk-LTHVM4XN.js +109 -0
- package/dist/chunk-LTHVM4XN.js.map +1 -0
- package/dist/{chunk-WM7DNKBD.js → chunk-M4V2JVSZ.js} +2 -2
- package/dist/{chunk-I2HL5M6T.js → chunk-MJIHJ7OG.js} +52 -52
- package/dist/{chunk-J334N6QV.js → chunk-MLKWJOAJ.js} +2 -2
- package/dist/{chunk-C6BWLYW5.js → chunk-N3VNUM4Z.js} +171 -79
- package/dist/chunk-N3VNUM4Z.js.map +1 -0
- package/dist/{chunk-DF3I6JGP.js → chunk-NSA5ZRUL.js} +15 -15
- package/dist/{chunk-VI5SGGXB.js → chunk-OEEW4KJA.js} +4 -4
- package/dist/{chunk-7AG54AF3.js → chunk-PUR2CKX2.js} +1 -1
- package/dist/chunk-PUR2CKX2.js.map +1 -0
- package/dist/{chunk-NT36GU6X.js → chunk-R7IYU5DZ.js} +2 -2
- package/dist/{chunk-TT5U3UDO.js → chunk-SNKPUJHR.js} +4 -4
- package/dist/{chunk-T55EGZSJ.js → chunk-UVPL565C.js} +2 -2
- package/dist/chunk-W5H6ZRPT.js +14 -0
- package/dist/chunk-W5H6ZRPT.js.map +1 -0
- package/dist/{chunk-YQGHW5ML.js → chunk-WRFKZEO6.js} +4 -4
- package/dist/{chunk-KLFYKC3K.js → chunk-XPHVAOBT.js} +195 -74
- package/dist/chunk-XPHVAOBT.js.map +1 -0
- package/dist/{chunk-H7HUQIY7.js → chunk-Y4YD5TYW.js} +3 -3
- package/dist/{chunk-MDBZTH7N.js → chunk-YKBHOBJK.js} +44 -10
- package/dist/chunk-YKBHOBJK.js.map +1 -0
- package/dist/{chunk-YUYPWJD3.js → chunk-YOLZS7NY.js} +2 -2
- package/dist/{chunk-6OIDDKAA.js → chunk-YTU7WKYN.js} +35 -9
- package/dist/chunk-YTU7WKYN.js.map +1 -0
- package/dist/{cli-IOlDHSBT.d.ts → cli-BLME420h.d.ts} +3 -3
- package/dist/cli.d.ts +6 -6
- package/dist/cli.js +60 -59
- package/dist/compat/codex-cli-fallback.d.ts +1 -0
- package/dist/compat/codex-cli-fallback.js +22 -0
- package/dist/compat/codex-cli-fallback.js.map +1 -0
- package/dist/compat/codex-thread-key.d.ts +1 -0
- package/dist/compat/codex-thread-key.js +18 -0
- package/dist/compat/codex-thread-key.js.map +1 -0
- package/dist/compounding/engine.d.ts +1 -1
- package/dist/compounding/engine.js +9 -8
- 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 +3 -3
- package/dist/connectors/codex-materialize-runner.d.ts +1 -1
- package/dist/connectors/codex-materialize-runner.js +9 -8
- package/dist/connectors/codex-materialize.d.ts +1 -1
- package/dist/connectors/index.d.ts +1 -1
- package/dist/connectors/index.js +9 -8
- package/dist/consolidation-provenance-check.d.ts +1 -1
- package/dist/consolidation-undo.d.ts +1 -1
- package/dist/content-hash.d.ts +14 -0
- package/dist/content-hash.js +10 -0
- package/dist/content-hash.js.map +1 -0
- package/dist/contradiction/index.d.ts +1 -1
- 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/dashboard-runtime.js +2 -2
- 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 +1 -1
- package/dist/entity-retrieval.js +9 -8
- package/dist/entity-schema.d.ts +1 -1
- package/dist/explicit-capture.d.ts +4 -4
- package/dist/extraction-faithfulness.d.ts +1 -1
- package/dist/extraction-faithfulness.js +2 -2
- 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-redaction-rules.d.ts +33 -0
- package/dist/extraction-redaction-rules.js +14 -0
- package/dist/extraction-redaction-rules.js.map +1 -0
- package/dist/extraction.d.ts +1 -1
- package/dist/extraction.js +3 -3
- package/dist/faithfulness-config.d.ts +1 -0
- package/dist/faithfulness-config.js +1 -1
- package/dist/fallback-llm.d.ts +1 -1
- package/dist/{forget-OEE5OELK.js → forget-WYLR4ZFV.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/identity-continuity.d.ts +1 -1
- package/dist/importance.d.ts +1 -1
- package/dist/index.d.ts +9 -9
- package/dist/index.js +107 -105
- package/dist/index.js.map +1 -1
- package/dist/intent.d.ts +1 -1
- package/dist/lcm/engine.d.ts +1 -1
- package/dist/lcm/engine.js +2 -2
- package/dist/lcm/index.d.ts +1 -1
- package/dist/lcm/index.js +4 -4
- 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 +9 -4
- package/dist/local-model-endpoint.js +1 -1
- package/dist/maintenance/memory-governance.d.ts +1 -1
- package/dist/maintenance/memory-governance.js +9 -8
- package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +9 -8
- package/dist/maintenance/rebuild-memory-projection.js +10 -9
- package/dist/mcp-memory-inspector-app.d.ts +5 -5
- package/dist/memory-action-policy.d.ts +1 -1
- package/dist/memory-cache.d.ts +1 -1
- package/dist/memory-lifecycle-ledger-utils.d.ts +1 -1
- package/dist/memory-projection-store.d.ts +1 -1
- package/dist/memory-provenance.d.ts +1 -1
- package/dist/memory-worth-outcomes.d.ts +1 -1
- package/dist/models-json.d.ts +1 -1
- package/dist/namespaces/migrate.d.ts +2 -2
- package/dist/namespaces/migrate.js +19 -18
- 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 +2 -2
- package/dist/namespaces/storage.js +9 -8
- package/dist/native-knowledge.d.ts +1 -1
- package/dist/operator-toolkit.d.ts +1 -1
- package/dist/operator-toolkit.js +28 -27
- package/dist/orchestration/maintenance.d.ts +2 -2
- package/dist/orchestration/maintenance.js +11 -10
- package/dist/{orchestrator-C_OMSIMZ.d.ts → orchestrator-DqPAz8ot.d.ts} +3 -3
- package/dist/orchestrator.d.ts +4 -4
- package/dist/orchestrator.js +51 -49
- package/dist/patterns-cli.d.ts +1 -1
- package/dist/policy-runtime.d.ts +1 -1
- package/dist/provenance.d.ts +1 -1
- package/dist/provenance.js +1 -1
- package/dist/qmd-recall-cache.d.ts +1 -1
- package/dist/qmd.d.ts +1 -1
- package/dist/recall-disclosure-escalation.d.ts +1 -1
- package/dist/recall-explain-renderer.d.ts +1 -1
- package/dist/recall-explain-renderer.js +3 -3
- package/dist/recall-planner-llm.d.ts +1 -1
- package/dist/recall-state.d.ts +1 -1
- package/dist/recall-tag-filter.d.ts +1 -1
- package/dist/recall-xray-cli.d.ts +1 -1
- package/dist/recall-xray-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/resolve-auth-token.d.ts +1 -1
- package/dist/resume-bundles.js +4 -4
- package/dist/retrieval-agents.d.ts +1 -1
- package/dist/retrieval-tiers.d.ts +1 -1
- package/dist/routing/engine.d.ts +1 -1
- package/dist/routing/store.d.ts +1 -1
- package/dist/schemas.d.ts +22 -22
- 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 +14 -14
- package/dist/search/lancedb-backend.d.ts +1 -1
- package/dist/search/lancedb-backend.js +2 -2
- package/dist/search/meilisearch-backend.d.ts +1 -1
- package/dist/search/meilisearch-backend.js +2 -2
- package/dist/search/noop-backend.d.ts +1 -1
- package/dist/search/orama-backend.d.ts +1 -1
- package/dist/search/orama-backend.js +2 -2
- package/dist/search/port.d.ts +1 -1
- package/dist/search/remote-backend.d.ts +1 -1
- package/dist/{semantic-consolidation-B8LiYtvx.d.ts → semantic-consolidation-Cl15ksZy.d.ts} +1 -1
- package/dist/semantic-consolidation.d.ts +2 -2
- package/dist/semantic-consolidation.js +10 -9
- package/dist/semantic-rule-promotion.js +9 -8
- package/dist/semantic-rule-verifier.d.ts +1 -1
- package/dist/semantic-rule-verifier.js +9 -8
- 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.d.ts +3 -3
- package/dist/storage.js +9 -8
- package/dist/summarizer.d.ts +1 -1
- package/dist/summary-snapshot.d.ts +1 -1
- package/dist/temporal-supersession.d.ts +1 -1
- package/dist/temporal-validity.d.ts +1 -1
- package/dist/threading.d.ts +1 -1
- package/dist/tier-migration.d.ts +1 -1
- package/dist/tier-routing.d.ts +1 -1
- package/dist/topics.d.ts +1 -1
- package/dist/transcript.d.ts +1 -1
- package/dist/transfer/types.d.ts +12 -12
- package/dist/trust-score-stage.d.ts +1 -1
- package/dist/trust-score.d.ts +1 -1
- package/dist/{types-DmTaqob2.d.ts → types-ChQb9D6s.d.ts} +8 -0
- 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 +9 -8
- package/package.json +26 -2
- package/src/access-http.ts +68 -1
- package/src/admin/admin-surfaces.test.ts +289 -0
- package/src/admin/admin-surfaces.ts +138 -7
- package/src/bitemporal-dedup-backfill.test.ts +294 -0
- package/src/chat/chat-engine.test.ts +66 -1
- package/src/chat/chat-http.test.ts +119 -1
- package/src/chat/chat-http.ts +252 -97
- package/src/chat/chat-session.ts +143 -7
- package/src/compat/codex-cli-fallback.ts +23 -0
- package/src/compat/codex-subpath-aliases.test.ts +93 -0
- package/src/compat/codex-thread-key.ts +23 -0
- package/src/config.test.ts +50 -0
- package/src/config.ts +21 -4
- package/src/content-hash.ts +24 -0
- package/src/correction/correction-access-wiring.ts +104 -19
- package/src/correction/correction-contract.ts +68 -10
- package/src/correction/correction-executor.test.ts +112 -2
- package/src/correction/correction-executor.ts +65 -5
- package/src/correction/correction-planner.test.ts +47 -0
- package/src/correction/correction-planner.ts +40 -1
- package/src/correction/correction-storage-integration.test.ts +183 -0
- package/src/extraction-faithfulness.test.ts +240 -0
- package/src/extraction-faithfulness.ts +58 -6
- package/src/extraction-redaction-rules.test.ts +213 -0
- package/src/extraction-redaction-rules.ts +208 -0
- package/src/faithfulness-config.ts +16 -1
- package/src/local-model-endpoint.ts +24 -3
- package/src/orchestrator.ts +252 -9
- package/src/provenance-extraction.test.ts +266 -0
- package/src/provenance.ts +66 -16
- package/src/storage.ts +6 -10
- package/src/types.ts +8 -0
- package/dist/chunk-4R3CGCI5.js.map +0 -1
- package/dist/chunk-4SF232E6.js.map +0 -1
- package/dist/chunk-6OIDDKAA.js.map +0 -1
- package/dist/chunk-7AG54AF3.js.map +0 -1
- package/dist/chunk-C4X4QGIO.js.map +0 -1
- package/dist/chunk-C6BWLYW5.js.map +0 -1
- package/dist/chunk-KLFYKC3K.js.map +0 -1
- package/dist/chunk-MDBZTH7N.js.map +0 -1
- package/dist/chunk-XGTBNVIU.js.map +0 -1
- package/dist/chunk-Z3FGC3QE.js.map +0 -1
- /package/dist/{chunk-HCVWF657.js.map → chunk-2KAYTPPT.js.map} +0 -0
- /package/dist/{chunk-ZK2L72VN.js.map → chunk-37436GML.js.map} +0 -0
- /package/dist/{chunk-SC2YAWRF.js.map → chunk-3TSTGI6F.js.map} +0 -0
- /package/dist/{chunk-FACTVMXQ.js.map → chunk-4H4F3BFL.js.map} +0 -0
- /package/dist/{chunk-WAFDHKES.js.map → chunk-4NOI577P.js.map} +0 -0
- /package/dist/{chunk-YQMPUYHE.js.map → chunk-4NR2PDZ5.js.map} +0 -0
- /package/dist/{chunk-TAPSNIMA.js.map → chunk-5CEJH5ZN.js.map} +0 -0
- /package/dist/{chunk-PKMQK2WY.js.map → chunk-773DPI6T.js.map} +0 -0
- /package/dist/{chunk-FXCIOLRB.js.map → chunk-ASKXIAHD.js.map} +0 -0
- /package/dist/{chunk-5OPYYPJN.js.map → chunk-CBWI22JN.js.map} +0 -0
- /package/dist/{chunk-ZOHMPFOB.js.map → chunk-CKFLLAIS.js.map} +0 -0
- /package/dist/{chunk-GZQXOQQ2.js.map → chunk-CSRXQ6NB.js.map} +0 -0
- /package/dist/{chunk-QR67FU5G.js.map → chunk-CTOQEZSN.js.map} +0 -0
- /package/dist/{chunk-ZUDM75KG.js.map → chunk-DCWIQFNA.js.map} +0 -0
- /package/dist/{chunk-6CWGS2LY.js.map → chunk-DKJCRGWM.js.map} +0 -0
- /package/dist/{chunk-JJJCVCCQ.js.map → chunk-DMQWV6SQ.js.map} +0 -0
- /package/dist/{chunk-F3XZN24Z.js.map → chunk-DRUDC2UX.js.map} +0 -0
- /package/dist/{chunk-4WZ3J7M6.js.map → chunk-EY6MDMHK.js.map} +0 -0
- /package/dist/{chunk-YNDLCWXS.js.map → chunk-EZ25VE3G.js.map} +0 -0
- /package/dist/{chunk-6SQQOJ4U.js.map → chunk-GKRLPHPU.js.map} +0 -0
- /package/dist/{chunk-D7EBTQ24.js.map → chunk-HOHVIVDR.js.map} +0 -0
- /package/dist/{chunk-RKNJBZ55.js.map → chunk-JBPKEARU.js.map} +0 -0
- /package/dist/{chunk-UBHVAGO7.js.map → chunk-JYLFZWUX.js.map} +0 -0
- /package/dist/{chunk-LD53WPMU.js.map → chunk-LQ6JI4VH.js.map} +0 -0
- /package/dist/{chunk-WM7DNKBD.js.map → chunk-M4V2JVSZ.js.map} +0 -0
- /package/dist/{chunk-I2HL5M6T.js.map → chunk-MJIHJ7OG.js.map} +0 -0
- /package/dist/{chunk-J334N6QV.js.map → chunk-MLKWJOAJ.js.map} +0 -0
- /package/dist/{chunk-DF3I6JGP.js.map → chunk-NSA5ZRUL.js.map} +0 -0
- /package/dist/{chunk-VI5SGGXB.js.map → chunk-OEEW4KJA.js.map} +0 -0
- /package/dist/{chunk-NT36GU6X.js.map → chunk-R7IYU5DZ.js.map} +0 -0
- /package/dist/{chunk-TT5U3UDO.js.map → chunk-SNKPUJHR.js.map} +0 -0
- /package/dist/{chunk-T55EGZSJ.js.map → chunk-UVPL565C.js.map} +0 -0
- /package/dist/{chunk-YQGHW5ML.js.map → chunk-WRFKZEO6.js.map} +0 -0
- /package/dist/{chunk-H7HUQIY7.js.map → chunk-Y4YD5TYW.js.map} +0 -0
- /package/dist/{chunk-YUYPWJD3.js.map → chunk-YOLZS7NY.js.map} +0 -0
- /package/dist/{forget-OEE5OELK.js.map → forget-WYLR4ZFV.js.map} +0 -0
|
@@ -15,6 +15,15 @@ async function callOpenAiCompatibleChat(endpoint, messages, options, fetchImpl =
|
|
|
15
15
|
const url = joinBaseUrl(endpoint.baseUrl, "/chat/completions");
|
|
16
16
|
const controller = new AbortController();
|
|
17
17
|
const timer = setTimeout(() => controller.abort(), options.timeoutMs);
|
|
18
|
+
const batchSignal = options.signal;
|
|
19
|
+
const onBatchAbort = () => controller.abort();
|
|
20
|
+
if (batchSignal) {
|
|
21
|
+
if (batchSignal.aborted) {
|
|
22
|
+
controller.abort();
|
|
23
|
+
} else {
|
|
24
|
+
batchSignal.addEventListener("abort", onBatchAbort, { once: true });
|
|
25
|
+
}
|
|
26
|
+
}
|
|
18
27
|
try {
|
|
19
28
|
const body = {
|
|
20
29
|
model: endpoint.model,
|
|
@@ -45,6 +54,7 @@ async function callOpenAiCompatibleChat(endpoint, messages, options, fetchImpl =
|
|
|
45
54
|
return { content, modelUsed: extractModel(parsed) ?? endpoint.model };
|
|
46
55
|
} finally {
|
|
47
56
|
clearTimeout(timer);
|
|
57
|
+
if (batchSignal) batchSignal.removeEventListener("abort", onBatchAbort);
|
|
48
58
|
}
|
|
49
59
|
}
|
|
50
60
|
function joinBaseUrl(base, path) {
|
|
@@ -76,4 +86,4 @@ export {
|
|
|
76
86
|
resolveCorrectionIntentEndpoint,
|
|
77
87
|
callOpenAiCompatibleChat
|
|
78
88
|
};
|
|
79
|
-
//# sourceMappingURL=chunk-
|
|
89
|
+
//# sourceMappingURL=chunk-AAD2ZS6P.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/local-model-endpoint.ts"],"sourcesContent":["/**\n * Local fine-tuned model endpoint resolver + openai-compatible caller\n * (issue #1585 model-lab integration).\n *\n * Remnic's two classification workloads — the extraction faithfulness gate\n * (#1576) and passive-correction intent detection (#1581) — can run on small\n * fine-tuned models served locally (Ollama / vLLM) instead of prompted\n * frontier LLMs. The model-lab (`model-lab/`) produces those models; this\n * module is the config-side half: it resolves the optional local endpoint\n * pointer from config and, when set, makes a minimal openai-compatible\n * chat-completions call to it.\n *\n * Design:\n * - **Pointers are optional.** Empty defaults preserve the existing routing\n * chain exactly (rule 39 / byte-identical pre-feature). A resolver returns\n * `null` when the pointer is unset, so callers short-circuit before any\n * network.\n * - **Graceful degradation.** A local-endpoint failure (network, non-2xx,\n * malformed body, timeout) returns `null`; callers fall back to the\n * configured chain (checklist §4 — never block writes on a classifier).\n * - **No inline casts.** The fetch JSON is narrowed with `in` / `typeof`\n * guards (project rule: never assert a shape to read one property).\n * - **Injectable fetch.** `callOpenAiCompatibleChat` takes an optional\n * `fetchImpl` so the caller is unit-testable without a live server.\n */\n\nimport type { PluginConfig } from \"./types.js\";\n\n/** A resolved local endpoint: where to call + which model to name. */\nexport interface LocalModelEndpoint {\n /** Base URL, e.g. `http://localhost:11434/v1` (no trailing slash required). */\n baseUrl: string;\n /** Model name the server expects, e.g. `remnic-faithfulness-gate-v1`. */\n model: string;\n}\n\n/** A chat message in the openai-compatible shape this caller sends. */\nexport interface EndpointChatMessage {\n role: \"system\" | \"user\" | \"assistant\";\n content: string;\n}\n\n/** Options for a single local-endpoint chat call. */\nexport interface EndpointChatOptions {\n /** Per-call timeout in ms. Bounds each attempt so one slow server can't\n * starve the batch (matches the local-LLM precedent). */\n timeoutMs: number;\n /** Optional batch AbortSignal forwarded into the probe (issue #1700 nit #5).\n * When the batch budget elapses (or the caller aborts), the in-flight probe\n * aborts immediately instead of waiting for its own `timeoutMs` — a\n * micro-optimization, not a correctness fix (the outer race already bounds\n * the total). Undefined preserves the prior per-attempt-only behavior. */\n signal?: AbortSignal;\n /** Sampling temperature — classification wants low entropy (0.0–0.2). */\n temperature?: number;\n /** Max output tokens. */\n maxTokens?: number;\n /** Request JSON-object output (the gate emits a JSON verdict array). */\n responseFormatJson?: boolean;\n}\n\n/** Result of a local-endpoint chat call. */\nexport interface EndpointChatResult {\n content: string;\n /** The model the server reports it used (falls back to the requested name). */\n modelUsed: string;\n}\n\n/**\n * Resolve the faithfulness-gate local endpoint from config (issue #1585).\n *\n * Returns the endpoint only when BOTH a base URL and a model name are\n * configured; otherwise `null` (gate uses its existing routing chain). The\n * gate's verifier needs a model identity, so a base URL alone is intentionally\n * insufficient — silently calling whatever the server's default model is would\n * be an unreviewed behavioral change.\n */\nexport function resolveFaithfulnessGateEndpoint(\n config: Pick<PluginConfig, \"extractionFaithfulnessModel\" | \"extractionFaithfulnessBaseUrl\">,\n): LocalModelEndpoint | null {\n const baseUrl = config.extractionFaithfulnessBaseUrl.trim();\n const model = config.extractionFaithfulnessModel.trim();\n if (!baseUrl || !model) return null;\n return { baseUrl, model };\n}\n\n/**\n * Resolve the correction-intent local endpoint from config (issue #1581/#1585).\n *\n * Same contract as the gate resolver. Consumption by the model-backed\n * detector is the consuming child's job — the rule-based\n * `detectPassiveCorrections` remains the default path; this pointer lets a\n * future model-backed detector route to a fine-tuned local classifier when an\n * operator configures one.\n */\nexport function resolveCorrectionIntentEndpoint(\n config: Pick<PluginConfig, \"correctionIntentModel\" | \"correctionIntentBaseUrl\">,\n): LocalModelEndpoint | null {\n const baseUrl = config.correctionIntentBaseUrl.trim();\n const model = config.correctionIntentModel.trim();\n if (!baseUrl || !model) return null;\n return { baseUrl, model };\n}\n\ntype FetchLike = typeof fetch;\n\n/**\n * Make an openai-compatible chat-completions call to a local endpoint.\n *\n * POSTs to `${baseUrl}/chat/completions` with `{ model, messages, ... }` and\n * returns the first choice's content. Any failure (non-2xx, network error,\n * malformed body, timeout) returns `null` so callers fall back gracefully.\n *\n * The response is narrowed with runtime guards — never an unchecked cast — so\n * a surprising server response fails closed (`null`) rather than reading a\n * fabricated field.\n */\nexport async function callOpenAiCompatibleChat(\n endpoint: LocalModelEndpoint,\n messages: EndpointChatMessage[],\n options: EndpointChatOptions,\n fetchImpl: FetchLike = fetch,\n): Promise<EndpointChatResult | null> {\n const url = joinBaseUrl(endpoint.baseUrl, \"/chat/completions\");\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), options.timeoutMs);\n // Forward the batch AbortSignal into the probe (issue #1700 nit #5): if the\n // batch budget already elapsed, abort the in-flight probe immediately rather\n // than waiting for the probe's own timeoutMs. AbortSignal.any is ES2024\n // (forbidden here); wire the listener manually + guard the already-aborted\n // case. The fetch still uses the probe's controller, so clearing the timer\n // below is the only cleanup needed.\n const batchSignal = options.signal;\n const onBatchAbort = () => controller.abort();\n if (batchSignal) {\n if (batchSignal.aborted) {\n controller.abort();\n } else {\n batchSignal.addEventListener(\"abort\", onBatchAbort, { once: true });\n }\n }\n try {\n const body: Record<string, unknown> = {\n model: endpoint.model,\n messages,\n temperature: options.temperature ?? 0.1,\n };\n if (typeof options.maxTokens === \"number\") {\n body.max_tokens = options.maxTokens;\n }\n if (options.responseFormatJson) {\n body.response_format = { type: \"json_object\" };\n }\n let response: Response;\n try {\n response = await fetchImpl(url, {\n method: \"POST\",\n headers: { \"content-type\": \"application/json\" },\n body: JSON.stringify(body),\n signal: controller.signal,\n });\n } catch {\n // Network error or abort — fail closed, let the caller fall back.\n return null;\n }\n if (!response.ok) return null;\n const parsed: unknown = await response.json().catch(() => null);\n const content = extractFirstChoiceContent(parsed);\n if (content === null) return null;\n return { content, modelUsed: extractModel(parsed) ?? endpoint.model };\n } finally {\n clearTimeout(timer);\n if (batchSignal) batchSignal.removeEventListener(\"abort\", onBatchAbort);\n }\n}\n\n/** Join a base URL and a path, tolerating a trailing slash on the base. */\nfunction joinBaseUrl(base: string, path: string): string {\n return base.endsWith(\"/\") ? `${base.slice(0, -1)}${path}` : `${base}${path}`;\n}\n\n/**\n * Narrow the openai-compatible response and pull the first choice's content.\n *\n * `in` / `typeof` guards only — no `as` cast (project rule). Returns `null`\n * for any shape that isn't `{ choices: [{ message: { content: string } }, …] }`.\n */\nfunction extractFirstChoiceContent(data: unknown): string | null {\n if (!data || typeof data !== \"object\") return null;\n // After `in`, TS narrows the property to `unknown` — read it directly, no cast.\n if (!(\"choices\" in data) || !Array.isArray(data.choices)) return null;\n const choices: unknown[] = data.choices;\n for (const choice of choices) {\n if (!choice || typeof choice !== \"object\") continue;\n if (!(\"message\" in choice)) continue;\n const message = choice.message;\n if (!message || typeof message !== \"object\") continue;\n if (!(\"content\" in message)) continue;\n const content = message.content;\n if (typeof content === \"string\" && content.length > 0) return content;\n }\n return null;\n}\n\n/** Narrow the `model` field from the response (best-effort, may be absent). */\nfunction extractModel(data: unknown): string | null {\n if (!data || typeof data !== \"object\" || !(\"model\" in data)) return null;\n const model = data.model;\n return typeof model === \"string\" && model.length > 0 ? model : null;\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1,12 +1,21 @@
|
|
|
1
1
|
import {
|
|
2
2
|
enqueuePassiveCorrectionNotification
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-EY6MDMHK.js";
|
|
4
4
|
import {
|
|
5
5
|
stripAttributesSuffix
|
|
6
6
|
} from "./chunk-SVOZFLIQ.js";
|
|
7
7
|
import {
|
|
8
8
|
serializeMutations
|
|
9
9
|
} from "./chunk-LTJAMRGI.js";
|
|
10
|
+
import {
|
|
11
|
+
supersessionKeysForFact
|
|
12
|
+
} from "./chunk-TKZ3AL5V.js";
|
|
13
|
+
import {
|
|
14
|
+
computeContentHash
|
|
15
|
+
} from "./chunk-W5H6ZRPT.js";
|
|
16
|
+
import {
|
|
17
|
+
sanitizeMemoryContent
|
|
18
|
+
} from "./chunk-5GKPFL3S.js";
|
|
10
19
|
import {
|
|
11
20
|
log
|
|
12
21
|
} from "./chunk-NU3CSQ4H.js";
|
|
@@ -79,22 +88,68 @@ function validateRedactionPattern(pattern) {
|
|
|
79
88
|
`redaction_rule.pattern exceeds the ${REDACTION_PATTERN_MAX}-character bound.`
|
|
80
89
|
);
|
|
81
90
|
}
|
|
82
|
-
if (isRegexLike(trimmed) &&
|
|
91
|
+
if (isRegexLike(trimmed) && isUnsafeRedactionRegex(trimmed)) {
|
|
83
92
|
throw new CorrectionContractError(
|
|
84
|
-
"redaction_rule.pattern is
|
|
93
|
+
"redaction_rule.pattern is unsafe \u2014 use a bounded literal or a regex without nested quantifiers / overlapping alternation."
|
|
85
94
|
);
|
|
86
95
|
}
|
|
96
|
+
if (isRegexLike(trimmed)) {
|
|
97
|
+
const regexBody = trimmed.slice(1, -1);
|
|
98
|
+
if (regexBody.length === 0) {
|
|
99
|
+
throw new CorrectionContractError("redaction_rule.pattern body is empty \u2014 use a non-empty regex.");
|
|
100
|
+
}
|
|
101
|
+
try {
|
|
102
|
+
if (new RegExp(regexBody).test("")) {
|
|
103
|
+
throw new CorrectionContractError(
|
|
104
|
+
"redaction_rule.pattern matches the empty string \u2014 it would withhold every fact."
|
|
105
|
+
);
|
|
106
|
+
}
|
|
107
|
+
} catch (e) {
|
|
108
|
+
if (e instanceof CorrectionContractError) throw e;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
87
111
|
return trimmed;
|
|
88
112
|
}
|
|
89
113
|
function isRegexLike(pattern) {
|
|
90
|
-
|
|
91
|
-
return /[\\^$.|?*+()[\]{}]/.test(pattern);
|
|
114
|
+
return pattern.startsWith("/") && pattern.endsWith("/") && pattern.length >= 2;
|
|
92
115
|
}
|
|
93
|
-
function
|
|
116
|
+
function isUnsafeRedactionRegex(pattern) {
|
|
94
117
|
const body = pattern.startsWith("/") && pattern.endsWith("/") ? pattern.slice(1, -1) : pattern;
|
|
95
118
|
if (/(?:^|[^\\])\(\.\*\)|(?:^|[^\\])\.\*|(?:^|[^\\])\.\+|^\.([^*+]?)$/.test(body)) {
|
|
96
119
|
return true;
|
|
97
120
|
}
|
|
121
|
+
if (body.length > 512) return true;
|
|
122
|
+
for (let i = 0; i < body.length; i++) {
|
|
123
|
+
if (body[i] !== "(") continue;
|
|
124
|
+
let depth = 1;
|
|
125
|
+
let j = i + 1;
|
|
126
|
+
while (j < body.length && depth > 0) {
|
|
127
|
+
if (body[j] === "\\") {
|
|
128
|
+
j += 2;
|
|
129
|
+
continue;
|
|
130
|
+
}
|
|
131
|
+
if (body[j] === "(") depth++;
|
|
132
|
+
else if (body[j] === ")") depth--;
|
|
133
|
+
j++;
|
|
134
|
+
}
|
|
135
|
+
if (depth !== 0) continue;
|
|
136
|
+
const afterGroup = body[j];
|
|
137
|
+
if (afterGroup !== "+" && afterGroup !== "*" && afterGroup !== "{") continue;
|
|
138
|
+
const groupBody = body.slice(i + 1, j - 1);
|
|
139
|
+
if (/[+*?]$/.test(groupBody) || /\{\d+,?\d*\}[+*?]?$/.test(groupBody)) {
|
|
140
|
+
return true;
|
|
141
|
+
}
|
|
142
|
+
if (groupBody.includes("|")) {
|
|
143
|
+
const branches = groupBody.split("|");
|
|
144
|
+
if (branches.length >= 2) {
|
|
145
|
+
const firstChars = new Set(branches.map((b) => b[0]).filter(Boolean));
|
|
146
|
+
if (firstChars.size < branches.filter((b) => b.length > 0).length) {
|
|
147
|
+
return true;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
i = j;
|
|
152
|
+
}
|
|
98
153
|
return false;
|
|
99
154
|
}
|
|
100
155
|
function validateCorrectionAction(action) {
|
|
@@ -198,11 +253,13 @@ var CorrectionContractError = class extends Error {
|
|
|
198
253
|
|
|
199
254
|
// src/correction/correction-access-wiring.ts
|
|
200
255
|
import path2 from "path";
|
|
256
|
+
import { createHash } from "crypto";
|
|
201
257
|
import { mkdir as mkdir2, writeFile as writeFile2 } from "fs/promises";
|
|
202
258
|
|
|
203
259
|
// src/correction/correction-planner.ts
|
|
204
260
|
import { mkdir, readFile, rename, unlink, readdir, writeFile } from "fs/promises";
|
|
205
261
|
import path from "path";
|
|
262
|
+
var REDACTED_REQUEST_TEXT = "[redacted \u2014 never-store/redaction correction text withheld from the pending-plan file]";
|
|
206
263
|
var CorrectionPlanner = class {
|
|
207
264
|
constructor(deps) {
|
|
208
265
|
this.deps = deps;
|
|
@@ -386,10 +443,12 @@ var CorrectionPlanner = class {
|
|
|
386
443
|
async persist(plan) {
|
|
387
444
|
const dir = await this.pendingDir(plan.namespace);
|
|
388
445
|
const target = path.join(dir, `${plan.planId}.json`);
|
|
446
|
+
const sensitive = plan.classification === "never_store" || plan.actions.some((a) => a.kind === "redaction_rule");
|
|
447
|
+
const persistedPlan = sensitive ? { ...plan, request: { ...plan.request, text: REDACTED_REQUEST_TEXT } } : plan;
|
|
389
448
|
await serializeMutations(`correction-plan:${target}`, async () => {
|
|
390
449
|
await mkdir(dir, { recursive: true });
|
|
391
450
|
const tmp = `${target}.${process.pid}.${Date.now().toString(36)}.tmp`;
|
|
392
|
-
await writeFile(tmp, `${JSON.stringify(
|
|
451
|
+
await writeFile(tmp, `${JSON.stringify(persistedPlan)}
|
|
393
452
|
`, "utf-8");
|
|
394
453
|
await rename(tmp, target);
|
|
395
454
|
});
|
|
@@ -451,6 +510,11 @@ var CorrectionPlanner = class {
|
|
|
451
510
|
const plan = parsePlan(raw);
|
|
452
511
|
if (!plan) return;
|
|
453
512
|
plan.status = status;
|
|
513
|
+
if (status !== "applying") {
|
|
514
|
+
plan.actions = plan.actions.map(
|
|
515
|
+
(a) => a.kind === "redaction_rule" ? { ...a, pattern: "[redacted \u2014 pattern applied]" } : a
|
|
516
|
+
);
|
|
517
|
+
}
|
|
454
518
|
const tmp = `${file}.${process.pid}.${Date.now().toString(36)}.tmp`;
|
|
455
519
|
await writeFile(tmp, `${JSON.stringify(plan)}
|
|
456
520
|
`, "utf-8");
|
|
@@ -652,7 +716,7 @@ var CorrectionExecutor = class {
|
|
|
652
716
|
continue;
|
|
653
717
|
}
|
|
654
718
|
const destId = await this.deps.rescopeMemory(namespace, action.memoryId, action.toNamespace);
|
|
655
|
-
results.push({ action, status: "applied", memoryId:
|
|
719
|
+
results.push({ action, status: "applied", memoryId: destId });
|
|
656
720
|
appliedTouched.push(action.memoryId);
|
|
657
721
|
try {
|
|
658
722
|
await this.deps.propagate(action.toNamespace, [destId]);
|
|
@@ -726,7 +790,14 @@ var CorrectionExecutor = class {
|
|
|
726
790
|
sourceMemoryId: memoryId,
|
|
727
791
|
rawContent: memory.rawContent,
|
|
728
792
|
...memory.entityRef ? { entityRef: memory.entityRef } : {},
|
|
729
|
-
...memory.supersessionKey ? { supersessionKey: memory.supersessionKey } : {}
|
|
793
|
+
...memory.supersessionKey ? { supersessionKey: memory.supersessionKey } : {},
|
|
794
|
+
// #1672 item 4: carry the canonical contentHash (exact tier) and the
|
|
795
|
+
// full supersession-key set (keyed tier) so paraphrased re-observations
|
|
796
|
+
// of the same supersession identity are blocked, not just the literal
|
|
797
|
+
// body. Without these the tombstone projected from a structured fact
|
|
798
|
+
// dropped both fields and the fact could resurrect.
|
|
799
|
+
...memory.contentHash ? { contentHash: memory.contentHash } : {},
|
|
800
|
+
...memory.supersessionKeys && memory.supersessionKeys.length > 0 ? { supersessionKeys: memory.supersessionKeys } : {}
|
|
730
801
|
});
|
|
731
802
|
await this.deps.retireMemory(namespace, memoryId, {
|
|
732
803
|
status: reason === "supersession" ? "superseded" : "retracted",
|
|
@@ -745,9 +816,15 @@ var CorrectionExecutor = class {
|
|
|
745
816
|
}
|
|
746
817
|
}
|
|
747
818
|
};
|
|
819
|
+
var CORRECTION_ERROR_MAX = 500;
|
|
820
|
+
function sanitizeErrorMessage(raw) {
|
|
821
|
+
const stripped = raw.replace(/(^|[\s:'"(])\/(?:[^\s'">)\\]+\/)+[^\s'">)\\]*/g, "$1<path>").replace(/(^|[\s:'"(])[A-Za-z]:\\[^\s'">)\\]+(?:\\[^\s'">) ]*)*/g, "$1<path>");
|
|
822
|
+
const trimmed = stripped.trim();
|
|
823
|
+
return trimmed.length > CORRECTION_ERROR_MAX ? `${trimmed.slice(0, CORRECTION_ERROR_MAX)}\u2026` : trimmed;
|
|
824
|
+
}
|
|
748
825
|
function errMsg(err) {
|
|
749
|
-
|
|
750
|
-
return
|
|
826
|
+
const raw = err instanceof Error ? err.message : String(err);
|
|
827
|
+
return sanitizeErrorMessage(raw);
|
|
751
828
|
}
|
|
752
829
|
|
|
753
830
|
// src/correction/correction-service.ts
|
|
@@ -868,7 +945,7 @@ async function searchMemories(wiring, text, namespaces, limit) {
|
|
|
868
945
|
const storage = await wiring.orchestrator.getStorage(ns);
|
|
869
946
|
const all = await storage.readAllMemories();
|
|
870
947
|
for (const m of all) {
|
|
871
|
-
if (m
|
|
948
|
+
if (!isEligibleCorrectionCandidate(m)) continue;
|
|
872
949
|
const hay = `${m.content} ${m.frontmatter.tags?.join(" ") ?? ""}`.toLowerCase();
|
|
873
950
|
let hits = 0;
|
|
874
951
|
for (const tok of tokens) {
|
|
@@ -1016,7 +1093,7 @@ async function expandEntityNeighbors(wiring, seedIds, namespaces, limit) {
|
|
|
1016
1093
|
for (const m of all) {
|
|
1017
1094
|
if (out.length >= limit) break;
|
|
1018
1095
|
if (seen.has(m.frontmatter.id)) continue;
|
|
1019
|
-
if (m
|
|
1096
|
+
if (!isEligibleCorrectionCandidate(m)) continue;
|
|
1020
1097
|
if (m.frontmatter.entityRef && seedRefs.has(m.frontmatter.entityRef)) {
|
|
1021
1098
|
out.push(toCandidate(m, ns, 0.5));
|
|
1022
1099
|
seen.add(m.frontmatter.id);
|
|
@@ -1107,9 +1184,13 @@ async function applyEditMemory(wiring, namespace, memoryId, patch) {
|
|
|
1107
1184
|
const storage = await wiring.orchestrator.getStorage(namespace);
|
|
1108
1185
|
const existing = await storage.getMemoryById(memoryId);
|
|
1109
1186
|
if (!existing) throw new CorrectionContractError(`memory not found for edit: ${memoryId}`);
|
|
1187
|
+
const contentHashForPatch = existing.frontmatter.category === "fact" ? computeContentHash(sanitizeMemoryContent(patch).text) : void 0;
|
|
1110
1188
|
await storage.writeMemoryFrontmatter(
|
|
1111
1189
|
{ ...existing, content: patch },
|
|
1112
|
-
{
|
|
1190
|
+
{
|
|
1191
|
+
updated: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1192
|
+
...contentHashForPatch ? { contentHash: contentHashForPatch } : {}
|
|
1193
|
+
}
|
|
1113
1194
|
);
|
|
1114
1195
|
return memoryId;
|
|
1115
1196
|
}
|
|
@@ -1173,26 +1254,42 @@ async function rescopeMemoryFn(wiring, namespace, memoryId, toNamespace) {
|
|
|
1173
1254
|
async function appendTombstoneFn(wiring, namespace, input) {
|
|
1174
1255
|
const storage = await wiring.orchestrator.getStorage(namespace);
|
|
1175
1256
|
const enabled = typeof storage.isTombstonesEnabled === "function" ? storage.isTombstonesEnabled() : true;
|
|
1176
|
-
const
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1257
|
+
const keys = input.supersessionKeys && input.supersessionKeys.length > 0 ? input.supersessionKeys : input.supersessionKey ? [input.supersessionKey] : [void 0];
|
|
1258
|
+
const writtenIds = [];
|
|
1259
|
+
let firstId = null;
|
|
1260
|
+
for (const key of keys) {
|
|
1261
|
+
const result = await storage.appendTombstone({
|
|
1262
|
+
reason: input.reason,
|
|
1263
|
+
createdBy: "user_correction",
|
|
1264
|
+
sourceMemoryId: input.sourceMemoryId,
|
|
1265
|
+
rawContent: input.rawContent,
|
|
1266
|
+
...input.entityRef ? { entityRef: input.entityRef } : {},
|
|
1267
|
+
...key ? { supersessionKey: key } : {},
|
|
1268
|
+
...input.contentHash ? { contentHash: input.contentHash } : {}
|
|
1269
|
+
});
|
|
1270
|
+
if (result === null && enabled) {
|
|
1271
|
+
for (const id of writtenIds) {
|
|
1272
|
+
try {
|
|
1273
|
+
await storage.revokeTombstone(id, "user_correction");
|
|
1274
|
+
} catch {
|
|
1275
|
+
}
|
|
1276
|
+
}
|
|
1277
|
+
throw new CorrectionContractError(
|
|
1278
|
+
`tombstone persistence failed for memory ${input.sourceMemoryId} (tombstones enabled but store returned null \u2014 I/O error swallowed)`
|
|
1279
|
+
);
|
|
1280
|
+
}
|
|
1281
|
+
if (firstId === null) firstId = result;
|
|
1282
|
+
if (result) writtenIds.push(result);
|
|
1188
1283
|
}
|
|
1189
|
-
return
|
|
1284
|
+
return firstId;
|
|
1190
1285
|
}
|
|
1191
1286
|
async function registerRedactionRuleFn(wiring, namespace, pattern) {
|
|
1192
1287
|
const storage = await wiring.orchestrator.getStorage(namespace);
|
|
1193
1288
|
const dir = path2.join(storage.dir, "state", "corrections", "redaction-rules");
|
|
1194
1289
|
await mkdir2(dir, { recursive: true });
|
|
1195
|
-
const
|
|
1290
|
+
const slugBase = pattern.replace(/[^a-zA-Z0-9]+/g, "-").slice(0, 48) || "rule";
|
|
1291
|
+
const patternHash = createHash("sha256").update(pattern).digest("hex").slice(0, 16);
|
|
1292
|
+
const slug = `${slugBase}-${patternHash}`;
|
|
1196
1293
|
await writeFile2(
|
|
1197
1294
|
path2.join(dir, `${slug}.json`),
|
|
1198
1295
|
`${JSON.stringify({ pattern, namespace, createdAt: (/* @__PURE__ */ new Date()).toISOString() })}
|
|
@@ -1252,15 +1349,27 @@ function toCandidate(m, namespace, score) {
|
|
|
1252
1349
|
// candidate for diff rendering if needed.
|
|
1253
1350
|
};
|
|
1254
1351
|
}
|
|
1352
|
+
function isEligibleCorrectionCandidate(m) {
|
|
1353
|
+
if (m.frontmatter.status && m.frontmatter.status !== "active") return false;
|
|
1354
|
+
if (typeof m.frontmatter.archivedAt === "string" && m.frontmatter.archivedAt.length > 0) return false;
|
|
1355
|
+
return true;
|
|
1356
|
+
}
|
|
1255
1357
|
function toExecutorMemory(m) {
|
|
1256
1358
|
const fm = m.frontmatter;
|
|
1257
1359
|
const rawBody = fm.structuredAttributes ? stripAttributesSuffix(m.content) : m.content;
|
|
1360
|
+
const supersessionKeys = supersessionKeysForFact({
|
|
1361
|
+
entityRef: fm.entityRef,
|
|
1362
|
+
structuredAttributes: fm.structuredAttributes
|
|
1363
|
+
});
|
|
1258
1364
|
return {
|
|
1259
1365
|
memoryId: fm.id,
|
|
1260
1366
|
content: m.content,
|
|
1261
1367
|
category: fm.category,
|
|
1262
1368
|
rawContent: rawBody,
|
|
1263
|
-
...fm.entityRef ? { entityRef: fm.entityRef } : {}
|
|
1369
|
+
...fm.entityRef ? { entityRef: fm.entityRef } : {},
|
|
1370
|
+
...supersessionKeys.length > 0 ? { supersessionKeys } : {},
|
|
1371
|
+
...supersessionKeys.length > 0 ? { supersessionKey: supersessionKeys[0] } : {},
|
|
1372
|
+
...typeof fm.contentHash === "string" && fm.contentHash.length > 0 ? { contentHash: fm.contentHash } : {}
|
|
1264
1373
|
};
|
|
1265
1374
|
}
|
|
1266
1375
|
function isCorrectionFeatureEnabled(config) {
|
|
@@ -1685,4 +1794,4 @@ export {
|
|
|
1685
1794
|
capturePassiveCorrections,
|
|
1686
1795
|
clusterByKey
|
|
1687
1796
|
};
|
|
1688
|
-
//# sourceMappingURL=chunk-
|
|
1797
|
+
//# sourceMappingURL=chunk-AQLOP5F4.js.map
|