@remnic/core 9.3.613 → 9.3.615
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-cli.js +59 -58
- package/dist/access-cli.js.map +1 -1
- package/dist/access-http.d.ts +4 -2
- package/dist/access-http.js +23 -23
- package/dist/access-mcp.d.ts +9 -2
- package/dist/access-mcp.js +20 -20
- package/dist/access-schema.d.ts +26 -14
- package/dist/access-schema.js +3 -3
- package/dist/{access-service-D2J9dh_9.d.ts → access-service-CBNEKjzN.d.ts} +71 -6
- package/dist/access-service.d.ts +2 -2
- package/dist/access-service.js +17 -17
- package/dist/active-recall.js +20 -3
- package/dist/active-recall.js.map +1 -1
- package/dist/adapters/index.js +4 -4
- package/dist/adapters/registry.js +2 -2
- package/dist/behavior-learner.js +2 -3
- package/dist/behavior-learner.js.map +1 -1
- package/dist/bootstrap.d.ts +1 -1
- package/dist/briefing.js +3 -3
- package/dist/buffer.d.ts +1 -1
- package/dist/buffer.js +1 -1
- package/dist/calibration.d.ts +5 -2
- package/dist/calibration.js +7 -5
- package/dist/calibration.js.map +1 -1
- package/dist/{capsule-crypto-7FJQINUR.js → capsule-crypto-YO5QJ6L3.js} +2 -2
- package/dist/causal-consolidation.d.ts +8 -2
- package/dist/causal-consolidation.js +13 -11
- package/dist/causal-consolidation.js.map +1 -1
- package/dist/{chunk-3BP57I6J.js → chunk-2F6NP3NT.js} +2 -1
- package/dist/{chunk-3BP57I6J.js.map → chunk-2F6NP3NT.js.map} +1 -1
- package/dist/{chunk-AU7Q3LSC.js → chunk-2QSZNTDO.js} +4 -4
- package/dist/{chunk-HSVJGWYS.js → chunk-2ROPI5OE.js} +2 -2
- package/dist/{chunk-C4SQJZAF.js → chunk-2SGJY2UY.js} +6 -3
- package/dist/chunk-2SGJY2UY.js.map +1 -0
- package/dist/{chunk-ZDTVJXIP.js → chunk-3MAONBX3.js} +13 -5
- package/dist/chunk-3MAONBX3.js.map +1 -0
- package/dist/{chunk-G3Z3QEF5.js → chunk-3PY7VHV7.js} +2 -2
- package/dist/chunk-3PY7VHV7.js.map +1 -0
- package/dist/{chunk-CF3ZF2YU.js → chunk-3QSU4NFF.js} +3 -3
- package/dist/{chunk-AJA46VX5.js → chunk-3T74IZB3.js} +11 -2
- package/dist/chunk-3T74IZB3.js.map +1 -0
- package/dist/{chunk-KVEVLBKC.js → chunk-4HFJQCJZ.js} +13 -8
- package/dist/chunk-4HFJQCJZ.js.map +1 -0
- package/dist/{chunk-KGK2QKWL.js → chunk-4R4KTDIE.js} +1 -1
- package/dist/chunk-4R4KTDIE.js.map +1 -0
- package/dist/{chunk-OI27U2HT.js → chunk-5BTCT236.js} +2 -2
- package/dist/{chunk-TH67Q46T.js → chunk-5OHHEORR.js} +64 -21
- package/dist/chunk-5OHHEORR.js.map +1 -0
- package/dist/{chunk-CO7ZO4TU.js → chunk-5VDJMYTF.js} +2 -2
- package/dist/{chunk-BFBF3XEF.js → chunk-6BDVBBBY.js} +33 -25
- package/dist/{chunk-BFBF3XEF.js.map → chunk-6BDVBBBY.js.map} +1 -1
- package/dist/{chunk-EAZGEEG2.js → chunk-6L46YAEZ.js} +45 -9
- package/dist/chunk-6L46YAEZ.js.map +1 -0
- package/dist/{chunk-YFS5OEKO.js → chunk-7MLB4NCL.js} +2 -2
- package/dist/{chunk-LZ3VEOU5.js → chunk-AL4RAJL5.js} +22 -5
- package/dist/chunk-AL4RAJL5.js.map +1 -0
- package/dist/{chunk-557IAFPD.js → chunk-APRRL26Q.js} +2 -2
- package/dist/{chunk-QDDHYAKV.js → chunk-AZDOWD2L.js} +2 -2
- package/dist/{chunk-MLT75J5S.js → chunk-B6SU7YSE.js} +3 -3
- package/dist/{chunk-FXKPZ3H6.js → chunk-BPSGLMQ4.js} +2 -2
- package/dist/{chunk-2NLLXCJG.js → chunk-BXLOS5AJ.js} +2 -2
- package/dist/{chunk-NOMEVTUD.js → chunk-C6C7XVKG.js} +5 -4
- package/dist/chunk-C6C7XVKG.js.map +1 -0
- package/dist/{chunk-XKIQZXUB.js → chunk-CI7RKSRE.js} +7 -1
- package/dist/chunk-CI7RKSRE.js.map +1 -0
- package/dist/{chunk-IK34DVAC.js → chunk-CIOMS6DI.js} +2 -2
- package/dist/{chunk-2I5JGH3M.js → chunk-CYEPCZN5.js} +2 -2
- package/dist/{chunk-2I5JGH3M.js.map → chunk-CYEPCZN5.js.map} +1 -1
- package/dist/{chunk-JHMFYY7L.js → chunk-DCGT4FPP.js} +13 -5
- package/dist/chunk-DCGT4FPP.js.map +1 -0
- package/dist/{chunk-7DZRO2DC.js → chunk-DEPRLVLK.js} +2 -2
- package/dist/{chunk-CSKLPDN6.js → chunk-DEVUWMME.js} +52 -19
- package/dist/chunk-DEVUWMME.js.map +1 -0
- package/dist/{chunk-DHGSZ3UD.js → chunk-DGNQRNLL.js} +2 -2
- package/dist/{chunk-X7Y7WX73.js → chunk-DQEMWVMT.js} +1 -1
- package/dist/{chunk-HJNQQICM.js → chunk-EXUAP5LH.js} +108 -51
- package/dist/chunk-EXUAP5LH.js.map +1 -0
- package/dist/chunk-FAV25DUZ.js +12 -0
- package/dist/chunk-FAV25DUZ.js.map +1 -0
- package/dist/{chunk-ETUPBUHB.js → chunk-GDASG7NC.js} +2 -2
- package/dist/{chunk-L227SKTB.js → chunk-GDB4J2H3.js} +17 -1
- package/dist/chunk-GDB4J2H3.js.map +1 -0
- package/dist/{chunk-IP73YCZP.js → chunk-GLPBYIXN.js} +4 -2
- package/dist/chunk-GLPBYIXN.js.map +1 -0
- package/dist/{chunk-4HP7HIE3.js → chunk-HP5FMB6L.js} +2 -2
- package/dist/{chunk-EVZFIAPG.js → chunk-IBTZEBUD.js} +23 -10
- package/dist/chunk-IBTZEBUD.js.map +1 -0
- package/dist/{chunk-DOX2CG6Y.js → chunk-IEUU7O4F.js} +2 -2
- package/dist/{chunk-EUML3N6B.js → chunk-IMA6GU4Y.js} +3 -3
- package/dist/chunk-IMA6GU4Y.js.map +1 -0
- package/dist/{chunk-JNANKJLN.js → chunk-JOASJWQR.js} +2 -2
- package/dist/chunk-JOASJWQR.js.map +1 -0
- package/dist/{chunk-WSGF57U2.js → chunk-JQDZQ4TB.js} +2 -2
- package/dist/{chunk-HINSGUA7.js → chunk-KBL3JJR6.js} +9 -13
- package/dist/chunk-KBL3JJR6.js.map +1 -0
- package/dist/{chunk-IOTENEVL.js → chunk-KGLPJROV.js} +57 -50
- package/dist/chunk-KGLPJROV.js.map +1 -0
- package/dist/{chunk-W7L6HXUC.js → chunk-LXOM6IQU.js} +2 -2
- package/dist/{chunk-G6R5UD3Q.js → chunk-MGN7VHWQ.js} +42 -1
- package/dist/{chunk-G6R5UD3Q.js.map → chunk-MGN7VHWQ.js.map} +1 -1
- package/dist/{chunk-DLJ4IR6M.js → chunk-MHQC2WU2.js} +2 -2
- package/dist/chunk-MHQC2WU2.js.map +1 -0
- package/dist/{chunk-5RPTH6AU.js → chunk-NM5NQYJE.js} +20 -19
- package/dist/chunk-NM5NQYJE.js.map +1 -0
- package/dist/{chunk-6JGNHWCI.js → chunk-OBIRVF36.js} +3 -3
- package/dist/{chunk-CHCA44C3.js → chunk-ODPLEWB6.js} +3 -3
- package/dist/chunk-ODPLEWB6.js.map +1 -0
- package/dist/{chunk-HENLZHIT.js → chunk-OIF36KGD.js} +7 -4
- package/dist/chunk-OIF36KGD.js.map +1 -0
- package/dist/{chunk-GUPISBV2.js → chunk-PP2JH3GP.js} +2 -2
- package/dist/{chunk-OXJBNGBK.js → chunk-PSUB67YB.js} +2 -2
- package/dist/{chunk-UWY7GIVS.js → chunk-PYIFUBRK.js} +45 -13
- package/dist/chunk-PYIFUBRK.js.map +1 -0
- package/dist/{chunk-KIB7SDIJ.js → chunk-Q6YIJGXJ.js} +2 -2
- package/dist/{chunk-ZT3EGNLR.js → chunk-QPD426WT.js} +2 -2
- package/dist/{chunk-RLV3PQGH.js → chunk-QVO4YOB7.js} +6 -6
- package/dist/{chunk-GMAG2HS4.js → chunk-RG3LBSGH.js} +46 -9
- package/dist/chunk-RG3LBSGH.js.map +1 -0
- package/dist/{chunk-XSWKORGM.js → chunk-S53OYO3F.js} +3 -1
- package/dist/chunk-S53OYO3F.js.map +1 -0
- package/dist/{chunk-YCN4BVDK.js → chunk-SCPFRKIT.js} +4 -2
- package/dist/chunk-SCPFRKIT.js.map +1 -0
- package/dist/{chunk-NZPF2SYV.js → chunk-T7N6KQGS.js} +138 -5
- package/dist/chunk-T7N6KQGS.js.map +1 -0
- package/dist/{chunk-VJXSUAO7.js → chunk-TNOWU6RP.js} +13 -10
- package/dist/chunk-TNOWU6RP.js.map +1 -0
- package/dist/{chunk-PCI747N2.js → chunk-TZVQQTG4.js} +48 -19
- package/dist/chunk-TZVQQTG4.js.map +1 -0
- package/dist/{chunk-KQAFEZQX.js → chunk-VDX2J7OX.js} +2 -2
- package/dist/{chunk-IK7DCC5H.js → chunk-VMGLYN42.js} +2 -2
- package/dist/{chunk-KM2A35EO.js → chunk-WB3LYXC5.js} +11 -7
- package/dist/chunk-WB3LYXC5.js.map +1 -0
- package/dist/{chunk-PPPZY2EU.js → chunk-WD2W4234.js} +9 -3
- package/dist/chunk-WD2W4234.js.map +1 -0
- package/dist/{chunk-NSKYFGDL.js → chunk-X4QQB7O6.js} +2 -2
- package/dist/{chunk-HPWVAEET.js → chunk-X6IRLNOO.js} +3 -7
- package/dist/chunk-X6IRLNOO.js.map +1 -0
- package/dist/{chunk-46GJIW5M.js → chunk-XAZOWLW4.js} +5 -5
- package/dist/{chunk-46GJIW5M.js.map → chunk-XAZOWLW4.js.map} +1 -1
- package/dist/{chunk-XPSVGJYA.js → chunk-YRMKDTKF.js} +12 -9
- package/dist/chunk-YRMKDTKF.js.map +1 -0
- package/dist/{chunk-6ZZP4EJF.js → chunk-ZJR7VG5L.js} +3 -3
- package/dist/{chunk-6ZZP4EJF.js.map → chunk-ZJR7VG5L.js.map} +1 -1
- package/dist/{chunk-2QANQKSQ.js → chunk-ZK32E74R.js} +156 -45
- package/dist/chunk-ZK32E74R.js.map +1 -0
- package/dist/{cli-OrfKXNU4.d.ts → cli-Cw729yLf.d.ts} +6 -2
- package/dist/cli.d.ts +3 -3
- package/dist/cli.js +61 -60
- package/dist/compounding/engine.js +3 -3
- package/dist/compounding/preference-consolidator.js +39 -11
- package/dist/compounding/preference-consolidator.js.map +1 -1
- package/dist/config.js +1 -1
- package/dist/connectors/codex-materialize-runner.js +3 -3
- package/dist/connectors/index.js +3 -3
- package/dist/consolidation-provenance-check.js +1 -1
- package/dist/contradiction/index.js +4 -4
- package/dist/conversation-index/backend.js +2 -2
- package/dist/conversation-index/indexer.js +1 -1
- package/dist/cross-namespace-budget.js +1 -1
- package/dist/enrichment/index.js +1 -1
- package/dist/entity-retrieval.js +3 -3
- package/dist/evals.js +1 -1
- package/dist/explicit-capture.d.ts +11 -1
- package/dist/explicit-capture.js +1 -1
- package/dist/extraction-judge.js +8 -1
- package/dist/extraction.js +2 -2
- package/dist/fallback-llm.d.ts +23 -6
- package/dist/fallback-llm.js +5 -3
- package/dist/{first-start-migration-GYJWIH36.js → first-start-migration-FF7YFGRP.js} +6 -6
- package/dist/index.d.ts +3 -3
- package/dist/index.js +95 -94
- package/dist/index.js.map +1 -1
- package/dist/lcm/archive.js +2 -2
- package/dist/lcm/engine.js +5 -5
- package/dist/lcm/index.js +7 -7
- package/dist/lcm/summarizer.js +3 -3
- package/dist/maintenance/memory-governance-cron.d.ts +6 -4
- package/dist/maintenance/memory-governance-cron.js +1 -1
- package/dist/maintenance/memory-governance.js +3 -3
- package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +3 -3
- package/dist/maintenance/rebuild-memory-projection.js +4 -4
- package/dist/mcp-memory-inspector-app.d.ts +2 -2
- package/dist/mcp-memory-inspector-app.js +1 -1
- package/dist/migrate/from-engram.js +1 -1
- package/dist/namespaces/migrate.js +16 -15
- package/dist/namespaces/search.js +12 -11
- package/dist/namespaces/storage.js +3 -3
- package/dist/network/webdav.d.ts +2 -0
- package/dist/network/webdav.js +1 -1
- package/dist/objective-state-writers.js +2 -2
- package/dist/operator-toolkit.d.ts +3 -1
- package/dist/operator-toolkit.js +21 -20
- package/dist/{orchestrator-DTRQG75J.d.ts → orchestrator-CqWOjfgl.d.ts} +46 -3
- package/dist/orchestrator.d.ts +1 -1
- package/dist/orchestrator.js +48 -45
- package/dist/patterns-cli.js +1 -1
- package/dist/qmd-recall-cache.d.ts +2 -0
- package/dist/qmd-recall-cache.js +1 -1
- package/dist/qmd.d.ts +37 -2
- package/dist/qmd.js +4 -1
- package/dist/recall-explain-renderer.js +3 -3
- package/dist/recall-planner-llm.d.ts +57 -0
- package/dist/recall-planner-llm.js +167 -0
- package/dist/recall-planner-llm.js.map +1 -0
- package/dist/recall-xray-cli.js +4 -4
- package/dist/recall-xray-renderer.js +3 -3
- package/dist/recall-xray.js +2 -2
- package/dist/resume-bundles.js +2 -2
- package/dist/retrieval-agents.js +2 -2
- package/dist/routing/store.js +1 -1
- package/dist/schemas.d.ts +22 -22
- package/dist/search/factory.js +11 -10
- package/dist/search/index.js +11 -10
- package/dist/search/lancedb-backend.d.ts +1 -1
- package/dist/search/lancedb-backend.js +3 -2
- package/dist/search/meilisearch-backend.d.ts +1 -1
- package/dist/search/meilisearch-backend.js +3 -2
- package/dist/search/noop-backend.d.ts +1 -1
- package/dist/search/noop-backend.js +1 -1
- package/dist/search/orama-backend.d.ts +1 -1
- package/dist/search/orama-backend.js +3 -2
- package/dist/search/port.d.ts +6 -1
- package/dist/search/port.js +7 -0
- package/dist/search/remote-backend.d.ts +1 -1
- package/dist/search/remote-backend.js +1 -1
- package/dist/semantic-consolidation.js +4 -4
- package/dist/semantic-rule-promotion.js +3 -3
- package/dist/semantic-rule-verifier.js +3 -3
- package/dist/session-observer-state.js +1 -1
- package/dist/storage.js +2 -2
- package/dist/summarizer.js +2 -2
- package/dist/temporal-index.js +1 -1
- package/dist/{tier-stats-SKML2OSF.js → tier-stats-3LYQ3VV5.js} +3 -3
- 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/transfer/export-sqlite.js +1 -1
- package/dist/transfer/types.d.ts +12 -12
- package/dist/types.d.ts +32 -0
- package/dist/types.js +1 -1
- package/dist/utility-learner.js +1 -1
- package/dist/utility-runtime.js +2 -2
- package/dist/verified-recall.js +3 -3
- package/dist/work/board.js +2 -2
- package/dist/work/storage.d.ts +2 -0
- package/dist/work/storage.js +1 -1
- package/package.json +1 -1
- package/src/access-http.ts +24 -10
- package/src/access-mcp.test.ts +160 -0
- package/src/access-mcp.ts +72 -7
- package/src/access-schema.ts +11 -0
- package/src/access-service-coding-write.test.ts +478 -0
- package/src/access-service.ts +237 -32
- package/src/active-recall.test.ts +40 -0
- package/src/active-recall.ts +19 -2
- package/src/behavior-learner.ts +5 -3
- package/src/buffer-session.test.ts +58 -0
- package/src/buffer-surprise-trigger.test.ts +4 -18
- package/src/buffer.ts +39 -11
- package/src/calibration.ts +10 -4
- package/src/causal-consolidation.test.ts +47 -2
- package/src/causal-consolidation.ts +13 -9
- package/src/cli.ts +19 -4
- package/src/compounding/engine.ts +2 -0
- package/src/compounding/preference-consolidator.test.ts +292 -0
- package/src/compounding/preference-consolidator.ts +55 -19
- package/src/config.test.ts +213 -0
- package/src/config.ts +175 -4
- package/src/connectors/codex-materialize-runner.ts +7 -4
- package/src/consolidation-provenance-check.ts +24 -5
- package/src/conversation-index/indexer.test.ts +22 -0
- package/src/conversation-index/indexer.ts +7 -3
- package/src/cross-namespace-budget.test.ts +44 -21
- package/src/cross-namespace-budget.ts +2 -2
- package/src/enrichment/pipeline.ts +11 -16
- package/src/evals.ts +1 -1
- package/src/explicit-capture.ts +19 -2
- package/src/extraction-judge-chain.test.ts +55 -0
- package/src/extraction-judge.ts +7 -9
- package/src/extraction.ts +16 -5
- package/src/fallback-llm.test.ts +600 -1
- package/src/fallback-llm.ts +91 -22
- package/src/maintenance/memory-governance-cron.ts +39 -29
- package/src/mcp-memory-inspector-app.ts +54 -12
- package/src/message-parts/index.ts +6 -0
- package/src/message-parts/message-parts.test.ts +30 -0
- package/src/migrate/from-engram.ts +19 -5
- package/src/namespaces/search.test.ts +15 -2
- package/src/namespaces/search.ts +1 -1
- package/src/network/webdav.ts +61 -21
- package/src/operator-toolkit.ts +6 -2
- package/src/orchestrator.ts +173 -20
- package/src/qmd-client.test.ts +85 -0
- package/src/qmd-recall-cache.test.ts +16 -0
- package/src/qmd-recall-cache.ts +7 -0
- package/src/qmd.test.ts +54 -0
- package/src/qmd.ts +119 -19
- package/src/recall-planner-llm.test.ts +224 -0
- package/src/recall-planner-llm.ts +289 -0
- package/src/routing/store.ts +4 -8
- package/src/search/factory.ts +3 -0
- package/src/search/lancedb-backend.ts +15 -3
- package/src/search/meilisearch-backend.ts +70 -7
- package/src/search/noop-backend.ts +5 -1
- package/src/search/orama-backend.ts +15 -3
- package/src/search/port.ts +15 -0
- package/src/search/remote-backend.ts +5 -1
- package/src/session-observer-state.ts +1 -1
- package/src/summarizer.ts +3 -3
- package/src/temporal-index.test.ts +18 -0
- package/src/temporal-index.ts +45 -0
- package/src/training-export/cli-date-validation.test.ts +36 -0
- package/src/training-export/date-parse.ts +21 -2
- package/src/transfer/export-sqlite.ts +3 -0
- package/src/types.ts +35 -0
- package/src/utility-learner.ts +1 -0
- package/src/work/storage.ts +23 -0
- package/dist/chunk-2QANQKSQ.js.map +0 -1
- package/dist/chunk-5RPTH6AU.js.map +0 -1
- package/dist/chunk-AJA46VX5.js.map +0 -1
- package/dist/chunk-C4SQJZAF.js.map +0 -1
- package/dist/chunk-CHCA44C3.js.map +0 -1
- package/dist/chunk-CSKLPDN6.js.map +0 -1
- package/dist/chunk-DLJ4IR6M.js.map +0 -1
- package/dist/chunk-EAZGEEG2.js.map +0 -1
- package/dist/chunk-EUML3N6B.js.map +0 -1
- package/dist/chunk-EVZFIAPG.js.map +0 -1
- package/dist/chunk-G3Z3QEF5.js.map +0 -1
- package/dist/chunk-GMAG2HS4.js.map +0 -1
- package/dist/chunk-HENLZHIT.js.map +0 -1
- package/dist/chunk-HINSGUA7.js.map +0 -1
- package/dist/chunk-HJNQQICM.js.map +0 -1
- package/dist/chunk-HPWVAEET.js.map +0 -1
- package/dist/chunk-IOTENEVL.js.map +0 -1
- package/dist/chunk-IP73YCZP.js.map +0 -1
- package/dist/chunk-JHMFYY7L.js.map +0 -1
- package/dist/chunk-JNANKJLN.js.map +0 -1
- package/dist/chunk-KGK2QKWL.js.map +0 -1
- package/dist/chunk-KM2A35EO.js.map +0 -1
- package/dist/chunk-KVEVLBKC.js.map +0 -1
- package/dist/chunk-L227SKTB.js.map +0 -1
- package/dist/chunk-LZ3VEOU5.js.map +0 -1
- package/dist/chunk-NOMEVTUD.js.map +0 -1
- package/dist/chunk-NZPF2SYV.js.map +0 -1
- package/dist/chunk-PCI747N2.js.map +0 -1
- package/dist/chunk-PPPZY2EU.js.map +0 -1
- package/dist/chunk-TH67Q46T.js.map +0 -1
- package/dist/chunk-UWY7GIVS.js.map +0 -1
- package/dist/chunk-VJXSUAO7.js.map +0 -1
- package/dist/chunk-XKIQZXUB.js.map +0 -1
- package/dist/chunk-XPSVGJYA.js.map +0 -1
- package/dist/chunk-XSWKORGM.js.map +0 -1
- package/dist/chunk-YCN4BVDK.js.map +0 -1
- package/dist/chunk-ZDTVJXIP.js.map +0 -1
- /package/dist/{capsule-crypto-7FJQINUR.js.map → capsule-crypto-YO5QJ6L3.js.map} +0 -0
- /package/dist/{chunk-AU7Q3LSC.js.map → chunk-2QSZNTDO.js.map} +0 -0
- /package/dist/{chunk-HSVJGWYS.js.map → chunk-2ROPI5OE.js.map} +0 -0
- /package/dist/{chunk-CF3ZF2YU.js.map → chunk-3QSU4NFF.js.map} +0 -0
- /package/dist/{chunk-OI27U2HT.js.map → chunk-5BTCT236.js.map} +0 -0
- /package/dist/{chunk-CO7ZO4TU.js.map → chunk-5VDJMYTF.js.map} +0 -0
- /package/dist/{chunk-YFS5OEKO.js.map → chunk-7MLB4NCL.js.map} +0 -0
- /package/dist/{chunk-557IAFPD.js.map → chunk-APRRL26Q.js.map} +0 -0
- /package/dist/{chunk-QDDHYAKV.js.map → chunk-AZDOWD2L.js.map} +0 -0
- /package/dist/{chunk-MLT75J5S.js.map → chunk-B6SU7YSE.js.map} +0 -0
- /package/dist/{chunk-FXKPZ3H6.js.map → chunk-BPSGLMQ4.js.map} +0 -0
- /package/dist/{chunk-2NLLXCJG.js.map → chunk-BXLOS5AJ.js.map} +0 -0
- /package/dist/{chunk-IK34DVAC.js.map → chunk-CIOMS6DI.js.map} +0 -0
- /package/dist/{chunk-7DZRO2DC.js.map → chunk-DEPRLVLK.js.map} +0 -0
- /package/dist/{chunk-DHGSZ3UD.js.map → chunk-DGNQRNLL.js.map} +0 -0
- /package/dist/{chunk-X7Y7WX73.js.map → chunk-DQEMWVMT.js.map} +0 -0
- /package/dist/{chunk-ETUPBUHB.js.map → chunk-GDASG7NC.js.map} +0 -0
- /package/dist/{chunk-4HP7HIE3.js.map → chunk-HP5FMB6L.js.map} +0 -0
- /package/dist/{chunk-DOX2CG6Y.js.map → chunk-IEUU7O4F.js.map} +0 -0
- /package/dist/{chunk-WSGF57U2.js.map → chunk-JQDZQ4TB.js.map} +0 -0
- /package/dist/{chunk-W7L6HXUC.js.map → chunk-LXOM6IQU.js.map} +0 -0
- /package/dist/{chunk-6JGNHWCI.js.map → chunk-OBIRVF36.js.map} +0 -0
- /package/dist/{chunk-GUPISBV2.js.map → chunk-PP2JH3GP.js.map} +0 -0
- /package/dist/{chunk-OXJBNGBK.js.map → chunk-PSUB67YB.js.map} +0 -0
- /package/dist/{chunk-KIB7SDIJ.js.map → chunk-Q6YIJGXJ.js.map} +0 -0
- /package/dist/{chunk-ZT3EGNLR.js.map → chunk-QPD426WT.js.map} +0 -0
- /package/dist/{chunk-RLV3PQGH.js.map → chunk-QVO4YOB7.js.map} +0 -0
- /package/dist/{chunk-KQAFEZQX.js.map → chunk-VDX2J7OX.js.map} +0 -0
- /package/dist/{chunk-IK7DCC5H.js.map → chunk-VMGLYN42.js.map} +0 -0
- /package/dist/{chunk-NSKYFGDL.js.map → chunk-X4QQB7O6.js.map} +0 -0
- /package/dist/{first-start-migration-GYJWIH36.js.map → first-start-migration-FF7YFGRP.js.map} +0 -0
- /package/dist/{tier-stats-SKML2OSF.js.map → tier-stats-3LYQ3VV5.js.map} +0 -0
|
@@ -0,0 +1,289 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
|
|
3
|
+
import type { PluginConfig, RecallPlanMode } from "./types.js";
|
|
4
|
+
import { planRecallMode } from "./intent.js";
|
|
5
|
+
import {
|
|
6
|
+
FallbackLlmClient,
|
|
7
|
+
fallbackLlmRuntimeContextFromConfig,
|
|
8
|
+
gatewayTaskChainOptions,
|
|
9
|
+
type FallbackLlmOptions,
|
|
10
|
+
} from "./fallback-llm.js";
|
|
11
|
+
import { log } from "./logger.js";
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* LLM-based recall planning (issue #1367, Option C).
|
|
15
|
+
*
|
|
16
|
+
* Classifies an incoming prompt into a {@link RecallPlanMode} using an LLM
|
|
17
|
+
* instead of (or alongside) the regex heuristic in {@link planRecallMode}.
|
|
18
|
+
*
|
|
19
|
+
* Provider-agnostic by construction: it routes through {@link FallbackLlmClient},
|
|
20
|
+
* which resolves the model chain from gateway providers (OpenAI, Anthropic,
|
|
21
|
+
* Ollama, Codex, …) or gateway agent personas / `taskModelChain`. Nothing here
|
|
22
|
+
* is hard-coded to a single provider or to OpenAI's Responses API — the API
|
|
23
|
+
* dialect is chosen per-provider by the client based on each provider's `api`
|
|
24
|
+
* field. The configured `recallPlannerModel` is tried first, with the broader
|
|
25
|
+
* task chain (and the gateway default) as resilient fallbacks.
|
|
26
|
+
*
|
|
27
|
+
* Invariants:
|
|
28
|
+
* - Never throws to the caller (gotcha #13). Any LLM failure, timeout, empty
|
|
29
|
+
* response, or unavailable backend falls back to the heuristic result and
|
|
30
|
+
* sets `fallbackUsed: true` (gotcha #34 — failures are distinct from a valid
|
|
31
|
+
* classification).
|
|
32
|
+
* - When `recallPlannerLlmEnabled` is false the LLM is never contacted.
|
|
33
|
+
*/
|
|
34
|
+
|
|
35
|
+
export type RecallPlannerSource = "llm" | "heuristic" | "heuristic-fallback";
|
|
36
|
+
|
|
37
|
+
export interface RecallPlannerLlmResult {
|
|
38
|
+
/** The mode to act on. */
|
|
39
|
+
mode: RecallPlanMode;
|
|
40
|
+
/** The heuristic mode, always computed (the fallback floor / shadow baseline). */
|
|
41
|
+
heuristicMode: RecallPlanMode;
|
|
42
|
+
/** Where `mode` came from. */
|
|
43
|
+
source: RecallPlannerSource;
|
|
44
|
+
/** Short human-readable rationale (LLM reason, or why we fell back). */
|
|
45
|
+
reason: string;
|
|
46
|
+
/** Model that actually served the classification, when an LLM was used. */
|
|
47
|
+
modelUsed?: string;
|
|
48
|
+
/** Wall-clock spent in the LLM call (0 when no call was made). */
|
|
49
|
+
latencyMs: number;
|
|
50
|
+
/** True when the LLM was enabled but we had to fall back to the heuristic. */
|
|
51
|
+
fallbackUsed: boolean;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const PLANNER_SCHEMA = z.object({
|
|
55
|
+
// gotcha #2: optional fields use .optional().nullable()
|
|
56
|
+
mode: z.enum(["no_recall", "minimal", "full", "graph_mode"]),
|
|
57
|
+
reason: z.string().max(280).optional().nullable(),
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
const SYSTEM_PROMPT = [
|
|
61
|
+
"You are a recall-planning classifier for a long-term memory system.",
|
|
62
|
+
"Given the user's latest message, decide how much stored memory should be retrieved before the assistant responds.",
|
|
63
|
+
"Reply with a single JSON object: {\"mode\": <one of no_recall|minimal|full|graph_mode>, \"reason\": <short string>}.",
|
|
64
|
+
"",
|
|
65
|
+
"Modes:",
|
|
66
|
+
'- "no_recall": low-information acknowledgements or chit-chat with nothing to look up (e.g. "ok", "thanks", "sounds good"). Retrieve nothing.',
|
|
67
|
+
'- "minimal": short, self-contained operational directives that rarely need history (e.g. "restart the service", "run the tests", "show status"). Retrieve a little.',
|
|
68
|
+
'- "full": anything memory-seeking, analytical, or a question that benefits from prior context, decisions, or facts. This is the safe default when unsure.',
|
|
69
|
+
'- "graph_mode": queries about timelines, sequences, history, causal chains, or root cause ("how did we get here", "what led to this regression"). Retrieve relationship/graph context.',
|
|
70
|
+
"",
|
|
71
|
+
"When uncertain, prefer \"full\" over dropping recall. Never invent facts; only classify intent.",
|
|
72
|
+
].join("\n");
|
|
73
|
+
|
|
74
|
+
/** Clamp a planner prompt to the configured character budget. */
|
|
75
|
+
function clampPrompt(prompt: string, maxChars: number): string {
|
|
76
|
+
const safeMax = Number.isFinite(maxChars) && maxChars > 0 ? Math.floor(maxChars) : 4000;
|
|
77
|
+
if (prompt.length <= safeMax) return prompt;
|
|
78
|
+
return prompt.slice(0, safeMax);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/** Trim and cap the optional memory hints used to ground the classification. */
|
|
82
|
+
function clampHints(hints: string[] | undefined, maxHints: number): string[] {
|
|
83
|
+
if (!Array.isArray(hints) || hints.length === 0) return [];
|
|
84
|
+
const safeMax = Number.isFinite(maxHints) && maxHints > 0 ? Math.floor(maxHints) : 0;
|
|
85
|
+
if (safeMax <= 0) return [];
|
|
86
|
+
const cleaned: string[] = [];
|
|
87
|
+
for (const hint of hints) {
|
|
88
|
+
if (typeof hint !== "string") continue;
|
|
89
|
+
const trimmed = hint.trim();
|
|
90
|
+
if (trimmed.length === 0) continue;
|
|
91
|
+
cleaned.push(trimmed);
|
|
92
|
+
if (cleaned.length >= safeMax) break;
|
|
93
|
+
}
|
|
94
|
+
return cleaned;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
function buildMessages(
|
|
98
|
+
prompt: string,
|
|
99
|
+
hints: string[],
|
|
100
|
+
config: PluginConfig,
|
|
101
|
+
): Array<{ role: "system" | "user" | "assistant"; content: string }> {
|
|
102
|
+
const clampedPrompt = clampPrompt(prompt, config.recallPlannerMaxPromptChars);
|
|
103
|
+
const userParts = [`User message:\n${clampedPrompt}`];
|
|
104
|
+
if (hints.length > 0) {
|
|
105
|
+
userParts.push(
|
|
106
|
+
`\nRecent memory topics (for grounding only, do not treat as the message):\n- ${hints.join("\n- ")}`,
|
|
107
|
+
);
|
|
108
|
+
}
|
|
109
|
+
userParts.push('\nRespond with JSON only: {"mode": "...", "reason": "..."}.');
|
|
110
|
+
return [
|
|
111
|
+
{ role: "system", content: SYSTEM_PROMPT },
|
|
112
|
+
{ role: "user", content: userParts.join("\n") },
|
|
113
|
+
];
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Resolve the FallbackLlmClient routing options for the recall planner.
|
|
118
|
+
*
|
|
119
|
+
* - The dedicated `recallPlannerModel` is tried first (as the `model`
|
|
120
|
+
* override — it is prepended to the chain by FallbackLlmClient). If it does
|
|
121
|
+
* not resolve to a configured provider it is silently skipped, so a stale
|
|
122
|
+
* default never breaks routing.
|
|
123
|
+
* - In gateway mode the shared `gatewayTaskChainOptions` (taskModelChain >
|
|
124
|
+
* gatewayAgentId, gotcha #22) is layered in as the fallback chain, plus the
|
|
125
|
+
* implicit gateway default appended by the client.
|
|
126
|
+
* - In plugin mode only the explicit model + gateway providers apply.
|
|
127
|
+
*/
|
|
128
|
+
/**
|
|
129
|
+
* A `recallPlannerModel` value is only usable as a FallbackLlmClient `model`
|
|
130
|
+
* override when it is provider-qualified (`provider/model`). The client's
|
|
131
|
+
* `parseModelString` rejects bare names, so forwarding a bare value (e.g. the
|
|
132
|
+
* legacy default `"gpt-5.5"`) would log "invalid model format" on every call
|
|
133
|
+
* and never resolve. Bare values are dropped so routing falls through to the
|
|
134
|
+
* gateway chain / agent / default instead (issue #1367 review on PR #1428).
|
|
135
|
+
*/
|
|
136
|
+
function qualifiedPlannerModel(recallPlannerModel: string | undefined): string | undefined {
|
|
137
|
+
if (typeof recallPlannerModel !== "string") return undefined;
|
|
138
|
+
const trimmed = recallPlannerModel.trim();
|
|
139
|
+
return trimmed.includes("/") ? trimmed : undefined;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
export function resolveRecallPlannerLlmOptions(
|
|
143
|
+
config: Pick<
|
|
144
|
+
PluginConfig,
|
|
145
|
+
"modelSource" | "taskModelChain" | "gatewayAgentId" | "recallPlannerModel" | "recallPlannerTimeoutMs"
|
|
146
|
+
>,
|
|
147
|
+
): FallbackLlmOptions {
|
|
148
|
+
const chainOptions =
|
|
149
|
+
config.modelSource === "gateway" ? gatewayTaskChainOptions(config) : {};
|
|
150
|
+
return {
|
|
151
|
+
...chainOptions,
|
|
152
|
+
model: qualifiedPlannerModel(config.recallPlannerModel),
|
|
153
|
+
temperature: 0,
|
|
154
|
+
maxTokens: 64,
|
|
155
|
+
timeoutMs:
|
|
156
|
+
typeof config.recallPlannerTimeoutMs === "number" && config.recallPlannerTimeoutMs > 0
|
|
157
|
+
? config.recallPlannerTimeoutMs
|
|
158
|
+
: 1500,
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
// One-time warning per distinct routing signature so an opted-in operator with
|
|
163
|
+
// no usable model learns why planning silently uses the heuristic, without
|
|
164
|
+
// spamming a line on every recall.
|
|
165
|
+
const warnedNoRoutingSignatures = new Set<string>();
|
|
166
|
+
|
|
167
|
+
function heuristicResult(
|
|
168
|
+
heuristicMode: RecallPlanMode,
|
|
169
|
+
source: RecallPlannerSource,
|
|
170
|
+
reason: string,
|
|
171
|
+
latencyMs: number,
|
|
172
|
+
fallbackUsed: boolean,
|
|
173
|
+
): RecallPlannerLlmResult {
|
|
174
|
+
return { mode: heuristicMode, heuristicMode, source, reason, latencyMs, fallbackUsed };
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* Plan the recall mode for `prompt`, optionally consulting an LLM.
|
|
179
|
+
*
|
|
180
|
+
* Always safe to call: returns the heuristic result when the LLM is disabled,
|
|
181
|
+
* unavailable, or fails.
|
|
182
|
+
*
|
|
183
|
+
* @param llm injectable client (tests pass a stub); constructed from gateway
|
|
184
|
+
* config when omitted.
|
|
185
|
+
*/
|
|
186
|
+
export async function planRecallModeLLM(
|
|
187
|
+
prompt: string,
|
|
188
|
+
hints: string[] | undefined,
|
|
189
|
+
config: PluginConfig,
|
|
190
|
+
llm?: FallbackLlmClient,
|
|
191
|
+
signal?: AbortSignal,
|
|
192
|
+
): Promise<RecallPlannerLlmResult> {
|
|
193
|
+
const heuristicMode = planRecallMode(prompt);
|
|
194
|
+
|
|
195
|
+
if (!config.recallPlannerLlmEnabled) {
|
|
196
|
+
return heuristicResult(heuristicMode, "heuristic", "llm-disabled", 0, false);
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
// Participate in the recall cancellation contract: if the outer recall is
|
|
200
|
+
// already aborted (outer timeout / reset / session abort), don't start an LLM
|
|
201
|
+
// round-trip — fall back to the heuristic immediately (#1428 review).
|
|
202
|
+
if (signal?.aborted) {
|
|
203
|
+
return heuristicResult(heuristicMode, "heuristic-fallback", "aborted", 0, true);
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
const safePrompt = typeof prompt === "string" ? prompt.trim() : "";
|
|
207
|
+
if (safePrompt.length === 0) {
|
|
208
|
+
// Empty prompts never need an LLM round-trip.
|
|
209
|
+
return heuristicResult(heuristicMode, "heuristic", "empty-prompt", 0, false);
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
const client =
|
|
213
|
+
llm ??
|
|
214
|
+
new FallbackLlmClient(
|
|
215
|
+
config.gatewayConfig,
|
|
216
|
+
fallbackLlmRuntimeContextFromConfig(config),
|
|
217
|
+
);
|
|
218
|
+
|
|
219
|
+
// Forward the recall abort signal so an aborted/timed-out outer recall can
|
|
220
|
+
// cancel an in-flight planner call (FallbackLlmClient honors `signal`).
|
|
221
|
+
const options = { ...resolveRecallPlannerLlmOptions(config), signal };
|
|
222
|
+
|
|
223
|
+
// Availability check uses the same routing options so plugin-mode / empty
|
|
224
|
+
// chains short-circuit to the heuristic without a network attempt. `model`
|
|
225
|
+
// here is already provider-qualified (bare names were dropped), so a present
|
|
226
|
+
// model means the override is genuinely routable.
|
|
227
|
+
const availabilityProbe = {
|
|
228
|
+
agentId: options.agentId,
|
|
229
|
+
modelChain: options.modelChain,
|
|
230
|
+
};
|
|
231
|
+
if (!client.isAvailable(availabilityProbe) && !options.model) {
|
|
232
|
+
// Opted-in but nothing routable resolves (e.g. plugin mode with the bare
|
|
233
|
+
// default `recallPlannerModel` and no gateway chain). Warn once so it's not
|
|
234
|
+
// a silent no-op, then fall back to the heuristic.
|
|
235
|
+
const signature = `${config.modelSource}:${config.recallPlannerModel ?? ""}`;
|
|
236
|
+
if (!warnedNoRoutingSignatures.has(signature)) {
|
|
237
|
+
warnedNoRoutingSignatures.add(signature);
|
|
238
|
+
log.warn(
|
|
239
|
+
"[recall-planner] recallPlannerLlmEnabled is on but no routable model resolves — " +
|
|
240
|
+
"set recallPlannerModel to a 'provider/model' value or configure a gateway model chain. " +
|
|
241
|
+
"Falling back to the heuristic planner.",
|
|
242
|
+
);
|
|
243
|
+
}
|
|
244
|
+
return heuristicResult(heuristicMode, "heuristic-fallback", "llm-no-model", 0, true);
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
const clampedHints = clampHints(hints, config.recallPlannerMaxMemoryHints);
|
|
248
|
+
const messages = buildMessages(safePrompt, clampedHints, config);
|
|
249
|
+
|
|
250
|
+
const start = Date.now();
|
|
251
|
+
try {
|
|
252
|
+
const detailed = await client.parseWithSchemaDetailed(messages, PLANNER_SCHEMA, options);
|
|
253
|
+
const latencyMs = Date.now() - start;
|
|
254
|
+
if (!detailed?.result) {
|
|
255
|
+
// Distinguish failure from a valid empty (gotcha #34): a null here means
|
|
256
|
+
// no parseable classification, so fall back to the heuristic.
|
|
257
|
+
return heuristicResult(heuristicMode, "heuristic-fallback", "llm-empty", latencyMs, true);
|
|
258
|
+
}
|
|
259
|
+
const mode = detailed.result.mode;
|
|
260
|
+
const reason =
|
|
261
|
+
typeof detailed.result.reason === "string" && detailed.result.reason.trim().length > 0
|
|
262
|
+
? detailed.result.reason.trim()
|
|
263
|
+
: "llm-classified";
|
|
264
|
+
return {
|
|
265
|
+
mode,
|
|
266
|
+
heuristicMode,
|
|
267
|
+
source: "llm",
|
|
268
|
+
reason,
|
|
269
|
+
modelUsed: detailed.modelUsed,
|
|
270
|
+
latencyMs,
|
|
271
|
+
fallbackUsed: false,
|
|
272
|
+
};
|
|
273
|
+
} catch (err) {
|
|
274
|
+
const latencyMs = Date.now() - start;
|
|
275
|
+
if (signal?.aborted) {
|
|
276
|
+
// Cancelled by the outer recall — expected, not an error worth warning on.
|
|
277
|
+
return heuristicResult(heuristicMode, "heuristic-fallback", "aborted", latencyMs, true);
|
|
278
|
+
}
|
|
279
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
280
|
+
log.warn(`[recall-planner] LLM failed, falling back to heuristic: ${message}`);
|
|
281
|
+
return heuristicResult(
|
|
282
|
+
heuristicMode,
|
|
283
|
+
"heuristic-fallback",
|
|
284
|
+
`llm-error:${message}`,
|
|
285
|
+
latencyMs,
|
|
286
|
+
true,
|
|
287
|
+
);
|
|
288
|
+
}
|
|
289
|
+
}
|
package/src/routing/store.ts
CHANGED
|
@@ -85,14 +85,10 @@ export class RoutingRulesStore {
|
|
|
85
85
|
}
|
|
86
86
|
|
|
87
87
|
async read(options?: RoutingEngineOptions): Promise<RouteRule[]> {
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
.filter((rule): rule is RouteRule => rule !== null);
|
|
93
|
-
} catch {
|
|
94
|
-
return [];
|
|
95
|
-
}
|
|
88
|
+
const persisted = await this.readPersistedRules();
|
|
89
|
+
return persisted
|
|
90
|
+
.map((rule) => normalizeRule(rule, options))
|
|
91
|
+
.filter((rule): rule is RouteRule => rule !== null);
|
|
96
92
|
}
|
|
97
93
|
|
|
98
94
|
async write(rules: RouteRule[], options?: RoutingEngineOptions): Promise<RouteRule[]> {
|
package/src/search/factory.ts
CHANGED
|
@@ -105,6 +105,9 @@ function qmdOptions(config: PluginConfig): QmdClientOptions {
|
|
|
105
105
|
qmdEmbedModel: config.qmdEmbedModel,
|
|
106
106
|
qmdRerankModel: config.qmdRerankModel,
|
|
107
107
|
qmdGenerateModel: config.qmdGenerateModel,
|
|
108
|
+
qmdSearchStrategy: config.qmdSearchStrategy,
|
|
109
|
+
qmdSubprocessStrategy: config.qmdSubprocessStrategy,
|
|
110
|
+
qmdDaemonTimeoutMs: config.qmdDaemonTimeoutMs,
|
|
108
111
|
};
|
|
109
112
|
}
|
|
110
113
|
|
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
import { log } from "../logger.js";
|
|
2
|
-
import
|
|
2
|
+
import {
|
|
3
|
+
resolveEnsureCollectionArgs,
|
|
4
|
+
type SearchBackend,
|
|
5
|
+
type SearchExecutionOptions,
|
|
6
|
+
type SearchQueryOptions,
|
|
7
|
+
type SearchResult,
|
|
8
|
+
} from "./port.js";
|
|
3
9
|
import type { EmbedHelper, EmbedProviderIdentity, EmbedWithProviderResult } from "./embed-helper.js";
|
|
4
10
|
import { scanMemoryDir } from "./document-scanner.js";
|
|
5
11
|
import { isSearchAborted, throwIfSearchAborted } from "./abort.js";
|
|
@@ -305,10 +311,16 @@ export class LanceDbBackend implements SearchBackend {
|
|
|
305
311
|
|
|
306
312
|
async ensureCollection(
|
|
307
313
|
_memoryDir: string,
|
|
308
|
-
|
|
314
|
+
collectionOrExecution?: string | SearchExecutionOptions,
|
|
315
|
+
execution?: SearchExecutionOptions,
|
|
309
316
|
): Promise<"present" | "missing" | "unknown" | "skipped"> {
|
|
317
|
+
const { collection, execution: effectiveExecution } = resolveEnsureCollectionArgs(
|
|
318
|
+
collectionOrExecution,
|
|
319
|
+
execution,
|
|
320
|
+
);
|
|
321
|
+
if (isSearchAborted(effectiveExecution)) return "skipped";
|
|
310
322
|
try {
|
|
311
|
-
await this.
|
|
323
|
+
await this.ensureTableForCollection(collection ?? this.collection);
|
|
312
324
|
return "present";
|
|
313
325
|
} catch {
|
|
314
326
|
return "missing";
|
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
import { log } from "../logger.js";
|
|
2
|
-
import
|
|
2
|
+
import {
|
|
3
|
+
resolveEnsureCollectionArgs,
|
|
4
|
+
type SearchBackend,
|
|
5
|
+
type SearchExecutionOptions,
|
|
6
|
+
type SearchQueryOptions,
|
|
7
|
+
type SearchResult,
|
|
8
|
+
} from "./port.js";
|
|
3
9
|
import { scanMemoryDir } from "./document-scanner.js";
|
|
4
10
|
import { isSearchAborted, throwIfSearchAborted } from "./abort.js";
|
|
5
11
|
|
|
@@ -134,6 +140,8 @@ export class MeilisearchBackend implements SearchBackend {
|
|
|
134
140
|
if (isSearchAborted(execution)) return;
|
|
135
141
|
|
|
136
142
|
try {
|
|
143
|
+
const ensured = await this.ensureCollection(memoryDir, collection, execution);
|
|
144
|
+
if (ensured === "skipped" || ensured === "missing") return;
|
|
137
145
|
const client = await this.ensureClient();
|
|
138
146
|
if (isSearchAborted(execution)) return;
|
|
139
147
|
const docs = await scanMemoryDir(memoryDir);
|
|
@@ -196,21 +204,47 @@ export class MeilisearchBackend implements SearchBackend {
|
|
|
196
204
|
|
|
197
205
|
async ensureCollection(
|
|
198
206
|
_memoryDir: string,
|
|
199
|
-
|
|
207
|
+
collectionOrExecution?: string | SearchExecutionOptions,
|
|
208
|
+
execution?: SearchExecutionOptions,
|
|
200
209
|
): Promise<"present" | "missing" | "unknown" | "skipped"> {
|
|
210
|
+
const { collection, execution: effectiveExecution } = resolveEnsureCollectionArgs(
|
|
211
|
+
collectionOrExecution,
|
|
212
|
+
execution,
|
|
213
|
+
);
|
|
201
214
|
if (!this.available) return "skipped";
|
|
215
|
+
if (isSearchAborted(effectiveExecution)) return "skipped";
|
|
216
|
+
const targetCollection = collection ?? this.collection;
|
|
202
217
|
try {
|
|
203
218
|
const client = await this.ensureClient();
|
|
219
|
+
if (isSearchAborted(effectiveExecution)) return "skipped";
|
|
204
220
|
try {
|
|
205
|
-
await client.getIndex(
|
|
221
|
+
await client.getIndex(targetCollection);
|
|
206
222
|
return "present";
|
|
207
|
-
} catch {
|
|
223
|
+
} catch (err) {
|
|
224
|
+
if (!isMeilisearchIndexNotFoundError(err)) {
|
|
225
|
+
log.debug(
|
|
226
|
+
`MeilisearchBackend collection check unavailable for "${targetCollection}" (will not skip update): ${
|
|
227
|
+
err instanceof Error ? err.message : String(err)
|
|
228
|
+
}`,
|
|
229
|
+
);
|
|
230
|
+
return "unknown";
|
|
231
|
+
}
|
|
208
232
|
// Index doesn't exist — create it
|
|
209
|
-
|
|
233
|
+
if (isSearchAborted(effectiveExecution)) return "skipped";
|
|
234
|
+
const createTask = await client.createIndex(targetCollection, { primaryKey: "id" });
|
|
235
|
+
if (isSearchAborted(effectiveExecution)) return "skipped";
|
|
236
|
+
if (createTask?.taskUid !== undefined && createTask?.taskUid !== null) {
|
|
237
|
+
await client.waitForTask(createTask.taskUid, { timeOutMs: this.timeoutMs });
|
|
238
|
+
}
|
|
210
239
|
return "present";
|
|
211
240
|
}
|
|
212
|
-
} catch {
|
|
213
|
-
|
|
241
|
+
} catch (err) {
|
|
242
|
+
log.debug(
|
|
243
|
+
`MeilisearchBackend collection check failed for "${targetCollection}" (will not disable updates): ${
|
|
244
|
+
err instanceof Error ? err.message : String(err)
|
|
245
|
+
}`,
|
|
246
|
+
);
|
|
247
|
+
return "unknown";
|
|
214
248
|
}
|
|
215
249
|
}
|
|
216
250
|
|
|
@@ -261,3 +295,32 @@ export class MeilisearchBackend implements SearchBackend {
|
|
|
261
295
|
}));
|
|
262
296
|
}
|
|
263
297
|
}
|
|
298
|
+
|
|
299
|
+
function isMeilisearchIndexNotFoundError(err: unknown): boolean {
|
|
300
|
+
if (!err || typeof err !== "object") {
|
|
301
|
+
return false;
|
|
302
|
+
}
|
|
303
|
+
const record = err as Record<string, unknown>;
|
|
304
|
+
const code = typeof record.code === "string" ? record.code.toLowerCase() : "";
|
|
305
|
+
const type = typeof record.type === "string" ? record.type.toLowerCase() : "";
|
|
306
|
+
const status =
|
|
307
|
+
typeof record.status === "number"
|
|
308
|
+
? record.status
|
|
309
|
+
: typeof record.statusCode === "number"
|
|
310
|
+
? record.statusCode
|
|
311
|
+
: undefined;
|
|
312
|
+
const message = err instanceof Error
|
|
313
|
+
? err.message.toLowerCase()
|
|
314
|
+
: typeof record.message === "string"
|
|
315
|
+
? record.message.toLowerCase()
|
|
316
|
+
: "";
|
|
317
|
+
|
|
318
|
+
return (
|
|
319
|
+
code === "index_not_found"
|
|
320
|
+
|| type === "index_not_found"
|
|
321
|
+
|| status === 404
|
|
322
|
+
|| message.includes("index_not_found")
|
|
323
|
+
|| /index .*not found/.test(message)
|
|
324
|
+
|| /index .*does not exist/.test(message)
|
|
325
|
+
);
|
|
326
|
+
}
|
|
@@ -51,7 +51,11 @@ export class NoopSearchBackend implements SearchBackend {
|
|
|
51
51
|
async embed(): Promise<void> {}
|
|
52
52
|
async embedCollection(_collection: string): Promise<void> {}
|
|
53
53
|
|
|
54
|
-
async ensureCollection(
|
|
54
|
+
async ensureCollection(
|
|
55
|
+
_memoryDir: string,
|
|
56
|
+
_collectionOrExecution?: string | SearchExecutionOptions,
|
|
57
|
+
_execution?: SearchExecutionOptions,
|
|
58
|
+
): Promise<"skipped"> {
|
|
55
59
|
return "skipped";
|
|
56
60
|
}
|
|
57
61
|
}
|
|
@@ -1,7 +1,13 @@
|
|
|
1
1
|
import path from "node:path";
|
|
2
2
|
import { mkdir, readdir, readFile, rename, rm, writeFile } from "node:fs/promises";
|
|
3
3
|
import { log } from "../logger.js";
|
|
4
|
-
import
|
|
4
|
+
import {
|
|
5
|
+
resolveEnsureCollectionArgs,
|
|
6
|
+
type SearchBackend,
|
|
7
|
+
type SearchExecutionOptions,
|
|
8
|
+
type SearchQueryOptions,
|
|
9
|
+
type SearchResult,
|
|
10
|
+
} from "./port.js";
|
|
5
11
|
import type { EmbedHelper, EmbedProviderIdentity, EmbedWithProviderResult } from "./embed-helper.js";
|
|
6
12
|
import { scanMemoryDir } from "./document-scanner.js";
|
|
7
13
|
import { isSearchAborted, throwIfSearchAborted } from "./abort.js";
|
|
@@ -357,11 +363,17 @@ export class OramaBackend implements SearchBackend {
|
|
|
357
363
|
|
|
358
364
|
async ensureCollection(
|
|
359
365
|
_memoryDir: string,
|
|
360
|
-
|
|
366
|
+
collectionOrExecution?: string | SearchExecutionOptions,
|
|
367
|
+
execution?: SearchExecutionOptions,
|
|
361
368
|
): Promise<"present" | "missing" | "unknown" | "skipped"> {
|
|
369
|
+
const { collection, execution: effectiveExecution } = resolveEnsureCollectionArgs(
|
|
370
|
+
collectionOrExecution,
|
|
371
|
+
execution,
|
|
372
|
+
);
|
|
373
|
+
if (isSearchAborted(effectiveExecution)) return "skipped";
|
|
362
374
|
try {
|
|
363
375
|
await this.ensureModules();
|
|
364
|
-
await this.
|
|
376
|
+
await this.ensureDbForCollection(collection ?? this.collection);
|
|
365
377
|
return "present";
|
|
366
378
|
} catch {
|
|
367
379
|
return "missing";
|
package/src/search/port.ts
CHANGED
|
@@ -16,6 +16,16 @@ export interface SearchExecutionOptions {
|
|
|
16
16
|
signal?: AbortSignal;
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
+
export function resolveEnsureCollectionArgs(
|
|
20
|
+
collectionOrExecution?: string | SearchExecutionOptions,
|
|
21
|
+
execution?: SearchExecutionOptions,
|
|
22
|
+
): { collection?: string; execution?: SearchExecutionOptions } {
|
|
23
|
+
if (typeof collectionOrExecution === "string") {
|
|
24
|
+
return { collection: collectionOrExecution, execution };
|
|
25
|
+
}
|
|
26
|
+
return { collection: undefined, execution: collectionOrExecution ?? execution };
|
|
27
|
+
}
|
|
28
|
+
|
|
19
29
|
/**
|
|
20
30
|
* Abstract search backend interface.
|
|
21
31
|
*
|
|
@@ -87,4 +97,9 @@ export interface SearchBackend {
|
|
|
87
97
|
memoryDir: string,
|
|
88
98
|
execution?: SearchExecutionOptions,
|
|
89
99
|
): Promise<"present" | "missing" | "unknown" | "skipped">;
|
|
100
|
+
ensureCollection(
|
|
101
|
+
memoryDir: string,
|
|
102
|
+
collection?: string,
|
|
103
|
+
execution?: SearchExecutionOptions,
|
|
104
|
+
): Promise<"present" | "missing" | "unknown" | "skipped">;
|
|
90
105
|
}
|
|
@@ -82,7 +82,11 @@ export class RemoteSearchBackend implements SearchBackend {
|
|
|
82
82
|
async embed(): Promise<void> {}
|
|
83
83
|
async embedCollection(_collection: string): Promise<void> {}
|
|
84
84
|
|
|
85
|
-
async ensureCollection(
|
|
85
|
+
async ensureCollection(
|
|
86
|
+
_memoryDir: string,
|
|
87
|
+
_collectionOrExecution?: string | SearchExecutionOptions,
|
|
88
|
+
_execution?: SearchExecutionOptions,
|
|
89
|
+
): Promise<"skipped"> {
|
|
86
90
|
return "skipped";
|
|
87
91
|
}
|
|
88
92
|
|
|
@@ -242,7 +242,7 @@ export class SessionObserverState {
|
|
|
242
242
|
}
|
|
243
243
|
|
|
244
244
|
private async writeSessions(sessionsMap: Map<string, SessionObserverCursor>): Promise<void> {
|
|
245
|
-
const sessions
|
|
245
|
+
const sessions = Object.create(null) as Record<string, SessionObserverCursor>;
|
|
246
246
|
for (const [key, value] of sessionsMap.entries()) {
|
|
247
247
|
sessions[key] = value;
|
|
248
248
|
}
|
package/src/summarizer.ts
CHANGED
|
@@ -3,7 +3,7 @@ import path from "node:path";
|
|
|
3
3
|
import { z } from "zod";
|
|
4
4
|
import { log } from "./logger.js";
|
|
5
5
|
import { LocalLlmClient } from "./local-llm.js";
|
|
6
|
-
import { FallbackLlmClient, fallbackLlmRuntimeContextFromConfig } from "./fallback-llm.js";
|
|
6
|
+
import { FallbackLlmClient, fallbackLlmRuntimeContextFromConfig, gatewayTaskChainOptions } from "./fallback-llm.js";
|
|
7
7
|
import { ModelRegistry } from "./model-registry.js";
|
|
8
8
|
import { extractJsonCandidates } from "./json-extract.js";
|
|
9
9
|
import type { HourlySummary, TranscriptEntry, PluginConfig, GatewayConfig } from "./types.js";
|
|
@@ -85,8 +85,8 @@ export class HourlySummarizer {
|
|
|
85
85
|
|
|
86
86
|
private withGatewayAgent(options: import("./fallback-llm.js").FallbackLlmOptions): import("./fallback-llm.js").FallbackLlmOptions {
|
|
87
87
|
if (!this.useGatewayModelSource) return options;
|
|
88
|
-
|
|
89
|
-
return
|
|
88
|
+
// Shared resolution (taskModelChain > gatewayAgentId) — gotcha #22. Issue #1365.
|
|
89
|
+
return { ...options, ...gatewayTaskChainOptions(this.config) };
|
|
90
90
|
}
|
|
91
91
|
|
|
92
92
|
async initialize(): Promise<void> {
|
|
@@ -218,3 +218,21 @@ test("tag queries distinguish missing index from valid no-match results", async
|
|
|
218
218
|
assert.deepEqual(noFilterPrefilter.expandedTags, []);
|
|
219
219
|
assert.equal(noFilterPrefilter.paths, null);
|
|
220
220
|
});
|
|
221
|
+
|
|
222
|
+
test("indexMemory replaces stale date and tag memberships for an existing path", async () => {
|
|
223
|
+
const memoryDir = await mkdtemp(join(tmpdir(), "remnic-temporal-index-update-"));
|
|
224
|
+
const memoryPath = "/tmp/remnic-temporal-updated-memory.md";
|
|
225
|
+
|
|
226
|
+
indexMemory(memoryDir, memoryPath, "2026-01-01T00:00:00.000Z", ["alpha"]);
|
|
227
|
+
indexMemory(memoryDir, memoryPath, "2026-02-01T00:00:00.000Z", ["beta"]);
|
|
228
|
+
|
|
229
|
+
const januaryMatches = await queryByDateRangeAsync(memoryDir, "2026-01-01", "2026-01-02");
|
|
230
|
+
const februaryMatches = await queryByDateRangeAsync(memoryDir, "2026-02-01", "2026-02-02");
|
|
231
|
+
const alphaMatches = await queryByTagsAsync(memoryDir, ["alpha"]);
|
|
232
|
+
const betaMatches = await queryByTagsAsync(memoryDir, ["beta"]);
|
|
233
|
+
|
|
234
|
+
assert.deepEqual(januaryMatches, new Set());
|
|
235
|
+
assert.deepEqual(februaryMatches, new Set([memoryPath]));
|
|
236
|
+
assert.deepEqual(alphaMatches, new Set());
|
|
237
|
+
assert.deepEqual(betaMatches, new Set([memoryPath]));
|
|
238
|
+
});
|