@remnic/core 9.3.726 → 9.3.728
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 +22 -22
- package/dist/access-cli.js +45 -45
- package/dist/access-http.d.ts +20 -5
- package/dist/access-http.js +27 -27
- package/dist/access-mcp.d.ts +5 -5
- package/dist/access-mcp.js +26 -26
- package/dist/access-operations-batch.js +23 -23
- package/dist/access-operations.d.ts +6 -6
- package/dist/access-operations.js +25 -25
- package/dist/access-schema.d.ts +4 -4
- package/dist/access-schema.js +3 -3
- 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 +21 -21
- 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/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 +7 -7
- 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 +44 -2
- package/dist/capabilities.js +5 -3
- package/dist/{capsule-crypto-GWVG7LGC.js → capsule-crypto-7FJQINUR.js} +2 -2
- 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 +8 -8
- package/dist/causal-trajectory-graph.d.ts +1 -1
- package/dist/{chunk-OWHERGF2.js → chunk-2NLLXCJG.js} +2 -2
- package/dist/{chunk-BIA7ELIB.js → chunk-36SEDFAU.js} +3 -3
- package/dist/{chunk-UQSVUEN2.js → chunk-37436GML.js} +2 -2
- package/dist/{chunk-DVRHLN2O.js → chunk-3RCBIOOJ.js} +18 -2
- package/dist/{chunk-DVRHLN2O.js.map → chunk-3RCBIOOJ.js.map} +1 -1
- package/dist/{chunk-RRHHQYJS.js → chunk-3TSTGI6F.js} +2 -2
- package/dist/{chunk-5OOA7SGX.js → chunk-4ESAR77N.js} +2 -2
- package/dist/{chunk-FO3HO52S.js → chunk-4H4F3BFL.js} +2 -2
- package/dist/{chunk-BEUCACTV.js → chunk-4NOI577P.js} +2 -2
- package/dist/{chunk-BBIE7W52.js → chunk-4NR2PDZ5.js} +2 -2
- package/dist/{chunk-WGTWGDR5.js → chunk-76NHR6ZL.js} +5 -5
- package/dist/{chunk-PKMQK2WY.js → chunk-773DPI6T.js} +4 -4
- package/dist/{chunk-MQVKHFIU.js → chunk-7RLCCNHU.js} +8 -8
- package/dist/{chunk-XGTBNVIU.js → chunk-AAD2ZS6P.js} +11 -1
- package/dist/chunk-AAD2ZS6P.js.map +1 -0
- package/dist/{chunk-EZNDNMRH.js → chunk-AQLOP5F4.js} +2 -2
- package/dist/{chunk-UNNDFYUX.js → chunk-ARV3AUOM.js} +5 -5
- package/dist/{chunk-NPL7VDM6.js → chunk-ASKXIAHD.js} +2 -2
- package/dist/{chunk-TQQH2FTX.js → chunk-BQCHEV7O.js} +106 -15
- package/dist/{chunk-TQQH2FTX.js.map → chunk-BQCHEV7O.js.map} +1 -1
- package/dist/{chunk-ZA2S2VLL.js → chunk-C2PG7IEH.js} +5 -2
- package/dist/chunk-C2PG7IEH.js.map +1 -0
- package/dist/{chunk-K4ZNARDO.js → chunk-CBWI22JN.js} +2 -2
- package/dist/{chunk-ZOHMPFOB.js → chunk-CKFLLAIS.js} +3 -3
- package/dist/{chunk-JPUT5NGH.js → chunk-DMQWV6SQ.js} +2 -2
- package/dist/{chunk-F3XZN24Z.js → chunk-DRUDC2UX.js} +2 -2
- package/dist/{chunk-KJR66XOM.js → chunk-EY6MDMHK.js} +2 -2
- package/dist/{chunk-3TUT4PWB.js → chunk-FVZ2ISIX.js} +2 -2
- 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-PLG6JHQS.js → chunk-H5BWGCRZ.js} +43 -42
- package/dist/chunk-H5BWGCRZ.js.map +1 -0
- package/dist/{chunk-2NBP25BG.js → chunk-HGNOCPZX.js} +171 -79
- package/dist/chunk-HGNOCPZX.js.map +1 -0
- package/dist/{chunk-5NWYQUQC.js → chunk-HOHVIVDR.js} +2 -2
- package/dist/{chunk-DCKNMLEQ.js → chunk-I5REUWLH.js} +11 -5
- package/dist/chunk-I5REUWLH.js.map +1 -0
- package/dist/{chunk-6WAJQKBS.js → chunk-JYLFZWUX.js} +2 -2
- package/dist/{chunk-5W7CTZ2E.js → chunk-KQAFEZQX.js} +4 -4
- package/dist/{chunk-UKTDXTWX.js → chunk-M4AYVEWS.js} +7 -7
- package/dist/{chunk-YTZ3VGC7.js → chunk-M4V2JVSZ.js} +2 -2
- package/dist/{chunk-TA3Y6GEX.js → chunk-MLKWJOAJ.js} +2 -2
- package/dist/{chunk-DQXPJ6HD.js → chunk-O6YH5F47.js} +4 -4
- package/dist/{chunk-7AG54AF3.js → chunk-PUR2CKX2.js} +1 -1
- package/dist/chunk-PUR2CKX2.js.map +1 -0
- package/dist/{chunk-OAHOL3ZC.js → chunk-QNEUZIAH.js} +152 -62
- package/dist/chunk-QNEUZIAH.js.map +1 -0
- package/dist/{chunk-Q6D75LVH.js → chunk-UM5AWJNQ.js} +79 -17
- package/dist/chunk-UM5AWJNQ.js.map +1 -0
- package/dist/{chunk-53EEQYE5.js → chunk-UTHQPSRC.js} +8 -8
- package/dist/{chunk-BB57OZWC.js → chunk-UVPL565C.js} +2 -2
- package/dist/{chunk-6AFVIOVZ.js → chunk-V4GNSDFH.js} +2 -2
- package/dist/{chunk-EHISUJFN.js → chunk-WAS3NV46.js} +6 -3
- package/dist/chunk-WAS3NV46.js.map +1 -0
- package/dist/{chunk-UVYI6VIX.js → chunk-X7Y7WX73.js} +1 -1
- package/dist/{chunk-V7CMKMHM.js → chunk-Y4YD5TYW.js} +3 -3
- package/dist/{chunk-7NS7AWMZ.js → chunk-YGIQORJ3.js} +3 -3
- package/dist/{chunk-MDBZTH7N.js → chunk-YKBHOBJK.js} +44 -10
- package/dist/chunk-YKBHOBJK.js.map +1 -0
- package/dist/{chunk-3MS3QVX6.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 +49 -49
- 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 +7 -7
- 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 +7 -7
- package/dist/connectors/codex-materialize.d.ts +1 -1
- package/dist/connectors/index.d.ts +1 -1
- package/dist/connectors/index.js +7 -7
- package/dist/consolidation-provenance-check.d.ts +1 -1
- package/dist/consolidation-undo.d.ts +1 -1
- package/dist/contradiction/index.d.ts +1 -1
- package/dist/conversation-index/backend.d.ts +1 -1
- package/dist/conversation-index/chunker.d.ts +1 -1
- package/dist/conversation-index/faiss-adapter.d.ts +1 -1
- package/dist/conversation-index/indexer.d.ts +1 -1
- package/dist/conversation-index/search.d.ts +1 -1
- package/dist/day-summary.d.ts +1 -1
- package/dist/delinearize.d.ts +1 -1
- package/dist/direct-answer-wiring.d.ts +1 -1
- package/dist/direct-answer.d.ts +1 -1
- package/dist/embedding-fallback.d.ts +1 -1
- package/dist/embedding-fallback.js +2 -1
- package/dist/enrichment/index.d.ts +1 -1
- package/dist/entity-retrieval.d.ts +1 -1
- package/dist/entity-retrieval.js +7 -7
- 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.d.ts +1 -1
- package/dist/extraction.js +3 -2
- 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/{first-start-migration-PG5HBC3K.js → first-start-migration-22LPFHD5.js} +6 -2
- package/dist/first-start-migration-22LPFHD5.js.map +1 -0
- package/dist/graph-dashboard-diff.d.ts +1 -1
- package/dist/graph-dashboard-key.d.ts +1 -1
- package/dist/graph-dashboard-parser.d.ts +1 -1
- package/dist/graph-edge-reinforcement.d.ts +1 -1
- package/dist/graph-snapshot.d.ts +1 -1
- package/dist/graph.d.ts +1 -1
- package/dist/identity-continuity.d.ts +1 -1
- package/dist/importance.d.ts +1 -1
- package/dist/index.d.ts +9 -9
- package/dist/index.js +64 -64
- 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 +7 -7
- 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 +7 -7
- package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +7 -7
- package/dist/maintenance/rebuild-memory-projection.js +8 -8
- 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 +14 -13
- package/dist/namespaces/principal.d.ts +1 -1
- package/dist/namespaces/search.d.ts +1 -1
- package/dist/namespaces/search.js +6 -5
- package/dist/namespaces/storage.d.ts +2 -2
- package/dist/namespaces/storage.js +7 -7
- package/dist/native-knowledge.d.ts +1 -1
- package/dist/operator-toolkit.d.ts +1 -1
- package/dist/operator-toolkit.js +20 -20
- package/dist/orchestration/maintenance.d.ts +2 -2
- package/dist/orchestration/maintenance.js +9 -9
- package/dist/{orchestrator-C_OMSIMZ.d.ts → orchestrator-DqPAz8ot.d.ts} +3 -3
- package/dist/orchestrator.d.ts +4 -4
- package/dist/orchestrator.js +33 -33
- 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/search/embed-helper.d.ts +1 -1
- package/dist/search/embed-helper.js +2 -1
- package/dist/search/factory.d.ts +1 -1
- package/dist/search/factory.js +5 -4
- package/dist/search/index.d.ts +1 -1
- package/dist/search/index.js +9 -8
- 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-B8LiYtvx.d.ts → semantic-consolidation-Cl15ksZy.d.ts} +1 -1
- package/dist/semantic-consolidation.d.ts +2 -2
- package/dist/semantic-consolidation.js +8 -8
- package/dist/semantic-rule-promotion.js +7 -7
- package/dist/semantic-rule-verifier.d.ts +1 -1
- package/dist/semantic-rule-verifier.js +7 -7
- 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 +1 -1
- package/dist/storage.js +6 -6
- 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/backup.js +2 -2
- package/dist/transfer/capsule-export.js +2 -2
- package/dist/transfer/capsule-import.js +2 -2
- 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 +7 -7
- package/package.json +26 -2
- package/src/access-http.ts +68 -1
- package/src/access-service.ts +2 -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/capabilities.test.ts +155 -0
- package/src/capabilities.ts +91 -0
- package/src/chat/chat-engine.test.ts +104 -1
- package/src/chat/chat-http.test.ts +119 -1
- package/src/chat/chat-http.ts +252 -97
- package/src/chat/chat-session.ts +166 -7
- package/src/cli.ts +3 -2
- 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/embedding-fallback.ts +2 -1
- package/src/extraction-faithfulness.test.ts +240 -0
- package/src/extraction-faithfulness.ts +58 -6
- package/src/extraction.ts +7 -3
- package/src/faithfulness-config.ts +16 -1
- package/src/local-model-endpoint.ts +24 -3
- package/src/maintenance/first-start-migration.ts +3 -1
- package/src/orchestrator.ts +238 -34
- package/src/provenance-extraction.test.ts +266 -0
- package/src/provenance.ts +66 -16
- package/src/search/embed-helper.ts +3 -2
- package/src/types.ts +8 -0
- package/dist/chunk-2NBP25BG.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-DCKNMLEQ.js.map +0 -1
- package/dist/chunk-EHISUJFN.js.map +0 -1
- package/dist/chunk-MDBZTH7N.js.map +0 -1
- package/dist/chunk-OAHOL3ZC.js.map +0 -1
- package/dist/chunk-PLG6JHQS.js.map +0 -1
- package/dist/chunk-Q6D75LVH.js.map +0 -1
- package/dist/chunk-XGTBNVIU.js.map +0 -1
- package/dist/chunk-ZA2S2VLL.js.map +0 -1
- package/dist/first-start-migration-PG5HBC3K.js.map +0 -1
- /package/dist/{capsule-crypto-GWVG7LGC.js.map → capsule-crypto-7FJQINUR.js.map} +0 -0
- /package/dist/{chunk-OWHERGF2.js.map → chunk-2NLLXCJG.js.map} +0 -0
- /package/dist/{chunk-BIA7ELIB.js.map → chunk-36SEDFAU.js.map} +0 -0
- /package/dist/{chunk-UQSVUEN2.js.map → chunk-37436GML.js.map} +0 -0
- /package/dist/{chunk-RRHHQYJS.js.map → chunk-3TSTGI6F.js.map} +0 -0
- /package/dist/{chunk-5OOA7SGX.js.map → chunk-4ESAR77N.js.map} +0 -0
- /package/dist/{chunk-FO3HO52S.js.map → chunk-4H4F3BFL.js.map} +0 -0
- /package/dist/{chunk-BEUCACTV.js.map → chunk-4NOI577P.js.map} +0 -0
- /package/dist/{chunk-BBIE7W52.js.map → chunk-4NR2PDZ5.js.map} +0 -0
- /package/dist/{chunk-WGTWGDR5.js.map → chunk-76NHR6ZL.js.map} +0 -0
- /package/dist/{chunk-PKMQK2WY.js.map → chunk-773DPI6T.js.map} +0 -0
- /package/dist/{chunk-MQVKHFIU.js.map → chunk-7RLCCNHU.js.map} +0 -0
- /package/dist/{chunk-EZNDNMRH.js.map → chunk-AQLOP5F4.js.map} +0 -0
- /package/dist/{chunk-UNNDFYUX.js.map → chunk-ARV3AUOM.js.map} +0 -0
- /package/dist/{chunk-NPL7VDM6.js.map → chunk-ASKXIAHD.js.map} +0 -0
- /package/dist/{chunk-K4ZNARDO.js.map → chunk-CBWI22JN.js.map} +0 -0
- /package/dist/{chunk-ZOHMPFOB.js.map → chunk-CKFLLAIS.js.map} +0 -0
- /package/dist/{chunk-JPUT5NGH.js.map → chunk-DMQWV6SQ.js.map} +0 -0
- /package/dist/{chunk-F3XZN24Z.js.map → chunk-DRUDC2UX.js.map} +0 -0
- /package/dist/{chunk-KJR66XOM.js.map → chunk-EY6MDMHK.js.map} +0 -0
- /package/dist/{chunk-3TUT4PWB.js.map → chunk-FVZ2ISIX.js.map} +0 -0
- /package/dist/{chunk-6SQQOJ4U.js.map → chunk-GKRLPHPU.js.map} +0 -0
- /package/dist/{chunk-5NWYQUQC.js.map → chunk-HOHVIVDR.js.map} +0 -0
- /package/dist/{chunk-6WAJQKBS.js.map → chunk-JYLFZWUX.js.map} +0 -0
- /package/dist/{chunk-5W7CTZ2E.js.map → chunk-KQAFEZQX.js.map} +0 -0
- /package/dist/{chunk-UKTDXTWX.js.map → chunk-M4AYVEWS.js.map} +0 -0
- /package/dist/{chunk-YTZ3VGC7.js.map → chunk-M4V2JVSZ.js.map} +0 -0
- /package/dist/{chunk-TA3Y6GEX.js.map → chunk-MLKWJOAJ.js.map} +0 -0
- /package/dist/{chunk-DQXPJ6HD.js.map → chunk-O6YH5F47.js.map} +0 -0
- /package/dist/{chunk-53EEQYE5.js.map → chunk-UTHQPSRC.js.map} +0 -0
- /package/dist/{chunk-BB57OZWC.js.map → chunk-UVPL565C.js.map} +0 -0
- /package/dist/{chunk-6AFVIOVZ.js.map → chunk-V4GNSDFH.js.map} +0 -0
- /package/dist/{chunk-UVYI6VIX.js.map → chunk-X7Y7WX73.js.map} +0 -0
- /package/dist/{chunk-V7CMKMHM.js.map → chunk-Y4YD5TYW.js.map} +0 -0
- /package/dist/{chunk-7NS7AWMZ.js.map → chunk-YGIQORJ3.js.map} +0 -0
- /package/dist/{chunk-3MS3QVX6.js.map → chunk-YOLZS7NY.js.map} +0 -0
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
import {
|
|
2
|
+
MeilisearchBackend
|
|
3
|
+
} from "./chunk-WRFKZEO6.js";
|
|
4
|
+
import {
|
|
5
|
+
NoopSearchBackend
|
|
6
|
+
} from "./chunk-CYEPCZN5.js";
|
|
1
7
|
import {
|
|
2
8
|
OramaBackend
|
|
3
9
|
} from "./chunk-LQ6JI4VH.js";
|
|
@@ -6,16 +12,10 @@ import {
|
|
|
6
12
|
} from "./chunk-SANZHXY2.js";
|
|
7
13
|
import {
|
|
8
14
|
EmbedHelper
|
|
9
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-WAS3NV46.js";
|
|
10
16
|
import {
|
|
11
17
|
LanceDbBackend
|
|
12
18
|
} from "./chunk-5CEJH5ZN.js";
|
|
13
|
-
import {
|
|
14
|
-
MeilisearchBackend
|
|
15
|
-
} from "./chunk-WRFKZEO6.js";
|
|
16
|
-
import {
|
|
17
|
-
NoopSearchBackend
|
|
18
|
-
} from "./chunk-CYEPCZN5.js";
|
|
19
19
|
import {
|
|
20
20
|
createConversationIndexBackend
|
|
21
21
|
} from "./chunk-DCWIQFNA.js";
|
|
@@ -170,4 +170,4 @@ export {
|
|
|
170
170
|
createConversationSearchBackend,
|
|
171
171
|
createConversationIndexRuntime
|
|
172
172
|
};
|
|
173
|
-
//# sourceMappingURL=chunk-
|
|
173
|
+
//# sourceMappingURL=chunk-UTHQPSRC.js.map
|
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
} from "./chunk-ZBJMUXZH.js";
|
|
5
5
|
import {
|
|
6
6
|
StorageManager
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-7RLCCNHU.js";
|
|
8
8
|
import {
|
|
9
9
|
getCachedRuleMemories,
|
|
10
10
|
setCachedRuleMemories
|
|
@@ -117,4 +117,4 @@ export {
|
|
|
117
117
|
compareVerifiedSemanticRuleResults,
|
|
118
118
|
searchVerifiedSemanticRules
|
|
119
119
|
};
|
|
120
|
-
//# sourceMappingURL=chunk-
|
|
120
|
+
//# sourceMappingURL=chunk-UVPL565C.js.map
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
createSearchBackend
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-UTHQPSRC.js";
|
|
4
4
|
import {
|
|
5
5
|
namespaceIdentityToken,
|
|
6
6
|
normalizeNamespaceIdentity
|
|
@@ -401,4 +401,4 @@ export {
|
|
|
401
401
|
namespaceCollectionName,
|
|
402
402
|
NamespaceSearchRouter
|
|
403
403
|
};
|
|
404
|
-
//# sourceMappingURL=chunk-
|
|
404
|
+
//# sourceMappingURL=chunk-V4GNSDFH.js.map
|
|
@@ -5,6 +5,9 @@ import {
|
|
|
5
5
|
getHostEmbeddingProvider,
|
|
6
6
|
normalizeHostEmbeddingVector
|
|
7
7
|
} from "./chunk-3ONXXHQO.js";
|
|
8
|
+
import {
|
|
9
|
+
resolveMemoryLifecycleCapabilities
|
|
10
|
+
} from "./chunk-3RCBIOOJ.js";
|
|
8
11
|
import {
|
|
9
12
|
log
|
|
10
13
|
} from "./chunk-NU3CSQ4H.js";
|
|
@@ -129,7 +132,7 @@ var EmbedHelper = class {
|
|
|
129
132
|
return this.cachedProvider;
|
|
130
133
|
}
|
|
131
134
|
resolveProvider(options = {}) {
|
|
132
|
-
if (!this.config.
|
|
135
|
+
if (!resolveMemoryLifecycleCapabilities(this.config).embeddingFallback) return null;
|
|
133
136
|
if (options.includeHost !== false && this.config.hostEmbeddingProviderEnabled !== false) {
|
|
134
137
|
const hostProvider = this.resolveHostEmbeddingProvider();
|
|
135
138
|
if (hostProvider) {
|
|
@@ -155,7 +158,7 @@ var EmbedHelper = class {
|
|
|
155
158
|
return null;
|
|
156
159
|
}
|
|
157
160
|
resolveFallbackProviderForIdentity(identity) {
|
|
158
|
-
if (!this.config.
|
|
161
|
+
if (!resolveMemoryLifecycleCapabilities(this.config).embeddingFallback) return null;
|
|
159
162
|
const separator = identity.indexOf(":");
|
|
160
163
|
if (separator <= 0 || separator === identity.length - 1) return null;
|
|
161
164
|
const type = identity.slice(0, separator);
|
|
@@ -305,4 +308,4 @@ function normalizeHttpEmbeddingVector(vector) {
|
|
|
305
308
|
export {
|
|
306
309
|
EmbedHelper
|
|
307
310
|
};
|
|
308
|
-
//# sourceMappingURL=chunk-
|
|
311
|
+
//# sourceMappingURL=chunk-WAS3NV46.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/search/embed-helper.ts"],"sourcesContent":["import { log } from \"../logger.js\";\nimport { resolveMemoryLifecycleCapabilities } from \"../capabilities.js\";\nimport type { PluginConfig } from \"../types.js\";\nimport { isAbortError } from \"../abort-error.js\";\nimport { withTimeoutSignal } from \"./abort.js\";\nimport {\n getHostEmbeddingProvider,\n type HostEmbeddingProvider,\n type HostEmbeddingInputType,\n normalizeHostEmbeddingVector,\n} from \"../host-embedding-provider.js\";\n\ntype ProviderConfig = {\n type: \"openai\" | \"local\" | \"host\";\n model: string;\n endpoint?: string;\n headers?: Record<string, string>;\n hostProvider?: HostEmbeddingProvider;\n};\n\ntype HostEmbeddingScopeConfig = PluginConfig & {\n /**\n * Internal namespace-router metadata. Host adapters register providers at\n * the root memoryDir while namespace backends operate under scoped dirs.\n */\n hostEmbeddingProviderScope?: string;\n};\n\ntype EmbedHelperOptions = {\n /** Backend-local vector schema dimension for host-provider validation. */\n hostEmbeddingExpectedDimension?: number;\n};\n\nexport type EmbedProviderIdentity = `${ProviderConfig[\"type\"]}:${string}`;\n\nexport type EmbedWithProviderResult = {\n vector: number[];\n providerIdentity: EmbedProviderIdentity;\n};\n\nexport type EmbedBatchWithProviderResult = {\n vectors: (number[] | null)[];\n providerIdentity: EmbedProviderIdentity;\n};\n\nconst DEFAULT_OPENAI_MODEL = \"text-embedding-3-small\";\nconst DEFAULT_PROVIDER_CACHE_TTL_MS = 250;\n\n/**\n * Standalone embedding helper for search backend adapters.\n *\n * NOTE: This intentionally duplicates provider resolution from EmbeddingFallback.\n * EmbeddingFallback is tightly integrated with the plugin lifecycle (telemetry,\n * rate-limit backoff, provider rotation). This class is a lightweight standalone\n * utility used by LanceDB/Orama backends which operate outside plugin context.\n * Merging them would break the port/adapter separation between search and plugin layers.\n */\nexport class EmbedHelper {\n private cachedProvider: ProviderConfig | null | undefined;\n private cachedProviderAt = 0;\n private providerCacheTtlMs = DEFAULT_PROVIDER_CACHE_TTL_MS;\n\n constructor(\n private readonly config: PluginConfig,\n private readonly options: EmbedHelperOptions = {},\n ) {}\n\n /**\n * Whether an embedding provider is available.\n * Re-resolves periodically so late host-provider registration is visible\n * without repeatedly probing provider state on every hot-path call.\n */\n isAvailable(): boolean {\n return this.getProvider() !== null;\n }\n\n /**\n * Embed a single text string. Returns null if no provider is available.\n */\n async embed(text: string, options: { signal?: AbortSignal } = {}): Promise<number[] | null> {\n return (await this.embedWithProvider(text, options))?.vector ?? null;\n }\n\n async embedWithProvider(\n text: string,\n options: { signal?: AbortSignal } = {},\n ): Promise<EmbedWithProviderResult | null> {\n const provider = this.getProvider();\n if (!provider) return null;\n const result = await this.callEmbed(text, provider, options.signal, \"query\");\n if (result) {\n return {\n vector: result,\n providerIdentity: providerIdentity(provider),\n };\n }\n if (provider.type !== \"host\") return null;\n const fallbackProvider = this.resolveProvider({ includeHost: false });\n if (!fallbackProvider) return null;\n const fallbackResult = await this.callEmbed(text, fallbackProvider, options.signal, \"query\");\n return fallbackResult\n ? {\n vector: fallbackResult,\n providerIdentity: providerIdentity(fallbackProvider),\n }\n : null;\n }\n\n async embedWithFallbackProviderIdentity(\n text: string,\n identity: EmbedProviderIdentity,\n options: { signal?: AbortSignal } = {},\n ): Promise<EmbedWithProviderResult | null> {\n const provider = this.resolveFallbackProviderForIdentity(identity);\n if (!provider) return null;\n const result = await this.callEmbed(text, provider, options.signal, \"query\");\n return result\n ? {\n vector: result,\n providerIdentity: providerIdentity(provider),\n }\n : null;\n }\n\n /**\n * Embed a batch of texts. Returns an array parallel to input; entries are null on failure.\n */\n async embedBatch(\n texts: string[],\n batchSize = 32,\n options: { signal?: AbortSignal } = {},\n ): Promise<(number[] | null)[]> {\n return (await this.embedBatchWithProvider(texts, batchSize, options))?.vectors ?? texts.map(() => null);\n }\n\n async embedBatchWithProvider(\n texts: string[],\n batchSize = 32,\n options: { signal?: AbortSignal } = {},\n ): Promise<EmbedBatchWithProviderResult | null> {\n const provider = this.getProvider();\n if (!provider) return null;\n\n if (provider.type === \"host\") {\n const hostResults = await this.embedAllWithProvider(texts, batchSize, provider, options);\n if (!hostResults.some((result) => result === null)) {\n return {\n vectors: hostResults,\n providerIdentity: providerIdentity(provider),\n };\n }\n const fallbackProvider = this.resolveProvider({ includeHost: false });\n if (!fallbackProvider) {\n return {\n vectors: hostResults,\n providerIdentity: providerIdentity(provider),\n };\n }\n const fallbackResults = await this.embedAllWithProvider(texts, batchSize, fallbackProvider, options);\n return {\n vectors: fallbackResults,\n providerIdentity: providerIdentity(fallbackProvider),\n };\n }\n\n return {\n vectors: await this.embedAllWithProvider(texts, batchSize, provider, options),\n providerIdentity: providerIdentity(provider),\n };\n }\n\n getProviderIdentity(): EmbedProviderIdentity | null {\n const provider = this.getProvider();\n return provider ? providerIdentity(provider) : null;\n }\n\n private async embedAllWithProvider(\n texts: string[],\n batchSize: number,\n provider: ProviderConfig,\n options: { signal?: AbortSignal } = {},\n ): Promise<(number[] | null)[]> {\n const results: (number[] | null)[] = new Array(texts.length).fill(null);\n for (let i = 0; i < texts.length; i += batchSize) {\n const batch = texts.slice(i, i + batchSize);\n const batchResults =\n provider.type === \"host\" && provider.hostProvider?.embedBatch\n ? await this.callHostEmbedBatch(batch, provider.hostProvider, options.signal)\n : await Promise.all(\n batch.map((t) => this.callEmbed(t, provider, options.signal, \"document\")),\n );\n for (let j = 0; j < batchResults.length; j++) {\n results[i + j] = batchResults[j];\n }\n }\n return results;\n }\n\n private getProvider(): ProviderConfig | null {\n const now = Date.now();\n if (\n this.cachedProvider !== undefined &&\n now - this.cachedProviderAt < this.providerCacheTtlMs\n ) {\n return this.cachedProvider;\n }\n this.cachedProvider = this.resolveProvider();\n this.cachedProviderAt = now;\n return this.cachedProvider;\n }\n\n private resolveProvider(options: { includeHost?: boolean } = {}): ProviderConfig | null {\n if (!resolveMemoryLifecycleCapabilities(this.config).embeddingFallback) return null;\n\n if (\n options.includeHost !== false &&\n this.config.hostEmbeddingProviderEnabled !== false\n ) {\n const hostProvider = this.resolveHostEmbeddingProvider();\n if (hostProvider) {\n return {\n type: \"host\",\n model: hostProvider.model || hostProvider.id,\n hostProvider,\n };\n }\n }\n\n const preferred = this.config.embeddingFallbackProvider;\n const providers = preferred === \"auto\" ? [\"openai\", \"local\"] : [preferred];\n\n for (const p of providers) {\n if (p === \"openai\") {\n const provider = this.createOpenAiProvider();\n if (provider) return provider;\n }\n\n if (p === \"local\") {\n const provider = this.createLocalProvider();\n if (provider) return provider;\n }\n }\n\n return null;\n }\n\n private resolveFallbackProviderForIdentity(identity: EmbedProviderIdentity): ProviderConfig | null {\n if (!resolveMemoryLifecycleCapabilities(this.config).embeddingFallback) return null;\n const separator = identity.indexOf(\":\");\n if (separator <= 0 || separator === identity.length - 1) return null;\n const type = identity.slice(0, separator);\n const model = identity.slice(separator + 1);\n\n if (type === \"openai\") {\n const provider = this.createOpenAiProvider();\n return provider && provider.model === model ? provider : null;\n }\n if (type === \"local\") {\n const provider = this.createLocalProvider();\n return provider && provider.model === model ? provider : null;\n }\n return null;\n }\n\n private createOpenAiProvider(): ProviderConfig | null {\n if (!this.config.openaiApiKey) return null;\n const baseUrl = this.config.openaiBaseUrl ?? \"https://api.openai.com/v1\";\n return {\n type: \"openai\",\n model: DEFAULT_OPENAI_MODEL,\n endpoint: `${baseUrl.replace(/\\/$/, \"\")}/embeddings`,\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${this.config.openaiApiKey}`,\n },\n };\n }\n\n private createLocalProvider(): ProviderConfig | null {\n if (!this.config.localLlmEnabled || !this.config.localLlmUrl) return null;\n const base = this.config.localLlmUrl.replace(/\\/$/, \"\");\n const endpoint = /\\/v1$/i.test(base) ? `${base}/embeddings` : `${base}/v1/embeddings`;\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n ...(this.config.localLlmHeaders ?? {}),\n };\n if (this.config.localLlmApiKey && this.config.localLlmAuthHeader !== false) {\n headers.Authorization = `Bearer ${this.config.localLlmApiKey}`;\n }\n return {\n type: \"local\",\n model:\n this.config.embeddingFallbackModel ||\n this.config.localLlmModel ||\n DEFAULT_OPENAI_MODEL,\n endpoint,\n headers,\n };\n }\n\n private resolveHostEmbeddingProvider(): HostEmbeddingProvider | undefined {\n const scopedConfig = this.config as HostEmbeddingScopeConfig;\n const scopes = [\n scopedConfig.memoryDir,\n scopedConfig.hostEmbeddingProviderScope,\n ].filter((scope): scope is string => typeof scope === \"string\" && scope.trim().length > 0);\n\n for (const scope of new Set(scopes)) {\n const provider = getHostEmbeddingProvider(scope);\n if (provider) return provider;\n }\n return undefined;\n }\n\n private async callEmbed(\n input: string,\n provider: ProviderConfig,\n signal?: AbortSignal,\n inputType: HostEmbeddingInputType = \"document\",\n ): Promise<number[] | null> {\n if (provider.type === \"host\") {\n return this.callHostEmbed(input, provider.hostProvider, signal, inputType);\n }\n if (!provider.endpoint || !provider.headers) return null;\n try {\n const res = await fetch(provider.endpoint, {\n method: \"POST\",\n headers: provider.headers,\n body: JSON.stringify({\n model: provider.model,\n input: input.slice(0, 8000),\n encoding_format: \"float\",\n }),\n signal: withTimeoutSignal(signal, 30_000),\n });\n if (!res.ok) {\n log.debug(`EmbedHelper request failed: ${provider.type} ${res.status}`);\n return null;\n }\n const payload = (await res.json()) as any;\n const vector = payload?.data?.[0]?.embedding;\n return normalizeHttpEmbeddingVector(vector);\n } catch (err) {\n if (isAbortError(err)) throw err;\n log.debug(`EmbedHelper error: ${err}`);\n return null;\n }\n }\n\n private async callHostEmbed(\n input: string,\n provider: HostEmbeddingProvider | undefined,\n signal?: AbortSignal,\n inputType: HostEmbeddingInputType = \"document\",\n ): Promise<number[] | null> {\n if (!provider) return null;\n try {\n const vector = await provider.embed(input.slice(0, 8000), {\n signal: withTimeoutSignal(signal, 30_000),\n inputType,\n });\n return this.normalizeHostEmbeddingVector(vector);\n } catch (err) {\n if (isAbortError(err)) throw err;\n log.debug(`EmbedHelper host provider error: ${err}`);\n return null;\n }\n }\n\n private async callHostEmbedBatch(\n inputs: string[],\n provider: HostEmbeddingProvider,\n signal?: AbortSignal,\n ): Promise<(number[] | null)[]> {\n try {\n const vectors = await provider.embedBatch?.(\n inputs.map((input) => input.slice(0, 8000)),\n {\n signal: withTimeoutSignal(signal, 30_000),\n inputType: \"document\",\n },\n );\n if (!Array.isArray(vectors)) return inputs.map(() => null);\n return inputs.map((_, index) => this.normalizeHostEmbeddingVector(vectors[index]));\n } catch (err) {\n if (isAbortError(err)) throw err;\n log.debug(`EmbedHelper host provider batch error: ${err}`);\n return inputs.map(() => null);\n }\n }\n\n private normalizeHostEmbeddingVector(value: unknown): number[] | null {\n const vector = normalizeHostEmbeddingVector(value);\n if (!vector) return null;\n const expectedDimension = this.resolveHostEmbeddingExpectedDimension();\n if (expectedDimension !== null && vector.length !== expectedDimension) {\n return null;\n }\n return vector;\n }\n\n private resolveHostEmbeddingExpectedDimension(): number | null {\n const value = this.options.hostEmbeddingExpectedDimension;\n return typeof value === \"number\" && Number.isInteger(value) && value > 0\n ? value\n : null;\n }\n}\n\nfunction providerIdentity(provider: ProviderConfig): EmbedProviderIdentity {\n return `${provider.type}:${provider.model}`;\n}\n\nfunction normalizeHttpEmbeddingVector(vector: unknown): number[] | null {\n if (!Array.isArray(vector)) return null;\n const normalized: number[] = [];\n for (const component of vector) {\n if (typeof component !== \"number\" || !Number.isFinite(component)) {\n return null;\n }\n normalized.push(component);\n }\n return normalized;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AA6CA,IAAM,uBAAuB;AAC7B,IAAM,gCAAgC;AAW/B,IAAM,cAAN,MAAkB;AAAA,EAKvB,YACmB,QACA,UAA8B,CAAC,GAChD;AAFiB;AACA;AAAA,EAChB;AAAA,EAFgB;AAAA,EACA;AAAA,EANX;AAAA,EACA,mBAAmB;AAAA,EACnB,qBAAqB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAY7B,cAAuB;AACrB,WAAO,KAAK,YAAY,MAAM;AAAA,EAChC;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,MAAM,MAAc,UAAoC,CAAC,GAA6B;AAC1F,YAAQ,MAAM,KAAK,kBAAkB,MAAM,OAAO,IAAI,UAAU;AAAA,EAClE;AAAA,EAEA,MAAM,kBACJ,MACA,UAAoC,CAAC,GACI;AACzC,UAAM,WAAW,KAAK,YAAY;AAClC,QAAI,CAAC,SAAU,QAAO;AACtB,UAAM,SAAS,MAAM,KAAK,UAAU,MAAM,UAAU,QAAQ,QAAQ,OAAO;AAC3E,QAAI,QAAQ;AACV,aAAO;AAAA,QACL,QAAQ;AAAA,QACR,kBAAkB,iBAAiB,QAAQ;AAAA,MAC7C;AAAA,IACF;AACA,QAAI,SAAS,SAAS,OAAQ,QAAO;AACrC,UAAM,mBAAmB,KAAK,gBAAgB,EAAE,aAAa,MAAM,CAAC;AACpE,QAAI,CAAC,iBAAkB,QAAO;AAC9B,UAAM,iBAAiB,MAAM,KAAK,UAAU,MAAM,kBAAkB,QAAQ,QAAQ,OAAO;AAC3F,WAAO,iBACH;AAAA,MACE,QAAQ;AAAA,MACR,kBAAkB,iBAAiB,gBAAgB;AAAA,IACrD,IACA;AAAA,EACN;AAAA,EAEA,MAAM,kCACJ,MACA,UACA,UAAoC,CAAC,GACI;AACzC,UAAM,WAAW,KAAK,mCAAmC,QAAQ;AACjE,QAAI,CAAC,SAAU,QAAO;AACtB,UAAM,SAAS,MAAM,KAAK,UAAU,MAAM,UAAU,QAAQ,QAAQ,OAAO;AAC3E,WAAO,SACH;AAAA,MACE,QAAQ;AAAA,MACR,kBAAkB,iBAAiB,QAAQ;AAAA,IAC7C,IACA;AAAA,EACN;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,WACJ,OACA,YAAY,IACZ,UAAoC,CAAC,GACP;AAC9B,YAAQ,MAAM,KAAK,uBAAuB,OAAO,WAAW,OAAO,IAAI,WAAW,MAAM,IAAI,MAAM,IAAI;AAAA,EACxG;AAAA,EAEA,MAAM,uBACJ,OACA,YAAY,IACZ,UAAoC,CAAC,GACS;AAC9C,UAAM,WAAW,KAAK,YAAY;AAClC,QAAI,CAAC,SAAU,QAAO;AAEtB,QAAI,SAAS,SAAS,QAAQ;AAC5B,YAAM,cAAc,MAAM,KAAK,qBAAqB,OAAO,WAAW,UAAU,OAAO;AACvF,UAAI,CAAC,YAAY,KAAK,CAAC,WAAW,WAAW,IAAI,GAAG;AAClD,eAAO;AAAA,UACL,SAAS;AAAA,UACT,kBAAkB,iBAAiB,QAAQ;AAAA,QAC7C;AAAA,MACF;AACA,YAAM,mBAAmB,KAAK,gBAAgB,EAAE,aAAa,MAAM,CAAC;AACpE,UAAI,CAAC,kBAAkB;AACrB,eAAO;AAAA,UACL,SAAS;AAAA,UACT,kBAAkB,iBAAiB,QAAQ;AAAA,QAC7C;AAAA,MACF;AACA,YAAM,kBAAkB,MAAM,KAAK,qBAAqB,OAAO,WAAW,kBAAkB,OAAO;AACnG,aAAO;AAAA,QACL,SAAS;AAAA,QACT,kBAAkB,iBAAiB,gBAAgB;AAAA,MACrD;AAAA,IACF;AAEA,WAAO;AAAA,MACL,SAAS,MAAM,KAAK,qBAAqB,OAAO,WAAW,UAAU,OAAO;AAAA,MAC5E,kBAAkB,iBAAiB,QAAQ;AAAA,IAC7C;AAAA,EACF;AAAA,EAEA,sBAAoD;AAClD,UAAM,WAAW,KAAK,YAAY;AAClC,WAAO,WAAW,iBAAiB,QAAQ,IAAI;AAAA,EACjD;AAAA,EAEA,MAAc,qBACZ,OACA,WACA,UACA,UAAoC,CAAC,GACP;AAC9B,UAAM,UAA+B,IAAI,MAAM,MAAM,MAAM,EAAE,KAAK,IAAI;AACtE,aAAS,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK,WAAW;AAChD,YAAM,QAAQ,MAAM,MAAM,GAAG,IAAI,SAAS;AAC1C,YAAM,eACJ,SAAS,SAAS,UAAU,SAAS,cAAc,aAC/C,MAAM,KAAK,mBAAmB,OAAO,SAAS,cAAc,QAAQ,MAAM,IAC1E,MAAM,QAAQ;AAAA,QACZ,MAAM,IAAI,CAAC,MAAM,KAAK,UAAU,GAAG,UAAU,QAAQ,QAAQ,UAAU,CAAC;AAAA,MAC1E;AACN,eAAS,IAAI,GAAG,IAAI,aAAa,QAAQ,KAAK;AAC5C,gBAAQ,IAAI,CAAC,IAAI,aAAa,CAAC;AAAA,MACjC;AAAA,IACF;AACA,WAAO;AAAA,EACT;AAAA,EAEQ,cAAqC;AAC3C,UAAM,MAAM,KAAK,IAAI;AACrB,QACE,KAAK,mBAAmB,UACxB,MAAM,KAAK,mBAAmB,KAAK,oBACnC;AACA,aAAO,KAAK;AAAA,IACd;AACA,SAAK,iBAAiB,KAAK,gBAAgB;AAC3C,SAAK,mBAAmB;AACxB,WAAO,KAAK;AAAA,EACd;AAAA,EAEQ,gBAAgB,UAAqC,CAAC,GAA0B;AACtF,QAAI,CAAC,mCAAmC,KAAK,MAAM,EAAE,kBAAmB,QAAO;AAE/E,QACE,QAAQ,gBAAgB,SACxB,KAAK,OAAO,iCAAiC,OAC7C;AACA,YAAM,eAAe,KAAK,6BAA6B;AACvD,UAAI,cAAc;AAChB,eAAO;AAAA,UACL,MAAM;AAAA,UACN,OAAO,aAAa,SAAS,aAAa;AAAA,UAC1C;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAEA,UAAM,YAAY,KAAK,OAAO;AAC9B,UAAM,YAAY,cAAc,SAAS,CAAC,UAAU,OAAO,IAAI,CAAC,SAAS;AAEzE,eAAW,KAAK,WAAW;AACzB,UAAI,MAAM,UAAU;AAClB,cAAM,WAAW,KAAK,qBAAqB;AAC3C,YAAI,SAAU,QAAO;AAAA,MACvB;AAEA,UAAI,MAAM,SAAS;AACjB,cAAM,WAAW,KAAK,oBAAoB;AAC1C,YAAI,SAAU,QAAO;AAAA,MACvB;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AAAA,EAEQ,mCAAmC,UAAwD;AACjG,QAAI,CAAC,mCAAmC,KAAK,MAAM,EAAE,kBAAmB,QAAO;AAC/E,UAAM,YAAY,SAAS,QAAQ,GAAG;AACtC,QAAI,aAAa,KAAK,cAAc,SAAS,SAAS,EAAG,QAAO;AAChE,UAAM,OAAO,SAAS,MAAM,GAAG,SAAS;AACxC,UAAM,QAAQ,SAAS,MAAM,YAAY,CAAC;AAE1C,QAAI,SAAS,UAAU;AACrB,YAAM,WAAW,KAAK,qBAAqB;AAC3C,aAAO,YAAY,SAAS,UAAU,QAAQ,WAAW;AAAA,IAC3D;AACA,QAAI,SAAS,SAAS;AACpB,YAAM,WAAW,KAAK,oBAAoB;AAC1C,aAAO,YAAY,SAAS,UAAU,QAAQ,WAAW;AAAA,IAC3D;AACA,WAAO;AAAA,EACT;AAAA,EAEQ,uBAA8C;AACpD,QAAI,CAAC,KAAK,OAAO,aAAc,QAAO;AACtC,UAAM,UAAU,KAAK,OAAO,iBAAiB;AAC7C,WAAO;AAAA,MACL,MAAM;AAAA,MACN,OAAO;AAAA,MACP,UAAU,GAAG,QAAQ,QAAQ,OAAO,EAAE,CAAC;AAAA,MACvC,SAAS;AAAA,QACP,gBAAgB;AAAA,QAChB,eAAe,UAAU,KAAK,OAAO,YAAY;AAAA,MACnD;AAAA,IACF;AAAA,EACF;AAAA,EAEQ,sBAA6C;AACnD,QAAI,CAAC,KAAK,OAAO,mBAAmB,CAAC,KAAK,OAAO,YAAa,QAAO;AACrE,UAAM,OAAO,KAAK,OAAO,YAAY,QAAQ,OAAO,EAAE;AACtD,UAAM,WAAW,SAAS,KAAK,IAAI,IAAI,GAAG,IAAI,gBAAgB,GAAG,IAAI;AACrE,UAAM,UAAkC;AAAA,MACtC,gBAAgB;AAAA,MAChB,GAAI,KAAK,OAAO,mBAAmB,CAAC;AAAA,IACtC;AACA,QAAI,KAAK,OAAO,kBAAkB,KAAK,OAAO,uBAAuB,OAAO;AAC1E,cAAQ,gBAAgB,UAAU,KAAK,OAAO,cAAc;AAAA,IAC9D;AACA,WAAO;AAAA,MACL,MAAM;AAAA,MACN,OACE,KAAK,OAAO,0BACZ,KAAK,OAAO,iBACZ;AAAA,MACF;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAAA,EAEQ,+BAAkE;AACxE,UAAM,eAAe,KAAK;AAC1B,UAAM,SAAS;AAAA,MACb,aAAa;AAAA,MACb,aAAa;AAAA,IACf,EAAE,OAAO,CAAC,UAA2B,OAAO,UAAU,YAAY,MAAM,KAAK,EAAE,SAAS,CAAC;AAEzF,eAAW,SAAS,IAAI,IAAI,MAAM,GAAG;AACnC,YAAM,WAAW,yBAAyB,KAAK;AAC/C,UAAI,SAAU,QAAO;AAAA,IACvB;AACA,WAAO;AAAA,EACT;AAAA,EAEA,MAAc,UACZ,OACA,UACA,QACA,YAAoC,YACV;AAC1B,QAAI,SAAS,SAAS,QAAQ;AAC5B,aAAO,KAAK,cAAc,OAAO,SAAS,cAAc,QAAQ,SAAS;AAAA,IAC3E;AACA,QAAI,CAAC,SAAS,YAAY,CAAC,SAAS,QAAS,QAAO;AACpD,QAAI;AACF,YAAM,MAAM,MAAM,MAAM,SAAS,UAAU;AAAA,QACzC,QAAQ;AAAA,QACR,SAAS,SAAS;AAAA,QAClB,MAAM,KAAK,UAAU;AAAA,UACnB,OAAO,SAAS;AAAA,UAChB,OAAO,MAAM,MAAM,GAAG,GAAI;AAAA,UAC1B,iBAAiB;AAAA,QACnB,CAAC;AAAA,QACD,QAAQ,kBAAkB,QAAQ,GAAM;AAAA,MAC1C,CAAC;AACD,UAAI,CAAC,IAAI,IAAI;AACX,YAAI,MAAM,+BAA+B,SAAS,IAAI,IAAI,IAAI,MAAM,EAAE;AACtE,eAAO;AAAA,MACT;AACA,YAAM,UAAW,MAAM,IAAI,KAAK;AAChC,YAAM,SAAS,SAAS,OAAO,CAAC,GAAG;AACnC,aAAO,6BAA6B,MAAM;AAAA,IAC5C,SAAS,KAAK;AACZ,UAAI,aAAa,GAAG,EAAG,OAAM;AAC7B,UAAI,MAAM,sBAAsB,GAAG,EAAE;AACrC,aAAO;AAAA,IACT;AAAA,EACF;AAAA,EAEA,MAAc,cACZ,OACA,UACA,QACA,YAAoC,YACV;AAC1B,QAAI,CAAC,SAAU,QAAO;AACtB,QAAI;AACF,YAAM,SAAS,MAAM,SAAS,MAAM,MAAM,MAAM,GAAG,GAAI,GAAG;AAAA,QACxD,QAAQ,kBAAkB,QAAQ,GAAM;AAAA,QACxC;AAAA,MACF,CAAC;AACD,aAAO,KAAK,6BAA6B,MAAM;AAAA,IACjD,SAAS,KAAK;AACZ,UAAI,aAAa,GAAG,EAAG,OAAM;AAC7B,UAAI,MAAM,oCAAoC,GAAG,EAAE;AACnD,aAAO;AAAA,IACT;AAAA,EACF;AAAA,EAEA,MAAc,mBACZ,QACA,UACA,QAC8B;AAC9B,QAAI;AACF,YAAM,UAAU,MAAM,SAAS;AAAA,QAC7B,OAAO,IAAI,CAAC,UAAU,MAAM,MAAM,GAAG,GAAI,CAAC;AAAA,QAC1C;AAAA,UACE,QAAQ,kBAAkB,QAAQ,GAAM;AAAA,UACxC,WAAW;AAAA,QACb;AAAA,MACF;AACA,UAAI,CAAC,MAAM,QAAQ,OAAO,EAAG,QAAO,OAAO,IAAI,MAAM,IAAI;AACzD,aAAO,OAAO,IAAI,CAAC,GAAG,UAAU,KAAK,6BAA6B,QAAQ,KAAK,CAAC,CAAC;AAAA,IACnF,SAAS,KAAK;AACZ,UAAI,aAAa,GAAG,EAAG,OAAM;AAC7B,UAAI,MAAM,0CAA0C,GAAG,EAAE;AACzD,aAAO,OAAO,IAAI,MAAM,IAAI;AAAA,IAC9B;AAAA,EACF;AAAA,EAEQ,6BAA6B,OAAiC;AACpE,UAAM,SAAS,6BAA6B,KAAK;AACjD,QAAI,CAAC,OAAQ,QAAO;AACpB,UAAM,oBAAoB,KAAK,sCAAsC;AACrE,QAAI,sBAAsB,QAAQ,OAAO,WAAW,mBAAmB;AACrE,aAAO;AAAA,IACT;AACA,WAAO;AAAA,EACT;AAAA,EAEQ,wCAAuD;AAC7D,UAAM,QAAQ,KAAK,QAAQ;AAC3B,WAAO,OAAO,UAAU,YAAY,OAAO,UAAU,KAAK,KAAK,QAAQ,IACnE,QACA;AAAA,EACN;AACF;AAEA,SAAS,iBAAiB,UAAiD;AACzE,SAAO,GAAG,SAAS,IAAI,IAAI,SAAS,KAAK;AAC3C;AAEA,SAAS,6BAA6B,QAAkC;AACtE,MAAI,CAAC,MAAM,QAAQ,MAAM,EAAG,QAAO;AACnC,QAAM,aAAuB,CAAC;AAC9B,aAAW,aAAa,QAAQ;AAC9B,QAAI,OAAO,cAAc,YAAY,CAAC,OAAO,SAAS,SAAS,GAAG;AAChE,aAAO;AAAA,IACT;AACA,eAAW,KAAK,SAAS;AAAA,EAC3B;AACA,SAAO;AACT;","names":[]}
|
|
@@ -10,10 +10,10 @@ import {
|
|
|
10
10
|
import {
|
|
11
11
|
listMemoryGovernanceRuns,
|
|
12
12
|
readMemoryGovernanceRunArtifact
|
|
13
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-4NOI577P.js";
|
|
14
14
|
import {
|
|
15
15
|
StorageManager
|
|
16
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-7RLCCNHU.js";
|
|
17
17
|
import {
|
|
18
18
|
MEMORY_LIFECYCLE_EVENT_SORT_ORDER,
|
|
19
19
|
buildLifecycleEventsForMemory,
|
|
@@ -929,4 +929,4 @@ export {
|
|
|
929
929
|
verifyMemoryProjection,
|
|
930
930
|
repairMemoryProjection
|
|
931
931
|
};
|
|
932
|
-
//# sourceMappingURL=chunk-
|
|
932
|
+
//# sourceMappingURL=chunk-Y4YD5TYW.js.map
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import {
|
|
2
2
|
NamespaceStorageRouter
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-3TSTGI6F.js";
|
|
4
4
|
import {
|
|
5
5
|
namespaceCollectionName
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-V4GNSDFH.js";
|
|
7
7
|
import {
|
|
8
8
|
namespaceIdentityFromToken,
|
|
9
9
|
namespaceIdentityToken
|
|
@@ -204,4 +204,4 @@ export {
|
|
|
204
204
|
verifyNamespaces,
|
|
205
205
|
runNamespaceMigration
|
|
206
206
|
};
|
|
207
|
-
//# sourceMappingURL=chunk-
|
|
207
|
+
//# sourceMappingURL=chunk-YGIQORJ3.js.map
|
|
@@ -73,17 +73,16 @@ function isStrictIsoTimestamp(s) {
|
|
|
73
73
|
}
|
|
74
74
|
function toStrictIsoTimestamp(ts) {
|
|
75
75
|
if (typeof ts !== "string" || ts.length === 0) return void 0;
|
|
76
|
-
|
|
77
|
-
|
|
76
|
+
const value = ts.trim();
|
|
77
|
+
if (value.length === 0) return void 0;
|
|
78
|
+
if (isStrictIsoTimestamp(value)) return value;
|
|
79
|
+
const parsed = Date.parse(value);
|
|
78
80
|
if (Number.isNaN(parsed)) return void 0;
|
|
79
|
-
if (!/[-:T]/.test(
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
const [_, ys, ms, ds] = ymd;
|
|
83
|
-
const y = Number(ys), mo = Number(ms), da = Number(ds);
|
|
84
|
-
if (!isValidCalendarDate(y, mo, da)) return void 0;
|
|
81
|
+
if (!/[-:T]/.test(value)) return void 0;
|
|
82
|
+
if (/^\d{4}\D/.test(value) && parseYearLedDatePrefix(value) === null) {
|
|
83
|
+
return void 0;
|
|
85
84
|
}
|
|
86
|
-
const mdy = /^(\d{1,2})\D(\d{1,2})\D(\d{4})/.exec(
|
|
85
|
+
const mdy = /^(\d{1,2})\D(\d{1,2})\D(\d{4})/.exec(value);
|
|
87
86
|
if (mdy) {
|
|
88
87
|
const a = Number(mdy[1]), b = Number(mdy[2]), yr = Number(mdy[3]);
|
|
89
88
|
if (!isValidCalendarDate(yr, a, b) && !isValidCalendarDate(yr, b, a)) {
|
|
@@ -99,6 +98,41 @@ function isValidCalendarDate(y, mo, da) {
|
|
|
99
98
|
const daysInMonth = [31, leap, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
|
|
100
99
|
return da <= daysInMonth[mo - 1];
|
|
101
100
|
}
|
|
101
|
+
var MONTH_NAMES = {
|
|
102
|
+
jan: 1,
|
|
103
|
+
january: 1,
|
|
104
|
+
feb: 2,
|
|
105
|
+
february: 2,
|
|
106
|
+
mar: 3,
|
|
107
|
+
march: 3,
|
|
108
|
+
apr: 4,
|
|
109
|
+
april: 4,
|
|
110
|
+
may: 5,
|
|
111
|
+
jun: 6,
|
|
112
|
+
june: 6,
|
|
113
|
+
jul: 7,
|
|
114
|
+
july: 7,
|
|
115
|
+
aug: 8,
|
|
116
|
+
august: 8,
|
|
117
|
+
sep: 9,
|
|
118
|
+
september: 9,
|
|
119
|
+
sept: 9,
|
|
120
|
+
oct: 10,
|
|
121
|
+
october: 10,
|
|
122
|
+
nov: 11,
|
|
123
|
+
november: 11,
|
|
124
|
+
dec: 12,
|
|
125
|
+
december: 12
|
|
126
|
+
};
|
|
127
|
+
function parseYearLedDatePrefix(s) {
|
|
128
|
+
const m = /^(\d{4})[^0-9T](\d{1,2}|[A-Za-z]{3,})[^0-9T:](\d{1,2})(?![\d:])/.exec(s);
|
|
129
|
+
if (!m) return null;
|
|
130
|
+
const y = Number(m[1]);
|
|
131
|
+
const da = Number(m[3]);
|
|
132
|
+
const mo = /^\d+$/.test(m[2]) ? Number(m[2]) : MONTH_NAMES[m[2].toLowerCase()] ?? -1;
|
|
133
|
+
if (!isValidCalendarDate(y, mo, da)) return null;
|
|
134
|
+
return { y, mo, da };
|
|
135
|
+
}
|
|
102
136
|
var ProvenanceSourceSchema = z.object({
|
|
103
137
|
sessionKey: z.string().min(1),
|
|
104
138
|
observedAt: z.string().min(1).refine(isStrictIsoTimestamp, "must be a valid ISO 8601 timestamp (YYYY-MM-DDTHH:MM:SS[Z|\xB1HH:MM], no calendar overflow)"),
|
|
@@ -298,4 +332,4 @@ export {
|
|
|
298
332
|
parseProvenanceConfig,
|
|
299
333
|
buildFactProvenance
|
|
300
334
|
};
|
|
301
|
-
//# sourceMappingURL=chunk-
|
|
335
|
+
//# sourceMappingURL=chunk-YKBHOBJK.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/provenance.ts"],"sourcesContent":["/**\n * Claim-level provenance spans (issue #1575 PR 1).\n *\n * Centralizes the parse/serialize logic for the `sources` array and the\n * coarse `provenance` strength tag, plus the `provenance` config-block\n * parser. Extracted from `storage.ts` and `config.ts` so those files keep\n * only thin delegation call-sites — the frontmatter round-trip and config\n * parsing growth lives here (issue #1520 ratchet discipline).\n *\n * Contract:\n * - When no provenance fields are present, output is byte-identical to\n * pre-feature behavior (rule 39).\n * - Corrupt `sources` lines / unknown `provenance` tags drop to\n * `undefined` on read so a malformed frontmatter never poisons\n * downstream readers (rule 34 spirit — drop corrupt rather than poison).\n * - Validation lives on the write path; this module only parses.\n * - Invariant (review round 5, cursor thread KQN): a `verified` or\n * `unverified` tag is NEVER persisted/read without surviving sources —\n * without excerpts the tag is indistinguishable from a grounded fact to\n * downstream faithfulness/correction/TrustScore surfaces. The invariant\n * is enforced symmetrically: `serializeProvenanceFields` (write) and\n * `reconcileProvenanceRead` (read) both downgrade the tag to `none`\n * when no source survives.\n */\n\nimport { z } from \"zod\";\n\nimport { coerceBool, coerceNumber } from \"./connectors/coerce.js\";\nimport { readEnvVar } from \"./runtime/env.js\";\nimport { collapseWhitespace } from \"./whitespace.js\";\nimport type { MemoryFrontmatter, ProvenanceConfig, ProvenanceSource } from \"./types.js\";\nimport { isSafeMemoryContent } from \"./sanitize.js\";\n\n/**\n * Canonical key order for a serialized `ProvenanceSource` (issue #1575).\n * Deterministic emission (rule 38) — readers and the byte-identical-when-off\n * contract (rule 39) depend on this order never drifting.\n */\nconst PROVENANCE_SOURCE_KEY_ORDER = [\n \"sessionKey\",\n \"turnId\",\n \"observedAt\",\n \"quote\",\n \"charStart\",\n \"charEnd\",\n] as const;\n\n/**\n * Build a single `ProvenanceSource` object whose keys appear in the canonical\n * order, omitting absent optional fields. The result is what gets fed to\n * `JSON.stringify` so the on-disk line is deterministic.\n */\nfunction canonicalProvenanceSource(src: ProvenanceSource): Record<string, unknown> {\n const out: Record<string, unknown> = {};\n for (const key of PROVENANCE_SOURCE_KEY_ORDER) {\n const value = src[key];\n if (value !== undefined) out[key] = value;\n }\n return out;\n}\n\n/**\n * Serialize the `sources` array (issue #1575) as a single JSON line, matching\n * the `structuredAttributes` precedent. Each entry is rebuilt in canonical key\n * order (rule 38) so the output is byte-stable. The `provenance` enum is\n * emitted bare (same style as `status`) — only the three documented values\n * are ever written.\n *\n * Verified-requires-evidence invariant (review round 5, cursor thread KQN):\n * a `verified`/`unverified` tag is downgraded to `none` whenever no source\n * survives write validation — whether sources were absent, an empty array,\n * or all entries failed the schema. This covers all three failure shapes the\n * earlier 3-branch logic left open (`{provenance:\"verified\"}`,\n * `{sources:[],provenance:\"verified\"}`, `{sources:[invalid…],provenance:\"verified\"}`).\n */\nexport function serializeProvenanceFields(fm: MemoryFrontmatter, lines: string[]): void {\n let hasValidSources = false;\n if (fm.sources && fm.sources.length > 0) {\n // Validate each entry against the same schema used on read so invalid\n // in-memory sources are dropped at write time, not silently lost on the\n // next read (review thread 4 — write-path validation parity).\n const canonical: Record<string, unknown>[] = [];\n for (const src of fm.sources) {\n const result = ProvenanceSourceSchema.safeParse(src);\n if (result.success) canonical.push(canonicalProvenanceSource(result.data));\n }\n if (canonical.length > 0) {\n lines.push(`sources: ${JSON.stringify(canonical)}`);\n hasValidSources = true;\n }\n }\n // A verified/unverified tag requires surviving evidence; without it the\n // tag is meaningless downstream (faithfulness/TrustScore cannot distinguish\n // it from a grounded fact). Downgrade to \"none\" regardless of WHY no source\n // survived (absent / empty / all-invalid) — single invariant, all cases.\n const tag =\n (fm.provenance === \"verified\" || fm.provenance === \"unverified\") && !hasValidSources\n ? \"none\"\n : fm.provenance;\n if (tag) {\n lines.push(`provenance: ${tag}`);\n }\n}\n\n/**\n * Parse the coarse `provenance` strength tag (issue #1575). Returns\n * `undefined` for missing/blank/unknown values so a corrupt or hand-edited\n * field fails safely to the legacy-equivalent `\"none\"` semantics on read\n * (rule 34 spirit — drop corrupt rather than poison).\n */\nexport function parseProvenanceTag(\n raw: string | undefined,\n): \"verified\" | \"unverified\" | \"none\" | undefined {\n if (raw === undefined) return undefined;\n const trimmed = raw.trim();\n if (trimmed.length === 0) return undefined;\n if (trimmed === \"verified\" || trimmed === \"unverified\" || trimmed === \"none\") {\n return trimmed;\n }\n return undefined;\n}\n\n/**\n * Enforce the verified-requires-evidence invariant on the READ path.\n * `parseProvenanceTag` and `parseProvenanceSources` are independent (they\n * parse separate frontmatter lines), so a hand-edited or imported memory may\n * carry `provenance: verified` with no surviving `sources` — a corrupt line,\n * an empty array, or all-invalid entries. Downgrade such a tag to `none` so\n * the in-memory object never exposes an ungrounded \"verified\" fact\n * (review round 5, cursor thread KQN — read-path parity with the write-path\n * downgrade in `serializeProvenanceFields`). `none`/`undefined` tags pass\n * through unchanged.\n */\nexport function reconcileProvenanceRead(\n tag: \"verified\" | \"unverified\" | \"none\" | undefined,\n sources: ProvenanceSource[] | undefined,\n): \"verified\" | \"unverified\" | \"none\" | undefined {\n if ((tag === \"verified\" || tag === \"unverified\") && (!sources || sources.length === 0)) {\n return \"none\";\n }\n return tag;\n}\n\n/**\n * Strict ISO-8601 timestamp check (review round 6, codex thread OXPAp).\n * `Date.parse` accepts non-ISO strings (bare years like `\"123\"`) and\n * silently normalizes calendar overflow (`2026-02-30` -> March 2, hour 25\n * -> next day), so malformed provenance survives as if valid. Require the\n * full `YYYY-MM-DDTHH:MM:SS[.fff](Z|±HH:MM)` shape and reject overflow via a\n * `Date.UTC` round-trip component check — the offset does not affect whether\n * a wall-clock field overflows, so this is correct for any timezone suffix.\n */\nfunction isStrictIsoTimestamp(s: string): boolean {\n const m = /^(\\d{4})-(\\d{2})-(\\d{2})T(\\d{2}):(\\d{2}):(\\d{2})(?:\\.\\d+)?(?:Z|[+-]\\d{2}:\\d{2})$/.exec(s);\n if (!m) return false;\n const y = Number(m[1]), mo = Number(m[2]), da = Number(m[3]);\n const h = Number(m[4]), mi = Number(m[5]), se = Number(m[6]);\n // Date.UTC normalizes overflow (Feb 30 -> Mar 2); a component round-trip\n // catches what Date.parse silently accepts.\n const d = new Date(Date.UTC(y, mo - 1, da, h, mi, se));\n // The component round-trip validates wall-clock overflow (Feb 30 -> Mar 2);\n // Date.parse additionally rejects impossible timezone offsets such as\n // +99:99, which the regex accepts but the runtime treats as NaN\n // (codex thread OXQ0e).\n return (\n !Number.isNaN(Date.parse(s)) &&\n d.getUTCFullYear() === y &&\n d.getUTCMonth() === mo - 1 &&\n d.getUTCDate() === da &&\n d.getUTCHours() === h &&\n d.getUTCMinutes() === mi &&\n d.getUTCSeconds() === se\n );\n}\n\n/**\n * Coerce a turn timestamp to a strict ISO-8601 string (cursor thread Ocveu —\n * \"Non-ISO turn timestamps drop sources\"). The write-path `ProvenanceSourceSchema`\n * rejects anything `isStrictIsoTimestamp` fails, so a turn whose `timestamp`\n * parses via `new Date(...)` but isn't already strict ISO (e.g.\n * `\"2026/01/15 12:00:00\"` or `\"Jan 15 2026\"`) would be silently dropped at\n * serialization — clearing the whole `sources` array and downgrading the tag\n * to `\"none\"`. Normalizing at extraction time preserves the source.\n *\n * Returns the strict ISO string when the timestamp already passes or\n * `Date.parse` can round-trip it; `undefined` for empty / unparseable input\n * so callers can decide whether to skip the source or fall back.\n */\nfunction toStrictIsoTimestamp(ts: string | undefined | null): string | undefined {\n if (typeof ts !== \"string\" || ts.length === 0) return undefined;\n // Trim surrounding whitespace: Date.parse accepts leading/trailing\n // whitespace, so an imported \" 2026-05\" would otherwise bypass the\n // year-led partial-date guard below and fabricate May 1\n // (chatgpt-codex-connector review on #1714, issue #1657).\n const value = ts.trim();\n if (value.length === 0) return undefined;\n if (isStrictIsoTimestamp(value)) return value;\n const parsed = Date.parse(value);\n if (Number.isNaN(parsed)) return undefined;\n // Reject bare-year / numeric-only strings that Date.parse accepts (e.g.\n // \"123\") — isStrictIsoTimestamp already rejected them, and the round-trip\n // below would otherwise resurrect them. Require at least one date/time\n // separator so a plain number never round-trips into a fake epoch.\n if (!/[-:T]/.test(value)) return undefined;\n // Reject year-led timestamps that are not a COMPLETE, calendar-valid date\n // (issue #1657). Date.parse silently fills missing components (\"2026-05\" ->\n // May 1, \"2026-Jan\" -> Jan 1) and rolls overflow (\"2026-02-30\" and\n // \"2026-Feb-30\" -> March 2), fabricating observedAt. `parseYearLedDatePrefix`\n // requires a complete three-component date — numeric OR textual month — with\n // real date separators (not T/:, and not the space that precedes a time\n // component, so the hour is never captured as the day) and a calendar-valid\n // day, in one rule (subsumes the prior partial-numeric and numeric-overflow\n // checks, and extends them to textual months). Non-year-led shapes\n // (\"Jan 15 2026\", \"02/30/2026\") fall through to Date.parse / the mdy check.\n if (/^\\d{4}\\D/.test(value) && parseYearLedDatePrefix(value) === null) {\n return undefined;\n }\n // Also validate M/D/Y or D/M/Y formats (provider/import common shapes:\n // 02/30/2026, 30-02-2026, etc.). Date.parse silently shifts overflow in\n // these too. Try both month-first and day-first interpretations; if\n // neither is a valid calendar date, reject (chatgpt-codex-connector thread\n // dH47 — non-YMD overflow timestamps).\n const mdy = /^(\\d{1,2})\\D(\\d{1,2})\\D(\\d{4})/.exec(value);\n if (mdy) {\n const a = Number(mdy[1]), b = Number(mdy[2]), yr = Number(mdy[3]);\n if (!isValidCalendarDate(yr, a, b) && !isValidCalendarDate(yr, b, a)) {\n return undefined;\n }\n }\n const iso = new Date(parsed).toISOString();\n return isStrictIsoTimestamp(iso) ? iso : undefined;\n}\n\n/**\n * Validate numeric calendar components without Date overflow (review thread\n * dANc). Date.UTC silently normalizes Feb 30 -> Mar 2; a component round-trip\n * catches what Date.parse accepts. Mirrors the same technique isStrictIsoTimestamp\n * uses for full ISO strings, applied here to the non-ISO normalization path.\n */\nfunction isValidCalendarDate(y: number, mo: number, da: number): boolean {\n if (mo < 1 || mo > 12 || da < 1) return false;\n const leap = (y % 4 === 0 && (y % 100 !== 0 || y % 400 === 0)) ? 29 : 28;\n const daysInMonth = [31, leap, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];\n return da <= daysInMonth[mo - 1]!;\n}\n\n/**\n * Recognized month-name → number map for year-led textual-month dates\n * (issue #1657). Both the 3-letter abbreviations and the full names that\n * Date.parse accepts for year-first shapes (e.g. \"2026-Jan-15\",\n * \"2026-January-15\", \"2026 February 2\").\n */\nconst MONTH_NAMES: Record<string, number> = {\n jan: 1, january: 1,\n feb: 2, february: 2,\n mar: 3, march: 3,\n apr: 4, april: 4,\n may: 5,\n jun: 6, june: 6,\n jul: 7, july: 7,\n aug: 8, august: 8,\n sep: 9, september: 9,\n sept: 9,\n oct: 10, october: 10,\n nov: 11, november: 11,\n dec: 12, december: 12,\n};\n\n/**\n * Parse a complete, calendar-valid year-led date prefix from `s`\n * (issue #1657): `YYYY <sep> (MM | MonthName) <sep> DD` where the separators\n * are real date separators (non-digit, non-T, non-colon) and the day is a\n * true calendar day — not the hour before a `:` time separator (the\n * `(?![\\d:])` lookahead rejects \"2026-05 10:00\" capturing \"10\" as the day).\n * Returns the numeric components for a complete, valid date; `null` for an\n * incomplete (\"2026-05\", \"2026-Jan\"), overflowed (\"2026-02-30\",\n * \"2026-Feb-30\"), or non-year-led prefix. Centralizes the fabricated-date\n * rejection for the toStrictIsoTimestamp normalization path across numeric\n * and textual months in one rule.\n */\nfunction parseYearLedDatePrefix(s: string): { y: number; mo: number; da: number } | null {\n const m = /^(\\d{4})[^0-9T](\\d{1,2}|[A-Za-z]{3,})[^0-9T:](\\d{1,2})(?![\\d:])/.exec(s);\n if (!m) return null;\n const y = Number(m[1]);\n const da = Number(m[3]);\n const mo = /^\\d+$/.test(m[2]) ? Number(m[2]) : (MONTH_NAMES[m[2]!.toLowerCase()] ?? -1);\n if (!isValidCalendarDate(y, mo, da)) return null;\n return { y, mo, da };\n}\n\n/**\n * Zod schema for a single `ProvenanceSource` entry (issue #1575). Parsed\n * JSON from frontmatter is external data, so each entry is validated here\n * rather than trusted via a cast (rule: no inline-cast-access on parsed\n * blobs). `safeParse` lets us drop corrupt entries individually instead of\n * failing the whole field.\n */\nconst ProvenanceSourceSchema = z\n .object({\n sessionKey: z.string().min(1),\n observedAt: z\n .string()\n .min(1)\n .refine(isStrictIsoTimestamp, \"must be a valid ISO 8601 timestamp (YYYY-MM-DDTHH:MM:SS[Z|±HH:MM], no calendar overflow)\"),\n quote: z.string().min(1),\n turnId: z.string().min(1).optional(),\n charStart: z.number().finite().nonnegative().int().optional(),\n charEnd: z.number().finite().nonnegative().int().optional(),\n })\n .refine(\n (src) => src.charStart === undefined || src.charEnd === undefined || src.charEnd >= src.charStart,\n { message: \"charEnd must be >= charStart (half-open interval, rule 35)\" },\n );\n\n/**\n * Parse the `sources` array (issue #1575) from its single-line JSON form.\n * Mirrors `parseStructuredAttributes` (JSON.parse) but validates each entry\n * against `ProvenanceSourceSchema` and DROPS corrupt ones rather than\n * poisoning downstream readers — the same \"drop corrupt rather than poison\"\n * contract as `parseMemoryWorthCounterField`. If no entry survives, the\n * whole field is `undefined` (legacy-equivalent).\n */\nexport function parseProvenanceSources(raw: string | undefined): ProvenanceSource[] | undefined {\n if (raw === undefined) return undefined;\n const trimmed = raw.trim();\n if (trimmed.length === 0) return undefined;\n let parsed: unknown;\n try {\n parsed = JSON.parse(trimmed);\n } catch {\n return undefined;\n }\n if (!Array.isArray(parsed)) return undefined;\n const sources: ProvenanceSource[] = [];\n for (const entry of parsed) {\n const result = ProvenanceSourceSchema.safeParse(entry);\n if (result.success) sources.push(result.data);\n }\n return sources.length > 0 ? sources : undefined;\n}\n\n/**\n * Parse the `provenance` config block (issue #1575 PR 1). Validates the\n * shape before applying defaults — a shorthand like `provenance: false` must\n * reject loudly rather than normalize to `{}` and silently enable the feature\n * (rule 51). Booleans coerce via `coerceBool` (rule 36); numeric cap clamps\n * at 1 (rule 28). `REMNIC_PROVENANCE_ENABLED` / `ENGRAM_PROVENANCE_ENABLED`\n * are honored only when the `enabled` key is omitted (explicit config wins).\n *\n * Schema-default note (review rounds 1–3, settled): `provenance.enabled` has\n * NO `\"default\"` in any plugin.json schema. OpenClaw's loader runs\n * `applyDefaults: true` before exposing `api.pluginConfig` (src/index.ts:1345,\n * PR #1593 round 8), so a schema default would be materialized into the\n * merged config and mask the `REMNIC_`/`ENGRAM_` env override. The code-level\n * default-on here (`return true` when `enabled` is omitted) supplies the\n * default-on behavior without that materialization. This matches the\n * emitLegacyTools/namespaceCatalogEnabled precedent, which omits the env\n * override only after a raw-vs-effective split — overkill for a single\n * boolean, so this field uses the simpler omit-the-default approach.\n */\nexport function parseProvenanceConfig(raw: unknown): ProvenanceConfig {\n if (\n raw !== undefined &&\n (raw === null || typeof raw !== \"object\" || Array.isArray(raw))\n ) {\n throw new Error(\n `provenance must be an object (got ${JSON.stringify(raw)}). Use provenance: { enabled: false } to opt out; omit the key to use the default-on behavior (issue #1575).`,\n );\n }\n const rawProvenance =\n raw && typeof raw === \"object\" && !Array.isArray(raw)\n ? (raw as Record<string, unknown>)\n : {};\n return {\n enabled: (() => {\n if (rawProvenance.enabled === undefined) {\n const envEnabled =\n readEnvVar(\"REMNIC_PROVENANCE_ENABLED\") ?? readEnvVar(\"ENGRAM_PROVENANCE_ENABLED\");\n if (envEnabled !== undefined) {\n const coerced = coerceBool(envEnabled);\n if (coerced === undefined) {\n throw new Error(\n `REMNIC_PROVENANCE_ENABLED must be a boolean-like value (true/false/1/0/yes/no/on/off); got ${JSON.stringify(envEnabled)}`,\n );\n }\n return coerced;\n }\n return true;\n }\n const coerced = coerceBool(rawProvenance.enabled);\n if (coerced === undefined) {\n throw new Error(\n `provenance.enabled must be a boolean or one of \"true\"/\"false\"/\"1\"/\"0\"/\"yes\"/\"no\"/\"on\"/\"off\" (got ${JSON.stringify(rawProvenance.enabled)}). Omit the key to use the default-on behavior (issue #1575).`,\n );\n }\n return coerced;\n })(),\n maxQuoteChars: (() => {\n if (rawProvenance.maxQuoteChars === undefined) return 300;\n const rawCap = coerceNumber(rawProvenance.maxQuoteChars);\n // Reject present-but-invalid rather than silently widening the cap\n // (AGENTS.md input-validation rule — a typo should not persist more\n // text than the operator configured).\n if (rawCap === undefined || !Number.isFinite(rawCap) || rawCap < 1 || !Number.isInteger(rawCap)) {\n throw new Error(\n `provenance.maxQuoteChars must be a positive integer >= 1 (got ${JSON.stringify(rawProvenance.maxQuoteChars)}).`,\n );\n }\n return rawCap;\n })(),\n requireSpans: (() => {\n if (rawProvenance.requireSpans === undefined) return false;\n const coerced = coerceBool(rawProvenance.requireSpans);\n if (coerced === undefined) {\n throw new Error(\n `provenance.requireSpans must be a boolean or one of \"true\"/\"false\"/\"1\"/\"0\"/\"yes\"/\"no\"/\"on\"/\"off\" (got ${JSON.stringify(rawProvenance.requireSpans)}).`,\n );\n }\n return coerced;\n })(),\n };\n}\n\n// ---------------------------------------------------------------------------\n// Issue #1575 PR 2 — extraction-side post-parse validator.\n// ---------------------------------------------------------------------------\n//\n// This runs once at write time (inside `ExtractionEngine.extract`, after the\n// LLM output is parsed and sanitized, before the result is returned for\n// persistence). Its job: locate each fact's LLM-provided `quote` in the\n// buffered turn texts and build a `ProvenanceSource[]` with verified\n// offsets. Never throws, never drops a fact (rule 34 spirit — an\n// unverifiable span is a tagged state, not a silent failure).\n//\n// Reuses `collapseWhitespace` from `whitespace.ts` for normalization so there\n// is exactly one normalizer in the codebase (issue #1575 pitfall: \"do not\n// write a second normalizer\").\n// ---------------------------------------------------------------------------\n\n/**\n * A turn in the buffered conversation, reduced to the fields the provenance\n * validator needs. `ExtractionEngine.extract` maps its `BufferTurn[]` to this\n * shape so the validator is pure and testable without the full BufferTurn type.\n */\nexport interface ProvenanceTurnInput {\n content: string;\n sessionKey?: string;\n logicalSessionKey?: string;\n timestamp: string;\n turnId?: string;\n}\n\n/**\n * Result of building provenance for a single extracted fact.\n */\nexport interface ProvenanceBuildResult {\n /** Verified sources (one per matching turn). Absent when no quote survives. */\n sources?: ProvenanceSource[];\n /** Coarse strength tag persisted to frontmatter. */\n provenance: \"verified\" | \"unverified\" | \"none\";\n /**\n * Transient signal (never persisted): `true` when `config.requireSpans`\n * is enabled and the LLM-provided quote could not be located in ANY source\n * turn (the strict case `ProvenanceConfig.requireSpans` documents: \"facts\n * whose quote cannot be located are routed to `pending_review`\"). The\n * extraction consumer carries this onto the in-memory `ExtractedFact` so\n * the persist path can route the fact to the review queue. A quote that\n * WAS located but whose source was dropped (e.g. un-coercible timestamp)\n * does NOT set this flag — the span was found, so requireSpans is\n * satisfied (chatgpt-codex-connector thread 4xB).\n */\n requireSpansPending?: boolean;\n}\n\n/**\n * Cap a quote string at `maxChars`, truncating at the last word boundary that\n * fits and appending an ellipsis marker. Quotes at or under the cap pass\n * through unchanged. Operates on Unicode code points (not UTF-16 units) so\n * emoji and astral-plane characters are not split mid-glyph.\n */\nfunction capQuote(quote: string, maxChars: number): string {\n const glyphs = Array.from(quote);\n if (glyphs.length <= maxChars) return quote;\n // Walk backward from the cap to find a word boundary (space). If the entire\n // span is one long token (no spaces), cut at the cap — a hard cut is better\n // than no quote at all.\n let cut = maxChars;\n while (cut > 0 && !/\\s/.test(glyphs[cut - 1]!)) cut--;\n if (cut === 0) cut = maxChars; // no word boundary found\n return glyphs.slice(0, cut).join(\"\").trimEnd() + \"\\u2026\";\n}\n\n/**\n * Casefold a string for normalized matching. Uses `toLowerCase` (not\n * `toLocaleLowerCase`) for determinism across runtime locales — the existing\n * `normalizeFactKey` helper in extraction.ts follows the same convention.\n */\nfunction casefold(s: string): string {\n return s.toLowerCase();\n}\n\n/**\n * Locate `quote` within `text`, returning whether a match was found and, when\n * recoverable, the half-open `[start, end)` offsets. Tries exact substring\n * first, then whitespace/case-normalized match.\n *\n * For the normalized path, the mapping from the normalized string back to\n * original offsets is recovered by walking both strings in lockstep: we know\n * `collapseWhitespace(text)` is a subsequence of `text` with whitespace runs\n * collapsed, so we can track the original offset as we scan.\n *\n * Returns `{ matched: false }` when neither match succeeds. Returns\n * `{ matched: true, offsets }` when offsets are recoverable. Returns\n * `{ matched: true }` (offsets omitted) when the normalized substring was\n * found but original offsets could not be recovered — callers still treat\n * this as a verified match and record a source without offsets (cursor\n * thread Ocver — \"Normalized match drops verified provenance\").\n */\ntype LocateQuoteResult =\n | { matched: false }\n | { matched: true; offsets?: { charStart: number; charEnd: number } };\n\nfunction locateQuoteOffsets(quote: string, text: string): LocateQuoteResult {\n // 1. Exact substring match (handles unicode, curly quotes, emoji verbatim).\n const exactIdx = text.indexOf(quote);\n if (exactIdx >= 0) {\n return { matched: true, offsets: { charStart: exactIdx, charEnd: exactIdx + quote.length } };\n }\n\n // 2. Whitespace/case-normalized match. Collapse runs of whitespace and\n // casefold both sides, then find the normalized quote in the normalized\n // text. Recover original offsets by scanning forward from the normalized\n // match start through the original text, accumulating non-whitespace\n // glyphs until we've consumed the normalized quote length.\n const normQuote = collapseWhitespace(casefold(quote));\n if (normQuote.length === 0) return { matched: false };\n const normText = collapseWhitespace(casefold(text));\n const normIdx = normText.indexOf(normQuote);\n if (normIdx < 0) return { matched: false };\n\n // Recover original offsets: walk the original text, skipping leading\n // whitespace to align with the collapsed form, then track how many\n // normalized chars we've consumed.\n const normQuoteLen = normQuote.length;\n let origIdx = 0;\n // Skip leading whitespace in original text (collapseWhitespace trims both ends).\n while (origIdx < text.length && /\\s/.test(text[origIdx]!)) origIdx++;\n // Walk through original text, counting normalized chars consumed.\n // Each non-whitespace char in original = 1 normalized char.\n // Whitespace runs in original = 1 space in normalized (but only between non-ws).\n let normPos = 0;\n let origStart = -1;\n let origEnd = -1;\n let prevWasWs = true; // suppress the leading space in collapsed form\n while (origIdx < text.length && origEnd < 0) {\n const ch = text[origIdx]!;\n if (/\\s/.test(ch)) {\n if (!prevWasWs) {\n // This whitespace run collapses to a single space in normalized text.\n if (normPos === normIdx) origStart = origIdx; // normalized space aligns\n normPos++;\n prevWasWs = true;\n }\n origIdx++;\n continue;\n }\n // Non-whitespace char.\n if (normPos === normIdx && origStart < 0) {\n origStart = origIdx;\n }\n normPos++;\n prevWasWs = false;\n origIdx++;\n if (normPos >= normIdx + normQuoteLen) {\n origEnd = origIdx;\n }\n }\n if (origStart >= 0 && origEnd >= 0) {\n return { matched: true, offsets: { charStart: origStart, charEnd: origEnd } };\n }\n // Normalized substring was found, but original offsets are not recoverable\n // (edge case in the normalized mapping). The match still counts as verified\n // — record a source without offsets rather than dropping the turn entirely\n // (cursor thread Ocver). charStart/charEnd are best-effort debugging aids,\n // not a precondition for a verified source.\n return { matched: true };\n}\n\n/**\n * Build provenance sources for a single extracted fact by locating its\n * LLM-provided `quote` in the buffered turns (issue #1575 PR 2).\n *\n * Matching strategy (per issue design):\n * 1. Exact substring match in a turn → `provenance: \"verified\"` with\n * `charStart`/`charEnd` offsets.\n * 2. Whitespace/case-normalized match → `\"verified\"`, offsets recovered\n * when possible, else omitted.\n * 3. No match in any turn → `\"unverified\"` — the quote survives as a\n * source (the LLM vouched for it) but without located offsets.\n * 4. No quote provided by the LLM → `\"none\"` — no evidence to record.\n *\n * A quote appearing in multiple turns produces multiple sources (one per\n * matching turn) so a repeated utterance backs the fact from each occurrence.\n *\n * The quote is capped at `config.maxQuoteChars` (truncated at a word boundary\n * with an ellipsis marker) BEFORE storage. Locating uses the original\n * (untruncated) quote for maximum match fidelity; the capped excerpt is what\n * gets persisted.\n *\n * When `config.enabled === false`, returns `{ provenance: \"none\" }`\n * immediately — byte-identical to pre-feature extraction (rule 39).\n *\n * Never throws. An unexpected error degrades to `{ provenance: \"none\" }` so\n * extraction never crashes on a provenance hiccup (rule 13/18).\n */\n/**\n * Strip a leading extraction-prompt role label from a quote (cursor thread Oc3Z2\n * — \"Quote prompt mismatches validator\"). The extraction prompt renders each\n * buffered turn as `[role] content` (or `[context role] content`), so a\n * faithful LLM may include that prefix in its verbatim quote. buildFactProvenance\n * searches the raw `turn.content` (no prefix), so a quote carrying the label\n * would never match. Stripping the leading label lets the actual utterance\n * verify against the turn text. Only a SINGLE leading label is stripped — a\n * multi-turn quote (with embedded labels) is left untouched and will simply\n * fail to match a single turn, as before.\n *\n * The regex is constrained to the labels the prompt actually emits — `user`,\n * `assistant`, optionally prefixed with `context ` (extraction.ts renders\n * `[user]`, `[assistant]`, `[context user]`, `[context assistant]`). A\n * real utterance that happens to start with other bracketed text (e.g.\n * `[do not] deploy before approval`, `[P1] fix the cache`) is preserved\n * verbatim so the quote can match the turn and the persisted span retains its\n * original meaning (chatgpt-codex-connector thread 4xA — limiting role-prefix\n * stripping to actual prompt labels).\n */\nfunction stripLeadingRolePrefix(quote: string): string {\n return quote.replace(/^\\s*\\[(?:context\\s+)?(?:user|assistant)\\]\\s+/i, \"\");\n}\n\nexport function buildFactProvenance(\n factQuote: string | null | undefined,\n turns: ReadonlyArray<ProvenanceTurnInput>,\n config: ProvenanceConfig,\n): ProvenanceBuildResult {\n if (!config.enabled) return { provenance: \"none\" };\n const rawQuote = typeof factQuote === \"string\" ? factQuote.trim() : \"\";\n // requireSpans (chatgpt-codex-connector thread dEsu + cursor thread dGKJ):\n // every early exit that drops a fact's span (no quote, empty after label\n // strip, or unsafe quote) must flag requireSpansPending when the operator\n // opted into requireSpans, so the persist path routes the fact to\n // pending_review instead of active. Only the disabled-feature exit (above)\n // and the unexpected-error catch (below) omit the flag — those are\n // policy-neutral degradations, not a missing-span decision.\n const noneResult = (): ProvenanceBuildResult =>\n config.requireSpans === true\n ? { provenance: \"none\", requireSpansPending: true }\n : { provenance: \"none\" };\n if (rawQuote.length === 0) return noneResult();\n // Strip a leading prompt role label so a faithful quote verifies against\n // the raw turn content (cursor thread Oc3Z2). Prefer the RAW quote when it\n // matches at least one turn — an utterance that literally begins with\n // [user]/[assistant] must verify as-is, not be truncated to the post-label\n // text (cursor/codex thread dEsw). The strip handles the common case where\n // the LLM includes the prompt label; this preserves the rare case where the\n // utterance itself starts with that text.\n const strippedQuote = stripLeadingRolePrefix(rawQuote);\n const useRawQuote =\n rawQuote === strippedQuote ||\n turns.some(\n (t) =>\n typeof t?.content === \"string\" &&\n t.content.length > 0 &&\n locateQuoteOffsets(rawQuote, t.content).matched,\n );\n const quote = useRawQuote ? rawQuote : strippedQuote;\n if (quote.length === 0) return noneResult();\n // Sanitize the quote before persisting it as a provenance span\n // (chatgpt-codex-connector thread dANZ): the fact body is sanitized via\n // sanitizeMemoryContent, but sources[].quote was persisted verbatim,\n // reintroducing unsafe memory text (e.g. \"ignore previous instructions\")\n // through the provenance field exposed to memory_get/x-ray/faithfulness.\n // An unsafe quote cannot serve as evidence — drop the source entirely\n // (consistent with how the body is sanitized: unsafe text is redacted,\n // and a redacted quote is useless as a verbatim span).\n if (!isSafeMemoryContent(quote)) return noneResult();\n\n try {\n // Search every turn for the quote. Collect verified sources.\n const sources: ProvenanceSource[] = [];\n // Track the first turn where the quote was located even when its\n // timestamp can't be coerced (cursor thread 4Pj — \"Bad timestamp drops\n // matched source\"). Without this, a located-but-unverifiable quote falls\n // through to the unverified branch and is attributed to the *last* turn's\n // session, mislabeling the source's origin session. Also drives the\n // requireSpans signal: only a quote that was NOT located in any turn\n // qualifies for pending_review routing under requireSpans (thread 4xB).\n let locatedTurn: ProvenanceTurnInput | undefined;\n for (const turn of turns) {\n if (!turn || typeof turn.content !== \"string\" || turn.content.length === 0) continue;\n const located = locateQuoteOffsets(quote, turn.content);\n // cursor thread Ocver: a normalized match counts as verified even when\n // original offsets are unrecoverable — record the source without\n // charStart/charEnd instead of skipping the turn.\n if (!located.matched) continue;\n if (!locatedTurn) locatedTurn = turn;\n // cursor thread Ocveu: normalize the turn timestamp to strict ISO so\n // the write-path ProvenanceSourceSchema keeps the source. Skip the turn\n // when the timestamp can't be coerced — pushing it would guarantee a\n // serialization drop (and the tag downgrade) for this source.\n const observedAt = toStrictIsoTimestamp(turn.timestamp);\n if (!observedAt) continue;\n sources.push({\n sessionKey: turn.sessionKey ?? turn.logicalSessionKey ?? \"unknown\",\n ...(turn.turnId ? { turnId: turn.turnId } : {}),\n observedAt,\n quote: capQuote(quote, config.maxQuoteChars),\n ...(located.offsets\n ? { charStart: located.offsets.charStart, charEnd: located.offsets.charEnd }\n : {}),\n });\n }\n\n if (sources.length > 0) {\n return { sources, provenance: \"verified\" };\n }\n\n // Quote provided but could not be turned into a verified source.\n // Determine the session to attribute: prefer the turn where the quote was\n // LOCATED even if its timestamp couldn't be coerced (cursor thread 4Pj — a\n // located quote must not be tied to the *last* turn's session). If the\n // quote was not located in any turn at all, fall back to the last turn's\n // session (the documented unverified behavior: the LLM vouched for the\n // excerpt but we couldn't pin it to a character offset). Normalize the\n // timestamp (thread Ocveu); fall back to epoch when no turn supplies a\n // coercible timestamp so the unverified source still survives the\n // write-path schema.\n const fallbackTurn = locatedTurn ?? turns[turns.length - 1];\n const fallbackSessionKey = fallbackTurn\n ? (fallbackTurn.sessionKey ?? fallbackTurn.logicalSessionKey ?? \"unknown\")\n : \"unknown\";\n const fallbackObservedAt = fallbackTurn\n ? (toStrictIsoTimestamp(fallbackTurn.timestamp) ?? new Date(0).toISOString())\n : new Date(0).toISOString();\n // requireSpans signal (chatgpt-codex-connector thread 4xB): when an\n // operator opts into provenance.requireSpans, a fact whose quote could\n // not be located in ANY turn (locatedTurn undefined) is flagged so the\n // persist path routes it to pending_review instead of active. A quote\n // that WAS located (locatedTurn set) satisfies requireSpans even when\n // its source was dropped for an un-coercible timestamp — the span was\n // found, so the fact has the grounding requireSpans demands.\n const requireSpansPending =\n config.requireSpans === true && locatedTurn === undefined;\n return {\n sources: [\n {\n sessionKey: fallbackSessionKey,\n observedAt: fallbackObservedAt,\n quote: capQuote(quote, config.maxQuoteChars),\n },\n ],\n provenance: \"unverified\",\n ...(requireSpansPending ? { requireSpansPending: true } : {}),\n };\n } catch {\n // Never crash extraction on a provenance error (rule 13/18).\n return { provenance: \"none\" };\n }\n}\n"],"mappings":"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","names":["coerced"]}
|
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
import {
|
|
5
5
|
compareEntityTimestamps,
|
|
6
6
|
normalizeEntityName
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-7RLCCNHU.js";
|
|
8
8
|
import {
|
|
9
9
|
sanitizeMemoryContent
|
|
10
10
|
} from "./chunk-5GKPFL3S.js";
|
|
@@ -679,4 +679,4 @@ export {
|
|
|
679
679
|
entityIndexVersion,
|
|
680
680
|
entityRecentTranscriptLookbackHours
|
|
681
681
|
};
|
|
682
|
-
//# sourceMappingURL=chunk-
|
|
682
|
+
//# sourceMappingURL=chunk-YOLZS7NY.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
callOpenAiCompatibleChat,
|
|
3
3
|
resolveFaithfulnessGateEndpoint
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-AAD2ZS6P.js";
|
|
5
5
|
import {
|
|
6
6
|
gatewayTaskChainOptions
|
|
7
7
|
} from "./chunk-VUA4S7P6.js";
|
|
@@ -78,6 +78,13 @@ function parseFaithfulnessResponse(raw, expectedCount) {
|
|
|
78
78
|
}
|
|
79
79
|
return null;
|
|
80
80
|
}
|
|
81
|
+
function coversAllIndexes(map, expectedCount) {
|
|
82
|
+
if (map.size < expectedCount) return false;
|
|
83
|
+
for (let i = 0; i < expectedCount; i++) {
|
|
84
|
+
if (!map.has(i)) return false;
|
|
85
|
+
}
|
|
86
|
+
return true;
|
|
87
|
+
}
|
|
81
88
|
function parseEntries(data, expectedCount) {
|
|
82
89
|
if (!Array.isArray(data)) {
|
|
83
90
|
if (data && typeof data === "object") {
|
|
@@ -93,7 +100,7 @@ function parseEntries(data, expectedCount) {
|
|
|
93
100
|
if (!entry || typeof entry !== "object") continue;
|
|
94
101
|
const obj = entry;
|
|
95
102
|
const idx = typeof obj.index === "number" ? obj.index : void 0;
|
|
96
|
-
if (idx === void 0 || idx < 0 || idx >= expectedCount) continue;
|
|
103
|
+
if (idx === void 0 || !Number.isInteger(idx) || idx < 0 || idx >= expectedCount) continue;
|
|
97
104
|
const verdictRaw = typeof obj.verdict === "string" ? obj.verdict : void 0;
|
|
98
105
|
if (!verdictRaw || !VALID_VERDICTS.has(verdictRaw)) continue;
|
|
99
106
|
const rationale = typeof obj.rationale === "string" && obj.rationale.trim().length > 0 ? obj.rationale.trim().slice(0, 500) : void 0;
|
|
@@ -105,7 +112,7 @@ function parseEntries(data, expectedCount) {
|
|
|
105
112
|
}
|
|
106
113
|
return map.size > 0 ? map : null;
|
|
107
114
|
}
|
|
108
|
-
async function callFaithfulnessLlm(systemPrompt, userPrompt, config, localLlm, fallbackLlm, timeoutMs, signal, fetchImpl = fetch) {
|
|
115
|
+
async function callFaithfulnessLlm(systemPrompt, userPrompt, expectedCount, config, localLlm, fallbackLlm, timeoutMs, signal, fetchImpl = fetch) {
|
|
109
116
|
const messages = [
|
|
110
117
|
{ role: "system", content: systemPrompt },
|
|
111
118
|
{ role: "user", content: userPrompt }
|
|
@@ -116,15 +123,33 @@ async function callFaithfulnessLlm(systemPrompt, userPrompt, config, localLlm, f
|
|
|
116
123
|
const result = await callOpenAiCompatibleChat(
|
|
117
124
|
localEndpoint,
|
|
118
125
|
messages,
|
|
119
|
-
{
|
|
126
|
+
{
|
|
127
|
+
temperature: 0.1,
|
|
128
|
+
maxTokens: 2048,
|
|
129
|
+
responseFormatJson: true,
|
|
130
|
+
timeoutMs: probeBudgetMs,
|
|
131
|
+
// Forward the batch signal so the probe aborts the instant the batch
|
|
132
|
+
// budget elapses, not after probeBudgetMs (issue #1700 nit #5).
|
|
133
|
+
...signal ? { signal } : {}
|
|
134
|
+
},
|
|
120
135
|
fetchImpl
|
|
121
136
|
);
|
|
122
137
|
if (result?.content) {
|
|
123
|
-
|
|
138
|
+
if (!config.extractionFaithfulnessLocalParseFallback) {
|
|
139
|
+
return { content: result.content, modelUsed: result.modelUsed };
|
|
140
|
+
}
|
|
141
|
+
const parsedLocal = parseFaithfulnessResponse(result.content, expectedCount);
|
|
142
|
+
if (parsedLocal && coversAllIndexes(parsedLocal, expectedCount)) {
|
|
143
|
+
return { content: result.content, modelUsed: result.modelUsed };
|
|
144
|
+
}
|
|
145
|
+
log.debug(
|
|
146
|
+
"extraction-faithfulness: local endpoint returned incomplete/unparseable output; falling back to configured chain"
|
|
147
|
+
);
|
|
148
|
+
} else {
|
|
149
|
+
log.debug(
|
|
150
|
+
"extraction-faithfulness: local model-lab endpoint unavailable, trying configured chain"
|
|
151
|
+
);
|
|
124
152
|
}
|
|
125
|
-
log.debug(
|
|
126
|
-
"extraction-faithfulness: local model-lab endpoint unavailable, trying configured chain"
|
|
127
|
-
);
|
|
128
153
|
}
|
|
129
154
|
const modelOverride = localEndpoint ? void 0 : config.extractionFaithfulnessModel || void 0;
|
|
130
155
|
const skipLocal = config.modelSource === "gateway" || Boolean(modelOverride);
|
|
@@ -215,6 +240,7 @@ async function checkFaithfulnessBatch(inputs, config, localLlm, fallbackLlm, fet
|
|
|
215
240
|
const callPromise = callFaithfulnessLlm(
|
|
216
241
|
FAITHFULNESS_SYSTEM_PROMPT,
|
|
217
242
|
userPrompt,
|
|
243
|
+
checkableInputs.length,
|
|
218
244
|
config,
|
|
219
245
|
localLlm,
|
|
220
246
|
fallbackLlm,
|
|
@@ -659,4 +685,4 @@ export {
|
|
|
659
685
|
serializeFaithfulnessFields,
|
|
660
686
|
parseFaithfulnessField
|
|
661
687
|
};
|
|
662
|
-
//# sourceMappingURL=chunk-
|
|
688
|
+
//# sourceMappingURL=chunk-YTU7WKYN.js.map
|