@remnic/core 10.0.69 → 10.0.71
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 +82 -79
- package/dist/access-authorization-probe.js +83 -80
- package/dist/access-boundary.js +82 -79
- package/dist/access-cli.js +196 -193
- package/dist/access-cli.js.map +1 -1
- package/dist/access-extraction-force-flush.js +82 -79
- package/dist/access-http-briefing.js +83 -80
- package/dist/access-http-query.js +84 -81
- package/dist/access-http.js +106 -103
- package/dist/access-identity-continuity-surface.js +82 -79
- package/dist/access-lcm-surface.js +82 -79
- package/dist/access-mcp.js +95 -92
- package/dist/access-namespace-preflight.js +82 -79
- package/dist/access-observe-lcm-archive.d.ts +5 -0
- package/dist/access-observe-lcm-archive.d.ts.map +1 -0
- package/dist/access-observe-lcm-archive.js +9 -0
- package/dist/access-observe-objective-state.d.ts +8 -0
- package/dist/access-observe-objective-state.d.ts.map +1 -0
- package/dist/access-observe-objective-state.js +17 -0
- package/dist/access-observe-stage-timing.d.ts +11 -0
- package/dist/access-observe-stage-timing.d.ts.map +1 -0
- package/dist/access-observe-stage-timing.js +9 -0
- package/dist/access-observe-stage-timing.js.map +1 -0
- package/dist/access-observe-write-category.js +13 -13
- package/dist/access-observe-write-surface.d.ts.map +1 -1
- package/dist/access-observe-write-surface.js +82 -79
- package/dist/access-offline-manifest.js +8 -8
- package/dist/access-operations-batch.js +85 -82
- package/dist/access-operations.js +92 -89
- package/dist/access-recall-concurrency.js +82 -79
- package/dist/access-recall-response.js +82 -79
- package/dist/access-recall-surface.js +82 -79
- package/dist/access-schema.js +12 -12
- package/dist/access-service.d.ts +1 -0
- package/dist/access-service.d.ts.map +1 -1
- package/dist/access-service.js +82 -79
- package/dist/access-surface-catalog.js +84 -81
- package/dist/access-surface-catalog.js.map +1 -1
- package/dist/active-recall.js +26 -26
- package/dist/adapters/index.js +4 -4
- package/dist/adapters/registry.js +2 -2
- package/dist/briefing.js +17 -17
- package/dist/buffer-turn-helpers.d.ts +10 -1
- package/dist/buffer-turn-helpers.d.ts.map +1 -1
- package/dist/buffer-turn-helpers.js +3 -1
- package/dist/buffer.d.ts +4 -0
- package/dist/buffer.d.ts.map +1 -1
- package/dist/buffer.js +9 -9
- package/dist/calibration.js +4 -4
- package/dist/{capsule-crypto-GWVG7LGC.js → capsule-crypto-7FJQINUR.js} +2 -2
- package/dist/capsule-crypto-7FJQINUR.js.map +1 -0
- package/dist/causal-behavior.js +2 -2
- package/dist/causal-chain.js +2 -2
- package/dist/causal-consolidation.js +22 -22
- package/dist/causal-retrieval.js +2 -2
- package/dist/causal-trajectory-graph.js +3 -3
- package/dist/causal-trajectory.js +1 -1
- package/dist/{chunk-6WKWL53V.js → chunk-23BA3USG.js} +128 -122
- package/dist/chunk-23BA3USG.js.map +1 -0
- package/dist/{chunk-OWHERGF2.js → chunk-2NLLXCJG.js} +2 -2
- package/dist/{chunk-CI3MAAIY.js → chunk-2R44BBPK.js} +2 -2
- package/dist/{chunk-QDZWQBLU.js → chunk-2R7OCBRR.js} +2 -2
- package/dist/{chunk-B3MWELZ3.js → chunk-2WPWEVAH.js} +2 -2
- package/dist/{chunk-PLCYKAWH.js → chunk-3ICAWZUU.js} +4 -4
- package/dist/{chunk-R4ZHF4K2.js → chunk-43FLJLT2.js} +4 -4
- package/dist/{chunk-PMDOGXA2.js → chunk-4PMFSYH7.js} +2 -2
- package/dist/{chunk-HXFIILGF.js → chunk-4RASUAN3.js} +4 -4
- package/dist/{chunk-EI6M5NVK.js → chunk-5JBVPJCT.js} +2 -2
- package/dist/{chunk-4NV7O76Q.js → chunk-5ORJHH43.js} +2 -2
- package/dist/{chunk-74AY3S7U.js → chunk-5RW247F5.js} +10 -10
- package/dist/{chunk-4XINO77L.js → chunk-66JOLMWS.js} +2 -2
- package/dist/{chunk-AYJQ644F.js → chunk-6KBCUIZP.js} +2 -2
- package/dist/{chunk-GKL6QYZO.js → chunk-6L63IN3M.js} +1 -1
- package/dist/{chunk-OPFVXM2D.js → chunk-7P5VBRBS.js} +2 -2
- package/dist/{chunk-4SOWMA55.js → chunk-7WFY2L5J.js} +3 -3
- package/dist/{chunk-GJ4HU6LK.js → chunk-AGRMXXVA.js} +2 -2
- package/dist/{chunk-KOLJJN5G.js → chunk-AQNHEDXP.js} +11 -4
- package/dist/chunk-AQNHEDXP.js.map +1 -0
- package/dist/{chunk-IVUVQPTQ.js → chunk-AZNE2H6D.js} +2 -2
- package/dist/{chunk-HPB5TF55.js → chunk-BCBY5GYZ.js} +3 -3
- package/dist/{chunk-M4IEZGCK.js → chunk-BFBS7OFQ.js} +7 -7
- package/dist/{chunk-4PG5R6BJ.js → chunk-BNU5TQLR.js} +2 -2
- package/dist/{chunk-TVE7W67N.js → chunk-BTU77RB5.js} +2 -2
- package/dist/{chunk-H6VJSITJ.js → chunk-CIL4GHMD.js} +3 -3
- package/dist/{chunk-KZZ5EZ7O.js → chunk-DC3DWF2M.js} +2 -2
- package/dist/{chunk-R2BIVU2Z.js → chunk-DE4U5PTV.js} +50 -46
- package/dist/chunk-DE4U5PTV.js.map +1 -0
- package/dist/{chunk-DDBB55L2.js → chunk-DSSTOV5M.js} +534 -361
- package/dist/chunk-DSSTOV5M.js.map +1 -0
- package/dist/{chunk-4MPAKYZU.js → chunk-EGKDONTC.js} +12 -6
- package/dist/chunk-EGKDONTC.js.map +1 -0
- package/dist/{chunk-AUFPPBC3.js → chunk-ENPJX3BB.js} +3 -3
- package/dist/{chunk-CTH2CQCB.js → chunk-EQ6EMJRG.js} +2 -2
- package/dist/{chunk-63A2BU2B.js → chunk-F4ZHKDBW.js} +5 -5
- package/dist/{chunk-3LBDEGQA.js → chunk-FDUCIUQ5.js} +2 -2
- package/dist/{chunk-OCK4D5PC.js → chunk-FGGLVCHI.js} +2 -2
- package/dist/{chunk-XVZA6VXC.js → chunk-FZVROZKC.js} +4 -4
- package/dist/{chunk-3RHU5MD7.js → chunk-GXAZ4Q2S.js} +2 -2
- package/dist/{chunk-UVVFPCPX.js → chunk-H2X32F2K.js} +2 -2
- package/dist/{chunk-645WOU5I.js → chunk-H7BZBSP6.js} +4 -4
- package/dist/{chunk-W7K5BP3M.js → chunk-HQPFACXO.js} +2 -2
- package/dist/{chunk-TECK5IVY.js → chunk-HZNURRDS.js} +2 -2
- package/dist/{chunk-U2CAGMUD.js → chunk-ICBUTKLL.js} +2 -2
- package/dist/{chunk-B4DXREWC.js → chunk-IQXQ3KWR.js} +2 -2
- package/dist/{chunk-AL3TCNSJ.js → chunk-J6GZ2254.js} +4 -4
- package/dist/{chunk-5MGKGEL7.js → chunk-J72ZY7NU.js} +2 -2
- package/dist/{chunk-OH55F76C.js → chunk-JEX2JL3U.js} +2 -2
- package/dist/{chunk-Y3XPSGNF.js → chunk-JGLZ46JS.js} +2 -2
- package/dist/{chunk-EXQJMFRF.js → chunk-JY4LXMZR.js} +2 -2
- package/dist/{chunk-6P7U3HWG.js → chunk-K36RMINQ.js} +3 -3
- package/dist/{chunk-BUKK5SWA.js → chunk-KQAFEZQX.js} +2 -2
- package/dist/{chunk-LN4X2NDA.js → chunk-KY3KJUNN.js} +10 -10
- package/dist/chunk-L3E7MLMK.js +20 -0
- package/dist/chunk-L3E7MLMK.js.map +1 -0
- package/dist/{chunk-H5DIRCZP.js → chunk-LHMCZ6VW.js} +18 -18
- package/dist/{chunk-GGD2YDS6.js → chunk-LN7CWLAU.js} +2 -2
- package/dist/{chunk-GHHQLSSY.js → chunk-LYOCAUI6.js} +3 -3
- package/dist/{chunk-VA3GNAWQ.js → chunk-LZIOY7ZU.js} +4 -5
- package/dist/chunk-LZIOY7ZU.js.map +1 -0
- package/dist/{chunk-W26D2USW.js → chunk-MUH7RR6T.js} +6 -6
- package/dist/{chunk-IAGVM7EY.js → chunk-N2Y6COEM.js} +2 -2
- package/dist/{chunk-64JLBFCQ.js → chunk-N7NAGECH.js} +2 -2
- package/dist/{chunk-5Y6VA6X2.js → chunk-OGQGDOYK.js} +2 -2
- package/dist/{chunk-U7MIMS2Y.js → chunk-OUBEJWVI.js} +17 -1
- package/dist/chunk-OUBEJWVI.js.map +1 -0
- package/dist/{chunk-JLMOH5JA.js → chunk-OWZXDBV4.js} +2 -2
- package/dist/{chunk-ZORS5BG5.js → chunk-PJAMFIDE.js} +10 -10
- package/dist/chunk-QCFZDYYG.js +34 -0
- package/dist/chunk-QCFZDYYG.js.map +1 -0
- package/dist/{chunk-SXTVZ6JL.js → chunk-QIOQI7QZ.js} +2 -2
- package/dist/{chunk-MMCO4SRG.js → chunk-QNN4FYBD.js} +19 -11
- package/dist/chunk-QNN4FYBD.js.map +1 -0
- package/dist/{chunk-75DCOS6I.js → chunk-QUPTDKSX.js} +67 -67
- package/dist/{chunk-HH73M65H.js → chunk-QVZZE6VH.js} +3 -3
- package/dist/{chunk-XWE3EOWX.js → chunk-RZED7FAU.js} +2 -2
- package/dist/{chunk-IZBIDPMY.js → chunk-S37O4S6E.js} +2 -2
- package/dist/{chunk-NHWDTOBN.js → chunk-S73ZVU37.js} +21 -21
- package/dist/{chunk-YSATDEBY.js → chunk-SBRUTD5O.js} +5 -5
- package/dist/{chunk-WVP2I6C5.js → chunk-SDL22RRW.js} +50 -11
- package/dist/chunk-SDL22RRW.js.map +1 -0
- package/dist/{chunk-PRKNAIGZ.js → chunk-T6T2RMWW.js} +5 -5
- package/dist/{chunk-CIEEYVUB.js → chunk-TPX7XXY4.js} +2 -2
- package/dist/{chunk-L334PSLW.js → chunk-U2A56LLF.js} +8 -8
- package/dist/{chunk-P4TV3TQ2.js → chunk-U6IL4724.js} +5 -5
- package/dist/{chunk-5UM4H64E.js → chunk-UAOJVQXC.js} +2 -2
- package/dist/{chunk-MOIJWWNA.js → chunk-UE5JYPU6.js} +13 -13
- package/dist/{chunk-TGQW3AMK.js → chunk-UIFWZMO7.js} +23 -23
- package/dist/{chunk-UW6LBFYN.js → chunk-USX5YIKB.js} +6 -6
- package/dist/{chunk-QGFR73SN.js → chunk-VK5HKVQ7.js} +2 -2
- package/dist/{chunk-ZOBYTRBU.js → chunk-VNTQU6KB.js} +47 -2
- package/dist/chunk-VNTQU6KB.js.map +1 -0
- package/dist/{chunk-IHCXMYSE.js → chunk-VPEIWMUT.js} +2 -2
- package/dist/{chunk-O5ZINWW3.js → chunk-VSJ3ARFS.js} +2 -2
- package/dist/{chunk-RLVI2M5Q.js → chunk-W4V7P5HP.js} +2 -2
- package/dist/{chunk-ELHJK7LM.js → chunk-WBN66HPI.js} +6 -6
- package/dist/{chunk-BJLCV2P3.js → chunk-WGRAB3KB.js} +2 -2
- package/dist/{chunk-5KDDAQ6K.js → chunk-WN2DASTS.js} +10 -10
- package/dist/{chunk-IG3EZ3TF.js → chunk-WNQ3B3Q5.js} +2 -2
- package/dist/{chunk-V6SBA5O7.js → chunk-WYOHQJKC.js} +7 -7
- package/dist/chunk-WZU5AGO6.js +38 -0
- package/dist/chunk-WZU5AGO6.js.map +1 -0
- package/dist/{chunk-WHROVQ5Q.js → chunk-X4DHAXFO.js} +3 -3
- package/dist/{chunk-UVYI6VIX.js → chunk-X7Y7WX73.js} +1 -1
- package/dist/{chunk-JLGBJ4AX.js → chunk-XPZM7GP6.js} +10 -10
- package/dist/{chunk-64S6X4IU.js → chunk-XTN54NML.js} +4 -4
- package/dist/{chunk-UYUFDTIX.js → chunk-YIXWY4OZ.js} +2 -2
- package/dist/{chunk-NCZGGGWI.js → chunk-YPYSC3TX.js} +12 -12
- package/dist/{chunk-AVGDYYMA.js → chunk-ZBET3W26.js} +3 -3
- package/dist/{chunk-Y7427SL7.js → chunk-ZG4GNPRE.js} +216 -50
- package/dist/chunk-ZG4GNPRE.js.map +1 -0
- package/dist/chunk-ZODKV27J.js +443 -0
- package/dist/chunk-ZODKV27J.js.map +1 -0
- package/dist/cli.js +133 -130
- package/dist/coding/export-okf-codegraph.js +16 -16
- package/dist/coding/pre-action-gate.js +2 -2
- package/dist/compounding/engine.js +18 -18
- package/dist/config.js +26 -26
- package/dist/connectors/codex-materialize-runner.js +19 -19
- package/dist/connectors/codex-materialize.js +2 -2
- package/dist/connectors/index.js +20 -20
- package/dist/consolidation-provenance-check.js +2 -2
- package/dist/convergence-refresh.js +20 -20
- package/dist/corpus-watermark.js +20 -20
- package/dist/deep-recall-http-glue.js +13 -13
- package/dist/deep-recall.js +2 -2
- package/dist/embedding-fallback.js +2 -2
- package/dist/entity-retrieval.js +20 -20
- package/dist/event-order-recall.js +2 -2
- package/dist/external-wiki-access.js +83 -80
- package/dist/extraction-span-materialize.js +2 -2
- package/dist/extraction-window-drain.d.ts.map +1 -1
- package/dist/extraction-window-drain.js +1 -1
- package/dist/extraction.js +32 -32
- package/dist/{graph-edge-decay-OEX5OGMI.js → graph-edge-decay-CXTNJ7IQ.js} +6 -6
- package/dist/graph-edge-decay-CXTNJ7IQ.js.map +1 -0
- package/dist/graph-jsonl.js +4 -4
- package/dist/graph-snapshot.js +4 -4
- package/dist/graph.js +3 -3
- package/dist/harmonic-retrieval.js +17 -17
- package/dist/index.js +281 -278
- package/dist/lcm/archive.d.ts +12 -2
- package/dist/lcm/archive.d.ts.map +1 -1
- package/dist/lcm/archive.js +2 -2
- package/dist/lcm/engine.d.ts +59 -8
- package/dist/lcm/engine.d.ts.map +1 -1
- package/dist/lcm/engine.js +6 -6
- package/dist/lcm/index.js +16 -16
- package/dist/lcm/queue.d.ts +7 -3
- package/dist/lcm/queue.d.ts.map +1 -1
- package/dist/lcm/queue.js +1 -1
- package/dist/lcm/summarizer.d.ts +8 -1
- package/dist/lcm/summarizer.d.ts.map +1 -1
- package/dist/lcm/summarizer.js +3 -3
- package/dist/local-llm.js +4 -4
- package/dist/location/index.js +19 -19
- package/dist/maintenance/memory-governance.js +18 -18
- package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +17 -17
- package/dist/maintenance/rebuild-memory-projection-runner.js +20 -20
- package/dist/maintenance/rebuild-memory-projection.js +19 -19
- package/dist/memory-browse-operations.js +83 -80
- package/dist/memory-browse.js +6 -6
- package/dist/namespaces/migrate.js +18 -18
- package/dist/namespaces/search.js +7 -7
- package/dist/namespaces/storage.js +17 -17
- package/dist/offline-sync-changeset-generations.js +5 -5
- package/dist/offline-sync-embedding-generation.js +4 -4
- package/dist/offline-sync-snapshot-stream.js +7 -7
- package/dist/offline-sync.js +9 -9
- package/dist/operator-doctor-corpus.js +21 -21
- package/dist/operator-toolkit.js +41 -41
- package/dist/orchestration/backlog-scheduler.d.ts +151 -0
- package/dist/orchestration/backlog-scheduler.d.ts.map +1 -0
- package/dist/orchestration/backlog-scheduler.js +891 -0
- package/dist/orchestration/backlog-scheduler.js.map +1 -0
- package/dist/orchestration/buffer-drain-runner.d.ts +31 -27
- package/dist/orchestration/buffer-drain-runner.d.ts.map +1 -1
- package/dist/orchestration/buffer-drain-runner.js +202 -404
- package/dist/orchestration/buffer-drain-runner.js.map +1 -1
- package/dist/orchestration/extraction-drain.d.ts +50 -17
- package/dist/orchestration/extraction-drain.d.ts.map +1 -1
- package/dist/orchestration/extraction-queue-coordinator.d.ts +19 -1
- package/dist/orchestration/extraction-queue-coordinator.d.ts.map +1 -1
- package/dist/orchestration/extraction-run.d.ts +8 -0
- package/dist/orchestration/extraction-run.d.ts.map +1 -1
- package/dist/orchestration/extraction-task-queueing.d.ts +44 -0
- package/dist/orchestration/extraction-task-queueing.d.ts.map +1 -0
- package/dist/orchestration/maintenance.js +33 -33
- package/dist/orchestration/turn-ingestion.d.ts +11 -5
- package/dist/orchestration/turn-ingestion.d.ts.map +1 -1
- package/dist/orchestrator.d.ts +13 -0
- package/dist/orchestrator.d.ts.map +1 -1
- package/dist/orchestrator.js +196 -193
- package/dist/qmd.js +4 -4
- package/dist/recall-navigation-operations.js +83 -80
- package/dist/recall-navigation.js +82 -79
- package/dist/recall-state-view-admission.js +6 -6
- package/dist/recall-why-service.js +6 -6
- package/dist/resume-bundles.js +29 -29
- package/dist/search/factory.js +6 -6
- package/dist/search/index.js +12 -12
- package/dist/semantic-consolidation.js +25 -25
- package/dist/semantic-rule-promotion.js +17 -17
- package/dist/semantic-rule-verifier.js +17 -17
- package/dist/source-agent-qualifier.js +24 -24
- package/dist/standup/build.js +17 -17
- package/dist/storage/buffer-drain-claims.d.ts +15 -0
- package/dist/storage/buffer-drain-claims.d.ts.map +1 -1
- package/dist/storage/buffer-drain-claims.js +2 -2
- package/dist/storage/buffer-session-files.js +2 -2
- package/dist/storage.js +16 -16
- package/dist/summarizer.js +6 -6
- package/dist/support-passport/index.js +85 -82
- 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-okf.js +17 -17
- package/dist/verified-recall.js +17 -17
- package/dist/who-knows-cli.js +18 -18
- package/dist/who-knows.js +17 -17
- package/package.json +12 -2
- package/src/access-observe-lcm-archive.ts +30 -0
- package/src/access-observe-lcm-fail-closed.test.ts +118 -0
- package/src/access-observe-objective-state.ts +40 -0
- package/src/access-observe-stage-timing.test.ts +246 -0
- package/src/access-observe-stage-timing.ts +58 -0
- package/src/access-observe-write-surface.ts +45 -45
- package/src/access-service.ts +1 -0
- package/src/backlog-scheduler.test.ts +806 -0
- package/src/buffer-drain-handover.test.ts +363 -18
- package/src/buffer-drain-inprocess.test.ts +355 -0
- package/src/buffer-drain-model-boundary.test.ts +1062 -0
- package/src/buffer-drop-extraction-chunk.test.ts +237 -22
- package/src/buffer-turn-helpers.ts +26 -1
- package/src/buffer.ts +8 -0
- package/src/extraction-window-drain.ts +7 -7
- package/src/lcm/archive.ts +59 -7
- package/src/lcm/engine.ts +256 -53
- package/src/lcm/queue.test.ts +32 -14
- package/src/lcm/queue.ts +24 -16
- package/src/lcm/summarizer.ts +15 -2
- package/src/lcm-durability.test.ts +856 -0
- package/src/lcm-engine.test.ts +12 -3
- package/src/orchestration/backlog-scheduler.ts +481 -0
- package/src/orchestration/buffer-drain-runner.ts +545 -180
- package/src/orchestration/extraction-drain.ts +287 -108
- package/src/orchestration/extraction-queue-coordinator.ts +51 -3
- package/src/orchestration/extraction-run.test.ts +41 -0
- package/src/orchestration/extraction-run.ts +24 -5
- package/src/orchestration/extraction-task-queueing.ts +87 -0
- package/src/orchestration/turn-ingestion.ts +46 -59
- package/src/orchestrator-extraction-queue.test.ts +46 -2
- package/src/orchestrator-flush.test.ts +4 -1
- package/src/orchestrator.ts +47 -21
- package/src/storage/buffer-drain-claims.ts +55 -0
- package/dist/chunk-4MPAKYZU.js.map +0 -1
- package/dist/chunk-6WKWL53V.js.map +0 -1
- package/dist/chunk-DDBB55L2.js.map +0 -1
- package/dist/chunk-KOLJJN5G.js.map +0 -1
- package/dist/chunk-MMCO4SRG.js.map +0 -1
- package/dist/chunk-R2BIVU2Z.js.map +0 -1
- package/dist/chunk-U7MIMS2Y.js.map +0 -1
- package/dist/chunk-VA3GNAWQ.js.map +0 -1
- package/dist/chunk-WVP2I6C5.js.map +0 -1
- package/dist/chunk-Y7427SL7.js.map +0 -1
- package/dist/chunk-ZOBYTRBU.js.map +0 -1
- /package/dist/{capsule-crypto-GWVG7LGC.js.map → access-observe-lcm-archive.js.map} +0 -0
- /package/dist/{graph-edge-decay-OEX5OGMI.js.map → access-observe-objective-state.js.map} +0 -0
- /package/dist/{chunk-OWHERGF2.js.map → chunk-2NLLXCJG.js.map} +0 -0
- /package/dist/{chunk-CI3MAAIY.js.map → chunk-2R44BBPK.js.map} +0 -0
- /package/dist/{chunk-QDZWQBLU.js.map → chunk-2R7OCBRR.js.map} +0 -0
- /package/dist/{chunk-B3MWELZ3.js.map → chunk-2WPWEVAH.js.map} +0 -0
- /package/dist/{chunk-PLCYKAWH.js.map → chunk-3ICAWZUU.js.map} +0 -0
- /package/dist/{chunk-R4ZHF4K2.js.map → chunk-43FLJLT2.js.map} +0 -0
- /package/dist/{chunk-PMDOGXA2.js.map → chunk-4PMFSYH7.js.map} +0 -0
- /package/dist/{chunk-HXFIILGF.js.map → chunk-4RASUAN3.js.map} +0 -0
- /package/dist/{chunk-EI6M5NVK.js.map → chunk-5JBVPJCT.js.map} +0 -0
- /package/dist/{chunk-4NV7O76Q.js.map → chunk-5ORJHH43.js.map} +0 -0
- /package/dist/{chunk-74AY3S7U.js.map → chunk-5RW247F5.js.map} +0 -0
- /package/dist/{chunk-4XINO77L.js.map → chunk-66JOLMWS.js.map} +0 -0
- /package/dist/{chunk-AYJQ644F.js.map → chunk-6KBCUIZP.js.map} +0 -0
- /package/dist/{chunk-GKL6QYZO.js.map → chunk-6L63IN3M.js.map} +0 -0
- /package/dist/{chunk-OPFVXM2D.js.map → chunk-7P5VBRBS.js.map} +0 -0
- /package/dist/{chunk-4SOWMA55.js.map → chunk-7WFY2L5J.js.map} +0 -0
- /package/dist/{chunk-GJ4HU6LK.js.map → chunk-AGRMXXVA.js.map} +0 -0
- /package/dist/{chunk-IVUVQPTQ.js.map → chunk-AZNE2H6D.js.map} +0 -0
- /package/dist/{chunk-HPB5TF55.js.map → chunk-BCBY5GYZ.js.map} +0 -0
- /package/dist/{chunk-M4IEZGCK.js.map → chunk-BFBS7OFQ.js.map} +0 -0
- /package/dist/{chunk-4PG5R6BJ.js.map → chunk-BNU5TQLR.js.map} +0 -0
- /package/dist/{chunk-TVE7W67N.js.map → chunk-BTU77RB5.js.map} +0 -0
- /package/dist/{chunk-H6VJSITJ.js.map → chunk-CIL4GHMD.js.map} +0 -0
- /package/dist/{chunk-KZZ5EZ7O.js.map → chunk-DC3DWF2M.js.map} +0 -0
- /package/dist/{chunk-AUFPPBC3.js.map → chunk-ENPJX3BB.js.map} +0 -0
- /package/dist/{chunk-CTH2CQCB.js.map → chunk-EQ6EMJRG.js.map} +0 -0
- /package/dist/{chunk-63A2BU2B.js.map → chunk-F4ZHKDBW.js.map} +0 -0
- /package/dist/{chunk-3LBDEGQA.js.map → chunk-FDUCIUQ5.js.map} +0 -0
- /package/dist/{chunk-OCK4D5PC.js.map → chunk-FGGLVCHI.js.map} +0 -0
- /package/dist/{chunk-XVZA6VXC.js.map → chunk-FZVROZKC.js.map} +0 -0
- /package/dist/{chunk-3RHU5MD7.js.map → chunk-GXAZ4Q2S.js.map} +0 -0
- /package/dist/{chunk-UVVFPCPX.js.map → chunk-H2X32F2K.js.map} +0 -0
- /package/dist/{chunk-645WOU5I.js.map → chunk-H7BZBSP6.js.map} +0 -0
- /package/dist/{chunk-W7K5BP3M.js.map → chunk-HQPFACXO.js.map} +0 -0
- /package/dist/{chunk-TECK5IVY.js.map → chunk-HZNURRDS.js.map} +0 -0
- /package/dist/{chunk-U2CAGMUD.js.map → chunk-ICBUTKLL.js.map} +0 -0
- /package/dist/{chunk-B4DXREWC.js.map → chunk-IQXQ3KWR.js.map} +0 -0
- /package/dist/{chunk-AL3TCNSJ.js.map → chunk-J6GZ2254.js.map} +0 -0
- /package/dist/{chunk-5MGKGEL7.js.map → chunk-J72ZY7NU.js.map} +0 -0
- /package/dist/{chunk-OH55F76C.js.map → chunk-JEX2JL3U.js.map} +0 -0
- /package/dist/{chunk-Y3XPSGNF.js.map → chunk-JGLZ46JS.js.map} +0 -0
- /package/dist/{chunk-EXQJMFRF.js.map → chunk-JY4LXMZR.js.map} +0 -0
- /package/dist/{chunk-6P7U3HWG.js.map → chunk-K36RMINQ.js.map} +0 -0
- /package/dist/{chunk-BUKK5SWA.js.map → chunk-KQAFEZQX.js.map} +0 -0
- /package/dist/{chunk-LN4X2NDA.js.map → chunk-KY3KJUNN.js.map} +0 -0
- /package/dist/{chunk-H5DIRCZP.js.map → chunk-LHMCZ6VW.js.map} +0 -0
- /package/dist/{chunk-GGD2YDS6.js.map → chunk-LN7CWLAU.js.map} +0 -0
- /package/dist/{chunk-GHHQLSSY.js.map → chunk-LYOCAUI6.js.map} +0 -0
- /package/dist/{chunk-W26D2USW.js.map → chunk-MUH7RR6T.js.map} +0 -0
- /package/dist/{chunk-IAGVM7EY.js.map → chunk-N2Y6COEM.js.map} +0 -0
- /package/dist/{chunk-64JLBFCQ.js.map → chunk-N7NAGECH.js.map} +0 -0
- /package/dist/{chunk-5Y6VA6X2.js.map → chunk-OGQGDOYK.js.map} +0 -0
- /package/dist/{chunk-JLMOH5JA.js.map → chunk-OWZXDBV4.js.map} +0 -0
- /package/dist/{chunk-ZORS5BG5.js.map → chunk-PJAMFIDE.js.map} +0 -0
- /package/dist/{chunk-SXTVZ6JL.js.map → chunk-QIOQI7QZ.js.map} +0 -0
- /package/dist/{chunk-75DCOS6I.js.map → chunk-QUPTDKSX.js.map} +0 -0
- /package/dist/{chunk-HH73M65H.js.map → chunk-QVZZE6VH.js.map} +0 -0
- /package/dist/{chunk-XWE3EOWX.js.map → chunk-RZED7FAU.js.map} +0 -0
- /package/dist/{chunk-IZBIDPMY.js.map → chunk-S37O4S6E.js.map} +0 -0
- /package/dist/{chunk-NHWDTOBN.js.map → chunk-S73ZVU37.js.map} +0 -0
- /package/dist/{chunk-YSATDEBY.js.map → chunk-SBRUTD5O.js.map} +0 -0
- /package/dist/{chunk-PRKNAIGZ.js.map → chunk-T6T2RMWW.js.map} +0 -0
- /package/dist/{chunk-CIEEYVUB.js.map → chunk-TPX7XXY4.js.map} +0 -0
- /package/dist/{chunk-L334PSLW.js.map → chunk-U2A56LLF.js.map} +0 -0
- /package/dist/{chunk-P4TV3TQ2.js.map → chunk-U6IL4724.js.map} +0 -0
- /package/dist/{chunk-5UM4H64E.js.map → chunk-UAOJVQXC.js.map} +0 -0
- /package/dist/{chunk-MOIJWWNA.js.map → chunk-UE5JYPU6.js.map} +0 -0
- /package/dist/{chunk-TGQW3AMK.js.map → chunk-UIFWZMO7.js.map} +0 -0
- /package/dist/{chunk-UW6LBFYN.js.map → chunk-USX5YIKB.js.map} +0 -0
- /package/dist/{chunk-QGFR73SN.js.map → chunk-VK5HKVQ7.js.map} +0 -0
- /package/dist/{chunk-IHCXMYSE.js.map → chunk-VPEIWMUT.js.map} +0 -0
- /package/dist/{chunk-O5ZINWW3.js.map → chunk-VSJ3ARFS.js.map} +0 -0
- /package/dist/{chunk-RLVI2M5Q.js.map → chunk-W4V7P5HP.js.map} +0 -0
- /package/dist/{chunk-ELHJK7LM.js.map → chunk-WBN66HPI.js.map} +0 -0
- /package/dist/{chunk-BJLCV2P3.js.map → chunk-WGRAB3KB.js.map} +0 -0
- /package/dist/{chunk-5KDDAQ6K.js.map → chunk-WN2DASTS.js.map} +0 -0
- /package/dist/{chunk-IG3EZ3TF.js.map → chunk-WNQ3B3Q5.js.map} +0 -0
- /package/dist/{chunk-V6SBA5O7.js.map → chunk-WYOHQJKC.js.map} +0 -0
- /package/dist/{chunk-WHROVQ5Q.js.map → chunk-X4DHAXFO.js.map} +0 -0
- /package/dist/{chunk-UVYI6VIX.js.map → chunk-X7Y7WX73.js.map} +0 -0
- /package/dist/{chunk-JLGBJ4AX.js.map → chunk-XPZM7GP6.js.map} +0 -0
- /package/dist/{chunk-64S6X4IU.js.map → chunk-XTN54NML.js.map} +0 -0
- /package/dist/{chunk-UYUFDTIX.js.map → chunk-YIXWY4OZ.js.map} +0 -0
- /package/dist/{chunk-NCZGGGWI.js.map → chunk-YPYSC3TX.js.map} +0 -0
- /package/dist/{chunk-AVGDYYMA.js.map → chunk-ZBET3W26.js.map} +0 -0
|
@@ -0,0 +1,443 @@
|
|
|
1
|
+
import {
|
|
2
|
+
ExtractionDrain,
|
|
3
|
+
TurnIngestionCoordinator
|
|
4
|
+
} from "./chunk-DSSTOV5M.js";
|
|
5
|
+
import {
|
|
6
|
+
headerConnector,
|
|
7
|
+
renderExtractionConversation,
|
|
8
|
+
resolveSourceConnector
|
|
9
|
+
} from "./chunk-EQ6EMJRG.js";
|
|
10
|
+
import {
|
|
11
|
+
SmartBuffer
|
|
12
|
+
} from "./chunk-EGKDONTC.js";
|
|
13
|
+
import {
|
|
14
|
+
shouldSkipImplicitExtraction
|
|
15
|
+
} from "./chunk-RZH5RVJC.js";
|
|
16
|
+
import {
|
|
17
|
+
selfDeps
|
|
18
|
+
} from "./chunk-S73ZVU37.js";
|
|
19
|
+
import {
|
|
20
|
+
describeError,
|
|
21
|
+
groupTurnsByExtractionScope
|
|
22
|
+
} from "./chunk-OUBEJWVI.js";
|
|
23
|
+
import {
|
|
24
|
+
resolveMemoryLifecycleCapabilities
|
|
25
|
+
} from "./chunk-C5LWPYS3.js";
|
|
26
|
+
import {
|
|
27
|
+
log
|
|
28
|
+
} from "./chunk-3WCASNQZ.js";
|
|
29
|
+
|
|
30
|
+
// src/orchestration/buffer-drain-runner.ts
|
|
31
|
+
import { hostname } from "os";
|
|
32
|
+
var DENIED_SCOPE_REASONS = /* @__PURE__ */ new Set([
|
|
33
|
+
"pinned_namespace_unavailable",
|
|
34
|
+
"namespace_write_revoked",
|
|
35
|
+
"scope_profile_revoked",
|
|
36
|
+
// The resolved profile has no writable layer: the same current-policy
|
|
37
|
+
// refusal family, surfaced from inside the shared runExtraction gate.
|
|
38
|
+
"scope_profile_no_writable_layer",
|
|
39
|
+
// captureMode=explicit: ordinary buffered conversation turns never create
|
|
40
|
+
// memories; only deliberately accepted captures drain.
|
|
41
|
+
"capture_mode_explicit"
|
|
42
|
+
]);
|
|
43
|
+
var DEFAULT_LEASE_MS = 12e4;
|
|
44
|
+
var ClaimBufferStorage = class {
|
|
45
|
+
constructor(claims, key, ownerId, entry) {
|
|
46
|
+
this.claims = claims;
|
|
47
|
+
this.key = key;
|
|
48
|
+
this.ownerId = ownerId;
|
|
49
|
+
this.entry = entry;
|
|
50
|
+
}
|
|
51
|
+
claims;
|
|
52
|
+
key;
|
|
53
|
+
ownerId;
|
|
54
|
+
entry;
|
|
55
|
+
async loadBuffer() {
|
|
56
|
+
const entries = /* @__PURE__ */ Object.create(null);
|
|
57
|
+
entries[this.key] = {
|
|
58
|
+
turns: this.entry.turns,
|
|
59
|
+
retainedTurns: this.entry.retainedTurns,
|
|
60
|
+
lastExtractionAt: this.entry.lastExtractionAt,
|
|
61
|
+
extractionCount: this.entry.extractionCount
|
|
62
|
+
};
|
|
63
|
+
return {
|
|
64
|
+
turns: this.entry.turns,
|
|
65
|
+
lastExtractionAt: this.entry.lastExtractionAt,
|
|
66
|
+
extractionCount: this.entry.extractionCount,
|
|
67
|
+
entries
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
async saveBuffer(state) {
|
|
71
|
+
const entry = state.entries?.[this.key];
|
|
72
|
+
await this.claims.writeEntry(
|
|
73
|
+
this.key,
|
|
74
|
+
this.ownerId,
|
|
75
|
+
entry ?? { turns: [], lastExtractionAt: null, extractionCount: 0 },
|
|
76
|
+
this.entry
|
|
77
|
+
);
|
|
78
|
+
}
|
|
79
|
+
async saveBufferSession(key, entry) {
|
|
80
|
+
await this.claims.writeEntry(key, this.ownerId, entry, key === this.key ? this.entry : void 0);
|
|
81
|
+
}
|
|
82
|
+
async deleteBufferSession() {
|
|
83
|
+
}
|
|
84
|
+
};
|
|
85
|
+
function pendingTurnCount(entry) {
|
|
86
|
+
if (!entry) return 0;
|
|
87
|
+
return entry.turns.length + (entry.retainedTurns?.length ?? 0);
|
|
88
|
+
}
|
|
89
|
+
async function loadClaimedSession(claims, key) {
|
|
90
|
+
const claim = await claims.load(key);
|
|
91
|
+
if (!claim) {
|
|
92
|
+
return {
|
|
93
|
+
kind: "notClaimed",
|
|
94
|
+
notClaimed: {
|
|
95
|
+
key,
|
|
96
|
+
status: "skipped",
|
|
97
|
+
turnsAtStart: 0,
|
|
98
|
+
turnsRemaining: 0,
|
|
99
|
+
persistedCount: 0,
|
|
100
|
+
durableOutputCount: 0,
|
|
101
|
+
reason: "not_claimed"
|
|
102
|
+
}
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
return { kind: "claimed", claim, turnsAtStart: pendingTurnCount(claim.entry) };
|
|
106
|
+
}
|
|
107
|
+
function busyLeaseOutcome(key, turnsAtStart) {
|
|
108
|
+
return {
|
|
109
|
+
key,
|
|
110
|
+
status: "skipped",
|
|
111
|
+
turnsAtStart,
|
|
112
|
+
turnsRemaining: turnsAtStart,
|
|
113
|
+
persistedCount: 0,
|
|
114
|
+
durableOutputCount: 0,
|
|
115
|
+
reason: "claimed_by_another_drain"
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
async function adoptLease(claims, key, ownerId, leaseMs) {
|
|
119
|
+
const held = await claims.adopt(key, {
|
|
120
|
+
ownerId,
|
|
121
|
+
pid: process.pid,
|
|
122
|
+
host: hostname(),
|
|
123
|
+
acquiredAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
124
|
+
heartbeatAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
125
|
+
leaseMs
|
|
126
|
+
});
|
|
127
|
+
return held === "busy" ? busyLeaseOutcome(key, pendingTurnCount((await claims.load(key))?.entry)) : null;
|
|
128
|
+
}
|
|
129
|
+
function assembleOutcome(key, turnsAtStart, verdict, counts, denied) {
|
|
130
|
+
const outcome = {
|
|
131
|
+
key,
|
|
132
|
+
status: verdict.status,
|
|
133
|
+
turnsAtStart,
|
|
134
|
+
turnsRemaining: verdict.turnsRemaining,
|
|
135
|
+
persistedCount: counts.persistedCount,
|
|
136
|
+
durableOutputCount: counts.durableOutputCount
|
|
137
|
+
};
|
|
138
|
+
if (denied.size > 0) outcome.denied = [...denied].map(([deniedReason, turns]) => ({ reason: deniedReason, turns }));
|
|
139
|
+
if (verdict.reason !== void 0) outcome.reason = verdict.reason;
|
|
140
|
+
return outcome;
|
|
141
|
+
}
|
|
142
|
+
async function ackEmptyClaim(claims, key, ownerId, turnsAtStart) {
|
|
143
|
+
const ackOutcome = await claims.ack(key, ownerId);
|
|
144
|
+
if (ackOutcome !== "acked") {
|
|
145
|
+
const reloaded = await claims.load(key);
|
|
146
|
+
const turnsRemaining = pendingTurnCount(reloaded?.entry);
|
|
147
|
+
await claims.releaseLease(key, ownerId);
|
|
148
|
+
return {
|
|
149
|
+
key,
|
|
150
|
+
status: "deferred",
|
|
151
|
+
turnsAtStart,
|
|
152
|
+
turnsRemaining,
|
|
153
|
+
persistedCount: 0,
|
|
154
|
+
durableOutputCount: 0,
|
|
155
|
+
reason: ackOutcome === "not_empty" ? "ack_not_empty" : "ack_not_owner"
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
return { key, status: "drained", turnsAtStart, turnsRemaining: 0, persistedCount: 0, durableOutputCount: 0 };
|
|
159
|
+
}
|
|
160
|
+
function startLeaseHeartbeat(claims, key, ownerId, leaseMs, abort) {
|
|
161
|
+
const heartbeat = setInterval(
|
|
162
|
+
() => {
|
|
163
|
+
void claims.heartbeat(key, ownerId, leaseMs).then((state) => {
|
|
164
|
+
if (state === "lost") abort.abort(new Error(`buffer drain: lease lost for session ${key}`));
|
|
165
|
+
}).catch((err) => {
|
|
166
|
+
abort.abort(new Error(`buffer drain: lease heartbeat failed for session ${key}: ${describeError(err)}`));
|
|
167
|
+
});
|
|
168
|
+
},
|
|
169
|
+
Math.max(1e3, Math.floor(leaseMs / 3))
|
|
170
|
+
);
|
|
171
|
+
heartbeat.unref?.();
|
|
172
|
+
return heartbeat;
|
|
173
|
+
}
|
|
174
|
+
function buildClaimExecution(orchestrator, claims, key, ownerId, claim) {
|
|
175
|
+
const claimBuffer = new SmartBuffer(orchestrator.config, new ClaimBufferStorage(claims, key, ownerId, claim.entry));
|
|
176
|
+
const isolatedRun = orchestrator.extractionRunCoordinatorForBuffer(claimBuffer);
|
|
177
|
+
const coordinator = new TurnIngestionCoordinator(selfDeps(orchestrator));
|
|
178
|
+
const config = orchestrator.config;
|
|
179
|
+
const ingestionDeps = selfDeps(orchestrator);
|
|
180
|
+
const executionDrain = new ExtractionDrain(
|
|
181
|
+
{
|
|
182
|
+
config: {
|
|
183
|
+
extractionMinUserTurns: config.extractionMinUserTurns,
|
|
184
|
+
extractionMinChars: config.extractionMinChars,
|
|
185
|
+
extractionMaxTurnChars: config.extractionMaxTurnChars,
|
|
186
|
+
extractionChunkDropAfterFailures: config.extractionChunkDropAfterFailures
|
|
187
|
+
},
|
|
188
|
+
extractionWindowBudgetChars: () => ingestionDeps.extractionWindowBudgetChars?.() ?? Number.POSITIVE_INFINITY,
|
|
189
|
+
// Render-exact chunk sizing: the model clamp bounds the CONVERSATION
|
|
190
|
+
// (truncateLocalExtractionConversation), so measure exactly that —
|
|
191
|
+
// with the SAME source-classification gate extract() applies when it
|
|
192
|
+
// prepends the connector header (header margin included when the
|
|
193
|
+
// engine would render it).
|
|
194
|
+
measureRenderedTurns: (turns) => {
|
|
195
|
+
const sourceConnector = resolveMemoryLifecycleCapabilities(config).extractionScopeClassification ? resolveSourceConnector(turns) : void 0;
|
|
196
|
+
return renderExtractionConversation(
|
|
197
|
+
turns.map((turn) => ({ ...turn, content: turn.content.trim().slice(0, config.extractionMaxTurnChars) })),
|
|
198
|
+
headerConnector(sourceConnector)
|
|
199
|
+
).conversation.length;
|
|
200
|
+
},
|
|
201
|
+
runExtraction: (turns, runOptions) => isolatedRun.runExtraction(turns, runOptions),
|
|
202
|
+
getStorage: () => ingestionDeps.getStorage(),
|
|
203
|
+
buffer: claimBuffer
|
|
204
|
+
},
|
|
205
|
+
{ dropFailedChunks: false }
|
|
206
|
+
);
|
|
207
|
+
return { claimBuffer, coordinator, executionDrain };
|
|
208
|
+
}
|
|
209
|
+
function planOptionForGroup(group) {
|
|
210
|
+
if (group.scopeProfileWritePlan !== void 0) return { scopeProfileWritePlan: group.scopeProfileWritePlan };
|
|
211
|
+
if (group.turns.some((turn) => turn.acceptedCapture === true)) return { scopeProfileWritePlan: null };
|
|
212
|
+
return {};
|
|
213
|
+
}
|
|
214
|
+
function explicitModeDenied(group, config) {
|
|
215
|
+
return shouldSkipImplicitExtraction(config) && !group.turns.some((turn) => turn.acceptedCapture === true);
|
|
216
|
+
}
|
|
217
|
+
async function drainScopeGroups(ctx) {
|
|
218
|
+
const groupOutcomes = [];
|
|
219
|
+
let groupError;
|
|
220
|
+
for (const group of groupTurnsByExtractionScope(ctx.turns)) {
|
|
221
|
+
if (ctx.signal.aborted) break;
|
|
222
|
+
if (explicitModeDenied(group, ctx.config)) {
|
|
223
|
+
log.warn(
|
|
224
|
+
`buffer drain: session ${ctx.key} denied capture_mode_explicit (${group.turns.length} ordinary turn(s) retained)`
|
|
225
|
+
);
|
|
226
|
+
groupOutcomes.push({
|
|
227
|
+
turns: group.turns.length,
|
|
228
|
+
result: { status: "skipped", reason: "capture_mode_explicit", persistedCount: 0, durableOutputCount: 0 }
|
|
229
|
+
});
|
|
230
|
+
continue;
|
|
231
|
+
}
|
|
232
|
+
const settleGate = Promise.withResolvers();
|
|
233
|
+
let done = false;
|
|
234
|
+
const onSettle = (cause, result) => {
|
|
235
|
+
if (done) return;
|
|
236
|
+
done = true;
|
|
237
|
+
settleGate.resolve({ cause, result });
|
|
238
|
+
};
|
|
239
|
+
const exited = Promise.withResolvers();
|
|
240
|
+
void ctx.coordinator.queueBufferedExtraction(group.turns, "trigger_mode", {
|
|
241
|
+
bufferKey: ctx.key,
|
|
242
|
+
clearBufferAfterExtraction: true,
|
|
243
|
+
clearMatchingTurns: true,
|
|
244
|
+
skipDedupeCheck: true,
|
|
245
|
+
skipCharThreshold: true,
|
|
246
|
+
skipUserTurnThreshold: true,
|
|
247
|
+
// Automatic background work yields to fail-closed foreground flushes
|
|
248
|
+
// (preemptRunning), same as the live trigger path.
|
|
249
|
+
preemptable: true,
|
|
250
|
+
abortSignal: ctx.signal,
|
|
251
|
+
writeNamespaceOverride: group.writeNamespaceOverride,
|
|
252
|
+
principalOverride: group.principalOverride,
|
|
253
|
+
...planOptionForGroup(group),
|
|
254
|
+
execution: { buffer: ctx.claimBuffer, drain: ctx.executionDrain },
|
|
255
|
+
onTaskSettled: (error, result) => settleGate.resolve({ cause: error, result }),
|
|
256
|
+
onTaskExit: () => exited.resolve()
|
|
257
|
+
}).catch((cause) => onSettle(cause));
|
|
258
|
+
const [verdict] = await Promise.all([settleGate.promise, exited.promise]);
|
|
259
|
+
const settled = verdict;
|
|
260
|
+
if (settled.cause !== void 0) {
|
|
261
|
+
groupError = settled.cause;
|
|
262
|
+
break;
|
|
263
|
+
}
|
|
264
|
+
groupOutcomes.push({ turns: group.turns.length, result: settled.result });
|
|
265
|
+
}
|
|
266
|
+
return { groupOutcomes, groupError };
|
|
267
|
+
}
|
|
268
|
+
function deniedByReason(groupOutcomes) {
|
|
269
|
+
const denied = /* @__PURE__ */ new Map();
|
|
270
|
+
for (const entry of groupOutcomes) {
|
|
271
|
+
if (entry.result?.status !== "skipped" || !DENIED_SCOPE_REASONS.has(entry.result.reason ?? "")) continue;
|
|
272
|
+
denied.set(entry.result.reason, (denied.get(entry.result.reason) ?? 0) + entry.turns);
|
|
273
|
+
}
|
|
274
|
+
return denied;
|
|
275
|
+
}
|
|
276
|
+
function lastGroupReason(groupOutcomes) {
|
|
277
|
+
for (let index = groupOutcomes.length - 1; index >= 0; index -= 1) {
|
|
278
|
+
const reason = groupOutcomes[index]?.result?.reason;
|
|
279
|
+
if (reason !== void 0) return reason;
|
|
280
|
+
}
|
|
281
|
+
return void 0;
|
|
282
|
+
}
|
|
283
|
+
async function settleDrainVerdict(claims, key, ownerId, groupOutcomes, groupError, turnsRemaining) {
|
|
284
|
+
if (turnsRemaining === 0) return await ackOrReload(claims, key, ownerId);
|
|
285
|
+
if (groupError) {
|
|
286
|
+
await claims.releaseLease(key, ownerId);
|
|
287
|
+
return { status: "failed", reason: describeError(groupError), turnsRemaining };
|
|
288
|
+
}
|
|
289
|
+
await claims.releaseLease(key, ownerId);
|
|
290
|
+
const reason = groupOutcomes.find((entry) => entry.result?.reason !== void 0 && DENIED_SCOPE_REASONS.has(entry.result.reason))?.result?.reason ?? lastGroupReason(groupOutcomes) ?? "deferred";
|
|
291
|
+
return { status: "deferred", reason, turnsRemaining };
|
|
292
|
+
}
|
|
293
|
+
async function ackOrReload(claims, key, ownerId) {
|
|
294
|
+
const ackOutcome = await claims.ack(key, ownerId);
|
|
295
|
+
if (ackOutcome === "acked") return { status: "drained", turnsRemaining: 0 };
|
|
296
|
+
const reloaded = await claims.load(key);
|
|
297
|
+
const turnsRemaining = pendingTurnCount(reloaded?.entry);
|
|
298
|
+
await claims.releaseLease(key, ownerId);
|
|
299
|
+
return { status: "deferred", reason: ackOutcome === "not_empty" ? "ack_not_empty" : "ack_not_owner", turnsRemaining };
|
|
300
|
+
}
|
|
301
|
+
function groupCounts(groupOutcomes) {
|
|
302
|
+
return {
|
|
303
|
+
persistedCount: groupOutcomes.reduce((sum, entry) => sum + (entry.result?.persistedCount ?? 0), 0),
|
|
304
|
+
durableOutputCount: groupOutcomes.reduce((sum, entry) => sum + (entry.result?.durableOutputCount ?? 0), 0)
|
|
305
|
+
};
|
|
306
|
+
}
|
|
307
|
+
async function bufferSessionListings(claims, entries) {
|
|
308
|
+
const listings = [];
|
|
309
|
+
const seen = /* @__PURE__ */ new Set();
|
|
310
|
+
for (const [key, entry] of Object.entries(entries)) {
|
|
311
|
+
seen.add(key);
|
|
312
|
+
const claim = claims.isClaimed(key) ? await claims.load(key) : null;
|
|
313
|
+
listings.push({
|
|
314
|
+
key,
|
|
315
|
+
turns: claim ? pendingTurnCount(claim.entry) : pendingTurnCount(entry),
|
|
316
|
+
claimed: claim !== null
|
|
317
|
+
});
|
|
318
|
+
}
|
|
319
|
+
return { listings, seen };
|
|
320
|
+
}
|
|
321
|
+
async function orphanClaimListings(claims, seen) {
|
|
322
|
+
const out = [];
|
|
323
|
+
for (const listed of await claims.list()) {
|
|
324
|
+
if (seen.has(listed.key)) continue;
|
|
325
|
+
out.push({ key: listed.key, turns: listed.turnCount, claimed: true });
|
|
326
|
+
}
|
|
327
|
+
return out;
|
|
328
|
+
}
|
|
329
|
+
function drainAbortSignal(callerSignal, abort) {
|
|
330
|
+
return callerSignal ? AbortSignal.any([callerSignal, abort.signal]) : abort.signal;
|
|
331
|
+
}
|
|
332
|
+
async function runClaimDrain(ctx, options, heartbeat) {
|
|
333
|
+
if (ctx.turns.length === 0) {
|
|
334
|
+
const outcome2 = await ackEmptyClaim(ctx.claims, ctx.key, ctx.ownerId, ctx.turnsAtStart);
|
|
335
|
+
options.onEvent?.({ type: "session_finished", key: ctx.key, outcome: outcome2 });
|
|
336
|
+
return outcome2;
|
|
337
|
+
}
|
|
338
|
+
const { groupOutcomes, groupError } = await drainScopeGroups(ctx);
|
|
339
|
+
const remaining = await ctx.claims.load(ctx.key);
|
|
340
|
+
const { status, reason, turnsRemaining } = await settleDrainVerdict(
|
|
341
|
+
ctx.claims,
|
|
342
|
+
ctx.key,
|
|
343
|
+
ctx.ownerId,
|
|
344
|
+
groupOutcomes,
|
|
345
|
+
groupError,
|
|
346
|
+
pendingTurnCount(remaining?.entry)
|
|
347
|
+
);
|
|
348
|
+
const outcome = assembleOutcome(
|
|
349
|
+
ctx.key,
|
|
350
|
+
ctx.turnsAtStart,
|
|
351
|
+
{ status, reason, turnsRemaining },
|
|
352
|
+
groupCounts(groupOutcomes),
|
|
353
|
+
deniedByReason(groupOutcomes)
|
|
354
|
+
);
|
|
355
|
+
log.info(`buffer drain: session ${ctx.key} ${status} (${outcome.turnsRemaining} turn(s) remaining)`);
|
|
356
|
+
options.onEvent?.({ type: "session_finished", key: ctx.key, outcome });
|
|
357
|
+
return outcome;
|
|
358
|
+
}
|
|
359
|
+
var BufferDrainRunner = class {
|
|
360
|
+
constructor(orchestrator) {
|
|
361
|
+
this.orchestrator = orchestrator;
|
|
362
|
+
}
|
|
363
|
+
orchestrator;
|
|
364
|
+
/** The claim store of this orchestrator's memory root. */
|
|
365
|
+
get claims() {
|
|
366
|
+
return this.orchestrator.storage.bufferDrainClaims();
|
|
367
|
+
}
|
|
368
|
+
/**
|
|
369
|
+
* Drain one claimed session. The caller owns the lease (it may have taken
|
|
370
|
+
* it already); this method verifies ownership before touching content.
|
|
371
|
+
*/
|
|
372
|
+
async drainSession(key, options) {
|
|
373
|
+
const claims = this.claims;
|
|
374
|
+
const leaseMs = options.leaseMs ?? DEFAULT_LEASE_MS;
|
|
375
|
+
const claimed = await loadClaimedSession(claims, key);
|
|
376
|
+
if (claimed.kind === "notClaimed") return claimed.notClaimed;
|
|
377
|
+
const { claim, turnsAtStart } = claimed;
|
|
378
|
+
options.onEvent?.({ type: "session_started", key, turns: turnsAtStart });
|
|
379
|
+
const busy = await adoptLease(claims, key, options.ownerId, leaseMs);
|
|
380
|
+
if (busy !== null) {
|
|
381
|
+
const outcome = busy;
|
|
382
|
+
options.onEvent?.({ type: "session_finished", key, outcome });
|
|
383
|
+
return outcome;
|
|
384
|
+
}
|
|
385
|
+
const { claimBuffer, coordinator, executionDrain } = buildClaimExecution(
|
|
386
|
+
this.orchestrator,
|
|
387
|
+
claims,
|
|
388
|
+
key,
|
|
389
|
+
options.ownerId,
|
|
390
|
+
claim
|
|
391
|
+
);
|
|
392
|
+
await claimBuffer.load();
|
|
393
|
+
const turns = [...claim.entry.retainedTurns ?? [], ...claim.entry.turns];
|
|
394
|
+
const abort = new AbortController();
|
|
395
|
+
const signal = drainAbortSignal(options.signal, abort);
|
|
396
|
+
const heartbeat = startLeaseHeartbeat(claims, key, options.ownerId, leaseMs, abort);
|
|
397
|
+
try {
|
|
398
|
+
return await runClaimDrain(
|
|
399
|
+
{
|
|
400
|
+
orchestrator: this.orchestrator,
|
|
401
|
+
claims,
|
|
402
|
+
key,
|
|
403
|
+
ownerId: options.ownerId,
|
|
404
|
+
claimBuffer,
|
|
405
|
+
coordinator,
|
|
406
|
+
executionDrain,
|
|
407
|
+
turns,
|
|
408
|
+
turnsAtStart,
|
|
409
|
+
config: this.orchestrator.config,
|
|
410
|
+
signal
|
|
411
|
+
},
|
|
412
|
+
options,
|
|
413
|
+
heartbeat
|
|
414
|
+
);
|
|
415
|
+
} finally {
|
|
416
|
+
clearInterval(heartbeat);
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
/** Claim a session file for the drain. Returns false when it is not claimable. */
|
|
420
|
+
async claim(key, ownerId, leaseMs = DEFAULT_LEASE_MS) {
|
|
421
|
+
const lease = {
|
|
422
|
+
ownerId,
|
|
423
|
+
pid: process.pid,
|
|
424
|
+
host: hostname(),
|
|
425
|
+
acquiredAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
426
|
+
heartbeatAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
427
|
+
leaseMs
|
|
428
|
+
};
|
|
429
|
+
return await this.claims.claimFromSessionFile(key, lease) === "claimed";
|
|
430
|
+
}
|
|
431
|
+
/** Sessions with buffered turns, claimed or not (CLI scan). */
|
|
432
|
+
async scan() {
|
|
433
|
+
const sessions = await this.orchestrator.storage.loadBuffer();
|
|
434
|
+
const { listings, seen } = await bufferSessionListings(this.claims, sessions.entries ?? {});
|
|
435
|
+
return [...listings, ...await orphanClaimListings(this.claims, seen)];
|
|
436
|
+
}
|
|
437
|
+
};
|
|
438
|
+
|
|
439
|
+
export {
|
|
440
|
+
ClaimBufferStorage,
|
|
441
|
+
BufferDrainRunner
|
|
442
|
+
};
|
|
443
|
+
//# sourceMappingURL=chunk-ZODKV27J.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/orchestration/buffer-drain-runner.ts"],"sourcesContent":["/** Claim-backed extraction-buffer drain (`remnic buffer drain` worker AND the */\n\nimport { hostname } from \"node:os\";\nimport type { BufferStorage } from \"../buffer-persistence.js\";\nimport { type ExtractionScopeGroup, describeError, groupTurnsByExtractionScope } from \"../buffer-turn-helpers.js\";\nimport { SmartBuffer } from \"../buffer.js\";\nimport { resolveMemoryLifecycleCapabilities } from \"../capabilities.js\";\nimport { shouldSkipImplicitExtraction } from \"../explicit-capture.js\";\nimport { log } from \"../logger.js\";\nimport type { ResolvedScopeProfilePlan } from \"../namespaces/scope-profiles.js\";\nimport type { Orchestrator } from \"../orchestrator.js\";\nimport { headerConnector, renderExtractionConversation, resolveSourceConnector } from \"../source-agent-qualifier.js\";\nimport type { BufferDrainClaims, DrainLease } from \"../storage/buffer-drain-claims.js\";\nimport type { BufferEntryState, BufferState, BufferTurn, PluginConfig } from \"../types.js\";\nimport { ExtractionDrain } from \"./extraction-drain.js\";\nimport type { ExtractionRunResult } from \"./extraction-run.js\";\nimport { selfDeps } from \"./self-deps.js\";\nimport { TurnIngestionCoordinator, type TurnIngestionDeps } from \"./turn-ingestion.js\";\n\nexport type DrainSessionStatus = \"drained\" | \"deferred\" | \"failed\" | \"skipped\";\n\nexport interface DrainSessionOutcome {\n key: string;\n status: DrainSessionStatus;\n /** Turns the claim held when the drain started. */\n turnsAtStart: number;\n /** Turns still in the claim when the drain stopped. */\n turnsRemaining: number;\n /** Facts the extraction persisted during this run. */\n persistedCount: number;\n /** Durable outputs (memories + entities) the extraction wrote. */\n durableOutputCount: number;\n /** Why the session was skipped or deferred (machine-readable). */\n reason?: string;\n /** Current-policy denials: scope groups whose authorization no longer holds. */\n denied?: { reason: string; turns: number }[];\n}\n\n/** Extraction results that mean \"current policy refuses this scope\": the\n * turns are valid backlog whose captured scope is no longer writable. */\nconst DENIED_SCOPE_REASONS: ReadonlySet<string> = new Set([\n \"pinned_namespace_unavailable\",\n \"namespace_write_revoked\",\n \"scope_profile_revoked\",\n // The resolved profile has no writable layer: the same current-policy\n // refusal family, surfaced from inside the shared runExtraction gate.\n \"scope_profile_no_writable_layer\",\n // captureMode=explicit: ordinary buffered conversation turns never create\n // memories; only deliberately accepted captures drain.\n \"capture_mode_explicit\",\n]);\n\nexport interface BufferDrainRunnerOptions {\n /** Identity of this drainer; owns the lease it takes. */\n ownerId: string;\n /** Lease lifetime in ms. The heartbeat keeps it alive while draining. */\n leaseMs?: number;\n /** Cancels the run at the next chunk boundary. */\n signal?: AbortSignal;\n /** Progress callback (per session, and per claim transition). */\n onEvent?: (event: DrainRunnerEvent) => void;\n}\n\n/** A failed drain run: the reason a chunk or the session could not finish. */\nexport type DrainExtractionError = Error;\n\nexport type DrainRunnerEvent =\n | { type: \"session_started\"; key: string; turns: number }\n | { type: \"session_finished\"; key: string; outcome: DrainSessionOutcome };\n\nconst DEFAULT_LEASE_MS = 120_000;\n\n/**\n * A `BufferStorage` view of one drain claim: the claim file IS the buffer.\n * Writes are the drain's progress (what is left to extract), so every\n * successfully extracted chunk is durably removed before the next one runs.\n */\nexport class ClaimBufferStorage implements BufferStorage {\n constructor(\n private readonly claims: BufferDrainClaims,\n private readonly key: string,\n private readonly ownerId: string,\n private readonly entry: BufferEntryState\n ) {}\n\n async loadBuffer(): Promise<BufferState> {\n const entries: NonNullable<BufferState[\"entries\"]> = Object.create(null);\n entries[this.key] = {\n turns: this.entry.turns,\n retainedTurns: this.entry.retainedTurns,\n lastExtractionAt: this.entry.lastExtractionAt,\n extractionCount: this.entry.extractionCount,\n };\n return {\n turns: this.entry.turns,\n lastExtractionAt: this.entry.lastExtractionAt,\n extractionCount: this.entry.extractionCount,\n entries,\n };\n }\n\n async saveBuffer(state: BufferState): Promise<void> {\n // Whole-state fallback (the claim covers one session): persist the entry.\n const entry = state.entries?.[this.key];\n await this.claims.writeEntry(\n this.key,\n this.ownerId,\n entry ?? { turns: [], lastExtractionAt: null, extractionCount: 0 },\n this.entry\n );\n }\n\n async saveBufferSession(key: string, entry: BufferEntryState): Promise<void> {\n await this.claims.writeEntry(key, this.ownerId, entry, key === this.key ? this.entry : undefined);\n }\n\n async deleteBufferSession(): Promise<void> {\n // The claim is removed by the ack path, never by a buffer eviction: the\n // drain decides when the session is finished.\n }\n}\n\n/** Per-invocation isolated execution context for one claim drain. */\ninterface ClaimDrainExecution {\n claimBuffer: SmartBuffer;\n coordinator: TurnIngestionCoordinator;\n executionDrain: ExtractionDrain;\n}\n\n/** The scopeProfileWritePlan option a scope group forwards to the queue. */\ninterface GroupPlanOption {\n scopeProfileWritePlan?: ResolvedScopeProfilePlan | null;\n}\n\n/** Durable counters a drain pass contributed. */\ninterface GroupCounts {\n persistedCount: number;\n durableOutputCount: number;\n}\n\n/** Pending turns across canonical + retained copies (the honest backlog count). */\nfunction pendingTurnCount(entry: BufferEntryState | undefined): number {\n if (!entry) return 0;\n return entry.turns.length + (entry.retainedTurns?.length ?? 0);\n}\n\n/** Load one claimed session. An unclaimed key is nothing to drain. */\nasync function loadClaimedSession(\n claims: BufferDrainClaims,\n key: string\n): Promise<\n | { kind: \"notClaimed\"; notClaimed: DrainSessionOutcome }\n | { kind: \"claimed\"; claim: { entry: BufferEntryState }; turnsAtStart: number }\n> {\n const claim = await claims.load(key);\n if (!claim) {\n return {\n kind: \"notClaimed\",\n notClaimed: {\n key,\n status: \"skipped\",\n turnsAtStart: 0,\n turnsRemaining: 0,\n persistedCount: 0,\n durableOutputCount: 0,\n reason: \"not_claimed\",\n },\n };\n }\n return { kind: \"claimed\", claim, turnsAtStart: pendingTurnCount(claim.entry) };\n}\n\nfunction busyLeaseOutcome(key: string, turnsAtStart: number): DrainSessionOutcome {\n return {\n key,\n status: \"skipped\",\n turnsAtStart,\n turnsRemaining: turnsAtStart,\n persistedCount: 0,\n durableOutputCount: 0,\n reason: \"claimed_by_another_drain\",\n };\n}\n\n/** Take the lease unless this drainer already holds it. A busy lease means\n * another drainer owns the claim — skip without touching content. */\nasync function adoptLease(\n claims: BufferDrainClaims,\n key: string,\n ownerId: string,\n leaseMs: number\n): Promise<DrainSessionOutcome | null> {\n const held = await claims.adopt(key, {\n ownerId,\n pid: process.pid,\n host: hostname(),\n acquiredAt: new Date().toISOString(),\n heartbeatAt: new Date().toISOString(),\n leaseMs,\n });\n return held === \"busy\" ? busyLeaseOutcome(key, pendingTurnCount((await claims.load(key))?.entry)) : null;\n}\n\nfunction assembleOutcome(\n key: string,\n turnsAtStart: number,\n verdict: { status: DrainSessionStatus; reason?: string; turnsRemaining: number },\n counts: { persistedCount: number; durableOutputCount: number },\n denied: Map<string, number>\n): DrainSessionOutcome {\n const outcome: DrainSessionOutcome = {\n key,\n status: verdict.status,\n turnsAtStart,\n turnsRemaining: verdict.turnsRemaining,\n persistedCount: counts.persistedCount,\n durableOutputCount: counts.durableOutputCount,\n };\n if (denied.size > 0) outcome.denied = [...denied].map(([deniedReason, turns]) => ({ reason: deniedReason, turns }));\n if (verdict.reason !== undefined) outcome.reason = verdict.reason;\n return outcome;\n}\n\n/** Ack an EMPTY claim. The ack verdict is the truth: live ingress can merge\n * between the empty read and the ack — a not_empty ack means pending work\n * exists; reload it, release OUR lease, report deferred, never a false\n * drained. */\nasync function ackEmptyClaim(\n claims: BufferDrainClaims,\n key: string,\n ownerId: string,\n turnsAtStart: number\n): Promise<DrainSessionOutcome> {\n const ackOutcome = await claims.ack(key, ownerId);\n if (ackOutcome !== \"acked\") {\n const reloaded = await claims.load(key);\n const turnsRemaining = pendingTurnCount(reloaded?.entry);\n await claims.releaseLease(key, ownerId);\n return {\n key,\n status: \"deferred\",\n turnsAtStart,\n turnsRemaining,\n persistedCount: 0,\n durableOutputCount: 0,\n reason: ackOutcome === \"not_empty\" ? \"ack_not_empty\" : \"ack_not_owner\",\n };\n }\n return { key, status: \"drained\", turnsAtStart, turnsRemaining: 0, persistedCount: 0, durableOutputCount: 0 };\n}\n\n/** another drainer took the claim, so this run must stop instead of writing */\nfunction startLeaseHeartbeat(\n claims: BufferDrainClaims,\n key: string,\n ownerId: string,\n leaseMs: number,\n abort: AbortController\n): NodeJS.Timeout {\n const heartbeat = setInterval(\n () => {\n void claims\n .heartbeat(key, ownerId, leaseMs)\n .then((state) => {\n if (state === \"lost\") abort.abort(new Error(`buffer drain: lease lost for session ${key}`));\n })\n .catch((err: Error) => {\n // A heartbeat that cannot be renewed is a lease that cannot be held:\n // stop this run cleanly at the next chunk boundary (the next run\n // resumes it).\n abort.abort(new Error(`buffer drain: lease heartbeat failed for session ${key}: ${describeError(err)}`));\n });\n },\n Math.max(1_000, Math.floor(leaseMs / 3))\n );\n heartbeat.unref?.();\n return heartbeat;\n}\n\n/** coordinator bound to it, and the no-drop chunked drain. Built per */\nfunction buildClaimExecution(\n orchestrator: Orchestrator,\n claims: BufferDrainClaims,\n key: string,\n ownerId: string,\n claim: { entry: BufferEntryState }\n): ClaimDrainExecution {\n const claimBuffer = new SmartBuffer(orchestrator.config, new ClaimBufferStorage(claims, key, ownerId, claim.entry));\n const isolatedRun = orchestrator.extractionRunCoordinatorForBuffer(claimBuffer);\n const coordinator = new TurnIngestionCoordinator(selfDeps<TurnIngestionDeps>(orchestrator));\n const config = orchestrator.config;\n const ingestionDeps = selfDeps<TurnIngestionDeps>(orchestrator);\n // No-drop: a repeatedly failing chunk stays in the claim as durable\n // retryable backlog — never side-filed, never counted as processed.\n const executionDrain = new ExtractionDrain(\n {\n config: {\n extractionMinUserTurns: config.extractionMinUserTurns,\n extractionMinChars: config.extractionMinChars,\n extractionMaxTurnChars: config.extractionMaxTurnChars,\n extractionChunkDropAfterFailures: config.extractionChunkDropAfterFailures,\n },\n extractionWindowBudgetChars: () => ingestionDeps.extractionWindowBudgetChars?.() ?? Number.POSITIVE_INFINITY,\n // Render-exact chunk sizing: the model clamp bounds the CONVERSATION\n // (truncateLocalExtractionConversation), so measure exactly that —\n // with the SAME source-classification gate extract() applies when it\n // prepends the connector header (header margin included when the\n // engine would render it).\n measureRenderedTurns: (turns) => {\n const sourceConnector = resolveMemoryLifecycleCapabilities(config).extractionScopeClassification\n ? resolveSourceConnector(turns)\n : undefined;\n return renderExtractionConversation(\n turns.map((turn) => ({ ...turn, content: turn.content.trim().slice(0, config.extractionMaxTurnChars) })),\n headerConnector(sourceConnector)\n ).conversation.length;\n },\n runExtraction: (turns, runOptions) => isolatedRun.runExtraction(turns, runOptions),\n getStorage: () => ingestionDeps.getStorage(),\n buffer: claimBuffer,\n },\n { dropFailedChunks: false }\n );\n return { claimBuffer, coordinator, executionDrain };\n}\n\n/** Plan semantics for one scope group: a pinned plan forwards as-is; a\n * planless ACCEPTED group pins null (existing flush behavior); unpinned\n * legacy groups pass NO option so runExtraction resolves the CURRENT\n * profile. */\nfunction planOptionForGroup(group: ExtractionScopeGroup): GroupPlanOption {\n if (group.scopeProfileWritePlan !== undefined) return { scopeProfileWritePlan: group.scopeProfileWritePlan };\n if (group.turns.some((turn) => turn.acceptedCapture === true)) return { scopeProfileWritePlan: null };\n return {};\n}\n\n/** captureMode=explicit: ordinary buffered conversation turns never create\n * memories — only deliberately accepted captures drain. */\nfunction explicitModeDenied(group: ExtractionScopeGroup, config: PluginConfig): boolean {\n return shouldSkipImplicitExtraction(config) && !group.turns.some((turn) => turn.acceptedCapture === true);\n}\n\ninterface GroupOutcome {\n turns: number;\n result?: ExtractionRunResult;\n}\n\ninterface ScopeDrainContext {\n config: PluginConfig;\n key: string;\n signal: AbortSignal;\n claimBuffer: SmartBuffer;\n coordinator: TurnIngestionCoordinator;\n executionDrain: ExtractionDrain;\n turns: BufferTurn[];\n}\n\n/** Drain a claimed session's turns ONE captured-scope group at a time: each\n * group keeps its own namespace/principal/plan pins, and the shared\n * extraction boundary re-applies CURRENT authorization from the turn's\n * ORIGINAL coding binding before any write. Groups run sequentially (FIFO\n * per key — the queue's same-key exclusion would serialize them anyway); a\n * denied group never blocks or clears the other groups. */\nasync function drainScopeGroups(\n ctx: ScopeDrainContext\n): Promise<{ groupOutcomes: GroupOutcome[]; groupError?: DrainExtractionError }> {\n const groupOutcomes: GroupOutcome[] = [];\n let groupError: DrainExtractionError | undefined;\n for (const group of groupTurnsByExtractionScope(ctx.turns)) {\n if (ctx.signal.aborted) break;\n if (explicitModeDenied(group, ctx.config)) {\n log.warn(\n `buffer drain: session ${ctx.key} denied capture_mode_explicit (${group.turns.length} ordinary turn(s) retained)`\n );\n groupOutcomes.push({\n turns: group.turns.length,\n result: { status: \"skipped\", reason: \"capture_mode_explicit\", persistedCount: 0, durableOutputCount: 0 },\n });\n continue;\n }\n const settleGate = Promise.withResolvers<{ cause?: unknown; result?: ExtractionRunResult }>();\n let done = false;\n const onSettle = (cause: unknown, result?: ExtractionRunResult): void => {\n if (done) return;\n done = true;\n settleGate.resolve({ cause, result });\n };\n // Settlement and callback EXIT are tracked separately: the lease is\n // released only after BOTH the queued closure settled and fully exited\n // (an abort settles through its listener while the closure may still be\n // persisting).\n const exited = Promise.withResolvers<void>();\n void ctx.coordinator\n .queueBufferedExtraction(group.turns, \"trigger_mode\", {\n bufferKey: ctx.key,\n clearBufferAfterExtraction: true,\n clearMatchingTurns: true,\n skipDedupeCheck: true,\n skipCharThreshold: true,\n skipUserTurnThreshold: true,\n // Automatic background work yields to fail-closed foreground flushes\n // (preemptRunning), same as the live trigger path.\n preemptable: true,\n abortSignal: ctx.signal,\n writeNamespaceOverride: group.writeNamespaceOverride,\n principalOverride: group.principalOverride,\n ...planOptionForGroup(group),\n execution: { buffer: ctx.claimBuffer, drain: ctx.executionDrain },\n onTaskSettled: (error, result) => settleGate.resolve({ cause: error, result }),\n onTaskExit: () => exited.resolve(),\n })\n .catch((cause: DrainExtractionError) => onSettle(cause));\n const [verdict] = await Promise.all([settleGate.promise, exited.promise]);\n const settled = verdict;\n if (settled.cause !== undefined) {\n // SAFETY: settle captures whatever the queued closure rejected with;\n // every drain rejection site throws Error values, and a rejection is\n // always a DrainExtractionError in this path.\n groupError = settled.cause as Error;\n break;\n }\n groupOutcomes.push({ turns: group.turns.length, result: settled.result });\n }\n return { groupOutcomes, groupError };\n}\n\n/** Denied scope groups: policy refusals leave their turns pending (the group\n * result's turns were NOT cleared), aggregated per reason so a drain is\n * never reported complete while denied backlog remains. */\nfunction deniedByReason(groupOutcomes: readonly GroupOutcome[]): Map<string, number> {\n const denied = new Map<string, number>();\n for (const entry of groupOutcomes) {\n if (entry.result?.status !== \"skipped\" || !DENIED_SCOPE_REASONS.has(entry.result.reason ?? \"\")) continue;\n denied.set(entry.result.reason!, (denied.get(entry.result.reason!) ?? 0) + entry.turns);\n }\n return denied;\n}\n\nfunction lastGroupReason(groupOutcomes: readonly GroupOutcome[]): string | undefined {\n for (let index = groupOutcomes.length - 1; index >= 0; index -= 1) {\n const reason = groupOutcomes[index]?.result?.reason;\n if (reason !== undefined) return reason;\n }\n return undefined;\n}\n\n/** the session file is gone for good — but the ack verdict is the truth (live */\nasync function settleDrainVerdict(\n claims: BufferDrainClaims,\n key: string,\n ownerId: string,\n groupOutcomes: readonly GroupOutcome[],\n groupError: DrainExtractionError | undefined,\n turnsRemaining: number\n): Promise<{ status: DrainSessionStatus; reason?: string; turnsRemaining: number }> {\n if (turnsRemaining === 0) return await ackOrReload(claims, key, ownerId);\n if (groupError) {\n await claims.releaseLease(key, ownerId);\n return { status: \"failed\", reason: describeError(groupError), turnsRemaining };\n }\n await claims.releaseLease(key, ownerId);\n const reason =\n groupOutcomes.find((entry) => entry.result?.reason !== undefined && DENIED_SCOPE_REASONS.has(entry.result.reason!))\n ?.result?.reason ??\n lastGroupReason(groupOutcomes) ??\n \"deferred\";\n return { status: \"deferred\", reason, turnsRemaining };\n}\n\n/** Ack an emptied claim; a not-acked verdict means live ingress merged (or\n * the lease moved) — reload the honest pending count and release OUR lease,\n * keeping the source. */\nasync function ackOrReload(\n claims: BufferDrainClaims,\n key: string,\n ownerId: string\n): Promise<{ status: DrainSessionStatus; reason?: string; turnsRemaining: number }> {\n const ackOutcome = await claims.ack(key, ownerId);\n if (ackOutcome === \"acked\") return { status: \"drained\", turnsRemaining: 0 };\n const reloaded = await claims.load(key);\n const turnsRemaining = pendingTurnCount(reloaded?.entry);\n await claims.releaseLease(key, ownerId);\n return { status: \"deferred\", reason: ackOutcome === \"not_empty\" ? \"ack_not_empty\" : \"ack_not_owner\", turnsRemaining };\n}\n\nfunction groupCounts(groupOutcomes: readonly GroupOutcome[]): GroupCounts {\n return {\n persistedCount: groupOutcomes.reduce((sum, entry) => sum + (entry.result?.persistedCount ?? 0), 0),\n durableOutputCount: groupOutcomes.reduce((sum, entry) => sum + (entry.result?.durableOutputCount ?? 0), 0),\n };\n}\n\nexport interface DrainScanEntry {\n key: string;\n turns: number;\n claimed: boolean;\n}\n\n/** Session-buffer listings: a claimed session reports its CLAIM's pending\n * count (the live buffer copy may lag the claim), an unclaimed one its\n * buffer entry. */\nasync function bufferSessionListings(\n claims: BufferDrainClaims,\n entries: Record<string, BufferEntryState>\n): Promise<{ listings: DrainScanEntry[]; seen: Set<string> }> {\n const listings: DrainScanEntry[] = [];\n const seen = new Set<string>();\n for (const [key, entry] of Object.entries(entries)) {\n seen.add(key);\n const claim = claims.isClaimed(key) ? await claims.load(key) : null;\n listings.push({\n key,\n turns: claim ? pendingTurnCount(claim.entry) : pendingTurnCount(entry),\n claimed: claim !== null,\n });\n }\n return { listings, seen };\n}\n\n/** Claims the buffer state no longer lists (drained by an earlier run whose\n * claim file outlived its session file). */\nasync function orphanClaimListings(claims: BufferDrainClaims, seen: Set<string>): Promise<DrainScanEntry[]> {\n const out: DrainScanEntry[] = [];\n for (const listed of await claims.list()) {\n if (seen.has(listed.key)) continue;\n out.push({ key: listed.key, turns: listed.turnCount, claimed: true });\n }\n return out;\n}\n\n/** The drain runs on the caller's abort signal combined with this run's own\n * lease-loss controller. */\nfunction drainAbortSignal(callerSignal: AbortSignal | undefined, abort: AbortController): AbortSignal {\n return callerSignal ? AbortSignal.any([callerSignal, abort.signal]) : abort.signal;\n}\n\n/** One heartbeat-protected claim drain: run every scope group, settle the\n * verdict against the claim store, and assemble the honest outcome. The\n * heartbeat is cleared by the caller on every exit path. */\nasync function runClaimDrain(\n ctx: {\n orchestrator: Orchestrator;\n claims: BufferDrainClaims;\n key: string;\n ownerId: string;\n claimBuffer: SmartBuffer;\n coordinator: TurnIngestionCoordinator;\n executionDrain: ExtractionDrain;\n turns: BufferTurn[];\n turnsAtStart: number;\n config: PluginConfig;\n signal: AbortSignal;\n },\n options: BufferDrainRunnerOptions,\n heartbeat: NodeJS.Timeout\n): Promise<DrainSessionOutcome> {\n // An emptied claim acks here: the ack verdict is the truth (drained), or\n // live ingress merged between the read and the ack — deferred, source kept.\n if (ctx.turns.length === 0) {\n const outcome = await ackEmptyClaim(ctx.claims, ctx.key, ctx.ownerId, ctx.turnsAtStart);\n options.onEvent?.({ type: \"session_finished\", key: ctx.key, outcome });\n return outcome;\n }\n const { groupOutcomes, groupError } = await drainScopeGroups(ctx);\n // Heartbeat cleared on EVERY exit path: a rejected drain must not keep\n // renewing the lease forever (cleared in the caller's finally).\n const remaining = await ctx.claims.load(ctx.key);\n const { status, reason, turnsRemaining } = await settleDrainVerdict(\n ctx.claims,\n ctx.key,\n ctx.ownerId,\n groupOutcomes,\n groupError,\n pendingTurnCount(remaining?.entry)\n );\n const outcome = assembleOutcome(\n ctx.key,\n ctx.turnsAtStart,\n { status, reason, turnsRemaining },\n groupCounts(groupOutcomes),\n deniedByReason(groupOutcomes)\n );\n log.info(`buffer drain: session ${ctx.key} ${status} (${outcome.turnsRemaining} turn(s) remaining)`);\n options.onEvent?.({ type: \"session_finished\", key: ctx.key, outcome });\n return outcome;\n}\n\nexport class BufferDrainRunner {\n constructor(private readonly orchestrator: Orchestrator) {}\n\n /** The claim store of this orchestrator's memory root. */\n get claims(): BufferDrainClaims {\n return this.orchestrator.storage.bufferDrainClaims();\n }\n\n /**\n * Drain one claimed session. The caller owns the lease (it may have taken\n * it already); this method verifies ownership before touching content.\n */\n async drainSession(key: string, options: BufferDrainRunnerOptions): Promise<DrainSessionOutcome> {\n const claims = this.claims;\n const leaseMs = options.leaseMs ?? DEFAULT_LEASE_MS;\n const claimed = await loadClaimedSession(claims, key);\n if (claimed.kind === \"notClaimed\") return claimed.notClaimed;\n const { claim, turnsAtStart } = claimed;\n options.onEvent?.({ type: \"session_started\", key, turns: turnsAtStart });\n\n // Take the lease unless this drainer already holds it.\n const busy = await adoptLease(claims, key, options.ownerId, leaseMs);\n if (busy !== null) {\n const outcome = busy;\n options.onEvent?.({ type: \"session_finished\", key, outcome });\n return outcome;\n }\n\n // The claim is the buffer for this run: every successful chunk is removed\n // from it, so a kill leaves exactly the un-extracted turns.\n const { claimBuffer, coordinator, executionDrain } = buildClaimExecution(\n this.orchestrator,\n claims,\n key,\n options.ownerId,\n claim\n );\n await claimBuffer.load();\n\n // The claim's turns (retained first, like the live buffer's order).\n const turns = [...(claim.entry.retainedTurns ?? []), ...claim.entry.turns];\n\n // A lost lease means another drainer took the claim: stop instead of\n // writing progress into a claim this run no longer owns.\n const abort = new AbortController();\n const signal = drainAbortSignal(options.signal, abort);\n const heartbeat = startLeaseHeartbeat(claims, key, options.ownerId, leaseMs, abort);\n try {\n return await runClaimDrain(\n {\n orchestrator: this.orchestrator,\n claims,\n key,\n ownerId: options.ownerId,\n claimBuffer,\n coordinator,\n executionDrain,\n turns,\n turnsAtStart,\n config: this.orchestrator.config,\n signal,\n },\n options,\n heartbeat\n );\n } finally {\n clearInterval(heartbeat);\n }\n }\n\n /** Claim a session file for the drain. Returns false when it is not claimable. */\n async claim(key: string, ownerId: string, leaseMs = DEFAULT_LEASE_MS): Promise<boolean> {\n const lease: DrainLease = {\n ownerId,\n pid: process.pid,\n host: hostname(),\n acquiredAt: new Date().toISOString(),\n heartbeatAt: new Date().toISOString(),\n leaseMs,\n };\n return (await this.claims.claimFromSessionFile(key, lease)) === \"claimed\";\n }\n\n /** Sessions with buffered turns, claimed or not (CLI scan). */\n async scan(): Promise<DrainScanEntry[]> {\n const sessions = await this.orchestrator.storage.loadBuffer();\n const { listings, seen } = await bufferSessionListings(this.claims, sessions.entries ?? {});\n return [...listings, ...(await orphanClaimListings(this.claims, seen))];\n }\n}\n"],"mappings":"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","names":["outcome"]}
|