@iowarp/clio-coder 0.3.8 → 0.4.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/CHANGELOG.md +102 -0
- package/NOTICE +33 -0
- package/README.md +12 -3
- package/dist/{acp-U67UHUK2.js → acp-G5WJBNCT.js} +13 -12
- package/dist/{agents-YU6SGALZ.js → agents-FMV2Q5G4.js} +41 -36
- package/dist/assets/codewiki.json +1 -1
- package/dist/{auth-5ZPJOIVG.js → auth-3IDSJEIK.js} +18 -18
- package/dist/{builtins-C6JMZVV6.js → builtins-XCZWXSC7.js} +5 -5
- package/dist/{chunk-IFBNV6H6.js → chunk-2ANTL7MR.js} +3 -3
- package/dist/{chunk-5FR74PWO.js → chunk-2JDWVJND.js} +2 -2
- package/dist/{chunk-XWSF374K.js → chunk-2OQE55CK.js} +3 -3
- package/dist/{chunk-5H3GB5BO.js → chunk-32KWKNSF.js} +8 -384
- package/dist/{chunk-KTYTFRMB.js → chunk-36EJLSQQ.js} +34 -36
- package/dist/{chunk-FHJEP5SW.js → chunk-3BT2XMV4.js} +19 -13
- package/dist/chunk-3DPEIQKN.js +113 -0
- package/dist/{chunk-GU2UIAFZ.js → chunk-3URVFKWK.js} +7 -7
- package/dist/{chunk-WEH5XRJQ.js → chunk-3XML7CDN.js} +3 -3
- package/dist/chunk-42FMPA75.js +101 -0
- package/dist/{chunk-A2NJGIB3.js → chunk-5LXZXPKX.js} +2 -2
- package/dist/{chunk-VCBR6CU7.js → chunk-5PSMVOLM.js} +2 -2
- package/dist/{chunk-NMPKI6XL.js → chunk-6DB53AJS.js} +203 -25
- package/dist/{chunk-3BINW3FP.js → chunk-76ONBSIA.js} +2 -2
- package/dist/{chunk-26LEYJZH.js → chunk-7MCTRUCE.js} +2 -2
- package/dist/{chunk-TYPGUK6W.js → chunk-AB44T6BB.js} +111 -5
- package/dist/{chunk-K4XHGFR5.js → chunk-B7OBL7PK.js} +317 -721
- package/dist/{chunk-B5CSFE7B.js → chunk-BBVJUZHB.js} +2 -2
- package/dist/{chunk-EQ63NRB7.js → chunk-BBVYXMFO.js} +2 -2
- package/dist/{chunk-ZVJ5BLO2.js → chunk-BKFJHQCA.js} +154 -16
- package/dist/chunk-BKFM6EJV.js +462 -0
- package/dist/chunk-BMS5RKQY.js +27 -0
- package/dist/{chunk-ZNLWCMVZ.js → chunk-BPKCPIL7.js} +2 -2
- package/dist/{chunk-TLQJPP24.js → chunk-BUMFYQFY.js} +1394 -1349
- package/dist/{chunk-BNAZZHFG.js → chunk-BYP5D4HI.js} +1 -1
- package/dist/chunk-C2LTL2W6.js +2447 -0
- package/dist/{chunk-ME6CCNFO.js → chunk-CODPRO7Q.js} +8 -8
- package/dist/{chunk-E77JEWSD.js → chunk-CTJ4RNAA.js} +7 -37
- package/dist/{chunk-ODFEOB4F.js → chunk-CY6FY24N.js} +26 -8
- package/dist/{chunk-7RFXX52T.js → chunk-DQITNCXG.js} +642 -172
- package/dist/{chunk-TTHACPOM.js → chunk-DYJP44XW.js} +578 -117
- package/dist/{chunk-2HFZQUHL.js → chunk-F4CKPOEQ.js} +18 -8
- package/dist/{chunk-DGSYXYMX.js → chunk-FEFIFZTL.js} +3 -3
- package/dist/{chunk-GWS3VEIW.js → chunk-FWDFM5ZU.js} +24 -3
- package/dist/{chunk-MV3K5QF2.js → chunk-GCSMB2KY.js} +2 -2
- package/dist/chunk-GKF55TAZ.js +391 -0
- package/dist/{chunk-VWZOAB7K.js → chunk-GR5G2PVF.js} +9 -8
- package/dist/{chunk-4DGYLA73.js → chunk-GXNLGKAB.js} +80 -9
- package/dist/chunk-HHV2GANA.js +88 -0
- package/dist/{chunk-IIZWH4XA.js → chunk-HI63TFOG.js} +5 -4
- package/dist/{chunk-WLFILSD5.js → chunk-HJJTYUHX.js} +113 -83
- package/dist/{chunk-TT36MB5S.js → chunk-HLW2MRKE.js} +3 -1
- package/dist/{chunk-PMDBGQSJ.js → chunk-HWHKMHUA.js} +7 -7
- package/dist/chunk-HZHHCK24.js +1631 -0
- package/dist/{chunk-WSB3FPX7.js → chunk-I5VEOC6I.js} +39 -143
- package/dist/chunk-IBEBSCYA.js +564 -0
- package/dist/chunk-IQ7KR472.js +362 -0
- package/dist/{chunk-A3WNZD3P.js → chunk-J4W7KFM7.js} +949 -972
- package/dist/{chunk-TB5666IT.js → chunk-JDG2WCRO.js} +5 -5
- package/dist/{chunk-N22QMJKY.js → chunk-K5C3NCBD.js} +4 -4
- package/dist/{chunk-CGKSTWHD.js → chunk-K6BSR66V.js} +2 -1
- package/dist/{chunk-5C3AQNDW.js → chunk-KFZI4NIL.js} +216 -38
- package/dist/chunk-KMVISBZR.js +132 -0
- package/dist/{chunk-WXY7KU3G.js → chunk-LDQ2ZF2M.js} +2 -2
- package/dist/{chunk-XN3L4EYL.js → chunk-LQ3DZAMX.js} +3 -3
- package/dist/{chunk-U6MBIEMB.js → chunk-LY4S7GJC.js} +173 -144
- package/dist/{chunk-4SPRNWDE.js → chunk-MLKNTWH2.js} +19 -19
- package/dist/{chunk-MVVUPGPW.js → chunk-MXHC5QYU.js} +6 -6
- package/dist/chunk-NEKRRTYW.js +56 -0
- package/dist/{chunk-SPULKLCF.js → chunk-NHCZP4K7.js} +3 -3
- package/dist/chunk-NHLBIGRH.js +1506 -0
- package/dist/chunk-NQQH3YT7.js +302 -0
- package/dist/chunk-NYS75XW5.js +15 -0
- package/dist/{chunk-GN57SG4G.js → chunk-O4XIVISU.js} +10 -8
- package/dist/{chunk-EMYUUSFG.js → chunk-O6TL7WWY.js} +6 -6
- package/dist/chunk-OQBA45DZ.js +97 -0
- package/dist/{chunk-LU7P4LHA.js → chunk-P3FOHJT4.js} +2 -2
- package/dist/chunk-PMZCIOCJ.js +25 -0
- package/dist/{chunk-I4HZDVNP.js → chunk-PQEFIJ36.js} +2 -2
- package/dist/{chunk-J3YUBZWY.js → chunk-QBJA7R7N.js} +62 -6
- package/dist/chunk-QDC3K2U3.js +262 -0
- package/dist/{chunk-2HEJ2F35.js → chunk-QLFS5GO2.js} +22 -10
- package/dist/{chunk-7RGZWPB6.js → chunk-QLL7ILRG.js} +95 -32
- package/dist/{chunk-YS5VLNH5.js → chunk-QREDIESB.js} +6 -6
- package/dist/chunk-QSNYB6ZV.js +195 -0
- package/dist/{chunk-GOXNB3AO.js → chunk-RAPCMZL4.js} +75 -4
- package/dist/chunk-RKKLTLYB.js +45 -0
- package/dist/{chunk-P43ETTHK.js → chunk-SJ5ZKQ4S.js} +2 -2
- package/dist/{chunk-GPIEI3LY.js → chunk-SP2RXXYO.js} +6 -54
- package/dist/chunk-SUCTJL45.js +45 -0
- package/dist/{chunk-DYIM5TJT.js → chunk-SUW5DORT.js} +263 -7
- package/dist/chunk-T56WDKA5.js +183 -0
- package/dist/chunk-TVHHYFHE.js +255 -0
- package/dist/{chunk-FJ3H4MN5.js → chunk-TZ3SGWZZ.js} +3 -3
- package/dist/{chunk-MXKJU4JB.js → chunk-U77AMWDL.js} +91 -10
- package/dist/{chunk-5DHKRSMQ.js → chunk-ULC6OTWO.js} +11 -7
- package/dist/{chunk-RWSI4YD7.js → chunk-UM7N4G5A.js} +33 -12
- package/dist/{chunk-FCSXB6T2.js → chunk-UOSL25KY.js} +14 -2
- package/dist/{chunk-IGWKHNIQ.js → chunk-UXMFQ54G.js} +44 -37
- package/dist/{chunk-HFSBBKSQ.js → chunk-V5DHCITQ.js} +171 -3
- package/dist/{chunk-5WIGXA4T.js → chunk-VAZSBTKF.js} +111 -4
- package/dist/{chunk-VHN4MY6O.js → chunk-VEO4AP2K.js} +2 -2
- package/dist/{chunk-IJ7RPIYJ.js → chunk-VFA6GDY5.js} +65 -4
- package/dist/{chunk-PT7HYKEM.js → chunk-VO2LKSTM.js} +2 -2
- package/dist/chunk-VO67MWHC.js +75 -0
- package/dist/{chunk-XK56QHLX.js → chunk-VPKWYKEY.js} +19 -5
- package/dist/{chunk-TANS5ZJS.js → chunk-VYMXRQI6.js} +36 -22
- package/dist/{chunk-WWCZ5F23.js → chunk-W5VSYASO.js} +77 -16
- package/dist/{chunk-WNIJTQQK.js → chunk-WZR7K7ZX.js} +72 -116
- package/dist/{chunk-5Q2VVUKB.js → chunk-X3YGUTOB.js} +4 -4
- package/dist/chunk-X75E3D2N.js +686 -0
- package/dist/{chunk-VAWNZU7Z.js → chunk-YDFRH54B.js} +4 -4
- package/dist/chunk-YJX4SHTD.js +40 -0
- package/dist/{chunk-ZI647VB5.js → chunk-YPI3QQCF.js} +2 -2
- package/dist/chunk-Z2RR6MAK.js +127 -0
- package/dist/{chunk-FBVTI2TJ.js → chunk-Z4TXYIEG.js} +12 -131
- package/dist/cli/index.js +47 -36
- package/dist/{clio-QVTYJ57A.js → clio-2JXHBBY5.js} +7 -7
- package/dist/{code-nav-FGGFIE7L.js → code-nav-3YYRMYNF.js} +8 -8
- package/dist/{compile-cache-CVJMMODC.js → compile-cache-7FPE6PS3.js} +3 -3
- package/dist/{components-ZFA3SAER.js → components-RYZV4JGP.js} +5 -5
- package/dist/{config-LW5IJFQN.js → config-QZPCMYSO.js} +99 -63
- package/dist/{configure-7XIZCOU4.js → configure-TEGEBYCA.js} +23 -22
- package/dist/{context-Y6Y7QPR6.js → context-AV7OEZ4D.js} +12 -12
- package/dist/{context-L3WL3X7K.js → context-E6H5RNMC.js} +56 -47
- package/dist/{context-N52ZA626.js → context-GSXUE4CT.js} +29 -27
- package/dist/{context-clear-MBQRLSDQ.js → context-clear-SHIBYK6T.js} +55 -46
- package/dist/{context-index-HVMFQHK3.js → context-index-HNG3MOME.js} +2 -2
- package/dist/{context-working-set-GS6DSO7F.js → context-working-set-5ZGKPGZQ.js} +13 -13
- package/dist/{dispatch-runner-22ZCNOM3.js → dispatch-runner-EFMJT4LD.js} +93 -64
- package/dist/{docs-7LQ23DLM.js → docs-23KQS3XK.js} +5 -5
- package/dist/doctor-QOA5FNY5.js +313 -0
- package/dist/{eval-BEC2WHDA.js → eval-TFBYQH4H.js} +2032 -156
- package/dist/eval-inventory-SXH7PDKX.js +316 -0
- package/dist/{evidence-REJUMSKM.js → evidence-ERGESKGN.js} +203 -48
- package/dist/{evolve-PY5ZBA5K.js → evolve-VDXTSYCJ.js} +52 -43
- package/dist/{extensions-HVKU65YU.js → extensions-7BGBHN57.js} +13 -7
- package/dist/{fleet-7WZEWRFA.js → fleet-2RRVDF2V.js} +228 -108
- package/dist/{fleet-commands-UVHWM76J.js → fleet-commands-VJ726XIA.js} +11 -11
- package/dist/fleet-decisions-EPAPM3XJ.js +157 -0
- package/dist/{fleet-graph-6ULH7PES.js → fleet-graph-JF5QOATM.js} +18 -15
- package/dist/fleet-inspect-VLY4S7QM.js +442 -0
- package/dist/{fleet-preflight-J53T6CCE.js → fleet-preflight-AIZUEJOY.js} +5 -5
- package/dist/{fleet-validate-72PC4SLA.js → fleet-validate-AJRPDMDV.js} +22 -19
- package/dist/fleet-verify-JFEL2L3H.js +175 -0
- package/dist/fleet-view-ZCON35AG.js +102 -0
- package/dist/{init-OG3TPGQG.js → init-DN2WWLFE.js} +72 -62
- package/dist/install-XGLBQY5E.js +13 -0
- package/dist/interop-OZBKXAYL.js +114 -0
- package/dist/{library-CNTMPLRF.js → library-YWZG7IMW.js} +21 -18
- package/dist/{memory-6IS7F275.js → memory-I4C4HMLW.js} +54 -45
- package/dist/{models-ENRJDA5W.js → models-CEYXJBO6.js} +33 -30
- package/dist/{monitor-XLDVO7TN.js → monitor-NZ6GCI3P.js} +59 -52
- package/dist/{orchestrator-6KSPYRHA.js → orchestrator-GCGQ4N5I.js} +7827 -7328
- package/dist/panes-HMABYVO4.js +58 -0
- package/dist/panes-KY6W3V2E.js +103 -0
- package/dist/{paths-DBXMZMDU.js → paths-II4K7DNR.js} +5 -5
- package/dist/{reset-RZ4ER727.js → reset-DQ6FGCSH.js} +13 -11
- package/dist/resources-BB3MVJMD.js +111 -0
- package/dist/{run-Y2CNK5RU.js → run-H2GQDUER.js} +119 -87
- package/dist/{share-A55GYP6Z.js → share-GTJN6A5O.js} +20 -17
- package/dist/{skills-ALC5J6AT.js → skills-L55TEW6R.js} +33 -24
- package/dist/{skills-eval-JPBEBYQU.js → skills-eval-XVXPH2JI.js} +67 -56
- package/dist/skills-inventory-S4MXPJFV.js +126 -0
- package/dist/slash-commands-ZSGASKJC.js +77 -0
- package/dist/{steer-GGWFUJUD.js → steer-RZGSCY4R.js} +4 -4
- package/dist/{support-MIETYA5E.js → support-PKEUNNQL.js} +6 -6
- package/dist/{targets-VGNXIR3S.js → targets-NCPZ644J.js} +68 -40
- package/dist/{terminal-lease-WOBR64YA.js → terminal-lease-44SV3YCN.js} +6 -4
- package/dist/tools-DAF3DI3C.js +27 -0
- package/dist/{trace-PNCASAXC.js → trace-FYVW2MQA.js} +207 -10
- package/dist/tui-primitives-2AKXQNZK.js +13 -0
- package/dist/{uninstall-ZJF5H5ZN.js → uninstall-DW2PNOIC.js} +5 -5
- package/dist/{upgrade-FUSUAGHR.js → upgrade-3XPP6OQL.js} +27 -24
- package/dist/{usage-N4MKVHKD.js → usage-3NLHGTU2.js} +114 -62
- package/dist/{verifiers-YAWOJ3H2.js → verifiers-SSQONKRT.js} +172 -13
- package/dist/{verify-LTDHYBGY.js → verify-3U6J7FZI.js} +10 -10
- package/dist/{web-fetch-2YHJ3KTG.js → web-fetch-S7RR6GZ7.js} +3 -3
- package/dist/{wiki-generate-6M7GHTBJ.js → wiki-generate-CEHYGPGQ.js} +75 -65
- package/dist/with-panes-MKB46MPQ.js +782 -0
- package/dist/worker/entry.js +106 -75
- package/docs/README.md +3 -2
- package/docs/acp.md +24 -3
- package/docs/alcf-provider.md +1 -1
- package/docs/architecture.md +2 -2
- package/docs/artifact-versions.md +9 -1
- package/docs/built-in-agents.md +1 -1
- package/docs/capacity-and-scheduling.md +62 -3
- package/docs/commands-and-modes.md +31 -2
- package/docs/configuration-and-targets.md +69 -12
- package/docs/context-engine.md +63 -4
- package/docs/development-pipeline.md +19 -0
- package/docs/dispatch-typed-intent.md +385 -0
- package/docs/documentation-coverage.md +5 -5
- package/docs/documentation-guide.md +1 -1
- package/docs/environment-variables.md +3 -0
- package/docs/eval-runner.md +262 -11
- package/docs/evals-internal.md +72 -2
- package/docs/evidence-and-memory.md +12 -11
- package/docs/evolution.md +1 -1
- package/docs/exit-codes-and-output.md +1 -1
- package/docs/extensions-and-sharing.md +27 -1
- package/docs/fleet-dispatch.md +25 -4
- package/docs/installation-and-lifecycle.md +15 -2
- package/docs/middleware-and-components.md +1 -1
- package/docs/model-catalog.md +10 -1
- package/docs/observability.md +55 -4
- package/docs/proactive-memory.md +127 -14
- package/docs/prompt-envelope-and-tools.md +19 -1
- package/docs/provider-adapter-cookbook.md +1 -1
- package/docs/release-cut-checklist.md +19 -3
- package/docs/safety-model.md +2 -2
- package/docs/scientific-validation.md +3 -3
- package/docs/session-lifecycle.md +1 -1
- package/docs/skills-marketplace.md +1 -1
- package/docs/tool-usage.md +18 -8
- package/docs/trace-store.md +1 -1
- package/docs/troubleshooting.md +88 -1
- package/docs/tui-design.md +1 -1
- package/docs/worker-dispatch-mechanics.md +1 -1
- package/package.json +5 -2
- package/src/cli/acp.ts +6 -2
- package/src/cli/agents.ts +1 -1
- package/src/cli/argv.ts +25 -0
- package/src/cli/config-inspect.ts +33 -6
- package/src/cli/config.ts +1 -1
- package/src/cli/configure.ts +23 -21
- package/src/cli/doctor-panes.ts +124 -0
- package/src/cli/doctor-state-size.ts +82 -0
- package/src/cli/doctor-toolchain.ts +57 -0
- package/src/cli/doctor.ts +22 -1
- package/src/cli/eval-inventory.ts +436 -0
- package/src/cli/eval.ts +93 -16
- package/src/cli/evidence-detail.ts +88 -0
- package/src/cli/evidence-inventory.ts +183 -0
- package/src/cli/evidence.ts +30 -5
- package/src/cli/extensions.ts +5 -1
- package/src/cli/fleet-decisions.ts +69 -0
- package/src/cli/fleet-inspect.ts +334 -0
- package/src/cli/fleet-verify.ts +133 -0
- package/src/cli/fleet-view.ts +810 -0
- package/src/cli/fleet.ts +179 -39
- package/src/cli/index.ts +14 -2
- package/src/cli/interop-inspect.ts +128 -0
- package/src/cli/interop.ts +34 -0
- package/src/cli/panes.ts +35 -0
- package/src/cli/reset.ts +5 -2
- package/src/cli/run.ts +58 -0
- package/src/cli/skills-inventory.ts +185 -0
- package/src/cli/skills.ts +16 -13
- package/src/cli/targets.ts +44 -13
- package/src/cli/tools.ts +321 -0
- package/src/cli/trace-inspect.ts +252 -0
- package/src/cli/trace.ts +85 -5
- package/src/cli/usage.ts +63 -14
- package/src/cli/verifiers-inspect.ts +347 -0
- package/src/cli/verifiers.ts +9 -0
- package/src/core/bus-events.ts +33 -1
- package/src/core/cache-telemetry.ts +42 -0
- package/src/core/config.ts +67 -0
- package/src/core/defaults.ts +124 -8
- package/src/core/endpoint-key.ts +27 -0
- package/src/core/residency-target-key.ts +25 -0
- package/src/core/response-schema.ts +80 -6
- package/src/core/theme-token-hex.ts +43 -0
- package/src/core/tool-names.ts +2 -1
- package/src/core/xdg.ts +1 -1
- package/src/domains/agents/fleets/build-review.md +0 -3
- package/src/domains/agents/fleets/build-test.md +0 -3
- package/src/domains/agents/result-contract-filesystem.ts +32 -0
- package/src/domains/agents/result-contract.ts +164 -35
- package/src/domains/config/classify.ts +6 -0
- package/src/domains/context/codewiki/coordinator.ts +12 -4
- package/src/domains/dispatch/admission-error.ts +9 -0
- package/src/domains/dispatch/admission.ts +52 -14
- package/src/domains/dispatch/capacity-lease.ts +118 -9
- package/src/domains/dispatch/contract.ts +11 -0
- package/src/domains/dispatch/council-topology.ts +398 -0
- package/src/domains/dispatch/execution-plan.ts +44 -4
- package/src/domains/dispatch/extension.ts +378 -82
- package/src/domains/dispatch/fleet-node-prompt.ts +62 -0
- package/src/domains/dispatch/fleet-plan.ts +7 -2
- package/src/domains/dispatch/fleet-run.ts +87 -4
- package/src/domains/dispatch/gate-decisions.ts +11 -1
- package/src/domains/dispatch/gate-role-prompts.ts +9 -0
- package/src/domains/dispatch/gate-topology.ts +289 -0
- package/src/domains/dispatch/heartbeat.ts +32 -8
- package/src/domains/dispatch/index.ts +22 -0
- package/src/domains/dispatch/intent-compatibility.ts +330 -0
- package/src/domains/dispatch/intent.ts +85 -1
- package/src/domains/dispatch/orphan-recovery.ts +5 -0
- package/src/domains/dispatch/reservation-store.ts +139 -11
- package/src/domains/dispatch/run-event-journal-bridge.ts +149 -0
- package/src/domains/dispatch/run-event-journal.ts +598 -0
- package/src/domains/dispatch/state.ts +49 -1
- package/src/domains/dispatch/types.ts +13 -0
- package/src/domains/dispatch/validation.ts +33 -8
- package/src/domains/dispatch/worker-spawn.ts +25 -11
- package/src/domains/dispatch/write-boundary-enforcer.ts +20 -3
- package/src/domains/dispatch/write-boundary.ts +62 -1
- package/src/domains/eval/artifacts/store.ts +62 -0
- package/src/domains/eval/compare/behavioral.ts +224 -0
- package/src/domains/eval/compare/compare.ts +342 -2
- package/src/domains/eval/compare/envelope.ts +128 -0
- package/src/domains/eval/compare/gates.ts +24 -6
- package/src/domains/eval/compare/thresholds.ts +30 -3
- package/src/domains/eval/execution-provenance.ts +240 -0
- package/src/domains/eval/inventory.ts +113 -0
- package/src/domains/eval/metrics/aggregate.ts +136 -0
- package/src/domains/eval/metrics/call-ledger-stream.ts +112 -0
- package/src/domains/eval/metrics/tracked.ts +413 -0
- package/src/domains/eval/provenance.ts +117 -0
- package/src/domains/eval/reports/comparison.ts +128 -0
- package/src/domains/eval/reports/junit.ts +17 -3
- package/src/domains/eval/reports/markdown.ts +3 -3
- package/src/domains/eval/reports/text.ts +14 -0
- package/src/domains/eval/run-compare.ts +20 -0
- package/src/domains/eval/runners/clio-run.ts +127 -0
- package/src/domains/eval/runners/external-command.ts +28 -3
- package/src/domains/eval/schema/adapter.ts +111 -0
- package/src/domains/eval/schema/artifact.ts +20 -0
- package/src/domains/eval/schema/behavioral-metrics.ts +204 -0
- package/src/domains/eval/schema/behavioral.ts +520 -0
- package/src/domains/eval/schema/execution-envelope.ts +194 -0
- package/src/domains/eval/schema/serving.ts +105 -0
- package/src/domains/eval/schema/suite.ts +38 -8
- package/src/domains/eval/schema/validate.ts +58 -3
- package/src/domains/eval/schema/verdict.ts +237 -0
- package/src/domains/eval/suites/resolve.ts +2 -0
- package/src/domains/eval/suites/run.ts +264 -33
- package/src/domains/eval/verifiers/command.ts +2 -1
- package/src/domains/eval/workspaces/temp-copy.ts +145 -13
- package/src/domains/evidence/build.ts +2 -13
- package/src/domains/evidence/eval.ts +2 -12
- package/src/domains/evidence/findings-markdown.ts +33 -0
- package/src/domains/evidence/run-trust.ts +7 -113
- package/src/domains/evidence/store.ts +6 -0
- package/src/domains/evidence/trust-projection.ts +2 -2
- package/src/domains/extensions/compatibility.ts +285 -0
- package/src/domains/extensions/discovery.ts +38 -3
- package/src/domains/extensions/resources.ts +1 -1
- package/src/domains/extensions/state.ts +12 -3
- package/src/domains/extensions/types.ts +2 -0
- package/src/domains/lifecycle/doctor.ts +69 -1
- package/src/domains/memory/index.ts +14 -1
- package/src/domains/memory/task-bank-promotion.ts +64 -0
- package/src/domains/memory/task-memory-policy.ts +82 -17
- package/src/domains/memory/task-memory-spend.ts +131 -0
- package/src/domains/memory/task-memory-status.ts +7 -0
- package/src/domains/memory/task-memory-telemetry.ts +3 -0
- package/src/domains/middleware/index.ts +1 -0
- package/src/domains/middleware/memory-intervention.ts +97 -21
- package/src/domains/middleware/memory-step-endpoint.ts +71 -0
- package/src/domains/mux/contract.ts +434 -0
- package/src/domains/mux/detect.ts +158 -0
- package/src/domains/mux/extension.ts +47 -0
- package/src/domains/mux/index.ts +96 -0
- package/src/domains/mux/manifest.ts +6 -0
- package/src/domains/mux/operations.ts +164 -0
- package/src/domains/mux/pane-registry.ts +90 -0
- package/src/domains/mux/protocol.ts +49 -0
- package/src/domains/mux/socket-client.ts +816 -0
- package/src/domains/mux/types.ts +222 -0
- package/src/domains/mux/viewer-command.ts +59 -0
- package/src/domains/mux/yazi/assets/init.lua +2 -0
- package/src/domains/mux/yazi/assets/plugins/git.yazi/LICENSE +21 -0
- package/src/domains/mux/yazi/assets/plugins/git.yazi/README.md +78 -0
- package/src/domains/mux/yazi/assets/plugins/git.yazi/main.lua +255 -0
- package/src/domains/mux/yazi/assets/plugins/git.yazi/types.lua +12 -0
- package/src/domains/mux/yazi/assets/yazi.toml +17 -0
- package/src/domains/mux/yazi/event-stream.ts +180 -0
- package/src/domains/mux/yazi/profile.ts +299 -0
- package/src/domains/mux/yazi/session.ts +228 -0
- package/src/domains/mux/yazi/theme.ts +30 -0
- package/src/domains/observability/background-memory-usage.ts +140 -0
- package/src/domains/observability/cost.ts +22 -1
- package/src/domains/observability/index.ts +9 -0
- package/src/domains/observability/out-of-turn-usage.ts +51 -2
- package/src/domains/observability/trace-store.ts +234 -2
- package/src/domains/prompts/compiler.ts +100 -13
- package/src/domains/providers/endpoint-capacity.ts +228 -0
- package/src/domains/providers/endpoint-slots-store.ts +189 -0
- package/src/domains/providers/extension.ts +20 -3
- package/src/domains/providers/index.ts +32 -0
- package/src/domains/providers/model-runtime-capabilities.ts +32 -0
- package/src/domains/providers/models/local-models/clio-local-coding-targets.yaml +243 -1
- package/src/domains/providers/runtime-resolution.ts +8 -1
- package/src/domains/providers/runtimes/boot-manifest.ts +1 -0
- package/src/domains/providers/runtimes/builtins.ts +2 -0
- package/src/domains/providers/runtimes/common/probe-helpers.ts +31 -9
- package/src/domains/providers/runtimes/local-native/llamacpp-anthropic.ts +1 -1
- package/src/domains/providers/runtimes/local-native/llamacpp-completion.ts +1 -1
- package/src/domains/providers/runtimes/local-native/llamacpp-embed.ts +1 -1
- package/src/domains/providers/runtimes/local-native/llamacpp-rerank.ts +1 -1
- package/src/domains/providers/runtimes/local-native/llamacpp.ts +4 -1
- package/src/domains/providers/runtimes/local-native/lmstudio.ts +4 -1
- package/src/domains/providers/runtimes/local-native/ollama-native.ts +6 -1
- package/src/domains/providers/runtimes/protocol/litellm.ts +375 -0
- package/src/domains/providers/support.ts +1 -0
- package/src/domains/providers/target-model-cache.ts +124 -0
- package/src/domains/providers/types/capability-flags.ts +2 -0
- package/src/domains/providers/types/target-descriptor.ts +2 -0
- package/src/domains/resources/index.ts +3 -0
- package/src/domains/resources/prompts/loader.ts +95 -33
- package/src/domains/resources/skills/loader.ts +33 -0
- package/src/domains/safety/action-classifier.ts +6 -0
- package/src/domains/safety/call-target.ts +52 -0
- package/src/domains/safety/run-effects.ts +35 -4
- package/src/domains/session/context-accounting.ts +52 -1
- package/src/domains/session/context-ledger.ts +37 -13
- package/src/domains/session/index.ts +6 -0
- package/src/domains/session/prompt-cache.ts +140 -0
- package/src/domains/session/prompt-manifest.ts +42 -0
- package/src/domains/toolchain/archive.ts +175 -0
- package/src/domains/toolchain/contract.ts +28 -0
- package/src/domains/toolchain/extension.ts +47 -0
- package/src/domains/toolchain/index.ts +39 -0
- package/src/domains/toolchain/install.ts +327 -0
- package/src/domains/toolchain/manifest.ts +8 -0
- package/src/domains/toolchain/paths.ts +34 -0
- package/src/domains/toolchain/registry.ts +265 -0
- package/src/domains/toolchain/remove.ts +218 -0
- package/src/domains/toolchain/resolve.ts +182 -0
- package/src/domains/toolchain/types.ts +113 -0
- package/src/domains/toolchain/version.ts +88 -0
- package/src/engine/acp/adapter.ts +18 -3
- package/src/engine/acp/server.ts +413 -70
- package/src/engine/acp/types.ts +19 -1
- package/src/engine/ai.ts +35 -0
- package/src/engine/apis/llamacpp-residency.ts +55 -3
- package/src/engine/apis/lmstudio.ts +25 -5
- package/src/engine/apis/ollama-native.ts +2 -1
- package/src/engine/apis/openai-completions.ts +80 -17
- package/src/engine/apis/residency-lock.ts +3 -1
- package/src/engine/apis/residency.ts +34 -1
- package/src/engine/claude/sdk-module.ts +98 -0
- package/src/engine/claude/sdk-runtime.ts +19 -11
- package/src/engine/provider-payload.ts +29 -1
- package/src/engine/tui-primitives.ts +21 -0
- package/src/engine/tui.ts +1 -0
- package/src/engine/worker-runtime.ts +2 -13
- package/src/entry/boot-options.ts +2 -0
- package/src/entry/orchestrator.ts +279 -35
- package/src/entry/panes-activation.ts +31 -0
- package/src/entry/with-panes.ts +20 -0
- package/src/interactive/chat-loop-messages.ts +26 -7
- package/src/interactive/chat-loop.ts +318 -41
- package/src/interactive/chat-panel.ts +62 -8
- package/src/interactive/clio-editor.ts +45 -8
- package/src/interactive/context-activity.ts +5 -1
- package/src/interactive/context-meter.ts +1 -1
- package/src/interactive/context-overlay.ts +41 -10
- package/src/interactive/cost-overlay.ts +66 -6
- package/src/interactive/council-grid.ts +1 -3
- package/src/interactive/council.ts +11 -0
- package/src/interactive/dispatch-board.ts +102 -20
- package/src/interactive/fleet-run-preview.ts +41 -15
- package/src/interactive/handoff-round.ts +41 -2
- package/src/interactive/interactive-application.ts +177 -7
- package/src/interactive/interactive-input-runtime.ts +15 -0
- package/src/interactive/interactive-presentation.ts +4 -0
- package/src/interactive/interactive-shell.ts +20 -17
- package/src/interactive/interactive-slash-runtime.ts +63 -10
- package/src/interactive/memory-overlay.ts +9 -0
- package/src/interactive/modal-marker.ts +170 -0
- package/src/interactive/mutation-preview.ts +295 -0
- package/src/interactive/mux-bridge.ts +214 -0
- package/src/interactive/overlay-frame.ts +58 -2
- package/src/interactive/overlay-general-openers.ts +17 -0
- package/src/interactive/overlay-key-routing.ts +52 -3
- package/src/interactive/overlay-lifecycle.ts +56 -7
- package/src/interactive/overlay-model-selectors.ts +40 -3
- package/src/interactive/overlay-permission-lifecycle.ts +112 -24
- package/src/interactive/overlay-session-lifecycle.ts +73 -9
- package/src/interactive/overlay-transitions.ts +18 -4
- package/src/interactive/overlays/agents.ts +1 -0
- package/src/interactive/overlays/ask-user.ts +227 -49
- package/src/interactive/overlays/auth-dialog.ts +1 -0
- package/src/interactive/overlays/context-reset.ts +1 -0
- package/src/interactive/overlays/cwd-fallback.ts +1 -0
- package/src/interactive/overlays/decisions.ts +11 -11
- package/src/interactive/overlays/extensions.ts +1 -0
- package/src/interactive/overlays/fleet-run-approval.ts +1 -0
- package/src/interactive/overlays/handoff-review.ts +1 -0
- package/src/interactive/overlays/help-reference.ts +6 -0
- package/src/interactive/overlays/interop.ts +1 -0
- package/src/interactive/overlays/library-install-confirm.ts +1 -0
- package/src/interactive/overlays/library-tabs.ts +28 -0
- package/src/interactive/overlays/list-overlay.ts +10 -1
- package/src/interactive/overlays/message-picker.ts +1 -0
- package/src/interactive/overlays/model-scope.ts +86 -0
- package/src/interactive/overlays/model-selector.ts +1 -0
- package/src/interactive/overlays/prompts.ts +12 -1
- package/src/interactive/overlays/session-selector.ts +1 -0
- package/src/interactive/overlays/settings-sections.ts +30 -0
- package/src/interactive/overlays/settings.ts +614 -45
- package/src/interactive/overlays/side-question.ts +1 -0
- package/src/interactive/overlays/skills-hub.ts +3 -11
- package/src/interactive/overlays/tree-selector.ts +1 -0
- package/src/interactive/pane-policy.ts +46 -0
- package/src/interactive/panes-runtime.ts +292 -0
- package/src/interactive/permission-hint.ts +34 -2
- package/src/interactive/permission-overlay.ts +159 -9
- package/src/interactive/prewarm.ts +197 -0
- package/src/interactive/render-trace.ts +162 -15
- package/src/interactive/renderers/compaction-summary.ts +29 -0
- package/src/interactive/renderers/tool-execution.ts +4 -0
- package/src/interactive/renderers/worker-entry.ts +122 -14
- package/src/interactive/side-question.ts +58 -1
- package/src/interactive/slash-commands.ts +251 -15
- package/src/interactive/status/controller.ts +11 -0
- package/src/interactive/status/state-machine.ts +54 -2
- package/src/interactive/status/types.ts +7 -0
- package/src/interactive/tasks-overlay.ts +1 -0
- package/src/interactive/terminal-lease.ts +2 -0
- package/src/interactive/theme/tokens.ts +3 -14
- package/src/interactive/turn-context.ts +346 -33
- package/src/interactive/turn-persistence.ts +14 -4
- package/src/interactive/turn-prewarm.ts +364 -0
- package/src/interactive/turn-queues.ts +7 -4
- package/src/interactive/turn-runtime.ts +8 -1
- package/src/interactive/turn-state.ts +23 -0
- package/src/interactive/view/artifacts.ts +109 -1
- package/src/interactive/view/view-overlay.ts +29 -3
- package/src/interactive/watch-pane.ts +152 -0
- package/src/interactive/worker-progress.ts +7 -1
- package/src/interactive/worker-receipts.ts +19 -1
- package/src/interactive/worker-stream.ts +5 -0
- package/src/interactive/yazi-bridge.ts +444 -0
- package/src/tools/ask-user.ts +43 -2
- package/src/tools/bootstrap.ts +26 -2
- package/src/tools/builtin-tool-catalog.ts +15 -0
- package/src/tools/compete-worktrees.ts +83 -2
- package/src/tools/core-bootstrap.ts +2 -1
- package/src/tools/dispatch-admission.ts +14 -3
- package/src/tools/dispatch-arguments.ts +20 -20
- package/src/tools/dispatch-plan.ts +17 -9
- package/src/tools/dispatch-run-events.ts +134 -19
- package/src/tools/dispatch-runner.ts +29 -7
- package/src/tools/dispatch-scout.ts +1 -1
- package/src/tools/dispatch-types.ts +15 -3
- package/src/tools/dispatch.ts +1 -1
- package/src/tools/executables.ts +17 -14
- package/src/tools/observation.ts +54 -4
- package/src/tools/panes-surface.ts +38 -0
- package/src/tools/panes.ts +112 -0
- package/src/tools/policy.ts +10 -1
- package/src/tools/presentation.ts +1 -0
- package/src/tools/registry.ts +16 -0
- package/dist/chunk-AOCYTWAV.js +0 -449
- package/dist/chunk-HLE42MG7.js +0 -37
- package/dist/chunk-HWUFFB6L.js +0 -83
- package/dist/chunk-JOZYP4GM.js +0 -279
- package/dist/doctor-M7YEDGAE.js +0 -91
|
@@ -84,6 +84,8 @@ function capabilities(model: LmStudioModelInfo, instance?: LmStudioLoadedInstanc
|
|
|
84
84
|
out.reasoning = model.reasoningOptions.some((option) => option !== "off");
|
|
85
85
|
const contextWindow = loadedContextLength(instance) ?? model.maxContextLength;
|
|
86
86
|
if (contextWindow !== undefined) out.contextWindow = contextWindow;
|
|
87
|
+
const parallel = instance?.config.parallel;
|
|
88
|
+
if (typeof parallel === "number" && Number.isInteger(parallel) && parallel > 0) out.parallelSlots = parallel;
|
|
87
89
|
return out;
|
|
88
90
|
}
|
|
89
91
|
|
|
@@ -144,6 +146,7 @@ function probeFromCatalog(catalog: LmStudioCatalog, target: TargetDescriptor): P
|
|
|
144
146
|
const selected = resolveModel(models, configuredModel(target));
|
|
145
147
|
const result: ProbeResult = {
|
|
146
148
|
ok: true,
|
|
149
|
+
discoveredCapabilities: { parallelSlots: 1 },
|
|
147
150
|
models: ids,
|
|
148
151
|
modelCapabilities,
|
|
149
152
|
modelStates,
|
|
@@ -161,7 +164,7 @@ function probeFromCatalog(catalog: LmStudioCatalog, target: TargetDescriptor): P
|
|
|
161
164
|
};
|
|
162
165
|
if (catalog.latencyMs !== undefined) result.latencyMs = catalog.latencyMs;
|
|
163
166
|
if (selected) {
|
|
164
|
-
result.discoveredCapabilities = capabilities(selected.model, selected.instance);
|
|
167
|
+
result.discoveredCapabilities = { parallelSlots: 1, ...capabilities(selected.model, selected.instance) };
|
|
165
168
|
result.capabilityModelId = configuredModel(target) ?? selected.model.key;
|
|
166
169
|
}
|
|
167
170
|
const loaded = models.flatMap((model) =>
|
|
@@ -33,6 +33,11 @@ function positiveNumber(value: unknown): number | undefined {
|
|
|
33
33
|
return typeof value === "number" && Number.isFinite(value) && value > 0 ? value : undefined;
|
|
34
34
|
}
|
|
35
35
|
|
|
36
|
+
function ollamaParallelSlots(): number {
|
|
37
|
+
const parsed = Number(process.env.OLLAMA_NUM_PARALLEL);
|
|
38
|
+
return Number.isInteger(parsed) && parsed > 0 ? parsed : 1;
|
|
39
|
+
}
|
|
40
|
+
|
|
36
41
|
/**
|
|
37
42
|
* Resident models reported by `/api/ps`, keyed by wire id. Best-effort: the
|
|
38
43
|
* probe still succeeds on `/api/tags` alone, so an `/api/ps` failure (older
|
|
@@ -83,7 +88,7 @@ const ollamaNativeRuntime: RuntimeDescriptor = {
|
|
|
83
88
|
if (result.latencyMs !== undefined) failed.latencyMs = result.latencyMs;
|
|
84
89
|
return failed;
|
|
85
90
|
}
|
|
86
|
-
const out: ProbeResult = { ok: true };
|
|
91
|
+
const out: ProbeResult = { ok: true, discoveredCapabilities: { parallelSlots: ollamaParallelSlots() } };
|
|
87
92
|
if (result.latencyMs !== undefined) out.latencyMs = result.latencyMs;
|
|
88
93
|
const modelStates = await probeResidentModelStates(base, ctx);
|
|
89
94
|
if (modelStates) out.modelStates = modelStates;
|
|
@@ -0,0 +1,375 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* LiteLLM proxy: an OpenAI-compatible gateway that fronts a fleet.
|
|
3
|
+
*
|
|
4
|
+
* This is a separate runtime from `openai-compat` rather than a target flag on
|
|
5
|
+
* it, because a gateway answers two questions the generic protocol cannot.
|
|
6
|
+
*
|
|
7
|
+
* First, capability discovery. A gateway publishes semantic aliases: the client
|
|
8
|
+
* asks for `code` and the proxy decides that means `katcoder2.5-35b-moe` on one
|
|
9
|
+
* particular host. LiteLLM's `/v1/models` is the plain OpenAI listing, so every
|
|
10
|
+
* row flattens to a bare id and the context window, tool support, and modality
|
|
11
|
+
* of the model actually behind the alias are all erased. Reached over
|
|
12
|
+
* `openai-compat`, a 262k tool-calling coder is indistinguishable from a 4k
|
|
13
|
+
* chat toy, and Clio plans the session against its own assumed floor. LiteLLM
|
|
14
|
+
* publishes the real numbers on `/v1/model/info` instead, which is what this
|
|
15
|
+
* probe reads.
|
|
16
|
+
*
|
|
17
|
+
* Second, routed-deployment attribution. Which physical model answered is a
|
|
18
|
+
* per-response fact behind an alias, and LiteLLM returns it in `x-litellm-*`
|
|
19
|
+
* response headers. See {@link routedDeploymentFromHeaders}.
|
|
20
|
+
*
|
|
21
|
+
* Structured output is the one property worth stating explicitly, because
|
|
22
|
+
* getting it wrong is silent. `src/core/response-schema.ts` deliberately keys
|
|
23
|
+
* the schema dialect on runtime id and not on api family, since a generic
|
|
24
|
+
* OpenAI-compatible gateway answers HTTP 200 to a `response_format` spelling it
|
|
25
|
+
* does not implement and returns unconstrained JSON. LiteLLM earns its entry in
|
|
26
|
+
* that table by measurement rather than by assumption: against the homelab
|
|
27
|
+
* gateway on 2026-08-30, `{"type":"json_schema", json_schema:{...}}` was
|
|
28
|
+
* grammar-enforced end to end on both a llama.cpp upstream and an LM Studio
|
|
29
|
+
* upstream, `{"type":"json_object", schema:{...}}` was enforced on llama.cpp
|
|
30
|
+
* and rejected HTTP 400 by LM Studio, and the same prompt with no
|
|
31
|
+
* `response_format` returned plain prose. `drop_params: true` did not strip
|
|
32
|
+
* either spelling. The standard `json_schema` dialect is therefore the one that
|
|
33
|
+
* holds across every upstream, and it is what this runtime declares.
|
|
34
|
+
*/
|
|
35
|
+
|
|
36
|
+
import { CLIO_MIN_CONTEXT_WINDOW, CLIO_MIN_MAX_OUTPUT_TOKENS } from "../../../../core/context-floor.js";
|
|
37
|
+
import type { Api, Model } from "../../../../engine/types.js";
|
|
38
|
+
import { probeJson } from "../../probe/http.js";
|
|
39
|
+
import type { CapabilityFlags } from "../../types/capability-flags.js";
|
|
40
|
+
import type { KnowledgeBaseHit } from "../../types/knowledge-base.js";
|
|
41
|
+
import type { ProbeContext, ProbeModelStatus, ProbeResult, RuntimeDescriptor } from "../../types/runtime-descriptor.js";
|
|
42
|
+
import type { TargetDescriptor } from "../../types/target-descriptor.js";
|
|
43
|
+
import { stripTrailingSlash, synthLocalModel, withV1 } from "../common/local-synth.js";
|
|
44
|
+
|
|
45
|
+
const LITELLM_PROVIDER = "litellm";
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Conservative until the probe answers. A gateway that does not publish
|
|
49
|
+
* `model_info` has told Clio nothing, and claiming tools on a target whose tool
|
|
50
|
+
* surface is unknown produces a worker that fails on its first tool call rather
|
|
51
|
+
* than one that is never admitted.
|
|
52
|
+
*/
|
|
53
|
+
const defaultCapabilities: CapabilityFlags = {
|
|
54
|
+
chat: true,
|
|
55
|
+
tools: false,
|
|
56
|
+
reasoning: false,
|
|
57
|
+
vision: false,
|
|
58
|
+
audio: false,
|
|
59
|
+
embeddings: false,
|
|
60
|
+
rerank: false,
|
|
61
|
+
fim: false,
|
|
62
|
+
structuredOutputs: "json-schema",
|
|
63
|
+
contextWindow: CLIO_MIN_CONTEXT_WINDOW,
|
|
64
|
+
maxTokens: CLIO_MIN_MAX_OUTPUT_TOKENS,
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
/** The server root. This runtime's own paths carry `/v1` where they need it. */
|
|
68
|
+
function rootUrl(target: TargetDescriptor): string | null {
|
|
69
|
+
if (!target.url) return null;
|
|
70
|
+
const trimmed = stripTrailingSlash(target.url);
|
|
71
|
+
return trimmed.endsWith("/v1") ? trimmed.slice(0, -"/v1".length) : trimmed;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function bearerHeaders(target: TargetDescriptor, ctx: ProbeContext): Record<string, string> {
|
|
75
|
+
const headers: Record<string, string> = { ...(target.auth?.headers ?? {}) };
|
|
76
|
+
const envName = target.auth?.apiKeyEnvVar;
|
|
77
|
+
const fromEnv = envName && ctx.credentialsPresent.has(envName) ? process.env[envName]?.trim() : undefined;
|
|
78
|
+
const token = ctx.authToken?.trim() || fromEnv;
|
|
79
|
+
if (token) headers.authorization = `Bearer ${token}`;
|
|
80
|
+
return headers;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
interface LiteLLMModelInfoRow {
|
|
84
|
+
model_name?: unknown;
|
|
85
|
+
litellm_params?: { model?: unknown; api_base?: unknown };
|
|
86
|
+
model_info?: Record<string, unknown>;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
interface LiteLLMModelInfoResponse {
|
|
90
|
+
data?: ReadonlyArray<LiteLLMModelInfoRow>;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
interface LiteLLMModelsResponse {
|
|
94
|
+
data?: ReadonlyArray<{ id?: unknown }>;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
function positiveInteger(value: unknown): number | undefined {
|
|
98
|
+
return typeof value === "number" && Number.isFinite(value) && value > 0 ? Math.floor(value) : undefined;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function boolean(value: unknown): boolean | undefined {
|
|
102
|
+
return typeof value === "boolean" ? value : undefined;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Project one LiteLLM `model_info` block onto Clio's capability flags.
|
|
107
|
+
*
|
|
108
|
+
* Only fields the gateway actually filled in are returned. A `model_info` that
|
|
109
|
+
* declares nothing leaves the whole record empty rather than reporting zeros,
|
|
110
|
+
* so the caller can tell "the gateway says this model has no vision" apart from
|
|
111
|
+
* "the gateway did not say", and merge accordingly.
|
|
112
|
+
*/
|
|
113
|
+
export function capabilitiesFromLiteLLMModelInfo(info: Record<string, unknown>): Partial<CapabilityFlags> {
|
|
114
|
+
const caps: Partial<CapabilityFlags> = {};
|
|
115
|
+
const contextWindow = positiveInteger(info.max_input_tokens) ?? positiveInteger(info.max_tokens);
|
|
116
|
+
if (contextWindow !== undefined) caps.contextWindow = contextWindow;
|
|
117
|
+
const maxTokens = positiveInteger(info.max_output_tokens);
|
|
118
|
+
if (maxTokens !== undefined) caps.maxTokens = maxTokens;
|
|
119
|
+
const tools = boolean(info.supports_function_calling);
|
|
120
|
+
if (tools !== undefined) caps.tools = tools;
|
|
121
|
+
const vision = boolean(info.supports_vision);
|
|
122
|
+
if (vision !== undefined) caps.vision = vision;
|
|
123
|
+
const reasoning = boolean(info.supports_reasoning);
|
|
124
|
+
if (reasoning !== undefined) caps.reasoning = reasoning;
|
|
125
|
+
const audio = boolean(info.supports_audio_input);
|
|
126
|
+
if (audio !== undefined) caps.audio = audio;
|
|
127
|
+
// `mode` is LiteLLM's own surface discriminator. An embedding deployment is
|
|
128
|
+
// not a chat deployment, and admitting it as one produces a run that fails
|
|
129
|
+
// at the first completion rather than at selection.
|
|
130
|
+
if (info.mode === "embedding") {
|
|
131
|
+
caps.chat = false;
|
|
132
|
+
caps.embeddings = true;
|
|
133
|
+
}
|
|
134
|
+
if (info.mode === "rerank") {
|
|
135
|
+
caps.chat = false;
|
|
136
|
+
caps.rerank = true;
|
|
137
|
+
}
|
|
138
|
+
if (info.mode === "chat") caps.chat = true;
|
|
139
|
+
// Measured, not inferred: see the module header.
|
|
140
|
+
if (boolean(info.supports_response_schema) === true) caps.structuredOutputs = "json-schema";
|
|
141
|
+
return caps;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
interface LiteLLMCatalog {
|
|
145
|
+
models: string[];
|
|
146
|
+
modelCapabilities: Record<string, Partial<CapabilityFlags>>;
|
|
147
|
+
modelStates: Record<string, ProbeModelStatus>;
|
|
148
|
+
/** Physical deployment behind each alias, for display. */
|
|
149
|
+
deployments: Record<string, { model: string; apiBase?: string }>;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
const EMPTY_CATALOG: LiteLLMCatalog = { models: [], modelCapabilities: {}, modelStates: {}, deployments: {} };
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Read the catalog from `/v1/model/info`, falling back to `/v1/models`.
|
|
156
|
+
*
|
|
157
|
+
* The detail endpoint is the only one that carries capabilities, but it can be
|
|
158
|
+
* refused for a virtual key with narrower permissions than the master key. A
|
|
159
|
+
* gateway that answers the plain listing and refuses the detail is still usable;
|
|
160
|
+
* it just cannot tell Clio anything beyond which aliases exist, so the target
|
|
161
|
+
* falls back to its declared capabilities exactly as `openai-compat` would.
|
|
162
|
+
*/
|
|
163
|
+
async function fetchCatalog(base: string, ctx: ProbeContext, headers: Record<string, string>): Promise<LiteLLMCatalog> {
|
|
164
|
+
const detailOpts = { url: `${base}/v1/model/info`, timeoutMs: ctx.httpTimeoutMs, headers } as const;
|
|
165
|
+
const detail = await (ctx.signal
|
|
166
|
+
? probeJson<LiteLLMModelInfoResponse>({ ...detailOpts, signal: ctx.signal })
|
|
167
|
+
: probeJson<LiteLLMModelInfoResponse>(detailOpts));
|
|
168
|
+
|
|
169
|
+
if (detail.ok && Array.isArray(detail.data?.data)) {
|
|
170
|
+
const catalog: LiteLLMCatalog = { models: [], modelCapabilities: {}, modelStates: {}, deployments: {} };
|
|
171
|
+
for (const row of detail.data.data) {
|
|
172
|
+
if (typeof row?.model_name !== "string" || row.model_name.length === 0) continue;
|
|
173
|
+
const alias = row.model_name;
|
|
174
|
+
// One alias can carry several deployments. They share a name and Clio
|
|
175
|
+
// addresses them as one model, so the first row establishes the entry
|
|
176
|
+
// and later rows for the same alias are the load-balancing pool behind
|
|
177
|
+
// it rather than separate models.
|
|
178
|
+
if (catalog.deployments[alias] !== undefined) continue;
|
|
179
|
+
catalog.models.push(alias);
|
|
180
|
+
const caps = row.model_info ? capabilitiesFromLiteLLMModelInfo(row.model_info) : {};
|
|
181
|
+
if (Object.keys(caps).length > 0) catalog.modelCapabilities[alias] = caps;
|
|
182
|
+
const upstream = row.litellm_params?.model;
|
|
183
|
+
const apiBase = row.litellm_params?.api_base;
|
|
184
|
+
catalog.deployments[alias] = {
|
|
185
|
+
model: typeof upstream === "string" ? upstream : alias,
|
|
186
|
+
...(typeof apiBase === "string" ? { apiBase } : {}),
|
|
187
|
+
};
|
|
188
|
+
}
|
|
189
|
+
if (catalog.models.length > 0) return catalog;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
const listOpts = { url: `${base}/v1/models`, timeoutMs: ctx.httpTimeoutMs, headers } as const;
|
|
193
|
+
const list = await (ctx.signal
|
|
194
|
+
? probeJson<LiteLLMModelsResponse>({ ...listOpts, signal: ctx.signal })
|
|
195
|
+
: probeJson<LiteLLMModelsResponse>(listOpts));
|
|
196
|
+
if (!list.ok || !Array.isArray(list.data?.data)) return EMPTY_CATALOG;
|
|
197
|
+
const models = list.data.data
|
|
198
|
+
.map((row) => (typeof row?.id === "string" ? row.id : null))
|
|
199
|
+
.filter((id): id is string => id !== null && id.length > 0);
|
|
200
|
+
return { models, modelCapabilities: {}, modelStates: {}, deployments: {} };
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
/**
|
|
204
|
+
* The routed deployment LiteLLM reports for one response.
|
|
205
|
+
*
|
|
206
|
+
* Behind an alias the physical model is a per-request fact: a fallback, a
|
|
207
|
+
* context-window promotion, or an ordinary load-balancing choice all change it
|
|
208
|
+
* without changing what the client asked for. Reporting the alias back as the
|
|
209
|
+
* model is how a gateway hides an outage, and it is exactly what an operator
|
|
210
|
+
* needs to see. LiteLLM answers in headers on every completion.
|
|
211
|
+
*/
|
|
212
|
+
export interface RoutedDeployment {
|
|
213
|
+
/** The alias the client asked for, e.g. `code`. */
|
|
214
|
+
group?: string;
|
|
215
|
+
/** The physical model that answered, e.g. `openai/katcoder2.5-35b-moe`. */
|
|
216
|
+
model?: string;
|
|
217
|
+
/** The upstream that served it. */
|
|
218
|
+
apiBase?: string;
|
|
219
|
+
/** Stable id of the specific deployment inside the group. */
|
|
220
|
+
deploymentId?: string;
|
|
221
|
+
/** Non-zero when the request did not reach its first-choice deployment. */
|
|
222
|
+
attemptedFallbacks?: number;
|
|
223
|
+
attemptedRetries?: number;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
function headerValue(headers: { get(name: string): string | null }, name: string): string | undefined {
|
|
227
|
+
const raw = headers.get(name)?.trim();
|
|
228
|
+
return raw && raw.length > 0 ? raw : undefined;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
function headerInteger(headers: { get(name: string): string | null }, name: string): number | undefined {
|
|
232
|
+
const raw = headerValue(headers, name);
|
|
233
|
+
if (raw === undefined) return undefined;
|
|
234
|
+
const parsed = Number.parseInt(raw, 10);
|
|
235
|
+
return Number.isFinite(parsed) ? parsed : undefined;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
/**
|
|
239
|
+
* Extract the routed deployment from a LiteLLM response, or null when the
|
|
240
|
+
* headers are absent. Absent is the normal answer for every non-LiteLLM target,
|
|
241
|
+
* so callers treat null as "no attribution available" rather than an error.
|
|
242
|
+
*/
|
|
243
|
+
export function routedDeploymentFromHeaders(headers: { get(name: string): string | null }): RoutedDeployment | null {
|
|
244
|
+
const routed: RoutedDeployment = {};
|
|
245
|
+
const group = headerValue(headers, "x-litellm-model-group");
|
|
246
|
+
if (group !== undefined) routed.group = group;
|
|
247
|
+
const model = headerValue(headers, "x-litellm-model-name");
|
|
248
|
+
if (model !== undefined) routed.model = model;
|
|
249
|
+
const apiBase = headerValue(headers, "x-litellm-model-api-base");
|
|
250
|
+
if (apiBase !== undefined) routed.apiBase = apiBase;
|
|
251
|
+
const deploymentId = headerValue(headers, "x-litellm-model-id");
|
|
252
|
+
if (deploymentId !== undefined) routed.deploymentId = deploymentId;
|
|
253
|
+
const fallbacks = headerInteger(headers, "x-litellm-attempted-fallbacks");
|
|
254
|
+
if (fallbacks !== undefined) routed.attemptedFallbacks = fallbacks;
|
|
255
|
+
const retries = headerInteger(headers, "x-litellm-attempted-retries");
|
|
256
|
+
if (retries !== undefined) routed.attemptedRetries = retries;
|
|
257
|
+
return Object.keys(routed).length > 0 ? routed : null;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
/**
|
|
261
|
+
* One-line attribution for a routed response.
|
|
262
|
+
*
|
|
263
|
+
* A request that fell back says so. `code -> openai/qwen3.8-27b-dense @
|
|
264
|
+
* mini.tail78f300.ts.net:8080 (fallback)` is the whole point of the runtime:
|
|
265
|
+
* the operator asked for the coder, the coder was asleep, and something else
|
|
266
|
+
* answered.
|
|
267
|
+
*/
|
|
268
|
+
export function formatRoutedDeployment(routed: RoutedDeployment): string {
|
|
269
|
+
const parts: string[] = [];
|
|
270
|
+
if (routed.group && routed.model && routed.group !== routed.model) {
|
|
271
|
+
parts.push(`${routed.group} -> ${routed.model}`);
|
|
272
|
+
} else if (routed.model ?? routed.group) {
|
|
273
|
+
parts.push((routed.model ?? routed.group) as string);
|
|
274
|
+
}
|
|
275
|
+
if (routed.apiBase) {
|
|
276
|
+
let host = routed.apiBase;
|
|
277
|
+
try {
|
|
278
|
+
host = new URL(routed.apiBase).host;
|
|
279
|
+
} catch {
|
|
280
|
+
// A non-URL api_base is displayed verbatim.
|
|
281
|
+
}
|
|
282
|
+
parts.push(`@ ${host}`);
|
|
283
|
+
}
|
|
284
|
+
if ((routed.attemptedFallbacks ?? 0) > 0) parts.push("(fallback)");
|
|
285
|
+
else if ((routed.attemptedRetries ?? 0) > 0) parts.push("(retried)");
|
|
286
|
+
return parts.join(" ");
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
const litellmRuntime: RuntimeDescriptor = {
|
|
290
|
+
id: "litellm",
|
|
291
|
+
displayName: "LiteLLM gateway",
|
|
292
|
+
kind: "http",
|
|
293
|
+
tier: "protocol",
|
|
294
|
+
apiFamily: "openai-completions",
|
|
295
|
+
auth: "api-key",
|
|
296
|
+
defaultCapabilities,
|
|
297
|
+
|
|
298
|
+
async probe(target: TargetDescriptor, ctx: ProbeContext): Promise<ProbeResult> {
|
|
299
|
+
const base = rootUrl(target);
|
|
300
|
+
if (!base) return { ok: false, error: "target has no url" };
|
|
301
|
+
const headers = bearerHeaders(target, ctx);
|
|
302
|
+
|
|
303
|
+
// Liveness first, and deliberately on the unauthenticated endpoint. A
|
|
304
|
+
// gateway with authentication enforced answers 401 to `/v1/models` when
|
|
305
|
+
// credentials are missing or wrong, which is indistinguishable from an
|
|
306
|
+
// unreachable host if that is the only thing probed. `/health/liveliness`
|
|
307
|
+
// separates "the gateway is down" from "this key is not valid", and the
|
|
308
|
+
// two have completely different remedies.
|
|
309
|
+
const liveOpts = { url: `${base}/health/liveliness`, timeoutMs: ctx.httpTimeoutMs } as const;
|
|
310
|
+
const live = await (ctx.signal
|
|
311
|
+
? probeJson<unknown>({ ...liveOpts, signal: ctx.signal })
|
|
312
|
+
: probeJson<unknown>(liveOpts));
|
|
313
|
+
if (!live.ok) return { ok: false, error: live.error ?? "gateway is not reachable" };
|
|
314
|
+
|
|
315
|
+
const catalog = await fetchCatalog(base, ctx, headers);
|
|
316
|
+
if (catalog.models.length === 0) {
|
|
317
|
+
const result: ProbeResult = {
|
|
318
|
+
ok: false,
|
|
319
|
+
error: "gateway is live but served no model catalog; check the target's API key",
|
|
320
|
+
};
|
|
321
|
+
if (live.latencyMs !== undefined) result.latencyMs = live.latencyMs;
|
|
322
|
+
return result;
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
const result: ProbeResult = { ok: true, models: catalog.models };
|
|
326
|
+
if (live.latencyMs !== undefined) result.latencyMs = live.latencyMs;
|
|
327
|
+
if (Object.keys(catalog.modelCapabilities).length > 0) {
|
|
328
|
+
result.modelCapabilities = catalog.modelCapabilities;
|
|
329
|
+
const selected = target.defaultModel?.trim();
|
|
330
|
+
const selectedCaps = selected ? catalog.modelCapabilities[selected] : undefined;
|
|
331
|
+
if (selected && selectedCaps) {
|
|
332
|
+
result.discoveredCapabilities = selectedCaps;
|
|
333
|
+
result.capabilityModelId = selected;
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
const notes: string[] = [];
|
|
337
|
+
const configured = target.defaultModel?.trim();
|
|
338
|
+
if (configured && !catalog.models.includes(configured)) {
|
|
339
|
+
notes.push(`configured model '${configured}' is not in the gateway catalog`);
|
|
340
|
+
}
|
|
341
|
+
// Naming the physical model behind each alias is the difference between a
|
|
342
|
+
// catalog an operator can audit and a list of words.
|
|
343
|
+
const routed = Object.entries(catalog.deployments)
|
|
344
|
+
.map(([alias, deployment]) => `${alias}=${deployment.model}`)
|
|
345
|
+
.sort();
|
|
346
|
+
if (routed.length > 0) notes.push(`routes: ${routed.join(", ")}`);
|
|
347
|
+
if (notes.length > 0) result.notes = notes;
|
|
348
|
+
return result;
|
|
349
|
+
},
|
|
350
|
+
|
|
351
|
+
async probeModels(target: TargetDescriptor, ctx: ProbeContext): Promise<string[]> {
|
|
352
|
+
const base = rootUrl(target);
|
|
353
|
+
if (!base) return [];
|
|
354
|
+
return (await fetchCatalog(base, ctx, bearerHeaders(target, ctx))).models;
|
|
355
|
+
},
|
|
356
|
+
|
|
357
|
+
synthesizeModel(target: TargetDescriptor, wireModelId: string, kb: KnowledgeBaseHit | null): Model<Api> {
|
|
358
|
+
return synthLocalModel({
|
|
359
|
+
// A LiteLLM target is a gateway whether or not settings said so. The
|
|
360
|
+
// residency layer reads this to stay observe-only: the models behind an
|
|
361
|
+
// alias are the proxy's to load and evict, and a Clio stream that tried
|
|
362
|
+
// to manage them would be issuing load commands to a host that does not
|
|
363
|
+
// take them.
|
|
364
|
+
target: { ...target, gateway: true },
|
|
365
|
+
wireModelId,
|
|
366
|
+
kb,
|
|
367
|
+
defaultCapabilities,
|
|
368
|
+
apiFamily: "openai-completions",
|
|
369
|
+
provider: LITELLM_PROVIDER,
|
|
370
|
+
baseUrlForTarget: withV1,
|
|
371
|
+
});
|
|
372
|
+
},
|
|
373
|
+
};
|
|
374
|
+
|
|
375
|
+
export default litellmRuntime;
|
|
@@ -59,6 +59,7 @@ const SUMMARY_BY_RUNTIME_ID: Readonly<Record<string, string>> = {
|
|
|
59
59
|
llamacpp: "llama.cpp server (auto-detect surface)",
|
|
60
60
|
"anthropic-compat": "Generic Anthropic-compatible REST",
|
|
61
61
|
"openai-compat": "Generic OpenAI-compatible REST",
|
|
62
|
+
litellm: "LiteLLM gateway with per-alias capability discovery and routed-model attribution",
|
|
62
63
|
};
|
|
63
64
|
|
|
64
65
|
function groupPriority(group: ProviderSupportGroup): number {
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Disposable per-target model catalogs discovered by provider probes.
|
|
3
|
+
*
|
|
4
|
+
* A live endpoint catalog is machine state, not operator policy. Persisting it
|
|
5
|
+
* in settings.yaml made a three-target config carry hundreds of volatile model
|
|
6
|
+
* ids. Cache files keep that snapshot available to a new process without
|
|
7
|
+
* turning the hand-edited settings file into a probe transcript.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { createHash } from "node:crypto";
|
|
11
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
12
|
+
import { join } from "node:path";
|
|
13
|
+
import { safeResourceWrite } from "../../core/safe-resource-write.js";
|
|
14
|
+
import { clioCacheDir } from "../../core/xdg.js";
|
|
15
|
+
import type { TargetDescriptor } from "./types/target-descriptor.js";
|
|
16
|
+
|
|
17
|
+
export const TARGET_MODEL_CACHE_TTL_MS = 24 * 60 * 60 * 1_000;
|
|
18
|
+
const TARGET_MODEL_CACHE_VERSION = 1;
|
|
19
|
+
const TARGET_MODEL_CACHE_MAX_MODELS = 4_096;
|
|
20
|
+
const TARGET_MODEL_CACHE_MAX_MODEL_ID_CHARS = 1_024;
|
|
21
|
+
|
|
22
|
+
export interface TargetModelSnapshot {
|
|
23
|
+
version: 1;
|
|
24
|
+
targetId: string;
|
|
25
|
+
runtimeId: string;
|
|
26
|
+
url: string | null;
|
|
27
|
+
models: string[];
|
|
28
|
+
observedAt: string;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
interface TargetModelCacheOptions {
|
|
32
|
+
cacheDir?: string;
|
|
33
|
+
nowMs?: number;
|
|
34
|
+
ttlMs?: number;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function targetCacheKey(targetId: string): string {
|
|
38
|
+
return createHash("sha256").update(targetId).digest("hex").slice(0, 24);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export function targetModelSnapshotPath(targetId: string, cacheDir = clioCacheDir()): string {
|
|
42
|
+
return join(cacheDir, "provider-target-models", `${targetCacheKey(targetId)}.json`);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function normalizedModels(models: ReadonlyArray<string>): string[] {
|
|
46
|
+
const seen = new Set<string>();
|
|
47
|
+
const out: string[] = [];
|
|
48
|
+
for (const raw of models) {
|
|
49
|
+
const model = raw.trim();
|
|
50
|
+
if (model.length === 0 || model.length > TARGET_MODEL_CACHE_MAX_MODEL_ID_CHARS || seen.has(model)) continue;
|
|
51
|
+
seen.add(model);
|
|
52
|
+
out.push(model);
|
|
53
|
+
if (out.length >= TARGET_MODEL_CACHE_MAX_MODELS) break;
|
|
54
|
+
}
|
|
55
|
+
return out;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function parseSnapshot(value: unknown): TargetModelSnapshot | null {
|
|
59
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) return null;
|
|
60
|
+
const row = value as Partial<TargetModelSnapshot>;
|
|
61
|
+
if (row.version !== TARGET_MODEL_CACHE_VERSION) return null;
|
|
62
|
+
if (typeof row.targetId !== "string" || row.targetId.length === 0) return null;
|
|
63
|
+
if (typeof row.runtimeId !== "string" || row.runtimeId.length === 0) return null;
|
|
64
|
+
if (row.url !== null && typeof row.url !== "string") return null;
|
|
65
|
+
if (!Array.isArray(row.models) || row.models.some((model) => typeof model !== "string")) return null;
|
|
66
|
+
if (typeof row.observedAt !== "string" || !Number.isFinite(Date.parse(row.observedAt))) return null;
|
|
67
|
+
const models = normalizedModels(row.models);
|
|
68
|
+
if (models.length !== row.models.length) return null;
|
|
69
|
+
return {
|
|
70
|
+
version: TARGET_MODEL_CACHE_VERSION,
|
|
71
|
+
targetId: row.targetId,
|
|
72
|
+
runtimeId: row.runtimeId,
|
|
73
|
+
url: row.url,
|
|
74
|
+
models,
|
|
75
|
+
observedAt: row.observedAt,
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/** Read a fresh snapshot only when it still describes this target identity. */
|
|
80
|
+
export function readTargetModelSnapshot(
|
|
81
|
+
target: Pick<TargetDescriptor, "id" | "runtime" | "url">,
|
|
82
|
+
options: TargetModelCacheOptions = {},
|
|
83
|
+
): TargetModelSnapshot | null {
|
|
84
|
+
const path = targetModelSnapshotPath(target.id, options.cacheDir);
|
|
85
|
+
if (!existsSync(path)) return null;
|
|
86
|
+
try {
|
|
87
|
+
const snapshot = parseSnapshot(JSON.parse(readFileSync(path, "utf8")) as unknown);
|
|
88
|
+
if (snapshot === null) return null;
|
|
89
|
+
if (snapshot.targetId !== target.id || snapshot.runtimeId !== target.runtime) return null;
|
|
90
|
+
if (snapshot.url !== (target.url ?? null)) return null;
|
|
91
|
+
const observedMs = Date.parse(snapshot.observedAt);
|
|
92
|
+
const nowMs = options.nowMs ?? Date.now();
|
|
93
|
+
const ttlMs = options.ttlMs ?? TARGET_MODEL_CACHE_TTL_MS;
|
|
94
|
+
if (observedMs > nowMs || nowMs - observedMs >= ttlMs) return null;
|
|
95
|
+
return snapshot;
|
|
96
|
+
} catch {
|
|
97
|
+
return null;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/** Best-effort atomic replacement of one target's disposable probe snapshot. */
|
|
102
|
+
export function recordTargetModelSnapshot(
|
|
103
|
+
target: Pick<TargetDescriptor, "id" | "runtime" | "url">,
|
|
104
|
+
models: ReadonlyArray<string>,
|
|
105
|
+
options: Pick<TargetModelCacheOptions, "cacheDir" | "nowMs"> = {},
|
|
106
|
+
): boolean {
|
|
107
|
+
if (target.id.length === 0 || target.runtime.length === 0) return false;
|
|
108
|
+
const snapshot: TargetModelSnapshot = {
|
|
109
|
+
version: TARGET_MODEL_CACHE_VERSION,
|
|
110
|
+
targetId: target.id,
|
|
111
|
+
runtimeId: target.runtime,
|
|
112
|
+
url: target.url ?? null,
|
|
113
|
+
models: normalizedModels(models),
|
|
114
|
+
observedAt: new Date(options.nowMs ?? Date.now()).toISOString(),
|
|
115
|
+
};
|
|
116
|
+
try {
|
|
117
|
+
safeResourceWrite(targetModelSnapshotPath(target.id, options.cacheDir), `${JSON.stringify(snapshot, null, 2)}\n`, {
|
|
118
|
+
encoding: "utf8",
|
|
119
|
+
});
|
|
120
|
+
return true;
|
|
121
|
+
} catch {
|
|
122
|
+
return false;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
@@ -28,6 +28,8 @@ export interface CapabilityFlags {
|
|
|
28
28
|
fim: boolean;
|
|
29
29
|
contextWindow: number;
|
|
30
30
|
maxTokens: number;
|
|
31
|
+
/** Request slots reported by the endpoint probe. This is deployment capacity, not a model trait. */
|
|
32
|
+
parallelSlots?: number;
|
|
31
33
|
}
|
|
32
34
|
|
|
33
35
|
export const EMPTY_CAPABILITIES: CapabilityFlags = {
|
|
@@ -68,11 +68,14 @@ export {
|
|
|
68
68
|
parsePendingSkillRequests,
|
|
69
69
|
parseSkillCommand,
|
|
70
70
|
type Skill,
|
|
71
|
+
type SkillCatalogInvalidReason,
|
|
72
|
+
type SkillCatalogValidity,
|
|
71
73
|
type SkillExpansion,
|
|
72
74
|
type SkillList,
|
|
73
75
|
type SkillProvenance,
|
|
74
76
|
type SkillRoot,
|
|
75
77
|
type SkillSource,
|
|
78
|
+
skillCatalogValidity,
|
|
76
79
|
} from "./skills/loader.js";
|
|
77
80
|
export {
|
|
78
81
|
type DiscoverMarketplaceOptions,
|