@remnic/core 9.3.613 → 9.3.614
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 +58 -57
- package/dist/access-cli.js.map +1 -1
- package/dist/access-http.d.ts +4 -2
- package/dist/access-http.js +22 -22
- package/dist/access-mcp.d.ts +9 -2
- package/dist/access-mcp.js +19 -19
- package/dist/access-schema.d.ts +12 -12
- package/dist/access-schema.js +3 -3
- package/dist/{access-service-D2J9dh_9.d.ts → access-service-DGG_2xPK.d.ts} +1 -1
- package/dist/access-service.d.ts +2 -2
- package/dist/access-service.js +16 -16
- 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-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-IOTENEVL.js → chunk-7YQFWOF7.js} +57 -50
- package/dist/chunk-7YQFWOF7.js.map +1 -0
- package/dist/{chunk-2QANQKSQ.js → chunk-ADNZVFXG.js} +15 -15
- 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-TH67Q46T.js → chunk-B6FDZPCF.js} +17 -9
- package/dist/chunk-B6FDZPCF.js.map +1 -0
- 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-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-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-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-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-PPPZY2EU.js → chunk-QEMCQFDW.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-HJNQQICM.js → chunk-T5XWMMU2.js} +107 -50
- package/dist/chunk-T5XWMMU2.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-5RPTH6AU.js → chunk-VPGUMLBA.js} +8 -7
- package/dist/chunk-VPGUMLBA.js.map +1 -0
- package/dist/{chunk-KM2A35EO.js → chunk-WB3LYXC5.js} +11 -7
- package/dist/chunk-WB3LYXC5.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/{cli-OrfKXNU4.d.ts → cli-DWeu7eTY.d.ts} +6 -2
- package/dist/cli.d.ts +3 -3
- package/dist/cli.js +60 -59
- 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 +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 +94 -93
- 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 +47 -44
- 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 +3 -0
- package/src/access-mcp.test.ts +51 -0
- package/src/access-mcp.ts +26 -5
- 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/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-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-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-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-2QANQKSQ.js.map → chunk-ADNZVFXG.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-PPPZY2EU.js.map → chunk-QEMCQFDW.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
package/src/fallback-llm.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { log } from "./logger.js";
|
|
2
2
|
import path from "node:path";
|
|
3
|
-
import type { GatewayConfig, ModelProviderConfig,
|
|
3
|
+
import type { AgentPersonaModelConfig, GatewayConfig, ModelProviderConfig, PluginConfig } from "./types.js";
|
|
4
4
|
import { extractJsonCandidates } from "./json-extract.js";
|
|
5
5
|
import {
|
|
6
6
|
buildChatCompletionTemperature,
|
|
@@ -25,10 +25,34 @@ export interface FallbackLlmOptions {
|
|
|
25
25
|
signal?: AbortSignal;
|
|
26
26
|
/** Explicit "provider/model" override to try before the configured chain. */
|
|
27
27
|
model?: string;
|
|
28
|
+
/** Explicit model chain override to use instead of the configured agent/default chain. */
|
|
29
|
+
modelChain?: AgentPersonaModelConfig;
|
|
28
30
|
/** Override which agent persona's model chain to use (by ID from agents.list[]). */
|
|
29
31
|
agentId?: string;
|
|
30
32
|
}
|
|
31
33
|
|
|
34
|
+
export interface FallbackLlmAvailabilityOptions {
|
|
35
|
+
agentId?: string;
|
|
36
|
+
modelChain?: AgentPersonaModelConfig;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Resolve the gateway routing options Remnic's background tasks should pass to
|
|
41
|
+
* FallbackLlmClient — extraction, fact/profile/identity consolidation,
|
|
42
|
+
* summarization, calibration, and causal/semantic consolidation. Single source
|
|
43
|
+
* of truth so every task path stays consistent and can't diverge (gotcha #22):
|
|
44
|
+
* in gateway mode an explicit `taskModelChain` wins over the gateway agent
|
|
45
|
+
* persona; otherwise the persona (if any) is used. Returns `{}` in plugin mode
|
|
46
|
+
* because the chain resolves through gateway providers only. Issue #1365.
|
|
47
|
+
*/
|
|
48
|
+
export function gatewayTaskChainOptions(
|
|
49
|
+
config: Pick<PluginConfig, "modelSource" | "taskModelChain" | "gatewayAgentId">,
|
|
50
|
+
): Pick<FallbackLlmOptions, "modelChain" | "agentId"> {
|
|
51
|
+
if (config.modelSource !== "gateway") return {};
|
|
52
|
+
if (config.taskModelChain) return { modelChain: config.taskModelChain };
|
|
53
|
+
return config.gatewayAgentId ? { agentId: config.gatewayAgentId } : {};
|
|
54
|
+
}
|
|
55
|
+
|
|
32
56
|
export interface FallbackLlmResponse {
|
|
33
57
|
content: string;
|
|
34
58
|
modelUsed: string;
|
|
@@ -120,8 +144,11 @@ export class FallbackLlmClient {
|
|
|
120
144
|
/**
|
|
121
145
|
* Check if fallback is available (gateway config has at least one model).
|
|
122
146
|
*/
|
|
123
|
-
isAvailable(
|
|
124
|
-
const
|
|
147
|
+
isAvailable(agentIdOrOptions?: string | FallbackLlmAvailabilityOptions): boolean {
|
|
148
|
+
const options = typeof agentIdOrOptions === "string"
|
|
149
|
+
? { agentId: agentIdOrOptions }
|
|
150
|
+
: (agentIdOrOptions ?? {});
|
|
151
|
+
const models = this.getModelChain(options.agentId, undefined, options.modelChain);
|
|
125
152
|
return models.length > 0;
|
|
126
153
|
}
|
|
127
154
|
|
|
@@ -134,7 +161,7 @@ export class FallbackLlmClient {
|
|
|
134
161
|
messages: Array<{ role: "system" | "user" | "assistant"; content: string }>,
|
|
135
162
|
options: FallbackLlmOptions = {},
|
|
136
163
|
): Promise<FallbackLlmResponse | null> {
|
|
137
|
-
const models = this.getModelChain(options.agentId, options.model);
|
|
164
|
+
const models = this.getModelChain(options.agentId, options.model, options.modelChain);
|
|
138
165
|
if (models.length === 0) {
|
|
139
166
|
log.warn("fallback LLM: no models configured in gateway");
|
|
140
167
|
return null;
|
|
@@ -262,18 +289,30 @@ export class FallbackLlmClient {
|
|
|
262
289
|
* Get the full model chain from gateway config.
|
|
263
290
|
* Returns array of models in order: [primary, fallback1, fallback2, ...]
|
|
264
291
|
*
|
|
265
|
-
* When
|
|
266
|
-
*
|
|
267
|
-
*
|
|
292
|
+
* When modelChainOverride is provided, uses it instead of any configured
|
|
293
|
+
* agent/default chain. Otherwise, when agentId is provided, looks up the
|
|
294
|
+
* matching entry in agents.list[] and uses that persona's model chain.
|
|
295
|
+
* Falls back to agents.defaults.model if agentId is not found or not provided.
|
|
268
296
|
*/
|
|
269
|
-
private getModelChain(
|
|
297
|
+
private getModelChain(
|
|
298
|
+
agentId?: string,
|
|
299
|
+
modelOverride?: string,
|
|
300
|
+
modelChainOverride?: AgentPersonaModelConfig,
|
|
301
|
+
): ModelRef[] {
|
|
270
302
|
const chain: ModelRef[] = [];
|
|
271
303
|
const providers = this.gatewayConfig?.models?.providers ?? {};
|
|
272
304
|
|
|
273
|
-
// Resolve the model config: agent persona chain or global defaults
|
|
274
|
-
let modelConfig:
|
|
305
|
+
// Resolve the model config: explicit task chain, agent persona chain, or global defaults
|
|
306
|
+
let modelConfig: AgentPersonaModelConfig | undefined;
|
|
275
307
|
|
|
276
|
-
if (
|
|
308
|
+
if (modelChainOverride?.primary) {
|
|
309
|
+
modelConfig = modelChainOverride;
|
|
310
|
+
log.debug("fallback LLM: using explicit model chain override");
|
|
311
|
+
} else if (modelChainOverride) {
|
|
312
|
+
log.warn("fallback LLM: ignoring explicit model chain override without primary model");
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
if (!modelConfig && agentId) {
|
|
277
316
|
const persona = this.gatewayConfig?.agents?.list?.find(
|
|
278
317
|
(a) => a.id === agentId,
|
|
279
318
|
);
|
|
@@ -294,21 +333,20 @@ export class FallbackLlmClient {
|
|
|
294
333
|
// Build list of model strings: primary + fallbacks
|
|
295
334
|
const modelStrings: string[] = [];
|
|
296
335
|
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
if (!modelStrings.includes(modelConfig.primary)) {
|
|
303
|
-
modelStrings.push(modelConfig.primary);
|
|
336
|
+
const addModelString = (value: unknown): void => {
|
|
337
|
+
if (typeof value !== "string") return;
|
|
338
|
+
const trimmed = value.trim();
|
|
339
|
+
if (trimmed.length > 0 && !modelStrings.includes(trimmed)) {
|
|
340
|
+
modelStrings.push(trimmed);
|
|
304
341
|
}
|
|
305
|
-
}
|
|
342
|
+
};
|
|
343
|
+
|
|
344
|
+
addModelString(modelOverride);
|
|
345
|
+
addModelString(modelConfig?.primary);
|
|
306
346
|
|
|
307
347
|
if (Array.isArray(modelConfig?.fallbacks)) {
|
|
308
348
|
for (const fb of modelConfig.fallbacks) {
|
|
309
|
-
|
|
310
|
-
modelStrings.push(fb);
|
|
311
|
-
}
|
|
349
|
+
addModelString(fb);
|
|
312
350
|
}
|
|
313
351
|
}
|
|
314
352
|
|
|
@@ -320,6 +358,37 @@ export class FallbackLlmClient {
|
|
|
320
358
|
}
|
|
321
359
|
}
|
|
322
360
|
|
|
361
|
+
// Implicit last-resort: when a task-specific modelChain override is active,
|
|
362
|
+
// append the gateway default model so a stale or exhausted taskModelChain
|
|
363
|
+
// never leaves the chain empty — Remnic should never be the reason a chat is
|
|
364
|
+
// interrupted by a flush failure. Keyed on `modelChainOverride?.primary` —
|
|
365
|
+
// the SAME activation condition chain resolution uses above — so a
|
|
366
|
+
// primary-less override (e.g. {}) that falls through to a persona/default
|
|
367
|
+
// chain does NOT get the default appended (gotcha #39). Issue #1365 / PR #1370.
|
|
368
|
+
if (modelChainOverride?.primary && modelStrings.length > 0) {
|
|
369
|
+
// Append the FULL gateway default chain (primary + fallbacks), not just
|
|
370
|
+
// the primary — if the default primary is also unreachable, a listed
|
|
371
|
+
// default fallback may still succeed (cursor review #1425).
|
|
372
|
+
const defaults = this.gatewayConfig?.agents?.defaults?.model;
|
|
373
|
+
const defaultStrings: string[] = [
|
|
374
|
+
...(typeof defaults?.primary === "string" ? [defaults.primary] : []),
|
|
375
|
+
...(Array.isArray(defaults?.fallbacks) ? defaults.fallbacks : []),
|
|
376
|
+
];
|
|
377
|
+
for (const candidate of defaultStrings) {
|
|
378
|
+
if (typeof candidate !== "string") continue;
|
|
379
|
+
const trimmed = candidate.trim();
|
|
380
|
+
if (trimmed.length === 0 || modelStrings.includes(trimmed)) continue;
|
|
381
|
+
const defaultRef = this.parseModelString(trimmed, providers);
|
|
382
|
+
if (defaultRef) {
|
|
383
|
+
chain.push(defaultRef);
|
|
384
|
+
modelStrings.push(trimmed); // keep dedupe correct for later default fallbacks
|
|
385
|
+
log.debug(
|
|
386
|
+
`fallback LLM: appended gateway default model "${trimmed}" as implicit last resort`,
|
|
387
|
+
);
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
|
|
323
392
|
return chain;
|
|
324
393
|
}
|
|
325
394
|
|
|
@@ -388,40 +388,50 @@ export async function ensureGraphEdgeDecayCron(
|
|
|
388
388
|
|
|
389
389
|
const scheduleLabel = graphEdgeDecayScheduleLabel(scheduleExpr);
|
|
390
390
|
|
|
391
|
-
return ensureCronJob(
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
391
|
+
return ensureCronJob(
|
|
392
|
+
jobsPath,
|
|
393
|
+
GRAPH_EDGE_DECAY_CRON_ID,
|
|
394
|
+
() => ({
|
|
395
|
+
id: GRAPH_EDGE_DECAY_CRON_ID,
|
|
396
|
+
agentId,
|
|
397
|
+
// Schedule label reflects the actual cron expression (`daily` /
|
|
398
|
+
// `weekly` / `custom`) so cron dashboards do not show "weekly"
|
|
399
|
+
// when the schedule is in fact daily — Cursor review on PR #729.
|
|
400
|
+
name: `Remnic Graph Edge Decay (${scheduleLabel})`,
|
|
401
|
+
enabled: true,
|
|
402
|
+
schedule: {
|
|
403
|
+
kind: "cron",
|
|
404
|
+
expr: scheduleExpr,
|
|
405
|
+
tz: options.timezone,
|
|
406
|
+
},
|
|
407
|
+
sessionTarget: "isolated",
|
|
408
|
+
wakeMode: "now",
|
|
409
|
+
payload: {
|
|
410
|
+
kind: "agentTurn",
|
|
411
|
+
timeoutSeconds: 900,
|
|
412
|
+
thinking: "off",
|
|
413
|
+
message:
|
|
414
|
+
"You are OpenClaw automation. Call tool `engram.graph_edge_decay_run` with empty params. " +
|
|
415
|
+
"If successful output exactly NO_REPLY. On error output one concise line. Do NOT use message tool.",
|
|
416
|
+
},
|
|
417
|
+
delivery: { mode: "none" },
|
|
418
|
+
}),
|
|
419
|
+
{
|
|
420
|
+
updateExisting: true,
|
|
421
|
+
updateFields: ["name", "schedule"],
|
|
413
422
|
},
|
|
414
|
-
|
|
415
|
-
}));
|
|
423
|
+
);
|
|
416
424
|
}
|
|
417
425
|
|
|
418
426
|
/**
|
|
419
427
|
* Pick a cron expression that approximates a cadence in milliseconds.
|
|
420
428
|
*
|
|
421
|
-
* - cadence
|
|
422
|
-
* expressible in 5-field cron without
|
|
423
|
-
*
|
|
424
|
-
* - cadence
|
|
429
|
+
* - cadence <= 1 day → daily at 04:13. Sub-daily cadence is not natively
|
|
430
|
+
* expressible in 5-field cron without hour/minute step patterns; daily
|
|
431
|
+
* preserves the previous conservative behavior for those values.
|
|
432
|
+
* - cadence > 1 day → weekly on Sunday 04:13. Multi-day intervals like
|
|
433
|
+
* 2-6 days cannot be represented accurately by a portable 5-field cron
|
|
434
|
+
* expression, and daily would run more often than requested.
|
|
425
435
|
*
|
|
426
436
|
* Operators who need finer-grained control should set `scheduleExpr`
|
|
427
437
|
* directly via `ensureGraphEdgeDecayCron`.
|
|
@@ -431,7 +441,7 @@ export function graphEdgeDecayCadenceToCronExpr(cadenceMs: number): string {
|
|
|
431
441
|
return "13 4 * * 0";
|
|
432
442
|
}
|
|
433
443
|
const day = 24 * 60 * 60 * 1000;
|
|
434
|
-
if (cadenceMs
|
|
444
|
+
if (cadenceMs <= day) return "13 4 * * *";
|
|
435
445
|
return "13 4 * * 0";
|
|
436
446
|
}
|
|
437
447
|
|
|
@@ -72,9 +72,7 @@ export function buildChatGptMemoryInspectorActionRequest(
|
|
|
72
72
|
recall: EngramAccessRecallResponse,
|
|
73
73
|
xray: RecallXraySnapshot | null,
|
|
74
74
|
): ActionConfidenceRequest {
|
|
75
|
-
const provenances = xray
|
|
76
|
-
? recall.results.map(missingRecallProvenance)
|
|
77
|
-
: xray.results.map((result) => result.provenance ?? missingProvenance(result));
|
|
75
|
+
const provenances = buildRecallProvenances(recall, xray);
|
|
78
76
|
const hasUnsafeOrMissingProvenance = provenances.some(
|
|
79
77
|
(provenance) => provenance.safeToUse === false || provenance.safety === "blocked",
|
|
80
78
|
) || provenances.length < recall.count;
|
|
@@ -117,15 +115,7 @@ export function buildChatGptMemoryInspectorResult(
|
|
|
117
115
|
actionConfidence: ActionConfidenceResult,
|
|
118
116
|
): RemnicChatGptMemoryInspectorResult {
|
|
119
117
|
const xrayUnavailable = xray === null;
|
|
120
|
-
const
|
|
121
|
-
const xrayByPath = new Map<string, RecallXrayResult>();
|
|
122
|
-
for (const result of xray?.results ?? []) {
|
|
123
|
-
xrayById.set(result.memoryId, result);
|
|
124
|
-
xrayByPath.set(result.path, result);
|
|
125
|
-
}
|
|
126
|
-
const matchXrayResult = (summary: EngramAccessRecallResponse["results"][number]) =>
|
|
127
|
-
(summary.path ? xrayByPath.get(summary.path) : undefined)
|
|
128
|
-
?? xrayById.get(summary.id);
|
|
118
|
+
const matchXrayResult = buildXrayResultMatcher(xray);
|
|
129
119
|
const matchedXrayResults = recall.results.map(matchXrayResult);
|
|
130
120
|
|
|
131
121
|
const memories = recall.results.slice(0, 8).map((summary) => {
|
|
@@ -375,6 +365,40 @@ function average(values: number[]): number | undefined {
|
|
|
375
365
|
return values.reduce((sum, value) => sum + value, 0) / values.length;
|
|
376
366
|
}
|
|
377
367
|
|
|
368
|
+
function buildRecallProvenances(
|
|
369
|
+
recall: EngramAccessRecallResponse,
|
|
370
|
+
xray: RecallXraySnapshot | null,
|
|
371
|
+
): RetrievedMemoryProvenance[] {
|
|
372
|
+
if (xray === null) {
|
|
373
|
+
return recall.results.map(missingRecallProvenance);
|
|
374
|
+
}
|
|
375
|
+
const matchXrayResult = buildXrayResultMatcher(xray);
|
|
376
|
+
return recall.results.map((summary) => {
|
|
377
|
+
const result = matchXrayResult(summary);
|
|
378
|
+
if (result === undefined) {
|
|
379
|
+
return missingXrayResultProvenance(summary);
|
|
380
|
+
}
|
|
381
|
+
return result.provenance ?? missingProvenance(result);
|
|
382
|
+
});
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
function buildXrayResultMatcher(
|
|
386
|
+
xray: RecallXraySnapshot | null,
|
|
387
|
+
): (summary: EngramAccessRecallResponse["results"][number]) => RecallXrayResult | undefined {
|
|
388
|
+
const xrayById = new Map<string, RecallXrayResult>();
|
|
389
|
+
const xrayByPath = new Map<string, RecallXrayResult>();
|
|
390
|
+
for (const result of xray?.results ?? []) {
|
|
391
|
+
xrayById.set(result.memoryId, result);
|
|
392
|
+
xrayByPath.set(result.path, result);
|
|
393
|
+
}
|
|
394
|
+
return (summary) => {
|
|
395
|
+
if (summary.path) {
|
|
396
|
+
return xrayByPath.get(summary.path);
|
|
397
|
+
}
|
|
398
|
+
return xrayById.get(summary.id);
|
|
399
|
+
};
|
|
400
|
+
}
|
|
401
|
+
|
|
378
402
|
function missingProvenance(result: RecallXrayResult): RetrievedMemoryProvenance {
|
|
379
403
|
return {
|
|
380
404
|
source: "unknown",
|
|
@@ -391,6 +415,24 @@ function missingProvenance(result: RecallXrayResult): RetrievedMemoryProvenance
|
|
|
391
415
|
};
|
|
392
416
|
}
|
|
393
417
|
|
|
418
|
+
function missingXrayResultProvenance(
|
|
419
|
+
summary: EngramAccessRecallResponse["results"][number],
|
|
420
|
+
): RetrievedMemoryProvenance {
|
|
421
|
+
return {
|
|
422
|
+
source: "unknown",
|
|
423
|
+
scope: "unknown",
|
|
424
|
+
userContextScopes: [],
|
|
425
|
+
retrievalReason: `X-ray result missing for ${summary.path || summary.id}`,
|
|
426
|
+
confidence: 0,
|
|
427
|
+
stale: false,
|
|
428
|
+
corrected: false,
|
|
429
|
+
correctionState: "none",
|
|
430
|
+
safeToUse: false,
|
|
431
|
+
safety: "blocked",
|
|
432
|
+
safetyReasons: ["X-ray result was missing for this recalled memory."],
|
|
433
|
+
};
|
|
434
|
+
}
|
|
435
|
+
|
|
394
436
|
function missingRecallProvenance(
|
|
395
437
|
summary: EngramAccessRecallResponse["results"][number],
|
|
396
438
|
): RetrievedMemoryProvenance {
|
|
@@ -143,6 +143,12 @@ export function parseOpenAiMessageParts(
|
|
|
143
143
|
}
|
|
144
144
|
if (type === "message") {
|
|
145
145
|
for (const block of gatherContentBlocks(item.content)) {
|
|
146
|
+
if (isOpenAiResponseItem(block)) {
|
|
147
|
+
parts.push(
|
|
148
|
+
...parseOpenAiMessageParts([block]).map(({ ordinal: _ordinal, ...part }) => part),
|
|
149
|
+
);
|
|
150
|
+
continue;
|
|
151
|
+
}
|
|
146
152
|
const text = asNonEmptyString(block.text ?? block.content);
|
|
147
153
|
if (text) parts.push(makePart("text", { type, text }, { filePath: firstFilePath(text) }));
|
|
148
154
|
}
|
|
@@ -46,6 +46,36 @@ describe("message-parts parsers", () => {
|
|
|
46
46
|
assert.equal(parts[0]!.filePath, "src/config.ts");
|
|
47
47
|
});
|
|
48
48
|
|
|
49
|
+
it("preserves OpenAI message content arrays with mixed tool and result blocks", () => {
|
|
50
|
+
const parts = parseOpenAiMessageParts({
|
|
51
|
+
type: "message",
|
|
52
|
+
content: [
|
|
53
|
+
{ type: "output_text", text: "Updated src/a.ts" },
|
|
54
|
+
{
|
|
55
|
+
type: "function_call",
|
|
56
|
+
name: "apply_patch",
|
|
57
|
+
arguments: JSON.stringify({
|
|
58
|
+
patch: "*** Begin Patch\n*** Update File: src/a.ts\n*** End Patch",
|
|
59
|
+
}),
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
type: "function_call_output",
|
|
63
|
+
call_id: "call_1",
|
|
64
|
+
output: "Patched src/a.ts",
|
|
65
|
+
},
|
|
66
|
+
],
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
assert.equal(parts.length, 3);
|
|
70
|
+
assert.equal(parts[0]!.kind, "text");
|
|
71
|
+
assert.equal(parts[0]!.filePath, "src/a.ts");
|
|
72
|
+
assert.equal(parts[1]!.kind, "patch");
|
|
73
|
+
assert.equal(parts[1]!.toolName, "apply_patch");
|
|
74
|
+
assert.equal(parts[1]!.filePath, "src/a.ts");
|
|
75
|
+
assert.equal(parts[2]!.kind, "tool_result");
|
|
76
|
+
assert.equal(parts[2]!.filePath, "src/a.ts");
|
|
77
|
+
});
|
|
78
|
+
|
|
49
79
|
it("infers top-level OpenAI response item arrays before Anthropic arrays", () => {
|
|
50
80
|
const parts = parseMessageParts([
|
|
51
81
|
{
|
|
@@ -30,6 +30,7 @@ interface RollbackManifestEntry {
|
|
|
30
30
|
backupPath?: string;
|
|
31
31
|
createdByMigration?: boolean;
|
|
32
32
|
contentHash?: string;
|
|
33
|
+
mode?: number;
|
|
33
34
|
}
|
|
34
35
|
|
|
35
36
|
interface RollbackManifest {
|
|
@@ -42,6 +43,7 @@ interface ValidatedRollbackManifestEntry extends RollbackManifestEntry {
|
|
|
42
43
|
targetPath: string;
|
|
43
44
|
backupPath?: string;
|
|
44
45
|
contentHash?: string;
|
|
46
|
+
mode?: number;
|
|
45
47
|
}
|
|
46
48
|
|
|
47
49
|
export interface MigrationOptions {
|
|
@@ -308,11 +310,19 @@ function parseRollbackManifestEntry(raw: unknown, index: number): RollbackManife
|
|
|
308
310
|
if (raw.contentHash !== undefined && (typeof raw.contentHash !== "string" || !/^[a-f0-9]{64}$/u.test(raw.contentHash))) {
|
|
309
311
|
throw new Error(`rollback manifest entry ${index} has an invalid contentHash`);
|
|
310
312
|
}
|
|
313
|
+
const rawMode = raw.mode;
|
|
314
|
+
if (
|
|
315
|
+
rawMode !== undefined &&
|
|
316
|
+
(typeof rawMode !== "number" || !Number.isInteger(rawMode) || rawMode < 0 || rawMode > 0o777)
|
|
317
|
+
) {
|
|
318
|
+
throw new Error(`rollback manifest entry ${index} has an invalid mode`);
|
|
319
|
+
}
|
|
311
320
|
return {
|
|
312
321
|
targetPath: raw.targetPath,
|
|
313
322
|
...(raw.backupPath === undefined ? {} : { backupPath: raw.backupPath }),
|
|
314
323
|
...(raw.createdByMigration === undefined ? {} : { createdByMigration: raw.createdByMigration }),
|
|
315
324
|
...(raw.contentHash === undefined ? {} : { contentHash: raw.contentHash }),
|
|
325
|
+
...(rawMode === undefined ? {} : { mode: rawMode }),
|
|
316
326
|
};
|
|
317
327
|
}
|
|
318
328
|
|
|
@@ -486,6 +496,7 @@ async function validateRollbackManifestEntries(
|
|
|
486
496
|
...(backupPath === undefined ? {} : { backupPath }),
|
|
487
497
|
...(entry.createdByMigration === undefined ? {} : { createdByMigration: entry.createdByMigration }),
|
|
488
498
|
...(entry.contentHash === undefined ? {} : { contentHash: entry.contentHash }),
|
|
499
|
+
...(entry.mode === undefined ? {} : { mode: entry.mode }),
|
|
489
500
|
});
|
|
490
501
|
}
|
|
491
502
|
|
|
@@ -697,14 +708,16 @@ async function backupFile(
|
|
|
697
708
|
}
|
|
698
709
|
const backupPath = connectorBackupPathForTarget(targetPath, homeDir);
|
|
699
710
|
await ensureParent(backupPath);
|
|
711
|
+
const originalMode = isRemnicTokenStorePath(targetPath, homeDir)
|
|
712
|
+
? TOKEN_STORE_MODE
|
|
713
|
+
: (await stat(targetPath)).mode & 0o777;
|
|
700
714
|
if (isRemnicTokenStorePath(targetPath, homeDir)) {
|
|
701
715
|
await writeOwnerOnlyFile(backupPath, originalContent);
|
|
702
716
|
} else {
|
|
703
|
-
const originalMode = (await stat(targetPath)).mode & 0o777;
|
|
704
717
|
await writeFile(backupPath, originalContent, { encoding: "utf8", mode: originalMode });
|
|
705
718
|
await chmod(backupPath, originalMode);
|
|
706
719
|
}
|
|
707
|
-
manifest.entries.push({ targetPath, backupPath });
|
|
720
|
+
manifest.entries.push({ targetPath, backupPath, mode: originalMode });
|
|
708
721
|
await persistManifest?.();
|
|
709
722
|
}
|
|
710
723
|
|
|
@@ -990,9 +1003,10 @@ export async function rollbackFromEngramMigration(options?: MigrationOptions): P
|
|
|
990
1003
|
await assertExistingRegularFileNoFollow(entry.backupPath, "rollback manifest backup");
|
|
991
1004
|
await ensureParent(entry.targetPath);
|
|
992
1005
|
await copyFile(entry.backupPath, entry.targetPath);
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
1006
|
+
const restoreMode = isRemnicTokenStorePath(entry.targetPath, homeDir)
|
|
1007
|
+
? TOKEN_STORE_MODE
|
|
1008
|
+
: entry.mode ?? ((await lstat(entry.backupPath)).mode & 0o777);
|
|
1009
|
+
await chmod(entry.targetPath, restoreMode);
|
|
996
1010
|
restored.push(entry.targetPath);
|
|
997
1011
|
continue;
|
|
998
1012
|
}
|
|
@@ -8,6 +8,7 @@ class FakeBackend implements SearchBackend {
|
|
|
8
8
|
updates = 0;
|
|
9
9
|
calls: Array<{ method: string; collection: string | undefined }> = [];
|
|
10
10
|
ensureSignals: Array<AbortSignal | undefined> = [];
|
|
11
|
+
ensureCollections: Array<string | undefined> = [];
|
|
11
12
|
|
|
12
13
|
constructor(
|
|
13
14
|
private readonly globalUpdate: boolean,
|
|
@@ -64,8 +65,19 @@ class FakeBackend implements SearchBackend {
|
|
|
64
65
|
|
|
65
66
|
async embedCollection(): Promise<void> {}
|
|
66
67
|
|
|
67
|
-
async ensureCollection(
|
|
68
|
-
|
|
68
|
+
async ensureCollection(
|
|
69
|
+
_memoryDir?: string,
|
|
70
|
+
collectionOrExecution?: string | { signal?: AbortSignal },
|
|
71
|
+
execution?: { signal?: AbortSignal },
|
|
72
|
+
): Promise<"present"> {
|
|
73
|
+
const collection = typeof collectionOrExecution === "string"
|
|
74
|
+
? collectionOrExecution
|
|
75
|
+
: undefined;
|
|
76
|
+
const effectiveExecution = typeof collectionOrExecution === "string"
|
|
77
|
+
? execution
|
|
78
|
+
: collectionOrExecution ?? execution;
|
|
79
|
+
this.ensureCollections.push(collection);
|
|
80
|
+
this.ensureSignals.push(effectiveExecution?.signal);
|
|
69
81
|
return "present";
|
|
70
82
|
}
|
|
71
83
|
}
|
|
@@ -191,4 +203,5 @@ test("ensureNamespaceCollection forwards abort signals to backend collection che
|
|
|
191
203
|
|
|
192
204
|
assert.equal(state, "present");
|
|
193
205
|
assert.deepEqual(backend.ensureSignals, [controller.signal]);
|
|
206
|
+
assert.deepEqual(backend.ensureCollections, ["openclaw-engram--ns-6d61696e"]);
|
|
194
207
|
});
|
package/src/namespaces/search.ts
CHANGED
|
@@ -203,7 +203,7 @@ export class NamespaceSearchRouter {
|
|
|
203
203
|
const backend = this.createBackend(scopedConfig);
|
|
204
204
|
const available = await backend.probe().catch(() => false);
|
|
205
205
|
const collectionState = available
|
|
206
|
-
? await backend.ensureCollection(storage.dir, execution).catch(() => "unknown" as const)
|
|
206
|
+
? await backend.ensureCollection(storage.dir, scopedConfig.qmdCollection, execution).catch(() => "unknown" as const)
|
|
207
207
|
: "unknown";
|
|
208
208
|
return {
|
|
209
209
|
backend,
|
package/src/network/webdav.ts
CHANGED
|
@@ -86,7 +86,7 @@ export class WebDavServer {
|
|
|
86
86
|
|
|
87
87
|
private constructor(
|
|
88
88
|
options: Required<Omit<WebDavServerOptions, "auth">> & Pick<WebDavServerOptions, "auth">,
|
|
89
|
-
allowedRoots: AllowedRoot[]
|
|
89
|
+
allowedRoots: AllowedRoot[]
|
|
90
90
|
) {
|
|
91
91
|
this.options = options;
|
|
92
92
|
this.allowedRoots = allowedRoots;
|
|
@@ -313,7 +313,9 @@ export class WebDavServer {
|
|
|
313
313
|
return out;
|
|
314
314
|
}
|
|
315
315
|
|
|
316
|
-
private async resolvePath(
|
|
316
|
+
private async resolvePath(
|
|
317
|
+
requestPathname: string
|
|
318
|
+
): Promise<
|
|
317
319
|
| { ok: true; absolutePath: string; displayPath: string; rootAbsolute: string }
|
|
318
320
|
| { ok: false; code: number; message: string }
|
|
319
321
|
> {
|
|
@@ -355,11 +357,21 @@ export class WebDavServer {
|
|
|
355
357
|
if (!this.isPathInside(root.absolute, canonicalCandidate)) {
|
|
356
358
|
return { ok: false, code: 403, message: "path escaped allowlist via symlink" };
|
|
357
359
|
}
|
|
358
|
-
return {
|
|
360
|
+
return {
|
|
361
|
+
ok: true,
|
|
362
|
+
absolutePath: canonicalCandidate,
|
|
363
|
+
displayPath: `/${segments.join("/")}`,
|
|
364
|
+
rootAbsolute: root.absolute,
|
|
365
|
+
};
|
|
359
366
|
} catch (err) {
|
|
360
367
|
const code = (err as NodeJS.ErrnoException).code;
|
|
361
368
|
if (code === "ENOENT") {
|
|
362
|
-
return {
|
|
369
|
+
return {
|
|
370
|
+
ok: true,
|
|
371
|
+
absolutePath: candidate,
|
|
372
|
+
displayPath: `/${segments.join("/")}`,
|
|
373
|
+
rootAbsolute: root.absolute,
|
|
374
|
+
};
|
|
363
375
|
}
|
|
364
376
|
if (code === "ENOTDIR" || code === "ELOOP") {
|
|
365
377
|
return { ok: false, code: 400, message: "invalid path" };
|
|
@@ -372,7 +384,7 @@ export class WebDavServer {
|
|
|
372
384
|
method: "GET" | "HEAD",
|
|
373
385
|
absolutePath: string,
|
|
374
386
|
rootAbsolute: string,
|
|
375
|
-
res: ServerResponse
|
|
387
|
+
res: ServerResponse
|
|
376
388
|
): Promise<void> {
|
|
377
389
|
const revalidated = await this.revalidatePathInsideRoot(absolutePath, rootAbsolute);
|
|
378
390
|
if (!revalidated.ok) {
|
|
@@ -410,7 +422,7 @@ export class WebDavServer {
|
|
|
410
422
|
absolutePath: string,
|
|
411
423
|
rootAbsolute: string,
|
|
412
424
|
displayPath: string,
|
|
413
|
-
res: ServerResponse
|
|
425
|
+
res: ServerResponse
|
|
414
426
|
): Promise<void> {
|
|
415
427
|
const revalidated = await this.revalidatePathInsideRoot(absolutePath, rootAbsolute);
|
|
416
428
|
if (!revalidated.ok) {
|
|
@@ -432,27 +444,58 @@ export class WebDavServer {
|
|
|
432
444
|
if (info.isDirectory()) {
|
|
433
445
|
const children = await readdir(absolutePath, { withFileTypes: true });
|
|
434
446
|
for (const child of children) {
|
|
435
|
-
const
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
<d:propstat><d:prop><d:resourcetype>${child.isDirectory() ? "<d:collection/>" : ""}</d:resourcetype></d:prop><d:status>HTTP/1.1 200 OK</d:status></d:propstat>
|
|
440
|
-
</d:response>`);
|
|
447
|
+
const entry = await this.renderPropfindChildEntry(absolutePath, rootAbsolute, displayPath, child.name);
|
|
448
|
+
if (entry) {
|
|
449
|
+
entries.push(entry);
|
|
450
|
+
}
|
|
441
451
|
}
|
|
442
452
|
}
|
|
443
453
|
|
|
444
454
|
const xml = `<?xml version="1.0" encoding="utf-8"?>
|
|
445
455
|
<d:multistatus xmlns:d="DAV:">
|
|
446
|
-
|
|
447
|
-
<d:href>${xmlEscape(toEncodedHref(displayPath))}</d:href>
|
|
448
|
-
<d:propstat><d:prop><d:resourcetype>${info.isDirectory() ? "<d:collection/>" : ""}</d:resourcetype></d:prop><d:status>HTTP/1.1 200 OK</d:status></d:propstat>
|
|
449
|
-
</d:response>${entries.join("")}
|
|
456
|
+
${this.renderPropfindResponse(toEncodedHref(displayPath), info.isDirectory())}${entries.join("")}
|
|
450
457
|
</d:multistatus>`;
|
|
451
458
|
|
|
452
459
|
res.writeHead(207, { "Content-Type": "application/xml; charset=utf-8" });
|
|
453
460
|
res.end(xml);
|
|
454
461
|
}
|
|
455
462
|
|
|
463
|
+
private async renderPropfindChildEntry(
|
|
464
|
+
parentAbsolutePath: string,
|
|
465
|
+
rootAbsolute: string,
|
|
466
|
+
displayPath: string,
|
|
467
|
+
childName: string
|
|
468
|
+
): Promise<string | null> {
|
|
469
|
+
const childAbsolutePath = path.join(parentAbsolutePath, childName);
|
|
470
|
+
let revalidated;
|
|
471
|
+
try {
|
|
472
|
+
revalidated = await this.revalidatePathInsideRoot(childAbsolutePath, rootAbsolute);
|
|
473
|
+
} catch {
|
|
474
|
+
return null;
|
|
475
|
+
}
|
|
476
|
+
if (!revalidated.ok) {
|
|
477
|
+
return null;
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
let info;
|
|
481
|
+
try {
|
|
482
|
+
info = await stat(revalidated.absolutePath);
|
|
483
|
+
} catch {
|
|
484
|
+
return null;
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
const childHref = toEncodedHref(`${displayPath.replace(/\/$/, "")}/${childName}`);
|
|
488
|
+
return this.renderPropfindResponse(childHref, info.isDirectory());
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
private renderPropfindResponse(href: string, isDirectory: boolean): string {
|
|
492
|
+
return ` <d:response>
|
|
493
|
+
<d:href>${xmlEscape(href)}</d:href>
|
|
494
|
+
<d:propstat><d:prop><d:resourcetype>${isDirectory ? "<d:collection/>" : ""}</d:resourcetype></d:prop><d:status>HTTP/1.1 200 OK</d:status></d:propstat>
|
|
495
|
+
</d:response>
|
|
496
|
+
`;
|
|
497
|
+
}
|
|
498
|
+
|
|
456
499
|
private isPathInside(root: string, target: string): boolean {
|
|
457
500
|
if (target === root) return true;
|
|
458
501
|
if (root === path.parse(root).root) {
|
|
@@ -463,11 +506,8 @@ export class WebDavServer {
|
|
|
463
506
|
|
|
464
507
|
private async revalidatePathInsideRoot(
|
|
465
508
|
absolutePath: string,
|
|
466
|
-
rootAbsolute: string
|
|
467
|
-
): Promise<
|
|
468
|
-
| { ok: true; absolutePath: string }
|
|
469
|
-
| { ok: false; code: number; message: string }
|
|
470
|
-
> {
|
|
509
|
+
rootAbsolute: string
|
|
510
|
+
): Promise<{ ok: true; absolutePath: string } | { ok: false; code: number; message: string }> {
|
|
471
511
|
try {
|
|
472
512
|
const canonical = await realpath(absolutePath);
|
|
473
513
|
if (!this.isPathInside(rootAbsolute, canonical)) {
|