@remnic/core 1.0.2 → 1.1.0
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/LICENSE +21 -0
- package/README.md +1 -0
- package/dist/abort-error.d.ts +32 -0
- package/dist/abort-error.js +11 -0
- package/dist/access-cli.d.ts +13 -3
- package/dist/access-cli.js +96 -80
- package/dist/access-cli.js.map +1 -1
- package/dist/access-http.d.ts +12 -4
- package/dist/access-http.js +25 -18
- package/dist/access-mcp.d.ts +32 -4
- package/dist/access-mcp.js +16 -1
- package/dist/access-schema.d.ts +28 -28
- package/dist/access-schema.js +1 -1
- package/dist/access-service-HmO1Trrx.d.ts +732 -0
- package/dist/access-service.d.ts +15 -601
- package/dist/access-service.js +21 -15
- package/dist/active-memory-bridge.d.ts +66 -0
- package/dist/active-memory-bridge.js +11 -0
- package/dist/active-memory-bridge.js.map +1 -0
- package/dist/active-recall.d.ts +96 -0
- package/dist/active-recall.js +308 -0
- package/dist/active-recall.js.map +1 -0
- package/dist/behavior-learner.js +1 -1
- package/dist/bootstrap.d.ts +6 -3
- package/dist/bootstrap.js +2 -2
- package/dist/boxes.js +2 -2
- package/dist/briefing.d.ts +169 -0
- package/dist/briefing.js +52 -0
- package/dist/briefing.js.map +1 -0
- package/dist/buffer.d.ts +19 -5
- package/dist/buffer.js +2 -2
- package/dist/calibration.js +6 -6
- package/dist/causal-behavior.js +5 -5
- package/dist/causal-chain.js +3 -3
- package/dist/causal-consolidation.d.ts +22 -2
- package/dist/causal-consolidation.js +36 -9
- package/dist/causal-consolidation.js.map +1 -1
- package/dist/causal-retrieval.js +6 -6
- package/dist/causal-trajectory-graph.js +1 -1
- package/dist/causal-trajectory.d.ts +14 -1
- package/dist/causal-trajectory.js +5 -1
- package/dist/{chunk-KWBU5S5U.js → chunk-2ODBA7MQ.js} +9 -3
- package/dist/chunk-2ODBA7MQ.js.map +1 -0
- package/dist/{chunk-ZJLY4QSU.js → chunk-37UIFYWO.js} +130 -6
- package/dist/chunk-37UIFYWO.js.map +1 -0
- package/dist/chunk-3PG3H5TD.js +7 -0
- package/dist/chunk-3PG3H5TD.js.map +1 -0
- package/dist/{chunk-NTTLPF7F.js → chunk-3QFQGRHO.js} +5 -5
- package/dist/{chunk-QDOSNLB4.js → chunk-3QHL5ABG.js} +17 -15
- package/dist/chunk-3QHL5ABG.js.map +1 -0
- package/dist/{chunk-6UJQNRIO.js → chunk-3SV6CQHO.js} +92 -33
- package/dist/chunk-3SV6CQHO.js.map +1 -0
- package/dist/{chunk-U4PV25RD.js → chunk-3WHVNEN7.js} +1 -1
- package/dist/chunk-3WHVNEN7.js.map +1 -0
- package/dist/{chunk-XUHI52HK.js → chunk-44ICJRF3.js} +98 -10
- package/dist/chunk-44ICJRF3.js.map +1 -0
- package/dist/{chunk-HG2NKWR2.js → chunk-47UU5PU2.js} +49 -10
- package/dist/chunk-47UU5PU2.js.map +1 -0
- package/dist/chunk-4DJQYKMN.js +187 -0
- package/dist/chunk-4DJQYKMN.js.map +1 -0
- package/dist/chunk-4KAN3GZ3.js +225 -0
- package/dist/chunk-4KAN3GZ3.js.map +1 -0
- package/dist/chunk-4LACOVZX.js +813 -0
- package/dist/chunk-4LACOVZX.js.map +1 -0
- package/dist/{chunk-ORZMT74A.js → chunk-4NRAJUDS.js} +11 -1
- package/dist/chunk-4NRAJUDS.js.map +1 -0
- package/dist/{chunk-B7LOFDVE.js → chunk-4WMCPJWX.js} +8 -3
- package/dist/chunk-4WMCPJWX.js.map +1 -0
- package/dist/{chunk-G3AG3KZN.js → chunk-5IZL4DCV.js} +2 -2
- package/dist/{chunk-BRK4ODMI.js → chunk-5NPGSAVB.js} +2 -2
- package/dist/{chunk-QANCTXQF.js → chunk-6LX5ORAS.js} +3 -3
- package/dist/chunk-6MKAMLQL.js +16 -0
- package/dist/chunk-6MKAMLQL.js.map +1 -0
- package/dist/{chunk-ESSMF2FR.js → chunk-6PFRXT4K.js} +15 -6
- package/dist/chunk-6PFRXT4K.js.map +1 -0
- package/dist/{chunk-UIYZ5T3I.js → chunk-6UJ47TVX.js} +8 -8
- package/dist/chunk-6ZH4TU6I.js +245 -0
- package/dist/chunk-6ZH4TU6I.js.map +1 -0
- package/dist/{chunk-L5RPWGFK.js → chunk-7DHTMOND.js} +2 -2
- package/dist/{chunk-L7WO3MZ4.js → chunk-7ECD5ATE.js} +2 -2
- package/dist/{chunk-Q6FETXJA.js → chunk-7SEAZFFB.js} +2 -2
- package/dist/{chunk-V4YC4LUK.js → chunk-7WQ6SLIE.js} +175 -63
- package/dist/chunk-7WQ6SLIE.js.map +1 -0
- package/dist/chunk-ALXMCZEU.js +332 -0
- package/dist/chunk-ALXMCZEU.js.map +1 -0
- package/dist/{chunk-TVVVQQAK.js → chunk-BLKTA7MM.js} +58 -24
- package/dist/chunk-BLKTA7MM.js.map +1 -0
- package/dist/{chunk-SCHEKPYH.js → chunk-C2EFFULQ.js} +1 -1
- package/dist/{chunk-GJR6D6KC.js → chunk-D654IBA6.js} +2 -2
- package/dist/{chunk-OTFNI3OO.js → chunk-DEPL3635.js} +1828 -401
- package/dist/chunk-DEPL3635.js.map +1 -0
- package/dist/{chunk-UYSKNO6E.js → chunk-DHHP2Z4X.js} +15 -4
- package/dist/chunk-DHHP2Z4X.js.map +1 -0
- package/dist/{chunk-UV2FO7J4.js → chunk-E6K4NIEU.js} +2 -2
- package/dist/{chunk-T4WRIV2C.js → chunk-EABGC2TL.js} +2 -2
- package/dist/chunk-EJI5XIBB.js +232 -0
- package/dist/chunk-EJI5XIBB.js.map +1 -0
- package/dist/{chunk-ONRU4L2N.js → chunk-FEMOX5AD.js} +2 -2
- package/dist/{chunk-IFFFR3MR.js → chunk-FSFEQI74.js} +3 -3
- package/dist/chunk-G4SK7DSQ.js +121 -0
- package/dist/chunk-G4SK7DSQ.js.map +1 -0
- package/dist/{chunk-WWIQTB2Y.js → chunk-GGD5W7TB.js} +9 -2
- package/dist/chunk-GGD5W7TB.js.map +1 -0
- package/dist/{chunk-QWUUMMIK.js → chunk-GV6NLQ4X.js} +1355 -80
- package/dist/chunk-GV6NLQ4X.js.map +1 -0
- package/dist/{chunk-2PO5ZRKV.js → chunk-GZCUW5IC.js} +16 -3
- package/dist/chunk-GZCUW5IC.js.map +1 -0
- package/dist/{chunk-AAI7JARD.js → chunk-HMDCOMYU.js} +8 -11
- package/dist/chunk-HMDCOMYU.js.map +1 -0
- package/dist/chunk-IQT3XTKW.js +121 -0
- package/dist/chunk-IQT3XTKW.js.map +1 -0
- package/dist/{chunk-J3BT33K7.js → chunk-ITRLGI2T.js} +5 -5
- package/dist/{chunk-BDFZXRSO.js → chunk-J4IYOZZ5.js} +15 -2
- package/dist/chunk-J4IYOZZ5.js.map +1 -0
- package/dist/{chunk-J47FNDR7.js → chunk-JIU55F3X.js} +7 -7
- package/dist/{chunk-MDDAA2AO.js → chunk-JL2PU6AI.js} +17 -6
- package/dist/chunk-JL2PU6AI.js.map +1 -0
- package/dist/{chunk-ZKYI7UVO.js → chunk-JR4ZC3G4.js} +2 -2
- package/dist/{chunk-UCYSTFZR.js → chunk-JRNQ3RNA.js} +2 -2
- package/dist/{chunk-GPGBSNKM.js → chunk-K4FLSOR5.js} +2 -2
- package/dist/chunk-KVE7R4CG.js +320 -0
- package/dist/chunk-KVE7R4CG.js.map +1 -0
- package/dist/chunk-LAYN4LDC.js +267 -0
- package/dist/chunk-LAYN4LDC.js.map +1 -0
- package/dist/{chunk-ISY75RLM.js → chunk-MBJHSA7F.js} +344 -7
- package/dist/chunk-MBJHSA7F.js.map +1 -0
- package/dist/{chunk-PGK3VUHN.js → chunk-MTLYEMJB.js} +3 -2
- package/dist/chunk-MTLYEMJB.js.map +1 -0
- package/dist/{chunk-QY2BHY5O.js → chunk-MVTHXUBX.js} +297 -34
- package/dist/chunk-MVTHXUBX.js.map +1 -0
- package/dist/{chunk-LP47L3ZX.js → chunk-N42IWANG.js} +5 -5
- package/dist/{chunk-YNI4S5WT.js → chunk-N53K2EXC.js} +2 -2
- package/dist/{chunk-763GUIOU.js → chunk-NBNN5GOB.js} +2 -2
- package/dist/{chunk-CXWFUJR2.js → chunk-NQEVYWX6.js} +195 -5
- package/dist/chunk-NQEVYWX6.js.map +1 -0
- package/dist/{chunk-KL4CP4SB.js → chunk-O5ETUNBT.js} +17 -5
- package/dist/chunk-O5ETUNBT.js.map +1 -0
- package/dist/{chunk-OOSWAUYB.js → chunk-ODWDQNRE.js} +2 -2
- package/dist/chunk-OIT5QGG4.js +80 -0
- package/dist/chunk-OIT5QGG4.js.map +1 -0
- package/dist/{chunk-HLBYLYRD.js → chunk-PAORGQRI.js} +70 -13
- package/dist/chunk-PAORGQRI.js.map +1 -0
- package/dist/chunk-PVGDJXVK.js +21 -0
- package/dist/chunk-PVGDJXVK.js.map +1 -0
- package/dist/{chunk-OTAVQCSF.js → chunk-PYXS46O7.js} +2 -2
- package/dist/chunk-QDW3E4RD.js +108 -0
- package/dist/chunk-QDW3E4RD.js.map +1 -0
- package/dist/{chunk-YNCQ7E4M.js → chunk-QDYXG4CS.js} +4 -3
- package/dist/chunk-QDYXG4CS.js.map +1 -0
- package/dist/{chunk-HLXVTBF3.js → chunk-QNJMBKFK.js} +3 -2
- package/dist/chunk-QNJMBKFK.js.map +1 -0
- package/dist/{chunk-4A24LIM2.js → chunk-S75M5ZRK.js} +2 -2
- package/dist/chunk-SYUK3VLY.js +789 -0
- package/dist/chunk-SYUK3VLY.js.map +1 -0
- package/dist/{chunk-QCCCQT3O.js → chunk-TBBDFYXW.js} +2 -2
- package/dist/chunk-TBBDFYXW.js.map +1 -0
- package/dist/chunk-U66YHYC7.js +31 -0
- package/dist/chunk-U66YHYC7.js.map +1 -0
- package/dist/{chunk-MWGVGUIS.js → chunk-UEYA6UC7.js} +36 -4
- package/dist/chunk-UEYA6UC7.js.map +1 -0
- package/dist/{chunk-M5KEYE5E.js → chunk-URB2WSKZ.js} +2 -2
- package/dist/chunk-UVJFDP7P.js +202 -0
- package/dist/chunk-UVJFDP7P.js.map +1 -0
- package/dist/chunk-W6SL7OFG.js +180 -0
- package/dist/chunk-W6SL7OFG.js.map +1 -0
- package/dist/chunk-WBSAYXVI.js +7945 -0
- package/dist/chunk-WBSAYXVI.js.map +1 -0
- package/dist/{chunk-M5ZBBBJI.js → chunk-XZ2TIKGC.js} +39 -9
- package/dist/chunk-XZ2TIKGC.js.map +1 -0
- package/dist/chunk-Y4FHOFJ2.js +140 -0
- package/dist/chunk-Y4FHOFJ2.js.map +1 -0
- package/dist/chunk-YDBIWGNI.js +298 -0
- package/dist/chunk-YDBIWGNI.js.map +1 -0
- package/dist/chunk-YNB73F22.js +137 -0
- package/dist/chunk-YNB73F22.js.map +1 -0
- package/dist/{chunk-IZME7KW2.js → chunk-ZVBB3T7V.js} +31 -12
- package/dist/chunk-ZVBB3T7V.js.map +1 -0
- package/dist/chunking.js +1 -1
- package/dist/citations.d.ts +67 -0
- package/dist/citations.js +13 -0
- package/dist/citations.js.map +1 -0
- package/dist/cli-BneVIEvh.d.ts +1240 -0
- package/dist/cli.d.ts +32 -1147
- package/dist/cli.js +150 -7092
- package/dist/cli.js.map +1 -1
- package/dist/codex-materialize-CQlLTzke.d.ts +139 -0
- package/dist/codex-thread-key.d.ts +3 -0
- package/dist/codex-thread-key.js +7 -0
- package/dist/codex-thread-key.js.map +1 -0
- package/dist/config.js +3 -2
- package/dist/connectors/codex/instructions.md +160 -0
- package/dist/connectors/codex/resources/namespace-cheatsheet.md +48 -0
- package/dist/contradiction-review-WIUBAR52.js +21 -0
- package/dist/contradiction-review-WIUBAR52.js.map +1 -0
- package/dist/contradiction-scan-GR33PONM.js +376 -0
- package/dist/contradiction-scan-GR33PONM.js.map +1 -0
- package/dist/day-summary.d.ts +7 -2
- package/dist/day-summary.js +5 -2
- package/dist/direct-answer-wiring.d.ts +77 -0
- package/dist/direct-answer-wiring.js +75 -0
- package/dist/direct-answer-wiring.js.map +1 -0
- package/dist/direct-answer.d.ts +106 -0
- package/dist/direct-answer.js +10 -0
- package/dist/direct-answer.js.map +1 -0
- package/dist/embedding-fallback.d.ts +96 -2
- package/dist/embedding-fallback.js +6 -4
- package/dist/{engine-2A6J4XEX.js → engine-5TIQBYZR.js} +10 -7
- package/dist/engine-5TIQBYZR.js.map +1 -0
- package/dist/entity-retrieval.d.ts +3 -2
- package/dist/entity-retrieval.js +10 -7
- package/dist/entity-schema.d.ts +11 -0
- package/dist/entity-schema.js +19 -0
- package/dist/entity-schema.js.map +1 -0
- package/dist/explicit-capture.d.ts +6 -3
- package/dist/explicit-capture.js +2 -2
- package/dist/extraction-judge.d.ts +66 -0
- package/dist/extraction-judge.js +18 -0
- package/dist/extraction-judge.js.map +1 -0
- package/dist/extraction.d.ts +1 -0
- package/dist/extraction.js +12 -10
- package/dist/fallback-llm.d.ts +11 -2
- package/dist/fallback-llm.js +4 -4
- package/dist/graph.js +1 -1
- package/dist/harmonic-retrieval.js +2 -1
- package/dist/importance.d.ts +11 -1
- package/dist/importance.js +3 -1
- package/dist/index.d.ts +1027 -9
- package/dist/index.js +3303 -349
- package/dist/index.js.map +1 -1
- package/dist/intent.d.ts +2 -1
- package/dist/intent.js +3 -1
- package/dist/lifecycle.js +1 -1
- package/dist/local-llm.d.ts +10 -3
- package/dist/local-llm.js +2 -2
- package/dist/logger.d.ts +1 -1
- package/dist/logger.js +1 -1
- package/dist/memory-cache.d.ts +2 -2
- package/dist/memory-cache.js +1 -1
- package/dist/{memory-projection-store-NxMkbocT.d.ts → memory-projection-store-DeSXPh1j.d.ts} +1 -1
- package/dist/memory-projection-store.d.ts +1 -1
- package/dist/model-registry.js +2 -2
- package/dist/models-json.js +2 -2
- package/dist/native-knowledge.js +2 -2
- package/dist/negative.js +2 -2
- package/dist/operator-toolkit.js +20 -15
- package/dist/{orchestrator-zTa-Qo-1.d.ts → orchestrator-DRYA6_lW.d.ts} +273 -9
- package/dist/orchestrator.d.ts +6 -3
- package/dist/orchestrator.js +76 -63
- package/dist/page-versioning.d.ts +77 -0
- package/dist/page-versioning.js +15 -0
- package/dist/page-versioning.js.map +1 -0
- package/dist/plugin-id.d.ts +37 -0
- package/dist/plugin-id.js +11 -0
- package/dist/plugin-id.js.map +1 -0
- package/dist/policy-runtime.js +2 -2
- package/dist/profiling.js +2 -2
- package/dist/qmd.d.ts +5 -2
- package/dist/qmd.js +4 -3
- package/dist/recall-audit.d.ts +20 -0
- package/dist/recall-audit.js +50 -0
- package/dist/recall-audit.js.map +1 -0
- package/dist/recall-mmr.d.ts +152 -0
- package/dist/recall-mmr.js +17 -0
- package/dist/recall-mmr.js.map +1 -0
- package/dist/recall-qos.js +2 -2
- package/dist/recall-state.d.ts +28 -1
- package/dist/recall-state.js +2 -2
- package/dist/relevance.js +2 -2
- package/dist/resolution-QBTDHTG7.js +100 -0
- package/dist/resolution-QBTDHTG7.js.map +1 -0
- package/dist/resolve-provider-secret.d.ts +24 -1
- package/dist/resolve-provider-secret.js +4 -2
- package/dist/resume-bundles.js +6 -5
- package/dist/retrieval-agents.js +2 -2
- package/dist/retrieval.js +2 -2
- package/dist/schemas.d.ts +412 -54
- package/dist/schemas.js +3 -1
- package/dist/sdk-compat.d.ts +2 -0
- package/dist/sdk-compat.js +6 -3
- package/dist/sdk-compat.js.map +1 -1
- package/dist/semantic-chunking.d.ts +87 -0
- package/dist/semantic-chunking.js +20 -0
- package/dist/semantic-chunking.js.map +1 -0
- package/dist/semantic-consolidation-DrvSYRdB.d.ts +119 -0
- package/dist/semantic-consolidation.d.ts +4 -42
- package/dist/semantic-consolidation.js +23 -2
- package/dist/semantic-rule-promotion.js +9 -6
- package/dist/semantic-rule-verifier.js +10 -7
- package/dist/session-observer-state.js +2 -2
- package/dist/session-toggles.d.ts +22 -0
- package/dist/session-toggles.js +116 -0
- package/dist/session-toggles.js.map +1 -0
- package/dist/skills-registry.d.ts +47 -0
- package/dist/skills-registry.js +48 -0
- package/dist/skills-registry.js.map +1 -0
- package/dist/source-attribution.d.ts +169 -0
- package/dist/source-attribution.js +27 -0
- package/dist/source-attribution.js.map +1 -0
- package/dist/storage.d.ts +171 -10
- package/dist/storage.js +16 -5
- package/dist/summarizer.js +7 -7
- package/dist/temporal-supersession.d.ts +127 -0
- package/dist/temporal-supersession.js +20 -0
- package/dist/temporal-supersession.js.map +1 -0
- package/dist/threading.js +2 -2
- package/dist/tier-migration.d.ts +2 -1
- package/dist/tier-routing.js +2 -2
- package/dist/tokens.d.ts +21 -1
- package/dist/tokens.js +5 -1
- package/dist/transcript.js +2 -2
- package/dist/types-DJhqDJUV.d.ts +50 -0
- package/dist/types.d.ts +529 -3
- package/dist/types.js +1 -1
- package/dist/utility-learner.js +2 -2
- package/dist/utility-runtime.js +3 -3
- package/dist/verified-recall.js +11 -8
- package/dist/whitespace.d.ts +4 -0
- package/dist/whitespace.js +9 -0
- package/dist/whitespace.js.map +1 -0
- package/package.json +14 -8
- package/dist/chunk-2CJCWDMR.js +0 -87
- package/dist/chunk-2CJCWDMR.js.map +0 -1
- package/dist/chunk-2PO5ZRKV.js.map +0 -1
- package/dist/chunk-6UJQNRIO.js.map +0 -1
- package/dist/chunk-AAI7JARD.js.map +0 -1
- package/dist/chunk-B7LOFDVE.js.map +0 -1
- package/dist/chunk-BDFZXRSO.js.map +0 -1
- package/dist/chunk-CXWFUJR2.js.map +0 -1
- package/dist/chunk-DORBM6OB.js +0 -81
- package/dist/chunk-DORBM6OB.js.map +0 -1
- package/dist/chunk-ESSMF2FR.js.map +0 -1
- package/dist/chunk-HG2NKWR2.js.map +0 -1
- package/dist/chunk-HLBYLYRD.js.map +0 -1
- package/dist/chunk-HLXVTBF3.js.map +0 -1
- package/dist/chunk-ISY75RLM.js.map +0 -1
- package/dist/chunk-IZME7KW2.js.map +0 -1
- package/dist/chunk-KL4CP4SB.js.map +0 -1
- package/dist/chunk-KWBU5S5U.js.map +0 -1
- package/dist/chunk-M5ZBBBJI.js.map +0 -1
- package/dist/chunk-MDDAA2AO.js.map +0 -1
- package/dist/chunk-MWGVGUIS.js.map +0 -1
- package/dist/chunk-ORZMT74A.js.map +0 -1
- package/dist/chunk-OTFNI3OO.js.map +0 -1
- package/dist/chunk-PGK3VUHN.js.map +0 -1
- package/dist/chunk-QCCCQT3O.js.map +0 -1
- package/dist/chunk-QDOSNLB4.js.map +0 -1
- package/dist/chunk-QPKFPHOO.js +0 -178
- package/dist/chunk-QPKFPHOO.js.map +0 -1
- package/dist/chunk-QWUUMMIK.js.map +0 -1
- package/dist/chunk-QY2BHY5O.js.map +0 -1
- package/dist/chunk-TVVVQQAK.js.map +0 -1
- package/dist/chunk-U4PV25RD.js.map +0 -1
- package/dist/chunk-UYSKNO6E.js.map +0 -1
- package/dist/chunk-V4YC4LUK.js.map +0 -1
- package/dist/chunk-WWIQTB2Y.js.map +0 -1
- package/dist/chunk-XUHI52HK.js.map +0 -1
- package/dist/chunk-YNCQ7E4M.js.map +0 -1
- package/dist/chunk-ZJLY4QSU.js.map +0 -1
- /package/dist/{engine-2A6J4XEX.js.map → abort-error.js.map} +0 -0
- /package/dist/{chunk-NTTLPF7F.js.map → chunk-3QFQGRHO.js.map} +0 -0
- /package/dist/{chunk-G3AG3KZN.js.map → chunk-5IZL4DCV.js.map} +0 -0
- /package/dist/{chunk-BRK4ODMI.js.map → chunk-5NPGSAVB.js.map} +0 -0
- /package/dist/{chunk-QANCTXQF.js.map → chunk-6LX5ORAS.js.map} +0 -0
- /package/dist/{chunk-UIYZ5T3I.js.map → chunk-6UJ47TVX.js.map} +0 -0
- /package/dist/{chunk-L5RPWGFK.js.map → chunk-7DHTMOND.js.map} +0 -0
- /package/dist/{chunk-L7WO3MZ4.js.map → chunk-7ECD5ATE.js.map} +0 -0
- /package/dist/{chunk-Q6FETXJA.js.map → chunk-7SEAZFFB.js.map} +0 -0
- /package/dist/{chunk-SCHEKPYH.js.map → chunk-C2EFFULQ.js.map} +0 -0
- /package/dist/{chunk-GJR6D6KC.js.map → chunk-D654IBA6.js.map} +0 -0
- /package/dist/{chunk-UV2FO7J4.js.map → chunk-E6K4NIEU.js.map} +0 -0
- /package/dist/{chunk-T4WRIV2C.js.map → chunk-EABGC2TL.js.map} +0 -0
- /package/dist/{chunk-ONRU4L2N.js.map → chunk-FEMOX5AD.js.map} +0 -0
- /package/dist/{chunk-IFFFR3MR.js.map → chunk-FSFEQI74.js.map} +0 -0
- /package/dist/{chunk-J3BT33K7.js.map → chunk-ITRLGI2T.js.map} +0 -0
- /package/dist/{chunk-J47FNDR7.js.map → chunk-JIU55F3X.js.map} +0 -0
- /package/dist/{chunk-ZKYI7UVO.js.map → chunk-JR4ZC3G4.js.map} +0 -0
- /package/dist/{chunk-UCYSTFZR.js.map → chunk-JRNQ3RNA.js.map} +0 -0
- /package/dist/{chunk-GPGBSNKM.js.map → chunk-K4FLSOR5.js.map} +0 -0
- /package/dist/{chunk-LP47L3ZX.js.map → chunk-N42IWANG.js.map} +0 -0
- /package/dist/{chunk-YNI4S5WT.js.map → chunk-N53K2EXC.js.map} +0 -0
- /package/dist/{chunk-763GUIOU.js.map → chunk-NBNN5GOB.js.map} +0 -0
- /package/dist/{chunk-OOSWAUYB.js.map → chunk-ODWDQNRE.js.map} +0 -0
- /package/dist/{chunk-OTAVQCSF.js.map → chunk-PYXS46O7.js.map} +0 -0
- /package/dist/{chunk-4A24LIM2.js.map → chunk-S75M5ZRK.js.map} +0 -0
- /package/dist/{chunk-M5KEYE5E.js.map → chunk-URB2WSKZ.js.map} +0 -0
|
@@ -1,26 +1,28 @@
|
|
|
1
1
|
import {
|
|
2
2
|
getGatewayRuntimeAuthForModel,
|
|
3
3
|
resolveProviderApiKey
|
|
4
|
-
} from "./chunk-
|
|
5
|
-
import {
|
|
6
|
-
loadModelsJsonProviders
|
|
7
|
-
} from "./chunk-OOSWAUYB.js";
|
|
4
|
+
} from "./chunk-XZ2TIKGC.js";
|
|
8
5
|
import {
|
|
9
6
|
buildChatCompletionTokenLimit,
|
|
10
7
|
shouldAssumeOpenAiChatCompletions
|
|
11
8
|
} from "./chunk-Y27UJK6V.js";
|
|
9
|
+
import {
|
|
10
|
+
loadModelsJsonProviders
|
|
11
|
+
} from "./chunk-ODWDQNRE.js";
|
|
12
12
|
import {
|
|
13
13
|
extractJsonCandidates
|
|
14
14
|
} from "./chunk-UZB5KHKX.js";
|
|
15
15
|
import {
|
|
16
16
|
log
|
|
17
|
-
} from "./chunk-
|
|
17
|
+
} from "./chunk-2ODBA7MQ.js";
|
|
18
18
|
|
|
19
19
|
// src/fallback-llm.ts
|
|
20
20
|
var FallbackLlmClient = class {
|
|
21
21
|
gatewayConfig;
|
|
22
|
-
|
|
22
|
+
runtimeContext;
|
|
23
|
+
constructor(gatewayConfig, runtimeContext = {}) {
|
|
23
24
|
this.gatewayConfig = gatewayConfig;
|
|
25
|
+
this.runtimeContext = runtimeContext;
|
|
24
26
|
}
|
|
25
27
|
/**
|
|
26
28
|
* Check if fallback is available (gateway config has at least one model).
|
|
@@ -222,6 +224,14 @@ var FallbackLlmClient = class {
|
|
|
222
224
|
if (model.providerConfig.api === "anthropic-messages") {
|
|
223
225
|
return await this.callAnthropic(effectiveConfig, model.modelId, messages, options);
|
|
224
226
|
}
|
|
227
|
+
if (model.providerConfig.api === "openai-responses" || model.providerConfig.api === "openai-codex-responses" || model.providerConfig.api === "azure-openai-responses") {
|
|
228
|
+
return await this.callOpenAIResponses(
|
|
229
|
+
effectiveConfig,
|
|
230
|
+
model.modelId,
|
|
231
|
+
messages,
|
|
232
|
+
options
|
|
233
|
+
);
|
|
234
|
+
}
|
|
225
235
|
return await this.callOpenAI(
|
|
226
236
|
effectiveConfig,
|
|
227
237
|
model.modelId,
|
|
@@ -246,7 +256,8 @@ var FallbackLlmClient = class {
|
|
|
246
256
|
api: model.providerConfig.api,
|
|
247
257
|
baseUrl: model.providerConfig.baseUrl
|
|
248
258
|
},
|
|
249
|
-
cfg: this.gatewayConfig
|
|
259
|
+
cfg: this.gatewayConfig,
|
|
260
|
+
workspaceDir: this.runtimeContext.workspaceDir
|
|
250
261
|
});
|
|
251
262
|
if (result?.apiKey || result?.baseUrl) {
|
|
252
263
|
log.debug(
|
|
@@ -266,7 +277,12 @@ var FallbackLlmClient = class {
|
|
|
266
277
|
* secret refs, etc.). Used as fallback when gateway runtime auth isn't available.
|
|
267
278
|
*/
|
|
268
279
|
async resolveFallbackApiKey(model) {
|
|
269
|
-
return resolveProviderApiKey(
|
|
280
|
+
return resolveProviderApiKey(
|
|
281
|
+
model.providerId,
|
|
282
|
+
model.providerConfig.apiKey,
|
|
283
|
+
this.gatewayConfig,
|
|
284
|
+
this.runtimeContext.agentDir
|
|
285
|
+
);
|
|
270
286
|
}
|
|
271
287
|
/**
|
|
272
288
|
* Call OpenAI-compatible API.
|
|
@@ -314,11 +330,65 @@ var FallbackLlmClient = class {
|
|
|
314
330
|
} : void 0
|
|
315
331
|
};
|
|
316
332
|
}
|
|
333
|
+
/**
|
|
334
|
+
* Call an OpenAI-compatible Responses API.
|
|
335
|
+
*/
|
|
336
|
+
async callOpenAIResponses(config, modelId, messages, options) {
|
|
337
|
+
const base = config.baseUrl.replace(/\/$/, "");
|
|
338
|
+
const url = base.endsWith("/v1") ? `${base}/responses` : `${base}/v1/responses`;
|
|
339
|
+
const headers = {
|
|
340
|
+
"Content-Type": "application/json",
|
|
341
|
+
...config.headers
|
|
342
|
+
};
|
|
343
|
+
if (config.apiKey && typeof config.apiKey === "string" && config.authHeader !== false) {
|
|
344
|
+
headers["Authorization"] = `Bearer ${config.apiKey}`;
|
|
345
|
+
}
|
|
346
|
+
const instructions = messages.filter((message) => message.role === "system").map((message) => message.content).join("\n\n").trim();
|
|
347
|
+
const input = messages.filter((message) => message.role !== "system").map((message) => ({
|
|
348
|
+
role: message.role,
|
|
349
|
+
content: [{
|
|
350
|
+
type: message.role === "assistant" ? "output_text" : "input_text",
|
|
351
|
+
text: message.content
|
|
352
|
+
}]
|
|
353
|
+
}));
|
|
354
|
+
const body = {
|
|
355
|
+
model: modelId,
|
|
356
|
+
input,
|
|
357
|
+
max_output_tokens: Math.max(0, Math.floor(options.maxTokens ?? 4096)),
|
|
358
|
+
temperature: options.temperature ?? 0.3
|
|
359
|
+
};
|
|
360
|
+
if (instructions.length > 0) {
|
|
361
|
+
body.instructions = instructions;
|
|
362
|
+
}
|
|
363
|
+
const response = await fetch(url, {
|
|
364
|
+
method: "POST",
|
|
365
|
+
headers,
|
|
366
|
+
body: JSON.stringify(body)
|
|
367
|
+
});
|
|
368
|
+
if (!response.ok) {
|
|
369
|
+
const error = await response.text();
|
|
370
|
+
throw new Error(`OpenAI Responses API error: ${response.status} ${error}`);
|
|
371
|
+
}
|
|
372
|
+
const data = await response.json();
|
|
373
|
+
const outputText = extractResponsesOutputText(data);
|
|
374
|
+
if (!outputText) {
|
|
375
|
+
throw new Error("Empty response from OpenAI Responses API");
|
|
376
|
+
}
|
|
377
|
+
return {
|
|
378
|
+
content: outputText,
|
|
379
|
+
usage: data.usage ? {
|
|
380
|
+
inputTokens: data.usage.input_tokens,
|
|
381
|
+
outputTokens: data.usage.output_tokens,
|
|
382
|
+
totalTokens: data.usage.total_tokens
|
|
383
|
+
} : void 0
|
|
384
|
+
};
|
|
385
|
+
}
|
|
317
386
|
/**
|
|
318
387
|
* Call Anthropic Messages API.
|
|
319
388
|
*/
|
|
320
389
|
async callAnthropic(config, modelId, messages, options) {
|
|
321
|
-
const
|
|
390
|
+
const base = config.baseUrl.replace(/\/$/, "");
|
|
391
|
+
const url = base.endsWith("/v1") ? `${base}/messages` : `${base}/v1/messages`;
|
|
322
392
|
const headers = {
|
|
323
393
|
"Content-Type": "application/json",
|
|
324
394
|
"anthropic-version": "2023-06-01",
|
|
@@ -366,8 +436,26 @@ var FallbackLlmClient = class {
|
|
|
366
436
|
};
|
|
367
437
|
}
|
|
368
438
|
};
|
|
439
|
+
function extractResponsesOutputText(data) {
|
|
440
|
+
if (typeof data.output_text === "string" && data.output_text.trim().length > 0) {
|
|
441
|
+
return data.output_text;
|
|
442
|
+
}
|
|
443
|
+
const chunks = [];
|
|
444
|
+
for (const item of data.output ?? []) {
|
|
445
|
+
if (typeof item.text === "string" && item.text.trim().length > 0) {
|
|
446
|
+
chunks.push(item.text);
|
|
447
|
+
}
|
|
448
|
+
for (const part of item.content ?? []) {
|
|
449
|
+
if ((part.type === "output_text" || part.type === "text") && typeof part.text === "string" && part.text.trim().length > 0) {
|
|
450
|
+
chunks.push(part.text);
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
const joined = chunks.join("\n").trim();
|
|
455
|
+
return joined.length > 0 ? joined : null;
|
|
456
|
+
}
|
|
369
457
|
|
|
370
458
|
export {
|
|
371
459
|
FallbackLlmClient
|
|
372
460
|
};
|
|
373
|
-
//# sourceMappingURL=chunk-
|
|
461
|
+
//# sourceMappingURL=chunk-44ICJRF3.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/fallback-llm.ts"],"sourcesContent":["import { log } from \"./logger.js\";\nimport type { GatewayConfig, ModelProviderConfig, AgentPersona } from \"./types.js\";\nimport { extractJsonCandidates } from \"./json-extract.js\";\nimport {\n buildChatCompletionTokenLimit,\n shouldAssumeOpenAiChatCompletions,\n} from \"./openai-chat-compat.js\";\nimport { resolveProviderApiKey, getGatewayRuntimeAuthForModel } from \"./resolve-provider-secret.js\";\nimport { loadModelsJsonProviders } from \"./models-json.js\";\n\nexport interface FallbackLlmOptions {\n temperature?: number;\n maxTokens?: number;\n timeoutMs?: number;\n /** Override which agent persona's model chain to use (by ID from agents.list[]). */\n agentId?: string;\n}\n\nexport interface FallbackLlmResponse {\n content: string;\n modelUsed: string;\n usage?: {\n inputTokens?: number;\n outputTokens?: number;\n totalTokens?: number;\n };\n}\n\nexport interface FallbackLlmRuntimeContext {\n agentDir?: string;\n workspaceDir?: string;\n}\n\ninterface ModelRef {\n providerId: string;\n modelId: string;\n providerConfig: ModelProviderConfig;\n modelString: string;\n}\n\n/**\n * Generic fallback LLM client that uses the gateway's default AI configuration\n * and walks through the full fallback chain (primary + fallbacks).\n * Supports OpenAI and Anthropic API formats.\n */\nexport class FallbackLlmClient {\n private gatewayConfig: GatewayConfig | undefined;\n private runtimeContext: FallbackLlmRuntimeContext;\n\n constructor(\n gatewayConfig?: GatewayConfig,\n runtimeContext: FallbackLlmRuntimeContext = {},\n ) {\n this.gatewayConfig = gatewayConfig;\n this.runtimeContext = runtimeContext;\n }\n\n /**\n * Check if fallback is available (gateway config has at least one model).\n */\n isAvailable(agentId?: string): boolean {\n const models = this.getModelChain(agentId);\n return models.length > 0;\n }\n\n /**\n * Make a chat completion request using the gateway's default AI chain.\n * Tries primary first, then each fallback in order.\n * When agentId is provided, uses that agent persona's model chain instead of defaults.\n */\n async chatCompletion(\n messages: Array<{ role: \"system\" | \"user\" | \"assistant\"; content: string }>,\n options: FallbackLlmOptions = {},\n ): Promise<FallbackLlmResponse | null> {\n const models = this.getModelChain(options.agentId);\n if (models.length === 0) {\n log.warn(\"fallback LLM: no models configured in gateway\");\n return null;\n }\n\n const runChain = async (): Promise<FallbackLlmResponse | null> => {\n // Try each model in the chain\n for (let i = 0; i < models.length; i++) {\n const model = models[i];\n const isFallback = i > 0;\n\n try {\n const result = await this.tryModel(model, messages, options);\n if (result) {\n if (isFallback) {\n log.debug(`fallback LLM: succeeded using ${model.modelString} (fallback ${i})`);\n }\n return {\n content: result.content,\n modelUsed: model.modelString,\n usage: result.usage,\n };\n }\n } catch (err) {\n const errorMsg = err instanceof Error ? err.message : String(err);\n log.debug(`fallback LLM: ${model.modelString} failed (${errorMsg}), trying next...`);\n // Continue to next model in chain\n }\n }\n\n log.warn(`fallback LLM: all ${models.length} models in chain failed`);\n return null;\n };\n\n if (typeof options.timeoutMs === \"number\") {\n if (options.timeoutMs <= 0) {\n log.warn(\"fallback LLM: timed out before request started\");\n return null;\n }\n let timeoutHandle: ReturnType<typeof setTimeout> | undefined;\n try {\n return await Promise.race([\n runChain(),\n new Promise<null>((resolve) => {\n timeoutHandle = setTimeout(() => {\n log.warn(`fallback LLM: timed out after ${options.timeoutMs}ms`);\n resolve(null);\n }, options.timeoutMs);\n }),\n ]);\n } finally {\n if (timeoutHandle) clearTimeout(timeoutHandle);\n }\n }\n\n return await runChain();\n }\n\n /**\n * Make a request with structured output (Zod schema).\n * Returns parsed JSON or null on failure.\n */\n async parseWithSchema<T>(\n messages: Array<{ role: \"system\" | \"user\" | \"assistant\"; content: string }>,\n schema: { parse: (data: unknown) => T },\n options: FallbackLlmOptions = {},\n ): Promise<T | null> {\n const detailed = await this.parseWithSchemaDetailed(messages, schema, options);\n return detailed?.result ?? null;\n }\n\n /**\n * Like parseWithSchema but also returns the model that was used,\n * so callers can emit accurate trace events.\n */\n async parseWithSchemaDetailed<T>(\n messages: Array<{ role: \"system\" | \"user\" | \"assistant\"; content: string }>,\n schema: { parse: (data: unknown) => T },\n options: FallbackLlmOptions = {},\n ): Promise<{ result: T; modelUsed: string } | null> {\n const response = await this.chatCompletion(messages, options);\n if (!response?.content) return null;\n\n try {\n const candidates = extractJsonCandidates(response.content);\n for (const c of candidates) {\n try {\n const parsed = JSON.parse(c);\n return { result: schema.parse(parsed), modelUsed: response.modelUsed };\n } catch {\n // keep trying other candidates\n }\n }\n return null;\n } catch (err) {\n log.warn(\"fallback LLM: failed to parse structured output:\", err);\n return null;\n }\n }\n\n /**\n * Get the full model chain from gateway config.\n * Returns array of models in order: [primary, fallback1, fallback2, ...]\n *\n * When agentId is provided, looks up the matching entry in agents.list[]\n * and uses that persona's model chain. Falls back to agents.defaults.model\n * if agentId is not found or not provided.\n */\n private getModelChain(agentId?: string): ModelRef[] {\n const chain: ModelRef[] = [];\n const providers = this.gatewayConfig?.models?.providers ?? {};\n\n // Resolve the model config: agent persona chain or global defaults\n let modelConfig: { primary?: string; fallbacks?: string[] } | undefined;\n\n if (agentId) {\n const persona = this.gatewayConfig?.agents?.list?.find(\n (a) => a.id === agentId,\n );\n if (persona?.model) {\n modelConfig = persona.model;\n log.debug(`fallback LLM: using agent persona \"${agentId}\" model chain`);\n } else {\n log.warn(\n `fallback LLM: agent persona \"${agentId}\" not found or has no model config, falling back to defaults`,\n );\n }\n }\n\n if (!modelConfig) {\n modelConfig = this.gatewayConfig?.agents?.defaults?.model;\n }\n\n // Build list of model strings: primary + fallbacks\n const modelStrings: string[] = [];\n\n if (modelConfig?.primary) {\n modelStrings.push(modelConfig.primary);\n }\n\n if (Array.isArray(modelConfig?.fallbacks)) {\n for (const fb of modelConfig.fallbacks) {\n if (typeof fb === \"string\" && !modelStrings.includes(fb)) {\n modelStrings.push(fb);\n }\n }\n }\n\n // Parse each model string and look up provider config\n for (const modelString of modelStrings) {\n const modelRef = this.parseModelString(modelString, providers);\n if (modelRef) {\n chain.push(modelRef);\n }\n }\n\n return chain;\n }\n\n /**\n * Parse a \"provider/model\" string and look up its config.\n */\n private parseModelString(\n modelString: string,\n providers: Record<string, ModelProviderConfig>,\n ): ModelRef | null {\n // Parse \"provider/model\" format (e.g., \"openai/gpt-5.2\", \"anthropic/claude-opus-4-6\")\n const parts = modelString.split(\"/\");\n if (parts.length < 2) {\n log.warn(`fallback LLM: invalid model format: ${modelString}`);\n return null;\n }\n\n const providerId = parts[0];\n const modelId = parts.slice(1).join(\"/\"); // Handle cases like \"openai/gpt-5.2-turbo\"\n\n // Respect the active gateway config first so profile-local overrides and\n // credentials win. Fall back to the materialized models.json only when\n // the provider is absent from the loaded config (for built-in providers\n // registered by the gateway at runtime).\n const providerConfig = providers[providerId] ?? this.resolveFromModelsJson(providerId);\n if (!providerConfig) {\n log.warn(`fallback LLM: provider not found: ${providerId}`);\n return null;\n }\n\n return { providerId, modelId, providerConfig, modelString };\n }\n\n /**\n * Look up a provider from the gateway's materialized models.json, which\n * contains all providers including built-in ones (openai-codex, google-vertex,\n * etc.) that aren't in the user's openclaw.json but are registered by\n * gateway plugins. Returns null if the provider isn't found there either.\n */\n private resolveFromModelsJson(providerId: string): ModelProviderConfig | null {\n const allProviders = loadModelsJsonProviders();\n const config = allProviders[providerId];\n if (config) {\n log.debug(`fallback LLM: resolved provider \"${providerId}\" from models.json (api: ${config.api ?? \"default\"})`);\n return config;\n }\n return null;\n }\n\n /**\n * Try to call a single model.\n *\n * Uses the gateway's native getRuntimeAuthForModel when available — this\n * handles all provider-specific auth transforms (OAuth token exchange,\n * base URL overrides for codex/copilot/etc.) through the same codepath\n * the gateway itself uses. Falls back to resolveProviderApiKey for\n * simpler providers or when the runtime module isn't loaded.\n */\n private async tryModel(\n model: ModelRef,\n messages: Array<{ role: \"system\" | \"user\" | \"assistant\"; content: string }>,\n options: FallbackLlmOptions,\n ): Promise<{ content: string; usage?: FallbackLlmResponse[\"usage\"] } | null> {\n // Try the gateway's native runtime auth first — it handles all provider-\n // specific transforms (OAuth exchange, base URL rewrite, etc.)\n const runtimeAuth = await this.resolveRuntimeAuth(model);\n const effectiveBaseUrl = runtimeAuth?.baseUrl ?? model.providerConfig.baseUrl;\n const resolvedApiKey = runtimeAuth?.apiKey ?? await this.resolveFallbackApiKey(model);\n\n // If the raw key looks like an unresolved secret ref and resolution fails,\n // skip this provider entirely so the chain falls through to the next.\n const rawKey = model.providerConfig.apiKey;\n const needsResolution = rawKey === \"secretref-managed\"\n || (typeof rawKey === \"object\" && rawKey !== null);\n if (needsResolution && !resolvedApiKey) {\n throw new Error(`API key for provider \"${model.providerId}\" could not be resolved from secret ref`);\n }\n\n const effectiveConfig: ModelProviderConfig = {\n ...model.providerConfig,\n baseUrl: effectiveBaseUrl,\n ...(resolvedApiKey ? { apiKey: resolvedApiKey } : {}),\n };\n\n if (model.providerConfig.api === \"anthropic-messages\") {\n return await this.callAnthropic(effectiveConfig, model.modelId, messages, options);\n }\n\n if (\n model.providerConfig.api === \"openai-responses\" ||\n model.providerConfig.api === \"openai-codex-responses\" ||\n model.providerConfig.api === \"azure-openai-responses\"\n ) {\n return await this.callOpenAIResponses(\n effectiveConfig,\n model.modelId,\n messages,\n options,\n );\n }\n\n // For OpenAI-compatible chat-completions APIs (openai-completions,\n // ollama, etc.) and unknown formats, use chat completions — the gateway's\n // runtime auth resolver returns request-ready base URL and credentials for\n // most providers.\n return await this.callOpenAI(\n effectiveConfig,\n model.modelId,\n messages,\n options,\n shouldAssumeOpenAiChatCompletions(effectiveConfig.baseUrl),\n );\n }\n\n /**\n * Resolve request-ready auth through the gateway's native runtime, which\n * handles provider-specific transforms (OAuth token exchange for codex/copilot,\n * base URL rewrite, etc.). Returns null if the runtime isn't available.\n */\n private async resolveRuntimeAuth(\n model: ModelRef,\n ): Promise<{ apiKey?: string; baseUrl?: string } | null> {\n try {\n const getRuntimeAuth = await getGatewayRuntimeAuthForModel();\n if (!getRuntimeAuth) return null;\n\n const result = await getRuntimeAuth({\n model: {\n provider: model.providerId,\n id: model.modelId,\n api: model.providerConfig.api,\n baseUrl: model.providerConfig.baseUrl,\n },\n cfg: this.gatewayConfig,\n workspaceDir: this.runtimeContext.workspaceDir,\n });\n\n if (result?.apiKey || result?.baseUrl) {\n log.debug(\n `fallback LLM: resolved runtime auth for \"${model.modelString}\" (source: ${result.source ?? \"unknown\"}, mode: ${result.mode ?? \"unknown\"})`,\n );\n return { apiKey: result.apiKey, baseUrl: result.baseUrl };\n }\n } catch (err) {\n log.debug(\n `fallback LLM: gateway runtime auth failed for \"${model.modelString}\": ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n return null;\n }\n\n /**\n * Resolve API key through the existing provider-level resolution (env vars,\n * secret refs, etc.). Used as fallback when gateway runtime auth isn't available.\n */\n private async resolveFallbackApiKey(model: ModelRef): Promise<string | undefined> {\n return resolveProviderApiKey(\n model.providerId,\n model.providerConfig.apiKey,\n this.gatewayConfig,\n this.runtimeContext.agentDir,\n );\n }\n\n /**\n * Call OpenAI-compatible API.\n */\n private async callOpenAI(\n config: ModelProviderConfig,\n modelId: string,\n messages: Array<{ role: \"system\" | \"user\" | \"assistant\"; content: string }>,\n options: FallbackLlmOptions,\n assumeOpenAI: boolean,\n ): Promise<{ content: string; usage?: FallbackLlmResponse[\"usage\"] } | null> {\n const base = config.baseUrl.replace(/\\/$/, \"\");\n const url = base.endsWith(\"/v1\")\n ? `${base}/chat/completions`\n : `${base}/v1/chat/completions`;\n\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n ...config.headers,\n };\n\n // Handle auth — apiKey is already resolved to a string by tryModel()\n if (config.apiKey && typeof config.apiKey === \"string\") {\n if (config.authHeader !== false) {\n headers[\"Authorization\"] = `Bearer ${config.apiKey}`;\n }\n }\n\n const body = {\n model: modelId,\n messages,\n temperature: options.temperature ?? 0.3,\n ...buildChatCompletionTokenLimit(modelId, options.maxTokens ?? 4096, {\n assumeOpenAI,\n }),\n };\n\n const response = await fetch(url, {\n method: \"POST\",\n headers,\n body: JSON.stringify(body),\n });\n\n if (!response.ok) {\n const error = await response.text();\n throw new Error(`OpenAI API error: ${response.status} ${error}`);\n }\n\n const data = (await response.json()) as {\n choices: Array<{\n message: {\n content: string;\n };\n }>;\n usage?: {\n prompt_tokens?: number;\n completion_tokens?: number;\n total_tokens?: number;\n };\n };\n\n const content = data.choices?.[0]?.message?.content;\n if (!content) {\n throw new Error(\"Empty response from OpenAI API\");\n }\n\n return {\n content,\n usage: data.usage\n ? {\n inputTokens: data.usage.prompt_tokens,\n outputTokens: data.usage.completion_tokens,\n totalTokens: data.usage.total_tokens,\n }\n : undefined,\n };\n }\n\n /**\n * Call an OpenAI-compatible Responses API.\n */\n private async callOpenAIResponses(\n config: ModelProviderConfig,\n modelId: string,\n messages: Array<{ role: \"system\" | \"user\" | \"assistant\"; content: string }>,\n options: FallbackLlmOptions,\n ): Promise<{ content: string; usage?: FallbackLlmResponse[\"usage\"] } | null> {\n const base = config.baseUrl.replace(/\\/$/, \"\");\n const url = base.endsWith(\"/v1\")\n ? `${base}/responses`\n : `${base}/v1/responses`;\n\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n ...config.headers,\n };\n\n if (config.apiKey && typeof config.apiKey === \"string\" && config.authHeader !== false) {\n headers[\"Authorization\"] = `Bearer ${config.apiKey}`;\n }\n\n const instructions = messages\n .filter((message) => message.role === \"system\")\n .map((message) => message.content)\n .join(\"\\n\\n\")\n .trim();\n const input = messages\n .filter((message) => message.role !== \"system\")\n .map((message) => ({\n role: message.role,\n content: [{\n type: message.role === \"assistant\" ? \"output_text\" : \"input_text\",\n text: message.content,\n }],\n }));\n\n const body: Record<string, unknown> = {\n model: modelId,\n input,\n max_output_tokens: Math.max(0, Math.floor(options.maxTokens ?? 4096)),\n temperature: options.temperature ?? 0.3,\n };\n if (instructions.length > 0) {\n body.instructions = instructions;\n }\n\n const response = await fetch(url, {\n method: \"POST\",\n headers,\n body: JSON.stringify(body),\n });\n\n if (!response.ok) {\n const error = await response.text();\n throw new Error(`OpenAI Responses API error: ${response.status} ${error}`);\n }\n\n const data = (await response.json()) as {\n output_text?: string;\n output?: Array<{\n type?: string;\n text?: string;\n content?: Array<{\n type?: string;\n text?: string;\n }>;\n }>;\n usage?: {\n input_tokens?: number;\n output_tokens?: number;\n total_tokens?: number;\n };\n };\n\n const outputText = extractResponsesOutputText(data);\n if (!outputText) {\n throw new Error(\"Empty response from OpenAI Responses API\");\n }\n\n return {\n content: outputText,\n usage: data.usage\n ? {\n inputTokens: data.usage.input_tokens,\n outputTokens: data.usage.output_tokens,\n totalTokens: data.usage.total_tokens,\n }\n : undefined,\n };\n }\n\n /**\n * Call Anthropic Messages API.\n */\n private async callAnthropic(\n config: ModelProviderConfig,\n modelId: string,\n messages: Array<{ role: \"system\" | \"user\" | \"assistant\"; content: string }>,\n options: FallbackLlmOptions,\n ): Promise<{ content: string; usage?: FallbackLlmResponse[\"usage\"] } | null> {\n const base = config.baseUrl.replace(/\\/$/, \"\");\n const url = base.endsWith(\"/v1\")\n ? `${base}/messages`\n : `${base}/v1/messages`;\n\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n \"anthropic-version\": \"2023-06-01\",\n ...config.headers,\n };\n\n // Handle auth - Anthropic uses x-api-key header (apiKey resolved by tryModel)\n if (config.apiKey && typeof config.apiKey === \"string\") {\n headers[\"x-api-key\"] = config.apiKey;\n }\n\n // Extract system message (Anthropic handles it separately)\n const systemMessage = messages.find((m) => m.role === \"system\")?.content;\n const nonSystemMessages = messages.filter((m) => m.role !== \"system\");\n\n // Convert messages to Anthropic format\n const anthropicMessages = nonSystemMessages.map((m) => ({\n role: m.role,\n content: m.content,\n }));\n\n const body: Record<string, unknown> = {\n model: modelId,\n messages: anthropicMessages,\n max_tokens: options.maxTokens ?? 4096,\n temperature: options.temperature ?? 0.3,\n };\n\n if (systemMessage) {\n body.system = systemMessage;\n }\n\n const response = await fetch(url, {\n method: \"POST\",\n headers,\n body: JSON.stringify(body),\n });\n\n if (!response.ok) {\n const error = await response.text();\n throw new Error(`Anthropic API error: ${response.status} ${error}`);\n }\n\n const data = (await response.json()) as {\n content: Array<{\n type: string;\n text: string;\n }>;\n usage?: {\n input_tokens?: number;\n output_tokens?: number;\n };\n };\n\n const content = data.content?.[0]?.text;\n if (!content) {\n throw new Error(\"Empty response from Anthropic API\");\n }\n\n return {\n content,\n usage: data.usage\n ? {\n inputTokens: data.usage.input_tokens,\n outputTokens: data.usage.output_tokens,\n totalTokens: (data.usage.input_tokens ?? 0) + (data.usage.output_tokens ?? 0),\n }\n : undefined,\n };\n }\n}\n\nfunction extractResponsesOutputText(data: {\n output_text?: string;\n output?: Array<{\n type?: string;\n text?: string;\n content?: Array<{\n type?: string;\n text?: string;\n }>;\n }>;\n}): string | null {\n if (typeof data.output_text === \"string\" && data.output_text.trim().length > 0) {\n return data.output_text;\n }\n\n const chunks: string[] = [];\n for (const item of data.output ?? []) {\n if (typeof item.text === \"string\" && item.text.trim().length > 0) {\n chunks.push(item.text);\n }\n for (const part of item.content ?? []) {\n if (\n (part.type === \"output_text\" || part.type === \"text\") &&\n typeof part.text === \"string\" &&\n part.text.trim().length > 0\n ) {\n chunks.push(part.text);\n }\n }\n }\n\n const joined = chunks.join(\"\\n\").trim();\n return joined.length > 0 ? joined : null;\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
log
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-2ODBA7MQ.js";
|
|
4
4
|
|
|
5
5
|
// src/recall-state.ts
|
|
6
6
|
import { appendFile, mkdir, readFile, writeFile } from "fs/promises";
|
|
@@ -22,6 +22,14 @@ function clampGraphRecallExpandedEntries(entries, maxEntries = 64) {
|
|
|
22
22
|
};
|
|
23
23
|
}).filter((item) => item.path.length > 0 && item.namespace.length > 0).slice(0, limit);
|
|
24
24
|
}
|
|
25
|
+
function cloneTierExplain(tierExplain) {
|
|
26
|
+
if (!tierExplain) return void 0;
|
|
27
|
+
return structuredClone(tierExplain);
|
|
28
|
+
}
|
|
29
|
+
function cloneLastRecallSnapshot(snapshot) {
|
|
30
|
+
if (!snapshot) return null;
|
|
31
|
+
return structuredClone(snapshot);
|
|
32
|
+
}
|
|
25
33
|
var DEFAULT_TIER_MIGRATION_STATUS = {
|
|
26
34
|
updatedAt: (/* @__PURE__ */ new Date(0)).toISOString(),
|
|
27
35
|
lastCycle: null,
|
|
@@ -52,13 +60,17 @@ var LastRecallStore = class {
|
|
|
52
60
|
}
|
|
53
61
|
}
|
|
54
62
|
get(sessionKey) {
|
|
55
|
-
return this.state[sessionKey] ?? null;
|
|
63
|
+
return cloneLastRecallSnapshot(this.state[sessionKey] ?? null);
|
|
56
64
|
}
|
|
57
65
|
getMostRecent() {
|
|
58
66
|
const snapshots = Object.values(this.state);
|
|
59
67
|
if (snapshots.length === 0) return null;
|
|
60
|
-
snapshots.sort((a, b) =>
|
|
61
|
-
|
|
68
|
+
snapshots.sort((a, b) => {
|
|
69
|
+
const byTime = b.recordedAt.localeCompare(a.recordedAt);
|
|
70
|
+
if (byTime !== 0) return byTime;
|
|
71
|
+
return a.sessionKey.localeCompare(b.sessionKey);
|
|
72
|
+
});
|
|
73
|
+
return cloneLastRecallSnapshot(snapshots[0] ?? null);
|
|
62
74
|
}
|
|
63
75
|
/**
|
|
64
76
|
* Persist last-recall snapshot and append an impression log entry.
|
|
@@ -67,7 +79,7 @@ var LastRecallStore = class {
|
|
|
67
79
|
async record(opts) {
|
|
68
80
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
69
81
|
const queryHash = createHash("sha256").update(opts.query).digest("hex");
|
|
70
|
-
const
|
|
82
|
+
const liveSnapshot = {
|
|
71
83
|
sessionKey: opts.sessionKey,
|
|
72
84
|
recordedAt: now,
|
|
73
85
|
queryHash,
|
|
@@ -79,15 +91,17 @@ var LastRecallStore = class {
|
|
|
79
91
|
requestedMode: opts.requestedMode,
|
|
80
92
|
source: opts.source,
|
|
81
93
|
fallbackUsed: opts.fallbackUsed,
|
|
82
|
-
sourcesUsed: opts.sourcesUsed
|
|
83
|
-
budgetsApplied: opts.budgetsApplied
|
|
94
|
+
sourcesUsed: opts.sourcesUsed,
|
|
95
|
+
budgetsApplied: opts.budgetsApplied,
|
|
84
96
|
latencyMs: opts.latencyMs,
|
|
85
|
-
resultPaths: opts.resultPaths
|
|
97
|
+
resultPaths: opts.resultPaths,
|
|
86
98
|
policyVersion: opts.policyVersion,
|
|
87
99
|
identityInjectionMode: opts.identityInjection?.mode,
|
|
88
100
|
identityInjectedChars: opts.identityInjection?.injectedChars,
|
|
89
|
-
identityInjectionTruncated: opts.identityInjection?.truncated
|
|
101
|
+
identityInjectionTruncated: opts.identityInjection?.truncated,
|
|
102
|
+
tierExplain: opts.tierExplain
|
|
90
103
|
};
|
|
104
|
+
const snapshot = cloneLastRecallSnapshot(liveSnapshot);
|
|
91
105
|
this.state[opts.sessionKey] = snapshot;
|
|
92
106
|
const keys = Object.keys(this.state);
|
|
93
107
|
if (keys.length > 50) {
|
|
@@ -111,6 +125,31 @@ var LastRecallStore = class {
|
|
|
111
125
|
}
|
|
112
126
|
}
|
|
113
127
|
}
|
|
128
|
+
/**
|
|
129
|
+
* Attach a RecallTierExplain block to the existing snapshot for a
|
|
130
|
+
* session without rewriting the entire snapshot. Used by the
|
|
131
|
+
* post-recall direct-answer annotation path (issue #518 slice 3c):
|
|
132
|
+
* recallInternal records the snapshot first, then the orchestrator
|
|
133
|
+
* fires the direct-answer tier in observation mode and annotates
|
|
134
|
+
* the stored snapshot with whichever tier served the query.
|
|
135
|
+
*
|
|
136
|
+
* No-op when no snapshot exists for the given session; callers do
|
|
137
|
+
* not need to guard on existence.
|
|
138
|
+
*/
|
|
139
|
+
async annotateTierExplain(sessionKey, tierExplain) {
|
|
140
|
+
const current = this.state[sessionKey];
|
|
141
|
+
if (!current) return;
|
|
142
|
+
this.state[sessionKey] = {
|
|
143
|
+
...current,
|
|
144
|
+
tierExplain: cloneTierExplain(tierExplain)
|
|
145
|
+
};
|
|
146
|
+
try {
|
|
147
|
+
await mkdir(path.dirname(this.statePath), { recursive: true });
|
|
148
|
+
await writeFile(this.statePath, JSON.stringify(this.state, null, 2), "utf-8");
|
|
149
|
+
} catch (err) {
|
|
150
|
+
log.debug(`last recall tier-explain annotate failed: ${err}`);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
114
153
|
};
|
|
115
154
|
var TierMigrationStatusStore = class {
|
|
116
155
|
statePath;
|
|
@@ -182,4 +221,4 @@ export {
|
|
|
182
221
|
LastRecallStore,
|
|
183
222
|
TierMigrationStatusStore
|
|
184
223
|
};
|
|
185
|
-
//# sourceMappingURL=chunk-
|
|
224
|
+
//# sourceMappingURL=chunk-47UU5PU2.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/recall-state.ts"],"sourcesContent":["import { appendFile, mkdir, readFile, writeFile } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { createHash } from \"node:crypto\";\nimport { log } from \"./logger.js\";\nimport type {\n IdentityInjectionMode,\n RecallPlanMode,\n RecallTierExplain,\n} from \"./types.js\";\n\nexport interface LastRecallBudgetSummary {\n requestedTopK?: number;\n appliedTopK: number;\n recallBudgetChars: number;\n maxMemoryTokens: number;\n qmdFetchLimit?: number;\n qmdHybridFetchLimit?: number;\n finalContextChars?: number;\n truncated?: boolean;\n includedSections?: string[];\n omittedSections?: string[];\n}\n\nexport interface LastRecallSnapshot {\n sessionKey: string;\n recordedAt: string;\n queryHash: string;\n queryLen: number;\n memoryIds: string[];\n namespace?: string;\n traceId?: string;\n plannerMode?: RecallPlanMode;\n requestedMode?: RecallPlanMode;\n source?: string;\n fallbackUsed?: boolean;\n sourcesUsed?: string[];\n budgetsApplied?: LastRecallBudgetSummary;\n latencyMs?: number;\n resultPaths?: string[];\n policyVersion?: string;\n identityInjectionMode?: IdentityInjectionMode | \"none\";\n identityInjectedChars?: number;\n identityInjectionTruncated?: boolean;\n /**\n * Optional tier-level explanation of how recall was served\n * (issue #518). Populated by orchestrator call sites that can\n * identify a concrete tier; surfaces expose the block via\n * `engram query --explain`, the `?explain=1` HTTP flag, and the\n * `remnic_recall_explain` MCP tool. Orthogonal to the existing\n * graph-path `recallExplain` operation.\n */\n tierExplain?: RecallTierExplain;\n}\n\nexport interface GraphRecallExpandedEntry {\n path: string;\n score: number;\n namespace: string;\n seed: string;\n hopDepth: number;\n decayedWeight: number;\n graphType: \"entity\" | \"time\" | \"causal\";\n}\n\nexport function clampGraphRecallExpandedEntries(\n entries: unknown,\n maxEntries: number = 64,\n): GraphRecallExpandedEntry[] {\n const limit = Math.max(1, Math.floor(maxEntries));\n if (!Array.isArray(entries)) return [];\n return entries\n .filter((item): item is Record<string, unknown> => !!item && typeof item === \"object\")\n .map((item) => {\n const graphType: \"entity\" | \"time\" | \"causal\" =\n item.graphType === \"entity\" || item.graphType === \"time\" || item.graphType === \"causal\"\n ? item.graphType\n : \"entity\";\n return {\n path: typeof item.path === \"string\" ? item.path : \"\",\n score: typeof item.score === \"number\" && Number.isFinite(item.score) ? item.score : 0,\n namespace: typeof item.namespace === \"string\" ? item.namespace : \"\",\n seed: typeof item.seed === \"string\" ? item.seed : \"\",\n hopDepth:\n typeof item.hopDepth === \"number\" && Number.isFinite(item.hopDepth)\n ? Math.max(0, Math.floor(item.hopDepth))\n : 0,\n decayedWeight:\n typeof item.decayedWeight === \"number\" && Number.isFinite(item.decayedWeight)\n ? Math.max(0, item.decayedWeight)\n : 0,\n graphType,\n };\n })\n .filter((item) => item.path.length > 0 && item.namespace.length > 0)\n .slice(0, limit);\n}\n\ntype LastRecallState = Record<string, LastRecallSnapshot>;\n\n/**\n * Deep-copy a RecallTierExplain block. Used by both the write path\n * (so caller mutation after `record()` cannot tear the persisted\n * snapshot) and the read path (so caller mutation after `get()` /\n * `getMostRecent()` cannot tear the in-memory store).\n *\n * Uses structuredClone so future additions to RecallTierExplain do\n * not silently share references through hand-enumerated fields —\n * matching the pattern used elsewhere in the codebase (e.g.,\n * qmd-recall-cache.ts). The payload is pure JSON-shaped data, so\n * structuredClone is both safe and complete here.\n */\nfunction cloneTierExplain(\n tierExplain: RecallTierExplain | undefined,\n): RecallTierExplain | undefined {\n if (!tierExplain) return undefined;\n return structuredClone(tierExplain);\n}\n\n/**\n * Deep-copy a LastRecallSnapshot so callers that receive it cannot\n * mutate the store's internal state through mutable array/object\n * fields. Same structuredClone rationale as cloneTierExplain above.\n */\nfunction cloneLastRecallSnapshot(\n snapshot: LastRecallSnapshot | null,\n): LastRecallSnapshot | null {\n if (!snapshot) return null;\n return structuredClone(snapshot);\n}\n\nexport interface TierMigrationCycleSummary {\n trigger: \"extraction\" | \"maintenance\" | \"manual\";\n scanned: number;\n migrated: number;\n promoted: number;\n demoted: number;\n limit: number;\n dryRun: boolean;\n skipped?: string;\n errorCount?: number;\n}\n\nexport interface TierMigrationStatusSnapshot {\n updatedAt: string;\n lastCycle: TierMigrationCycleSummary | null;\n totals: {\n cycles: number;\n scanned: number;\n migrated: number;\n promoted: number;\n demoted: number;\n errors: number;\n };\n}\n\nconst DEFAULT_TIER_MIGRATION_STATUS: TierMigrationStatusSnapshot = {\n updatedAt: new Date(0).toISOString(),\n lastCycle: null,\n totals: {\n cycles: 0,\n scanned: 0,\n migrated: 0,\n promoted: 0,\n demoted: 0,\n errors: 0,\n },\n};\n\nexport class LastRecallStore {\n private readonly statePath: string;\n private readonly impressionsPath: string;\n private state: LastRecallState = {};\n\n constructor(memoryDir: string) {\n this.statePath = path.join(memoryDir, \"state\", \"last_recall.json\");\n this.impressionsPath = path.join(memoryDir, \"state\", \"recall_impressions.jsonl\");\n }\n\n async load(): Promise<void> {\n try {\n const raw = await readFile(this.statePath, \"utf-8\");\n const parsed = JSON.parse(raw) as LastRecallState;\n if (parsed && typeof parsed === \"object\") this.state = parsed;\n } catch {\n this.state = {};\n }\n }\n\n get(sessionKey: string): LastRecallSnapshot | null {\n // Defensive copy: callers must not be able to mutate internal state\n // by reaching into array/object fields on the returned snapshot.\n return cloneLastRecallSnapshot(this.state[sessionKey] ?? null);\n }\n\n getMostRecent(): LastRecallSnapshot | null {\n const snapshots = Object.values(this.state);\n if (snapshots.length === 0) return null;\n // Secondary key on sessionKey keeps the sort stable when two\n // snapshots share a recordedAt timestamp (CLAUDE.md rule 19).\n snapshots.sort((a, b) => {\n const byTime = b.recordedAt.localeCompare(a.recordedAt);\n if (byTime !== 0) return byTime;\n return a.sessionKey.localeCompare(b.sessionKey);\n });\n return cloneLastRecallSnapshot(snapshots[0] ?? null);\n }\n\n /**\n * Persist last-recall snapshot and append an impression log entry.\n * Does not store raw query text; uses a stable hash for correlation.\n */\n async record(opts: {\n sessionKey: string;\n query: string;\n memoryIds: string[];\n namespace?: string;\n traceId?: string;\n plannerMode?: RecallPlanMode;\n requestedMode?: RecallPlanMode;\n source?: string;\n fallbackUsed?: boolean;\n sourcesUsed?: string[];\n budgetsApplied?: LastRecallBudgetSummary;\n latencyMs?: number;\n resultPaths?: string[];\n policyVersion?: string;\n appendImpression?: boolean;\n identityInjection?: {\n mode: IdentityInjectionMode | \"none\";\n injectedChars: number;\n truncated: boolean;\n };\n /**\n * Per-tier explain annotation (issue #518). When supplied, the\n * snapshot carries it so downstream surfaces (CLI / HTTP / MCP)\n * can render which retrieval tier served the query.\n */\n tierExplain?: RecallTierExplain;\n }): Promise<void> {\n const now = new Date().toISOString();\n const queryHash = createHash(\"sha256\").update(opts.query).digest(\"hex\");\n\n // Build the snapshot from opts, then deep-copy it via\n // cloneLastRecallSnapshot so caller arrays/objects passed in\n // `opts` cannot retain a live reference to the persisted state\n // and tear it after record() returns.\n const liveSnapshot: LastRecallSnapshot = {\n sessionKey: opts.sessionKey,\n recordedAt: now,\n queryHash,\n queryLen: opts.query.length,\n memoryIds: opts.memoryIds,\n namespace: opts.namespace,\n traceId: opts.traceId,\n plannerMode: opts.plannerMode,\n requestedMode: opts.requestedMode,\n source: opts.source,\n fallbackUsed: opts.fallbackUsed,\n sourcesUsed: opts.sourcesUsed,\n budgetsApplied: opts.budgetsApplied,\n latencyMs: opts.latencyMs,\n resultPaths: opts.resultPaths,\n policyVersion: opts.policyVersion,\n identityInjectionMode: opts.identityInjection?.mode,\n identityInjectedChars: opts.identityInjection?.injectedChars,\n identityInjectionTruncated: opts.identityInjection?.truncated,\n tierExplain: opts.tierExplain,\n };\n // `cloneLastRecallSnapshot` handles `null` but that never applies\n // at this call site — the non-null assertion keeps the type\n // checker honest.\n const snapshot = cloneLastRecallSnapshot(liveSnapshot)!;\n\n this.state[opts.sessionKey] = snapshot;\n\n // Keep the state bounded; the impression log is append-only.\n const keys = Object.keys(this.state);\n if (keys.length > 50) {\n const ordered = keys\n .map((k) => ({ k, at: this.state[k]?.recordedAt ?? \"\" }))\n .sort((a, b) => b.at.localeCompare(a.at));\n for (const doomed of ordered.slice(50)) {\n delete this.state[doomed.k];\n }\n }\n\n try {\n await mkdir(path.dirname(this.statePath), { recursive: true });\n await writeFile(this.statePath, JSON.stringify(this.state, null, 2), \"utf-8\");\n } catch (err) {\n log.debug(`last recall store write failed: ${err}`);\n }\n\n if (opts.appendImpression !== false) {\n try {\n await mkdir(path.dirname(this.impressionsPath), { recursive: true });\n await appendFile(this.impressionsPath, JSON.stringify(snapshot) + \"\\n\", \"utf-8\");\n } catch (err) {\n log.debug(`recall impressions append failed: ${err}`);\n }\n }\n }\n\n /**\n * Attach a RecallTierExplain block to the existing snapshot for a\n * session without rewriting the entire snapshot. Used by the\n * post-recall direct-answer annotation path (issue #518 slice 3c):\n * recallInternal records the snapshot first, then the orchestrator\n * fires the direct-answer tier in observation mode and annotates\n * the stored snapshot with whichever tier served the query.\n *\n * No-op when no snapshot exists for the given session; callers do\n * not need to guard on existence.\n */\n async annotateTierExplain(\n sessionKey: string,\n tierExplain: RecallTierExplain,\n ): Promise<void> {\n const current = this.state[sessionKey];\n if (!current) return;\n this.state[sessionKey] = {\n ...current,\n tierExplain: cloneTierExplain(tierExplain),\n };\n try {\n await mkdir(path.dirname(this.statePath), { recursive: true });\n await writeFile(this.statePath, JSON.stringify(this.state, null, 2), \"utf-8\");\n } catch (err) {\n log.debug(`last recall tier-explain annotate failed: ${err}`);\n }\n }\n}\n\nexport class TierMigrationStatusStore {\n private readonly statePath: string;\n private state: TierMigrationStatusSnapshot = structuredClone(DEFAULT_TIER_MIGRATION_STATUS);\n\n constructor(memoryDir: string) {\n this.statePath = path.join(memoryDir, \"state\", \"tier-migration-status.json\");\n }\n\n async load(): Promise<void> {\n try {\n const raw = await readFile(this.statePath, \"utf-8\");\n const parsed = JSON.parse(raw) as Partial<TierMigrationStatusSnapshot> | null;\n if (!parsed || typeof parsed !== \"object\") {\n this.state = structuredClone(DEFAULT_TIER_MIGRATION_STATUS);\n return;\n }\n const totals = parsed.totals && typeof parsed.totals === \"object\"\n ? parsed.totals\n : DEFAULT_TIER_MIGRATION_STATUS.totals;\n this.state = {\n updatedAt:\n typeof parsed.updatedAt === \"string\" && parsed.updatedAt.length > 0\n ? parsed.updatedAt\n : DEFAULT_TIER_MIGRATION_STATUS.updatedAt,\n lastCycle:\n parsed.lastCycle && typeof parsed.lastCycle === \"object\"\n ? (parsed.lastCycle as TierMigrationCycleSummary)\n : null,\n totals: {\n cycles: typeof totals.cycles === \"number\" && Number.isFinite(totals.cycles) ? totals.cycles : 0,\n scanned: typeof totals.scanned === \"number\" && Number.isFinite(totals.scanned) ? totals.scanned : 0,\n migrated: typeof totals.migrated === \"number\" && Number.isFinite(totals.migrated) ? totals.migrated : 0,\n promoted: typeof totals.promoted === \"number\" && Number.isFinite(totals.promoted) ? totals.promoted : 0,\n demoted: typeof totals.demoted === \"number\" && Number.isFinite(totals.demoted) ? totals.demoted : 0,\n errors: typeof totals.errors === \"number\" && Number.isFinite(totals.errors) ? totals.errors : 0,\n },\n };\n } catch {\n this.state = structuredClone(DEFAULT_TIER_MIGRATION_STATUS);\n }\n }\n\n get(): TierMigrationStatusSnapshot {\n return {\n updatedAt: this.state.updatedAt,\n lastCycle: this.state.lastCycle ? { ...this.state.lastCycle } : null,\n totals: { ...this.state.totals },\n };\n }\n\n async recordCycle(summary: TierMigrationCycleSummary): Promise<void> {\n const now = new Date().toISOString();\n const migratedDelta = summary.dryRun ? 0 : Math.max(0, summary.migrated);\n const promotedDelta = summary.dryRun ? 0 : Math.max(0, summary.promoted);\n const demotedDelta = summary.dryRun ? 0 : Math.max(0, summary.demoted);\n const next: TierMigrationStatusSnapshot = {\n updatedAt: now,\n lastCycle: { ...summary },\n totals: {\n cycles: this.state.totals.cycles + 1,\n scanned: this.state.totals.scanned + Math.max(0, summary.scanned),\n migrated: this.state.totals.migrated + migratedDelta,\n promoted: this.state.totals.promoted + promotedDelta,\n demoted: this.state.totals.demoted + demotedDelta,\n errors: this.state.totals.errors + Math.max(0, summary.errorCount ?? 0),\n },\n };\n this.state = next;\n try {\n await mkdir(path.dirname(this.statePath), { recursive: true });\n await writeFile(this.statePath, JSON.stringify(next, null, 2), \"utf-8\");\n } catch (err) {\n log.debug(`tier migration status write failed: ${err}`);\n }\n }\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
// src/entity-schema.ts
|
|
2
|
+
var DEFAULT_ENTITY_SCHEMAS = {
|
|
3
|
+
person: {
|
|
4
|
+
sections: [
|
|
5
|
+
{
|
|
6
|
+
key: "beliefs",
|
|
7
|
+
title: "Beliefs",
|
|
8
|
+
description: "",
|
|
9
|
+
aliases: ["belief", "beliefs", "believe", "believes"]
|
|
10
|
+
},
|
|
11
|
+
{
|
|
12
|
+
key: "communication_style",
|
|
13
|
+
title: "Communication Style",
|
|
14
|
+
description: "",
|
|
15
|
+
aliases: ["communication", "communication style", "communicate", "writes", "writing style"]
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
key: "building",
|
|
19
|
+
title: "Building / Working On",
|
|
20
|
+
description: "",
|
|
21
|
+
aliases: ["building", "working on", "work on", "projects"]
|
|
22
|
+
}
|
|
23
|
+
]
|
|
24
|
+
},
|
|
25
|
+
project: {
|
|
26
|
+
sections: [
|
|
27
|
+
{ key: "status", title: "Status", description: "" },
|
|
28
|
+
{
|
|
29
|
+
key: "building",
|
|
30
|
+
title: "Building / Working On",
|
|
31
|
+
description: "",
|
|
32
|
+
aliases: ["building", "working on", "work on"]
|
|
33
|
+
},
|
|
34
|
+
{ key: "risks", title: "Risks", description: "" },
|
|
35
|
+
{ key: "notes", title: "Notes", description: "" }
|
|
36
|
+
]
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
function normalizeEntityText(value) {
|
|
40
|
+
return value.toLowerCase().replace(/[^a-z0-9]+/g, " ").trim();
|
|
41
|
+
}
|
|
42
|
+
function toSnakeCase(value) {
|
|
43
|
+
return normalizeEntityText(value).replace(/\s+/g, "_");
|
|
44
|
+
}
|
|
45
|
+
function titleFromKey(key) {
|
|
46
|
+
return key.split("_").filter(Boolean).map((token) => token.charAt(0).toUpperCase() + token.slice(1)).join(" ");
|
|
47
|
+
}
|
|
48
|
+
function tokenizeNormalized(value) {
|
|
49
|
+
return normalizeEntityText(value).split(/\s+/).filter(Boolean);
|
|
50
|
+
}
|
|
51
|
+
function normalizeSectionDefinition(raw) {
|
|
52
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw)) return null;
|
|
53
|
+
const value = raw;
|
|
54
|
+
const keySource = typeof value.key === "string" ? value.key : typeof value.title === "string" ? value.title : "";
|
|
55
|
+
const titleSource = typeof value.title === "string" ? value.title : typeof value.key === "string" ? value.key : "";
|
|
56
|
+
const key = toSnakeCase(keySource);
|
|
57
|
+
const title = titleSource.trim() || titleFromKey(key);
|
|
58
|
+
if (!key || !title) return null;
|
|
59
|
+
const description = typeof value.description === "string" ? value.description : "";
|
|
60
|
+
const aliases = Array.isArray(value.aliases) ? value.aliases.filter((alias) => typeof alias === "string").map((alias) => alias.trim()).filter((alias) => alias.length > 0) : [];
|
|
61
|
+
return aliases.length > 0 ? { key, title, description, aliases } : { key, title, description };
|
|
62
|
+
}
|
|
63
|
+
function normalizeEntitySchemas(raw) {
|
|
64
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw)) return void 0;
|
|
65
|
+
const result = {};
|
|
66
|
+
for (const [entityType, schema] of Object.entries(raw)) {
|
|
67
|
+
if (!schema || typeof schema !== "object" || Array.isArray(schema)) continue;
|
|
68
|
+
const rawSections = schema.sections;
|
|
69
|
+
if (!Array.isArray(rawSections)) continue;
|
|
70
|
+
const sections = rawSections.map((section) => normalizeSectionDefinition(section)).filter((section) => section !== null);
|
|
71
|
+
if (sections.length === 0) continue;
|
|
72
|
+
result[toSnakeCase(entityType)] = { sections };
|
|
73
|
+
}
|
|
74
|
+
return Object.keys(result).length > 0 ? result : void 0;
|
|
75
|
+
}
|
|
76
|
+
function mergeEntitySchemaDefinitions(defaults, overrides) {
|
|
77
|
+
const overrideByKey = new Map(overrides.sections.map((section) => [section.key, section]));
|
|
78
|
+
const mergedSections = [];
|
|
79
|
+
const seen = /* @__PURE__ */ new Set();
|
|
80
|
+
for (const section of defaults.sections) {
|
|
81
|
+
const override = overrideByKey.get(section.key);
|
|
82
|
+
const mergedAliases = Array.from(/* @__PURE__ */ new Set([...section.aliases ?? [], ...override?.aliases ?? []]));
|
|
83
|
+
const nextSection = override ? {
|
|
84
|
+
...section,
|
|
85
|
+
...override,
|
|
86
|
+
...mergedAliases.length > 0 ? { aliases: mergedAliases } : {}
|
|
87
|
+
} : section;
|
|
88
|
+
mergedSections.push(nextSection);
|
|
89
|
+
seen.add(nextSection.key);
|
|
90
|
+
}
|
|
91
|
+
for (const section of overrides.sections) {
|
|
92
|
+
if (seen.has(section.key)) continue;
|
|
93
|
+
mergedSections.push(section);
|
|
94
|
+
seen.add(section.key);
|
|
95
|
+
}
|
|
96
|
+
return { sections: mergedSections };
|
|
97
|
+
}
|
|
98
|
+
function getEntitySchema(entityType, entitySchemas) {
|
|
99
|
+
const normalizedType = toSnakeCase(entityType);
|
|
100
|
+
const defaults = DEFAULT_ENTITY_SCHEMAS[normalizedType];
|
|
101
|
+
const overrides = entitySchemas?.[normalizedType];
|
|
102
|
+
if (!defaults) return overrides;
|
|
103
|
+
if (!overrides) return defaults;
|
|
104
|
+
return mergeEntitySchemaDefinitions(defaults, overrides);
|
|
105
|
+
}
|
|
106
|
+
function matchEntitySchemaSection(entityType, title, entitySchemas) {
|
|
107
|
+
const normalizedTitle = normalizeEntityText(title);
|
|
108
|
+
if (!normalizedTitle) return null;
|
|
109
|
+
const schema = getEntitySchema(entityType, entitySchemas);
|
|
110
|
+
if (!schema) return null;
|
|
111
|
+
for (const section of schema.sections) {
|
|
112
|
+
const aliases = [section.title, section.key, ...section.aliases ?? []];
|
|
113
|
+
if (aliases.some((alias) => normalizeEntityText(alias) === normalizedTitle)) {
|
|
114
|
+
return section;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
return null;
|
|
118
|
+
}
|
|
119
|
+
function normalizeEntityStructuredSection(entityType, section, entitySchemas) {
|
|
120
|
+
const matchedSection = matchEntitySchemaSection(entityType, section.title, entitySchemas) ?? matchEntitySchemaSection(entityType, section.key, entitySchemas);
|
|
121
|
+
if (matchedSection) {
|
|
122
|
+
return {
|
|
123
|
+
key: matchedSection.key,
|
|
124
|
+
title: matchedSection.title
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
const key = toSnakeCase(section.key || section.title);
|
|
128
|
+
return {
|
|
129
|
+
key,
|
|
130
|
+
title: section.title.trim() || titleFromKey(key)
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
function queryMentionsAlias(query, alias) {
|
|
134
|
+
const queryTokens = tokenizeNormalized(query);
|
|
135
|
+
const aliasTokens = tokenizeNormalized(alias);
|
|
136
|
+
if (queryTokens.length === 0 || aliasTokens.length === 0) return false;
|
|
137
|
+
if (aliasTokens.length > queryTokens.length) return false;
|
|
138
|
+
for (let index = 0; index <= queryTokens.length - aliasTokens.length; index += 1) {
|
|
139
|
+
let matched = true;
|
|
140
|
+
for (let offset = 0; offset < aliasTokens.length; offset += 1) {
|
|
141
|
+
if (queryTokens[index + offset] !== aliasTokens[offset]) {
|
|
142
|
+
matched = false;
|
|
143
|
+
break;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
if (matched) return true;
|
|
147
|
+
}
|
|
148
|
+
return false;
|
|
149
|
+
}
|
|
150
|
+
function resolveRequestedEntitySectionKeys(query, entityType, availableSections, entitySchemas) {
|
|
151
|
+
if (availableSections.length === 0) return [];
|
|
152
|
+
const availableKeys = new Set(availableSections.map((section) => toSnakeCase(section.key)));
|
|
153
|
+
const schema = getEntitySchema(entityType, entitySchemas);
|
|
154
|
+
if (!schema) return [];
|
|
155
|
+
const matches = [];
|
|
156
|
+
for (const section of schema.sections) {
|
|
157
|
+
const key = toSnakeCase(section.key);
|
|
158
|
+
if (!availableKeys.has(key)) continue;
|
|
159
|
+
const aliases = [section.title, section.key, ...section.aliases ?? []];
|
|
160
|
+
if (aliases.some((alias) => queryMentionsAlias(query, alias))) {
|
|
161
|
+
matches.push(key);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
return matches;
|
|
165
|
+
}
|
|
166
|
+
function sortStructuredSectionsBySchema(entityType, sections, entitySchemas) {
|
|
167
|
+
const schema = getEntitySchema(entityType, entitySchemas);
|
|
168
|
+
if (!schema || sections.length <= 1) return sections;
|
|
169
|
+
const order = new Map(schema.sections.map((section, index) => [toSnakeCase(section.key), index]));
|
|
170
|
+
return [...sections].sort((left, right) => {
|
|
171
|
+
const leftRank = order.get(toSnakeCase(left.key)) ?? Number.MAX_SAFE_INTEGER;
|
|
172
|
+
const rightRank = order.get(toSnakeCase(right.key)) ?? Number.MAX_SAFE_INTEGER;
|
|
173
|
+
if (leftRank !== rightRank) return leftRank - rightRank;
|
|
174
|
+
return left.title.localeCompare(right.title);
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
export {
|
|
179
|
+
normalizeEntityText,
|
|
180
|
+
normalizeEntitySchemas,
|
|
181
|
+
getEntitySchema,
|
|
182
|
+
matchEntitySchemaSection,
|
|
183
|
+
normalizeEntityStructuredSection,
|
|
184
|
+
resolveRequestedEntitySectionKeys,
|
|
185
|
+
sortStructuredSectionsBySchema
|
|
186
|
+
};
|
|
187
|
+
//# sourceMappingURL=chunk-4DJQYKMN.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/entity-schema.ts"],"sourcesContent":["import type {\n EntitySchemaDefinition,\n EntitySchemaSectionDefinition,\n EntityStructuredSection,\n} from \"./types.js\";\n\nconst DEFAULT_ENTITY_SCHEMAS: Record<string, EntitySchemaDefinition> = {\n person: {\n sections: [\n {\n key: \"beliefs\",\n title: \"Beliefs\",\n description: \"\",\n aliases: [\"belief\", \"beliefs\", \"believe\", \"believes\"],\n },\n {\n key: \"communication_style\",\n title: \"Communication Style\",\n description: \"\",\n aliases: [\"communication\", \"communication style\", \"communicate\", \"writes\", \"writing style\"],\n },\n {\n key: \"building\",\n title: \"Building / Working On\",\n description: \"\",\n aliases: [\"building\", \"working on\", \"work on\", \"projects\"],\n },\n ],\n },\n project: {\n sections: [\n { key: \"status\", title: \"Status\", description: \"\" },\n {\n key: \"building\",\n title: \"Building / Working On\",\n description: \"\",\n aliases: [\"building\", \"working on\", \"work on\"],\n },\n { key: \"risks\", title: \"Risks\", description: \"\" },\n { key: \"notes\", title: \"Notes\", description: \"\" },\n ],\n },\n};\n\nexport function normalizeEntityText(value: string): string {\n return value\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, \" \")\n .trim();\n}\n\nfunction toSnakeCase(value: string): string {\n return normalizeEntityText(value).replace(/\\s+/g, \"_\");\n}\n\nfunction titleFromKey(key: string): string {\n return key\n .split(\"_\")\n .filter(Boolean)\n .map((token) => token.charAt(0).toUpperCase() + token.slice(1))\n .join(\" \");\n}\n\nfunction tokenizeNormalized(value: string): string[] {\n return normalizeEntityText(value).split(/\\s+/).filter(Boolean);\n}\n\nfunction normalizeSectionDefinition(raw: unknown): EntitySchemaSectionDefinition | null {\n if (!raw || typeof raw !== \"object\" || Array.isArray(raw)) return null;\n const value = raw as Record<string, unknown>;\n const keySource = typeof value.key === \"string\" ? value.key : typeof value.title === \"string\" ? value.title : \"\";\n const titleSource = typeof value.title === \"string\" ? value.title : typeof value.key === \"string\" ? value.key : \"\";\n const key = toSnakeCase(keySource);\n const title = titleSource.trim() || titleFromKey(key);\n if (!key || !title) return null;\n const description = typeof value.description === \"string\" ? value.description : \"\";\n const aliases = Array.isArray(value.aliases)\n ? value.aliases\n .filter((alias): alias is string => typeof alias === \"string\")\n .map((alias) => alias.trim())\n .filter((alias) => alias.length > 0)\n : [];\n return aliases.length > 0\n ? { key, title, description, aliases }\n : { key, title, description };\n}\n\nexport function normalizeEntitySchemas(raw: unknown): Record<string, EntitySchemaDefinition> | undefined {\n if (!raw || typeof raw !== \"object\" || Array.isArray(raw)) return undefined;\n const result: Record<string, EntitySchemaDefinition> = {};\n for (const [entityType, schema] of Object.entries(raw as Record<string, unknown>)) {\n if (!schema || typeof schema !== \"object\" || Array.isArray(schema)) continue;\n const rawSections = (schema as Record<string, unknown>).sections;\n if (!Array.isArray(rawSections)) continue;\n const sections = rawSections\n .map((section) => normalizeSectionDefinition(section))\n .filter((section): section is EntitySchemaSectionDefinition => section !== null);\n if (sections.length === 0) continue;\n result[toSnakeCase(entityType)] = { sections };\n }\n return Object.keys(result).length > 0 ? result : undefined;\n}\n\nfunction mergeEntitySchemaDefinitions(\n defaults: EntitySchemaDefinition,\n overrides: EntitySchemaDefinition,\n): EntitySchemaDefinition {\n const overrideByKey = new Map(overrides.sections.map((section) => [section.key, section]));\n const mergedSections: EntitySchemaSectionDefinition[] = [];\n const seen = new Set<string>();\n\n for (const section of defaults.sections) {\n const override = overrideByKey.get(section.key);\n const mergedAliases = Array.from(new Set([...(section.aliases ?? []), ...(override?.aliases ?? [])]));\n const nextSection = override\n ? {\n ...section,\n ...override,\n ...(mergedAliases.length > 0 ? { aliases: mergedAliases } : {}),\n }\n : section;\n mergedSections.push(nextSection);\n seen.add(nextSection.key);\n }\n\n for (const section of overrides.sections) {\n if (seen.has(section.key)) continue;\n mergedSections.push(section);\n seen.add(section.key);\n }\n\n return { sections: mergedSections };\n}\n\nexport function getEntitySchema(\n entityType: string,\n entitySchemas?: Record<string, EntitySchemaDefinition>,\n): EntitySchemaDefinition | undefined {\n const normalizedType = toSnakeCase(entityType);\n const defaults = DEFAULT_ENTITY_SCHEMAS[normalizedType];\n const overrides = entitySchemas?.[normalizedType];\n if (!defaults) return overrides;\n if (!overrides) return defaults;\n return mergeEntitySchemaDefinitions(defaults, overrides);\n}\n\nexport function matchEntitySchemaSection(\n entityType: string,\n title: string,\n entitySchemas?: Record<string, EntitySchemaDefinition>,\n): EntitySchemaSectionDefinition | null {\n const normalizedTitle = normalizeEntityText(title);\n if (!normalizedTitle) return null;\n const schema = getEntitySchema(entityType, entitySchemas);\n if (!schema) return null;\n for (const section of schema.sections) {\n const aliases = [section.title, section.key, ...(section.aliases ?? [])];\n if (aliases.some((alias) => normalizeEntityText(alias) === normalizedTitle)) {\n return section;\n }\n }\n return null;\n}\n\nexport function normalizeEntityStructuredSection(\n entityType: string,\n section: Pick<EntityStructuredSection, \"key\" | \"title\">,\n entitySchemas?: Record<string, EntitySchemaDefinition>,\n): Pick<EntityStructuredSection, \"key\" | \"title\"> {\n const matchedSection = matchEntitySchemaSection(entityType, section.title, entitySchemas)\n ?? matchEntitySchemaSection(entityType, section.key, entitySchemas);\n if (matchedSection) {\n return {\n key: matchedSection.key,\n title: matchedSection.title,\n };\n }\n const key = toSnakeCase(section.key || section.title);\n return {\n key,\n title: section.title.trim() || titleFromKey(key),\n };\n}\n\nfunction queryMentionsAlias(query: string, alias: string): boolean {\n const queryTokens = tokenizeNormalized(query);\n const aliasTokens = tokenizeNormalized(alias);\n if (queryTokens.length === 0 || aliasTokens.length === 0) return false;\n if (aliasTokens.length > queryTokens.length) return false;\n for (let index = 0; index <= queryTokens.length - aliasTokens.length; index += 1) {\n let matched = true;\n for (let offset = 0; offset < aliasTokens.length; offset += 1) {\n if (queryTokens[index + offset] !== aliasTokens[offset]) {\n matched = false;\n break;\n }\n }\n if (matched) return true;\n }\n return false;\n}\n\nexport function resolveRequestedEntitySectionKeys(\n query: string,\n entityType: string,\n availableSections: EntityStructuredSection[],\n entitySchemas?: Record<string, EntitySchemaDefinition>,\n): string[] {\n if (availableSections.length === 0) return [];\n const availableKeys = new Set(availableSections.map((section) => toSnakeCase(section.key)));\n const schema = getEntitySchema(entityType, entitySchemas);\n if (!schema) return [];\n const matches: string[] = [];\n for (const section of schema.sections) {\n const key = toSnakeCase(section.key);\n if (!availableKeys.has(key)) continue;\n const aliases = [section.title, section.key, ...(section.aliases ?? [])];\n if (aliases.some((alias) => queryMentionsAlias(query, alias))) {\n matches.push(key);\n }\n }\n return matches;\n}\n\nexport function sortStructuredSectionsBySchema(\n entityType: string,\n sections: EntityStructuredSection[],\n entitySchemas?: Record<string, EntitySchemaDefinition>,\n): EntityStructuredSection[] {\n const schema = getEntitySchema(entityType, entitySchemas);\n if (!schema || sections.length <= 1) return sections;\n const order = new Map(schema.sections.map((section, index) => [toSnakeCase(section.key), index]));\n return [...sections].sort((left, right) => {\n const leftRank = order.get(toSnakeCase(left.key)) ?? Number.MAX_SAFE_INTEGER;\n const rightRank = order.get(toSnakeCase(right.key)) ?? Number.MAX_SAFE_INTEGER;\n if (leftRank !== rightRank) return leftRank - rightRank;\n return left.title.localeCompare(right.title);\n });\n}\n"],"mappings":"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","names":[]}
|