@remnic/core 10.0.91 → 10.0.93
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/access-admin-ops-surface.js +334 -61
- package/dist/access-authorization-probe.js +2 -283
- package/dist/access-boundary.d.ts +1 -1
- package/dist/access-boundary.d.ts.map +1 -1
- package/dist/access-boundary.js +1 -282
- package/dist/access-cli.js +288 -304
- package/dist/access-cli.js.map +1 -1
- package/dist/access-coding-context-resolution.js +3 -3
- package/dist/access-extraction-force-flush.js +334 -61
- package/dist/access-http-briefing.js +334 -62
- package/dist/access-http-query.js +334 -63
- package/dist/access-http.js +332 -114
- package/dist/access-identity-continuity-surface.js +334 -61
- package/dist/access-lcm-surface.js +334 -61
- package/dist/access-mcp-frames.d.ts +20 -6
- package/dist/access-mcp-frames.d.ts.map +1 -1
- package/dist/access-mcp-frames.js +1 -1
- package/dist/access-mcp.d.ts +5 -0
- package/dist/access-mcp.d.ts.map +1 -1
- package/dist/access-mcp.js +332 -89
- package/dist/access-namespace-preflight.js +2 -282
- package/dist/access-observe-transcript.js +3 -3
- package/dist/access-observe-write-category.js +6 -6
- package/dist/access-observe-write-surface.js +334 -61
- package/dist/access-offline-manifest.js +12 -11
- package/dist/access-operations-batch.js +332 -66
- package/dist/access-operations.js +332 -75
- package/dist/access-recall-concurrency.js +334 -61
- package/dist/access-recall-diagnostics.js +6 -5
- package/dist/access-recall-response.js +334 -61
- package/dist/access-recall-surface.js +334 -61
- package/dist/access-schema.js +2 -2
- package/dist/access-service.d.ts +1 -0
- package/dist/access-service.d.ts.map +1 -1
- package/dist/access-service.js +337 -64
- package/dist/access-surface-catalog.js +6 -283
- package/dist/access-surface-catalog.js.map +1 -1
- package/dist/active-context-transform.js +1 -1
- package/dist/active-memory-bridge.js +3 -2
- package/dist/active-recall.js +36 -37
- package/dist/active-recall.js.map +1 -1
- package/dist/activity/journal-extract.d.ts +13 -1
- package/dist/activity/journal-extract.d.ts.map +1 -1
- package/dist/{auto-sync-3AZW7MXI.js → auto-sync-BO5YZKM6.js} +13 -15
- package/dist/{auto-sync-3AZW7MXI.js.map → auto-sync-BO5YZKM6.js.map} +1 -1
- package/dist/briefing.js +20 -20
- package/dist/buffer.js +16 -16
- package/dist/calibration.js +10 -10
- package/dist/{capsule-merge-2IIXFXN5.js → capsule-merge-6IDAYTKG.js} +6 -6
- package/dist/causal-consolidation.js +23 -23
- package/dist/{chunk-QL7RHYK6.js → chunk-2LMA22UU.js} +5 -5
- package/dist/{chunk-RGUUBAT5.js → chunk-2WCLTWV2.js} +3 -3
- package/dist/{chunk-RSK2WIEM.js → chunk-2YODOG2O.js} +2 -2
- package/dist/{chunk-WYG5UNDY.js → chunk-3AUDELZL.js} +2 -2
- package/dist/{chunk-OFVCFKDH.js → chunk-3CYOCE6U.js} +3 -3
- package/dist/{chunk-6HM6HARE.js → chunk-3FBAEPCU.js} +2 -2
- package/dist/{chunk-PIITB2YZ.js → chunk-3ZS3NUEI.js} +4 -4
- package/dist/{chunk-V4XE263I.js → chunk-43AA5FVD.js} +1 -1
- package/dist/chunk-43AA5FVD.js.map +1 -0
- package/dist/{chunk-ANZZLRUX.js → chunk-4IVRQMZW.js} +2 -2
- package/dist/{chunk-63E37JCN.js → chunk-4RAJT5L2.js} +4 -4
- package/dist/{chunk-45VUHDV2.js → chunk-5CO5G4MN.js} +2 -2
- package/dist/{chunk-PUEO37QG.js → chunk-5YT2IIFX.js} +729 -17
- package/dist/chunk-5YT2IIFX.js.map +1 -0
- package/dist/{chunk-P5VZSSYL.js → chunk-622V2AZA.js} +233 -40
- package/dist/chunk-622V2AZA.js.map +1 -0
- package/dist/{chunk-3UMDRGFS.js → chunk-65HWAQ4F.js} +3 -3
- package/dist/{chunk-T67LUYCR.js → chunk-77NTFICT.js} +5 -5
- package/dist/chunk-A2WFUMUN.js +86 -0
- package/dist/chunk-A2WFUMUN.js.map +1 -0
- package/dist/{chunk-UE6RRXMF.js → chunk-A4F7OIC5.js} +2 -2
- package/dist/chunk-AHA5VQGP.js +117 -0
- package/dist/chunk-AHA5VQGP.js.map +1 -0
- package/dist/{chunk-AOFEMUHG.js → chunk-ATG2PQ4V.js} +56 -5
- package/dist/chunk-ATG2PQ4V.js.map +1 -0
- package/dist/{chunk-63O7LVMN.js → chunk-B33YWUJV.js} +3 -3
- package/dist/{chunk-QVMOCJRV.js → chunk-B377OKUP.js} +2 -2
- package/dist/{chunk-IUKYFTGW.js → chunk-B3DR2JBZ.js} +140 -125
- package/dist/chunk-B3DR2JBZ.js.map +1 -0
- package/dist/{chunk-ZT6WPSII.js → chunk-BGHCSLE5.js} +2 -2
- package/dist/{chunk-YYOMGOHB.js → chunk-BOK6BN5M.js} +2 -2
- package/dist/{chunk-OH7QLI6W.js → chunk-BPPUH5JM.js} +5 -5
- package/dist/{chunk-EV76IZ37.js → chunk-BTI4C4MA.js} +2 -2
- package/dist/{chunk-O6ZSWHVR.js → chunk-C2KE5DMD.js} +4 -4
- package/dist/{chunk-47F6WWLQ.js → chunk-C73N66PR.js} +2 -2
- package/dist/{chunk-3XIWW4TB.js → chunk-CGJYL633.js} +2 -2
- package/dist/{chunk-WRT7GJ2D.js → chunk-CIWMTNHW.js} +4 -4
- package/dist/{chunk-O55EKIEC.js → chunk-D3ZKHLN2.js} +2 -2
- package/dist/{chunk-CD4BCCNP.js → chunk-DJ7WVEWX.js} +2 -2
- package/dist/{chunk-RO7RUBLD.js → chunk-EFL24KOI.js} +2 -2
- package/dist/{chunk-4CJTQHEG.js → chunk-ESLOLCD4.js} +3 -3
- package/dist/{chunk-Z4Q6USKJ.js → chunk-ETBVCRVL.js} +4 -4
- package/dist/{chunk-VILPVT4S.js → chunk-EZ47HOJ6.js} +4 -4
- package/dist/{chunk-EFYN5I7Z.js → chunk-F4QFU5IZ.js} +2 -2
- package/dist/{chunk-T6OZW2WR.js → chunk-FA7SLQ5X.js} +7 -1
- package/dist/chunk-FA7SLQ5X.js.map +1 -0
- package/dist/{chunk-SHUBTAY2.js → chunk-FMKILENU.js} +14 -14
- package/dist/{chunk-YLXETSAH.js → chunk-GCZJ7XRI.js} +2 -2
- package/dist/{chunk-J4MMPQ7Q.js → chunk-GQXOBKPL.js} +7 -9
- package/dist/{chunk-J4MMPQ7Q.js.map → chunk-GQXOBKPL.js.map} +1 -1
- package/dist/{chunk-UDKWFDV2.js → chunk-HLUHEMN4.js} +27 -3
- package/dist/chunk-HLUHEMN4.js.map +1 -0
- package/dist/{chunk-QFEDITXM.js → chunk-JNDMIAJ4.js} +2 -2
- package/dist/chunk-JTSSSR4L.js +359 -0
- package/dist/chunk-JTSSSR4L.js.map +1 -0
- package/dist/{chunk-5KBIOI4G.js → chunk-JVBAPAWZ.js} +217 -13
- package/dist/chunk-JVBAPAWZ.js.map +1 -0
- package/dist/{chunk-E5PPE4VA.js → chunk-K2VRKCPA.js} +2 -2
- package/dist/{chunk-MKRYQROF.js → chunk-LGEHAQHK.js} +4 -4
- package/dist/{chunk-7HTUYFR3.js → chunk-LLPMMMWG.js} +27 -10
- package/dist/chunk-LLPMMMWG.js.map +1 -0
- package/dist/{chunk-XYTQJD7F.js → chunk-LMJVP5CM.js} +2 -2
- package/dist/{chunk-JC36FPQ5.js → chunk-LPV72KRQ.js} +2 -2
- package/dist/{chunk-2LCRG2YV.js → chunk-M2XR6B6V.js} +2 -2
- package/dist/{chunk-GGRRF4PZ.js → chunk-MDPT6QFK.js} +1 -1
- package/dist/{chunk-GGRRF4PZ.js.map → chunk-MDPT6QFK.js.map} +1 -1
- package/dist/{chunk-VPQFK63H.js → chunk-MH632KPO.js} +2 -2
- package/dist/{chunk-EQ4U73UH.js → chunk-MLAMXQAW.js} +14 -2
- package/dist/chunk-MLAMXQAW.js.map +1 -0
- package/dist/{chunk-ZU5JDLOH.js → chunk-MMRTPH3J.js} +2 -2
- package/dist/{chunk-ZZ67UTQX.js → chunk-MUX7IL77.js} +2 -2
- package/dist/{chunk-RYWROSL5.js → chunk-NAQ4A5IX.js} +7 -7
- package/dist/{chunk-TVIVY7KU.js → chunk-NED7IR7B.js} +4 -4
- package/dist/{chunk-ADYP7HXE.js → chunk-NHVAX7MH.js} +3 -3
- package/dist/{chunk-TG3R2SID.js → chunk-NMGHGTVR.js} +5 -5
- package/dist/{chunk-YCNIGRRF.js → chunk-NS7U4ZYU.js} +13 -117
- package/dist/chunk-NS7U4ZYU.js.map +1 -0
- package/dist/{chunk-NGHDW6UU.js → chunk-NUQEREIP.js} +2 -2
- package/dist/{chunk-5IIQU4JZ.js → chunk-OB72KNMF.js} +4 -4
- package/dist/{chunk-7L3TODI7.js → chunk-OJXJWNFY.js} +2 -2
- package/dist/{chunk-66L5ZRJC.js → chunk-P3WRNWWM.js} +157 -4
- package/dist/chunk-P3WRNWWM.js.map +1 -0
- package/dist/{chunk-E6M225BJ.js → chunk-PC5DRBGD.js} +18 -8
- package/dist/chunk-PC5DRBGD.js.map +1 -0
- package/dist/{chunk-EURPSF4Y.js → chunk-PH5ZQM35.js} +2 -2
- package/dist/{chunk-BMWMTAQF.js → chunk-PRAUN6PN.js} +3 -3
- package/dist/{chunk-RWGRSKN5.js → chunk-PT4DZDJA.js} +2 -2
- package/dist/{chunk-7EPY3IQL.js → chunk-PZJQ46DH.js} +2 -2
- package/dist/{chunk-AH637HZ5.js → chunk-QDESY76F.js} +3 -3
- package/dist/{chunk-I6QGI65T.js → chunk-QRMG4HK4.js} +3 -3
- package/dist/{chunk-ZU3NJNO7.js → chunk-QSF5SJAM.js} +4 -4
- package/dist/{chunk-5IYOKDM4.js → chunk-R23JWJD3.js} +5 -5
- package/dist/{chunk-EWJZZDRG.js → chunk-R4BBGPI2.js} +219 -219
- package/dist/chunk-R4BBGPI2.js.map +1 -0
- package/dist/{chunk-LJQFJF4J.js → chunk-RM2YUFH6.js} +6 -6
- package/dist/{chunk-IPT2OY4B.js → chunk-RQFXZYTF.js} +35 -33
- package/dist/chunk-RQFXZYTF.js.map +1 -0
- package/dist/{chunk-AP6NCP3V.js → chunk-S3S72HRM.js} +8 -6
- package/dist/chunk-S3S72HRM.js.map +1 -0
- package/dist/{chunk-6QMWECO5.js → chunk-SGQPR5SX.js} +7 -7
- package/dist/{chunk-ZGFLIK5H.js → chunk-SPAKBUJY.js} +2 -2
- package/dist/{chunk-ER7XANP3.js → chunk-SQ3GEIEL.js} +4 -4
- package/dist/{chunk-5UCMYPVF.js → chunk-SVT5IA2H.js} +2 -2
- package/dist/{chunk-HVKUCT3W.js → chunk-T4KY6UYF.js} +5 -3
- package/dist/{chunk-HVKUCT3W.js.map → chunk-T4KY6UYF.js.map} +1 -1
- package/dist/{chunk-FRSHF6FU.js → chunk-TJ4F6H4H.js} +3 -3
- package/dist/{chunk-R6HMAIKM.js → chunk-TOSPNM4T.js} +2 -2
- package/dist/{chunk-NJJMVS5Y.js → chunk-TRQE3RYR.js} +5 -5
- package/dist/{chunk-RMXS4I66.js → chunk-TVDJEUV5.js} +2 -2
- package/dist/{chunk-PLCYKAWH.js → chunk-TYRWSE4B.js} +2 -2
- package/dist/{chunk-YS2GHSWN.js → chunk-UBEKET2V.js} +389 -39
- package/dist/chunk-UBEKET2V.js.map +1 -0
- package/dist/{chunk-IQWUACVG.js → chunk-UHMHJX5G.js} +3 -3
- package/dist/{chunk-YODUDA6R.js → chunk-UN4RVUG2.js} +22 -22
- package/dist/{chunk-KZSGBWOJ.js → chunk-V2KGDESV.js} +2 -2
- package/dist/{chunk-E6Z4FBX6.js → chunk-V2QSNFCT.js} +2 -2
- package/dist/{chunk-BCCG7VWM.js → chunk-V65H7MI6.js} +396 -13
- package/dist/chunk-V65H7MI6.js.map +1 -0
- package/dist/chunk-W54Z2MOP.js +4500 -0
- package/dist/chunk-W54Z2MOP.js.map +1 -0
- package/dist/{chunk-N74SGESS.js → chunk-WKSQTMU7.js} +2 -2
- package/dist/{chunk-RIZ5NUNN.js → chunk-WQ4XKIOX.js} +4 -4
- package/dist/{chunk-WWK6J6SE.js → chunk-WQURALGV.js} +4996 -2748
- package/dist/chunk-WQURALGV.js.map +1 -0
- package/dist/{chunk-QEYTRFR3.js → chunk-X26YOFGS.js} +2 -2
- package/dist/{chunk-ITHZFHST.js → chunk-X2BVB74H.js} +2 -2
- package/dist/{chunk-GNXGJBCA.js → chunk-XIYLWEXC.js} +2 -2
- package/dist/{chunk-IBJ6U753.js → chunk-XKZBZOKV.js} +4 -4
- package/dist/{chunk-7O2MC42R.js → chunk-XNRLRNQF.js} +2 -2
- package/dist/{chunk-65AUYLU3.js → chunk-XPXHQI6N.js} +2 -2
- package/dist/{chunk-JBCCWVU2.js → chunk-XRDYRWZI.js} +2 -2
- package/dist/chunk-XRWWCW4H.js +102 -0
- package/dist/chunk-XRWWCW4H.js.map +1 -0
- package/dist/chunk-YKJBSMMP.js +67137 -0
- package/dist/chunk-YKJBSMMP.js.map +1 -0
- package/dist/{chunk-2JSDPUKD.js → chunk-YMFPFXEX.js} +2 -2
- package/dist/{chunk-645WOU5I.js → chunk-ZDZJNXL6.js} +4 -4
- package/dist/{chunk-6TCXIRP5.js → chunk-ZKE4CO6B.js} +4 -4
- package/dist/{chunk-KEPXC4KN.js → chunk-ZSE774RV.js} +2 -2
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +305 -187
- package/dist/coding/export-okf-codegraph.js +29 -29
- package/dist/compounding/engine.js +23 -24
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +36 -37
- package/dist/connectors/codex-materialize-runner.js +20 -20
- package/dist/connectors/index.js +21 -21
- package/dist/connectors/live/framework.d.ts +7 -0
- package/dist/connectors/live/framework.d.ts.map +1 -1
- package/dist/connectors/live/google-drive.d.ts +17 -3
- package/dist/connectors/live/google-drive.d.ts.map +1 -1
- package/dist/consolidation-provenance-check.js +4 -4
- package/dist/consolidation-undo.js +5 -5
- package/dist/contradiction/index.js +7 -6
- package/dist/{contradiction-scan-P2MHYFVG.js → contradiction-scan-IBPYGQZF.js} +4 -3
- package/dist/convergence-refresh.js +22 -22
- package/dist/corpus-watermark.js +23 -23
- package/dist/deep-recall-http-glue.js +2 -2
- package/dist/deep-recall-policy-llm.js +4 -4
- package/dist/direct-answer-wiring.js +2 -2
- package/dist/embedding-fallback.js +1 -1
- package/dist/entity-retrieval.js +21 -21
- package/dist/eval-trajectory-store.js +2 -2
- package/dist/eval-trajectory.js +2 -2
- package/dist/event-order-recall.js +2 -2
- package/dist/explicit-capture.d.ts +3 -2
- package/dist/explicit-capture.d.ts.map +1 -1
- package/dist/explicit-capture.js +530 -6
- package/dist/explicit-cue-recall.js +2 -2
- package/dist/external-wiki-access.js +2 -283
- package/dist/extraction-faithfulness.js +4 -4
- package/dist/extraction-judge.js +5 -5
- package/dist/extraction-normalization.js +1 -1
- package/dist/extraction-quote-grounding.d.ts.map +1 -1
- package/dist/extraction-quote-grounding.js +1 -1
- package/dist/extraction-source-grounding-rules.js +2 -2
- package/dist/extraction-source-grounding.js +3 -3
- package/dist/extraction.js +43 -44
- package/dist/fallback-llm-codex-subscription.js +2 -2
- package/dist/fallback-llm.js +3 -3
- package/dist/{first-start-migration-QFI7B5SH.js → first-start-migration-FILJH3RO.js} +6 -5
- package/dist/{first-start-migration-QFI7B5SH.js.map → first-start-migration-FILJH3RO.js.map} +1 -1
- package/dist/focused-list-recall.js +2 -2
- package/dist/harmonic-retrieval.js +20 -20
- package/dist/index.js +776 -797
- package/dist/lcm/index.js +2 -2
- package/dist/live-connectors-runner.d.ts +2 -0
- package/dist/live-connectors-runner.d.ts.map +1 -1
- package/dist/live-connectors-runner.js +3 -4
- package/dist/local-llm-config.js +2 -2
- package/dist/local-llm-helpers.d.ts +4 -0
- package/dist/local-llm-helpers.d.ts.map +1 -1
- package/dist/local-llm-helpers.js +3 -1
- package/dist/local-llm.d.ts +4 -1
- package/dist/local-llm.d.ts.map +1 -1
- package/dist/local-llm.js +4 -4
- package/dist/location/index.js +27 -29
- package/dist/maintenance/memory-governance.js +20 -20
- package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +20 -20
- package/dist/maintenance/rebuild-memory-projection-runner.js +22 -22
- package/dist/maintenance/rebuild-memory-projection.js +21 -21
- package/dist/memory-browse-operations.js +2 -283
- package/dist/memory-browse.js +8 -7
- package/dist/memory-controller.js +2 -2
- package/dist/memory-subject.js +2 -2
- package/dist/namespaces/migrate.js +21 -21
- package/dist/namespaces/search.js +5 -5
- package/dist/namespaces/storage.js +20 -20
- package/dist/offline-sync-changeset-generations.js +1 -1
- package/dist/offline-sync-embedding-generation.js +1 -1
- package/dist/offline-sync-impression-drain.js +6 -6
- package/dist/offline-sync-snapshot-stream.js +1 -1
- package/dist/offline-sync.js +1 -1
- package/dist/operator-doctor-corpus.js +24 -24
- package/dist/operator-toolkit.js +58 -61
- package/dist/orchestration/backlog-scheduler.js +279 -295
- package/dist/orchestration/backlog-scheduler.js.map +1 -1
- package/dist/orchestration/buffer-drain-runner.js +279 -295
- package/dist/orchestration/extraction-run.d.ts +4 -0
- package/dist/orchestration/extraction-run.d.ts.map +1 -1
- package/dist/orchestration/fact-dedup-window.d.ts +1 -1
- package/dist/orchestration/fact-dedup-window.d.ts.map +1 -1
- package/dist/orchestration/maintenance.js +39 -42
- package/dist/orchestrator.d.ts +11 -11
- package/dist/orchestrator.d.ts.map +1 -1
- package/dist/orchestrator.js +291 -308
- package/dist/page-versioning.js +3 -3
- package/dist/qmd-daemon-session.js +2 -2
- package/dist/qmd.js +3 -3
- package/dist/recall-explain-renderer.js +3 -3
- package/dist/recall-navigate-access.js +2 -2
- package/dist/recall-navigate-disclosure.js +2 -2
- package/dist/recall-navigate.js +2 -2
- package/dist/recall-navigation-operations.js +2 -283
- package/dist/recall-navigation.js +334 -61
- package/dist/recall-planner-llm.js +3 -3
- package/dist/recall-state-view-admission.js +6 -6
- package/dist/recall-why-service.js +10 -9
- package/dist/recall-why.js +4 -3
- 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/reconcile/manifest.js +3 -3
- package/dist/{resolution-N7H3F2E4.js → resolution-OVVIF7ZY.js} +8 -7
- package/dist/response-guidance-recall.js +2 -2
- package/dist/resume-bundles.js +40 -41
- package/dist/salvage-envelope.js +4 -4
- package/dist/search/factory.js +4 -4
- package/dist/search/index.js +4 -4
- package/dist/semantic-consolidation.js +23 -23
- package/dist/semantic-rule-promotion.js +20 -20
- package/dist/semantic-rule-verifier.js +20 -20
- package/dist/shared-context/manager.js +2 -3
- package/dist/source-agent-qualifier.js +32 -33
- package/dist/standup/build.js +20 -20
- package/dist/{state-store-I5HLZTZT.js → state-store-EEAX2MBS.js} +2 -2
- package/dist/storage/content-hash-index.d.ts +10 -0
- package/dist/storage/content-hash-index.d.ts.map +1 -1
- package/dist/storage.js +19 -19
- package/dist/subject-config.js +3 -3
- package/dist/summarizer.d.ts +4 -1
- package/dist/summarizer.d.ts.map +1 -1
- package/dist/summarizer.js +6 -6
- package/dist/support-passport/index.js +53 -297
- package/dist/targeted-fact-recall.js +2 -2
- package/dist/tier-routing.js +3 -2
- package/dist/{tier-stats-FQGQSFET.js → tier-stats-FXEUJN73.js} +6 -5
- package/dist/{tier-stats-FQGQSFET.js.map → tier-stats-FXEUJN73.js.map} +1 -1
- package/dist/transcript.js +2 -2
- package/dist/transfer/capsule-import.js +4 -4
- package/dist/transfer/export-okf.js +20 -20
- package/dist/types.d.ts +10 -10
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +1 -1
- package/dist/verified-recall.js +20 -20
- package/dist/wearables/memory-gen.d.ts +5 -1
- package/dist/wearables/memory-gen.d.ts.map +1 -1
- package/dist/wearables/service.d.ts.map +1 -1
- package/dist/who-knows-cli.js +21 -21
- package/dist/who-knows.js +20 -20
- package/dist/write-envelope.js +3 -3
- package/package.json +2 -2
- package/src/access-boundary.ts +5 -1
- package/src/access-category-alias.test.ts +5 -0
- package/src/access-mcp-frames.test.ts +60 -5
- package/src/access-mcp-frames.ts +72 -18
- package/src/access-mcp.test.ts +66 -2
- package/src/access-mcp.ts +19 -13
- package/src/access-service-coding-write.test.ts +7 -0
- package/src/access-service.ts +3 -0
- package/src/activity/journal-extract-storage.test.ts +31 -0
- package/src/activity/journal-extract.test.ts +1 -0
- package/src/activity/journal-extract.ts +24 -3
- package/src/cli.ts +1 -2
- package/src/config.test.ts +17 -0
- package/src/config.ts +25 -7
- package/src/connectors/live/framework.ts +8 -0
- package/src/connectors/live/google-drive.test.ts +74 -0
- package/src/connectors/live/google-drive.ts +138 -11
- package/src/explicit-capture.test.ts +109 -17
- package/src/explicit-capture.ts +90 -37
- package/src/extraction-quote-grounding.test.ts +20 -0
- package/src/extraction-quote-grounding.ts +21 -11
- package/src/fact-dedup-window.test.ts +37 -0
- package/src/live-connectors-runner.ts +3 -0
- package/src/live-connectors-secretref.test.ts +126 -0
- package/src/local-llm-helpers.ts +12 -0
- package/src/local-llm-shutdown.test.ts +194 -0
- package/src/local-llm.ts +32 -30
- package/src/orchestration/extraction-run.ts +12 -3
- package/src/orchestration/fact-dedup-window.ts +5 -1
- package/src/orchestrator-connector-dedup.test.ts +9 -5
- package/src/orchestrator.ts +52 -55
- package/src/storage/content-hash-index.ts +27 -2
- package/src/storage-fact-hash-publish-failure.test.ts +87 -0
- package/src/summarizer-shutdown.test.ts +195 -0
- package/src/summarizer.ts +15 -2
- package/src/types.ts +10 -10
- package/src/wearables/memory-gen.test.ts +20 -0
- package/src/wearables/memory-gen.ts +14 -7
- package/src/wearables/service.ts +14 -1
- package/src/wearables/storage-io.test.ts +25 -0
- package/dist/chunk-27XYV2XL.js +0 -43
- package/dist/chunk-27XYV2XL.js.map +0 -1
- package/dist/chunk-5KBIOI4G.js.map +0 -1
- package/dist/chunk-66L5ZRJC.js.map +0 -1
- package/dist/chunk-7HTUYFR3.js.map +0 -1
- package/dist/chunk-AOFEMUHG.js.map +0 -1
- package/dist/chunk-AP6NCP3V.js.map +0 -1
- package/dist/chunk-APYY5CX3.js +0 -335
- package/dist/chunk-APYY5CX3.js.map +0 -1
- package/dist/chunk-ATPWMT2E.js +0 -223
- package/dist/chunk-ATPWMT2E.js.map +0 -1
- package/dist/chunk-BCCG7VWM.js.map +0 -1
- package/dist/chunk-E6M225BJ.js.map +0 -1
- package/dist/chunk-EQ4U73UH.js.map +0 -1
- package/dist/chunk-ETSJD5IV.js +0 -361
- package/dist/chunk-ETSJD5IV.js.map +0 -1
- package/dist/chunk-EWJZZDRG.js.map +0 -1
- package/dist/chunk-FHGWKODN.js +0 -2300
- package/dist/chunk-FHGWKODN.js.map +0 -1
- package/dist/chunk-GRTKLWYX.js +0 -621
- package/dist/chunk-GRTKLWYX.js.map +0 -1
- package/dist/chunk-IGLJNHOX.js +0 -62
- package/dist/chunk-IGLJNHOX.js.map +0 -1
- package/dist/chunk-IPT2OY4B.js.map +0 -1
- package/dist/chunk-IUKYFTGW.js.map +0 -1
- package/dist/chunk-KUIRDD74.js +0 -3991
- package/dist/chunk-KUIRDD74.js.map +0 -1
- package/dist/chunk-MVMRUGBH.js +0 -1919
- package/dist/chunk-MVMRUGBH.js.map +0 -1
- package/dist/chunk-ODL4ZTNI.js +0 -3644
- package/dist/chunk-ODL4ZTNI.js.map +0 -1
- package/dist/chunk-OGXXGHW6.js +0 -223
- package/dist/chunk-OGXXGHW6.js.map +0 -1
- package/dist/chunk-P5VZSSYL.js.map +0 -1
- package/dist/chunk-PPCLZ4JU.js +0 -28
- package/dist/chunk-PPCLZ4JU.js.map +0 -1
- package/dist/chunk-PUEO37QG.js.map +0 -1
- package/dist/chunk-RRTVGD3J.js +0 -792
- package/dist/chunk-RRTVGD3J.js.map +0 -1
- package/dist/chunk-STSLB4HT.js +0 -18793
- package/dist/chunk-STSLB4HT.js.map +0 -1
- package/dist/chunk-T6OZW2WR.js.map +0 -1
- package/dist/chunk-TRBGGJKZ.js +0 -32218
- package/dist/chunk-TRBGGJKZ.js.map +0 -1
- package/dist/chunk-UDKWFDV2.js.map +0 -1
- package/dist/chunk-V4XE263I.js.map +0 -1
- package/dist/chunk-V7IZKJI3.js +0 -22
- package/dist/chunk-V7IZKJI3.js.map +0 -1
- package/dist/chunk-VMVVSZTD.js +0 -61
- package/dist/chunk-VMVVSZTD.js.map +0 -1
- package/dist/chunk-VNUOAXWP.js +0 -203
- package/dist/chunk-VNUOAXWP.js.map +0 -1
- package/dist/chunk-WLBEZZK5.js +0 -729
- package/dist/chunk-WLBEZZK5.js.map +0 -1
- package/dist/chunk-WUUES6CU.js +0 -25
- package/dist/chunk-WUUES6CU.js.map +0 -1
- package/dist/chunk-WWK6J6SE.js.map +0 -1
- package/dist/chunk-XICOH5HT.js +0 -346
- package/dist/chunk-XICOH5HT.js.map +0 -1
- package/dist/chunk-YCNIGRRF.js.map +0 -1
- package/dist/chunk-YS2GHSWN.js.map +0 -1
- package/dist/chunk-ZCLEYJPB.js +0 -10143
- package/dist/chunk-ZCLEYJPB.js.map +0 -1
- /package/dist/{capsule-merge-2IIXFXN5.js.map → capsule-merge-6IDAYTKG.js.map} +0 -0
- /package/dist/{chunk-QL7RHYK6.js.map → chunk-2LMA22UU.js.map} +0 -0
- /package/dist/{chunk-RGUUBAT5.js.map → chunk-2WCLTWV2.js.map} +0 -0
- /package/dist/{chunk-RSK2WIEM.js.map → chunk-2YODOG2O.js.map} +0 -0
- /package/dist/{chunk-WYG5UNDY.js.map → chunk-3AUDELZL.js.map} +0 -0
- /package/dist/{chunk-OFVCFKDH.js.map → chunk-3CYOCE6U.js.map} +0 -0
- /package/dist/{chunk-6HM6HARE.js.map → chunk-3FBAEPCU.js.map} +0 -0
- /package/dist/{chunk-PIITB2YZ.js.map → chunk-3ZS3NUEI.js.map} +0 -0
- /package/dist/{chunk-ANZZLRUX.js.map → chunk-4IVRQMZW.js.map} +0 -0
- /package/dist/{chunk-63E37JCN.js.map → chunk-4RAJT5L2.js.map} +0 -0
- /package/dist/{chunk-45VUHDV2.js.map → chunk-5CO5G4MN.js.map} +0 -0
- /package/dist/{chunk-3UMDRGFS.js.map → chunk-65HWAQ4F.js.map} +0 -0
- /package/dist/{chunk-T67LUYCR.js.map → chunk-77NTFICT.js.map} +0 -0
- /package/dist/{chunk-UE6RRXMF.js.map → chunk-A4F7OIC5.js.map} +0 -0
- /package/dist/{chunk-63O7LVMN.js.map → chunk-B33YWUJV.js.map} +0 -0
- /package/dist/{chunk-QVMOCJRV.js.map → chunk-B377OKUP.js.map} +0 -0
- /package/dist/{chunk-ZT6WPSII.js.map → chunk-BGHCSLE5.js.map} +0 -0
- /package/dist/{chunk-YYOMGOHB.js.map → chunk-BOK6BN5M.js.map} +0 -0
- /package/dist/{chunk-OH7QLI6W.js.map → chunk-BPPUH5JM.js.map} +0 -0
- /package/dist/{chunk-EV76IZ37.js.map → chunk-BTI4C4MA.js.map} +0 -0
- /package/dist/{chunk-O6ZSWHVR.js.map → chunk-C2KE5DMD.js.map} +0 -0
- /package/dist/{chunk-47F6WWLQ.js.map → chunk-C73N66PR.js.map} +0 -0
- /package/dist/{chunk-3XIWW4TB.js.map → chunk-CGJYL633.js.map} +0 -0
- /package/dist/{chunk-WRT7GJ2D.js.map → chunk-CIWMTNHW.js.map} +0 -0
- /package/dist/{chunk-O55EKIEC.js.map → chunk-D3ZKHLN2.js.map} +0 -0
- /package/dist/{chunk-CD4BCCNP.js.map → chunk-DJ7WVEWX.js.map} +0 -0
- /package/dist/{chunk-RO7RUBLD.js.map → chunk-EFL24KOI.js.map} +0 -0
- /package/dist/{chunk-4CJTQHEG.js.map → chunk-ESLOLCD4.js.map} +0 -0
- /package/dist/{chunk-Z4Q6USKJ.js.map → chunk-ETBVCRVL.js.map} +0 -0
- /package/dist/{chunk-VILPVT4S.js.map → chunk-EZ47HOJ6.js.map} +0 -0
- /package/dist/{chunk-EFYN5I7Z.js.map → chunk-F4QFU5IZ.js.map} +0 -0
- /package/dist/{chunk-SHUBTAY2.js.map → chunk-FMKILENU.js.map} +0 -0
- /package/dist/{chunk-YLXETSAH.js.map → chunk-GCZJ7XRI.js.map} +0 -0
- /package/dist/{chunk-QFEDITXM.js.map → chunk-JNDMIAJ4.js.map} +0 -0
- /package/dist/{chunk-E5PPE4VA.js.map → chunk-K2VRKCPA.js.map} +0 -0
- /package/dist/{chunk-MKRYQROF.js.map → chunk-LGEHAQHK.js.map} +0 -0
- /package/dist/{chunk-XYTQJD7F.js.map → chunk-LMJVP5CM.js.map} +0 -0
- /package/dist/{chunk-JC36FPQ5.js.map → chunk-LPV72KRQ.js.map} +0 -0
- /package/dist/{chunk-2LCRG2YV.js.map → chunk-M2XR6B6V.js.map} +0 -0
- /package/dist/{chunk-VPQFK63H.js.map → chunk-MH632KPO.js.map} +0 -0
- /package/dist/{chunk-ZU5JDLOH.js.map → chunk-MMRTPH3J.js.map} +0 -0
- /package/dist/{chunk-ZZ67UTQX.js.map → chunk-MUX7IL77.js.map} +0 -0
- /package/dist/{chunk-RYWROSL5.js.map → chunk-NAQ4A5IX.js.map} +0 -0
- /package/dist/{chunk-TVIVY7KU.js.map → chunk-NED7IR7B.js.map} +0 -0
- /package/dist/{chunk-ADYP7HXE.js.map → chunk-NHVAX7MH.js.map} +0 -0
- /package/dist/{chunk-TG3R2SID.js.map → chunk-NMGHGTVR.js.map} +0 -0
- /package/dist/{chunk-NGHDW6UU.js.map → chunk-NUQEREIP.js.map} +0 -0
- /package/dist/{chunk-5IIQU4JZ.js.map → chunk-OB72KNMF.js.map} +0 -0
- /package/dist/{chunk-7L3TODI7.js.map → chunk-OJXJWNFY.js.map} +0 -0
- /package/dist/{chunk-EURPSF4Y.js.map → chunk-PH5ZQM35.js.map} +0 -0
- /package/dist/{chunk-BMWMTAQF.js.map → chunk-PRAUN6PN.js.map} +0 -0
- /package/dist/{chunk-RWGRSKN5.js.map → chunk-PT4DZDJA.js.map} +0 -0
- /package/dist/{chunk-7EPY3IQL.js.map → chunk-PZJQ46DH.js.map} +0 -0
- /package/dist/{chunk-AH637HZ5.js.map → chunk-QDESY76F.js.map} +0 -0
- /package/dist/{chunk-I6QGI65T.js.map → chunk-QRMG4HK4.js.map} +0 -0
- /package/dist/{chunk-ZU3NJNO7.js.map → chunk-QSF5SJAM.js.map} +0 -0
- /package/dist/{chunk-5IYOKDM4.js.map → chunk-R23JWJD3.js.map} +0 -0
- /package/dist/{chunk-LJQFJF4J.js.map → chunk-RM2YUFH6.js.map} +0 -0
- /package/dist/{chunk-6QMWECO5.js.map → chunk-SGQPR5SX.js.map} +0 -0
- /package/dist/{chunk-ZGFLIK5H.js.map → chunk-SPAKBUJY.js.map} +0 -0
- /package/dist/{chunk-ER7XANP3.js.map → chunk-SQ3GEIEL.js.map} +0 -0
- /package/dist/{chunk-5UCMYPVF.js.map → chunk-SVT5IA2H.js.map} +0 -0
- /package/dist/{chunk-FRSHF6FU.js.map → chunk-TJ4F6H4H.js.map} +0 -0
- /package/dist/{chunk-R6HMAIKM.js.map → chunk-TOSPNM4T.js.map} +0 -0
- /package/dist/{chunk-NJJMVS5Y.js.map → chunk-TRQE3RYR.js.map} +0 -0
- /package/dist/{chunk-RMXS4I66.js.map → chunk-TVDJEUV5.js.map} +0 -0
- /package/dist/{chunk-PLCYKAWH.js.map → chunk-TYRWSE4B.js.map} +0 -0
- /package/dist/{chunk-IQWUACVG.js.map → chunk-UHMHJX5G.js.map} +0 -0
- /package/dist/{chunk-YODUDA6R.js.map → chunk-UN4RVUG2.js.map} +0 -0
- /package/dist/{chunk-KZSGBWOJ.js.map → chunk-V2KGDESV.js.map} +0 -0
- /package/dist/{chunk-E6Z4FBX6.js.map → chunk-V2QSNFCT.js.map} +0 -0
- /package/dist/{chunk-N74SGESS.js.map → chunk-WKSQTMU7.js.map} +0 -0
- /package/dist/{chunk-RIZ5NUNN.js.map → chunk-WQ4XKIOX.js.map} +0 -0
- /package/dist/{chunk-QEYTRFR3.js.map → chunk-X26YOFGS.js.map} +0 -0
- /package/dist/{chunk-ITHZFHST.js.map → chunk-X2BVB74H.js.map} +0 -0
- /package/dist/{chunk-GNXGJBCA.js.map → chunk-XIYLWEXC.js.map} +0 -0
- /package/dist/{chunk-IBJ6U753.js.map → chunk-XKZBZOKV.js.map} +0 -0
- /package/dist/{chunk-7O2MC42R.js.map → chunk-XNRLRNQF.js.map} +0 -0
- /package/dist/{chunk-65AUYLU3.js.map → chunk-XPXHQI6N.js.map} +0 -0
- /package/dist/{chunk-JBCCWVU2.js.map → chunk-XRDYRWZI.js.map} +0 -0
- /package/dist/{chunk-2JSDPUKD.js.map → chunk-YMFPFXEX.js.map} +0 -0
- /package/dist/{chunk-645WOU5I.js.map → chunk-ZDZJNXL6.js.map} +0 -0
- /package/dist/{chunk-6TCXIRP5.js.map → chunk-ZKE4CO6B.js.map} +0 -0
- /package/dist/{chunk-KEPXC4KN.js.map → chunk-ZSE774RV.js.map} +0 -0
- /package/dist/{contradiction-scan-P2MHYFVG.js.map → contradiction-scan-IBPYGQZF.js.map} +0 -0
- /package/dist/{resolution-N7H3F2E4.js.map → resolution-OVVIF7ZY.js.map} +0 -0
- /package/dist/{state-store-I5HLZTZT.js.map → state-store-EEAX2MBS.js.map} +0 -0
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
// Shutdown-signal behavioral tests for LocalLlmClient: a daemon stop must
|
|
2
|
+
// abort in-flight chat requests at once (the abort reaches the transport),
|
|
3
|
+
// must not start another attempt once aborted, and must not sit out the
|
|
4
|
+
// retry backoff after abort. Uses the globalThis.fetch seam from
|
|
5
|
+
// local-llm-qos.test.ts with a hanging transport so the real retry loop is
|
|
6
|
+
// exercised, not a mock of it.
|
|
7
|
+
import assert from "node:assert/strict";
|
|
8
|
+
import test from "node:test";
|
|
9
|
+
|
|
10
|
+
import { parseConfig } from "./config.js";
|
|
11
|
+
import { LocalLlmClient } from "./local-llm.js";
|
|
12
|
+
import { initLogger, resetLogger, type LoggerBackend } from "./logger.js";
|
|
13
|
+
|
|
14
|
+
/** Captured log lines with the logger's "remnic: " prefix stripped. */
|
|
15
|
+
interface CapturedLog {
|
|
16
|
+
lines: string[];
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function createConfig(memoryDir: string) {
|
|
20
|
+
return parseConfig({
|
|
21
|
+
openaiApiKey: "sk-test",
|
|
22
|
+
memoryDir,
|
|
23
|
+
workspaceDir: `${memoryDir}/workspace`,
|
|
24
|
+
localLlmEnabled: true,
|
|
25
|
+
localLlmModel: "test-local-model",
|
|
26
|
+
localLlmUrl: "http://127.0.0.1:9",
|
|
27
|
+
// Mirror the production daemon: a 10-minute budget with 2 attempts, so
|
|
28
|
+
// an unhonored abort would outlive any sane test deadline.
|
|
29
|
+
localLlmTimeoutMs: 600_000,
|
|
30
|
+
localLlmRetry5xxCount: 1,
|
|
31
|
+
localLlmRetryBackoffMs: 30_000,
|
|
32
|
+
localLlmHeaders: {},
|
|
33
|
+
localLlm400TripThreshold: 3,
|
|
34
|
+
localLlm400CooldownMs: 60_000,
|
|
35
|
+
localLlmReasoningEffort: "none",
|
|
36
|
+
debug: false,
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
interface HangingFetchSpec {
|
|
41
|
+
calls: { signal: AbortSignal | undefined }[];
|
|
42
|
+
sawAbort: boolean;
|
|
43
|
+
/** Reject with AbortError after delayMs (timeout simulation); default hangs forever. */
|
|
44
|
+
timeoutAfterMs?: number;
|
|
45
|
+
/** Resolves when the transport stub is entered (request is in flight). */
|
|
46
|
+
entered: Promise<void>;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function installHangingFetch(spec: HangingFetchSpec): () => void {
|
|
50
|
+
const { promise: entered, resolve: markEntered } = Promise.withResolvers<void>();
|
|
51
|
+
spec.entered = entered;
|
|
52
|
+
const originalFetch = globalThis.fetch;
|
|
53
|
+
// SAFETY: the transport passes a string URL and an init with a signal;
|
|
54
|
+
// this async stub matches that call shape exactly.
|
|
55
|
+
globalThis.fetch = (async (url: string, init?: { signal?: AbortSignal }) => {
|
|
56
|
+
void url;
|
|
57
|
+
const signal = init?.signal;
|
|
58
|
+
spec.calls.push({ signal });
|
|
59
|
+
markEntered();
|
|
60
|
+
const { promise, reject } = Promise.withResolvers<Response>();
|
|
61
|
+
// A real transport rejects with AbortError when its signal aborts
|
|
62
|
+
// (undici behavior); the stub must honor it the same way or the client
|
|
63
|
+
// loop cannot observe the abort.
|
|
64
|
+
const onAbort = (): void => {
|
|
65
|
+
spec.sawAbort = true;
|
|
66
|
+
reject(new DOMException("This operation was aborted", "AbortError"));
|
|
67
|
+
};
|
|
68
|
+
if (signal) {
|
|
69
|
+
if (signal.aborted) onAbort();
|
|
70
|
+
else signal.addEventListener("abort", onAbort, { once: true });
|
|
71
|
+
}
|
|
72
|
+
if (spec.timeoutAfterMs !== undefined) {
|
|
73
|
+
const timer = setTimeout(() => {
|
|
74
|
+
signal?.removeEventListener("abort", onAbort);
|
|
75
|
+
reject(new DOMException("This operation was aborted", "AbortError"));
|
|
76
|
+
}, spec.timeoutAfterMs);
|
|
77
|
+
timer.unref?.();
|
|
78
|
+
}
|
|
79
|
+
return await promise;
|
|
80
|
+
}) as typeof fetch;
|
|
81
|
+
return () => {
|
|
82
|
+
globalThis.fetch = originalFetch;
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/** Polls a real runtime condition (a log line, a stub entry) instead of a
|
|
87
|
+
* guessed fixed sleep: the condition, not a duration, gates progress. */
|
|
88
|
+
async function waitFor(
|
|
89
|
+
predicate: () => boolean,
|
|
90
|
+
description: string,
|
|
91
|
+
timeoutMs = 5_000,
|
|
92
|
+
): Promise<void> {
|
|
93
|
+
const deadline = Date.now() + timeoutMs;
|
|
94
|
+
while (!predicate()) {
|
|
95
|
+
if (Date.now() > deadline) throw new Error(`condition not met: ${description}`);
|
|
96
|
+
await new Promise((resolve) => setTimeout(resolve, 10));
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
async function withTestDeadline<T>(promise: Promise<T>, timeoutMs: number, label: string): Promise<T> {
|
|
101
|
+
const { promise: deadline, reject } = Promise.withResolvers<never>();
|
|
102
|
+
const timer = setTimeout(() => reject(new Error(`${label}: test deadline exceeded (${timeoutMs}ms)`)), timeoutMs);
|
|
103
|
+
timer.unref?.();
|
|
104
|
+
try {
|
|
105
|
+
return await Promise.race([promise, deadline]);
|
|
106
|
+
} finally {
|
|
107
|
+
clearTimeout(timer);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
function installRecordingLogger(): CapturedLog {
|
|
112
|
+
const lines: string[] = [];
|
|
113
|
+
const body = (msg: string) => msg.replace(/^remnic: /, "");
|
|
114
|
+
const backend: LoggerBackend = {
|
|
115
|
+
info: (msg) => lines.push(body(msg)),
|
|
116
|
+
warn: (msg) => lines.push(body(msg)),
|
|
117
|
+
error: (msg) => lines.push(body(msg)),
|
|
118
|
+
};
|
|
119
|
+
initLogger(backend, false, { timestamps: false });
|
|
120
|
+
return { lines };
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
function quietLogger(): void {
|
|
124
|
+
initLogger({ info() {}, warn() {}, error() {}, debug() {} }, false);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
test("aborting the client shutdown signal aborts an in-flight request and reaches the transport stub", async () => {
|
|
128
|
+
quietLogger();
|
|
129
|
+
const spec: HangingFetchSpec = { calls: [], sawAbort: false, entered: Promise.resolve() };
|
|
130
|
+
const restoreFetch = installHangingFetch(spec);
|
|
131
|
+
try {
|
|
132
|
+
const controller = new AbortController();
|
|
133
|
+
const client = new LocalLlmClient(createConfig("/tmp/remnic-llm-shutdown-inflight"), undefined, controller.signal);
|
|
134
|
+
// SAFETY: availability is stubbed at the established field seam (same as
|
|
135
|
+
// local-llm-qos.test.ts) so the retry loop, not the network probe, runs.
|
|
136
|
+
const seams = client as any;
|
|
137
|
+
seams.isAvailable = true;
|
|
138
|
+
seams.lastHealthCheck = Date.now();
|
|
139
|
+
|
|
140
|
+
const pending = client.chatCompletion(
|
|
141
|
+
[{ role: "user", content: "shutdown abort in flight" }],
|
|
142
|
+
{ operation: "extraction" },
|
|
143
|
+
);
|
|
144
|
+
|
|
145
|
+
await spec.entered;
|
|
146
|
+
controller.abort();
|
|
147
|
+
|
|
148
|
+
const result = await withTestDeadline(pending, 2_000, "in-flight abort");
|
|
149
|
+
assert.equal(result, null);
|
|
150
|
+
assert.equal(spec.calls.length, 1, "no second attempt may start after abort");
|
|
151
|
+
assert.equal(spec.sawAbort, true, "the abort signal must reach the transport stub");
|
|
152
|
+
assert.equal(spec.calls[0]?.signal?.aborted, true);
|
|
153
|
+
} finally {
|
|
154
|
+
restoreFetch();
|
|
155
|
+
resetLogger();
|
|
156
|
+
}
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
test("an abort during retry backoff ends the loop without sleeping it out or starting another attempt", async () => {
|
|
160
|
+
const { lines } = installRecordingLogger();
|
|
161
|
+
const spec: HangingFetchSpec = { calls: [], sawAbort: false, timeoutAfterMs: 20, entered: Promise.resolve() };
|
|
162
|
+
const restoreFetch = installHangingFetch(spec);
|
|
163
|
+
try {
|
|
164
|
+
const controller = new AbortController();
|
|
165
|
+
const client = new LocalLlmClient(createConfig("/tmp/remnic-llm-shutdown-backoff"), undefined, controller.signal);
|
|
166
|
+
// SAFETY: availability is stubbed at the established field seam (same as
|
|
167
|
+
// local-llm-qos.test.ts) so the retry loop, not the network probe, runs.
|
|
168
|
+
const seams = client as any;
|
|
169
|
+
seams.isAvailable = true;
|
|
170
|
+
seams.lastHealthCheck = Date.now();
|
|
171
|
+
|
|
172
|
+
const pending = client.chatCompletion(
|
|
173
|
+
[{ role: "user", content: "shutdown abort during backoff" }],
|
|
174
|
+
{ operation: "extraction" },
|
|
175
|
+
);
|
|
176
|
+
|
|
177
|
+
// Sync point: the retry loop is in its 30s backoff when the backoff
|
|
178
|
+
// warn line lands; abort there.
|
|
179
|
+
await waitFor(
|
|
180
|
+
() => lines.some((line) => line.includes("retrying after 30000ms")),
|
|
181
|
+
"attempt 1 to fail and backoff to start",
|
|
182
|
+
);
|
|
183
|
+
controller.abort();
|
|
184
|
+
|
|
185
|
+
const startedAtMs = Date.now();
|
|
186
|
+
const result = await withTestDeadline(pending, 2_000, "backoff abort");
|
|
187
|
+
assert.equal(result, null);
|
|
188
|
+
assert.ok(Date.now() - startedAtMs < 1_500, "backoff must not be slept out after abort");
|
|
189
|
+
assert.equal(spec.calls.length, 1, "no second attempt may start after abort");
|
|
190
|
+
} finally {
|
|
191
|
+
restoreFetch();
|
|
192
|
+
resetLogger();
|
|
193
|
+
}
|
|
194
|
+
});
|
package/src/local-llm.ts
CHANGED
|
@@ -20,6 +20,7 @@ import {
|
|
|
20
20
|
type ProbeFetchResult,
|
|
21
21
|
normalizeBackendTripReason,
|
|
22
22
|
waitForRetryBackoff,
|
|
23
|
+
combineClientAbortSignals,
|
|
23
24
|
SingleFlightProbe,
|
|
24
25
|
type LocalLlmChatCompletionOptions,
|
|
25
26
|
type LocalLlmChatCompletionResult,
|
|
@@ -201,10 +202,14 @@ export class LocalLlmClient {
|
|
|
201
202
|
private static readonly HEALTH_CHECK_INTERVAL_MS = 60000; // 1 minute
|
|
202
203
|
private static readonly LMS_CACHE_INTERVAL_MS = 30000; // 30 seconds
|
|
203
204
|
private readonly chatTransport = new ChatTransport();
|
|
205
|
+
/** Orchestrator-owned stop signal: aborts every in-flight and queued
|
|
206
|
+
* request (and their retry backoffs) the moment teardown begins. */
|
|
207
|
+
private readonly shutdownSignal: AbortSignal | undefined;
|
|
204
208
|
|
|
205
|
-
constructor(config: PluginConfig, modelRegistry?: ModelRegistry) {
|
|
209
|
+
constructor(config: PluginConfig, modelRegistry?: ModelRegistry, shutdownSignal?: AbortSignal) {
|
|
206
210
|
this.config = config;
|
|
207
211
|
this.modelRegistry = modelRegistry;
|
|
212
|
+
this.shutdownSignal = shutdownSignal;
|
|
208
213
|
}
|
|
209
214
|
|
|
210
215
|
/**
|
|
@@ -829,7 +834,7 @@ export class LocalLlmClient {
|
|
|
829
834
|
|
|
830
835
|
private async runQueuedRequest(next: LocalLlmQueuedRequest): Promise<void> {
|
|
831
836
|
try {
|
|
832
|
-
if (next.options.signal?.aborted) {
|
|
837
|
+
if (combineClientAbortSignals(next.options.signal, this.shutdownSignal)?.aborted) {
|
|
833
838
|
next.resolve(null);
|
|
834
839
|
return;
|
|
835
840
|
}
|
|
@@ -879,8 +884,9 @@ export class LocalLlmClient {
|
|
|
879
884
|
}
|
|
880
885
|
|
|
881
886
|
try {
|
|
882
|
-
|
|
883
|
-
|
|
887
|
+
const signal = combineClientAbortSignals(options.signal, this.shutdownSignal);
|
|
888
|
+
if (signal?.aborted) return null;
|
|
889
|
+
const isAvailable = await this.checkAvailability(signal);
|
|
884
890
|
if (!isAvailable) {
|
|
885
891
|
log.debug(
|
|
886
892
|
`local LLM: checkAvailability returned false for ${this.config.localLlmUrl}`,
|
|
@@ -977,7 +983,7 @@ export class LocalLlmClient {
|
|
|
977
983
|
response = null;
|
|
978
984
|
responseBody = "";
|
|
979
985
|
// Wait out the shared endpoint backoff, then take a concurrency slot.
|
|
980
|
-
const gate = await rateLimit.beforeAttempt(
|
|
986
|
+
const gate = await rateLimit.beforeAttempt(signal);
|
|
981
987
|
if (gate.kind === "skip") {
|
|
982
988
|
log.warn(gate.reason === "queue"
|
|
983
989
|
? `local LLM concurrency queue exceeded the ${effectiveTimeoutMs}ms request budget; skipping request (op=${operation})`
|
|
@@ -989,24 +995,25 @@ export class LocalLlmClient {
|
|
|
989
995
|
if (gate.kind === "aborted") return null;
|
|
990
996
|
const attemptAbort = new AbortController();
|
|
991
997
|
const onCallerAbort = (): void => {
|
|
992
|
-
attemptAbort.abort(
|
|
998
|
+
attemptAbort.abort(signal?.reason);
|
|
993
999
|
};
|
|
994
|
-
if (
|
|
995
|
-
if (
|
|
1000
|
+
if (signal) {
|
|
1001
|
+
if (signal.aborted) {
|
|
996
1002
|
onCallerAbort();
|
|
997
1003
|
} else {
|
|
998
|
-
|
|
1004
|
+
signal.addEventListener("abort", onCallerAbort, { once: true });
|
|
999
1005
|
}
|
|
1000
1006
|
}
|
|
1001
1007
|
const attemptTimeout = setTimeout(() => attemptAbort.abort(), effectiveTimeoutMs);
|
|
1008
|
+
const postAttempt = (bodyJson: string): Promise<Response> => this.chatTransport.post({
|
|
1009
|
+
url: chatUrl,
|
|
1010
|
+
headers: this.buildRequestHeaders({ "Content-Type": "application/json" }),
|
|
1011
|
+
body: bodyJson,
|
|
1012
|
+
signal: attemptAbort.signal,
|
|
1013
|
+
budgetMs: this.config.localLlmTimeoutMs,
|
|
1014
|
+
});
|
|
1002
1015
|
try {
|
|
1003
|
-
response = await
|
|
1004
|
-
url: chatUrl,
|
|
1005
|
-
headers: this.buildRequestHeaders({ "Content-Type": "application/json" }),
|
|
1006
|
-
body: requestBodyJson,
|
|
1007
|
-
signal: attemptAbort.signal,
|
|
1008
|
-
budgetMs: this.config.localLlmTimeoutMs,
|
|
1009
|
-
});
|
|
1016
|
+
response = await postAttempt(requestBodyJson);
|
|
1010
1017
|
responseBody = await response.text();
|
|
1011
1018
|
if (
|
|
1012
1019
|
response.status === 400 &&
|
|
@@ -1019,18 +1026,12 @@ export class LocalLlmClient {
|
|
|
1019
1026
|
requestBodyJson = JSON.stringify(requestBody);
|
|
1020
1027
|
log.debug("local LLM rejected native JSON schema; retrying without it");
|
|
1021
1028
|
response = null;
|
|
1022
|
-
response = await
|
|
1023
|
-
url: chatUrl,
|
|
1024
|
-
headers: this.buildRequestHeaders({ "Content-Type": "application/json" }),
|
|
1025
|
-
body: requestBodyJson,
|
|
1026
|
-
signal: attemptAbort.signal,
|
|
1027
|
-
budgetMs: this.config.localLlmTimeoutMs,
|
|
1028
|
-
});
|
|
1029
|
+
response = await postAttempt(requestBodyJson);
|
|
1029
1030
|
responseBody = await response.text();
|
|
1030
1031
|
}
|
|
1031
1032
|
} catch (err) {
|
|
1032
1033
|
const error = err instanceof Error ? err : new Error(String(err));
|
|
1033
|
-
if (
|
|
1034
|
+
if (signal?.aborted) {
|
|
1034
1035
|
response = null;
|
|
1035
1036
|
lastAbortError = error;
|
|
1036
1037
|
break;
|
|
@@ -1046,12 +1047,12 @@ export class LocalLlmClient {
|
|
|
1046
1047
|
log.warn(
|
|
1047
1048
|
`local LLM request aborted: op=${operation} attempt=${attempt}/${maxAttempts} timeoutMs=${effectiveTimeoutMs} model=${this.config.localLlmModel}; retrying after ${backoffMs}ms`,
|
|
1048
1049
|
);
|
|
1049
|
-
if (!(await waitForRetryBackoff(backoffMs,
|
|
1050
|
+
if (!(await waitForRetryBackoff(backoffMs, signal))) return null;
|
|
1050
1051
|
continue;
|
|
1051
1052
|
}
|
|
1052
1053
|
} finally {
|
|
1053
1054
|
clearTimeout(attemptTimeout);
|
|
1054
|
-
|
|
1055
|
+
signal?.removeEventListener("abort", onCallerAbort);
|
|
1055
1056
|
gate.release();
|
|
1056
1057
|
}
|
|
1057
1058
|
|
|
@@ -1085,7 +1086,7 @@ export class LocalLlmClient {
|
|
|
1085
1086
|
log.warn(
|
|
1086
1087
|
`local LLM request got ${response.status}; retrying (attempt ${attempt + 1}/${maxAttempts}) after ${backoffMs}ms`,
|
|
1087
1088
|
);
|
|
1088
|
-
if (!(await waitForRetryBackoff(backoffMs,
|
|
1089
|
+
if (!(await waitForRetryBackoff(backoffMs, signal))) return null;
|
|
1089
1090
|
}
|
|
1090
1091
|
log.debug(
|
|
1091
1092
|
`local LLM: received response, status=${response?.status}, ok=${response?.ok}`,
|
|
@@ -1401,13 +1402,14 @@ export class LocalLlmClient {
|
|
|
1401
1402
|
}
|
|
1402
1403
|
if (options.priority) {
|
|
1403
1404
|
const priority = options.priority;
|
|
1405
|
+
const signal = combineClientAbortSignals(options.signal, this.shutdownSignal);
|
|
1404
1406
|
return await new Promise<LocalLlmChatCompletionResult | null>((resolve) => {
|
|
1405
1407
|
let settled = false;
|
|
1406
1408
|
let onAbort: (() => void) | undefined;
|
|
1407
1409
|
const finish = (value: LocalLlmChatCompletionResult | null): void => {
|
|
1408
1410
|
if (settled) return;
|
|
1409
1411
|
settled = true;
|
|
1410
|
-
if (onAbort)
|
|
1412
|
+
if (onAbort) signal?.removeEventListener("abort", onAbort);
|
|
1411
1413
|
resolve(value);
|
|
1412
1414
|
};
|
|
1413
1415
|
const queued: LocalLlmQueuedRequest = {
|
|
@@ -1424,8 +1426,8 @@ export class LocalLlmClient {
|
|
|
1424
1426
|
finish(null);
|
|
1425
1427
|
};
|
|
1426
1428
|
this.requestQueues[priority].push(queued);
|
|
1427
|
-
if (
|
|
1428
|
-
else if (
|
|
1429
|
+
if (signal?.aborted) onAbort();
|
|
1430
|
+
else if (signal) signal.addEventListener("abort", onAbort, { once: true });
|
|
1429
1431
|
this.scheduleQueueDrain();
|
|
1430
1432
|
});
|
|
1431
1433
|
}
|
|
@@ -113,6 +113,10 @@ export interface ExtractionRunCoordinatorDeps {
|
|
|
113
113
|
* threshold and honors a foreground-opened breaker (review round).
|
|
114
114
|
*/
|
|
115
115
|
providerBreaker?: ProviderCircuitBreaker;
|
|
116
|
+
/** Orchestrator-owned stop signal, combined into every extraction run's
|
|
117
|
+
* abort signal: queued tasks never start and in-flight runs abort the
|
|
118
|
+
* moment destroy() begins. Absent for standalone coordinators (tests). */
|
|
119
|
+
shutdownSignal?: AbortSignal;
|
|
116
120
|
}
|
|
117
121
|
|
|
118
122
|
// Recall/extraction abort helpers live in orchestrator-helpers.ts since
|
|
@@ -692,11 +696,16 @@ export class ExtractionRunCoordinator {
|
|
|
692
696
|
typeof deadlineMs === "number" && Number.isFinite(deadlineMs)
|
|
693
697
|
? new AbortController()
|
|
694
698
|
: undefined;
|
|
699
|
+
const shutdownSignal = this.deps.shutdownSignal;
|
|
700
|
+
const callerAbortSignal =
|
|
701
|
+
options.abortSignal && shutdownSignal
|
|
702
|
+
? AbortSignal.any([options.abortSignal, shutdownSignal])
|
|
703
|
+
: (options.abortSignal ?? shutdownSignal);
|
|
695
704
|
const extractionAbortSignal = extractionDeadlineController
|
|
696
|
-
?
|
|
697
|
-
? AbortSignal.any([
|
|
705
|
+
? callerAbortSignal
|
|
706
|
+
? AbortSignal.any([callerAbortSignal, extractionDeadlineController.signal])
|
|
698
707
|
: extractionDeadlineController.signal
|
|
699
|
-
:
|
|
708
|
+
: callerAbortSignal;
|
|
700
709
|
let extractionDeadlineTimer: NodeJS.Timeout | undefined;
|
|
701
710
|
const clearExtractionDeadlineTimer = (): void => {
|
|
702
711
|
if (extractionDeadlineTimer) {
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
import path from "node:path";
|
|
2
2
|
import { serializeMutations, withHeldFileLock } from "../utils/serialize-mutations.js";
|
|
3
|
-
|
|
3
|
+
// Import from the real modules, NOT the ../index.js barrel: a barrel edge
|
|
4
|
+
// from orchestration code that explicit-capture.ts imports re-orders module
|
|
5
|
+
// initialization and leaves access-boundary's registry in TDZ (#3354).
|
|
6
|
+
import { ContentHashIndex } from "../storage/content-hash-index.js";
|
|
7
|
+
import type { StorageManager } from "../storage.js";
|
|
4
8
|
import type { MemoryFile } from "../types.js";
|
|
5
9
|
import { normalizeStoredHashSource } from "./extraction-persist-citation.js";
|
|
6
10
|
import { stripAttributesSuffix } from "../structured-attributes.js";
|
|
@@ -1331,8 +1331,10 @@ test("#1909 round 11: the restart rebuild reflects the current corpus (archived
|
|
|
1331
1331
|
test("#1909 round 11 finding 2: destroy() flushes the debounced buffer BEFORE catalog touches", async () => {
|
|
1332
1332
|
// The buffer save fires a coalesced namespace-catalog touch; if catalog touches
|
|
1333
1333
|
// were flushed first, that shutdown-time touch would queue after and be lost.
|
|
1334
|
-
// destroy()
|
|
1335
|
-
// flush
|
|
1334
|
+
// destroy() flushes the buffer before the extraction drain and again after it
|
|
1335
|
+
// (post-drain removals); every buffer flush must run before the one catalog
|
|
1336
|
+
// flush so each shutdown-time touch folds into it and settles before destroy()
|
|
1337
|
+
// returns.
|
|
1336
1338
|
const memoryDir = await mkdtemp(path.join(os.tmpdir(), "remnic-destroy-order-"));
|
|
1337
1339
|
const config = parseConfig({
|
|
1338
1340
|
openaiApiKey: "sk-test",
|
|
@@ -1363,10 +1365,12 @@ test("#1909 round 11 finding 2: destroy() flushes the debounced buffer BEFORE ca
|
|
|
1363
1365
|
|
|
1364
1366
|
await priv.destroy();
|
|
1365
1367
|
assert.deepEqual(
|
|
1366
|
-
order,
|
|
1367
|
-
["
|
|
1368
|
-
"
|
|
1368
|
+
order.filter((step) => step === "catalog"),
|
|
1369
|
+
["catalog"],
|
|
1370
|
+
"the catalog-touch flush runs exactly once",
|
|
1369
1371
|
);
|
|
1372
|
+
assert.equal(order.at(-1), "catalog", "no buffer flush may run after the catalog-touch flush");
|
|
1373
|
+
assert.ok(order.includes("buffer"), "destroy() flushes the buffer");
|
|
1370
1374
|
});
|
|
1371
1375
|
test("#1909 round 14: destroy() surfaces a buffer flush failure and still completes teardown", async () => {
|
|
1372
1376
|
// Graceful-shutdown durability contract: a failed shutdown buffer flush must
|
package/src/orchestrator.ts
CHANGED
|
@@ -236,6 +236,7 @@ import {
|
|
|
236
236
|
runLiveConnectorsOnce,
|
|
237
237
|
type LiveConnectorsRunSummary,
|
|
238
238
|
} from "./live-connectors-runner.js";
|
|
239
|
+
import type { ResolveSecretRefFn } from "./resolve-auth-token.js";
|
|
239
240
|
import {
|
|
240
241
|
runPatternReinforcement,
|
|
241
242
|
type PatternReinforcementResult,
|
|
@@ -738,6 +739,9 @@ export class Orchestrator {
|
|
|
738
739
|
private _dependencyPropagationRecovery: Promise<void> | null = null;
|
|
739
740
|
private destroyed = false;
|
|
740
741
|
private acceptingEntityMigrationMaintenance = true;
|
|
742
|
+
/** Aborted at the start of destroy(); stops every local-LLM client and extraction task at once. */
|
|
743
|
+
private readonly shutdownController = new AbortController();
|
|
744
|
+
readonly shutdownSignal: AbortSignal = this.shutdownController.signal;
|
|
741
745
|
|
|
742
746
|
private get dependencyPropagationDelivery(): DependencyPropagationDelivery {
|
|
743
747
|
if (this.destroyed) throw new Error("orchestrator has been destroyed");
|
|
@@ -769,9 +773,8 @@ export class Orchestrator {
|
|
|
769
773
|
return this._providerBreaker;
|
|
770
774
|
}
|
|
771
775
|
|
|
772
|
-
/** The run-coordinator deps bundle, parameterized by its buffer accessor
|
|
773
|
-
* an isolated claim-backed drain
|
|
774
|
-
* backlog scheduler) while live extraction keeps `this.buffer`. */
|
|
776
|
+
/** The run-coordinator deps bundle, parameterized by its buffer accessor:
|
|
777
|
+
* an isolated claim-backed drain binds its own SmartBuffer (backlog scheduler). */
|
|
775
778
|
private extractionRunDeps(getBuffer: () => SmartBuffer): ExtractionRunCoordinatorDeps {
|
|
776
779
|
return {
|
|
777
780
|
config: this.config,
|
|
@@ -794,9 +797,26 @@ export class Orchestrator {
|
|
|
794
797
|
runTierMigrationCycle: (storage, trigger, options) => this.runTierMigrationCycle(storage, trigger, options),
|
|
795
798
|
recordProcessedExtractionFingerprint: (storage, fingerprint, preloadedMeta) =>
|
|
796
799
|
this.recordProcessedExtractionFingerprint(storage, fingerprint, preloadedMeta),
|
|
800
|
+
shutdownSignal: this.shutdownSignal,
|
|
797
801
|
};
|
|
798
802
|
}
|
|
799
803
|
|
|
804
|
+
/** Fast-tier client: low latency at all costs, thinking always suppressed. */
|
|
805
|
+
private buildFastLlm(config: PluginConfig): LocalLlmClient {
|
|
806
|
+
const client = new LocalLlmClient(
|
|
807
|
+
{
|
|
808
|
+
...config,
|
|
809
|
+
localLlmModel: config.localLlmFastModel || config.localLlmModel,
|
|
810
|
+
localLlmUrl: config.localLlmFastUrl,
|
|
811
|
+
localLlmTimeoutMs: config.localLlmFastTimeoutMs,
|
|
812
|
+
},
|
|
813
|
+
this.modelRegistry,
|
|
814
|
+
this.shutdownSignal,
|
|
815
|
+
);
|
|
816
|
+
client.disableThinking = true;
|
|
817
|
+
return client;
|
|
818
|
+
}
|
|
819
|
+
|
|
800
820
|
private get extractionRunCoordinator(): ExtractionRunCoordinator {
|
|
801
821
|
if (!this._extractionRunCoordinator) {
|
|
802
822
|
this._extractionRunCoordinator = new ExtractionRunCoordinator(this.extractionRunDeps(() => this.buffer));
|
|
@@ -982,6 +1002,8 @@ export class Orchestrator {
|
|
|
982
1002
|
* commands should call it before returning to let Node exit naturally.
|
|
983
1003
|
*/
|
|
984
1004
|
async destroy(): Promise<void> {
|
|
1005
|
+
// First, always: every client and extraction task holds this signal.
|
|
1006
|
+
this.shutdownController.abort();
|
|
985
1007
|
this.acceptingEntityMigrationMaintenance = false;
|
|
986
1008
|
this._orchestratorInitCoordinator?.retireStartupEpoch();
|
|
987
1009
|
this.abortDeferredInit();
|
|
@@ -995,23 +1017,29 @@ export class Orchestrator {
|
|
|
995
1017
|
await this.maintenanceScheduler.dispose();
|
|
996
1018
|
await this._dependencyPropagationRecovery;
|
|
997
1019
|
this._dependencyPropagationRecovery = null;
|
|
1020
|
+
// Persist unsent turns BEFORE the extraction drain: buffered turns must
|
|
1021
|
+
// already be on disk when shutdown abandons or bounds the drain's wait.
|
|
1022
|
+
let bufferFlushError: unknown;
|
|
1023
|
+
try {
|
|
1024
|
+
await this.buffer.flushPendingSave({ throwOnFailure: true });
|
|
1025
|
+
} catch (err) {
|
|
1026
|
+
bufferFlushError = err;
|
|
1027
|
+
}
|
|
998
1028
|
const extractionDrainError = await drainExtractionAndShutdownDependencyPropagation(
|
|
999
1029
|
this.extractionQueueCoordinator,
|
|
1000
1030
|
this._dependencyPropagationDelivery,
|
|
1001
1031
|
);
|
|
1032
|
+
// After the drain, never before: an extraction already in its persist
|
|
1033
|
+
// stage reads dependencyPropagationDelivery, and this flag gates that
|
|
1034
|
+
// getter ("orchestrator has been destroyed").
|
|
1002
1035
|
this.destroyed = true;
|
|
1003
1036
|
this._dependencyPropagationDelivery = undefined;
|
|
1037
|
+
// Persist post-drain removals; a failed write stays pending for next boot.
|
|
1038
|
+
await this.buffer.flushPendingSave().catch(() => undefined);
|
|
1004
1039
|
await drainRecallWrites(this);
|
|
1005
1040
|
await this.persistenceIndexCoordinator
|
|
1006
1041
|
.drainContentHashReconcileRetries()
|
|
1007
1042
|
.catch((err) => log.warn(`content-hash reconcile drain failed during destroy: ${err}`));
|
|
1008
|
-
// Save buffered turns before catalog flush; rethrow save failures after teardown.
|
|
1009
|
-
let bufferFlushError: unknown;
|
|
1010
|
-
try {
|
|
1011
|
-
await this.buffer.flushPendingSave({ throwOnFailure: true });
|
|
1012
|
-
} catch (err) {
|
|
1013
|
-
bufferFlushError = err;
|
|
1014
|
-
}
|
|
1015
1043
|
try {
|
|
1016
1044
|
// Flush catalog touches before backend disposal.
|
|
1017
1045
|
await this.namespaceCatalog.flushPendingTouches().catch(() => undefined);
|
|
@@ -1667,35 +1695,16 @@ export class Orchestrator {
|
|
|
1667
1695
|
config.gatewayConfig,
|
|
1668
1696
|
this.modelRegistry,
|
|
1669
1697
|
this.transcript,
|
|
1698
|
+
this.shutdownSignal,
|
|
1670
1699
|
);
|
|
1671
1700
|
this.judgeVerdictCache = createVerdictCache();
|
|
1672
1701
|
this.judgeDeferCounts = createDeferCountMap();
|
|
1673
|
-
this.localLlm = new LocalLlmClient(config, this.modelRegistry);
|
|
1674
|
-
//
|
|
1675
|
-
//
|
|
1676
|
-
// nothing from chain-of-thought reasoning. Apply the operator's
|
|
1677
|
-
// configured preference (default true) so thinking-capable models
|
|
1678
|
-
// skip reasoning tokens and avoid the common 60s extraction
|
|
1679
|
-
// timeout. Operators can set `localLlmDisableThinking: false`
|
|
1680
|
-
// when they want thinking enabled for narrative paths.
|
|
1702
|
+
this.localLlm = new LocalLlmClient(config, this.modelRegistry, this.shutdownSignal);
|
|
1703
|
+
// Operator-controlled thinking suppression for structured-output ops;
|
|
1704
|
+
// full rationale on THINKING_SUPPRESSED_OPERATIONS in local-llm.ts (issue #548).
|
|
1681
1705
|
this.localLlm.disableThinking = config.localLlmDisableThinking;
|
|
1682
1706
|
this.fastLlm = resolvePipelineProcessingCapabilities(this.config).localLlmFast
|
|
1683
|
-
? (
|
|
1684
|
-
const client = new LocalLlmClient(
|
|
1685
|
-
{
|
|
1686
|
-
...config,
|
|
1687
|
-
localLlmModel: config.localLlmFastModel || config.localLlmModel,
|
|
1688
|
-
localLlmUrl: config.localLlmFastUrl,
|
|
1689
|
-
localLlmTimeoutMs: config.localLlmFastTimeoutMs,
|
|
1690
|
-
},
|
|
1691
|
-
this.modelRegistry,
|
|
1692
|
-
);
|
|
1693
|
-
// Fast-tier always suppresses thinking — the contract of
|
|
1694
|
-
// `fastLlm` is "low latency at all costs" and that is
|
|
1695
|
-
// independent of the main-client config.
|
|
1696
|
-
client.disableThinking = true;
|
|
1697
|
-
return client;
|
|
1698
|
-
})()
|
|
1707
|
+
? this.buildFastLlm(config)
|
|
1699
1708
|
: this.localLlm;
|
|
1700
1709
|
this.semanticConsolidationCoordinator = new SemanticConsolidationCoordinator({
|
|
1701
1710
|
config,
|
|
@@ -1714,11 +1723,7 @@ export class Orchestrator {
|
|
|
1714
1723
|
)
|
|
1715
1724
|
: null;
|
|
1716
1725
|
if (config.modelSource === "gateway") {
|
|
1717
|
-
log.debug(
|
|
1718
|
-
`orchestrator: gateway model source active` +
|
|
1719
|
-
(config.gatewayAgentId ? ` (primary: ${config.gatewayAgentId})` : "") +
|
|
1720
|
-
(config.fastGatewayAgentId ? ` (fast: ${config.fastGatewayAgentId})` : ""),
|
|
1721
|
-
);
|
|
1726
|
+
log.debug(`orchestrator: gateway model source active (primary: ${config.gatewayAgentId ?? "none"}, fast: ${config.fastGatewayAgentId ?? "none"})`);
|
|
1722
1727
|
}
|
|
1723
1728
|
this.extraction = new ExtractionEngine(
|
|
1724
1729
|
config,
|
|
@@ -1972,18 +1977,11 @@ export class Orchestrator {
|
|
|
1972
1977
|
};
|
|
1973
1978
|
}
|
|
1974
1979
|
|
|
1975
|
-
/**
|
|
1976
|
-
*
|
|
1977
|
-
* (gateway model source or local LLM). Returns `undefined` when no chain
|
|
1978
|
-
* is available so `buildBriefing` can surface a clear unavailable reason
|
|
1979
|
-
* instead of failing at call time. Used by the access service and CLI as
|
|
1980
|
-
* the fallback when no direct `openaiApiKey` is configured, so briefing
|
|
1981
|
-
* follow-ups ride the same routing as every other fast-tier LLM feature.
|
|
1982
|
-
*/
|
|
1980
|
+
/** Briefing follow-up generator over the configured LLM chain, or
|
|
1981
|
+
* `undefined` when no chain is available (see buildBriefing). */
|
|
1983
1982
|
get briefingChainFollowupGenerator(): BriefingFollowupGenerator | undefined {
|
|
1984
|
-
// Plugin mode gates on `localLlmEnabled` alone:
|
|
1985
|
-
//
|
|
1986
|
-
// itself cannot serve requests (Cursor review on PR #1463).
|
|
1983
|
+
// Plugin mode gates on `localLlmEnabled` alone: chatCompletion returns
|
|
1984
|
+
// null when the master switch is off (Cursor review on PR #1463).
|
|
1987
1985
|
const chainAvailable =
|
|
1988
1986
|
this.config.modelSource === "gateway"
|
|
1989
1987
|
? this._fastGatewayLlm?.isAvailable(
|
|
@@ -2116,20 +2114,19 @@ export class Orchestrator {
|
|
|
2116
2114
|
async runLiveConnectors(options: {
|
|
2117
2115
|
force?: boolean;
|
|
2118
2116
|
abortSignal?: AbortSignal;
|
|
2117
|
+
resolveSecretRef?: ResolveSecretRefFn | null;
|
|
2119
2118
|
} = {}): Promise<LiveConnectorsRunSummary> {
|
|
2120
2119
|
return runLiveConnectorsOnce({
|
|
2121
2120
|
memoryDir: this.config.memoryDir,
|
|
2122
2121
|
connectors: this.config.connectors,
|
|
2123
2122
|
force: options.force === true,
|
|
2124
2123
|
abortSignal: options.abortSignal,
|
|
2124
|
+
resolveSecretRef: options.resolveSecretRef,
|
|
2125
2125
|
ingestDocuments: async (docs) => {
|
|
2126
2126
|
const fetchedAt = new Date().toISOString();
|
|
2127
2127
|
const turns = docs.map((doc) => ({
|
|
2128
|
-
role: "assistant" as const,
|
|
2129
|
-
content: doc.title
|
|
2130
|
-
? `# ${doc.title}\n\n${doc.content}`
|
|
2131
|
-
: doc.content,
|
|
2132
|
-
timestamp: fetchedAt,
|
|
2128
|
+
role: "assistant" as const, timestamp: fetchedAt,
|
|
2129
|
+
content: doc.title ? `# ${doc.title}\n\n${doc.content}` : doc.content,
|
|
2133
2130
|
}));
|
|
2134
2131
|
await this.ingestBulkImportBatch(turns);
|
|
2135
2132
|
},
|