@remnic/core 10.0.3 → 10.0.5
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 +62 -62
- package/dist/access-authorization-probe.js +63 -63
- package/dist/access-boundary.js +62 -62
- package/dist/access-cli.d.ts.map +1 -1
- package/dist/access-cli.js +146 -139
- package/dist/access-cli.js.map +1 -1
- package/dist/access-extraction-force-flush.js +62 -62
- package/dist/access-http-briefing.js +63 -63
- package/dist/access-http-query.js +64 -64
- package/dist/access-http.d.ts.map +1 -1
- package/dist/access-http.js +86 -85
- package/dist/access-identity-continuity-surface.js +62 -62
- package/dist/access-lcm-surface.js +62 -62
- package/dist/access-mcp-correction-tools.d.ts +10 -0
- package/dist/access-mcp-correction-tools.d.ts.map +1 -0
- package/dist/access-mcp-correction-tools.js +8 -0
- package/dist/access-mcp.d.ts.map +1 -1
- package/dist/access-mcp.js +76 -75
- package/dist/access-namespace-preflight.js +62 -62
- package/dist/access-observe-write-category.js +5 -5
- package/dist/access-observe-write-surface.js +62 -62
- package/dist/access-offline-manifest.js +8 -8
- package/dist/access-operations-batch.js +65 -65
- package/dist/access-operations.d.ts +1 -0
- package/dist/access-operations.d.ts.map +1 -1
- package/dist/access-operations.js +72 -72
- package/dist/access-recall-concurrency.js +62 -62
- package/dist/access-recall-diagnostics.js +2 -2
- package/dist/access-recall-response.js +62 -62
- package/dist/access-recall-surface.js +62 -62
- package/dist/access-service.d.ts.map +1 -1
- package/dist/access-service.js +62 -62
- package/dist/access-surface-catalog.js +64 -64
- package/dist/active-recall.js +31 -30
- package/dist/active-recall.js.map +1 -1
- package/dist/adapters/index.js +7 -7
- package/dist/adapters/registry.js +3 -3
- package/dist/{auto-sync-PAWBFQWL.js → auto-sync-FN7E3OTO.js} +6 -6
- package/dist/briefing.js +26 -26
- package/dist/buffer.js +8 -8
- package/dist/causal-consolidation.js +26 -26
- package/dist/{chunk-YQSWNFZE.js → chunk-2CP577K6.js} +2 -2
- package/dist/{chunk-6JIHC5AS.js → chunk-37HCPM56.js} +78 -67
- package/dist/chunk-37HCPM56.js.map +1 -0
- package/dist/{chunk-345MEMRU.js → chunk-3OUGSOJP.js} +2 -2
- package/dist/{chunk-CHI37EHP.js → chunk-4CWUZBPF.js} +8 -6
- package/dist/chunk-4CWUZBPF.js.map +1 -0
- package/dist/{chunk-G2STTRYB.js → chunk-4D2YH47Z.js} +2 -2
- package/dist/{chunk-IXYIW3MZ.js → chunk-4K2H4KTR.js} +5 -5
- package/dist/{chunk-UVVSOSHL.js → chunk-52CQKST6.js} +53 -53
- package/dist/{chunk-H7BZBSP6.js → chunk-52II7PB6.js} +4 -4
- package/dist/{chunk-BLHPADUX.js → chunk-5BPXMAUP.js} +22 -78
- package/dist/chunk-5BPXMAUP.js.map +1 -0
- package/dist/{chunk-ZS7RK6H6.js → chunk-5BY3IA2U.js} +16 -53
- package/dist/chunk-5BY3IA2U.js.map +1 -0
- package/dist/{chunk-2QZFZNXO.js → chunk-5CQO6LVM.js} +2 -2
- package/dist/{chunk-NLDMTXWV.js → chunk-5LNPW7NE.js} +2 -2
- package/dist/{chunk-WHTMVTU4.js → chunk-5X4ZJESN.js} +2 -2
- package/dist/{chunk-WI37MWRZ.js → chunk-63UNVGZW.js} +5 -5
- package/dist/{chunk-G3T6YMBO.js → chunk-64S6X4IU.js} +7 -7
- package/dist/{chunk-CFCEJNOE.js → chunk-6KHF6PAB.js} +2 -2
- package/dist/{chunk-5GINB5LC.js → chunk-6MKLMEBE.js} +1 -1
- package/dist/{chunk-5GINB5LC.js.map → chunk-6MKLMEBE.js.map} +1 -1
- package/dist/{chunk-35A7GCHG.js → chunk-6T42L5FI.js} +2 -2
- package/dist/{chunk-JDOBIFBK.js → chunk-7CXL25AA.js} +2 -2
- package/dist/{chunk-YLBE6PLR.js → chunk-7IGMKQWK.js} +2 -2
- package/dist/{chunk-CSLK7BN6.js → chunk-7LYRFI5A.js} +2 -2
- package/dist/{chunk-IB63OVUB.js → chunk-AJ6ORARY.js} +6 -6
- package/dist/{chunk-CGOKNQDK.js → chunk-ANZXWOYD.js} +2 -2
- package/dist/{chunk-5QXMESS7.js → chunk-AXC7UTLM.js} +2 -2
- package/dist/{chunk-RFIJRZ4K.js → chunk-B657ZGDH.js} +2 -2
- package/dist/{chunk-AW4QUFQF.js → chunk-BTNNL7ZW.js} +3 -2
- package/dist/{chunk-AW4QUFQF.js.map → chunk-BTNNL7ZW.js.map} +1 -1
- package/dist/{chunk-MY7B3HYC.js → chunk-CLCMDKTB.js} +2 -2
- package/dist/{chunk-QPWUG2S3.js → chunk-CYEK6Z3P.js} +4 -4
- package/dist/{chunk-IHCYCE6D.js → chunk-DJMVSUPK.js} +4 -4
- package/dist/{chunk-HP4CU2ZA.js → chunk-DST7HRSG.js} +2 -2
- package/dist/{chunk-IIFFC3RL.js → chunk-EDR6CVWZ.js} +2 -2
- package/dist/{chunk-AUWMKDKL.js → chunk-EMVJU7WC.js} +2 -2
- package/dist/{chunk-O6AYMAPJ.js → chunk-ENNC3RZ6.js} +2 -2
- package/dist/{chunk-2JRB3Z5N.js → chunk-EP5WXE2G.js} +3 -3
- package/dist/{chunk-QLK3SL7Q.js → chunk-ETSJD5IV.js} +131 -12
- package/dist/chunk-ETSJD5IV.js.map +1 -0
- package/dist/chunk-EWMRFW3F.js +38 -0
- package/dist/chunk-EWMRFW3F.js.map +1 -0
- package/dist/{chunk-I2KEH2LS.js → chunk-FC6RCOIU.js} +2 -2
- package/dist/{chunk-OZVHLBH6.js → chunk-FLV7M7CT.js} +2 -2
- package/dist/{chunk-Q6GI7HEC.js → chunk-FRH2UC7Q.js} +2 -2
- package/dist/{chunk-3SL52JKD.js → chunk-FZVROZKC.js} +5 -5
- package/dist/{chunk-2EZB2DL5.js → chunk-GE6HETIF.js} +3 -3
- package/dist/{chunk-2DHJTJIY.js → chunk-GEGUBU3D.js} +2 -2
- package/dist/{chunk-6AA7XFMO.js → chunk-GF4H3B3R.js} +8 -8
- package/dist/{chunk-NGOZH7R5.js → chunk-GVUW5XK5.js} +311 -142
- package/dist/chunk-GVUW5XK5.js.map +1 -0
- package/dist/{chunk-ME2LMFHF.js → chunk-HPAOMYKM.js} +92 -92
- package/dist/{chunk-4NRZ7BRS.js → chunk-I25RINZK.js} +2 -2
- package/dist/{chunk-XG4XXI66.js → chunk-I25RQA65.js} +2 -2
- package/dist/chunk-I56MTWE7.js +80 -0
- package/dist/chunk-I56MTWE7.js.map +1 -0
- package/dist/{chunk-EJJMDLVB.js → chunk-IJ4FEGZR.js} +2 -2
- package/dist/{chunk-EUL3S3LE.js → chunk-J5WI4QRP.js} +4 -4
- package/dist/{chunk-LMMC55WM.js → chunk-JA54KIYD.js} +4 -4
- package/dist/{chunk-5FLFPTDK.js → chunk-JA72X46J.js} +2 -2
- package/dist/{chunk-6GU3TNJJ.js → chunk-JMF5Q4JY.js} +246 -49
- package/dist/chunk-JMF5Q4JY.js.map +1 -0
- package/dist/{chunk-IDSSDL4W.js → chunk-JXSYWTFK.js} +21 -4
- package/dist/{chunk-IDSSDL4W.js.map → chunk-JXSYWTFK.js.map} +1 -1
- package/dist/{chunk-NLYOOGZ7.js → chunk-KE5PWLI6.js} +3 -3
- package/dist/chunk-KIUVEMBI.js +49 -0
- package/dist/chunk-KIUVEMBI.js.map +1 -0
- package/dist/{chunk-4DDIWRT7.js → chunk-KQI2PKYP.js} +2 -2
- package/dist/{chunk-Y2ADLCB3.js → chunk-KSUOM3YU.js} +9 -9
- package/dist/{chunk-BTOHGPHC.js → chunk-KZEMFD6E.js} +3 -3
- package/dist/{chunk-NXVD46HT.js → chunk-L2VS27PZ.js} +4 -4
- package/dist/{chunk-MYYHACOW.js → chunk-L34W4W4I.js} +2 -2
- package/dist/{chunk-KRTIHXWC.js → chunk-L3PWXD73.js} +2 -2
- package/dist/{chunk-NQHSXHJP.js → chunk-L6GNS5GB.js} +2 -2
- package/dist/{chunk-44PBRUXB.js → chunk-M47Q6566.js} +2 -2
- package/dist/{chunk-E7FN5N5E.js → chunk-MQNOIH2C.js} +7 -7
- package/dist/{chunk-IDSZNHIP.js → chunk-MULNBSPP.js} +4 -4
- package/dist/{chunk-RKSGUMVL.js → chunk-NBQIFCJE.js} +2 -2
- package/dist/{chunk-I6WFBNA4.js → chunk-NHSVW7UT.js} +15 -15
- package/dist/{chunk-32HO62I4.js → chunk-OFEHITAZ.js} +2 -2
- package/dist/{chunk-PCO3P7WJ.js → chunk-OGVJXIHX.js} +2 -2
- package/dist/{chunk-RYN4AIRM.js → chunk-OZABSIOV.js} +4 -4
- package/dist/{chunk-HO7IQP7G.js → chunk-QMFKW4OU.js} +3 -3
- package/dist/{chunk-34G4U6HS.js → chunk-QRZMJ2WN.js} +2 -2
- package/dist/{chunk-RKDSELA3.js → chunk-QWWMS4AE.js} +1 -1
- package/dist/chunk-QWWMS4AE.js.map +1 -0
- package/dist/{chunk-GUD6FYQG.js → chunk-RSMIRLKM.js} +2 -2
- package/dist/{chunk-TNVZCLJU.js → chunk-S5TGRZWY.js} +2 -2
- package/dist/{chunk-O24EWFPQ.js → chunk-SNXBXYUE.js} +3 -3
- package/dist/{chunk-KW77LGDX.js → chunk-SUAX5JWY.js} +2 -2
- package/dist/{chunk-PNFWIB4X.js → chunk-SWRN6U7Q.js} +2 -2
- package/dist/{chunk-X6X4UASX.js → chunk-SZXPKUMN.js} +232 -83
- package/dist/chunk-SZXPKUMN.js.map +1 -0
- package/dist/{chunk-R4NGLTUS.js → chunk-TDMNADPI.js} +2 -2
- package/dist/{chunk-QCP75JGO.js → chunk-TFA6HPOA.js} +5 -5
- package/dist/{chunk-LI76ESJL.js → chunk-TZQOCQXB.js} +2 -2
- package/dist/{chunk-OV7EYM6M.js → chunk-U6OXJQEH.js} +12 -12
- package/dist/{chunk-OWHPA4JS.js → chunk-V32NHP2R.js} +2 -2
- package/dist/{chunk-JSUA4YFE.js → chunk-WG4TMZJ2.js} +2 -2
- package/dist/{chunk-DQTCGVFK.js → chunk-WHCD4Z3D.js} +2 -2
- package/dist/{chunk-GBA4N2SG.js → chunk-WRICYGYG.js} +27 -26
- package/dist/chunk-WRICYGYG.js.map +1 -0
- package/dist/{chunk-KATEWTQJ.js → chunk-X7J56GPG.js} +2 -2
- package/dist/{chunk-7KICGR5W.js → chunk-XPRAOTJY.js} +2 -2
- package/dist/{chunk-2NV7MMMM.js → chunk-XQSJXNWC.js} +2 -2
- package/dist/{chunk-22DYJLFN.js → chunk-XVC7JU2N.js} +39 -18
- package/dist/chunk-XVC7JU2N.js.map +1 -0
- package/dist/{chunk-RXT6UB25.js → chunk-YJAOYEWI.js} +2 -2
- package/dist/{chunk-L6DJJEFW.js → chunk-YJEUHGZZ.js} +2 -2
- package/dist/{chunk-AXFWMRKI.js → chunk-YQJCWR4R.js} +2 -2
- package/dist/cli.js +110 -108
- package/dist/coding/export-okf-codegraph.js +25 -25
- package/dist/compounding/engine.js +25 -25
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +31 -30
- package/dist/connectors/codex-materialize-runner.js +25 -25
- package/dist/connectors/index.js +25 -25
- package/dist/consolidation-provenance-check.js +2 -2
- package/dist/contradiction/index.js +7 -7
- package/dist/convergence-refresh.js +27 -27
- package/dist/conversation-index/backend.js +2 -2
- package/dist/corpus-read-cancellation.d.ts +7 -0
- package/dist/corpus-read-cancellation.d.ts.map +1 -1
- package/dist/corpus-read-cancellation.js +1 -1
- package/dist/corpus-watermark.js +27 -27
- package/dist/correction/correction-access-wiring.d.ts +6 -6
- package/dist/correction/correction-access-wiring.d.ts.map +1 -1
- package/dist/correction/correction-classify.d.ts +25 -0
- package/dist/correction/correction-classify.d.ts.map +1 -0
- package/dist/correction/correction-config.d.ts +11 -0
- package/dist/correction/correction-config.d.ts.map +1 -0
- package/dist/correction/correction-contract.d.ts +13 -1
- package/dist/correction/correction-contract.d.ts.map +1 -1
- package/dist/correction/correction-executor.d.ts +2 -0
- package/dist/correction/correction-executor.d.ts.map +1 -1
- package/dist/correction/correction-planner.d.ts +24 -3
- package/dist/correction/correction-planner.d.ts.map +1 -1
- package/dist/directory-sidecars.js +2 -2
- package/dist/entity-retrieval.js +25 -25
- package/dist/event-order-recall.js +2 -2
- package/dist/explicit-capture.js +2 -2
- package/dist/external-wiki-access.js +63 -63
- package/dist/extraction-span-materialize.js +2 -2
- package/dist/extraction.js +34 -34
- package/dist/harmonic-retrieval.js +25 -25
- package/dist/index.js +221 -218
- package/dist/lcm/index.js +3 -3
- package/dist/local-llm.d.ts.map +1 -1
- package/dist/local-llm.js +1 -1
- package/dist/location/index.js +28 -28
- package/dist/maintenance/archive-observations.js +2 -2
- package/dist/maintenance/atomic-file.d.ts +1 -1
- package/dist/maintenance/atomic-file.d.ts.map +1 -1
- package/dist/maintenance/atomic-file.js +1 -1
- package/dist/maintenance/memory-governance.js +25 -25
- package/dist/maintenance/migrate-observations.js +3 -3
- package/dist/maintenance/observation-ledger-utils.js +2 -2
- package/dist/maintenance/projection-rebuild-abort.d.ts +17 -0
- package/dist/maintenance/projection-rebuild-abort.d.ts.map +1 -0
- package/dist/maintenance/projection-timeline.d.ts +19 -0
- package/dist/maintenance/projection-timeline.d.ts.map +1 -0
- package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +25 -25
- package/dist/maintenance/rebuild-memory-projection-runner.d.ts +8 -0
- package/dist/maintenance/rebuild-memory-projection-runner.d.ts.map +1 -0
- package/dist/maintenance/rebuild-memory-projection-runner.js +113 -0
- package/dist/maintenance/rebuild-memory-projection-runner.js.map +1 -0
- package/dist/maintenance/rebuild-memory-projection.d.ts +8 -0
- package/dist/maintenance/rebuild-memory-projection.d.ts.map +1 -1
- package/dist/maintenance/rebuild-memory-projection.js +26 -26
- package/dist/maintenance/rebuild-observations.js +3 -3
- package/dist/memory-browse-operations.js +63 -63
- package/dist/memory-browse.js +7 -7
- package/dist/memory-subject.js +1 -1
- package/dist/namespaces/migrate.js +26 -26
- package/dist/namespaces/search.js +10 -10
- package/dist/namespaces/storage.js +25 -25
- package/dist/offline-sync-impression-drain.js +3 -3
- package/dist/operator-doctor-corpus.js +28 -28
- package/dist/operator-toolkit.js +41 -40
- package/dist/orchestration/full-corpus-heap-guard.d.ts +25 -0
- package/dist/orchestration/full-corpus-heap-guard.d.ts.map +1 -0
- package/dist/orchestration/maintenance.d.ts.map +1 -1
- package/dist/orchestration/maintenance.js +38 -36
- package/dist/orchestration/projection-rebuild-schedule.d.ts +40 -0
- package/dist/orchestration/projection-rebuild-schedule.d.ts.map +1 -1
- package/dist/orchestration/session-context.d.ts.map +1 -1
- package/dist/orchestrator.js +142 -139
- package/dist/projection-rebuild-config.d.ts +52 -0
- package/dist/projection-rebuild-config.d.ts.map +1 -0
- package/dist/projection-rebuild-config.js +14 -0
- package/dist/projection-rebuild-config.js.map +1 -0
- package/dist/qmd.js +4 -4
- 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 +63 -63
- package/dist/recall-navigation.js +62 -62
- package/dist/recall-state-view-admission.js +7 -7
- package/dist/recall-state.js +2 -2
- package/dist/recall-why-service.js +8 -8
- 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/relevance.js +2 -2
- package/dist/{resolution-RSG4HZTL.js → resolution-TV3F7ZTH.js} +7 -7
- package/dist/resolution-TV3F7ZTH.js.map +1 -0
- package/dist/resume-bundles.js +32 -31
- package/dist/salvage-envelope.js +1 -1
- package/dist/search/factory.js +9 -9
- package/dist/search/index.js +17 -17
- package/dist/semantic-consolidation.js +31 -31
- package/dist/semantic-rule-promotion.js +25 -25
- package/dist/semantic-rule-verifier.js +25 -25
- package/dist/source-agent-qualifier.js +29 -29
- package/dist/standup/build.js +25 -25
- package/dist/storage/memory-lifecycle-ledger-access.d.ts +5 -3
- package/dist/storage/memory-lifecycle-ledger-access.d.ts.map +1 -1
- package/dist/storage/memory-read-store.d.ts +2 -2
- package/dist/storage/memory-read-store.d.ts.map +1 -1
- package/dist/storage.d.ts +4 -2
- package/dist/storage.d.ts.map +1 -1
- package/dist/storage.js +24 -24
- package/dist/subject-config.js +1 -1
- package/dist/summarizer.js +3 -3
- package/dist/support-passport/index.js +78 -78
- package/dist/transfer/export-okf.js +26 -26
- package/dist/types.d.ts +8 -40
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +1 -1
- package/dist/verified-recall.js +25 -25
- package/dist/who-knows-cli.js +26 -26
- package/dist/who-knows.js +25 -25
- package/dist/write-envelope.js +1 -1
- package/package.json +2 -2
- package/src/access-cli.ts +4 -0
- package/src/access-http.ts +1 -0
- package/src/access-mcp-correction-tools.ts +56 -0
- package/src/access-mcp.ts +4 -49
- package/src/access-operations.ts +3 -0
- package/src/access-service.ts +12 -21
- package/src/config.test.ts +35 -0
- package/src/config.ts +6 -65
- package/src/corpus-read-cancellation.ts +7 -0
- package/src/correction/correction-access-wiring.ts +56 -16
- package/src/correction/correction-classify.test.ts +185 -0
- package/src/correction/correction-classify.ts +157 -0
- package/src/correction/correction-config.ts +93 -0
- package/src/correction/correction-contract.ts +61 -14
- package/src/correction/correction-executor.test.ts +102 -2
- package/src/correction/correction-executor.ts +19 -1
- package/src/correction/correction-planner.test.ts +141 -0
- package/src/correction/correction-planner.ts +117 -11
- package/src/correction/correction-surfaces.test.ts +22 -1
- package/src/local-llm-qos.test.ts +36 -0
- package/src/local-llm.ts +20 -3
- package/src/maintenance/atomic-file.ts +2 -0
- package/src/maintenance/projection-rebuild-abort.ts +40 -0
- package/src/maintenance/projection-timeline.ts +209 -0
- package/src/maintenance/rebuild-memory-projection-runner.ts +94 -0
- package/src/maintenance/rebuild-memory-projection.memory.test.ts +159 -0
- package/src/maintenance/rebuild-memory-projection.retain-raw.test.ts +202 -0
- package/src/maintenance/rebuild-memory-projection.ts +63 -91
- package/src/orchestration/full-corpus-heap-guard.ts +38 -0
- package/src/orchestration/maintenance.test.ts +2 -2
- package/src/orchestration/maintenance.ts +2 -0
- package/src/orchestration/projection-rebuild-schedule.test.ts +498 -0
- package/src/orchestration/projection-rebuild-schedule.ts +280 -9
- package/src/orchestration/session-context.ts +0 -15
- package/src/projection-rebuild-config.ts +82 -0
- package/src/recall-handles-wiring.test.ts +24 -0
- package/src/storage/memory-lifecycle-ledger-access.ts +61 -33
- package/src/storage/memory-read-store.ts +10 -4
- package/src/storage.ts +45 -33
- package/src/types.ts +8 -41
- package/dist/chunk-22DYJLFN.js.map +0 -1
- package/dist/chunk-6GU3TNJJ.js.map +0 -1
- package/dist/chunk-6JIHC5AS.js.map +0 -1
- package/dist/chunk-BLHPADUX.js.map +0 -1
- package/dist/chunk-CHI37EHP.js.map +0 -1
- package/dist/chunk-GBA4N2SG.js.map +0 -1
- package/dist/chunk-NGOZH7R5.js.map +0 -1
- package/dist/chunk-QLK3SL7Q.js.map +0 -1
- package/dist/chunk-RKDSELA3.js.map +0 -1
- package/dist/chunk-X6X4UASX.js.map +0 -1
- package/dist/chunk-ZS7RK6H6.js.map +0 -1
- /package/dist/{resolution-RSG4HZTL.js.map → access-mcp-correction-tools.js.map} +0 -0
- /package/dist/{auto-sync-PAWBFQWL.js.map → auto-sync-FN7E3OTO.js.map} +0 -0
- /package/dist/{chunk-YQSWNFZE.js.map → chunk-2CP577K6.js.map} +0 -0
- /package/dist/{chunk-345MEMRU.js.map → chunk-3OUGSOJP.js.map} +0 -0
- /package/dist/{chunk-G2STTRYB.js.map → chunk-4D2YH47Z.js.map} +0 -0
- /package/dist/{chunk-IXYIW3MZ.js.map → chunk-4K2H4KTR.js.map} +0 -0
- /package/dist/{chunk-UVVSOSHL.js.map → chunk-52CQKST6.js.map} +0 -0
- /package/dist/{chunk-H7BZBSP6.js.map → chunk-52II7PB6.js.map} +0 -0
- /package/dist/{chunk-2QZFZNXO.js.map → chunk-5CQO6LVM.js.map} +0 -0
- /package/dist/{chunk-NLDMTXWV.js.map → chunk-5LNPW7NE.js.map} +0 -0
- /package/dist/{chunk-WHTMVTU4.js.map → chunk-5X4ZJESN.js.map} +0 -0
- /package/dist/{chunk-WI37MWRZ.js.map → chunk-63UNVGZW.js.map} +0 -0
- /package/dist/{chunk-G3T6YMBO.js.map → chunk-64S6X4IU.js.map} +0 -0
- /package/dist/{chunk-CFCEJNOE.js.map → chunk-6KHF6PAB.js.map} +0 -0
- /package/dist/{chunk-35A7GCHG.js.map → chunk-6T42L5FI.js.map} +0 -0
- /package/dist/{chunk-JDOBIFBK.js.map → chunk-7CXL25AA.js.map} +0 -0
- /package/dist/{chunk-YLBE6PLR.js.map → chunk-7IGMKQWK.js.map} +0 -0
- /package/dist/{chunk-CSLK7BN6.js.map → chunk-7LYRFI5A.js.map} +0 -0
- /package/dist/{chunk-IB63OVUB.js.map → chunk-AJ6ORARY.js.map} +0 -0
- /package/dist/{chunk-CGOKNQDK.js.map → chunk-ANZXWOYD.js.map} +0 -0
- /package/dist/{chunk-5QXMESS7.js.map → chunk-AXC7UTLM.js.map} +0 -0
- /package/dist/{chunk-RFIJRZ4K.js.map → chunk-B657ZGDH.js.map} +0 -0
- /package/dist/{chunk-MY7B3HYC.js.map → chunk-CLCMDKTB.js.map} +0 -0
- /package/dist/{chunk-QPWUG2S3.js.map → chunk-CYEK6Z3P.js.map} +0 -0
- /package/dist/{chunk-IHCYCE6D.js.map → chunk-DJMVSUPK.js.map} +0 -0
- /package/dist/{chunk-HP4CU2ZA.js.map → chunk-DST7HRSG.js.map} +0 -0
- /package/dist/{chunk-IIFFC3RL.js.map → chunk-EDR6CVWZ.js.map} +0 -0
- /package/dist/{chunk-AUWMKDKL.js.map → chunk-EMVJU7WC.js.map} +0 -0
- /package/dist/{chunk-O6AYMAPJ.js.map → chunk-ENNC3RZ6.js.map} +0 -0
- /package/dist/{chunk-2JRB3Z5N.js.map → chunk-EP5WXE2G.js.map} +0 -0
- /package/dist/{chunk-I2KEH2LS.js.map → chunk-FC6RCOIU.js.map} +0 -0
- /package/dist/{chunk-OZVHLBH6.js.map → chunk-FLV7M7CT.js.map} +0 -0
- /package/dist/{chunk-Q6GI7HEC.js.map → chunk-FRH2UC7Q.js.map} +0 -0
- /package/dist/{chunk-3SL52JKD.js.map → chunk-FZVROZKC.js.map} +0 -0
- /package/dist/{chunk-2EZB2DL5.js.map → chunk-GE6HETIF.js.map} +0 -0
- /package/dist/{chunk-2DHJTJIY.js.map → chunk-GEGUBU3D.js.map} +0 -0
- /package/dist/{chunk-6AA7XFMO.js.map → chunk-GF4H3B3R.js.map} +0 -0
- /package/dist/{chunk-ME2LMFHF.js.map → chunk-HPAOMYKM.js.map} +0 -0
- /package/dist/{chunk-4NRZ7BRS.js.map → chunk-I25RINZK.js.map} +0 -0
- /package/dist/{chunk-XG4XXI66.js.map → chunk-I25RQA65.js.map} +0 -0
- /package/dist/{chunk-EJJMDLVB.js.map → chunk-IJ4FEGZR.js.map} +0 -0
- /package/dist/{chunk-EUL3S3LE.js.map → chunk-J5WI4QRP.js.map} +0 -0
- /package/dist/{chunk-LMMC55WM.js.map → chunk-JA54KIYD.js.map} +0 -0
- /package/dist/{chunk-5FLFPTDK.js.map → chunk-JA72X46J.js.map} +0 -0
- /package/dist/{chunk-NLYOOGZ7.js.map → chunk-KE5PWLI6.js.map} +0 -0
- /package/dist/{chunk-4DDIWRT7.js.map → chunk-KQI2PKYP.js.map} +0 -0
- /package/dist/{chunk-Y2ADLCB3.js.map → chunk-KSUOM3YU.js.map} +0 -0
- /package/dist/{chunk-BTOHGPHC.js.map → chunk-KZEMFD6E.js.map} +0 -0
- /package/dist/{chunk-NXVD46HT.js.map → chunk-L2VS27PZ.js.map} +0 -0
- /package/dist/{chunk-MYYHACOW.js.map → chunk-L34W4W4I.js.map} +0 -0
- /package/dist/{chunk-KRTIHXWC.js.map → chunk-L3PWXD73.js.map} +0 -0
- /package/dist/{chunk-NQHSXHJP.js.map → chunk-L6GNS5GB.js.map} +0 -0
- /package/dist/{chunk-44PBRUXB.js.map → chunk-M47Q6566.js.map} +0 -0
- /package/dist/{chunk-E7FN5N5E.js.map → chunk-MQNOIH2C.js.map} +0 -0
- /package/dist/{chunk-IDSZNHIP.js.map → chunk-MULNBSPP.js.map} +0 -0
- /package/dist/{chunk-RKSGUMVL.js.map → chunk-NBQIFCJE.js.map} +0 -0
- /package/dist/{chunk-I6WFBNA4.js.map → chunk-NHSVW7UT.js.map} +0 -0
- /package/dist/{chunk-32HO62I4.js.map → chunk-OFEHITAZ.js.map} +0 -0
- /package/dist/{chunk-PCO3P7WJ.js.map → chunk-OGVJXIHX.js.map} +0 -0
- /package/dist/{chunk-RYN4AIRM.js.map → chunk-OZABSIOV.js.map} +0 -0
- /package/dist/{chunk-HO7IQP7G.js.map → chunk-QMFKW4OU.js.map} +0 -0
- /package/dist/{chunk-34G4U6HS.js.map → chunk-QRZMJ2WN.js.map} +0 -0
- /package/dist/{chunk-GUD6FYQG.js.map → chunk-RSMIRLKM.js.map} +0 -0
- /package/dist/{chunk-TNVZCLJU.js.map → chunk-S5TGRZWY.js.map} +0 -0
- /package/dist/{chunk-O24EWFPQ.js.map → chunk-SNXBXYUE.js.map} +0 -0
- /package/dist/{chunk-KW77LGDX.js.map → chunk-SUAX5JWY.js.map} +0 -0
- /package/dist/{chunk-PNFWIB4X.js.map → chunk-SWRN6U7Q.js.map} +0 -0
- /package/dist/{chunk-R4NGLTUS.js.map → chunk-TDMNADPI.js.map} +0 -0
- /package/dist/{chunk-QCP75JGO.js.map → chunk-TFA6HPOA.js.map} +0 -0
- /package/dist/{chunk-LI76ESJL.js.map → chunk-TZQOCQXB.js.map} +0 -0
- /package/dist/{chunk-OV7EYM6M.js.map → chunk-U6OXJQEH.js.map} +0 -0
- /package/dist/{chunk-OWHPA4JS.js.map → chunk-V32NHP2R.js.map} +0 -0
- /package/dist/{chunk-JSUA4YFE.js.map → chunk-WG4TMZJ2.js.map} +0 -0
- /package/dist/{chunk-DQTCGVFK.js.map → chunk-WHCD4Z3D.js.map} +0 -0
- /package/dist/{chunk-KATEWTQJ.js.map → chunk-X7J56GPG.js.map} +0 -0
- /package/dist/{chunk-7KICGR5W.js.map → chunk-XPRAOTJY.js.map} +0 -0
- /package/dist/{chunk-2NV7MMMM.js.map → chunk-XQSJXNWC.js.map} +0 -0
- /package/dist/{chunk-RXT6UB25.js.map → chunk-YJAOYEWI.js.map} +0 -0
- /package/dist/{chunk-L6DJJEFW.js.map → chunk-YJEUHGZZ.js.map} +0 -0
- /package/dist/{chunk-AXFWMRKI.js.map → chunk-YQJCWR4R.js.map} +0 -0
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
*/
|
|
22
22
|
|
|
23
23
|
import path from "node:path";
|
|
24
|
-
import { throwIfAborted } from "../abort-error.js";
|
|
24
|
+
import { abortError, isAbortError, throwIfAborted } from "../abort-error.js";
|
|
25
25
|
import { composeMemoryEnvelope, isMemoryCategory } from "../write-envelope.js";
|
|
26
26
|
import { log } from "../logger.js";
|
|
27
27
|
import { createHash } from "node:crypto";
|
|
@@ -48,6 +48,7 @@ import {
|
|
|
48
48
|
} from "./correction-planner.js";
|
|
49
49
|
import { type ExecutorDeps, type ExecutorMemory } from "./correction-executor.js";
|
|
50
50
|
import { CorrectionService, type CorrectionServiceDeps } from "./correction-service.js";
|
|
51
|
+
import { completeCorrectionClassify } from "./correction-classify.js";
|
|
51
52
|
import { resolveRecallAuxiliaryCapabilities } from "../capabilities.js";
|
|
52
53
|
import { isSupportPassportPrivateMemory } from "../support-passport/card-projection.js";
|
|
53
54
|
|
|
@@ -81,15 +82,15 @@ export interface CorrectionAccessWiring {
|
|
|
81
82
|
principal?: string;
|
|
82
83
|
}): Promise<boolean>;
|
|
83
84
|
/**
|
|
84
|
-
* Optional
|
|
85
|
-
*
|
|
86
|
-
*
|
|
87
|
-
*
|
|
88
|
-
* ships with the safe fallback.
|
|
85
|
+
* Optional test override for classify+draft. Production leaves this unset
|
|
86
|
+
* and uses completeCorrectionClassify: a short per-attempt timeout, caller
|
|
87
|
+
* abort, then the gateway/fallback model. A caller abort propagates; every
|
|
88
|
+
* other failure becomes the deterministic empty-action plan.
|
|
89
89
|
*/
|
|
90
90
|
llmComplete?(request: {
|
|
91
91
|
system: string;
|
|
92
92
|
user: string;
|
|
93
|
+
abortSignal?: AbortSignal;
|
|
93
94
|
}): Promise<string>;
|
|
94
95
|
}
|
|
95
96
|
|
|
@@ -144,10 +145,12 @@ function makePlannerDeps(
|
|
|
144
145
|
searchMemories(wiring, text, namespaces, limit),
|
|
145
146
|
resolveTargets: async ({ targetIds, namespaces }) =>
|
|
146
147
|
resolveTargetMemories(wiring, targetIds, namespaces),
|
|
148
|
+
inspectMemory: async ({ memoryId, namespaces }) =>
|
|
149
|
+
inspectCorrectionMemory(wiring, memoryId, namespaces),
|
|
147
150
|
expandNeighbors: async ({ seedIds, namespaces, limit }) =>
|
|
148
151
|
expandEntityNeighbors(wiring, seedIds, namespaces, limit),
|
|
149
|
-
classifyAndDraft: async ({ text, candidates }) =>
|
|
150
|
-
classifyAndDraft(wiring, text, candidates),
|
|
152
|
+
classifyAndDraft: async ({ text, candidates, abortSignal }) =>
|
|
153
|
+
classifyAndDraft(wiring, text, candidates, abortSignal),
|
|
151
154
|
renderDiff: async ({ candidates, actions }) =>
|
|
152
155
|
renderCorrectionDiff(wiring, candidates, actions),
|
|
153
156
|
storageDir: async (namespace) => (await wiring.orchestrator.getStorage(namespace)).dir,
|
|
@@ -294,22 +297,54 @@ async function classifyAndDraft(
|
|
|
294
297
|
wiring: CorrectionAccessWiring,
|
|
295
298
|
text: string,
|
|
296
299
|
candidates: PlannerCandidate[],
|
|
300
|
+
abortSignal?: AbortSignal,
|
|
297
301
|
): Promise<LlmClassificationResult> {
|
|
298
|
-
//
|
|
299
|
-
//
|
|
300
|
-
//
|
|
302
|
+
// Injected llmComplete stays as a test override. Production uses
|
|
303
|
+
// completeCorrectionClassify: short timeout, caller abort, gateway fallback.
|
|
304
|
+
// Abort throws. Every other failure is the deterministic empty-action plan.
|
|
301
305
|
try {
|
|
302
|
-
|
|
303
|
-
return fallbackClassification(candidates, "no LLM client available");
|
|
304
|
-
}
|
|
306
|
+
throwIfAborted(abortSignal, "correction classify aborted");
|
|
305
307
|
const user = buildClassifyPrompt(text, candidates);
|
|
306
|
-
const raw =
|
|
308
|
+
const raw = wiring.llmComplete
|
|
309
|
+
? await wiring.llmComplete({ system: CLASSIFY_SYSTEM_PROMPT, user, abortSignal })
|
|
310
|
+
: await completeCorrectionClassify(
|
|
311
|
+
[
|
|
312
|
+
{ role: "system", content: CLASSIFY_SYSTEM_PROMPT },
|
|
313
|
+
{ role: "user", content: user },
|
|
314
|
+
],
|
|
315
|
+
{ config: wiring.orchestrator.config, localLlm: wiring.orchestrator.localLlm },
|
|
316
|
+
abortSignal,
|
|
317
|
+
);
|
|
318
|
+
if (raw == null) return fallbackClassification(candidates, "correction classify unavailable");
|
|
319
|
+
throwIfAborted(abortSignal, "correction classify aborted");
|
|
307
320
|
return parseClassifyResponse(raw, candidates);
|
|
308
321
|
} catch (err) {
|
|
322
|
+
if (isAbortError(err) || abortSignal?.aborted) {
|
|
323
|
+
throw isAbortError(err) ? err : abortError("correction classify aborted");
|
|
324
|
+
}
|
|
309
325
|
return fallbackClassification(candidates, `LLM unavailable: ${errMsg(err)}`);
|
|
310
326
|
}
|
|
311
327
|
}
|
|
312
328
|
|
|
329
|
+
async function inspectCorrectionMemory(
|
|
330
|
+
wiring: CorrectionAccessWiring,
|
|
331
|
+
memoryId: string,
|
|
332
|
+
namespaces: readonly string[],
|
|
333
|
+
): Promise<{ candidate: PlannerCandidate; status: string } | null> {
|
|
334
|
+
for (const ns of namespaces) {
|
|
335
|
+
const storage = await wiring.orchestrator.getStorage(ns);
|
|
336
|
+
const memory = await storage.getMemoryByIdIncludingArchived(memoryId);
|
|
337
|
+
if (!memory || memory.frontmatter.id !== memoryId) continue;
|
|
338
|
+
const candidate = toCandidate(memory, ns, 1);
|
|
339
|
+
if (isSupportPassportPrivateMemory(memory)) return { candidate, status: "ineligible" };
|
|
340
|
+
if (typeof memory.frontmatter.archivedAt === "string" && memory.frontmatter.archivedAt.length > 0) {
|
|
341
|
+
return { candidate, status: "archived" };
|
|
342
|
+
}
|
|
343
|
+
return { candidate, status: memory.frontmatter.status ?? "active" };
|
|
344
|
+
}
|
|
345
|
+
return null;
|
|
346
|
+
}
|
|
347
|
+
|
|
313
348
|
async function renderCorrectionDiff(
|
|
314
349
|
_wiring: CorrectionAccessWiring,
|
|
315
350
|
candidates: PlannerCandidate[],
|
|
@@ -339,7 +374,10 @@ async function renderCorrectionDiff(
|
|
|
339
374
|
function describeAfterState(action: CorrectionAction): string {
|
|
340
375
|
switch (action.kind) {
|
|
341
376
|
case "supersede":
|
|
342
|
-
return action.replacement?.content
|
|
377
|
+
return action.replacement?.content
|
|
378
|
+
?? (action.winnerId
|
|
379
|
+
? `(superseded by ${action.winnerId}; recoverable)`
|
|
380
|
+
: "(superseded without replacement)");
|
|
343
381
|
case "edit":
|
|
344
382
|
return action.patch;
|
|
345
383
|
case "retract":
|
|
@@ -899,6 +937,7 @@ function toExecutorMemory(m: MemoryFile): ExecutorMemory {
|
|
|
899
937
|
...(typeof fm.contentHash === "string" && fm.contentHash.length > 0
|
|
900
938
|
? { contentHash: fm.contentHash }
|
|
901
939
|
: {}),
|
|
940
|
+
status: fm.status ?? "active",
|
|
902
941
|
} satisfies ExecutorMemory;
|
|
903
942
|
}
|
|
904
943
|
|
|
@@ -987,6 +1026,7 @@ Given a correction statement and candidate memories, respond with a JSON object:
|
|
|
987
1026
|
|
|
988
1027
|
Action shapes:
|
|
989
1028
|
- {"kind":"supersede","loserId":"<id>","replacement":{"content":"<new fact>"}}
|
|
1029
|
+
- {"kind":"supersede","loserId":"<id>","winnerId":"<existing id>"}
|
|
990
1030
|
- {"kind":"edit","memoryId":"<id>","patch":"<new full content>"}
|
|
991
1031
|
- {"kind":"retract","memoryId":"<id>"}
|
|
992
1032
|
- {"kind":"rescope","memoryId":"<id>","toNamespace":"<ns>"}
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Correction classify completion: short timeout, caller abort, gateway fallback.
|
|
3
|
+
*/
|
|
4
|
+
import { strict as assert } from "node:assert";
|
|
5
|
+
import { test } from "node:test";
|
|
6
|
+
|
|
7
|
+
import { isAbortError } from "../abort-error.js";
|
|
8
|
+
import type { PluginConfig } from "../types.js";
|
|
9
|
+
import { type CorrectionClassifyDeps, completeCorrectionClassify } from "./correction-classify.js";
|
|
10
|
+
|
|
11
|
+
const MESSAGES = [{ role: "user" as const, content: "the old fact is a duplicate" }];
|
|
12
|
+
|
|
13
|
+
function config(over: Partial<PluginConfig> = {}): PluginConfig {
|
|
14
|
+
return {
|
|
15
|
+
localLlmEnabled: true,
|
|
16
|
+
localLlmFallback: true,
|
|
17
|
+
modelSource: "plugin",
|
|
18
|
+
correctionClassifyTimeoutMs: 40,
|
|
19
|
+
...over,
|
|
20
|
+
} as PluginConfig;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function hangUntilAbort(): CorrectionClassifyDeps["localLlm"] {
|
|
24
|
+
return {
|
|
25
|
+
chatCompletion: (_messages, options) =>
|
|
26
|
+
new Promise((resolve) => {
|
|
27
|
+
const finish = () => resolve(null);
|
|
28
|
+
if (options?.signal?.aborted) {
|
|
29
|
+
finish();
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
options?.signal?.addEventListener("abort", finish, { once: true });
|
|
33
|
+
}),
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
test("classify falls back after the local attempt times out", async () => {
|
|
38
|
+
let fallbackCalls = 0;
|
|
39
|
+
let localSignal: AbortSignal | undefined;
|
|
40
|
+
const deps: CorrectionClassifyDeps = {
|
|
41
|
+
config: config(),
|
|
42
|
+
localLlm: {
|
|
43
|
+
chatCompletion: (_messages, options) =>
|
|
44
|
+
new Promise((resolve) => {
|
|
45
|
+
localSignal = options?.signal;
|
|
46
|
+
const finish = () => resolve(null);
|
|
47
|
+
if (options?.signal?.aborted) {
|
|
48
|
+
finish();
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
options?.signal?.addEventListener("abort", finish, { once: true });
|
|
52
|
+
}),
|
|
53
|
+
},
|
|
54
|
+
fallbackChat: async () => {
|
|
55
|
+
fallbackCalls += 1;
|
|
56
|
+
return { content: '{"classification":"outdated","confidence":0.8,"actions":[]}', modelUsed: "gateway" };
|
|
57
|
+
},
|
|
58
|
+
};
|
|
59
|
+
const content = await completeCorrectionClassify(MESSAGES, deps);
|
|
60
|
+
assert.equal(fallbackCalls, 1);
|
|
61
|
+
assert.equal(localSignal?.aborted, true);
|
|
62
|
+
assert.match(content ?? "", /outdated/);
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
test("classify cancels on caller abort and does not call the fallback", async () => {
|
|
66
|
+
let fallbackCalls = 0;
|
|
67
|
+
const caller = new AbortController();
|
|
68
|
+
const deps: CorrectionClassifyDeps = {
|
|
69
|
+
config: config({ correctionClassifyTimeoutMs: 30_000 }),
|
|
70
|
+
localLlm: hangUntilAbort(),
|
|
71
|
+
fallbackChat: async () => {
|
|
72
|
+
fallbackCalls += 1;
|
|
73
|
+
return { content: "should-not-run", modelUsed: "gateway" };
|
|
74
|
+
},
|
|
75
|
+
};
|
|
76
|
+
const pending = completeCorrectionClassify(MESSAGES, deps, caller.signal);
|
|
77
|
+
caller.abort();
|
|
78
|
+
await assert.rejects(pending, (err: unknown) => isAbortError(err));
|
|
79
|
+
assert.equal(fallbackCalls, 0);
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
test("classify uses the fallback when the local LLM returns null", async () => {
|
|
83
|
+
let localCalls = 0;
|
|
84
|
+
let fallbackCalls = 0;
|
|
85
|
+
const deps: CorrectionClassifyDeps = {
|
|
86
|
+
config: config(),
|
|
87
|
+
localLlm: {
|
|
88
|
+
chatCompletion: async () => {
|
|
89
|
+
localCalls += 1;
|
|
90
|
+
return null;
|
|
91
|
+
},
|
|
92
|
+
},
|
|
93
|
+
fallbackChat: async () => {
|
|
94
|
+
fallbackCalls += 1;
|
|
95
|
+
return { content: '{"ok":true}', modelUsed: "gateway" };
|
|
96
|
+
},
|
|
97
|
+
};
|
|
98
|
+
const content = await completeCorrectionClassify(MESSAGES, deps);
|
|
99
|
+
assert.equal(localCalls, 1);
|
|
100
|
+
assert.equal(fallbackCalls, 1);
|
|
101
|
+
assert.equal(content, '{"ok":true}');
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
test("classify does not call the fallback when the local LLM returns content", async () => {
|
|
105
|
+
let fallbackCalls = 0;
|
|
106
|
+
const deps: CorrectionClassifyDeps = {
|
|
107
|
+
config: config(),
|
|
108
|
+
localLlm: { chatCompletion: async () => ({ content: "local-json" }) },
|
|
109
|
+
fallbackChat: async () => {
|
|
110
|
+
fallbackCalls += 1;
|
|
111
|
+
return { content: "gateway", modelUsed: "gateway" };
|
|
112
|
+
},
|
|
113
|
+
};
|
|
114
|
+
assert.equal(await completeCorrectionClassify(MESSAGES, deps), "local-json");
|
|
115
|
+
assert.equal(fallbackCalls, 0);
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
test("gateway modelSource skips the local LLM", async () => {
|
|
119
|
+
let localCalls = 0;
|
|
120
|
+
const deps: CorrectionClassifyDeps = {
|
|
121
|
+
config: config({ modelSource: "gateway", localLlmEnabled: true }),
|
|
122
|
+
localLlm: {
|
|
123
|
+
chatCompletion: async () => {
|
|
124
|
+
localCalls += 1;
|
|
125
|
+
return { content: "local" };
|
|
126
|
+
},
|
|
127
|
+
},
|
|
128
|
+
fallbackChat: async () => ({ content: "gateway-primary", modelUsed: "gateway" }),
|
|
129
|
+
};
|
|
130
|
+
assert.equal(await completeCorrectionClassify(MESSAGES, deps), "gateway-primary");
|
|
131
|
+
assert.equal(localCalls, 0);
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
test("no configured gateway models return null without waiting out the classify timeout", async () => {
|
|
135
|
+
const started = Date.now();
|
|
136
|
+
const content = await completeCorrectionClassify(MESSAGES, {
|
|
137
|
+
config: config({ localLlmEnabled: false }),
|
|
138
|
+
localLlm: {
|
|
139
|
+
chatCompletion: async () => {
|
|
140
|
+
throw new Error("local must not run");
|
|
141
|
+
},
|
|
142
|
+
},
|
|
143
|
+
});
|
|
144
|
+
assert.equal(content, null);
|
|
145
|
+
assert.ok(Date.now() - started < 1000, `no-models path took ${Date.now() - started}ms`);
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
test("a fallback attempt timeout returns null instead of an abort", async () => {
|
|
149
|
+
const deps: CorrectionClassifyDeps = {
|
|
150
|
+
config: config({ localLlmEnabled: false, correctionClassifyTimeoutMs: 40 }),
|
|
151
|
+
localLlm: {
|
|
152
|
+
chatCompletion: async () => {
|
|
153
|
+
throw new Error("local must not run");
|
|
154
|
+
},
|
|
155
|
+
},
|
|
156
|
+
fallbackChat: (_messages, options) =>
|
|
157
|
+
new Promise((_resolve, reject) => {
|
|
158
|
+
const fail = () => {
|
|
159
|
+
const err = new Error("fallback attempt aborted");
|
|
160
|
+
err.name = "AbortError";
|
|
161
|
+
reject(err);
|
|
162
|
+
};
|
|
163
|
+
if (options.signal?.aborted) {
|
|
164
|
+
fail();
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
167
|
+
options.signal?.addEventListener("abort", fail, { once: true });
|
|
168
|
+
}),
|
|
169
|
+
};
|
|
170
|
+
assert.equal(await completeCorrectionClassify(MESSAGES, deps), null);
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
test("localLlmFallback false does not call the gateway after a local miss", async () => {
|
|
174
|
+
let fallbackCalls = 0;
|
|
175
|
+
const deps: CorrectionClassifyDeps = {
|
|
176
|
+
config: config({ localLlmFallback: false }),
|
|
177
|
+
localLlm: { chatCompletion: async () => null },
|
|
178
|
+
fallbackChat: async () => {
|
|
179
|
+
fallbackCalls += 1;
|
|
180
|
+
return { content: "nope", modelUsed: "gateway" };
|
|
181
|
+
},
|
|
182
|
+
};
|
|
183
|
+
await assert.rejects(() => completeCorrectionClassify(MESSAGES, deps), /fallback disabled/);
|
|
184
|
+
assert.equal(fallbackCalls, 0);
|
|
185
|
+
});
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Correction classify completion: a short per-attempt budget, caller abort,
|
|
3
|
+
* and the same gateway/fallback client extraction uses when the local LLM
|
|
4
|
+
* is down or `modelSource` is `gateway`.
|
|
5
|
+
*
|
|
6
|
+
* Each attempt (local, then gateway) gets `correctionClassifyTimeoutMs`.
|
|
7
|
+
* A caller abort cancels the in-flight attempt and does not fall through.
|
|
8
|
+
* A local timeout, null, or error falls through when `localLlmFallback` is
|
|
9
|
+
* not false. Gateway mode skips the local client and uses the task chain
|
|
10
|
+
* as the primary path.
|
|
11
|
+
*/
|
|
12
|
+
import { abortError, isAbortError, throwIfAborted } from "../abort-error.js";
|
|
13
|
+
import { resolveLocalLlmCapabilities } from "../capabilities.js";
|
|
14
|
+
import { fallbackLlmRuntimeContextFromConfig } from "../fallback-llm-codex-subscription.js";
|
|
15
|
+
import {
|
|
16
|
+
FallbackLlmClient,
|
|
17
|
+
type FallbackLlmOptions,
|
|
18
|
+
type FallbackLlmResponse,
|
|
19
|
+
gatewayTaskChainOptions,
|
|
20
|
+
} from "../fallback-llm.js";
|
|
21
|
+
import type { LocalLlmChatCompletionOptions } from "../local-llm-helpers.js";
|
|
22
|
+
import type { PluginConfig } from "../types.js";
|
|
23
|
+
import { DEFAULT_CORRECTION_CLASSIFY_TIMEOUT_MS, MAX_CORRECTION_CLASSIFY_TIMEOUT_MS } from "./correction-config.js";
|
|
24
|
+
|
|
25
|
+
export interface CorrectionClassifyMessage {
|
|
26
|
+
role: "system" | "user" | "assistant";
|
|
27
|
+
content: string;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export interface CorrectionClassifyDeps {
|
|
31
|
+
config: PluginConfig;
|
|
32
|
+
localLlm: {
|
|
33
|
+
chatCompletion(
|
|
34
|
+
messages: Array<{ role: string; content: string }>,
|
|
35
|
+
options?: LocalLlmChatCompletionOptions
|
|
36
|
+
): Promise<{ content: string } | null>;
|
|
37
|
+
};
|
|
38
|
+
/**
|
|
39
|
+
* Test seam. Production builds a {@link FallbackLlmClient} from config.
|
|
40
|
+
* Returning null is the no-models fast path.
|
|
41
|
+
*/
|
|
42
|
+
fallbackChat?(
|
|
43
|
+
messages: CorrectionClassifyMessage[],
|
|
44
|
+
options: FallbackLlmOptions
|
|
45
|
+
): Promise<FallbackLlmResponse | null>;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export async function completeCorrectionClassify(
|
|
49
|
+
messages: CorrectionClassifyMessage[],
|
|
50
|
+
deps: CorrectionClassifyDeps,
|
|
51
|
+
abortSignal?: AbortSignal
|
|
52
|
+
): Promise<string | null> {
|
|
53
|
+
throwIfAborted(abortSignal, "correction classify aborted");
|
|
54
|
+
const timeoutMs = classifyTimeoutMs(deps.config);
|
|
55
|
+
const gatewayPrimary = deps.config.modelSource === "gateway";
|
|
56
|
+
const localEnabled = resolveLocalLlmCapabilities(deps.config).localLlm === true && !gatewayPrimary;
|
|
57
|
+
|
|
58
|
+
if (localEnabled) {
|
|
59
|
+
const localAttempt = startAttempt(abortSignal, timeoutMs);
|
|
60
|
+
try {
|
|
61
|
+
const local = await deps.localLlm.chatCompletion(messages, {
|
|
62
|
+
operation: "correction-classify",
|
|
63
|
+
priority: "background",
|
|
64
|
+
timeoutMs,
|
|
65
|
+
temperature: 0.2,
|
|
66
|
+
signal: localAttempt.signal,
|
|
67
|
+
});
|
|
68
|
+
if (abortSignal?.aborted) throw abortError("correction classify aborted");
|
|
69
|
+
if (local?.content) return local.content;
|
|
70
|
+
if (deps.config.localLlmFallback === false) {
|
|
71
|
+
throw new Error("correction classify: local LLM unavailable and fallback disabled");
|
|
72
|
+
}
|
|
73
|
+
} catch (err) {
|
|
74
|
+
if (abortSignal?.aborted) {
|
|
75
|
+
throw isAbortError(err) ? err : abortError("correction classify aborted");
|
|
76
|
+
}
|
|
77
|
+
// A timeout abort belongs to this attempt. Fall through unless the
|
|
78
|
+
// operator turned the gateway path off.
|
|
79
|
+
if (deps.config.localLlmFallback === false) {
|
|
80
|
+
if (isAbortError(err)) {
|
|
81
|
+
throw new Error("correction classify: local LLM timed out and fallback disabled");
|
|
82
|
+
}
|
|
83
|
+
throw err;
|
|
84
|
+
}
|
|
85
|
+
} finally {
|
|
86
|
+
localAttempt.dispose();
|
|
87
|
+
}
|
|
88
|
+
} else if (!gatewayPrimary && deps.config.localLlmFallback === false) {
|
|
89
|
+
throw new Error("correction classify: local LLM disabled and fallback disabled");
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
throwIfAborted(abortSignal, "correction classify aborted");
|
|
93
|
+
const fallbackAttempt = startAttempt(abortSignal, timeoutMs);
|
|
94
|
+
try {
|
|
95
|
+
const fallbackOptions: FallbackLlmOptions = {
|
|
96
|
+
temperature: 0.2,
|
|
97
|
+
timeoutMs,
|
|
98
|
+
signal: fallbackAttempt.signal,
|
|
99
|
+
...gatewayTaskChainOptions(deps.config),
|
|
100
|
+
};
|
|
101
|
+
const fallback = deps.fallbackChat
|
|
102
|
+
? await deps.fallbackChat(messages, fallbackOptions)
|
|
103
|
+
: await new FallbackLlmClient(
|
|
104
|
+
deps.config.gatewayConfig,
|
|
105
|
+
fallbackLlmRuntimeContextFromConfig(deps.config)
|
|
106
|
+
).chatCompletion(messages, fallbackOptions);
|
|
107
|
+
if (abortSignal?.aborted) throw abortError("correction classify aborted");
|
|
108
|
+
return fallback?.content ?? null;
|
|
109
|
+
} catch (err) {
|
|
110
|
+
// The attempt signal aborts on its own budget. That is a finished miss
|
|
111
|
+
// (empty plan), not a caller disconnect — only the caller signal skips
|
|
112
|
+
// the empty-plan path.
|
|
113
|
+
if (abortSignal?.aborted) {
|
|
114
|
+
throw isAbortError(err) ? err : abortError("correction classify aborted");
|
|
115
|
+
}
|
|
116
|
+
if (isAbortError(err)) return null;
|
|
117
|
+
throw err;
|
|
118
|
+
} finally {
|
|
119
|
+
fallbackAttempt.dispose();
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
function classifyTimeoutMs(config: PluginConfig): number {
|
|
124
|
+
const configured = config.correctionClassifyTimeoutMs;
|
|
125
|
+
if (
|
|
126
|
+
typeof configured === "number" &&
|
|
127
|
+
Number.isInteger(configured) &&
|
|
128
|
+
configured >= 1 &&
|
|
129
|
+
configured <= MAX_CORRECTION_CLASSIFY_TIMEOUT_MS
|
|
130
|
+
) {
|
|
131
|
+
return configured;
|
|
132
|
+
}
|
|
133
|
+
return DEFAULT_CORRECTION_CLASSIFY_TIMEOUT_MS;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
function startAttempt(
|
|
137
|
+
caller: AbortSignal | undefined,
|
|
138
|
+
timeoutMs: number
|
|
139
|
+
): { signal: AbortSignal; dispose: () => void } {
|
|
140
|
+
// A ref'd timer, not AbortSignal.timeout: that helper's timer is unref'd,
|
|
141
|
+
// so a classify wait would not keep a short-lived caller alive until the
|
|
142
|
+
// budget elapses.
|
|
143
|
+
const controller = new AbortController();
|
|
144
|
+
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
145
|
+
const onCaller = (): void => controller.abort();
|
|
146
|
+
if (caller?.aborted) controller.abort();
|
|
147
|
+
else caller?.addEventListener("abort", onCaller, { once: true });
|
|
148
|
+
let disposed = false;
|
|
149
|
+
const dispose = (): void => {
|
|
150
|
+
if (disposed) return;
|
|
151
|
+
disposed = true;
|
|
152
|
+
clearTimeout(timer);
|
|
153
|
+
caller?.removeEventListener("abort", onCaller);
|
|
154
|
+
};
|
|
155
|
+
controller.signal.addEventListener("abort", dispose, { once: true });
|
|
156
|
+
return { signal: controller.signal, dispose };
|
|
157
|
+
}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Correction-contract config (issue #1580 plus classify timeout).
|
|
3
|
+
*
|
|
4
|
+
* Extracted from config.ts so the grandfathered parser file does not grow.
|
|
5
|
+
* Nested `correction.<key>` wins over the flat `correction<Key>` legacy key.
|
|
6
|
+
* Invalid values throw — they are never clamped or silently defaulted.
|
|
7
|
+
*
|
|
8
|
+
* Reads stay inline on `cfg` so the parsed-key extractor records the same
|
|
9
|
+
* paths the plugin schema declares.
|
|
10
|
+
*/
|
|
11
|
+
import { coerceBool, coerceNumber } from "../connectors/coerce.js";
|
|
12
|
+
|
|
13
|
+
export const DEFAULT_CORRECTION_CLASSIFY_TIMEOUT_MS = 45_000;
|
|
14
|
+
export const MAX_CORRECTION_CLASSIFY_TIMEOUT_MS = 300_000;
|
|
15
|
+
|
|
16
|
+
export interface ParsedCorrectionConfig {
|
|
17
|
+
correctionEnabled: boolean;
|
|
18
|
+
correctionApplyRequiresConfirm: boolean;
|
|
19
|
+
correctionMaxAffected: number;
|
|
20
|
+
correctionPlanTtlHours: number;
|
|
21
|
+
correctionClassifyTimeoutMs: number;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export function parseCorrectionConfig(cfg: Record<string, unknown>): ParsedCorrectionConfig {
|
|
25
|
+
return {
|
|
26
|
+
correctionEnabled: (() => {
|
|
27
|
+
const nested = (cfg.correction as Record<string, unknown> | undefined)?.enabled;
|
|
28
|
+
const raw = nested !== undefined ? nested : cfg.correctionEnabled;
|
|
29
|
+
if (raw === undefined || raw === null) return true;
|
|
30
|
+
const value = coerceBool(raw);
|
|
31
|
+
if (value === undefined) {
|
|
32
|
+
throw new Error(`Invalid correction.enabled: expected a boolean, got ${JSON.stringify(raw)}`);
|
|
33
|
+
}
|
|
34
|
+
return value;
|
|
35
|
+
})(),
|
|
36
|
+
correctionApplyRequiresConfirm: (() => {
|
|
37
|
+
const nested = (cfg.correction as Record<string, unknown> | undefined)?.applyRequiresConfirm;
|
|
38
|
+
const raw = nested !== undefined ? nested : cfg.correctionApplyRequiresConfirm;
|
|
39
|
+
if (raw === undefined || raw === null) return true;
|
|
40
|
+
const value = coerceBool(raw);
|
|
41
|
+
if (value === undefined) {
|
|
42
|
+
throw new Error(`Invalid correction.applyRequiresConfirm: expected a boolean, got ${JSON.stringify(raw)}`);
|
|
43
|
+
}
|
|
44
|
+
return value;
|
|
45
|
+
})(),
|
|
46
|
+
correctionMaxAffected: (() => {
|
|
47
|
+
const rawNested = (cfg.correction as Record<string, unknown> | undefined)?.maxAffected;
|
|
48
|
+
const raw = rawNested !== undefined ? rawNested : cfg.correctionMaxAffected;
|
|
49
|
+
if (raw === undefined || raw === null) return 10;
|
|
50
|
+
const n = coerceNumber(raw);
|
|
51
|
+
if (n === undefined || !Number.isFinite(n) || n < 1 || !Number.isInteger(n)) {
|
|
52
|
+
throw new Error(`Invalid correction.maxAffected: expected an integer >= 1, got ${JSON.stringify(raw)}`);
|
|
53
|
+
}
|
|
54
|
+
return n;
|
|
55
|
+
})(),
|
|
56
|
+
correctionPlanTtlHours: (() => {
|
|
57
|
+
const nested = (cfg.correction as Record<string, unknown> | undefined)?.planTtlHours;
|
|
58
|
+
const fromNested = nested !== undefined ? coerceNumber(nested) : undefined;
|
|
59
|
+
if (fromNested !== undefined && fromNested >= 1) return fromNested;
|
|
60
|
+
if (nested !== undefined && fromNested === undefined) {
|
|
61
|
+
throw new Error(`Invalid correction.planTtlHours: expected a number >= 1, got ${JSON.stringify(nested)}`);
|
|
62
|
+
}
|
|
63
|
+
if (fromNested !== undefined && fromNested < 1) {
|
|
64
|
+
throw new Error(`Invalid correction.planTtlHours: expected a number >= 1, got ${JSON.stringify(nested)}`);
|
|
65
|
+
}
|
|
66
|
+
const fromFlat = coerceNumber(cfg.correctionPlanTtlHours);
|
|
67
|
+
if (fromFlat !== undefined && fromFlat >= 1) return fromFlat;
|
|
68
|
+
if (cfg.correctionPlanTtlHours !== undefined && fromFlat === undefined) {
|
|
69
|
+
throw new Error(
|
|
70
|
+
`Invalid correction.planTtlHours: expected a number >= 1, got ${JSON.stringify(cfg.correctionPlanTtlHours)}`
|
|
71
|
+
);
|
|
72
|
+
}
|
|
73
|
+
if (fromFlat !== undefined && fromFlat < 1) {
|
|
74
|
+
throw new Error(
|
|
75
|
+
`Invalid correction.planTtlHours: expected a number >= 1, got ${JSON.stringify(cfg.correctionPlanTtlHours)}`
|
|
76
|
+
);
|
|
77
|
+
}
|
|
78
|
+
return 24;
|
|
79
|
+
})(),
|
|
80
|
+
correctionClassifyTimeoutMs: (() => {
|
|
81
|
+
const nested = (cfg.correction as Record<string, unknown> | undefined)?.classifyTimeoutMs;
|
|
82
|
+
const raw = nested !== undefined ? nested : cfg.correctionClassifyTimeoutMs;
|
|
83
|
+
if (raw === undefined || raw === null) return DEFAULT_CORRECTION_CLASSIFY_TIMEOUT_MS;
|
|
84
|
+
const n = coerceNumber(raw);
|
|
85
|
+
if (n === undefined || !Number.isInteger(n) || n < 1 || n > MAX_CORRECTION_CLASSIFY_TIMEOUT_MS) {
|
|
86
|
+
throw new Error(
|
|
87
|
+
`Invalid correction.classifyTimeoutMs: expected an integer from 1 to ${MAX_CORRECTION_CLASSIFY_TIMEOUT_MS}, got ${JSON.stringify(raw)}`
|
|
88
|
+
);
|
|
89
|
+
}
|
|
90
|
+
return n;
|
|
91
|
+
})(),
|
|
92
|
+
};
|
|
93
|
+
}
|