@iowarp/clio-coder 0.4.2 → 0.4.3
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 +35 -0
- package/CONTRIBUTING.md +86 -19
- package/README.md +35 -6
- package/dist/{acp-TMDQZDIG.js → acp-H2NGRPWO.js} +11 -11
- package/dist/{agents-5N5NG3XG.js → agents-TL5LLUQP.js} +54 -53
- package/dist/assets/codewiki.json +1 -1
- package/dist/{auth-Z5CCBXKQ.js → auth-E5SW4HMS.js} +19 -16
- package/dist/{builtins-K6TNDT24.js → builtins-IA7V7FUC.js} +9 -4
- package/dist/{chunk-ZW4HH5JJ.js → chunk-2APPQIER.js} +6 -6
- package/dist/{chunk-72GZI5EV.js → chunk-2JH2WHGE.js} +2 -2
- package/dist/{chunk-UBRFI4HS.js → chunk-2UG5F4C5.js} +127 -47
- package/dist/{chunk-UH632ZYL.js → chunk-2UH2KFUP.js} +2 -2
- package/dist/{chunk-3F7VUY77.js → chunk-2VIKGWFZ.js} +2 -2
- package/dist/{chunk-I66EAJFY.js → chunk-2WZ546HR.js} +267 -232
- package/dist/{chunk-RKSR6VSF.js → chunk-4IUZQIJ3.js} +29 -1
- package/dist/{chunk-2X4RYJTJ.js → chunk-4UVU7BJ5.js} +2 -2
- package/dist/{chunk-M2DAX4F6.js → chunk-4WR7VSYB.js} +2 -2
- package/dist/{chunk-5KW52TEP.js → chunk-54CBCGIR.js} +5 -5
- package/dist/{chunk-3KIPBMUA.js → chunk-5ICU3EUH.js} +2 -2
- package/dist/{chunk-77QIVUZB.js → chunk-5MEZN6CB.js} +4 -4
- package/dist/{chunk-O42A54GG.js → chunk-5OIVVPHF.js} +2 -2
- package/dist/{chunk-LJID3DYZ.js → chunk-64I3JVYM.js} +2 -2
- package/dist/{chunk-4JDLP6ZS.js → chunk-6PTFB5VS.js} +7 -7
- package/dist/{chunk-VN3SHNBN.js → chunk-7DICMOS6.js} +2 -2
- package/dist/{chunk-HLAFFSEK.js → chunk-7DRAWPTZ.js} +2 -2
- package/dist/chunk-7E7I3WLS.js +3762 -0
- package/dist/{chunk-YJISEZKC.js → chunk-7ZYNNDKC.js} +6 -6
- package/dist/{chunk-I66ZTYNP.js → chunk-AF4YM7Z4.js} +236 -101
- package/dist/{chunk-2HFQNRV3.js → chunk-AX2THNSA.js} +12 -12
- package/dist/{chunk-PGF63K6I.js → chunk-B4OAX3SI.js} +65 -3
- package/dist/{chunk-W6NIE6OW.js → chunk-B4VEBZKF.js} +3 -3
- package/dist/{chunk-JBCS7CRR.js → chunk-BEPZRGGU.js} +10 -10
- package/dist/{chunk-XGDPUNND.js → chunk-CE5AX47J.js} +2 -2
- package/dist/{chunk-I64IFBLB.js → chunk-DWUOQKRU.js} +17 -10
- package/dist/{chunk-DZAW46HP.js → chunk-E3TPLWFX.js} +3 -3
- package/dist/{chunk-HIICAHCJ.js → chunk-EKCHAPYA.js} +2 -2
- package/dist/{chunk-XE3PCIXH.js → chunk-F5JHEYZM.js} +7 -7
- package/dist/{chunk-5PFYMY2V.js → chunk-FTMGRKEF.js} +2 -2
- package/dist/{chunk-ZNT2M6TG.js → chunk-G76U63X4.js} +17 -17
- package/dist/{chunk-34BHNEE3.js → chunk-GHS5EBTQ.js} +58 -7
- package/dist/{chunk-2NHR3NAY.js → chunk-GI7YYQ3F.js} +40 -34
- package/dist/{chunk-DYHAXKHD.js → chunk-GWZNEVM2.js} +12 -8
- package/dist/chunk-GYV6VZOC.js +26 -0
- package/dist/{chunk-MQXIVJ35.js → chunk-HAXOFFRH.js} +5 -5
- package/dist/{chunk-W4YEMFBX.js → chunk-HEQY7ZFI.js} +2 -2
- package/dist/{chunk-IKOZFYBN.js → chunk-I7ZPNEJM.js} +145 -102
- package/dist/{chunk-WNP7O5WZ.js → chunk-ID64D7PE.js} +4 -4
- package/dist/{chunk-XQRY4DTA.js → chunk-IGLP3ODT.js} +10 -10
- package/dist/chunk-IJNZMHLA.js +101 -0
- package/dist/{chunk-JWJGP5DQ.js → chunk-INY6HTFL.js} +7 -7
- package/dist/{chunk-PBP4B7XR.js → chunk-IUE3Y34X.js} +2 -2
- package/dist/{chunk-B74PXLU7.js → chunk-IWT4SF4R.js} +3 -3
- package/dist/{chunk-B7HM5Z7T.js → chunk-JDAY6FIL.js} +5 -5
- package/dist/{chunk-PJX3WQUQ.js → chunk-JEQ3XTHC.js} +2 -2
- package/dist/{chunk-FSP7CMNU.js → chunk-JGRC33J2.js} +50 -4
- package/dist/{chunk-X7IARSHT.js → chunk-JKKCYP3C.js} +9 -9
- package/dist/{chunk-HJWWJ6IL.js → chunk-JSC3U7TI.js} +16 -4
- package/dist/{chunk-SSEYRH53.js → chunk-KK4JZPBQ.js} +19 -140
- package/dist/{chunk-IHXBNWMM.js → chunk-KXDSS5WJ.js} +7 -3
- package/dist/{chunk-Q4XWMHX6.js → chunk-L47TF46W.js} +2 -2
- package/dist/{chunk-O3YUNJZ2.js → chunk-LDJG7DW3.js} +81 -24
- package/dist/{chunk-CDNVLKUX.js → chunk-LLDJM5XK.js} +13 -7
- package/dist/{chunk-F2I26BDK.js → chunk-MUW2BDDH.js} +4 -4
- package/dist/{chunk-HKMD33FO.js → chunk-MWUZBSAQ.js} +79 -76
- package/dist/{chunk-QQLGQY2A.js → chunk-N2Z7HLVY.js} +20 -20
- package/dist/{chunk-DZEK6CJN.js → chunk-NIQJ66N4.js} +19 -19
- package/dist/{chunk-CWVRRIEI.js → chunk-NZMNUPZZ.js} +2 -2
- package/dist/{chunk-462T4EGZ.js → chunk-O5CVSAG5.js} +2 -2
- package/dist/{chunk-TPEQIQIE.js → chunk-OML5D5V5.js} +8 -8
- package/dist/{chunk-IKSLQ4XV.js → chunk-PAJQJ7BS.js} +558 -216
- package/dist/{chunk-ZW55JB7N.js → chunk-PUVDKJ2Y.js} +2 -2
- package/dist/{chunk-UH347SHR.js → chunk-QWGDJJYJ.js} +11 -11
- package/dist/chunk-R6Q67RJH.js +134 -0
- package/dist/{chunk-CRFOIAX3.js → chunk-RRNP2ANY.js} +6 -6
- package/dist/{chunk-IDNA72AH.js → chunk-RSJ25QSL.js} +2 -2
- package/dist/chunk-SKHCAU7K.js +385 -0
- package/dist/{chunk-RLYRBIYQ.js → chunk-TM6LQDI3.js} +20 -12
- package/dist/chunk-UOIZ7DA4.js +41 -0
- package/dist/{chunk-P75RZCJW.js → chunk-UPZU6GE4.js} +3 -3
- package/dist/{chunk-MCMZMDAC.js → chunk-V2ANDPVT.js} +4 -4
- package/dist/{chunk-AK5XEFVZ.js → chunk-VA5FNYMT.js} +26 -13
- package/dist/{chunk-IMXMHHMQ.js → chunk-VW6DOEDG.js} +332 -57
- package/dist/{chunk-XOXV5GKE.js → chunk-W6RRQCPQ.js} +16 -7
- package/dist/{chunk-CYZW7JHJ.js → chunk-WBKFA554.js} +8 -8
- package/dist/{chunk-BO7Y52RY.js → chunk-WCXUNS7U.js} +7 -7
- package/dist/{chunk-ZGNYYXQ6.js → chunk-WRBAGUNF.js} +3 -3
- package/dist/{chunk-FVDGR2ZL.js → chunk-XIVNBFZS.js} +85 -30
- package/dist/{chunk-BYMNWQ7O.js → chunk-XPWWI35G.js} +299 -58
- package/dist/{chunk-KPXDY6QF.js → chunk-XRZT5WY5.js} +2 -2
- package/dist/{chunk-AZ4WMN4W.js → chunk-Y3CBHOR6.js} +2 -2
- package/dist/{chunk-VXMFAE2W.js → chunk-YPC6ZR5L.js} +19 -6
- package/dist/{chunk-54ODD65L.js → chunk-YQWYVTMC.js} +4 -4
- package/dist/{chunk-M2WXEHER.js → chunk-ZA4VCIGV.js} +2 -2
- package/dist/{chunk-7BHIY2MW.js → chunk-ZDN3Y73Y.js} +6 -6
- package/dist/{chunk-E7GT7O5N.js → chunk-ZWPRK62N.js} +7 -4
- package/dist/cli/index.js +38 -37
- package/dist/{clio-7VB377CC.js → clio-CMMK4KRR.js} +7 -7
- package/dist/{code-nav-YVLCYA7V.js → code-nav-MDZNQS33.js} +7 -7
- package/dist/{components-UBWCQSRW.js → components-UCUQ4QXW.js} +4 -4
- package/dist/{config-4HVOS65E.js → config-SVM5P5YI.js} +76 -74
- package/dist/{configure-PIWO7B24.js → configure-LE3IK2TJ.js} +26 -24
- package/dist/{context-IYEHL3WQ.js → context-2OHRKS42.js} +66 -63
- package/dist/{context-N6ZE3LGJ.js → context-E3VC7RX5.js} +15 -11
- package/dist/{context-KQYIWPWT.js → context-VNCR7KAG.js} +60 -45
- package/dist/{context-clear-G4OGZJDS.js → context-clear-BW4O37TG.js} +61 -59
- package/dist/context-map-COB37XXN.js +505 -0
- package/dist/{context-working-set-BWLF6LJP.js → context-working-set-VDS25HXZ.js} +17 -16
- package/dist/{dispatch-runner-2QQAITS3.js → dispatch-runner-5AHT53RF.js} +85 -74
- package/dist/{doctor-LHBD36VU.js → doctor-WNNVO6FY.js} +37 -37
- package/dist/{eval-C45FYRJ6.js → eval-7G7SGAYO.js} +285 -114
- package/dist/{eval-inventory-6DEJPLBF.js → eval-inventory-Y6QRFOH5.js} +4 -4
- package/dist/{evidence-6SHONYAF.js → evidence-VD6736FQ.js} +63 -62
- package/dist/{evolve-KRKMV72X.js → evolve-AL3NGVRL.js} +62 -61
- package/dist/{extensions-KPZ2UHBB.js → extensions-MOVJ32NM.js} +7 -7
- package/dist/{fleet-IVTCKDHT.js → fleet-QZHUMAGI.js} +110 -108
- package/dist/{fleet-commands-EDWL3IT7.js → fleet-commands-BAYT5FJZ.js} +10 -10
- package/dist/{fleet-decisions-YP3YEFGK.js → fleet-decisions-IREVMRU4.js} +7 -6
- package/dist/{fleet-graph-ZFWKHY2M.js → fleet-graph-YCTT3HTI.js} +19 -18
- package/dist/{fleet-inspect-FVUNCBML.js → fleet-inspect-QVJTDAVB.js} +55 -54
- package/dist/{fleet-preflight-UN5XED4R.js → fleet-preflight-25QAFPK4.js} +4 -4
- package/dist/{fleet-validate-XOWC4HSX.js → fleet-validate-5O57AAJ7.js} +23 -22
- package/dist/{fleet-verify-UN3SODEL.js → fleet-verify-CPH2W2T6.js} +56 -55
- package/dist/{fleet-view-TWHJKCN6.js → fleet-view-SWBR3VGQ.js} +55 -54
- package/dist/{init-T2QORQ3Y.js → init-J477LKZH.js} +78 -76
- package/dist/{interop-IN5I2A66.js → interop-3FCM6XLG.js} +11 -11
- package/dist/{library-LSCATDLZ.js → library-QUQEIUG6.js} +28 -27
- package/dist/{memory-HYOKAGGJ.js → memory-SGGSEP65.js} +64 -63
- package/dist/{models-2GPMFYCM.js → models-HEKUAXXK.js} +49 -43
- package/dist/{monitor-E4ASVUJH.js → monitor-HKU57TYQ.js} +61 -60
- package/dist/{orchestrator-DDMPR3PY.js → orchestrator-VDFAEFAI.js} +919 -546
- package/dist/{panes-E3RUXOW5.js → panes-DN2SSFOH.js} +3 -3
- package/dist/{panes-IXKLOKA2.js → panes-TALGNPZT.js} +8 -8
- package/dist/{paths-L7LGY6RN.js → paths-NBMFAIEZ.js} +5 -5
- package/dist/reset-EAJFFJVB.js +344 -0
- package/dist/{resources-OTRSN34L.js → resources-OVKSEFVE.js} +27 -20
- package/dist/{run-5DEYH5QK.js → run-7DP7ZF2J.js} +113 -109
- package/dist/{share-IHWTLO3M.js → share-WML67FT3.js} +26 -25
- package/dist/{skills-IYMXMKW4.js → skills-SG662R2K.js} +39 -31
- package/dist/{skills-eval-DROHSJAR.js → skills-eval-VVZEUU46.js} +74 -73
- package/dist/{skills-inventory-D7X4L4ZX.js → skills-inventory-I2E23GET.js} +21 -20
- package/dist/{slash-commands-QBM7UZ3B.js → slash-commands-S7MBJDQK.js} +35 -34
- package/dist/{steer-Z5DO23FJ.js → steer-2LQOMCPB.js} +3 -3
- package/dist/{support-U7QOWY26.js → support-CC2UJBJ6.js} +6 -6
- package/dist/{targets-P2FUC4IL.js → targets-4QC3HIEW.js} +48 -45
- package/dist/{terminal-lease-YREJ3JX2.js → terminal-lease-TUHIJ6Y2.js} +2 -2
- package/dist/{tools-5B7RO6MV.js → tools-TFGJICCU.js} +8 -8
- package/dist/{trace-YMGMUM6A.js → trace-FXMXUZUF.js} +7 -7
- package/dist/uninstall-5PEVOE5B.js +408 -0
- package/dist/upgrade-M4WXY6KN.js +303 -0
- package/dist/{usage-ME5MPXGX.js → usage-N7ZNVLEM.js} +147 -102
- package/dist/{verifiers-BVZ7IWOO.js → verifiers-DJTP4XX6.js} +15 -15
- package/dist/{verify-5K7ZKQFC.js → verify-RWE4PPEK.js} +9 -9
- package/dist/{wiki-generate-F5W5QTYY.js → wiki-generate-C7IQOXSP.js} +84 -82
- package/dist/{with-panes-BYOJCLAM.js → with-panes-4GCGSL7J.js} +9 -9
- package/dist/worker/entry.js +61 -60
- package/docs/architecture/artifact-placement.md +1 -0
- package/docs/architecture/artifact-versions.md +1 -1
- package/docs/architecture/context-engine.md +4 -0
- package/docs/architecture/middleware-and-components.md +1 -1
- package/docs/architecture/model-catalog.md +21 -10
- package/docs/architecture/observability.md +12 -1
- package/docs/architecture/prompt-envelope-and-tools.md +2 -0
- package/docs/architecture/provider-adapter-cookbook.md +63 -0
- package/docs/architecture/safety-model.md +15 -5
- package/docs/guide/built-in-agents.md +17 -3
- package/docs/guide/commands-and-modes.md +1 -1
- package/docs/guide/configuration-and-targets.md +97 -9
- package/docs/guide/configuration-reference.md +7 -2
- package/docs/guide/environment-variables.md +2 -0
- package/docs/guide/installation-and-lifecycle.md +37 -4
- package/docs/guide/proactive-memory.md +66 -55
- package/docs/guide/skills-marketplace.md +18 -0
- package/docs/process/development-pipeline.md +34 -1
- package/docs/process/eval-runner.md +67 -3
- package/evals/behavioral-model.yaml +3 -2
- package/package.json +2 -2
- package/skills/README.md +7 -5
- package/skills/coding/ast-grep/SKILL.md +101 -30
- package/skills/coding/ast-grep/evals.md +26 -0
- package/skills/coding/coding-standards/SKILL.md +40 -5
- package/skills/coding/coding-standards/evals.md +23 -0
- package/skills/coding/prototype/SKILL.md +87 -28
- package/skills/coding/prototype/evals.md +19 -0
- package/skills/coding/tdd/SKILL.md +80 -53
- package/skills/coding/tdd/evals.md +20 -0
- package/skills/context/context-handoff/SKILL.md +43 -2
- package/skills/context/context-handoff/evals.md +44 -0
- package/skills/context/context-prime/SKILL.md +45 -15
- package/skills/context/context-prime/evals.md +45 -0
- package/skills/git/branch-closeout/SKILL.md +132 -0
- package/skills/git/branch-closeout/evals.md +133 -0
- package/skills/git/branch-closeout/references/closeout-checklist.md +81 -0
- package/skills/git/file-ticket/SKILL.md +77 -63
- package/skills/git/file-ticket/assets/issue-template.md +22 -0
- package/skills/git/file-ticket/evals.md +31 -26
- package/skills/git/file-ticket/references/issue-discovery.md +49 -0
- package/skills/git/fix-issue/SKILL.md +87 -64
- package/skills/git/fix-issue/evals.md +35 -31
- package/skills/git/fix-issue/references/diagnosis-and-rca.md +46 -0
- package/skills/git/resolve-merge-conflicts/SKILL.md +100 -51
- package/skills/git/resolve-merge-conflicts/evals.md +52 -25
- package/skills/git/resolve-merge-conflicts/references/conflict-matrix.md +126 -0
- package/skills/git/ship/SKILL.md +103 -67
- package/skills/git/ship/assets/pr-template.md +21 -0
- package/skills/git/ship/evals.md +44 -28
- package/skills/git/ship/references/remote-and-branch-policy.md +62 -0
- package/skills/git/worktree-create/SKILL.md +80 -50
- package/skills/git/worktree-create/evals.md +40 -33
- package/skills/git/worktree-create/references/worktree-setup.md +62 -66
- package/skills/git/worktree-merge/SKILL.md +112 -65
- package/skills/git/worktree-merge/evals.md +42 -34
- package/skills/git/worktree-merge/references/merge-strategies.md +52 -0
- package/skills/planning/archify/SKILL.md +196 -0
- package/skills/planning/archify/evals.md +65 -0
- package/skills/planning/architecture/SKILL.md +61 -12
- package/skills/planning/architecture/evals.md +65 -0
- package/skills/planning/backlog/SKILL.md +130 -14
- package/skills/planning/backlog/evals.md +142 -0
- package/skills/planning/prd/SKILL.md +46 -6
- package/skills/planning/prd/evals.md +54 -0
- package/skills/planning/product-intent/SKILL.md +57 -2
- package/skills/planning/product-intent/evals.md +70 -0
- package/skills/planning/tech-spec/SKILL.md +53 -2
- package/skills/planning/tech-spec/evals.md +73 -0
- package/skills/registry.yaml +58 -50
- package/skills/remote.yaml +13 -0
- package/skills/research/arxiv-literature/SKILL.md +76 -18
- package/skills/research/arxiv-literature/evals.md +50 -0
- package/skills/research/experiment-protocol/SKILL.md +20 -1
- package/skills/research/experiment-protocol/evals.md +23 -0
- package/skills/research/scientific-debugging/SKILL.md +23 -1
- package/skills/research/scientific-debugging/evals.md +18 -0
- package/skills/research/scientific-modernization/SKILL.md +26 -1
- package/skills/research/scientific-modernization/evals.md +27 -0
- package/skills/skill-marketplace.json +63 -28
- package/skills/workflow/cut-it/SKILL.md +65 -5
- package/skills/workflow/cut-it/evals.md +101 -0
- package/skills/workflow/design-council/SKILL.md +117 -27
- package/skills/workflow/design-council/evals.md +161 -0
- package/skills/workflow/grill-me/SKILL.md +86 -10
- package/skills/workflow/grill-me/evals.md +153 -0
- package/skills/workflow/workflow-distiller/SKILL.md +76 -17
- package/skills/workflow/workflow-distiller/evals.md +118 -0
- package/src/cli/configure-interop.ts +105 -13
- package/src/cli/configure-oauth.ts +57 -0
- package/src/cli/configure-onboarding.ts +980 -0
- package/src/cli/configure-target.ts +594 -0
- package/src/cli/configure.ts +1082 -528
- package/src/cli/context-map.ts +114 -0
- package/src/cli/context.ts +4 -0
- package/src/cli/index.ts +1 -0
- package/src/cli/lifecycle-presenter.ts +436 -0
- package/src/cli/models.ts +10 -2
- package/src/cli/modes/print.ts +5 -1
- package/src/cli/reset.ts +228 -106
- package/src/cli/run.ts +7 -2
- package/src/cli/select.ts +664 -0
- package/src/cli/skills.ts +9 -2
- package/src/cli/targets.ts +3 -0
- package/src/cli/uninstall.ts +233 -165
- package/src/cli/upgrade.ts +204 -149
- package/src/cli/usage.ts +86 -27
- package/src/cli/validate-model.ts +3 -3
- package/src/core/config.ts +56 -0
- package/src/core/external-diagnostic.ts +44 -0
- package/src/core/gateway-routing.ts +157 -0
- package/src/core/safe-exec.ts +17 -2
- package/src/core/skill-activation.ts +89 -2
- package/src/domains/agents/builtins/world-knowledge.md +31 -0
- package/src/domains/agents/catalog.ts +1 -1
- package/src/domains/agents/result-contract.ts +70 -0
- package/src/domains/context/wiki/map-seed.ts +589 -0
- package/src/domains/context/wiki/plan.ts +2 -2
- package/src/domains/dispatch/admission.ts +29 -0
- package/src/domains/dispatch/agent-candidates.ts +10 -0
- package/src/domains/dispatch/budget-envelope.ts +86 -1
- package/src/domains/dispatch/capability-match.ts +1 -0
- package/src/domains/dispatch/capacity-lease.ts +17 -0
- package/src/domains/dispatch/contract.ts +11 -1
- package/src/domains/dispatch/extension.ts +134 -29
- package/src/domains/dispatch/types.ts +3 -0
- package/src/domains/dispatch/worker-model-metadata.ts +38 -0
- package/src/domains/eval/metrics/call-ledger-stream.ts +34 -11
- package/src/domains/eval/metrics/token-stream.ts +201 -31
- package/src/domains/eval/metrics/tracked.ts +40 -4
- package/src/domains/eval/runners/clio-run.ts +5 -2
- package/src/domains/eval/schema/suite.ts +28 -0
- package/src/domains/eval/schema/verdict.ts +2 -2
- package/src/domains/eval/suites/resolve.ts +13 -1
- package/src/domains/eval/suites/run.ts +24 -3
- package/src/domains/interop/registry.ts +6 -2
- package/src/domains/interop/types.ts +4 -0
- package/src/domains/lifecycle/migrations/index.ts +4 -0
- package/src/domains/memory/task-memory-policy.ts +70 -26
- package/src/domains/memory/task-memory-telemetry.ts +1 -0
- package/src/domains/middleware/index.ts +0 -1
- package/src/domains/middleware/marketplace-offer.ts +3 -35
- package/src/domains/middleware/memory-intervention.ts +127 -32
- package/src/domains/middleware/memory-step-endpoint.ts +3 -2
- package/src/domains/middleware/skills-reminder.ts +31 -2
- package/src/domains/observability/compaction-usage.ts +118 -0
- package/src/domains/observability/cost.ts +1 -1
- package/src/domains/observability/extension.ts +6 -1
- package/src/domains/observability/out-of-turn-usage.ts +52 -21
- package/src/domains/providers/contract.ts +4 -1
- package/src/domains/providers/extension.ts +40 -9
- package/src/domains/providers/model-capabilities.ts +9 -0
- package/src/domains/providers/model-discovery.ts +2 -0
- package/src/domains/providers/model-runtime-capabilities.ts +15 -5
- package/src/domains/providers/models/local-models/clio-coder-local-coding-targets.yaml +32 -12
- package/src/domains/providers/runtimes/antigravity/antigravity-code.ts +225 -45
- package/src/domains/providers/runtimes/common/lmstudio-http.ts +6 -2
- package/src/domains/providers/runtimes/common/local-synth.ts +2 -0
- package/src/domains/providers/runtimes/protocol/litellm.ts +119 -29
- package/src/domains/providers/support.ts +11 -5
- package/src/domains/providers/target-model-cache.ts +25 -2
- package/src/domains/providers/types/capability-flags.ts +2 -0
- package/src/domains/providers/types/runtime-descriptor.ts +20 -1
- package/src/domains/providers/types/target-descriptor.ts +19 -0
- package/src/domains/resources/index.ts +3 -0
- package/src/domains/resources/skills/install.ts +72 -7
- package/src/domains/resources/skills/loader.ts +7 -0
- package/src/domains/resources/skills/marketplace.ts +63 -11
- package/src/domains/safety/autonomy.ts +15 -0
- package/src/domains/safety/index.ts +1 -0
- package/src/domains/safety/path-policy.ts +1 -1
- package/src/domains/safety/policy-engine.ts +34 -11
- package/src/domains/safety/protected-artifacts.ts +191 -88
- package/src/domains/safety/run-effects.ts +2 -22
- package/src/domains/safety/skill-authority.ts +55 -0
- package/src/domains/session/compaction/compact.ts +72 -22
- package/src/domains/session/entries.ts +6 -0
- package/src/domains/session/usage.ts +3 -3
- package/src/engine/agent.ts +13 -3
- package/src/engine/ai.ts +26 -8
- package/src/engine/antigravity/subprocess-runtime.ts +386 -120
- package/src/engine/api-registry.ts +3 -0
- package/src/engine/apis/openai-completions.ts +117 -14
- package/src/engine/external-subprocess.ts +114 -6
- package/src/entry/background-model-metadata.ts +18 -0
- package/src/entry/compaction-prompt.ts +57 -0
- package/src/entry/orchestrator.ts +405 -216
- package/src/entry/task-memory-lifecycle.ts +35 -0
- package/src/interactive/chat-loop-messages.ts +13 -4
- package/src/interactive/chat-loop.ts +65 -2
- package/src/interactive/chat-renderer.ts +1 -0
- package/src/interactive/cost-overlay.ts +26 -2
- package/src/interactive/interactive-slash-runtime.ts +2 -1
- package/src/interactive/renderers/worker-entry.ts +32 -0
- package/src/interactive/slash-commands.ts +24 -6
- package/src/interactive/theme/labels.ts +19 -13
- package/src/interactive/turn-context.ts +9 -5
- package/src/interactive/turn-recovery.ts +8 -0
- package/src/interactive/turn-runtime.ts +27 -11
- package/src/interactive/turn-state.ts +7 -0
- package/src/interactive/worker-receipts.ts +1 -0
- package/src/interactive/worker-stream.ts +6 -1
- package/src/tools/context/index.ts +30 -9
- package/src/tools/dispatch-arguments.ts +1 -0
- package/src/tools/dispatch-event-text.ts +10 -0
- package/src/tools/dispatch-plan.ts +1 -0
- package/src/tools/dispatch-runner.ts +12 -0
- package/src/tools/registry.ts +11 -5
- package/src/tools/worker-evidence.ts +3 -1
- package/src/worker/spec-contract.ts +4 -0
- package/dist/chunk-2Z2IKEXI.js +0 -1554
- package/dist/reset-OAQP3W4O.js +0 -230
- package/dist/uninstall-N34PCTGJ.js +0 -331
- package/dist/upgrade-PXK3S2YM.js +0 -325
|
@@ -1,78 +1,258 @@
|
|
|
1
|
+
import { boundedExternalDiagnostic } from "../../../../core/external-diagnostic.js";
|
|
2
|
+
import { runCommandVector, type SafeCommandResult } from "../../../../core/safe-exec.js";
|
|
1
3
|
import type { Api, Model } from "../../../../engine/types.js";
|
|
2
4
|
|
|
3
5
|
import { synthesizeCatalogBackedModel } from "../../catalog.js";
|
|
4
6
|
import type { CapabilityFlags } from "../../types/capability-flags.js";
|
|
5
7
|
import type { KnowledgeBaseHit } from "../../types/knowledge-base.js";
|
|
6
|
-
import type { RuntimeDescriptor } from "../../types/runtime-descriptor.js";
|
|
8
|
+
import type { ProbeContext, ProbeResult, RuntimeDescriptor } from "../../types/runtime-descriptor.js";
|
|
7
9
|
import type { TargetDescriptor } from "../../types/target-descriptor.js";
|
|
8
10
|
|
|
9
11
|
/**
|
|
10
|
-
* Antigravity CLI (`agy`)
|
|
12
|
+
* Antigravity CLI (`agy`) external delegation runtime.
|
|
11
13
|
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
* models, up to ~1M tokens of context) to the Clio worker fleet.
|
|
17
|
-
*
|
|
18
|
-
* `agy --print` prints plain text (there is no structured event stream), so the
|
|
19
|
-
* worker runner cannot mediate individual agy tool calls the way the Claude SDK
|
|
20
|
-
* runner does. Permission gating is coarse: `--mode plan --sandbox` for
|
|
21
|
-
* read-only runs and `--dangerously-skip-permissions` only under `full-auto`
|
|
22
|
-
* plus the explicit `CLIO_CODER_ALLOW_EXTERNAL_FULL_ACCESS=1` environment gate.
|
|
23
|
-
* agy's own `settings.json` still governs modes that Clio does not explicitly
|
|
24
|
-
* constrain.
|
|
14
|
+
* This is deliberately a dispatch-only subprocess, not a Gemini inference
|
|
15
|
+
* provider. The installed official CLI owns authentication, its agent loop,
|
|
16
|
+
* tools, network access, and model access. Clio supplies one bounded work order
|
|
17
|
+
* and translates the documented structured result into a worker result.
|
|
25
18
|
*/
|
|
26
19
|
|
|
27
20
|
export const ANTIGRAVITY_AUTH_NOTICE =
|
|
28
|
-
"
|
|
29
|
-
"
|
|
30
|
-
"but cannot mediate individual agy tool calls.";
|
|
21
|
+
"Experimental local delegation through your installed Antigravity (`agy`) CLI. Clio neither signs in nor stores " +
|
|
22
|
+
"or inspects Antigravity credentials. Run `agy` yourself and complete sign-in before probing this target.";
|
|
31
23
|
|
|
32
|
-
//
|
|
33
|
-
//
|
|
24
|
+
// Hints only until an account returns a live catalog. They are never used to
|
|
25
|
+
// validate a model after a successful live probe.
|
|
34
26
|
export const ANTIGRAVITY_MODELS: ReadonlyArray<string> = [
|
|
35
|
-
"
|
|
36
|
-
"
|
|
37
|
-
"
|
|
38
|
-
"
|
|
39
|
-
"
|
|
40
|
-
"Claude Sonnet 4.6 (Thinking)",
|
|
41
|
-
"Claude Opus 4.6 (Thinking)",
|
|
42
|
-
"GPT-OSS 120B (Medium)",
|
|
27
|
+
"gemini-3.8-flash-high",
|
|
28
|
+
"gemini-3.8-flash-medium",
|
|
29
|
+
"gemini-3.8-flash-low",
|
|
30
|
+
"gemini-3.1-pro-high",
|
|
31
|
+
"gemini-3.1-pro-low",
|
|
43
32
|
];
|
|
44
33
|
|
|
34
|
+
/** Typed Clio capabilities only. Antigravity's own opaque tools are declared separately. */
|
|
45
35
|
export const antigravityCapabilities: CapabilityFlags = {
|
|
46
36
|
chat: true,
|
|
47
|
-
tools:
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
vision: true,
|
|
37
|
+
tools: false,
|
|
38
|
+
reasoning: false,
|
|
39
|
+
vision: false,
|
|
51
40
|
audio: false,
|
|
52
41
|
embeddings: false,
|
|
53
42
|
rerank: false,
|
|
54
43
|
fim: false,
|
|
55
|
-
contextWindow:
|
|
56
|
-
maxTokens:
|
|
44
|
+
contextWindow: 0,
|
|
45
|
+
maxTokens: 0,
|
|
57
46
|
};
|
|
58
47
|
|
|
48
|
+
export const ANTIGRAVITY_MAX_CATALOG_BYTES = 1024 * 1024;
|
|
49
|
+
export const ANTIGRAVITY_MAX_DISCOVERED_MODELS = 4096;
|
|
50
|
+
const MAX_MODEL_ID_CHARS = 1024;
|
|
51
|
+
const MAX_MODEL_LABEL_CHARS = 1024;
|
|
52
|
+
|
|
53
|
+
type AntigravityProbeFailureKind = NonNullable<ProbeResult["failureKind"]>;
|
|
54
|
+
|
|
55
|
+
class AntigravityCatalogError extends Error {
|
|
56
|
+
readonly kind: AntigravityProbeFailureKind;
|
|
57
|
+
|
|
58
|
+
constructor(kind: AntigravityProbeFailureKind, message: string) {
|
|
59
|
+
super(message);
|
|
60
|
+
this.name = "AntigravityCatalogError";
|
|
61
|
+
this.kind = kind;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function record(value: unknown): Record<string, unknown> | null {
|
|
66
|
+
return typeof value === "object" && value !== null && !Array.isArray(value)
|
|
67
|
+
? (value as Record<string, unknown>)
|
|
68
|
+
: null;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export interface AntigravityModelCatalog {
|
|
72
|
+
models: string[];
|
|
73
|
+
labels: Record<string, string>;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/** Decode the machine-readable catalog emitted by `agy --output-format json models`. */
|
|
77
|
+
export function parseAntigravityModelCatalogDetails(output: string): AntigravityModelCatalog {
|
|
78
|
+
let decoded: unknown;
|
|
79
|
+
try {
|
|
80
|
+
decoded = JSON.parse(output);
|
|
81
|
+
} catch {
|
|
82
|
+
throw new AntigravityCatalogError(
|
|
83
|
+
"unsupported-feature",
|
|
84
|
+
"agy returned an unreadable model catalog; update the Antigravity CLI and retry",
|
|
85
|
+
);
|
|
86
|
+
}
|
|
87
|
+
const envelope = record(decoded);
|
|
88
|
+
const command = record(envelope?.command);
|
|
89
|
+
const data = record(command?.data);
|
|
90
|
+
if (envelope?.status !== "SUCCESS") {
|
|
91
|
+
const detail = boundedExternalDiagnostic(
|
|
92
|
+
typeof envelope?.error === "string"
|
|
93
|
+
? envelope.error
|
|
94
|
+
: typeof command?.error === "string"
|
|
95
|
+
? command.error
|
|
96
|
+
: "agy could not list models",
|
|
97
|
+
);
|
|
98
|
+
const kind = classifyAntigravityDiagnostic(detail);
|
|
99
|
+
throw new AntigravityCatalogError(kind, antigravityProbeMessage(kind, detail));
|
|
100
|
+
}
|
|
101
|
+
if (command?.name !== "models" || !Array.isArray(data?.models)) {
|
|
102
|
+
throw new AntigravityCatalogError(
|
|
103
|
+
"unsupported-feature",
|
|
104
|
+
"agy returned an unsupported model catalog; update the Antigravity CLI and retry",
|
|
105
|
+
);
|
|
106
|
+
}
|
|
107
|
+
if (data.models.length === 0) {
|
|
108
|
+
throw new AntigravityCatalogError(
|
|
109
|
+
"catalog-unavailable",
|
|
110
|
+
"agy returned no available models; run `agy` locally and verify the signed-in account has model access",
|
|
111
|
+
);
|
|
112
|
+
}
|
|
113
|
+
if (data.models.length > ANTIGRAVITY_MAX_DISCOVERED_MODELS) {
|
|
114
|
+
throw new AntigravityCatalogError(
|
|
115
|
+
"catalog-unavailable",
|
|
116
|
+
`agy returned more than ${ANTIGRAVITY_MAX_DISCOVERED_MODELS} models; the authoritative catalog was refused rather than truncated`,
|
|
117
|
+
);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
const models: string[] = [];
|
|
121
|
+
const labels: Record<string, string> = {};
|
|
122
|
+
const seen = new Set<string>();
|
|
123
|
+
for (const value of data.models) {
|
|
124
|
+
const model = record(value);
|
|
125
|
+
const id = typeof model?.id === "string" ? model.id.trim() : "";
|
|
126
|
+
const label = typeof model?.label === "string" ? model.label.trim() : "";
|
|
127
|
+
if (id.length === 0 || id.length > MAX_MODEL_ID_CHARS || /[\r\n\0]/u.test(id)) {
|
|
128
|
+
throw new AntigravityCatalogError("catalog-unavailable", "agy returned an invalid model identifier");
|
|
129
|
+
}
|
|
130
|
+
if (label.length === 0 || label.length > MAX_MODEL_LABEL_CHARS || /[\r\n\0]/u.test(label)) {
|
|
131
|
+
throw new AntigravityCatalogError("catalog-unavailable", `agy returned an invalid label for model '${id}'`);
|
|
132
|
+
}
|
|
133
|
+
if (seen.has(id)) {
|
|
134
|
+
if (labels[id] !== label) {
|
|
135
|
+
throw new AntigravityCatalogError(
|
|
136
|
+
"catalog-unavailable",
|
|
137
|
+
`agy returned conflicting labels for duplicate model '${id}'`,
|
|
138
|
+
);
|
|
139
|
+
}
|
|
140
|
+
continue;
|
|
141
|
+
}
|
|
142
|
+
seen.add(id);
|
|
143
|
+
models.push(id);
|
|
144
|
+
labels[id] = label;
|
|
145
|
+
}
|
|
146
|
+
return { models, labels };
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
function classifyAntigravityDiagnostic(detail: string): AntigravityProbeFailureKind {
|
|
150
|
+
if (/(?:enoent|not found|cannot find|could not start|spawn .*agy)/iu.test(detail)) return "missing";
|
|
151
|
+
if (/(?:sign[ -]?in|log[ -]?in|unauthori[sz]ed|authenticat|credential|account.*required)/iu.test(detail)) {
|
|
152
|
+
return "authentication";
|
|
153
|
+
}
|
|
154
|
+
if (
|
|
155
|
+
/(?:unknown|unsupported|unrecognized|invalid) (?:option|argument|command)|output-format|models command/iu.test(detail)
|
|
156
|
+
) {
|
|
157
|
+
return "unsupported-feature";
|
|
158
|
+
}
|
|
159
|
+
return "generic";
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
function antigravityProbeMessage(kind: AntigravityProbeFailureKind, detail: string): string {
|
|
163
|
+
const safeDetail = boundedExternalDiagnostic(detail || "no diagnostic was provided");
|
|
164
|
+
switch (kind) {
|
|
165
|
+
case "missing":
|
|
166
|
+
return "Antigravity CLI is not installed or `agy` is not on PATH";
|
|
167
|
+
case "authentication":
|
|
168
|
+
return `Antigravity sign-in is required; run \`agy\` yourself and complete sign-in (${safeDetail})`;
|
|
169
|
+
case "unsupported-feature":
|
|
170
|
+
return `the installed Antigravity CLI does not expose the required structured model catalog; update \`agy\` (${safeDetail})`;
|
|
171
|
+
case "catalog-unavailable":
|
|
172
|
+
return safeDetail;
|
|
173
|
+
case "cancelled":
|
|
174
|
+
return "Antigravity model discovery was cancelled";
|
|
175
|
+
default:
|
|
176
|
+
return `Antigravity model discovery failed: ${safeDetail}`;
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
export async function probeAntigravityModelCatalog(
|
|
181
|
+
ctx: ProbeContext,
|
|
182
|
+
runner: typeof runCommandVector = runCommandVector,
|
|
183
|
+
): Promise<ProbeResult> {
|
|
184
|
+
const result: SafeCommandResult = await runner("agy", ["--output-format", "json", "models"], {
|
|
185
|
+
cwd: process.cwd(),
|
|
186
|
+
workspaceRoot: process.cwd(),
|
|
187
|
+
timeoutMs: Math.max(1, ctx.httpTimeoutMs),
|
|
188
|
+
maxOutputBytes: ANTIGRAVITY_MAX_CATALOG_BYTES,
|
|
189
|
+
...(ctx.signal ? { signal: ctx.signal } : {}),
|
|
190
|
+
});
|
|
191
|
+
if (result.aborted || result.timedOut) {
|
|
192
|
+
return {
|
|
193
|
+
ok: false,
|
|
194
|
+
latencyMs: result.durationMs,
|
|
195
|
+
failureKind: "cancelled",
|
|
196
|
+
error: antigravityProbeMessage("cancelled", ""),
|
|
197
|
+
};
|
|
198
|
+
}
|
|
199
|
+
if (result.outputCapped) {
|
|
200
|
+
return {
|
|
201
|
+
ok: false,
|
|
202
|
+
latencyMs: result.durationMs,
|
|
203
|
+
failureKind: "catalog-unavailable",
|
|
204
|
+
error: `agy model catalog exceeded ${ANTIGRAVITY_MAX_CATALOG_BYTES} bytes`,
|
|
205
|
+
};
|
|
206
|
+
}
|
|
207
|
+
if (result.exitCode !== 0) {
|
|
208
|
+
const detail = boundedExternalDiagnostic(result.stderr || result.stdout || `agy exited ${String(result.exitCode)}`);
|
|
209
|
+
const kind = classifyAntigravityDiagnostic(detail);
|
|
210
|
+
return { ok: false, latencyMs: result.durationMs, failureKind: kind, error: antigravityProbeMessage(kind, detail) };
|
|
211
|
+
}
|
|
212
|
+
try {
|
|
213
|
+
const catalog = parseAntigravityModelCatalogDetails(result.stdout);
|
|
214
|
+
return {
|
|
215
|
+
ok: true,
|
|
216
|
+
latencyMs: result.durationMs,
|
|
217
|
+
models: catalog.models,
|
|
218
|
+
modelLabels: catalog.labels,
|
|
219
|
+
};
|
|
220
|
+
} catch (cause) {
|
|
221
|
+
const kind = cause instanceof AntigravityCatalogError ? cause.kind : "generic";
|
|
222
|
+
const detail = cause instanceof Error ? cause.message : String(cause);
|
|
223
|
+
return { ok: false, latencyMs: result.durationMs, failureKind: kind, error: boundedExternalDiagnostic(detail) };
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
|
|
59
227
|
const antigravityCodeRuntime: RuntimeDescriptor = {
|
|
60
228
|
id: "antigravity-code",
|
|
61
|
-
displayName: "Antigravity CLI",
|
|
229
|
+
displayName: "Antigravity CLI — experimental local delegation",
|
|
62
230
|
kind: "subprocess",
|
|
63
231
|
tier: "subscription",
|
|
64
|
-
|
|
65
|
-
// to its own runner before any pi-ai inference, so this only needs to be a
|
|
66
|
-
// valid, google-backed family. The runner is selected by runtime id, and the
|
|
67
|
-
// plain-text parser is named by `outputParser`.
|
|
68
|
-
apiFamily: "google-generative-ai",
|
|
232
|
+
apiFamily: "external-agent-subprocess",
|
|
69
233
|
auth: "none",
|
|
70
234
|
authNotice: ANTIGRAVITY_AUTH_NOTICE,
|
|
71
235
|
knownModels: [...ANTIGRAVITY_MODELS],
|
|
72
236
|
binaryName: "agy",
|
|
73
|
-
headlessCommand: "agy --
|
|
74
|
-
outputParser: "antigravity-
|
|
237
|
+
headlessCommand: "agy --input-format stream-json --output-format stream-json",
|
|
238
|
+
outputParser: "antigravity-stream-json",
|
|
75
239
|
defaultCapabilities: antigravityCapabilities,
|
|
240
|
+
externalAgentLoop: {
|
|
241
|
+
tools: "externally-governed-unobserved",
|
|
242
|
+
network: "externally-governed-unobserved",
|
|
243
|
+
budget: "external-one-shot",
|
|
244
|
+
generatingRetry: "forbidden",
|
|
245
|
+
modelCatalog: "live-authoritative",
|
|
246
|
+
},
|
|
247
|
+
async probe(_target: TargetDescriptor, ctx: ProbeContext) {
|
|
248
|
+
try {
|
|
249
|
+
return await probeAntigravityModelCatalog(ctx);
|
|
250
|
+
} catch (cause) {
|
|
251
|
+
const detail = boundedExternalDiagnostic(cause instanceof Error ? cause.message : String(cause));
|
|
252
|
+
const kind = classifyAntigravityDiagnostic(detail);
|
|
253
|
+
return { ok: false, failureKind: kind, error: antigravityProbeMessage(kind, detail) };
|
|
254
|
+
}
|
|
255
|
+
},
|
|
76
256
|
synthesizeModel(target: TargetDescriptor, wireModelId: string, kb: KnowledgeBaseHit | null): Model<Api> {
|
|
77
257
|
return synthesizeCatalogBackedModel({
|
|
78
258
|
target,
|
|
@@ -80,9 +260,9 @@ const antigravityCodeRuntime: RuntimeDescriptor = {
|
|
|
80
260
|
kb,
|
|
81
261
|
defaultCapabilities: antigravityCapabilities,
|
|
82
262
|
runtimeId: "antigravity-code",
|
|
83
|
-
api: "
|
|
84
|
-
provider: "
|
|
85
|
-
defaultBaseUrl: "antigravity
|
|
263
|
+
api: "external-agent-subprocess",
|
|
264
|
+
provider: "antigravity",
|
|
265
|
+
defaultBaseUrl: "external-agent://antigravity/local",
|
|
86
266
|
});
|
|
87
267
|
},
|
|
88
268
|
};
|
|
@@ -300,9 +300,13 @@ export function lmStudioReasoningLevels(options: ReadonlyArray<string> | undefin
|
|
|
300
300
|
export function lmStudioReasoningEffort(
|
|
301
301
|
level: ThinkingLevel,
|
|
302
302
|
options?: ReadonlyArray<string>,
|
|
303
|
-
): "none" | "low" | "medium" | "high" {
|
|
303
|
+
): "none" | "low" | "medium" | "high" | undefined {
|
|
304
|
+
// `allowed_options` describes the model's binary setting, but LM Studio's
|
|
305
|
+
// OpenAI-compatible request schema still accepts only effort-level values.
|
|
306
|
+
// Omit an active override for binary/default-on models; sending `low` works
|
|
307
|
+
// only through a warning and sending the advertised literal `on` is a 400.
|
|
308
|
+
if (options?.includes("on") && options.includes("off")) return level === "off" ? "none" : undefined;
|
|
304
309
|
if (level === "off") return "none";
|
|
305
|
-
if (options?.includes("on") && !options.includes("medium") && !options.includes("high")) return "low";
|
|
306
310
|
if (level === "medium" && options?.includes("medium") !== false) return "medium";
|
|
307
311
|
if ((level === "high" || level === "xhigh" || level === "max") && options?.includes("high") !== false) return "high";
|
|
308
312
|
return "low";
|
|
@@ -24,6 +24,7 @@ export interface ClioLocalModelMetadata {
|
|
|
24
24
|
quirks?: LocalModelQuirks;
|
|
25
25
|
chatTemplateKwargsUnsupported?: boolean;
|
|
26
26
|
lmstudio?: TargetDescriptor["lmstudio"];
|
|
27
|
+
litellm?: TargetDescriptor["litellm"];
|
|
27
28
|
};
|
|
28
29
|
}
|
|
29
30
|
|
|
@@ -109,6 +110,7 @@ export function synthLocalModel(input: LocalSynthesisInput): Model<Api> {
|
|
|
109
110
|
...(kb?.entry.family ? { family: kb.entry.family } : {}),
|
|
110
111
|
...(quirks ? { quirks } : {}),
|
|
111
112
|
...(target.lmstudio ? { lmstudio: target.lmstudio } : {}),
|
|
113
|
+
...(target.litellm ? { litellm: target.litellm } : {}),
|
|
112
114
|
},
|
|
113
115
|
};
|
|
114
116
|
if (headers) model.headers = headers;
|
|
@@ -4,11 +4,11 @@
|
|
|
4
4
|
* This is a separate runtime from `openai-compat` rather than a target flag on
|
|
5
5
|
* it, because a gateway answers two questions the generic protocol cannot.
|
|
6
6
|
*
|
|
7
|
-
* First, capability discovery. A gateway
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
7
|
+
* First, capability discovery. A gateway may publish aliases or truthful
|
|
8
|
+
* physical names such as `dynamo/qwen3.8-27b`. LiteLLM's `/v1/models` is the
|
|
9
|
+
* plain OpenAI listing, so every row flattens to a bare id and the context
|
|
10
|
+
* window, tool support, and modality of the model behind it are all erased.
|
|
11
|
+
* Reached over
|
|
12
12
|
* `openai-compat`, a 262k tool-calling coder is indistinguishable from a 4k
|
|
13
13
|
* chat toy, and Clio plans the session against its own assumed floor. LiteLLM
|
|
14
14
|
* publishes the real numbers on `/v1/model/info` instead, which is what this
|
|
@@ -26,7 +26,8 @@
|
|
|
26
26
|
* and rejected HTTP 400 by LM Studio, and the same prompt with no
|
|
27
27
|
* `response_format` returned plain prose. `drop_params: true` did not strip
|
|
28
28
|
* either spelling. The standard `json_schema` dialect is therefore the one that
|
|
29
|
-
* holds across every upstream, and
|
|
29
|
+
* holds across every measured upstream, and a gateway must publish that fact
|
|
30
|
+
* explicitly per route in `model_info` before Clio relies on it.
|
|
30
31
|
*/
|
|
31
32
|
|
|
32
33
|
import { CLIO_MIN_CONTEXT_WINDOW, CLIO_MIN_MAX_OUTPUT_TOKENS } from "../../../../core/context-floor.js";
|
|
@@ -55,7 +56,7 @@ const defaultCapabilities: CapabilityFlags = {
|
|
|
55
56
|
embeddings: false,
|
|
56
57
|
rerank: false,
|
|
57
58
|
fim: false,
|
|
58
|
-
structuredOutputs: "
|
|
59
|
+
structuredOutputs: "none",
|
|
59
60
|
contextWindow: CLIO_MIN_CONTEXT_WINDOW,
|
|
60
61
|
maxTokens: CLIO_MIN_MAX_OUTPUT_TOKENS,
|
|
61
62
|
};
|
|
@@ -106,8 +107,11 @@ function boolean(value: unknown): boolean | undefined {
|
|
|
106
107
|
* so the caller can tell "the gateway says this model has no vision" apart from
|
|
107
108
|
* "the gateway did not say", and merge accordingly.
|
|
108
109
|
*/
|
|
109
|
-
function capabilitiesFromLiteLLMModelInfo(info: Record<string, unknown>): Partial<CapabilityFlags> {
|
|
110
|
+
export function capabilitiesFromLiteLLMModelInfo(info: Record<string, unknown>): Partial<CapabilityFlags> {
|
|
110
111
|
const caps: Partial<CapabilityFlags> = {};
|
|
112
|
+
// This is a deployment declaration, never inferred from a URL, port or alias.
|
|
113
|
+
if (info.runtime === "lm-studio") caps.thinkingControlRuntime = "lmstudio";
|
|
114
|
+
else if (info.runtime === "llama.cpp") caps.thinkingControlRuntime = "llamacpp";
|
|
111
115
|
const contextWindow = positiveInteger(info.max_input_tokens) ?? positiveInteger(info.max_tokens);
|
|
112
116
|
if (contextWindow !== undefined) caps.contextWindow = contextWindow;
|
|
113
117
|
const maxTokens = positiveInteger(info.max_output_tokens);
|
|
@@ -132,20 +136,77 @@ function capabilitiesFromLiteLLMModelInfo(info: Record<string, unknown>): Partia
|
|
|
132
136
|
caps.rerank = true;
|
|
133
137
|
}
|
|
134
138
|
if (info.mode === "chat") caps.chat = true;
|
|
135
|
-
// Measured, not inferred: see the module header.
|
|
136
|
-
|
|
139
|
+
// Measured, not inferred: see the module header. An explicit false must
|
|
140
|
+
// override this runtime's measured default for an upstream that cannot
|
|
141
|
+
// preserve the schema contract.
|
|
142
|
+
const responseSchema = boolean(info.supports_response_schema);
|
|
143
|
+
if (responseSchema !== undefined) caps.structuredOutputs = responseSchema ? "json-schema" : "none";
|
|
137
144
|
return caps;
|
|
138
145
|
}
|
|
139
146
|
|
|
147
|
+
const BOOLEAN_CAPABILITIES = [
|
|
148
|
+
"chat",
|
|
149
|
+
"tools",
|
|
150
|
+
"reasoning",
|
|
151
|
+
"vision",
|
|
152
|
+
"audio",
|
|
153
|
+
"embeddings",
|
|
154
|
+
"rerank",
|
|
155
|
+
"fim",
|
|
156
|
+
] as const satisfies ReadonlyArray<keyof CapabilityFlags>;
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* One alias may load-balance across heterogeneous deployments. Clio can only
|
|
160
|
+
* promise what every possible route supports: numerical limits take the
|
|
161
|
+
* smallest fully-published value, booleans require unanimous publication, and
|
|
162
|
+
* one explicit false defeats a true. Missing data never becomes a capability.
|
|
163
|
+
*/
|
|
164
|
+
export function aggregateLiteLLMCapabilities(rows: ReadonlyArray<Partial<CapabilityFlags>>): Partial<CapabilityFlags> {
|
|
165
|
+
if (rows.length === 0) return {};
|
|
166
|
+
const aggregate: Partial<CapabilityFlags> = {};
|
|
167
|
+
for (const key of ["contextWindow", "maxTokens"] as const) {
|
|
168
|
+
const values = rows.map((row) => row[key]);
|
|
169
|
+
if (values.every((value): value is number => typeof value === "number")) {
|
|
170
|
+
aggregate[key] = Math.min(...values);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
for (const key of BOOLEAN_CAPABILITIES) {
|
|
174
|
+
const values = rows.map((row) => row[key]);
|
|
175
|
+
if (values.some((value) => value === false)) aggregate[key] = false;
|
|
176
|
+
else if (values.every((value) => value === true)) aggregate[key] = true;
|
|
177
|
+
}
|
|
178
|
+
const controlRuntime = rows[0]?.thinkingControlRuntime;
|
|
179
|
+
if (controlRuntime !== undefined && rows.every((row) => row.thinkingControlRuntime === controlRuntime)) {
|
|
180
|
+
aggregate.thinkingControlRuntime = controlRuntime;
|
|
181
|
+
}
|
|
182
|
+
const structuredOutputs = rows.map((row) => row.structuredOutputs);
|
|
183
|
+
if (structuredOutputs.some((value) => value === "none")) aggregate.structuredOutputs = "none";
|
|
184
|
+
else if (structuredOutputs.every((value) => value === "json-schema")) aggregate.structuredOutputs = "json-schema";
|
|
185
|
+
return aggregate;
|
|
186
|
+
}
|
|
187
|
+
|
|
140
188
|
interface LiteLLMCatalog {
|
|
141
189
|
models: string[];
|
|
142
190
|
modelCapabilities: Record<string, Partial<CapabilityFlags>>;
|
|
143
191
|
modelStates: Record<string, ProbeModelStatus>;
|
|
144
192
|
/** Physical deployment behind each alias, for display. */
|
|
145
|
-
deployments: Record<string, { model: string; apiBase?: string }
|
|
193
|
+
deployments: Record<string, Array<{ model: string; apiBase?: string }>>;
|
|
194
|
+
/** Whether the empty catalog is specifically because the gateway rejected the key. */
|
|
195
|
+
authFailed: boolean;
|
|
146
196
|
}
|
|
147
197
|
|
|
148
|
-
const EMPTY_CATALOG: LiteLLMCatalog = {
|
|
198
|
+
const EMPTY_CATALOG: LiteLLMCatalog = {
|
|
199
|
+
models: [],
|
|
200
|
+
modelCapabilities: {},
|
|
201
|
+
modelStates: {},
|
|
202
|
+
deployments: {},
|
|
203
|
+
authFailed: false,
|
|
204
|
+
};
|
|
205
|
+
|
|
206
|
+
/** Whether a failed probe leg failed specifically on the credential, not on reachability. */
|
|
207
|
+
function isAuthError(leg: { ok: boolean; error?: string }): boolean {
|
|
208
|
+
return !leg.ok && /^HTTP 40[13]\b/u.test(leg.error ?? "");
|
|
209
|
+
}
|
|
149
210
|
|
|
150
211
|
/**
|
|
151
212
|
* Read the catalog from `/v1/model/info`, falling back to `/v1/models`.
|
|
@@ -163,37 +224,50 @@ async function fetchCatalog(base: string, ctx: ProbeContext, headers: Record<str
|
|
|
163
224
|
: probeJson<LiteLLMModelInfoResponse>(detailOpts));
|
|
164
225
|
|
|
165
226
|
if (detail.ok && Array.isArray(detail.data?.data)) {
|
|
166
|
-
const catalog: LiteLLMCatalog = {
|
|
227
|
+
const catalog: LiteLLMCatalog = {
|
|
228
|
+
models: [],
|
|
229
|
+
modelCapabilities: {},
|
|
230
|
+
modelStates: {},
|
|
231
|
+
deployments: {},
|
|
232
|
+
authFailed: false,
|
|
233
|
+
};
|
|
234
|
+
const capabilityRows: Record<string, Array<Partial<CapabilityFlags>>> = {};
|
|
167
235
|
for (const row of detail.data.data) {
|
|
168
236
|
if (typeof row?.model_name !== "string" || row.model_name.length === 0) continue;
|
|
169
237
|
const alias = row.model_name;
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
catalog.models.push(alias);
|
|
238
|
+
if (catalog.deployments[alias] === undefined) {
|
|
239
|
+
catalog.models.push(alias);
|
|
240
|
+
catalog.deployments[alias] = [];
|
|
241
|
+
capabilityRows[alias] = [];
|
|
242
|
+
}
|
|
176
243
|
const caps = row.model_info ? capabilitiesFromLiteLLMModelInfo(row.model_info) : {};
|
|
177
|
-
|
|
244
|
+
capabilityRows[alias]?.push(caps);
|
|
178
245
|
const upstream = row.litellm_params?.model;
|
|
179
246
|
const apiBase = row.litellm_params?.api_base;
|
|
180
|
-
catalog.deployments[alias]
|
|
247
|
+
catalog.deployments[alias]?.push({
|
|
181
248
|
model: typeof upstream === "string" ? upstream : alias,
|
|
182
249
|
...(typeof apiBase === "string" ? { apiBase } : {}),
|
|
183
|
-
};
|
|
250
|
+
});
|
|
251
|
+
}
|
|
252
|
+
for (const alias of catalog.models) {
|
|
253
|
+
const caps = aggregateLiteLLMCapabilities(capabilityRows[alias] ?? []);
|
|
254
|
+
if (Object.keys(caps).length > 0) catalog.modelCapabilities[alias] = caps;
|
|
184
255
|
}
|
|
185
256
|
if (catalog.models.length > 0) return catalog;
|
|
186
257
|
}
|
|
258
|
+
const detailAuthFailed = isAuthError(detail);
|
|
187
259
|
|
|
188
260
|
const listOpts = { url: `${base}/v1/models`, timeoutMs: ctx.httpTimeoutMs, headers } as const;
|
|
189
261
|
const list = await (ctx.signal
|
|
190
262
|
? probeJson<LiteLLMModelsResponse>({ ...listOpts, signal: ctx.signal })
|
|
191
263
|
: probeJson<LiteLLMModelsResponse>(listOpts));
|
|
192
|
-
if (!list.ok || !Array.isArray(list.data?.data))
|
|
264
|
+
if (!list.ok || !Array.isArray(list.data?.data)) {
|
|
265
|
+
return { ...EMPTY_CATALOG, authFailed: detailAuthFailed || isAuthError(list) };
|
|
266
|
+
}
|
|
193
267
|
const models = list.data.data
|
|
194
268
|
.map((row) => (typeof row?.id === "string" ? row.id : null))
|
|
195
269
|
.filter((id): id is string => id !== null && id.length > 0);
|
|
196
|
-
return { models, modelCapabilities: {}, modelStates: {}, deployments: {} };
|
|
270
|
+
return { models, modelCapabilities: {}, modelStates: {}, deployments: {}, authFailed: false };
|
|
197
271
|
}
|
|
198
272
|
|
|
199
273
|
const litellmRuntime: RuntimeDescriptor = {
|
|
@@ -226,8 +300,11 @@ const litellmRuntime: RuntimeDescriptor = {
|
|
|
226
300
|
if (catalog.models.length === 0) {
|
|
227
301
|
const result: ProbeResult = {
|
|
228
302
|
ok: false,
|
|
229
|
-
error:
|
|
303
|
+
error: catalog.authFailed
|
|
304
|
+
? "gateway rejected the key"
|
|
305
|
+
: "gateway is live but served no model catalog; check the target's API key",
|
|
230
306
|
};
|
|
307
|
+
if (catalog.authFailed) result.authFailed = true;
|
|
231
308
|
if (live.latencyMs !== undefined) result.latencyMs = live.latencyMs;
|
|
232
309
|
return result;
|
|
233
310
|
}
|
|
@@ -248,10 +325,23 @@ const litellmRuntime: RuntimeDescriptor = {
|
|
|
248
325
|
if (configured && !catalog.models.includes(configured)) {
|
|
249
326
|
notes.push(`configured model '${configured}' is not in the gateway catalog`);
|
|
250
327
|
}
|
|
251
|
-
//
|
|
252
|
-
//
|
|
253
|
-
|
|
254
|
-
|
|
328
|
+
// A node/model catalog already names placement. Summarize those one-to-one
|
|
329
|
+
// routes instead of flooding target diagnostics with dozens of tautologies;
|
|
330
|
+
// retain the explicit mapping for genuine aliases and multi-deployments.
|
|
331
|
+
const routeEntries = Object.entries(catalog.deployments);
|
|
332
|
+
const physical = routeEntries.filter(([alias, deployments]) => {
|
|
333
|
+
const slash = alias.indexOf("/");
|
|
334
|
+
if (slash <= 0 || deployments.length !== 1) return false;
|
|
335
|
+
const upstream = deployments[0]?.model.replace(/^openai\//u, "");
|
|
336
|
+
return upstream === alias.slice(slash + 1);
|
|
337
|
+
});
|
|
338
|
+
if (physical.length > 0) notes.push(`physical routes: ${physical.length} node/model names map one-to-one`);
|
|
339
|
+
const routed = routeEntries
|
|
340
|
+
.filter(([alias]) => !physical.some(([physicalAlias]) => physicalAlias === alias))
|
|
341
|
+
.map(([alias, deployments]) => {
|
|
342
|
+
const models = [...new Set(deployments.map((deployment) => deployment.model))];
|
|
343
|
+
return `${alias}=${models.join("|")}`;
|
|
344
|
+
})
|
|
255
345
|
.sort();
|
|
256
346
|
if (routed.length > 0) notes.push(`routes: ${routed.join(", ")}`);
|
|
257
347
|
if (notes.length > 0) result.notes = notes;
|
|
@@ -5,7 +5,7 @@ import { getRuntimeRegistry } from "./registry.js";
|
|
|
5
5
|
import type { RuntimeDescriptor } from "./types/runtime-descriptor.js";
|
|
6
6
|
import type { TargetDescriptor } from "./types/target-descriptor.js";
|
|
7
7
|
|
|
8
|
-
export type ProviderSupportGroup = "featured" | "cloud-api" | "subscription" | "local-http";
|
|
8
|
+
export type ProviderSupportGroup = "featured" | "external-worker" | "cloud-api" | "subscription" | "local-http";
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
11
|
* Where a runtime's model ids come from, which decides whether their order
|
|
@@ -44,6 +44,7 @@ const SUMMARY_BY_RUNTIME_ID: Readonly<Record<string, string>> = {
|
|
|
44
44
|
alcf: "ALCF inference gateway (Sophia/Metis) via Globus",
|
|
45
45
|
anthropic: "Anthropic API",
|
|
46
46
|
"anthropic-max": "Claude Pro/Max subscription via Anthropic OAuth",
|
|
47
|
+
"antigravity-code": "Experimental local delegation via the installed Antigravity CLI",
|
|
47
48
|
bedrock: "Amazon Bedrock",
|
|
48
49
|
"claude-code": "Claude Code subscription via installed claude CLI",
|
|
49
50
|
"claude-sdk": "Claude Code subscription via Claude Agent SDK",
|
|
@@ -59,19 +60,21 @@ const SUMMARY_BY_RUNTIME_ID: Readonly<Record<string, string>> = {
|
|
|
59
60
|
llamacpp: "llama.cpp server (auto-detect surface)",
|
|
60
61
|
"anthropic-compat": "Generic Anthropic-compatible REST",
|
|
61
62
|
"openai-compat": "Generic OpenAI-compatible REST",
|
|
62
|
-
litellm: "LiteLLM gateway with per-
|
|
63
|
+
litellm: "LiteLLM gateway with per-route capability discovery and physical-model attribution",
|
|
63
64
|
};
|
|
64
65
|
|
|
65
66
|
function groupPriority(group: ProviderSupportGroup): number {
|
|
66
67
|
switch (group) {
|
|
67
68
|
case "featured":
|
|
68
69
|
return 0;
|
|
69
|
-
case "
|
|
70
|
+
case "external-worker":
|
|
70
71
|
return 1;
|
|
71
|
-
case "
|
|
72
|
+
case "subscription":
|
|
72
73
|
return 2;
|
|
73
|
-
case "
|
|
74
|
+
case "cloud-api":
|
|
74
75
|
return 3;
|
|
76
|
+
case "local-http":
|
|
77
|
+
return 4;
|
|
75
78
|
}
|
|
76
79
|
}
|
|
77
80
|
|
|
@@ -79,6 +82,8 @@ export function supportGroupLabel(group: ProviderSupportGroup): string {
|
|
|
79
82
|
switch (group) {
|
|
80
83
|
case "featured":
|
|
81
84
|
return "Featured";
|
|
85
|
+
case "external-worker":
|
|
86
|
+
return "External delegation";
|
|
82
87
|
case "subscription":
|
|
83
88
|
return "Subscriptions";
|
|
84
89
|
case "cloud-api":
|
|
@@ -90,6 +95,7 @@ export function supportGroupLabel(group: ProviderSupportGroup): string {
|
|
|
90
95
|
|
|
91
96
|
function classifyGroup(runtime: RuntimeDescriptor): ProviderSupportGroup {
|
|
92
97
|
if (runtime.id === "openai-codex") return "featured";
|
|
98
|
+
if (runtime.externalAgentLoop !== undefined) return "external-worker";
|
|
93
99
|
if (runtime.id === "alcf") return "cloud-api";
|
|
94
100
|
if (runtime.auth === "oauth" || runtime.auth === "claude-cli") return "subscription";
|
|
95
101
|
if (catalogProviderForRuntime(runtime.id) || (runtime.auth === "api-key" && !runtime.probe)) {
|