@remnic/core 9.62.1 → 9.62.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/access-admin-ops-surface.d.ts +11 -11
- package/dist/access-admin-ops-surface.js +26 -26
- package/dist/access-audit.js +2 -2
- package/dist/access-authorization-probe.d.ts +11 -11
- package/dist/access-authorization-probe.js +27 -27
- package/dist/access-boundary.d.ts +11 -11
- package/dist/access-boundary.js +26 -26
- package/dist/access-cli.js +88 -86
- package/dist/access-cli.js.map +1 -1
- package/dist/access-coding-context-resolution.d.ts +1 -1
- package/dist/access-extraction-force-flush.d.ts +11 -11
- package/dist/access-extraction-force-flush.js +26 -26
- package/dist/access-health-types.d.ts +1 -1
- package/dist/access-http-lcm-compaction.d.ts +11 -11
- package/dist/access-http-lifecycle-flush.d.ts +11 -11
- package/dist/access-http-offline-stream.d.ts +11 -11
- package/dist/access-http-query.js +26 -26
- package/dist/access-http.d.ts +12 -12
- package/dist/access-http.js +36 -36
- package/dist/access-identity-continuity-surface.d.ts +9 -9
- package/dist/access-identity-continuity-surface.js +26 -26
- package/dist/access-lcm-surface.d.ts +11 -11
- package/dist/access-lcm-surface.js +26 -26
- package/dist/access-mcp.d.ts +11 -11
- package/dist/access-mcp.js +31 -31
- package/dist/access-memory-search-fanout.d.ts +2 -2
- package/dist/{access-namespace-preflight-EMvicnrb.d.ts → access-namespace-preflight-yO4LMGFH.d.ts} +1 -1
- package/dist/access-namespace-preflight.d.ts +3 -3
- package/dist/access-namespace-preflight.js +26 -26
- package/dist/access-observe-write-surface.d.ts +11 -11
- package/dist/access-observe-write-surface.js +26 -26
- package/dist/access-offline-manifest.d.ts +9 -9
- package/dist/access-offline-manifest.js +2 -2
- package/dist/access-operations-batch.js +27 -27
- package/dist/access-operations.d.ts +11 -11
- package/dist/access-operations.js +30 -30
- package/dist/access-recall-concurrency.d.ts +11 -11
- package/dist/access-recall-concurrency.js +26 -26
- package/dist/access-recall-response.d.ts +11 -11
- package/dist/access-recall-response.js +26 -26
- package/dist/access-recall-surface.d.ts +11 -11
- package/dist/access-recall-surface.js +26 -26
- package/dist/{access-service-BeDYQQ62.d.ts → access-service-M4LgO141.d.ts} +7 -7
- package/dist/access-service-helpers.d.ts +11 -11
- package/dist/access-service.d.ts +11 -11
- package/dist/access-service.js +26 -26
- package/dist/access-surface-catalog.d.ts +11 -11
- package/dist/access-surface-catalog.js +28 -28
- package/dist/access-wearables-meetings-surface.d.ts +3 -3
- package/dist/action-confidence.d.ts +1 -1
- package/dist/active-memory-bridge.d.ts +1 -1
- package/dist/active-recall.d.ts +1 -1
- package/dist/active-recall.js +1 -1
- package/dist/ambient-provenance.d.ts +1 -1
- package/dist/artifact-search.d.ts +1 -1
- package/dist/{auto-sync-FMWQQB3J.js → auto-sync-Z52VWMNC.js} +3 -3
- package/dist/behavior-learner.d.ts +1 -1
- package/dist/behavior-learner.js +2 -2
- package/dist/behavior-signals.d.ts +1 -1
- package/dist/bootstrap.d.ts +9 -9
- package/dist/briefing-window.d.ts +2 -2
- package/dist/briefing.d.ts +2 -2
- package/dist/briefing.js +11 -10
- package/dist/buffer-surprise-report.d.ts +1 -1
- package/dist/buffer-turn-helpers.d.ts +1 -1
- package/dist/buffer.d.ts +2 -2
- package/dist/bulk-import/index.d.ts +3 -3
- package/dist/calibration.d.ts +1 -1
- package/dist/capabilities.d.ts +1 -1
- package/dist/{catalog-B2SxZ6LU.d.ts → catalog-CyYTf_ok.d.ts} +1 -1
- package/dist/causal-behavior.d.ts +1 -1
- package/dist/causal-behavior.js +3 -3
- package/dist/causal-chain.js +3 -3
- package/dist/causal-consolidation.d.ts +1 -1
- package/dist/causal-consolidation.js +14 -14
- package/dist/causal-retrieval.js +3 -3
- package/dist/causal-trajectory-graph.d.ts +1 -1
- package/dist/causal-trajectory.js +2 -2
- package/dist/{chunk-B2QHVLJO.js → chunk-256FBCVX.js} +22 -10
- package/dist/chunk-256FBCVX.js.map +1 -0
- package/dist/{chunk-QP2IZTUR.js → chunk-2TYIAKU5.js} +2 -2
- package/dist/{chunk-QNMNNFKD.js → chunk-347ZR6D4.js} +2 -2
- package/dist/{chunk-76YNCJ5H.js → chunk-3F3CVVDS.js} +2 -2
- package/dist/{chunk-KCFZOSR6.js → chunk-3MA7JVXN.js} +4 -4
- package/dist/{chunk-KHQ57QLJ.js → chunk-46WM6JX2.js} +7 -3
- package/dist/chunk-46WM6JX2.js.map +1 -0
- package/dist/chunk-47DU4SGJ.js +92 -0
- package/dist/chunk-47DU4SGJ.js.map +1 -0
- package/dist/{chunk-HKYNBEL4.js → chunk-4FFROSFG.js} +37 -14
- package/dist/{chunk-HKYNBEL4.js.map → chunk-4FFROSFG.js.map} +1 -1
- package/dist/{chunk-TLUSSS2F.js → chunk-4HO3542O.js} +2 -2
- package/dist/{chunk-4E67XCT2.js → chunk-4IZ2IT7D.js} +3 -3
- package/dist/{chunk-33JBK2XP.js → chunk-5F6HMNMZ.js} +2 -2
- package/dist/{chunk-5WQMORU5.js → chunk-5PFGMO33.js} +2 -2
- package/dist/{chunk-6HEM6HTQ.js → chunk-6GGTATZF.js} +2 -2
- package/dist/{chunk-UIRU3MIJ.js → chunk-7BJYTX6Q.js} +2 -2
- package/dist/{chunk-2GRLJMKJ.js → chunk-7DRSWPUV.js} +3 -3
- package/dist/{chunk-TVVEYCNW.js → chunk-7K5Q6COX.js} +4 -4
- package/dist/{chunk-HXXGZ4KV.js → chunk-ALNZEWGN.js} +2 -2
- package/dist/{chunk-5WVUO6QT.js → chunk-AR253JBM.js} +1 -1
- package/dist/chunk-AR253JBM.js.map +1 -0
- package/dist/{chunk-67MKNKJQ.js → chunk-AYIHDC5S.js} +2 -2
- package/dist/{chunk-IXJ5U6ZL.js → chunk-BBHFAVMP.js} +8 -8
- package/dist/{chunk-IIRK5V5Z.js → chunk-BHO6RHE5.js} +3 -3
- package/dist/{chunk-WANOCU3K.js → chunk-BP6WMYLP.js} +3 -3
- package/dist/{chunk-ZJKLGS76.js → chunk-CALURYWR.js} +283 -248
- package/dist/chunk-CALURYWR.js.map +1 -0
- package/dist/{chunk-JLMH5YMU.js → chunk-CH627RRV.js} +2 -2
- package/dist/{chunk-XIABRKF6.js → chunk-CLJ5QS6J.js} +239 -47
- package/dist/chunk-CLJ5QS6J.js.map +1 -0
- package/dist/{chunk-YLHM5BQQ.js → chunk-DCUMFQYM.js} +171 -8
- package/dist/chunk-DCUMFQYM.js.map +1 -0
- package/dist/{chunk-ZBJMUXZH.js → chunk-DJ7HMNSL.js} +15 -8
- package/dist/chunk-DJ7HMNSL.js.map +1 -0
- package/dist/{chunk-WTMG5GAK.js → chunk-DROAPP6N.js} +3 -3
- package/dist/{chunk-PBH2Z2NY.js → chunk-DTLF2SLZ.js} +2 -2
- package/dist/{chunk-7JAXC526.js → chunk-EFWHCTYJ.js} +2 -2
- package/dist/{chunk-3XG4QEA2.js → chunk-FF6E6HOT.js} +39 -39
- package/dist/{chunk-NP7FLVZW.js → chunk-G2FCSILA.js} +2 -2
- package/dist/{chunk-7PVTOZR4.js → chunk-H23GIXJC.js} +2 -2
- package/dist/{chunk-WT6UL3UA.js → chunk-H7PRHUBD.js} +2 -2
- package/dist/{chunk-ETCVSZLG.js → chunk-HSBQJRV2.js} +2 -2
- package/dist/{chunk-GZRDOVQN.js → chunk-HVKMJAEF.js} +2 -2
- package/dist/{chunk-CSOYVTRX.js → chunk-IIPJKCZB.js} +3 -3
- package/dist/{chunk-E57E5SCS.js → chunk-IRLH4NM2.js} +3 -3
- package/dist/{chunk-4G45LJJP.js → chunk-IZRNVNPV.js} +2 -2
- package/dist/{chunk-YSUSUZR4.js → chunk-JCJGYNIS.js} +3 -3
- package/dist/{chunk-EU74U4GT.js → chunk-JDI7G6EA.js} +2 -2
- package/dist/{chunk-QWPAQLYV.js → chunk-JFLKSD5V.js} +2 -2
- package/dist/{chunk-KQS72GCR.js → chunk-LJOIZPJH.js} +2 -2
- package/dist/{chunk-U27G4E5G.js → chunk-LLGDVG52.js} +3 -3
- package/dist/{chunk-7N7DB4L5.js → chunk-LTJTP5YQ.js} +10 -9
- package/dist/chunk-LTJTP5YQ.js.map +1 -0
- package/dist/{chunk-XL3TATMJ.js → chunk-OQIRBGUU.js} +21 -12
- package/dist/chunk-OQIRBGUU.js.map +1 -0
- package/dist/{chunk-JGW2EUCQ.js → chunk-PMRUMGK6.js} +2 -2
- package/dist/{chunk-3G6YU5YD.js → chunk-PSNN25DW.js} +2 -2
- package/dist/{chunk-LRGSLV7M.js → chunk-PYHOAXTI.js} +4 -4
- package/dist/{chunk-75U2FR7U.js → chunk-QCI73Z7C.js} +2 -2
- package/dist/{chunk-EHMMRZOZ.js → chunk-QICOU4RY.js} +2 -2
- package/dist/{chunk-K4WIUTNH.js → chunk-RFH7U5LT.js} +2 -2
- package/dist/{chunk-4SGDYYWV.js → chunk-RPKJHYVE.js} +2 -2
- package/dist/{chunk-BHO3IVAN.js → chunk-RYST72N5.js} +12 -1
- package/dist/chunk-RYST72N5.js.map +1 -0
- package/dist/chunk-T3GIETKV.js +152 -0
- package/dist/chunk-T3GIETKV.js.map +1 -0
- package/dist/{chunk-DYDACAK2.js → chunk-TGSMU3F2.js} +3 -3
- package/dist/{chunk-MJFDJTDC.js → chunk-TIRJV2LW.js} +2 -2
- package/dist/{chunk-QRA3XVJX.js → chunk-UDTME32W.js} +2 -2
- package/dist/{chunk-LAM6UDFV.js → chunk-WMOJIOIG.js} +2 -2
- package/dist/{chunk-LLLY5IBK.js → chunk-WR2YKUIW.js} +2 -2
- package/dist/{chunk-KYI3CM42.js → chunk-X6E7TT3A.js} +2 -2
- package/dist/{chunk-QN7XQEIT.js → chunk-YIIC5IDU.js} +2 -2
- package/dist/{chunk-JDJOAL4B.js → chunk-YSR3DXGC.js} +2 -2
- package/dist/{chunk-LBJBNWS2.js → chunk-YTHQHH5U.js} +2 -2
- package/dist/{chunk-JF6YSHJM.js → chunk-ZPGHA7EO.js} +12 -12
- package/dist/{chunk-VUDALPI5.js → chunk-ZQKXRKMR.js} +19 -5
- package/dist/chunk-ZQKXRKMR.js.map +1 -0
- package/dist/{chunk-YG56A6XY.js → chunk-ZS4JADYY.js} +3 -3
- package/dist/{cli-DB_uakTc.d.ts → cli-Bw9z-KqX.d.ts} +5 -5
- package/dist/cli.d.ts +13 -13
- package/dist/cli.js +60 -60
- package/dist/coding/pre-action-gate.d.ts +1 -1
- package/dist/coding/pre-action-gate.js +3 -3
- package/dist/compounding/engine.d.ts +2 -2
- package/dist/compounding/engine.js +11 -10
- 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 +1 -1
- package/dist/connectors/codex-materialize-runner.d.ts +1 -1
- package/dist/connectors/codex-materialize-runner.js +11 -10
- package/dist/connectors/codex-materialize.d.ts +1 -1
- package/dist/connectors/index.d.ts +1 -1
- package/dist/connectors/index.js +11 -10
- package/dist/consolidation-provenance-check.d.ts +2 -2
- package/dist/consolidation-undo.d.ts +2 -2
- package/dist/contradiction/index.d.ts +2 -2
- package/dist/converge-config.d.ts +1 -1
- package/dist/convergence-refresh.d.ts +2 -2
- package/dist/convergence-refresh.js +13 -12
- package/dist/conversation-index/backend.d.ts +1 -1
- package/dist/conversation-index/chunker.d.ts +1 -1
- package/dist/conversation-index/faiss-adapter.d.ts +1 -1
- package/dist/conversation-index/indexer.d.ts +1 -1
- package/dist/conversation-index/search.d.ts +1 -1
- package/dist/corpus-watermark.d.ts +1 -1
- package/dist/corpus-watermark.js +13 -12
- package/dist/day-summary.d.ts +1 -1
- package/dist/delinearize.d.ts +1 -1
- package/dist/dependency-propagation-config.d.ts +1 -1
- package/dist/{dependency-propagation-delivery-DcOVpK3y.d.ts → dependency-propagation-delivery-BxhvAppj.d.ts} +1 -1
- package/dist/direct-answer-wiring.d.ts +1 -1
- package/dist/direct-answer-wiring.js +3 -3
- package/dist/direct-answer.d.ts +1 -1
- package/dist/direct-answer.js +2 -2
- package/dist/embedding-fallback.d.ts +1 -1
- package/dist/enrichment/index.d.ts +1 -1
- package/dist/entity-origin-fields.d.ts +1 -1
- package/dist/entity-retrieval.d.ts +2 -2
- package/dist/entity-retrieval.js +11 -10
- package/dist/entity-schema.d.ts +1 -1
- package/dist/episodic-context.d.ts +92 -0
- package/dist/episodic-context.js +16 -0
- package/dist/episodic-context.js.map +1 -0
- package/dist/explicit-capture.d.ts +9 -9
- package/dist/external-wiki-access.d.ts +11 -11
- package/dist/external-wiki-access.js +27 -27
- package/dist/external-wiki-collection-registration.d.ts +1 -1
- package/dist/external-wiki-collection.d.ts +1 -1
- package/dist/external-wiki-mcp-tools.d.ts +11 -11
- package/dist/extraction-error-classification.d.ts +1 -1
- package/dist/extraction-faithfulness.d.ts +1 -1
- package/dist/extraction-judge-telemetry.d.ts +1 -1
- package/dist/extraction-judge-training.d.ts +1 -1
- package/dist/extraction-judge.d.ts +1 -1
- package/dist/extraction-liveness.d.ts +1 -1
- package/dist/extraction-normalization.d.ts +1 -1
- package/dist/extraction-normalization.js +2 -2
- package/dist/extraction-prompt.d.ts +1 -1
- package/dist/extraction-source-grounding-rules.d.ts +1 -1
- package/dist/extraction-source-grounding.d.ts +1 -1
- package/dist/extraction.d.ts +1 -1
- package/dist/extraction.js +14 -14
- package/dist/fallback-llm.d.ts +1 -1
- package/dist/{forget-5TWK7CZT.js → forget-SZ2BXDGF.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-path-reconstruction.d.ts +1 -1
- package/dist/graph-path-scoring.d.ts +1 -1
- package/dist/graph-snapshot.d.ts +1 -1
- package/dist/graph.d.ts +1 -1
- package/dist/harmonic-construction.js +2 -2
- package/dist/harmonic-retrieval.js +2 -2
- package/dist/importance.d.ts +1 -1
- package/dist/importers/index.d.ts +1 -1
- package/dist/in-flight-reads.d.ts +1 -1
- package/dist/index.d.ts +21 -21
- package/dist/index.js +100 -98
- package/dist/intent.d.ts +1 -1
- package/dist/lcm/engine.d.ts +8 -2
- package/dist/lcm/engine.js +4 -4
- package/dist/lcm/index.d.ts +1 -1
- package/dist/lcm/index.js +9 -9
- package/dist/lcm/tools.d.ts +1 -1
- package/dist/lifecycle.d.ts +1 -1
- package/dist/live-connectors-runner.d.ts +1 -1
- package/dist/local-llm.d.ts +1 -1
- package/dist/local-model-endpoint.d.ts +1 -1
- package/dist/maintenance/memory-governance.d.ts +1 -1
- package/dist/maintenance/memory-governance.js +11 -10
- package/dist/maintenance/rebuild-memory-lifecycle-ledger.d.ts +2 -2
- package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +11 -10
- package/dist/maintenance/rebuild-memory-projection.d.ts +2 -2
- package/dist/maintenance/rebuild-memory-projection.js +12 -11
- package/dist/{maintenance-5c1olVtB.d.ts → maintenance-uJb74j64.d.ts} +3 -3
- package/dist/mcp-memory-inspector-app.d.ts +11 -11
- package/dist/memory-action-policy.d.ts +1 -1
- package/dist/memory-cache.d.ts +1 -1
- package/dist/memory-lifecycle-ledger-utils.d.ts +1 -1
- package/dist/memory-projection-store.d.ts +1 -1
- package/dist/memory-provenance.d.ts +1 -1
- package/dist/memory-snapshot.d.ts +1 -1
- package/dist/memory-worth-outcomes.d.ts +2 -2
- package/dist/models-json.d.ts +1 -1
- package/dist/namespaces/migrate.d.ts +3 -3
- package/dist/namespaces/migrate.js +12 -11
- 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 +3 -3
- package/dist/namespaces/storage.js +11 -10
- package/dist/native-knowledge.d.ts +1 -1
- package/dist/offline-sync-impression-drain.d.ts +1 -1
- package/dist/operator-doctor-corpus.d.ts +1 -1
- package/dist/operator-doctor-corpus.js +14 -13
- package/dist/operator-doctor-replica.d.ts +1 -1
- package/dist/operator-toolkit.d.ts +3 -3
- package/dist/operator-toolkit.js +19 -18
- package/dist/orchestration/compression-guideline-coordinator.d.ts +2 -2
- package/dist/orchestration/maintenance.d.ts +4 -4
- package/dist/orchestration/maintenance.js +16 -15
- package/dist/{orchestrator-HPuY6I4i.d.ts → orchestrator-CFi-5JSR.d.ts} +23 -8
- package/dist/orchestrator.d.ts +9 -9
- package/dist/orchestrator.js +88 -86
- package/dist/patterns-cli.d.ts +1 -1
- package/dist/{pipeline-CvVe1Q2_.d.ts → pipeline-BdF3ferY.d.ts} +1 -1
- package/dist/policy-runtime.d.ts +1 -1
- package/dist/policy-runtime.js +3 -3
- package/dist/proactive-contention.d.ts +1 -1
- package/dist/provenance.d.ts +1 -1
- package/dist/{public-http-D0JKFkyf.d.ts → public-http-DK-QwaBu.d.ts} +1 -1
- package/dist/{qmd-Bd0Tp76_.d.ts → qmd-D_62bYNl.d.ts} +1 -1
- package/dist/qmd-preflight.d.ts +2 -2
- package/dist/qmd-recall-cache.d.ts +1 -1
- package/dist/qmd.d.ts +2 -2
- package/dist/recall-concurrency-config.d.ts +1 -1
- package/dist/recall-disclosure-escalation.d.ts +1 -1
- package/dist/recall-explain-renderer.d.ts +1 -1
- package/dist/recall-explain-renderer.js +3 -3
- package/dist/recall-memory-map.d.ts +1 -1
- package/dist/recall-planner-llm.d.ts +1 -1
- package/dist/recall-query-policy.js +2 -2
- package/dist/recall-state.d.ts +1 -1
- package/dist/recall-tag-filter.d.ts +1 -1
- package/dist/recall-timings.d.ts +1 -1
- package/dist/recall-tokenization.d.ts +3 -1
- package/dist/recall-tokenization.js +5 -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/reconcile/cursor.d.ts +1 -1
- package/dist/reconcile/manifest.d.ts +10 -1
- package/dist/reconcile/manifest.js +1 -1
- package/dist/reconcile/plan.d.ts +1 -1
- package/dist/replay/normalizers/chatgpt.d.ts +1 -1
- package/dist/replay/normalizers/claude.d.ts +1 -1
- package/dist/replay/normalizers/openclaw.d.ts +1 -1
- package/dist/replay/normalizers/shared.d.ts +1 -1
- package/dist/replay/runner.d.ts +1 -1
- package/dist/replay/types.d.ts +1 -1
- package/dist/replica-divergence.d.ts +1 -1
- package/dist/replica-peers-config.d.ts +1 -1
- package/dist/resolve-auth-token.d.ts +1 -1
- package/dist/resume-bundles.js +4 -4
- package/dist/retrieval-agents.d.ts +2 -2
- package/dist/retrieval-tiers.d.ts +1 -1
- package/dist/routing/engine.d.ts +1 -1
- package/dist/routing/store.d.ts +1 -1
- package/dist/salvage-envelope.d.ts +1 -1
- package/dist/{scope-profiles-ClLtm9gK.d.ts → scope-profiles-CeMv7pP0.d.ts} +1 -1
- package/dist/search/embed-helper.d.ts +1 -1
- package/dist/search/factory.d.ts +1 -1
- package/dist/search/factory.js +5 -4
- package/dist/search/index.d.ts +1 -1
- package/dist/search/index.js +9 -8
- package/dist/search/lancedb-backend.d.ts +14 -1
- package/dist/search/lancedb-backend.js +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 +22 -1
- package/dist/search/orama-backend.js +2 -1
- package/dist/search/port.d.ts +1 -1
- package/dist/search/remote-backend.d.ts +1 -1
- package/dist/{semantic-consolidation-B1EkeEDj.d.ts → semantic-consolidation-B-85brYj.d.ts} +1 -1
- package/dist/semantic-consolidation.d.ts +2 -2
- package/dist/semantic-consolidation.js +12 -12
- package/dist/semantic-rule-promotion.js +11 -10
- package/dist/semantic-rule-verifier.d.ts +1 -1
- package/dist/semantic-rule-verifier.js +11 -11
- package/dist/{service-Cf3ANQj9.d.ts → service-CoO0HA2E.d.ts} +2 -2
- package/dist/session-observer-bands.d.ts +1 -1
- package/dist/session-observer-state.d.ts +1 -1
- package/dist/shared-context/manager.d.ts +1 -1
- package/dist/signal.d.ts +1 -1
- package/dist/source-agent-qualifier.d.ts +1 -1
- package/dist/source-agent-qualifier.js +11 -10
- package/dist/{storage-DS2O_6Qt.d.ts → storage-BVAVitkO.d.ts} +1 -1
- package/dist/storage.d.ts +2 -2
- package/dist/storage.js +10 -9
- package/dist/summarizer.d.ts +1 -1
- package/dist/summary-snapshot.d.ts +1 -1
- package/dist/support-passport/index.d.ts +14 -14
- package/dist/support-passport/index.js +29 -29
- package/dist/temporal-supersession.d.ts +2 -2
- package/dist/temporal-timeline-recall.d.ts +1 -1
- package/dist/temporal-validity.d.ts +1 -1
- package/dist/threading.d.ts +1 -1
- package/dist/tier-migration.d.ts +2 -2
- package/dist/tier-routing.d.ts +1 -1
- package/dist/topics.d.ts +1 -1
- package/dist/transcript.d.ts +1 -1
- package/dist/transfer/import-sqlite.js +2 -2
- package/dist/trust-score-stage.d.ts +1 -1
- package/dist/trust-score.d.ts +1 -1
- package/dist/trust-zones.js +2 -2
- package/dist/{types-BOANGhCJ.d.ts → types-DWHOxlZP.d.ts} +3 -0
- package/dist/types.d.ts +1 -1
- package/dist/types.js +1 -1
- package/dist/user-message-cleaning.d.ts +23 -0
- package/dist/user-message-cleaning.js +10 -0
- package/dist/user-message-cleaning.js.map +1 -0
- package/dist/utility-runtime.d.ts +1 -1
- package/dist/verified-recall.js +11 -11
- package/dist/work-product-ledger.js +2 -2
- package/dist/write-envelope.d.ts +1 -1
- package/package.json +12 -2
- package/src/access-service-offline-file-content.test.ts +1 -0
- package/src/config.ts +11 -0
- package/src/episodic-context-recall.integration.test.ts +169 -0
- package/src/episodic-context.test.ts +266 -0
- package/src/episodic-context.ts +274 -0
- package/src/lcm/engine.ts +18 -1
- package/src/lifecycle/tombstones.test.ts +134 -0
- package/src/lifecycle/tombstones.ts +29 -2
- package/src/orchestration/episodic-context-section.ts +255 -0
- package/src/orchestration/recall-internal-deps.ts +2 -0
- package/src/orchestration/recall-internal.ts +40 -25
- package/src/orchestration/recall-result-formatter.ts +37 -0
- package/src/recall-tokenization.ts +14 -8
- package/src/reconcile/manifest.test.ts +133 -4
- package/src/reconcile/manifest.ts +43 -7
- package/src/search/factory.ts +1 -0
- package/src/search/lancedb-backend.ts +24 -16
- package/src/search/orama-backend.test.ts +208 -1
- package/src/search/orama-backend.ts +133 -18
- package/src/search/orama-cjk-tokenizer.test.ts +108 -0
- package/src/search/orama-cjk-tokenizer.ts +143 -0
- package/src/storage/tombstone-migration-sources.test.ts +116 -0
- package/src/storage/tombstone-migration-sources.ts +90 -0
- package/src/storage.ts +13 -34
- package/src/types.ts +3 -3
- package/src/user-message-cleaning.ts +139 -0
- package/dist/chunk-5WVUO6QT.js.map +0 -1
- package/dist/chunk-7N7DB4L5.js.map +0 -1
- package/dist/chunk-B2QHVLJO.js.map +0 -1
- package/dist/chunk-BHO3IVAN.js.map +0 -1
- package/dist/chunk-KHQ57QLJ.js.map +0 -1
- package/dist/chunk-VUDALPI5.js.map +0 -1
- package/dist/chunk-XIABRKF6.js.map +0 -1
- package/dist/chunk-XL3TATMJ.js.map +0 -1
- package/dist/chunk-YLHM5BQQ.js.map +0 -1
- package/dist/chunk-ZBJMUXZH.js.map +0 -1
- package/dist/chunk-ZJKLGS76.js.map +0 -1
- /package/dist/{auto-sync-FMWQQB3J.js.map → auto-sync-Z52VWMNC.js.map} +0 -0
- /package/dist/{chunk-QP2IZTUR.js.map → chunk-2TYIAKU5.js.map} +0 -0
- /package/dist/{chunk-QNMNNFKD.js.map → chunk-347ZR6D4.js.map} +0 -0
- /package/dist/{chunk-76YNCJ5H.js.map → chunk-3F3CVVDS.js.map} +0 -0
- /package/dist/{chunk-KCFZOSR6.js.map → chunk-3MA7JVXN.js.map} +0 -0
- /package/dist/{chunk-TLUSSS2F.js.map → chunk-4HO3542O.js.map} +0 -0
- /package/dist/{chunk-4E67XCT2.js.map → chunk-4IZ2IT7D.js.map} +0 -0
- /package/dist/{chunk-33JBK2XP.js.map → chunk-5F6HMNMZ.js.map} +0 -0
- /package/dist/{chunk-5WQMORU5.js.map → chunk-5PFGMO33.js.map} +0 -0
- /package/dist/{chunk-6HEM6HTQ.js.map → chunk-6GGTATZF.js.map} +0 -0
- /package/dist/{chunk-UIRU3MIJ.js.map → chunk-7BJYTX6Q.js.map} +0 -0
- /package/dist/{chunk-2GRLJMKJ.js.map → chunk-7DRSWPUV.js.map} +0 -0
- /package/dist/{chunk-TVVEYCNW.js.map → chunk-7K5Q6COX.js.map} +0 -0
- /package/dist/{chunk-HXXGZ4KV.js.map → chunk-ALNZEWGN.js.map} +0 -0
- /package/dist/{chunk-67MKNKJQ.js.map → chunk-AYIHDC5S.js.map} +0 -0
- /package/dist/{chunk-IXJ5U6ZL.js.map → chunk-BBHFAVMP.js.map} +0 -0
- /package/dist/{chunk-IIRK5V5Z.js.map → chunk-BHO6RHE5.js.map} +0 -0
- /package/dist/{chunk-WANOCU3K.js.map → chunk-BP6WMYLP.js.map} +0 -0
- /package/dist/{chunk-JLMH5YMU.js.map → chunk-CH627RRV.js.map} +0 -0
- /package/dist/{chunk-WTMG5GAK.js.map → chunk-DROAPP6N.js.map} +0 -0
- /package/dist/{chunk-PBH2Z2NY.js.map → chunk-DTLF2SLZ.js.map} +0 -0
- /package/dist/{chunk-7JAXC526.js.map → chunk-EFWHCTYJ.js.map} +0 -0
- /package/dist/{chunk-3XG4QEA2.js.map → chunk-FF6E6HOT.js.map} +0 -0
- /package/dist/{chunk-NP7FLVZW.js.map → chunk-G2FCSILA.js.map} +0 -0
- /package/dist/{chunk-7PVTOZR4.js.map → chunk-H23GIXJC.js.map} +0 -0
- /package/dist/{chunk-WT6UL3UA.js.map → chunk-H7PRHUBD.js.map} +0 -0
- /package/dist/{chunk-ETCVSZLG.js.map → chunk-HSBQJRV2.js.map} +0 -0
- /package/dist/{chunk-GZRDOVQN.js.map → chunk-HVKMJAEF.js.map} +0 -0
- /package/dist/{chunk-CSOYVTRX.js.map → chunk-IIPJKCZB.js.map} +0 -0
- /package/dist/{chunk-E57E5SCS.js.map → chunk-IRLH4NM2.js.map} +0 -0
- /package/dist/{chunk-4G45LJJP.js.map → chunk-IZRNVNPV.js.map} +0 -0
- /package/dist/{chunk-YSUSUZR4.js.map → chunk-JCJGYNIS.js.map} +0 -0
- /package/dist/{chunk-EU74U4GT.js.map → chunk-JDI7G6EA.js.map} +0 -0
- /package/dist/{chunk-QWPAQLYV.js.map → chunk-JFLKSD5V.js.map} +0 -0
- /package/dist/{chunk-KQS72GCR.js.map → chunk-LJOIZPJH.js.map} +0 -0
- /package/dist/{chunk-U27G4E5G.js.map → chunk-LLGDVG52.js.map} +0 -0
- /package/dist/{chunk-JGW2EUCQ.js.map → chunk-PMRUMGK6.js.map} +0 -0
- /package/dist/{chunk-3G6YU5YD.js.map → chunk-PSNN25DW.js.map} +0 -0
- /package/dist/{chunk-LRGSLV7M.js.map → chunk-PYHOAXTI.js.map} +0 -0
- /package/dist/{chunk-75U2FR7U.js.map → chunk-QCI73Z7C.js.map} +0 -0
- /package/dist/{chunk-EHMMRZOZ.js.map → chunk-QICOU4RY.js.map} +0 -0
- /package/dist/{chunk-K4WIUTNH.js.map → chunk-RFH7U5LT.js.map} +0 -0
- /package/dist/{chunk-4SGDYYWV.js.map → chunk-RPKJHYVE.js.map} +0 -0
- /package/dist/{chunk-DYDACAK2.js.map → chunk-TGSMU3F2.js.map} +0 -0
- /package/dist/{chunk-MJFDJTDC.js.map → chunk-TIRJV2LW.js.map} +0 -0
- /package/dist/{chunk-QRA3XVJX.js.map → chunk-UDTME32W.js.map} +0 -0
- /package/dist/{chunk-LAM6UDFV.js.map → chunk-WMOJIOIG.js.map} +0 -0
- /package/dist/{chunk-LLLY5IBK.js.map → chunk-WR2YKUIW.js.map} +0 -0
- /package/dist/{chunk-KYI3CM42.js.map → chunk-X6E7TT3A.js.map} +0 -0
- /package/dist/{chunk-QN7XQEIT.js.map → chunk-YIIC5IDU.js.map} +0 -0
- /package/dist/{chunk-JDJOAL4B.js.map → chunk-YSR3DXGC.js.map} +0 -0
- /package/dist/{chunk-LBJBNWS2.js.map → chunk-YTHQHH5U.js.map} +0 -0
- /package/dist/{chunk-JF6YSHJM.js.map → chunk-ZPGHA7EO.js.map} +0 -0
- /package/dist/{chunk-YG56A6XY.js.map → chunk-ZS4JADYY.js.map} +0 -0
- /package/dist/{forget-5TWK7CZT.js.map → forget-SZ2BXDGF.js.map} +0 -0
|
@@ -18,12 +18,30 @@ import {
|
|
|
18
18
|
export const RECONCILE_MANIFEST_FORMAT = "remnic-reconcile-manifest";
|
|
19
19
|
export const RECONCILE_MANIFEST_SCHEMA_VERSION = 1;
|
|
20
20
|
const CONTENT_HASH_NORMALIZER_VERSION = 4;
|
|
21
|
+
/**
|
|
22
|
+
* Version of the identity-resolution LOGIC (alias recovery, candidate
|
|
23
|
+
* ordering), independent of the content normalizer: a cached manifest entry
|
|
24
|
+
* written before an identity-resolution change carries an older value and is
|
|
25
|
+
* reparsed even when its normalizerVersion still matches (issue #2367
|
|
26
|
+
* review round 2). Bump when parsedMemoryIdentity's output shape or
|
|
27
|
+
* semantics change.
|
|
28
|
+
*/
|
|
29
|
+
const IDENTITY_RESOLUTION_VERSION = 2;
|
|
21
30
|
|
|
22
31
|
export interface ReconcileMemoryIdentity {
|
|
23
32
|
id: string;
|
|
24
33
|
category: string;
|
|
25
34
|
contentHash: string;
|
|
35
|
+
/**
|
|
36
|
+
* Recovered current-normalizer identities for a record whose persisted hash
|
|
37
|
+
* is ambiguous under the legacy normalizer (issue #2367). The persisted
|
|
38
|
+
* hash stays primary; these participate in duplicate bucketing so a
|
|
39
|
+
* replica carrying the current form of the same fact still collapses.
|
|
40
|
+
*/
|
|
41
|
+
contentHashAliases?: readonly string[];
|
|
42
|
+
/** See IDENTITY_RESOLUTION_VERSION; absent on pre-versioning cache entries. */
|
|
26
43
|
normalizerVersion?: number;
|
|
44
|
+
identityResolutionVersion?: number;
|
|
27
45
|
status: MemoryStatus;
|
|
28
46
|
}
|
|
29
47
|
|
|
@@ -88,17 +106,34 @@ function parsedMemoryIdentity(
|
|
|
88
106
|
const legacyMatch = [...candidates].reverse().find(
|
|
89
107
|
(content) => computeLegacyContentHash(content) === storedHash
|
|
90
108
|
);
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
109
|
+
let contentHash: string;
|
|
110
|
+
let contentHashAliases: string[] | undefined;
|
|
111
|
+
if (currentMatch) {
|
|
112
|
+
contentHash = ContentHashIndex.computeHash(currentMatch);
|
|
113
|
+
} else if (legacyMatch && normalizeLegacyContent(legacyMatch).length > 0) {
|
|
114
|
+
// A non-empty legacy equality is ambiguous (issue #2367): the persisted
|
|
115
|
+
// hash may be an explicit contentHashSource identity that merely collides
|
|
116
|
+
// with the body's ASCII skeleton under the lossy legacy normalizer, and
|
|
117
|
+
// nothing in the record proves which it is. Keep the persisted hash as
|
|
118
|
+
// the primary identity and expose the recovered current identity as an
|
|
119
|
+
// alias so replicas carrying either form still collapse.
|
|
120
|
+
contentHash = storedHash ?? bodyHash;
|
|
121
|
+
const recovered = ContentHashIndex.computeHash(legacyMatch);
|
|
122
|
+
if (recovered !== contentHash) contentHashAliases = [recovered];
|
|
123
|
+
} else {
|
|
124
|
+
// An EMPTY legacy skeleton identifies nothing (every non-ASCII body maps
|
|
125
|
+
// to it), so preserving it would collapse unrelated records. Recovering
|
|
126
|
+
// the current identity here is repair, not replacement.
|
|
127
|
+
contentHash = legacyMatch ? ContentHashIndex.computeHash(legacyMatch) : storedHash ?? bodyHash;
|
|
128
|
+
}
|
|
96
129
|
|
|
97
130
|
return {
|
|
98
131
|
id: parsed.frontmatter.id,
|
|
99
132
|
category: parsed.frontmatter.category,
|
|
100
133
|
contentHash,
|
|
134
|
+
...(contentHashAliases ? { contentHashAliases } : {}),
|
|
101
135
|
normalizerVersion: CONTENT_HASH_NORMALIZER_VERSION,
|
|
136
|
+
identityResolutionVersion: IDENTITY_RESOLUTION_VERSION,
|
|
102
137
|
status: inferMemoryStatus(parsed.frontmatter, filePath),
|
|
103
138
|
};
|
|
104
139
|
}
|
|
@@ -136,7 +171,8 @@ export async function buildReconcileManifest(options: BuildReconcileManifestOpti
|
|
|
136
171
|
if (
|
|
137
172
|
cached?.sha256.toLowerCase() === file.sha256.toLowerCase() &&
|
|
138
173
|
(cached.memory === undefined ||
|
|
139
|
-
cached.memory.normalizerVersion === CONTENT_HASH_NORMALIZER_VERSION
|
|
174
|
+
(cached.memory.normalizerVersion === CONTENT_HASH_NORMALIZER_VERSION &&
|
|
175
|
+
cached.memory.identityResolutionVersion === IDENTITY_RESOLUTION_VERSION))
|
|
140
176
|
) {
|
|
141
177
|
files.push({ ...file, ...(cached.memory ? { memory: cached.memory } : {}) });
|
|
142
178
|
continue;
|
|
@@ -168,7 +204,7 @@ function activeFactByPath(manifest: ReconcileManifest | undefined): Map<string,
|
|
|
168
204
|
}
|
|
169
205
|
|
|
170
206
|
function memoryIdentityHashes(memory: ReconcileMemoryIdentity): string[] {
|
|
171
|
-
return [memory.contentHash];
|
|
207
|
+
return [memory.contentHash, ...(memory.contentHashAliases ?? [])];
|
|
172
208
|
}
|
|
173
209
|
|
|
174
210
|
function contentHashRows(
|
package/src/search/factory.ts
CHANGED
|
@@ -79,6 +79,7 @@ function resolveNonQmdBackend(config: PluginConfig): SearchBackend | undefined {
|
|
|
79
79
|
embedHelper,
|
|
80
80
|
memoryDir: config.memoryDir,
|
|
81
81
|
embeddingDimension: config.oramaEmbeddingDimension!,
|
|
82
|
+
cjkSegmentationEnabled: config.oramaCjkSegmentation !== false,
|
|
82
83
|
});
|
|
83
84
|
}
|
|
84
85
|
|
|
@@ -221,12 +221,8 @@ export class LanceDbBackend implements SearchBackend {
|
|
|
221
221
|
rows.length > 0 && rows.every((row) => row.vectorProvider === embeddingProviderIdentity),
|
|
222
222
|
);
|
|
223
223
|
if (isSearchAborted(execution)) return;
|
|
224
|
-
//
|
|
225
|
-
|
|
226
|
-
await table.createIndex("content", { config: this.lanceIndex.fts() });
|
|
227
|
-
} catch {
|
|
228
|
-
// FTS index creation may fail on some platforms — degrade gracefully
|
|
229
|
-
}
|
|
224
|
+
// FTS index on the content column.
|
|
225
|
+
await this.createFtsIndex(table);
|
|
230
226
|
if (collection === this.collection) this.table = table;
|
|
231
227
|
} catch (err) {
|
|
232
228
|
log.debug(`LanceDbBackend update failed: ${err}`);
|
|
@@ -365,11 +361,7 @@ export class LanceDbBackend implements SearchBackend {
|
|
|
365
361
|
vectorProvider: "",
|
|
366
362
|
};
|
|
367
363
|
const newTable = await db.createTable(collection, [emptyRow]);
|
|
368
|
-
|
|
369
|
-
await newTable.createIndex("content", { config: this.lanceIndex.fts() });
|
|
370
|
-
} catch {
|
|
371
|
-
// FTS index creation may fail — degrade gracefully
|
|
372
|
-
}
|
|
364
|
+
await this.createFtsIndex(newTable);
|
|
373
365
|
try {
|
|
374
366
|
await newTable.delete("docid = '__placeholder__'");
|
|
375
367
|
} catch {
|
|
@@ -424,11 +416,7 @@ export class LanceDbBackend implements SearchBackend {
|
|
|
424
416
|
};
|
|
425
417
|
this.table = await db.createTable(this.collection, [emptyRow]);
|
|
426
418
|
// Create FTS index on content column
|
|
427
|
-
|
|
428
|
-
await this.table.createIndex("content", { config: this.lanceIndex.fts() });
|
|
429
|
-
} catch {
|
|
430
|
-
// FTS index creation may fail — degrade gracefully
|
|
431
|
-
}
|
|
419
|
+
await this.createFtsIndex(this.table);
|
|
432
420
|
// Remove placeholder row
|
|
433
421
|
try {
|
|
434
422
|
await this.table.delete("docid = '__placeholder__'");
|
|
@@ -438,6 +426,26 @@ export class LanceDbBackend implements SearchBackend {
|
|
|
438
426
|
return this.table;
|
|
439
427
|
}
|
|
440
428
|
|
|
429
|
+
/**
|
|
430
|
+
* Create the FTS index on the content column with the default tokenizer.
|
|
431
|
+
*
|
|
432
|
+
* Known limitation (issue #2187): tantivy's default tokenizer does not
|
|
433
|
+
* segment space-free scripts (CJK/Thai), so lexical recall over those
|
|
434
|
+
* scripts is near zero here. LanceDB's `baseTokenizer: "ngram"` option is
|
|
435
|
+
* not script-aware — it would n-gram English content too, degrading
|
|
436
|
+
* precision and bloating the index — so no CJK-capable configuration is
|
|
437
|
+
* available in the current @lancedb/lancedb API. Non-English lexical recall
|
|
438
|
+
* on this backend rides on the vector tier instead. See
|
|
439
|
+
* docs/search-backends.md ("Non-English content").
|
|
440
|
+
*/
|
|
441
|
+
private async createFtsIndex(table: any): Promise<void> {
|
|
442
|
+
try {
|
|
443
|
+
await table.createIndex("content", { config: this.lanceIndex.fts() });
|
|
444
|
+
} catch {
|
|
445
|
+
// FTS index creation may fail on some platforms — degrade gracefully
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
|
|
441
449
|
private async searchTable(
|
|
442
450
|
table: any,
|
|
443
451
|
query: string,
|
|
@@ -1,8 +1,46 @@
|
|
|
1
1
|
import assert from "node:assert/strict";
|
|
2
|
+
import { mkdir, mkdtemp, rm, writeFile } from "node:fs/promises";
|
|
3
|
+
import os from "node:os";
|
|
2
4
|
import path from "node:path";
|
|
3
5
|
import test from "node:test";
|
|
4
6
|
|
|
5
|
-
import {
|
|
7
|
+
import { EmbedHelper } from "./embed-helper.js";
|
|
8
|
+
import { OramaBackend, resolveOramaCollectionDbFilePath } from "./orama-backend.js";
|
|
9
|
+
import type { PluginConfig } from "../types.js";
|
|
10
|
+
|
|
11
|
+
function noEmbedHelper(): EmbedHelper {
|
|
12
|
+
return new EmbedHelper({} as PluginConfig);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
async function writeMemoryFact(
|
|
16
|
+
memoryDir: string,
|
|
17
|
+
fileName: string,
|
|
18
|
+
content: string,
|
|
19
|
+
): Promise<void> {
|
|
20
|
+
await mkdir(path.join(memoryDir, "facts"), { recursive: true });
|
|
21
|
+
await writeFile(path.join(memoryDir, "facts", fileName), content, "utf8");
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
async function createBackend(
|
|
25
|
+
memoryDir: string,
|
|
26
|
+
dbPath: string,
|
|
27
|
+
cjkSegmentationEnabled?: boolean,
|
|
28
|
+
options: { update?: boolean } = {},
|
|
29
|
+
): Promise<OramaBackend> {
|
|
30
|
+
const backend = new OramaBackend({
|
|
31
|
+
dbPath,
|
|
32
|
+
collection: "openclaw-engram",
|
|
33
|
+
embedHelper: noEmbedHelper(),
|
|
34
|
+
memoryDir,
|
|
35
|
+
embeddingDimension: 4,
|
|
36
|
+
cjkSegmentationEnabled,
|
|
37
|
+
});
|
|
38
|
+
assert.equal(await backend.probe(), true);
|
|
39
|
+
if (options.update !== false) {
|
|
40
|
+
await backend.update();
|
|
41
|
+
}
|
|
42
|
+
return backend;
|
|
43
|
+
}
|
|
6
44
|
|
|
7
45
|
test("Orama collection filenames cannot escape dbPath", () => {
|
|
8
46
|
const dbPath = path.join("/tmp", "remnic-orama-db");
|
|
@@ -25,3 +63,172 @@ test("Orama collection filenames cannot escape dbPath", () => {
|
|
|
25
63
|
);
|
|
26
64
|
}
|
|
27
65
|
});
|
|
66
|
+
|
|
67
|
+
test("Orama lexical search finds a Japanese fact with no embeddings, at parity with English (issue #2187)", async () => {
|
|
68
|
+
const root = await mkdtemp(path.join(os.tmpdir(), "remnic-orama-cjk-"));
|
|
69
|
+
try {
|
|
70
|
+
await writeMemoryFact(
|
|
71
|
+
root,
|
|
72
|
+
"japanese-fact.md",
|
|
73
|
+
"---\nid: mem-japanese-fact\n---\n東京都庁の所在地は新宿区にある。最寄り駅は都庁前駅だ。",
|
|
74
|
+
);
|
|
75
|
+
await writeMemoryFact(
|
|
76
|
+
root,
|
|
77
|
+
"english-fact.md",
|
|
78
|
+
"---\nid: mem-english-fact\n---\nThe Tokyo Metropolitan Government Office is located in Shinjuku. The nearest station is Tochomae.",
|
|
79
|
+
);
|
|
80
|
+
|
|
81
|
+
const backend = await createBackend(root, path.join(root, "orama-db"));
|
|
82
|
+
|
|
83
|
+
const japanese = await backend.bm25Search("東京都庁の所在地");
|
|
84
|
+
const english = await backend.bm25Search("Tokyo Metropolitan Government Office location");
|
|
85
|
+
|
|
86
|
+
assert.equal(japanese.some((r) => r.docid === "mem-japanese-fact"), true);
|
|
87
|
+
assert.equal(english.some((r) => r.docid === "mem-english-fact"), true);
|
|
88
|
+
} finally {
|
|
89
|
+
await rm(root, { recursive: true, force: true });
|
|
90
|
+
}
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
test("Orama CJK tokenizer rebuilds stale pre-CJK indexes on first open (issue #2187)", async () => {
|
|
94
|
+
const root = await mkdtemp(path.join(os.tmpdir(), "remnic-orama-rebuild-"));
|
|
95
|
+
try {
|
|
96
|
+
await writeMemoryFact(
|
|
97
|
+
root,
|
|
98
|
+
"japanese-fact.md",
|
|
99
|
+
"---\nid: mem-japanese-fact\n---\n東京都庁の所在地は新宿区にある。",
|
|
100
|
+
);
|
|
101
|
+
await writeMemoryFact(
|
|
102
|
+
root,
|
|
103
|
+
"russian-fact.md",
|
|
104
|
+
"---\nid: mem-russian-fact\n---\nПравительство Токио находится в Синдзюку.",
|
|
105
|
+
);
|
|
106
|
+
await writeMemoryFact(
|
|
107
|
+
root,
|
|
108
|
+
"english-fact.md",
|
|
109
|
+
"---\nid: mem-english-fact\n---\nNebula-472 deploy finished in production.",
|
|
110
|
+
);
|
|
111
|
+
|
|
112
|
+
// Phase 1: index with the pre-CJK stock tokenizer (marker "english").
|
|
113
|
+
const legacyBackend = await createBackend(root, path.join(root, "orama-db"), false);
|
|
114
|
+
const legacyJapanese = await legacyBackend.bm25Search("東京都庁の所在地");
|
|
115
|
+
assert.equal(
|
|
116
|
+
legacyJapanese.some((r) => r.docid === "mem-japanese-fact"),
|
|
117
|
+
false,
|
|
118
|
+
"stock tokenizer must not match Japanese phrases",
|
|
119
|
+
);
|
|
120
|
+
const legacyEnglish = await legacyBackend.bm25Search("Nebula-472 deploy");
|
|
121
|
+
assert.equal(legacyEnglish.some((r) => r.docid === "mem-english-fact"), true);
|
|
122
|
+
|
|
123
|
+
// Phase 2: reopen with CJK segmentation on and NO update() call — the
|
|
124
|
+
// stale marker alone must trigger the in-place rebuild during probe().
|
|
125
|
+
const rebuiltBackend = await createBackend(root, path.join(root, "orama-db"), true, {
|
|
126
|
+
update: false,
|
|
127
|
+
});
|
|
128
|
+
const rebuiltJapanese = await rebuiltBackend.bm25Search("東京都庁の所在地");
|
|
129
|
+
assert.equal(rebuiltJapanese.some((r) => r.docid === "mem-japanese-fact"), true);
|
|
130
|
+
|
|
131
|
+
// Non-CJK non-Latin scripts are re-indexed too (whole-word terms), not
|
|
132
|
+
// just CJK/Thai.
|
|
133
|
+
const rebuiltRussian = await rebuiltBackend.bm25Search("Правительство Токио");
|
|
134
|
+
assert.equal(rebuiltRussian.some((r) => r.docid === "mem-russian-fact"), true);
|
|
135
|
+
|
|
136
|
+
// English-corpus behavior is unchanged by the rebuild.
|
|
137
|
+
const rebuiltEnglish = await rebuiltBackend.bm25Search("Nebula-472 deploy");
|
|
138
|
+
assert.equal(rebuiltEnglish.some((r) => r.docid === "mem-english-fact"), true);
|
|
139
|
+
} finally {
|
|
140
|
+
await rm(root, { recursive: true, force: true });
|
|
141
|
+
}
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
test("Orama English-only corpora are not re-indexed when the tokenizer version advances (issue #2187)", async () => {
|
|
145
|
+
const root = await mkdtemp(path.join(os.tmpdir(), "remnic-orama-english-"));
|
|
146
|
+
try {
|
|
147
|
+
await writeMemoryFact(
|
|
148
|
+
root,
|
|
149
|
+
"english-fact.md",
|
|
150
|
+
"---\nid: mem-english-fact\n---\nNebula-472 deploy finished in production.",
|
|
151
|
+
);
|
|
152
|
+
|
|
153
|
+
const legacyBackend = await createBackend(root, path.join(root, "orama-db"), false);
|
|
154
|
+
assert.equal(
|
|
155
|
+
(await legacyBackend.bm25Search("Nebula-472 deploy")).some((r) => r.docid === "mem-english-fact"),
|
|
156
|
+
true,
|
|
157
|
+
);
|
|
158
|
+
|
|
159
|
+
const upgradedBackend = await createBackend(root, path.join(root, "orama-db"), true);
|
|
160
|
+
assert.equal(
|
|
161
|
+
(await upgradedBackend.bm25Search("Nebula-472 deploy")).some((r) => r.docid === "mem-english-fact"),
|
|
162
|
+
true,
|
|
163
|
+
"English recall must survive the tokenizer upgrade",
|
|
164
|
+
);
|
|
165
|
+
} finally {
|
|
166
|
+
await rm(root, { recursive: true, force: true });
|
|
167
|
+
}
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
test("Orama downgrades persisted CJK indexes when segmentation is disabled (issue #2187)", async () => {
|
|
171
|
+
const root = await mkdtemp(path.join(os.tmpdir(), "remnic-orama-downgrade-"));
|
|
172
|
+
try {
|
|
173
|
+
await writeMemoryFact(
|
|
174
|
+
root,
|
|
175
|
+
"japanese-fact.md",
|
|
176
|
+
"---\nid: mem-japanese-fact\n---\n東京都庁の所在地は新宿区にある。",
|
|
177
|
+
);
|
|
178
|
+
|
|
179
|
+
// Phase 1: index with CJK segmentation on (marker "english+cjk-v1").
|
|
180
|
+
const cjkBackend = await createBackend(root, path.join(root, "orama-db"), true);
|
|
181
|
+
assert.equal(
|
|
182
|
+
(await cjkBackend.bm25Search("東京都庁の所在地")).some((r) => r.docid === "mem-japanese-fact"),
|
|
183
|
+
true,
|
|
184
|
+
"CJK tokenizer must match Japanese phrases before the downgrade",
|
|
185
|
+
);
|
|
186
|
+
|
|
187
|
+
// Phase 2: reopen with segmentation disabled and NO update() call — the
|
|
188
|
+
// persisted CJK marker alone must trigger the stock re-index.
|
|
189
|
+
const downgraded = await createBackend(root, path.join(root, "orama-db"), false, {
|
|
190
|
+
update: false,
|
|
191
|
+
});
|
|
192
|
+
assert.equal(
|
|
193
|
+
(await downgraded.bm25Search("東京都庁の所在地")).some((r) => r.docid === "mem-japanese-fact"),
|
|
194
|
+
false,
|
|
195
|
+
"stock tokenizer must not match Japanese phrases after the downgrade",
|
|
196
|
+
);
|
|
197
|
+
} finally {
|
|
198
|
+
await rm(root, { recursive: true, force: true });
|
|
199
|
+
}
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
test("Orama rebuild gate inspects every indexed string field, not only content (issue #2187)", async () => {
|
|
203
|
+
const root = await mkdtemp(path.join(os.tmpdir(), "remnic-orama-pathfield-"));
|
|
204
|
+
try {
|
|
205
|
+
// The only non-Latin text is the FILENAME, which lands in the indexed
|
|
206
|
+
// path field; the body is pure English.
|
|
207
|
+
await writeMemoryFact(
|
|
208
|
+
root,
|
|
209
|
+
"東京-fact.md",
|
|
210
|
+
"---\nid: mem-path-only\n---\nAn English body with no non-Latin characters.",
|
|
211
|
+
);
|
|
212
|
+
|
|
213
|
+
// Phase 1: pre-CJK stock index — the CJK filename never becomes a term.
|
|
214
|
+
const legacyBackend = await createBackend(root, path.join(root, "orama-db"), false);
|
|
215
|
+
assert.equal(
|
|
216
|
+
(await legacyBackend.bm25Search("東京")).some((r) => r.docid === "mem-path-only"),
|
|
217
|
+
false,
|
|
218
|
+
"stock tokenizer must not match the CJK filename",
|
|
219
|
+
);
|
|
220
|
+
|
|
221
|
+
// Phase 2: reopen with segmentation on and NO update() call — the
|
|
222
|
+
// path field alone must gate the in-place re-index.
|
|
223
|
+
const rebuilt = await createBackend(root, path.join(root, "orama-db"), true, {
|
|
224
|
+
update: false,
|
|
225
|
+
});
|
|
226
|
+
assert.equal(
|
|
227
|
+
(await rebuilt.bm25Search("東京")).some((r) => r.docid === "mem-path-only"),
|
|
228
|
+
true,
|
|
229
|
+
"non-Latin text in the path field must gate the rebuild",
|
|
230
|
+
);
|
|
231
|
+
} finally {
|
|
232
|
+
await rm(root, { recursive: true, force: true });
|
|
233
|
+
}
|
|
234
|
+
});
|
|
@@ -9,17 +9,28 @@ import {
|
|
|
9
9
|
type SearchQueryOptions,
|
|
10
10
|
type SearchResult,
|
|
11
11
|
} from "./port.js";
|
|
12
|
-
import type { EmbedHelper, EmbedProviderIdentity, EmbedWithProviderResult } from "./embed-helper.js";
|
|
13
|
-
import { scanMemoryDir } from "./document-scanner.js";
|
|
14
|
-
import { isSearchAborted, throwIfSearchAborted } from "./abort.js";
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
12
|
+
import type { EmbedHelper, EmbedProviderIdentity, EmbedWithProviderResult } from "./embed-helper.js";
|
|
13
|
+
import { scanMemoryDir } from "./document-scanner.js";
|
|
14
|
+
import { isSearchAborted, throwIfSearchAborted } from "./abort.js";
|
|
15
|
+
import {
|
|
16
|
+
containsNonLegacyTokenizerChars,
|
|
17
|
+
createCjkCapableTokenizer,
|
|
18
|
+
ORAMA_CJK_TOKENIZER_LANGUAGE,
|
|
19
|
+
} from "./orama-cjk-tokenizer.js";
|
|
20
|
+
|
|
21
|
+
export interface OramaBackendOptions {
|
|
22
|
+
dbPath: string;
|
|
23
|
+
collection: string;
|
|
24
|
+
embedHelper: EmbedHelper;
|
|
25
|
+
memoryDir: string;
|
|
26
|
+
embeddingDimension: number;
|
|
27
|
+
/**
|
|
28
|
+
* Segment space-free scripts (CJK/Thai) in the lexical index. Default
|
|
29
|
+
* `true`; `false` restores the stock English-only tokenizer (issue #2187).
|
|
30
|
+
*/
|
|
31
|
+
cjkSegmentationEnabled?: boolean;
|
|
32
|
+
}
|
|
33
|
+
|
|
23
34
|
|
|
24
35
|
const ORAMA_COLLECTION_FILENAME_PATTERN = /^[A-Za-z0-9][A-Za-z0-9._-]*$/;
|
|
25
36
|
|
|
@@ -57,6 +68,7 @@ export class OramaBackend implements SearchBackend {
|
|
|
57
68
|
private readonly embedHelper: EmbedHelper;
|
|
58
69
|
private readonly memoryDir: string;
|
|
59
70
|
private readonly embeddingDimension: number;
|
|
71
|
+
private readonly cjkSegmentationEnabled: boolean;
|
|
60
72
|
private available = false;
|
|
61
73
|
private db: any = null;
|
|
62
74
|
private oramaModule: any = null;
|
|
@@ -72,6 +84,7 @@ export class OramaBackend implements SearchBackend {
|
|
|
72
84
|
this.embedHelper = opts.embedHelper;
|
|
73
85
|
this.memoryDir = opts.memoryDir;
|
|
74
86
|
this.embeddingDimension = opts.embeddingDimension;
|
|
87
|
+
this.cjkSegmentationEnabled = opts.cjkSegmentationEnabled !== false;
|
|
75
88
|
}
|
|
76
89
|
|
|
77
90
|
async probe(): Promise<boolean> {
|
|
@@ -127,6 +140,11 @@ export class OramaBackend implements SearchBackend {
|
|
|
127
140
|
}
|
|
128
141
|
}
|
|
129
142
|
|
|
143
|
+
/**
|
|
144
|
+
* Full-text (FTS) search only. With the stock tokenizer this cannot match
|
|
145
|
+
* space-free CJK/Thai text lexically — hybrid or vector search provides
|
|
146
|
+
* the fallback for those scripts (issue #2187).
|
|
147
|
+
*/
|
|
130
148
|
async bm25Search(query: string, collection?: string, maxResults?: number, execution?: SearchExecutionOptions): Promise<SearchResult[]> {
|
|
131
149
|
if (isSearchAborted(execution)) return [];
|
|
132
150
|
const db = await this.ensureDbForCollection(collection ?? this.collection);
|
|
@@ -403,8 +421,11 @@ export class OramaBackend implements SearchBackend {
|
|
|
403
421
|
return this.db;
|
|
404
422
|
}
|
|
405
423
|
|
|
406
|
-
this.db = await this.
|
|
407
|
-
await this.
|
|
424
|
+
this.db = await this.applyTokenizerVersion(
|
|
425
|
+
await this.migrateLegacyVectorProviderSchema(
|
|
426
|
+
await this.persistModule.restore("json", raw),
|
|
427
|
+
this.collection,
|
|
428
|
+
),
|
|
408
429
|
this.collection,
|
|
409
430
|
);
|
|
410
431
|
return this.db;
|
|
@@ -426,8 +447,11 @@ export class OramaBackend implements SearchBackend {
|
|
|
426
447
|
return await this.createDb();
|
|
427
448
|
}
|
|
428
449
|
|
|
429
|
-
return await this.
|
|
430
|
-
await this.
|
|
450
|
+
return await this.applyTokenizerVersion(
|
|
451
|
+
await this.migrateLegacyVectorProviderSchema(
|
|
452
|
+
await this.persistModule.restore("json", raw),
|
|
453
|
+
collection,
|
|
454
|
+
),
|
|
431
455
|
collection,
|
|
432
456
|
);
|
|
433
457
|
}
|
|
@@ -442,7 +466,95 @@ export class OramaBackend implements SearchBackend {
|
|
|
442
466
|
vectorProvider: "string",
|
|
443
467
|
vector: `vector[${this.embeddingDimension}]`,
|
|
444
468
|
};
|
|
445
|
-
|
|
469
|
+
if (!this.cjkSegmentationEnabled) {
|
|
470
|
+
return await create({ schema });
|
|
471
|
+
}
|
|
472
|
+
return await create({
|
|
473
|
+
schema,
|
|
474
|
+
components: { tokenizer: createCjkCapableTokenizer(this.oramaModule) },
|
|
475
|
+
});
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
/**
|
|
479
|
+
* Attach the CJK-capable tokenizer to a restored index and rebuild the
|
|
480
|
+
* full-text index when it predates CJK tokenization. Orama persists
|
|
481
|
+
* `tokenizer.language` with the index, so a marker other than
|
|
482
|
+
* `ORAMA_CJK_TOKENIZER_LANGUAGE` identifies an index whose terms were
|
|
483
|
+
* produced by the stock English tokenizer. Corpora whose content the stock
|
|
484
|
+
* tokenizer and this tokenizer treat identically (pure legacy Latin) need
|
|
485
|
+
* no re-indexing — only the version marker is rewritten for them.
|
|
486
|
+
*/
|
|
487
|
+
private async applyTokenizerVersion(db: any, collection: string): Promise<any> {
|
|
488
|
+
const persistedLanguage =
|
|
489
|
+
db?.tokenizer?.language && typeof db.tokenizer.language === "string"
|
|
490
|
+
? db.tokenizer.language
|
|
491
|
+
: "";
|
|
492
|
+
if (this.cjkSegmentationEnabled) {
|
|
493
|
+
db.tokenizer = createCjkCapableTokenizer(this.oramaModule);
|
|
494
|
+
if (persistedLanguage === ORAMA_CJK_TOKENIZER_LANGUAGE) return db;
|
|
495
|
+
} else {
|
|
496
|
+
// Segmentation disabled: a database persisted under the CJK tokenizer
|
|
497
|
+
// keeps its CJK terms unless it is re-indexed under the stock one, so
|
|
498
|
+
// downgrade it instead of returning it unchanged (issue #2187 round 2).
|
|
499
|
+
if (persistedLanguage !== ORAMA_CJK_TOKENIZER_LANGUAGE) return db;
|
|
500
|
+
db.tokenizer = this.oramaModule.components.tokenizer.createTokenizer({ language: "english" });
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
|
|
504
|
+
try {
|
|
505
|
+
const { search: oramaSearch, count, update: oramaUpdate } = this.oramaModule;
|
|
506
|
+
const existingCount = await count(db);
|
|
507
|
+
if (existingCount === 0) {
|
|
508
|
+
await this.persistDbForCollection(db, collection);
|
|
509
|
+
return db;
|
|
510
|
+
}
|
|
511
|
+
const allHits = await oramaSearch(db, { term: "", limit: existingCount + 100 });
|
|
512
|
+
const hits = allHits.hits ?? [];
|
|
513
|
+
const hasNonLegacyContent = hits.some((hit: any) => {
|
|
514
|
+
const doc = this.getStoredDocument(db, hit);
|
|
515
|
+
// Orama full-text queries every string field by default, so every
|
|
516
|
+
// indexed string field gates the rebuild — non-Latin text that only
|
|
517
|
+
// rides in snippet/path/id would otherwise keep stale terms
|
|
518
|
+
// (issue #2187 review round 2).
|
|
519
|
+
for (const field of [doc.content, doc.snippet, doc.path, doc.id, doc.vectorProvider]) {
|
|
520
|
+
if (typeof field === "string" && containsNonLegacyTokenizerChars(field)) return true;
|
|
521
|
+
}
|
|
522
|
+
return false;
|
|
523
|
+
});
|
|
524
|
+
if (hasNonLegacyContent) {
|
|
525
|
+
// Re-index every document in place (Orama update is remove+insert,
|
|
526
|
+
// so content is re-tokenized; vectors are carried through). A single
|
|
527
|
+
// failing document must not block the rest of the corpus: it keeps
|
|
528
|
+
// its pre-upgrade terms, which is no worse than before the upgrade.
|
|
529
|
+
for (const hit of hits) {
|
|
530
|
+
try {
|
|
531
|
+
const doc = this.getStoredDocument(db, hit);
|
|
532
|
+
const vector = this.getStoredVector(db, hit, doc);
|
|
533
|
+
await oramaUpdate(db, hit.id, {
|
|
534
|
+
id: typeof doc.id === "string" && doc.id.length > 0 ? doc.id : String(hit.id),
|
|
535
|
+
path: typeof doc.path === "string" ? doc.path : "",
|
|
536
|
+
content: typeof doc.content === "string" ? doc.content : "",
|
|
537
|
+
snippet:
|
|
538
|
+
typeof doc.snippet === "string"
|
|
539
|
+
? doc.snippet
|
|
540
|
+
: typeof doc.content === "string"
|
|
541
|
+
? doc.content.slice(0, 200)
|
|
542
|
+
: "",
|
|
543
|
+
vectorProvider: typeof doc.vectorProvider === "string" ? doc.vectorProvider : "",
|
|
544
|
+
vector: vector ?? this.zeroVector(),
|
|
545
|
+
});
|
|
546
|
+
} catch (docErr) {
|
|
547
|
+
log.debug(
|
|
548
|
+
`OramaBackend tokenizer-version re-index skipped document ${hit.id} in ${collection}: ${docErr}`,
|
|
549
|
+
);
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
await this.persistDbForCollection(db, collection);
|
|
554
|
+
} catch (err) {
|
|
555
|
+
log.debug(`OramaBackend tokenizer-version rebuild for ${collection} failed: ${err}`);
|
|
556
|
+
}
|
|
557
|
+
return db;
|
|
446
558
|
}
|
|
447
559
|
|
|
448
560
|
private async migrateLegacyVectorProviderSchema(db: any, collection: string): Promise<any> {
|
|
@@ -526,8 +638,11 @@ export class OramaBackend implements SearchBackend {
|
|
|
526
638
|
await this.ensureModules();
|
|
527
639
|
const raw = await readFile(filePath, "utf-8");
|
|
528
640
|
const collection = path.basename(filePath, ".msp");
|
|
529
|
-
return await this.
|
|
530
|
-
await this.
|
|
641
|
+
return await this.applyTokenizerVersion(
|
|
642
|
+
await this.migrateLegacyVectorProviderSchema(
|
|
643
|
+
await this.persistModule.restore("json", raw),
|
|
644
|
+
collection,
|
|
645
|
+
),
|
|
531
646
|
collection,
|
|
532
647
|
);
|
|
533
648
|
} catch (err) {
|