@iowarp/clio-coder 0.3.7 → 0.3.9
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 +80 -0
- package/README.md +13 -4
- package/dist/{acp-SK4MD6MM.js → acp-7LOELQFP.js} +13 -13
- package/dist/{agents-2FN2K6ME.js → agents-FIBG2SHA.js} +41 -37
- package/dist/assets/codewiki.json +1 -1
- package/dist/{auth-QIYZWM5I.js → auth-OI4LIH2I.js} +31 -24
- package/dist/builtins-AD25UL3C.js +17 -0
- package/dist/{chunk-5FR74PWO.js → chunk-2JDWVJND.js} +2 -2
- package/dist/chunk-3DPEIQKN.js +113 -0
- package/dist/{chunk-EOOQZZDE.js → chunk-3DUR4WUA.js} +19 -19
- package/dist/{chunk-WHJYKASB.js → chunk-3MRC2YSQ.js} +2 -2
- package/dist/{chunk-EBEFWSGL.js → chunk-3UUY7R3Z.js} +14 -10
- package/dist/{chunk-LADCF22A.js → chunk-3V5AYSEQ.js} +113 -54
- package/dist/{chunk-BMWK7ZIZ.js → chunk-465CC7FK.js} +16 -13
- package/dist/{chunk-5WIGXA4T.js → chunk-47CMYGET.js} +111 -4
- package/dist/{chunk-CEYBNUGC.js → chunk-4H6ULJ3H.js} +378 -36
- package/dist/{chunk-YTYFXUI3.js → chunk-4LJX2PUC.js} +9 -9
- package/dist/{chunk-DOOEX22V.js → chunk-56KB5IJP.js} +5 -5
- package/dist/{chunk-SPULKLCF.js → chunk-5DQRIYDZ.js} +2 -2
- package/dist/{chunk-TSHXZTOQ.js → chunk-5HFBWUMU.js} +23 -11
- package/dist/{chunk-5UJ6ECTS.js → chunk-5PVQ4SRS.js} +80 -8
- package/dist/{chunk-ZWLZP4ZT.js → chunk-5QKCQQ3E.js} +359 -17
- package/dist/{chunk-6M7VS3J3.js → chunk-5T7RBWN2.js} +111 -5
- package/dist/chunk-774ILSRL.js +172 -0
- package/dist/chunk-7C6RYZGQ.js +391 -0
- package/dist/{chunk-GH5622CP.js → chunk-A2NJGIB3.js} +2 -2
- package/dist/{chunk-C4JBQ5SR.js → chunk-AD7Y7STJ.js} +6 -6
- package/dist/{chunk-GEYXPTRF.js → chunk-AEYBF3TB.js} +33 -12
- package/dist/{chunk-2SFS6XQE.js → chunk-AMKHQW3C.js} +3 -2
- package/dist/{chunk-D4MDIG46.js → chunk-B5CSFE7B.js} +7 -7
- package/dist/{chunk-MXI6J5JF.js → chunk-B5XRQOLB.js} +10 -10
- package/dist/{chunk-X2KV5FXT.js → chunk-BVDVID7E.js} +2 -2
- package/dist/{chunk-JNXPYBB4.js → chunk-CA42X6KT.js} +3 -3
- package/dist/{chunk-VREKEFLL.js → chunk-D73KXYPF.js} +3 -3
- package/dist/{chunk-JTSEDYVQ.js → chunk-DG4M6ZUE.js} +7 -7
- package/dist/{chunk-DQA7QLMD.js → chunk-EBOC7MT3.js} +10 -25
- package/dist/{chunk-KZ2H5X4G.js → chunk-ECUO3KDP.js} +129 -14
- package/dist/{chunk-JRIO5UD2.js → chunk-EQ63NRB7.js} +5 -5
- package/dist/{chunk-YD734TPH.js → chunk-FALJGAWU.js} +2 -2
- package/dist/{chunk-GWS3VEIW.js → chunk-FWDFM5ZU.js} +24 -3
- package/dist/{chunk-XEGB6BCN.js → chunk-GAYUJ7LE.js} +68 -14
- package/dist/{chunk-UND3GU2L.js → chunk-H7IXIC72.js} +2 -2
- package/dist/{chunk-IR4CFBFN.js → chunk-HAY4ZE2P.js} +12 -12
- package/dist/{chunk-UVDSQ6LW.js → chunk-HCBCAYZU.js} +74 -147
- package/dist/{chunk-4DWFMQDR.js → chunk-HJB5IUKP.js} +89 -145
- package/dist/{chunk-M4AKACEO.js → chunk-HKO36JWF.js} +33 -5
- package/dist/{chunk-KCMKRQX4.js → chunk-HPCTNZM2.js} +45 -82
- package/dist/{chunk-465YSENW.js → chunk-IFBNV6H6.js} +3 -3
- package/dist/{chunk-FJ3H4MN5.js → chunk-IHKBWSXF.js} +2 -2
- package/dist/chunk-JEQQR47K.js +3025 -0
- package/dist/{chunk-FO5ZOVUY.js → chunk-KV2AOLDF.js} +27 -7
- package/dist/chunk-LU7P4LHA.js +33 -0
- package/dist/{chunk-6TUKSZVF.js → chunk-LXPJXFM5.js} +11 -11
- package/dist/{chunk-VQNODYQ4.js → chunk-MIX5N5AC.js} +488 -3668
- package/dist/chunk-MLOK6ZOS.js +2888 -0
- package/dist/{chunk-ZZMN5OM4.js → chunk-MV2VUEJC.js} +2 -2
- package/dist/{chunk-MVVUPGPW.js → chunk-MXHC5QYU.js} +6 -6
- package/dist/{chunk-OBMAI2DP.js → chunk-N3PBVRTZ.js} +12 -388
- package/dist/{chunk-WJHBC77E.js → chunk-N5XKWMDW.js} +17 -7
- package/dist/{chunk-5C3AQNDW.js → chunk-NNNWO6F2.js} +124 -36
- package/dist/{chunk-UFQ3F4FW.js → chunk-NQ6UCCOD.js} +4 -4
- package/dist/chunk-NUGM5KR6.js +165 -0
- package/dist/{chunk-DMD2AGVS.js → chunk-NZU6YDNV.js} +20 -18
- package/dist/{chunk-WHGPSPT5.js → chunk-O6I4CIEU.js} +151 -13
- package/dist/{chunk-XN3L4EYL.js → chunk-OEDBCISO.js} +2 -2
- package/dist/{chunk-PD3MESLB.js → chunk-P3JGPQFL.js} +4 -4
- package/dist/{chunk-UHXRNZ2J.js → chunk-PNY46YEY.js} +23 -6
- package/dist/{chunk-THKY7CD7.js → chunk-PZ4I4JE2.js} +134 -29
- package/dist/{chunk-SROCI7ZU.js → chunk-QQ7EKM72.js} +5 -5
- package/dist/{chunk-QCTRSGHQ.js → chunk-R7LNVMCS.js} +91 -53
- package/dist/{chunk-GOXNB3AO.js → chunk-RAPCMZL4.js} +75 -4
- package/dist/chunk-RKKLTLYB.js +45 -0
- package/dist/{chunk-OB5HIGJY.js → chunk-RKRLDWD3.js} +4 -1
- package/dist/{chunk-DJNLUABN.js → chunk-S4COXYBG.js} +588 -32
- package/dist/{chunk-3HAPLH5M.js → chunk-T3Z6VAAF.js} +172 -11
- package/dist/{chunk-FOT2FX5J.js → chunk-TD7UE2L5.js} +12 -10
- package/dist/{chunk-UUANF5CR.js → chunk-TEO2TLVN.js} +856 -967
- package/dist/{chunk-FCSXB6T2.js → chunk-UOSL25KY.js} +14 -2
- package/dist/{chunk-EELBMBT6.js → chunk-VKBMFOYV.js} +74 -15
- package/dist/chunk-VO2LKSTM.js +165 -0
- package/dist/{chunk-5C77SEEY.js → chunk-VPTUJU4P.js} +3 -3
- package/dist/{chunk-WEH5XRJQ.js → chunk-WIE7ZOSW.js} +2 -2
- package/dist/{chunk-J7PIKKWC.js → chunk-WXCJ7VME.js} +8 -8
- package/dist/{chunk-4DGYLA73.js → chunk-XDOQXGFO.js} +22 -7
- package/dist/{chunk-PPAMZ32Z.js → chunk-XK56QHLX.js} +6 -1
- package/dist/{chunk-AB4XIIVB.js → chunk-YKOFT37S.js} +6 -6
- package/dist/chunk-YSEHGPCT.js +127 -0
- package/dist/{chunk-HFSBBKSQ.js → chunk-YW7UVM5V.js} +138 -3
- package/dist/cli/index.js +32 -32
- package/dist/{clio-WBVQEBKO.js → clio-LT5V7SSZ.js} +9 -9
- package/dist/{code-nav-FGGFIE7L.js → code-nav-LMW275PA.js} +5 -5
- package/dist/codewiki/build-worker.js +4 -4
- package/dist/{components-F7OEATSO.js → components-ZFA3SAER.js} +8 -8
- package/dist/{config-TRBL3RCF.js → config-RXS5T3JT.js} +98 -65
- package/dist/{configure-OLCVPHNM.js → configure-2WYWSCSD.js} +26 -22
- package/dist/{context-MJIJ6GOX.js → context-I3BTOTCS.js} +12 -12
- package/dist/{context-XEWE3MOJ.js → context-MVOORGMF.js} +54 -47
- package/dist/{context-WFPKQSM6.js → context-PALKKQYL.js} +28 -28
- package/dist/{context-clear-KNOS2JPB.js → context-clear-N2WOYZ2K.js} +53 -46
- package/dist/{context-index-SSR5ECNE.js → context-index-HNG3MOME.js} +6 -6
- package/dist/{context-working-set-EUXAZI6N.js → context-working-set-MIEVECVZ.js} +17 -18
- package/dist/{dispatch-runner-B7MTOVKL.js → dispatch-runner-VVA4SRRH.js} +90 -61
- package/dist/{docs-FLJTIDSE.js → docs-7LQ23DLM.js} +8 -8
- package/dist/doctor-TWBWFK5V.js +165 -0
- package/dist/eval-IJ5VEZDJ.js +4483 -0
- package/dist/{evidence-JZNBUOQZ.js → evidence-L5APPXNV.js} +68 -61
- package/dist/{evolve-FJVC4KKI.js → evolve-RGNKFJ52.js} +47 -40
- package/dist/{extensions-IQL36S7K.js → extensions-7WYWUX5A.js} +13 -7
- package/dist/{fleet-BDKYJFCP.js → fleet-6CNVBZZP.js} +113 -76
- package/dist/{fleet-commands-ZFIWZSB3.js → fleet-commands-L2SXSYEI.js} +10 -10
- package/dist/{fleet-graph-Y6HPXIVF.js → fleet-graph-2J3OOIPO.js} +17 -15
- package/dist/{fleet-preflight-BHSNPBMH.js → fleet-preflight-CZRJ4JP5.js} +5 -6
- package/dist/{fleet-validate-BIYREGIK.js → fleet-validate-C5RI6DP7.js} +20 -19
- package/dist/{init-LQUB5COQ.js → init-VBN2ACVA.js} +70 -63
- package/dist/{library-NJAHIGG4.js → library-JHGUMLY2.js} +22 -20
- package/dist/{memory-OG6HOYKM.js → memory-K4OQIYWG.js} +49 -42
- package/dist/{models-5ZG5XY7J.js → models-2NCZUWDD.js} +35 -29
- package/dist/{monitor-TJ7AMTGB.js → monitor-MMVTJABD.js} +64 -45
- package/dist/{orchestrator-WZYB54DM.js → orchestrator-ZKBPCHW6.js} +1971 -520
- package/dist/{paths-XUC7GS6E.js → paths-DBXMZMDU.js} +5 -5
- package/dist/registry-LG64LTF4.js +11 -0
- package/dist/{reset-PXQT45IY.js → reset-DD5JGOY3.js} +11 -11
- package/dist/{run-FQ74YF62.js → run-QEGNX7FL.js} +89 -83
- package/dist/{share-FW7SVCL3.js → share-JKD3BQMW.js} +20 -18
- package/dist/{skills-7E7IRB3R.js → skills-LMQIKDOZ.js} +23 -21
- package/dist/{skills-eval-LI75W6OK.js → skills-eval-I7X2774U.js} +59 -52
- package/dist/{steer-GGWFUJUD.js → steer-CF5TDANS.js} +3 -3
- package/dist/support-I7LOJLIF.js +38 -0
- package/dist/{targets-4CIFKCTW.js → targets-RUSR6B5Z.js} +77 -42
- package/dist/{terminal-lease-WUZY7ZV5.js → terminal-lease-QYVORFR4.js} +6 -4
- package/dist/{trace-PNCASAXC.js → trace-ODOQIVIW.js} +61 -6
- package/dist/{uninstall-7FV7IP4E.js → uninstall-ZJF5H5ZN.js} +8 -8
- package/dist/{upgrade-K2HVIVMQ.js → upgrade-XANW3FXB.js} +29 -26
- package/dist/{usage-GTZELZQX.js → usage-4H7ZRXQT.js} +110 -61
- package/dist/{verifiers-RLAHT27O.js → verifiers-UZXNBZEB.js} +13 -13
- package/dist/{verify-BX3BRKH5.js → verify-BVKWTNDL.js} +9 -9
- package/dist/{wiki-generate-ASIFASCN.js → wiki-generate-MY7WV2QI.js} +76 -69
- package/dist/worker/entry.js +69 -66
- package/docs/alcf-provider.md +1 -1
- package/docs/architecture.md +1 -1
- package/docs/artifact-versions.md +11 -5
- package/docs/built-in-agents.md +1 -1
- package/docs/capacity-and-scheduling.md +23 -2
- package/docs/commands-and-modes.md +2 -2
- package/docs/configuration-and-targets.md +37 -5
- package/docs/context-engine.md +63 -4
- package/docs/documentation-coverage.md +3 -3
- package/docs/documentation-guide.md +1 -1
- package/docs/environment-variables.md +2 -0
- package/docs/eval-runner.md +262 -11
- package/docs/evals-internal.md +72 -2
- package/docs/evidence-and-memory.md +77 -12
- package/docs/evolution.md +1 -1
- package/docs/extensions-and-sharing.md +3 -1
- package/docs/fleet-dispatch.md +34 -9
- package/docs/glossary.md +21 -1
- package/docs/installation-and-lifecycle.md +1 -1
- package/docs/middleware-and-components.md +1 -1
- package/docs/model-catalog.md +1 -1
- package/docs/observability.md +54 -3
- package/docs/proactive-memory.md +127 -14
- package/docs/prompt-envelope-and-tools.md +22 -2
- package/docs/provider-adapter-cookbook.md +1 -1
- package/docs/release-cut-checklist.md +60 -41
- package/docs/safety-model.md +1 -1
- package/docs/scientific-validation.md +1 -1
- package/docs/skills-marketplace.md +1 -1
- package/docs/tool-usage.md +1 -1
- package/docs/trace-store.md +1 -1
- package/docs/troubleshooting.md +87 -0
- package/docs/tui-design.md +1 -1
- package/docs/worker-dispatch-mechanics.md +1 -1
- package/package.json +2 -2
- package/src/cli/agents.ts +1 -1
- package/src/cli/argv.ts +5 -0
- package/src/cli/config-inspect.ts +33 -6
- package/src/cli/config.ts +1 -1
- package/src/cli/configure.ts +107 -23
- package/src/cli/doctor-state-size.ts +82 -0
- package/src/cli/doctor.ts +7 -1
- package/src/cli/eval.ts +80 -16
- package/src/cli/evidence.ts +30 -25
- package/src/cli/extensions.ts +5 -1
- package/src/cli/fleet-preflight.ts +2 -12
- package/src/cli/fleet.ts +32 -3
- package/src/cli/shared.ts +1 -0
- package/src/cli/targets.ts +45 -11
- package/src/cli/trace.ts +63 -4
- package/src/cli/usage.ts +63 -14
- package/src/cli/validate-model.ts +60 -5
- package/src/core/bus-events.ts +54 -1
- package/src/core/cache-telemetry.ts +42 -0
- package/src/core/commit-attribution.ts +4 -4
- package/src/core/config.ts +18 -0
- package/src/core/defaults.ts +36 -6
- package/src/core/endpoint-key.ts +27 -0
- package/src/core/path-boundary.ts +100 -0
- package/src/core/residency-target-key.ts +25 -0
- package/src/core/response-schema.ts +36 -2
- package/src/domains/agents/extension.ts +2 -11
- package/src/domains/agents/fleet-contract.ts +30 -12
- package/src/domains/agents/recipe.ts +7 -1
- package/src/domains/agents/registry.ts +73 -5
- package/src/domains/agents/result-contract.ts +128 -17
- package/src/domains/agents/write-boundary.ts +15 -50
- package/src/domains/config/classify.ts +3 -0
- package/src/domains/context/codewiki/coordinator.ts +12 -4
- package/src/domains/context/project-rules.ts +51 -1
- package/src/domains/dispatch/admission.ts +40 -3
- package/src/domains/dispatch/assignment-reconcile.ts +22 -5
- package/src/domains/dispatch/assignment-store.ts +151 -14
- package/src/domains/dispatch/capacity-lease.ts +98 -9
- package/src/domains/dispatch/contract.ts +26 -1
- package/src/domains/dispatch/delegation-plan.ts +2 -5
- package/src/domains/dispatch/execution-plan.ts +44 -4
- package/src/domains/dispatch/execution-role.ts +9 -1
- package/src/domains/dispatch/extension.ts +309 -96
- package/src/domains/dispatch/fleet-run.ts +78 -4
- package/src/domains/dispatch/gate-role-prompts.ts +38 -0
- package/src/domains/dispatch/heartbeat.ts +32 -8
- package/src/domains/dispatch/index.ts +6 -1
- package/src/domains/dispatch/intent-requirements.ts +40 -0
- package/src/domains/dispatch/intent.ts +84 -8
- package/src/domains/dispatch/orphan-recovery.ts +5 -0
- package/src/domains/dispatch/path-scope.ts +370 -0
- package/src/domains/dispatch/receipt-integrity.ts +2 -1
- package/src/domains/dispatch/reservation-store.ts +116 -8
- package/src/domains/dispatch/state.ts +4 -0
- package/src/domains/dispatch/types.ts +14 -7
- package/src/domains/dispatch/validation.ts +6 -3
- package/src/domains/dispatch/worker-spawn.ts +25 -11
- package/src/domains/dispatch/write-boundary-enforcer.ts +62 -0
- package/src/domains/dispatch/write-boundary.ts +262 -22
- 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 +355 -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/metrics/aggregate.ts +136 -0
- package/src/domains/eval/metrics/call-ledger-stream.ts +112 -0
- package/src/domains/eval/metrics/evidence.ts +79 -2
- 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 +139 -2
- 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 +74 -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 +68 -21
- package/src/domains/evidence/eval.ts +2 -12
- package/src/domains/evidence/findings-markdown.ts +33 -0
- package/src/domains/evidence/index.ts +21 -0
- package/src/domains/evidence/provenance.ts +46 -11
- package/src/domains/evidence/run-trust.ts +7 -113
- package/src/domains/evidence/trust-projection.ts +274 -0
- package/src/domains/evidence/trust-status.ts +145 -17
- package/src/domains/evidence/types.ts +4 -0
- package/src/domains/extensions/compatibility.ts +285 -0
- package/src/domains/extensions/discovery.ts +126 -4
- package/src/domains/extensions/resources.ts +21 -9
- package/src/domains/extensions/state.ts +18 -5
- package/src/domains/extensions/types.ts +6 -1
- package/src/domains/lifecycle/doctor.ts +209 -2
- package/src/domains/memory/index.ts +14 -0
- package/src/domains/memory/task-bank-promotion.ts +64 -0
- package/src/domains/memory/task-memory-policy.ts +77 -8
- 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 +2 -0
- package/src/domains/middleware/index.ts +1 -0
- package/src/domains/middleware/memory-intervention.ts +69 -5
- package/src/domains/middleware/memory-step-endpoint.ts +71 -0
- package/src/domains/observability/background-memory-usage.ts +140 -0
- package/src/domains/observability/cost.ts +1 -1
- package/src/domains/observability/index.ts +7 -0
- package/src/domains/observability/out-of-turn-usage.ts +51 -2
- package/src/domains/observability/trace-store.ts +192 -2
- package/src/domains/prompts/compiler.ts +100 -13
- package/src/domains/prompts/contract.ts +3 -5
- package/src/domains/providers/endpoint-capacity.ts +96 -0
- package/src/domains/providers/extension.ts +30 -2
- package/src/domains/providers/index.ts +10 -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/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/types/capability-flags.ts +2 -0
- package/src/domains/providers/types/target-descriptor.ts +2 -0
- package/src/domains/resources/common-loader.ts +3 -0
- package/src/domains/resources/prompts/loader.ts +184 -17
- package/src/domains/safety/call-target.ts +52 -0
- package/src/domains/safety/policy-engine.ts +5 -5
- package/src/domains/safety/run-effects.ts +96 -2
- package/src/domains/safety/scope.ts +7 -12
- 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/engine/acp/adapter.ts +18 -3
- package/src/engine/acp/server.ts +4 -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/prompt-templates.ts +18 -1
- package/src/engine/provider-payload.ts +29 -1
- package/src/engine/worker-runtime.ts +6 -3
- package/src/entry/orchestrator.ts +176 -30
- 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 +40 -10
- package/src/interactive/cost-overlay.ts +64 -6
- package/src/interactive/dispatch-board.ts +127 -5
- package/src/interactive/fleet-run-preview.ts +41 -15
- package/src/interactive/handoff-round.ts +41 -2
- package/src/interactive/interactive-application.ts +24 -1
- package/src/interactive/interactive-event-projection.ts +14 -0
- package/src/interactive/interactive-input-runtime.ts +8 -0
- package/src/interactive/interactive-presentation.ts +4 -0
- package/src/interactive/interactive-shell.ts +20 -17
- package/src/interactive/interactive-slash-runtime.ts +27 -4
- package/src/interactive/memory-overlay.ts +8 -0
- package/src/interactive/mutation-preview.ts +295 -0
- package/src/interactive/overlay-general-openers.ts +16 -0
- package/src/interactive/overlay-key-routing.ts +38 -0
- package/src/interactive/overlay-lifecycle.ts +38 -5
- package/src/interactive/overlay-permission-lifecycle.ts +22 -2
- package/src/interactive/overlay-session-lifecycle.ts +73 -9
- package/src/interactive/overlays/ask-user.ts +91 -19
- package/src/interactive/overlays/help-reference.ts +4 -0
- package/src/interactive/overlays/prompts.ts +11 -1
- package/src/interactive/overlays/settings.ts +176 -48
- 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/tool-execution.ts +4 -0
- package/src/interactive/side-question.ts +58 -1
- package/src/interactive/slash-commands.ts +7 -2
- 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/terminal-lease.ts +2 -0
- package/src/interactive/turn-context.ts +299 -31
- 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 +42 -9
- package/src/interactive/view/view-overlay.ts +43 -6
- package/src/interactive/worker-receipts.ts +14 -2
- package/src/interactive/worker-stream.ts +8 -0
- package/src/tools/ask-user.ts +43 -2
- package/src/tools/dispatch-admission.ts +12 -13
- package/src/tools/dispatch-arguments.ts +27 -0
- package/src/tools/dispatch-plan.ts +46 -9
- package/src/tools/dispatch-runner.ts +48 -13
- package/src/tools/dispatch-scout.ts +1 -1
- package/src/tools/monitor.ts +13 -0
- package/src/tools/registry.ts +16 -0
- package/src/tools/worker-evidence.ts +19 -13
- package/src/worker/spec-contract.ts +2 -1
- package/dist/chunk-AOCYTWAV.js +0 -449
- package/dist/chunk-HWUFFB6L.js +0 -83
- package/dist/chunk-R346GLFC.js +0 -31
- package/dist/chunk-ZGH7FGS5.js +0 -1079
- package/dist/doctor-RN4YKO2X.js +0 -87
- package/dist/eval-RUBJVSNQ.js +0 -2557
|
@@ -0,0 +1,3025 @@
|
|
|
1
|
+
import { createRequire as __clioCreateRequire } from "node:module"; const require = __clioCreateRequire(import.meta.url);
|
|
2
|
+
import {
|
|
3
|
+
THINKING_LEVELS
|
|
4
|
+
} from "./chunk-XDOQXGFO.js";
|
|
5
|
+
import {
|
|
6
|
+
listCatalogModelsForRuntime,
|
|
7
|
+
mergeCapabilities,
|
|
8
|
+
synthesizeCatalogBackedModel
|
|
9
|
+
} from "./chunk-VO2LKSTM.js";
|
|
10
|
+
import {
|
|
11
|
+
init_esm_shims
|
|
12
|
+
} from "./chunk-3R73A4XB.js";
|
|
13
|
+
|
|
14
|
+
// src/domains/providers/runtimes/builtins.ts
|
|
15
|
+
init_esm_shims();
|
|
16
|
+
|
|
17
|
+
// src/domains/providers/runtimes/antigravity/antigravity-code.ts
|
|
18
|
+
init_esm_shims();
|
|
19
|
+
var ANTIGRAVITY_AUTH_NOTICE = "Uses your existing Antigravity (`agy`) login. Clio stores no Antigravity credentials. agy runs its own agent harness as a subprocess; Clio maps autonomy levels onto its CLI flags but cannot mediate individual agy tool calls.";
|
|
20
|
+
var ANTIGRAVITY_MODELS = [
|
|
21
|
+
"Gemini 3.5 Flash (High)",
|
|
22
|
+
"Gemini 3.5 Flash (Medium)",
|
|
23
|
+
"Gemini 3.5 Flash (Low)",
|
|
24
|
+
"Gemini 3.1 Pro (High)",
|
|
25
|
+
"Gemini 3.1 Pro (Low)",
|
|
26
|
+
"Claude Sonnet 4.6 (Thinking)",
|
|
27
|
+
"Claude Opus 4.6 (Thinking)",
|
|
28
|
+
"GPT-OSS 120B (Medium)"
|
|
29
|
+
];
|
|
30
|
+
var antigravityCapabilities = {
|
|
31
|
+
chat: true,
|
|
32
|
+
tools: true,
|
|
33
|
+
toolCallFormat: "openai",
|
|
34
|
+
reasoning: true,
|
|
35
|
+
vision: true,
|
|
36
|
+
audio: false,
|
|
37
|
+
embeddings: false,
|
|
38
|
+
rerank: false,
|
|
39
|
+
fim: false,
|
|
40
|
+
contextWindow: 1e6,
|
|
41
|
+
maxTokens: 8192
|
|
42
|
+
};
|
|
43
|
+
var antigravityCodeRuntime = {
|
|
44
|
+
id: "antigravity-code",
|
|
45
|
+
displayName: "Antigravity CLI",
|
|
46
|
+
kind: "subprocess",
|
|
47
|
+
tier: "subscription",
|
|
48
|
+
// Reuses the existing `google-generative-ai` api family: the worker branches
|
|
49
|
+
// to its own runner before any pi-ai inference, so this only needs to be a
|
|
50
|
+
// valid, google-backed family. The runner is selected by runtime id, and the
|
|
51
|
+
// plain-text parser is named by `outputParser`.
|
|
52
|
+
apiFamily: "google-generative-ai",
|
|
53
|
+
auth: "none",
|
|
54
|
+
authNotice: ANTIGRAVITY_AUTH_NOTICE,
|
|
55
|
+
knownModels: [...ANTIGRAVITY_MODELS],
|
|
56
|
+
binaryName: "agy",
|
|
57
|
+
headlessCommand: "agy --print",
|
|
58
|
+
outputParser: "antigravity-print-text",
|
|
59
|
+
defaultCapabilities: antigravityCapabilities,
|
|
60
|
+
synthesizeModel(target, wireModelId, kb) {
|
|
61
|
+
return synthesizeCatalogBackedModel({
|
|
62
|
+
target,
|
|
63
|
+
wireModelId,
|
|
64
|
+
kb,
|
|
65
|
+
defaultCapabilities: antigravityCapabilities,
|
|
66
|
+
runtimeId: "antigravity-code",
|
|
67
|
+
api: "google-generative-ai",
|
|
68
|
+
provider: "google",
|
|
69
|
+
defaultBaseUrl: "antigravity://local"
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
};
|
|
73
|
+
var antigravity_code_default = antigravityCodeRuntime;
|
|
74
|
+
|
|
75
|
+
// src/domains/providers/runtimes/claude/claude-code.ts
|
|
76
|
+
init_esm_shims();
|
|
77
|
+
|
|
78
|
+
// src/domains/providers/runtimes/claude/common.ts
|
|
79
|
+
init_esm_shims();
|
|
80
|
+
var CLAUDE_CODE_AUTH_NOTICE = "Uses your existing Claude Code login from the installed `claude` command. Clio stores no Claude Code credentials.";
|
|
81
|
+
var CLAUDE_CODE_MODELS = [
|
|
82
|
+
"sonnet",
|
|
83
|
+
"opus",
|
|
84
|
+
"haiku",
|
|
85
|
+
"claude-sonnet-4-5",
|
|
86
|
+
"claude-opus-4-5",
|
|
87
|
+
"claude-haiku-4-5",
|
|
88
|
+
"claude-3-7-sonnet-latest"
|
|
89
|
+
];
|
|
90
|
+
var claudeCodeCapabilities = {
|
|
91
|
+
chat: true,
|
|
92
|
+
tools: true,
|
|
93
|
+
toolCallFormat: "anthropic",
|
|
94
|
+
reasoning: true,
|
|
95
|
+
thinkingFormat: "anthropic-extended",
|
|
96
|
+
vision: true,
|
|
97
|
+
audio: false,
|
|
98
|
+
embeddings: false,
|
|
99
|
+
rerank: false,
|
|
100
|
+
fim: false,
|
|
101
|
+
contextWindow: 2e5,
|
|
102
|
+
maxTokens: 8192
|
|
103
|
+
};
|
|
104
|
+
function synthesizeClaudeDelegatedModel(input) {
|
|
105
|
+
return synthesizeCatalogBackedModel({
|
|
106
|
+
target: input.target,
|
|
107
|
+
wireModelId: input.wireModelId,
|
|
108
|
+
kb: input.kb,
|
|
109
|
+
defaultCapabilities: input.defaultCapabilities,
|
|
110
|
+
runtimeId: input.runtimeId,
|
|
111
|
+
api: input.apiFamily,
|
|
112
|
+
provider: "anthropic",
|
|
113
|
+
defaultBaseUrl: "claude-code://local"
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// src/domains/providers/runtimes/claude/claude-code.ts
|
|
118
|
+
var claudeCodeRuntime = {
|
|
119
|
+
id: "claude-code",
|
|
120
|
+
displayName: "Claude Code CLI",
|
|
121
|
+
kind: "subprocess",
|
|
122
|
+
tier: "subscription",
|
|
123
|
+
apiFamily: "claude-code-subprocess",
|
|
124
|
+
auth: "claude-cli",
|
|
125
|
+
authNotice: CLAUDE_CODE_AUTH_NOTICE,
|
|
126
|
+
knownModels: [...CLAUDE_CODE_MODELS],
|
|
127
|
+
binaryName: "claude",
|
|
128
|
+
headlessCommand: "claude -p --output-format stream-json",
|
|
129
|
+
outputParser: "claude-code-stream-json",
|
|
130
|
+
defaultCapabilities: claudeCodeCapabilities,
|
|
131
|
+
synthesizeModel(target, wireModelId, kb) {
|
|
132
|
+
return synthesizeClaudeDelegatedModel({
|
|
133
|
+
target,
|
|
134
|
+
wireModelId,
|
|
135
|
+
kb,
|
|
136
|
+
defaultCapabilities: claudeCodeCapabilities,
|
|
137
|
+
runtimeId: "claude-code",
|
|
138
|
+
apiFamily: "claude-code-subprocess"
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
};
|
|
142
|
+
var claude_code_default = claudeCodeRuntime;
|
|
143
|
+
|
|
144
|
+
// src/domains/providers/runtimes/claude/claude-sdk.ts
|
|
145
|
+
init_esm_shims();
|
|
146
|
+
var claudeSdkRuntime = {
|
|
147
|
+
id: "claude-sdk",
|
|
148
|
+
displayName: "Claude Agent SDK",
|
|
149
|
+
kind: "sdk",
|
|
150
|
+
tier: "subscription",
|
|
151
|
+
apiFamily: "claude-agent-sdk",
|
|
152
|
+
auth: "claude-cli",
|
|
153
|
+
authNotice: CLAUDE_CODE_AUTH_NOTICE,
|
|
154
|
+
knownModels: [...CLAUDE_CODE_MODELS],
|
|
155
|
+
binaryName: "claude",
|
|
156
|
+
headlessCommand: "@anthropic-ai/claude-agent-sdk query()",
|
|
157
|
+
outputParser: "claude-agent-sdk-messages",
|
|
158
|
+
defaultCapabilities: claudeCodeCapabilities,
|
|
159
|
+
synthesizeModel(target, wireModelId, kb) {
|
|
160
|
+
return synthesizeClaudeDelegatedModel({
|
|
161
|
+
target,
|
|
162
|
+
wireModelId,
|
|
163
|
+
kb,
|
|
164
|
+
defaultCapabilities: claudeCodeCapabilities,
|
|
165
|
+
runtimeId: "claude-sdk",
|
|
166
|
+
apiFamily: "claude-agent-sdk"
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
};
|
|
170
|
+
var claude_sdk_default = claudeSdkRuntime;
|
|
171
|
+
|
|
172
|
+
// src/domains/providers/runtimes/cloud/alcf.ts
|
|
173
|
+
init_esm_shims();
|
|
174
|
+
|
|
175
|
+
// src/domains/providers/probe/http.ts
|
|
176
|
+
init_esm_shims();
|
|
177
|
+
import { performance } from "node:perf_hooks";
|
|
178
|
+
async function probeHttp(opts) {
|
|
179
|
+
const { response, latencyMs, error } = await runFetch(opts);
|
|
180
|
+
if (response === null) return { ok: false, error: error ?? "unknown transport error", latencyMs };
|
|
181
|
+
const method = opts.method ?? "GET";
|
|
182
|
+
if (response.ok) return { ok: true, latencyMs };
|
|
183
|
+
if (method === "HEAD" && response.status === 405) return { ok: true, latencyMs };
|
|
184
|
+
return {
|
|
185
|
+
ok: false,
|
|
186
|
+
latencyMs,
|
|
187
|
+
error: `HTTP ${response.status}: ${response.statusText}`
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
async function probeJson(opts) {
|
|
191
|
+
const { response, latencyMs, error } = await runFetch(opts);
|
|
192
|
+
if (response === null) return { ok: false, error: error ?? "unknown transport error", latencyMs };
|
|
193
|
+
const method = opts.method ?? "GET";
|
|
194
|
+
if (!response.ok && !(method === "HEAD" && response.status === 405)) {
|
|
195
|
+
return {
|
|
196
|
+
ok: false,
|
|
197
|
+
latencyMs,
|
|
198
|
+
error: `HTTP ${response.status}: ${response.statusText}`
|
|
199
|
+
};
|
|
200
|
+
}
|
|
201
|
+
let data;
|
|
202
|
+
try {
|
|
203
|
+
data = await response.json();
|
|
204
|
+
} catch (err) {
|
|
205
|
+
return { ok: false, latencyMs, error: `JSON parse: ${describeError(err)}` };
|
|
206
|
+
}
|
|
207
|
+
return { ok: true, latencyMs, data };
|
|
208
|
+
}
|
|
209
|
+
async function runFetch(opts) {
|
|
210
|
+
const controller = new AbortController();
|
|
211
|
+
let timedOut = false;
|
|
212
|
+
const timer = setTimeout(() => {
|
|
213
|
+
timedOut = true;
|
|
214
|
+
controller.abort();
|
|
215
|
+
}, opts.timeoutMs);
|
|
216
|
+
const onExternalAbort = () => controller.abort();
|
|
217
|
+
if (opts.signal) {
|
|
218
|
+
if (opts.signal.aborted) controller.abort();
|
|
219
|
+
else opts.signal.addEventListener("abort", onExternalAbort, { once: true });
|
|
220
|
+
}
|
|
221
|
+
const init = {
|
|
222
|
+
method: opts.method ?? "GET",
|
|
223
|
+
signal: controller.signal
|
|
224
|
+
};
|
|
225
|
+
if (opts.headers) init.headers = opts.headers;
|
|
226
|
+
if (opts.body !== void 0) init.body = opts.body;
|
|
227
|
+
const started = performance.now();
|
|
228
|
+
try {
|
|
229
|
+
const response = await fetch(opts.url, init);
|
|
230
|
+
return { response, latencyMs: Math.round(performance.now() - started) };
|
|
231
|
+
} catch (err) {
|
|
232
|
+
const latencyMs = Math.round(performance.now() - started);
|
|
233
|
+
if (timedOut) {
|
|
234
|
+
return { response: null, latencyMs, error: `timeout after ${opts.timeoutMs}ms` };
|
|
235
|
+
}
|
|
236
|
+
if (opts.signal?.aborted) {
|
|
237
|
+
return { response: null, latencyMs, error: "aborted by caller" };
|
|
238
|
+
}
|
|
239
|
+
return { response: null, latencyMs, error: describeError(err) };
|
|
240
|
+
} finally {
|
|
241
|
+
clearTimeout(timer);
|
|
242
|
+
if (opts.signal) opts.signal.removeEventListener("abort", onExternalAbort);
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
function describeError(err) {
|
|
246
|
+
if (!(err instanceof Error)) return String(err);
|
|
247
|
+
const cause = err.cause;
|
|
248
|
+
if (cause instanceof Error && cause.message.length > 0) {
|
|
249
|
+
const code = cause.code;
|
|
250
|
+
return typeof code === "string" && !cause.message.includes(code) ? `${cause.message} (${code})` : cause.message;
|
|
251
|
+
}
|
|
252
|
+
return err.message;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
// src/domains/providers/runtimes/common/local-synth.ts
|
|
256
|
+
init_esm_shims();
|
|
257
|
+
|
|
258
|
+
// src/domains/providers/types/local-model-quirks.ts
|
|
259
|
+
init_esm_shims();
|
|
260
|
+
var KV_CACHE_QUANTS = ["f32", "f16", "q8_0", "q4_0", "q4_1", "iq4_nl", "q5_0", "q5_1"];
|
|
261
|
+
function isRecord(value) {
|
|
262
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
263
|
+
}
|
|
264
|
+
function asKvCacheQuant(value) {
|
|
265
|
+
if (value === false) return false;
|
|
266
|
+
if (typeof value !== "string") return void 0;
|
|
267
|
+
return KV_CACHE_QUANTS.includes(value) ? value : void 0;
|
|
268
|
+
}
|
|
269
|
+
function asPositive(value) {
|
|
270
|
+
return typeof value === "number" && Number.isFinite(value) && value >= 0 ? value : void 0;
|
|
271
|
+
}
|
|
272
|
+
function asInteger(value) {
|
|
273
|
+
const n = asPositive(value);
|
|
274
|
+
return n !== void 0 && Number.isInteger(n) ? n : void 0;
|
|
275
|
+
}
|
|
276
|
+
function asPenalty(value) {
|
|
277
|
+
return typeof value === "number" && Number.isFinite(value) ? value : void 0;
|
|
278
|
+
}
|
|
279
|
+
function extractKvCache(raw) {
|
|
280
|
+
if (!isRecord(raw)) return void 0;
|
|
281
|
+
const out = {};
|
|
282
|
+
const k = asKvCacheQuant(raw.kQuant);
|
|
283
|
+
if (k !== void 0) out.kQuant = k;
|
|
284
|
+
const v = asKvCacheQuant(raw.vQuant);
|
|
285
|
+
if (v !== void 0) out.vQuant = v;
|
|
286
|
+
if (typeof raw.useFp16 === "boolean") out.useFp16 = raw.useFp16;
|
|
287
|
+
return Object.keys(out).length > 0 ? out : void 0;
|
|
288
|
+
}
|
|
289
|
+
function extractSamplingProfile(raw) {
|
|
290
|
+
if (!isRecord(raw)) return void 0;
|
|
291
|
+
const out = {};
|
|
292
|
+
const temperature = asPositive(raw.temperature);
|
|
293
|
+
if (temperature !== void 0) out.temperature = temperature;
|
|
294
|
+
const topP = asPositive(raw.topP);
|
|
295
|
+
if (topP !== void 0) out.topP = topP;
|
|
296
|
+
const topK = asInteger(raw.topK);
|
|
297
|
+
if (topK !== void 0) out.topK = topK;
|
|
298
|
+
const minP = asPositive(raw.minP);
|
|
299
|
+
if (minP !== void 0) out.minP = minP;
|
|
300
|
+
const rp = asPenalty(raw.repeatPenalty) ?? asPenalty(raw.repetitionPenalty);
|
|
301
|
+
if (rp !== void 0) out.repeatPenalty = rp;
|
|
302
|
+
const pp = asPenalty(raw.presencePenalty);
|
|
303
|
+
if (pp !== void 0) out.presencePenalty = pp;
|
|
304
|
+
const fp = asPenalty(raw.frequencyPenalty);
|
|
305
|
+
if (fp !== void 0) out.frequencyPenalty = fp;
|
|
306
|
+
const maxTokens = asInteger(raw.maxTokens);
|
|
307
|
+
if (maxTokens !== void 0) out.maxTokens = maxTokens;
|
|
308
|
+
return Object.keys(out).length > 0 ? out : void 0;
|
|
309
|
+
}
|
|
310
|
+
function extractSampling(raw) {
|
|
311
|
+
if (!isRecord(raw)) return void 0;
|
|
312
|
+
const out = {};
|
|
313
|
+
const thinking = extractSamplingProfile(raw.thinking);
|
|
314
|
+
if (thinking) out.thinking = thinking;
|
|
315
|
+
const instruct = extractSamplingProfile(raw.instruct);
|
|
316
|
+
if (instruct) out.instruct = instruct;
|
|
317
|
+
return Object.keys(out).length > 0 ? out : void 0;
|
|
318
|
+
}
|
|
319
|
+
var THINKING_MECHANISMS = [
|
|
320
|
+
"effort-levels",
|
|
321
|
+
"budget-tokens",
|
|
322
|
+
"on-off",
|
|
323
|
+
"always-on",
|
|
324
|
+
"none"
|
|
325
|
+
];
|
|
326
|
+
function asThinkingMechanism(value) {
|
|
327
|
+
if (typeof value !== "string") return void 0;
|
|
328
|
+
return THINKING_MECHANISMS.includes(value) ? value : void 0;
|
|
329
|
+
}
|
|
330
|
+
function extractBudgetByLevel(raw) {
|
|
331
|
+
if (!isRecord(raw)) return void 0;
|
|
332
|
+
const out = {};
|
|
333
|
+
const minimal = asInteger(raw.minimal);
|
|
334
|
+
if (minimal !== void 0) out.minimal = minimal;
|
|
335
|
+
const low = asInteger(raw.low);
|
|
336
|
+
if (low !== void 0) out.low = low;
|
|
337
|
+
const medium = asInteger(raw.medium);
|
|
338
|
+
if (medium !== void 0) out.medium = medium;
|
|
339
|
+
const high = asInteger(raw.high);
|
|
340
|
+
if (high !== void 0) out.high = high;
|
|
341
|
+
const xhigh = asInteger(raw.xhigh);
|
|
342
|
+
if (xhigh !== void 0) out.xhigh = xhigh;
|
|
343
|
+
return Object.keys(out).length > 0 ? out : void 0;
|
|
344
|
+
}
|
|
345
|
+
function extractEffortByLevel(raw) {
|
|
346
|
+
if (!isRecord(raw)) return void 0;
|
|
347
|
+
const out = {};
|
|
348
|
+
if (typeof raw.off === "string" && raw.off.length > 0) out.off = raw.off;
|
|
349
|
+
if (typeof raw.minimal === "string" && raw.minimal.length > 0) out.minimal = raw.minimal;
|
|
350
|
+
if (typeof raw.low === "string" && raw.low.length > 0) out.low = raw.low;
|
|
351
|
+
if (typeof raw.medium === "string" && raw.medium.length > 0) out.medium = raw.medium;
|
|
352
|
+
if (typeof raw.high === "string" && raw.high.length > 0) out.high = raw.high;
|
|
353
|
+
if (typeof raw.xhigh === "string" && raw.xhigh.length > 0) out.xhigh = raw.xhigh;
|
|
354
|
+
return Object.keys(out).length > 0 ? out : void 0;
|
|
355
|
+
}
|
|
356
|
+
function extractThinkingQuirks(raw) {
|
|
357
|
+
if (!isRecord(raw)) return void 0;
|
|
358
|
+
const mechanism = asThinkingMechanism(raw.mechanism);
|
|
359
|
+
if (!mechanism) return void 0;
|
|
360
|
+
const out = { mechanism };
|
|
361
|
+
const budgetByLevel = extractBudgetByLevel(raw.budgetByLevel);
|
|
362
|
+
if (budgetByLevel) out.budgetByLevel = budgetByLevel;
|
|
363
|
+
const effortByLevel = extractEffortByLevel(raw.effortByLevel);
|
|
364
|
+
if (effortByLevel) out.effortByLevel = effortByLevel;
|
|
365
|
+
if (typeof raw.guidance === "string" && raw.guidance.length > 0) out.guidance = raw.guidance;
|
|
366
|
+
return out;
|
|
367
|
+
}
|
|
368
|
+
function extractLocalModelQuirks(raw) {
|
|
369
|
+
if (!isRecord(raw)) return void 0;
|
|
370
|
+
const out = {};
|
|
371
|
+
const kvCache = extractKvCache(raw.kvCache);
|
|
372
|
+
if (kvCache) out.kvCache = kvCache;
|
|
373
|
+
const sampling = extractSampling(raw.sampling);
|
|
374
|
+
if (sampling) out.sampling = sampling;
|
|
375
|
+
const thinking = extractThinkingQuirks(raw.thinking);
|
|
376
|
+
if (thinking) out.thinking = thinking;
|
|
377
|
+
return Object.keys(out).length > 0 ? out : void 0;
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
// src/domains/providers/runtimes/common/local-synth.ts
|
|
381
|
+
function openAIThinkingFormat(caps) {
|
|
382
|
+
switch (caps.thinkingFormat) {
|
|
383
|
+
case "qwen-chat-template":
|
|
384
|
+
case "openrouter":
|
|
385
|
+
case "zai":
|
|
386
|
+
return caps.thinkingFormat;
|
|
387
|
+
case "deepseek-r1":
|
|
388
|
+
return "deepseek";
|
|
389
|
+
case "harmony":
|
|
390
|
+
return "harmony";
|
|
391
|
+
default:
|
|
392
|
+
return void 0;
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
function localOpenAICompat(caps, runtimeId) {
|
|
396
|
+
const compat = {
|
|
397
|
+
supportsStore: false,
|
|
398
|
+
supportsDeveloperRole: false,
|
|
399
|
+
supportsReasoningEffort: false,
|
|
400
|
+
supportsUsageInStreaming: true,
|
|
401
|
+
supportsFinishReason: false,
|
|
402
|
+
maxTokensField: "max_tokens",
|
|
403
|
+
supportsThinkingTokenBudget: runtimeId === "vllm",
|
|
404
|
+
supportsStrictMode: false
|
|
405
|
+
};
|
|
406
|
+
const thinkingFormat = openAIThinkingFormat(caps);
|
|
407
|
+
if (thinkingFormat) compat.thinkingFormat = thinkingFormat;
|
|
408
|
+
return compat;
|
|
409
|
+
}
|
|
410
|
+
function localAnthropicCompat() {
|
|
411
|
+
return {
|
|
412
|
+
supportsEagerToolInputStreaming: false,
|
|
413
|
+
supportsLongCacheRetention: false
|
|
414
|
+
};
|
|
415
|
+
}
|
|
416
|
+
function synthLocalModel(input) {
|
|
417
|
+
const { target, wireModelId, kb, defaultCapabilities: defaultCapabilities25, apiFamily, provider } = input;
|
|
418
|
+
const caps = mergeCapabilities(defaultCapabilities25, kb?.entry.capabilities ?? null, null, target.capabilities ?? null);
|
|
419
|
+
const rawUrl = target.url ?? "";
|
|
420
|
+
const baseUrl = rawUrl.length > 0 ? input.baseUrlForTarget(rawUrl) : "";
|
|
421
|
+
const pricing = target.pricing;
|
|
422
|
+
const headers = target.auth?.headers;
|
|
423
|
+
const quirks = extractLocalModelQuirks(kb?.entry.quirks);
|
|
424
|
+
const model = {
|
|
425
|
+
id: wireModelId,
|
|
426
|
+
name: `${wireModelId} (${target.id})`,
|
|
427
|
+
api: apiFamily,
|
|
428
|
+
provider,
|
|
429
|
+
baseUrl,
|
|
430
|
+
reasoning: caps.reasoning,
|
|
431
|
+
input: caps.vision ? ["text", "image"] : ["text"],
|
|
432
|
+
cost: {
|
|
433
|
+
input: pricing?.input ?? 0,
|
|
434
|
+
output: pricing?.output ?? 0,
|
|
435
|
+
cacheRead: pricing?.cacheRead ?? 0,
|
|
436
|
+
cacheWrite: pricing?.cacheWrite ?? 0
|
|
437
|
+
},
|
|
438
|
+
contextWindow: caps.contextWindow,
|
|
439
|
+
maxTokens: caps.maxTokens,
|
|
440
|
+
clio: {
|
|
441
|
+
targetId: target.id,
|
|
442
|
+
runtimeId: target.runtime,
|
|
443
|
+
...target.lifecycle ? { lifecycle: target.lifecycle } : {},
|
|
444
|
+
...target.gateway === true ? { gateway: true } : {},
|
|
445
|
+
...kb?.entry.family ? { family: kb.entry.family } : {},
|
|
446
|
+
...quirks ? { quirks } : {},
|
|
447
|
+
...target.lmstudio ? { lmstudio: target.lmstudio } : {}
|
|
448
|
+
}
|
|
449
|
+
};
|
|
450
|
+
if (headers) model.headers = headers;
|
|
451
|
+
if (apiFamily === "openai-completions") {
|
|
452
|
+
model.compat = localOpenAICompat(caps, target.runtime);
|
|
453
|
+
}
|
|
454
|
+
if (apiFamily === "anthropic-messages") {
|
|
455
|
+
model.compat = localAnthropicCompat();
|
|
456
|
+
}
|
|
457
|
+
return model;
|
|
458
|
+
}
|
|
459
|
+
function stripTrailingSlash(url2) {
|
|
460
|
+
return url2.endsWith("/") ? url2.slice(0, -1) : url2;
|
|
461
|
+
}
|
|
462
|
+
function stripRedundantV1(url2) {
|
|
463
|
+
return url2.endsWith("/v1") ? url2.slice(0, -"/v1".length) : url2;
|
|
464
|
+
}
|
|
465
|
+
var withV1 = (url2) => `${stripRedundantV1(stripTrailingSlash(url2))}/v1`;
|
|
466
|
+
var withAsIs = (url2) => stripTrailingSlash(url2);
|
|
467
|
+
function targetBaseUrl(target) {
|
|
468
|
+
return target.url ? stripTrailingSlash(target.url) : null;
|
|
469
|
+
}
|
|
470
|
+
function targetRootUrl(target) {
|
|
471
|
+
return target.url ? stripRedundantV1(stripTrailingSlash(target.url)) : null;
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
// src/domains/providers/runtimes/protocol/openai-compat.ts
|
|
475
|
+
init_esm_shims();
|
|
476
|
+
|
|
477
|
+
// src/core/context-floor.ts
|
|
478
|
+
init_esm_shims();
|
|
479
|
+
var CLIO_MIN_CONTEXT_WINDOW = 131072;
|
|
480
|
+
var CLIO_MIN_MAX_OUTPUT_TOKENS = 32768;
|
|
481
|
+
var CLIO_CONTEXT_WINDOW_WARN_BELOW = 128e3;
|
|
482
|
+
|
|
483
|
+
// src/domains/providers/probe/reasoning.ts
|
|
484
|
+
init_esm_shims();
|
|
485
|
+
import { performance as performance2 } from "node:perf_hooks";
|
|
486
|
+
var PROMPT = "What is 2+2? Think briefly, then answer.";
|
|
487
|
+
function nonEmptyString(value) {
|
|
488
|
+
return typeof value === "string" && value.trim().length > 0;
|
|
489
|
+
}
|
|
490
|
+
function detectReasoningField(data) {
|
|
491
|
+
const message = data.choices?.[0]?.message;
|
|
492
|
+
if (!message) return null;
|
|
493
|
+
if (nonEmptyString(message.reasoning_content)) return "reasoning_content";
|
|
494
|
+
if (nonEmptyString(message.reasoning)) return "reasoning";
|
|
495
|
+
if (nonEmptyString(message.reasoning_text)) return "reasoning_text";
|
|
496
|
+
return null;
|
|
497
|
+
}
|
|
498
|
+
function trimTrailingSlash(url2) {
|
|
499
|
+
return url2.endsWith("/") ? url2.slice(0, -1) : url2;
|
|
500
|
+
}
|
|
501
|
+
async function probeOpenAICompatReasoning(opts) {
|
|
502
|
+
const controller = new AbortController();
|
|
503
|
+
let timedOut = false;
|
|
504
|
+
const timer = setTimeout(() => {
|
|
505
|
+
timedOut = true;
|
|
506
|
+
controller.abort();
|
|
507
|
+
}, opts.timeoutMs);
|
|
508
|
+
const onExternalAbort = () => controller.abort();
|
|
509
|
+
if (opts.signal) {
|
|
510
|
+
if (opts.signal.aborted) controller.abort();
|
|
511
|
+
else opts.signal.addEventListener("abort", onExternalAbort, { once: true });
|
|
512
|
+
}
|
|
513
|
+
const headers = { "content-type": "application/json" };
|
|
514
|
+
if (opts.apiKey && opts.apiKey.length > 0) headers.authorization = `Bearer ${opts.apiKey}`;
|
|
515
|
+
const body = JSON.stringify({
|
|
516
|
+
model: opts.modelId,
|
|
517
|
+
messages: [{ role: "user", content: PROMPT }],
|
|
518
|
+
max_tokens: 200,
|
|
519
|
+
temperature: 0,
|
|
520
|
+
stream: false,
|
|
521
|
+
reasoning_effort: "low"
|
|
522
|
+
});
|
|
523
|
+
const url2 = `${trimTrailingSlash(opts.baseUrl)}/v1/chat/completions`;
|
|
524
|
+
const started = performance2.now();
|
|
525
|
+
try {
|
|
526
|
+
const response = await fetch(url2, {
|
|
527
|
+
method: "POST",
|
|
528
|
+
headers,
|
|
529
|
+
body,
|
|
530
|
+
signal: controller.signal
|
|
531
|
+
});
|
|
532
|
+
const latencyMs = Math.round(performance2.now() - started);
|
|
533
|
+
if (!response.ok) {
|
|
534
|
+
return { reasoning: false, latencyMs, error: `HTTP ${response.status}: ${response.statusText}` };
|
|
535
|
+
}
|
|
536
|
+
const data = await response.json();
|
|
537
|
+
const field = detectReasoningField(data);
|
|
538
|
+
if (field) return { reasoning: true, field, latencyMs };
|
|
539
|
+
return { reasoning: false, latencyMs };
|
|
540
|
+
} catch (err) {
|
|
541
|
+
const latencyMs = Math.round(performance2.now() - started);
|
|
542
|
+
if (timedOut) return { reasoning: false, latencyMs, error: `timeout after ${opts.timeoutMs}ms` };
|
|
543
|
+
if (opts.signal?.aborted) return { reasoning: false, latencyMs, error: "aborted by caller" };
|
|
544
|
+
return { reasoning: false, latencyMs, error: err instanceof Error ? err.message : String(err) };
|
|
545
|
+
} finally {
|
|
546
|
+
clearTimeout(timer);
|
|
547
|
+
if (opts.signal) opts.signal.removeEventListener("abort", onExternalAbort);
|
|
548
|
+
}
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
// src/domains/providers/runtimes/common/probe-helpers.ts
|
|
552
|
+
init_esm_shims();
|
|
553
|
+
|
|
554
|
+
// src/domains/providers/types/context-window-slots.ts
|
|
555
|
+
init_esm_shims();
|
|
556
|
+
function formatContextWindowSlots(contextWindow, slots) {
|
|
557
|
+
const format = (n) => Math.round(n).toLocaleString("en-US");
|
|
558
|
+
return `${format(contextWindow)} (${format(slots.totalContextSize)} / ${slots.slots} slots)`;
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
// src/domains/providers/runtimes/common/probe-helpers.ts
|
|
562
|
+
async function probeUrl(url2, ctx, method = "GET") {
|
|
563
|
+
const base = { url: url2, timeoutMs: ctx.httpTimeoutMs, method };
|
|
564
|
+
return ctx.signal ? probeHttp({ ...base, signal: ctx.signal }) : probeHttp(base);
|
|
565
|
+
}
|
|
566
|
+
async function probeOpenAIModels(base, ctx, modelsPath = "/v1/models") {
|
|
567
|
+
return (await probeOpenAIModelCatalog(base, ctx, modelsPath)).models;
|
|
568
|
+
}
|
|
569
|
+
var OPENAI_COMPAT_DETAIL_PATHS = ["/api/v0/models"];
|
|
570
|
+
async function probeModelDetailRows(base, ctx, modelsPath) {
|
|
571
|
+
const rows = /* @__PURE__ */ new Map();
|
|
572
|
+
for (const detailPath of OPENAI_COMPAT_DETAIL_PATHS) {
|
|
573
|
+
if (detailPath === modelsPath) continue;
|
|
574
|
+
const opts = { url: `${base}${detailPath}`, timeoutMs: ctx.httpTimeoutMs };
|
|
575
|
+
const result = await (ctx.signal ? probeJson({ ...opts, signal: ctx.signal }) : probeJson(opts));
|
|
576
|
+
if (!result.ok || !Array.isArray(result.data?.data)) continue;
|
|
577
|
+
for (const row of result.data.data) {
|
|
578
|
+
if (typeof row?.id !== "string" || row.id.length === 0) continue;
|
|
579
|
+
if (!rows.has(row.id)) rows.set(row.id, row);
|
|
580
|
+
}
|
|
581
|
+
if (rows.size > 0) break;
|
|
582
|
+
}
|
|
583
|
+
return rows;
|
|
584
|
+
}
|
|
585
|
+
async function probeOpenAIModelCatalog(base, ctx, modelsPath = "/v1/models") {
|
|
586
|
+
const opts = { url: `${base}${modelsPath}`, timeoutMs: ctx.httpTimeoutMs };
|
|
587
|
+
const result = await (ctx.signal ? probeJson({ ...opts, signal: ctx.signal }) : probeJson(opts));
|
|
588
|
+
if (!result.ok || !result.data?.data) return { models: [], modelCapabilities: {}, modelStates: {} };
|
|
589
|
+
const detail = await probeModelDetailRows(base, ctx, modelsPath);
|
|
590
|
+
const models = [];
|
|
591
|
+
const modelCapabilities = {};
|
|
592
|
+
const modelStates = {};
|
|
593
|
+
for (const row of result.data.data) {
|
|
594
|
+
if (typeof row?.id !== "string" || row.id.length === 0) continue;
|
|
595
|
+
models.push(row.id);
|
|
596
|
+
const detailRow = detail.get(row.id);
|
|
597
|
+
const caps = {
|
|
598
|
+
...detailRow ? capabilitiesFromOpenAIModelEntry(detailRow) : {},
|
|
599
|
+
...capabilitiesFromOpenAIModelEntry(row)
|
|
600
|
+
};
|
|
601
|
+
if (Object.keys(caps).length > 0) modelCapabilities[row.id] = caps;
|
|
602
|
+
const loadedContext = loadedContextFromEntry(row) ?? (detailRow ? loadedContextFromEntry(detailRow) : void 0);
|
|
603
|
+
const state = modelStateFromOpenAIModelEntry(row) ?? (detailRow ? modelStateFromOpenAIModelEntry(detailRow) : void 0) ?? // A reported loaded context is itself the residency answer: nothing
|
|
604
|
+
// serves a window for a model it has not loaded.
|
|
605
|
+
(loadedContext !== void 0 ? { state: "loaded" } : void 0);
|
|
606
|
+
const contextSlots = contextSlotsFromEntry(row) ?? (detailRow ? contextSlotsFromEntry(detailRow) : void 0);
|
|
607
|
+
const withSlots = contextSlots ? { ...state ?? { state: "unknown" }, contextSlots } : state;
|
|
608
|
+
if (withSlots) {
|
|
609
|
+
modelStates[row.id] = loadedContext === void 0 ? withSlots : { ...withSlots, contextLength: loadedContext };
|
|
610
|
+
}
|
|
611
|
+
}
|
|
612
|
+
return { models, modelCapabilities, modelStates };
|
|
613
|
+
}
|
|
614
|
+
function isRecord2(value) {
|
|
615
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
616
|
+
}
|
|
617
|
+
function positiveNumber(value) {
|
|
618
|
+
return typeof value === "number" && Number.isFinite(value) && value > 0 ? value : void 0;
|
|
619
|
+
}
|
|
620
|
+
function firstPositiveNumber(record, keys) {
|
|
621
|
+
for (const key of keys) {
|
|
622
|
+
const value = positiveNumber(record[key]);
|
|
623
|
+
if (value !== void 0) return value;
|
|
624
|
+
}
|
|
625
|
+
return void 0;
|
|
626
|
+
}
|
|
627
|
+
function capabilityListFlag(record, name) {
|
|
628
|
+
const list = record.capabilities;
|
|
629
|
+
if (!Array.isArray(list)) return void 0;
|
|
630
|
+
return list.some((entry) => entry === name) ? true : void 0;
|
|
631
|
+
}
|
|
632
|
+
function booleanFromAny(record, keys) {
|
|
633
|
+
for (const key of keys) {
|
|
634
|
+
const value = record[key];
|
|
635
|
+
if (typeof value === "boolean") return value;
|
|
636
|
+
}
|
|
637
|
+
return void 0;
|
|
638
|
+
}
|
|
639
|
+
function nestedRecord(record, key) {
|
|
640
|
+
const value = record[key];
|
|
641
|
+
return isRecord2(value) ? value : null;
|
|
642
|
+
}
|
|
643
|
+
function firstString(record, keys) {
|
|
644
|
+
if (!record) return void 0;
|
|
645
|
+
for (const key of keys) {
|
|
646
|
+
const value = record[key];
|
|
647
|
+
if (typeof value === "string" && value.trim().length > 0) return value.trim();
|
|
648
|
+
}
|
|
649
|
+
return void 0;
|
|
650
|
+
}
|
|
651
|
+
function firstBoolean(record, keys) {
|
|
652
|
+
if (!record) return void 0;
|
|
653
|
+
for (const key of keys) {
|
|
654
|
+
const value = record[key];
|
|
655
|
+
if (typeof value === "boolean") return value;
|
|
656
|
+
}
|
|
657
|
+
return void 0;
|
|
658
|
+
}
|
|
659
|
+
function normalizeModelState(raw) {
|
|
660
|
+
const value = raw?.trim().toLowerCase().replace(/[\s_]+/g, "-");
|
|
661
|
+
if (!value) return void 0;
|
|
662
|
+
if (value === "loaded" || value === "ready" || value === "running" || value === "active") return "loaded";
|
|
663
|
+
if (value === "loading" || value === "pending" || value === "queued" || value === "starting") return "loading";
|
|
664
|
+
if (value === "unloaded" || value === "not-loaded" || value === "idle" || value === "sleeping" || value === "stopped") {
|
|
665
|
+
return "unloaded";
|
|
666
|
+
}
|
|
667
|
+
if (value === "failed" || value === "error" || value === "errored") return "failed";
|
|
668
|
+
if (value === "unknown") return "unknown";
|
|
669
|
+
return void 0;
|
|
670
|
+
}
|
|
671
|
+
function modelStateFromOpenAIModelEntry(row) {
|
|
672
|
+
const status = nestedRecord(row, "status");
|
|
673
|
+
const failed = firstBoolean(status, ["failed"]) ?? firstBoolean(row, ["failed"]);
|
|
674
|
+
if (failed === true) {
|
|
675
|
+
const detail = firstString(status, ["error", "reason", "message"]) ?? firstString(row, ["error", "reason", "message"]);
|
|
676
|
+
return detail ? { state: "failed", detail } : { state: "failed" };
|
|
677
|
+
}
|
|
678
|
+
const raw = typeof row.status === "string" ? row.status : firstString(status, ["value", "state", "status"]) ?? firstString(row, ["state"]);
|
|
679
|
+
const normalized = normalizeModelState(raw);
|
|
680
|
+
if (normalized) {
|
|
681
|
+
const detail = firstString(status, ["detail", "message", "reason"]);
|
|
682
|
+
return detail ? { state: normalized, detail } : { state: normalized };
|
|
683
|
+
}
|
|
684
|
+
const loaded = firstBoolean(status, ["loaded"]) ?? firstBoolean(row, ["loaded"]);
|
|
685
|
+
if (loaded === true) return { state: "loaded" };
|
|
686
|
+
if (loaded === false) return { state: "unloaded" };
|
|
687
|
+
return void 0;
|
|
688
|
+
}
|
|
689
|
+
function loadedContextFromEntry(row) {
|
|
690
|
+
const reported = firstPositiveNumber(row, ["loaded_context_length", "loadedContextLength"]);
|
|
691
|
+
return reported === void 0 ? void 0 : Math.floor(reported);
|
|
692
|
+
}
|
|
693
|
+
function statusArgsFromEntry(row) {
|
|
694
|
+
const status = nestedRecord(row, "status");
|
|
695
|
+
return argsFromStatus(status);
|
|
696
|
+
}
|
|
697
|
+
function contextSlotsFromEntry(row) {
|
|
698
|
+
return llamaCppRequestContextWindow(parseLlamaCppServerFlags(statusArgsFromEntry(row)))?.slots;
|
|
699
|
+
}
|
|
700
|
+
function capabilitiesFromOpenAIModelEntry(row) {
|
|
701
|
+
const caps = {};
|
|
702
|
+
const meta = nestedRecord(row, "meta");
|
|
703
|
+
const flags = parseLlamaCppServerFlags(statusArgsFromEntry(row));
|
|
704
|
+
const contextWindow = llamaCppRequestContextWindow(flags)?.contextWindow ?? firstPositiveNumber(row, [
|
|
705
|
+
// What is actually loaded outranks what the model could support: a
|
|
706
|
+
// model served at 8k out of a possible 262k has an 8k window today,
|
|
707
|
+
// and the run has to be planned against the real one.
|
|
708
|
+
"loaded_context_length",
|
|
709
|
+
"loadedContextLength",
|
|
710
|
+
"context_window",
|
|
711
|
+
"contextWindow",
|
|
712
|
+
"context_length",
|
|
713
|
+
"contextLength",
|
|
714
|
+
"max_context_length",
|
|
715
|
+
"maxContextLength",
|
|
716
|
+
"n_ctx"
|
|
717
|
+
]) ?? (meta ? firstPositiveNumber(meta, ["n_ctx", "n_ctx_train", "context_length", "contextWindow"]) : void 0);
|
|
718
|
+
if (contextWindow !== void 0) caps.contextWindow = Math.floor(contextWindow);
|
|
719
|
+
const maxTokens = positiveNumber(flags.maxTokens) ?? firstPositiveNumber(row, [
|
|
720
|
+
"max_output_tokens",
|
|
721
|
+
"maxOutputTokens",
|
|
722
|
+
"max_completion_tokens",
|
|
723
|
+
"maxCompletionTokens",
|
|
724
|
+
"max_tokens",
|
|
725
|
+
"maxTokens",
|
|
726
|
+
"n_predict"
|
|
727
|
+
]);
|
|
728
|
+
if (maxTokens !== void 0) caps.maxTokens = Math.floor(maxTokens);
|
|
729
|
+
const tools = flags.jinja ?? booleanFromAny(row, ["tools", "tool_use", "toolUse", "trained_for_tool_use"]) ?? capabilityListFlag(row, "tool_use");
|
|
730
|
+
if (tools !== void 0) caps.tools = tools;
|
|
731
|
+
const reasoning = flags.reasoning ?? (flags.reasoningBudget !== void 0 ? true : void 0) ?? booleanFromAny(row, ["reasoning", "thinking"]);
|
|
732
|
+
if (reasoning !== void 0) caps.reasoning = reasoning;
|
|
733
|
+
const architecture = nestedRecord(row, "architecture");
|
|
734
|
+
const architectureInput = architecture?.input_modalities;
|
|
735
|
+
const modalities = Array.isArray(row.modalities) ? row.modalities : Array.isArray(row.input) ? row.input : Array.isArray(architectureInput) ? architectureInput : null;
|
|
736
|
+
if (modalities) {
|
|
737
|
+
caps.vision = modalities.some((entry) => entry === "image" || entry === "vision");
|
|
738
|
+
if (modalities.some((entry) => entry === "audio")) caps.audio = true;
|
|
739
|
+
}
|
|
740
|
+
return caps;
|
|
741
|
+
}
|
|
742
|
+
function modelEntries(payload) {
|
|
743
|
+
if (!Array.isArray(payload?.data)) return [];
|
|
744
|
+
const out = [];
|
|
745
|
+
for (const row of payload.data) {
|
|
746
|
+
if (typeof row?.id !== "string" || row.id.length === 0) continue;
|
|
747
|
+
out.push({ id: row.id, status: row.status });
|
|
748
|
+
}
|
|
749
|
+
return out;
|
|
750
|
+
}
|
|
751
|
+
async function probeOpenAIModelEntries(base, ctx) {
|
|
752
|
+
const opts = { url: `${base}/v1/models`, timeoutMs: ctx.httpTimeoutMs };
|
|
753
|
+
const result = await (ctx.signal ? probeJson({ ...opts, signal: ctx.signal }) : probeJson(opts));
|
|
754
|
+
if (!result.ok) return [];
|
|
755
|
+
return modelEntries(result.data);
|
|
756
|
+
}
|
|
757
|
+
function llamaCppRequestContextWindow(flags) {
|
|
758
|
+
const total = positiveNumber(flags.contextSize);
|
|
759
|
+
if (total === void 0) return void 0;
|
|
760
|
+
const parallel = positiveNumber(flags.parallel);
|
|
761
|
+
if (parallel === void 0 || parallel <= 1 || flags.kvUnified === true) return { contextWindow: Math.floor(total) };
|
|
762
|
+
const slots = Math.floor(parallel);
|
|
763
|
+
return {
|
|
764
|
+
contextWindow: Math.floor(total / slots),
|
|
765
|
+
slots: { totalContextSize: Math.floor(total), slots }
|
|
766
|
+
};
|
|
767
|
+
}
|
|
768
|
+
function argsFromStatus(status) {
|
|
769
|
+
if (!isRecord2(status)) return [];
|
|
770
|
+
const args = status.args;
|
|
771
|
+
if (Array.isArray(args)) return args.filter((entry) => typeof entry === "string");
|
|
772
|
+
if (typeof args === "string") return args.trim().split(/\s+/).filter(Boolean);
|
|
773
|
+
return [];
|
|
774
|
+
}
|
|
775
|
+
function looksLikeFlag(token) {
|
|
776
|
+
return token.startsWith("-") && Number.isNaN(Number(token));
|
|
777
|
+
}
|
|
778
|
+
function valueAfter(args, ...flags) {
|
|
779
|
+
for (const flag of flags) {
|
|
780
|
+
const index = args.indexOf(flag);
|
|
781
|
+
if (index < 0) continue;
|
|
782
|
+
const value = args[index + 1];
|
|
783
|
+
return value && !looksLikeFlag(value) ? value : void 0;
|
|
784
|
+
}
|
|
785
|
+
return void 0;
|
|
786
|
+
}
|
|
787
|
+
function numberFlag(args, ...flags) {
|
|
788
|
+
const value = valueAfter(args, ...flags);
|
|
789
|
+
if (value === void 0) return void 0;
|
|
790
|
+
const parsed = Number(value);
|
|
791
|
+
return Number.isFinite(parsed) ? parsed : void 0;
|
|
792
|
+
}
|
|
793
|
+
function booleanFlag(args, ...flags) {
|
|
794
|
+
const flag = flags.find((candidate) => args.includes(candidate));
|
|
795
|
+
if (flag === void 0) return void 0;
|
|
796
|
+
const value = valueAfter(args, flag);
|
|
797
|
+
if (value === void 0) return true;
|
|
798
|
+
const normalized = value.toLowerCase();
|
|
799
|
+
if (normalized === "true" || normalized === "on" || normalized === "1") return true;
|
|
800
|
+
if (normalized === "false" || normalized === "off" || normalized === "0") return false;
|
|
801
|
+
return void 0;
|
|
802
|
+
}
|
|
803
|
+
function parseLlamaCppServerFlags(args) {
|
|
804
|
+
const flags = {};
|
|
805
|
+
const ctxSize = numberFlag(args, "--ctx-size", "-c");
|
|
806
|
+
if (ctxSize !== void 0) flags.contextSize = ctxSize;
|
|
807
|
+
const maxTokens = numberFlag(args, "--n-predict");
|
|
808
|
+
if (maxTokens !== void 0) flags.maxTokens = maxTokens;
|
|
809
|
+
const flashAttention = booleanFlag(args, "--flash-attn");
|
|
810
|
+
if (flashAttention !== void 0) flags.flashAttention = flashAttention;
|
|
811
|
+
const jinja = booleanFlag(args, "--jinja");
|
|
812
|
+
if (jinja !== void 0) flags.jinja = jinja;
|
|
813
|
+
const reasoningRaw = valueAfter(args, "--reasoning");
|
|
814
|
+
if (reasoningRaw) flags.reasoning = reasoningRaw === "on" || reasoningRaw === "true" || reasoningRaw === "1";
|
|
815
|
+
const reasoningBudget = numberFlag(args, "--reasoning-budget");
|
|
816
|
+
if (reasoningBudget !== void 0) flags.reasoningBudget = reasoningBudget;
|
|
817
|
+
const temperature = numberFlag(args, "--temperature");
|
|
818
|
+
if (temperature !== void 0) flags.temperature = temperature;
|
|
819
|
+
const topP = numberFlag(args, "--top-p");
|
|
820
|
+
if (topP !== void 0) flags.topP = topP;
|
|
821
|
+
const topK = numberFlag(args, "--top-k");
|
|
822
|
+
if (topK !== void 0) flags.topK = topK;
|
|
823
|
+
const nGpuLayers = numberFlag(args, "--n-gpu-layers");
|
|
824
|
+
if (nGpuLayers !== void 0) flags.nGpuLayers = nGpuLayers;
|
|
825
|
+
const parallel = numberFlag(args, "--parallel", "-np");
|
|
826
|
+
if (parallel !== void 0) flags.parallel = parallel;
|
|
827
|
+
const kvUnifiedAt = Math.max(args.lastIndexOf("--kv-unified"), args.lastIndexOf("-kvu"));
|
|
828
|
+
const noKvUnifiedAt = args.lastIndexOf("--no-kv-unified");
|
|
829
|
+
if (noKvUnifiedAt > kvUnifiedAt) flags.kvUnified = false;
|
|
830
|
+
else if (kvUnifiedAt >= 0) flags.kvUnified = booleanFlag(args, "--kv-unified", "-kvu") ?? true;
|
|
831
|
+
const cacheTypeK = valueAfter(args, "--cache-type-k");
|
|
832
|
+
if (cacheTypeK) flags.cacheTypeK = cacheTypeK;
|
|
833
|
+
const cacheTypeV = valueAfter(args, "--cache-type-v");
|
|
834
|
+
if (cacheTypeV) flags.cacheTypeV = cacheTypeV;
|
|
835
|
+
const mmproj = valueAfter(args, "--mmproj");
|
|
836
|
+
if (mmproj) flags.mmproj = mmproj;
|
|
837
|
+
const chatTemplateKwargs = valueAfter(args, "--chat-template-kwargs");
|
|
838
|
+
if (chatTemplateKwargs) flags.chatTemplateKwargs = chatTemplateKwargs;
|
|
839
|
+
return flags;
|
|
840
|
+
}
|
|
841
|
+
function selectedModelEntry(entries, target) {
|
|
842
|
+
const expected = target.defaultModel?.trim();
|
|
843
|
+
if (expected) return entries.find((entry) => entry.id === expected) ?? null;
|
|
844
|
+
return entries[0] ?? null;
|
|
845
|
+
}
|
|
846
|
+
function statusNotes(id, status) {
|
|
847
|
+
if (!isRecord2(status)) return [];
|
|
848
|
+
const notes = [];
|
|
849
|
+
if (status.failed === true) notes.push(`llama.cpp router marks ${id} as failed`);
|
|
850
|
+
const state = typeof status.state === "string" ? status.state : void 0;
|
|
851
|
+
if (state === "loading") notes.push(`llama.cpp router reports ${id} is still loading`);
|
|
852
|
+
return notes;
|
|
853
|
+
}
|
|
854
|
+
async function probeLlamaCppModelStatus(base, target, ctx) {
|
|
855
|
+
const entries = await probeOpenAIModelEntries(base, ctx);
|
|
856
|
+
const selected = selectedModelEntry(entries, target);
|
|
857
|
+
if (!selected) return {};
|
|
858
|
+
const args = argsFromStatus(selected.status);
|
|
859
|
+
if (args.length === 0) return { notes: statusNotes(selected.id, selected.status) };
|
|
860
|
+
const flags = parseLlamaCppServerFlags(args);
|
|
861
|
+
const caps = {};
|
|
862
|
+
const window = llamaCppRequestContextWindow(flags);
|
|
863
|
+
if (window !== void 0) caps.contextWindow = window.contextWindow;
|
|
864
|
+
if (flags.maxTokens !== void 0 && flags.maxTokens > 0) caps.maxTokens = flags.maxTokens;
|
|
865
|
+
if (flags.reasoning === true || flags.reasoningBudget !== void 0) caps.reasoning = true;
|
|
866
|
+
if (flags.mmproj) caps.vision = true;
|
|
867
|
+
if (flags.jinja === true) caps.tools = true;
|
|
868
|
+
if (flags.parallel !== void 0 && Number.isInteger(flags.parallel) && flags.parallel > 0) {
|
|
869
|
+
caps.parallelSlots = flags.parallel;
|
|
870
|
+
}
|
|
871
|
+
const enrichment = { modelId: selected.id, serverFlags: flags };
|
|
872
|
+
if (Object.keys(caps).length > 0) enrichment.discoveredCapabilities = caps;
|
|
873
|
+
const notes = statusNotes(selected.id, selected.status);
|
|
874
|
+
if (window?.slots) {
|
|
875
|
+
notes.push(
|
|
876
|
+
`${selected.id} context window ${formatContextWindowSlots(window.contextWindow, window.slots)}: --ctx-size is split across --parallel slots without --kv-unified`
|
|
877
|
+
);
|
|
878
|
+
}
|
|
879
|
+
if (notes.length > 0) enrichment.notes = notes;
|
|
880
|
+
return enrichment;
|
|
881
|
+
}
|
|
882
|
+
async function detectModelMismatch(base, target, ctx) {
|
|
883
|
+
const expected = target.defaultModel?.trim();
|
|
884
|
+
if (!expected) return null;
|
|
885
|
+
const ids = await probeOpenAIModels(base, ctx);
|
|
886
|
+
if (ids.length === 0) return null;
|
|
887
|
+
if (ids.includes(expected)) return null;
|
|
888
|
+
const loaded = ids[0] ?? "(unknown)";
|
|
889
|
+
return `wire model id ${expected} does not match server's loaded model ${loaded}; llama.cpp serves a single fixed model`;
|
|
890
|
+
}
|
|
891
|
+
async function probeLlamaCppProps(base, ctx, modelId) {
|
|
892
|
+
const request = async (url2) => {
|
|
893
|
+
const opts = { url: url2, timeoutMs: ctx.httpTimeoutMs };
|
|
894
|
+
const result = await (ctx.signal ? probeJson({ ...opts, signal: ctx.signal }) : probeJson(opts));
|
|
895
|
+
return result.ok && result.data ? result.data : null;
|
|
896
|
+
};
|
|
897
|
+
const router = await request(`${base}/props`);
|
|
898
|
+
if (router === null) return {};
|
|
899
|
+
const selected = typeof router.total_slots === "number" || !modelId ? null : await request(`${base}/props?model=${encodeURIComponent(modelId)}`);
|
|
900
|
+
const data = selected ?? router;
|
|
901
|
+
const enrichment = {};
|
|
902
|
+
const caps = {};
|
|
903
|
+
const nCtx = data.default_generation_settings?.n_ctx;
|
|
904
|
+
if (typeof nCtx === "number" && nCtx > 0) caps.contextWindow = nCtx;
|
|
905
|
+
const nPredict = data.default_generation_settings?.n_predict;
|
|
906
|
+
if (typeof nPredict === "number" && nPredict > 0) caps.maxTokens = nPredict;
|
|
907
|
+
const vision = data.modalities?.vision;
|
|
908
|
+
if (typeof vision === "boolean") caps.vision = vision;
|
|
909
|
+
const totalSlots = data.total_slots;
|
|
910
|
+
if (typeof totalSlots === "number" && Number.isInteger(totalSlots) && totalSlots > 0) caps.parallelSlots = totalSlots;
|
|
911
|
+
if (Object.keys(caps).length > 0) enrichment.discoveredCapabilities = caps;
|
|
912
|
+
const buildInfo = data.build_info ?? router.build_info;
|
|
913
|
+
if (typeof buildInfo === "string" && buildInfo.length > 0) {
|
|
914
|
+
enrichment.serverVersion = buildInfo;
|
|
915
|
+
}
|
|
916
|
+
return enrichment;
|
|
917
|
+
}
|
|
918
|
+
|
|
919
|
+
// src/domains/providers/runtimes/protocol/openai-compat.ts
|
|
920
|
+
function synthesizeOpenAICompatModel(input) {
|
|
921
|
+
return synthLocalModel({
|
|
922
|
+
target: input.target,
|
|
923
|
+
wireModelId: input.wireModelId,
|
|
924
|
+
kb: input.kb,
|
|
925
|
+
defaultCapabilities: input.defaultCapabilities,
|
|
926
|
+
apiFamily: input.apiFamily ?? "openai-completions",
|
|
927
|
+
provider: input.provider,
|
|
928
|
+
baseUrlForTarget: input.baseUrlForTarget ?? withV1
|
|
929
|
+
});
|
|
930
|
+
}
|
|
931
|
+
function makeOpenAICompatRuntime(spec) {
|
|
932
|
+
const apiFamily = spec.apiFamily ?? "openai-completions";
|
|
933
|
+
const asIs = spec.baseUrlStyle === "asIs";
|
|
934
|
+
const baseUrlForTarget = asIs ? withAsIs : withV1;
|
|
935
|
+
const healthPath = spec.healthPath ?? "/v1/models";
|
|
936
|
+
const modelsPath = spec.modelsPath ?? "/v1/models";
|
|
937
|
+
const probeBase = asIs ? targetBaseUrl : targetRootUrl;
|
|
938
|
+
return {
|
|
939
|
+
id: spec.id,
|
|
940
|
+
displayName: spec.displayName,
|
|
941
|
+
kind: "http",
|
|
942
|
+
tier: spec.tier,
|
|
943
|
+
apiFamily,
|
|
944
|
+
auth: spec.auth,
|
|
945
|
+
defaultCapabilities: spec.defaultCapabilities,
|
|
946
|
+
async probe(target, ctx) {
|
|
947
|
+
const base = probeBase(target);
|
|
948
|
+
if (!base) return { ok: false, error: "target has no url" };
|
|
949
|
+
const health = await probeUrl(`${base}${healthPath}`, ctx);
|
|
950
|
+
if (!health.ok) return health;
|
|
951
|
+
const catalog = await probeOpenAIModelCatalog(base, ctx, modelsPath);
|
|
952
|
+
const result = { ...health };
|
|
953
|
+
if (catalog.models.length > 0) result.models = catalog.models;
|
|
954
|
+
if (Object.keys(catalog.modelStates).length > 0) result.modelStates = catalog.modelStates;
|
|
955
|
+
if (Object.keys(catalog.modelCapabilities).length > 0) {
|
|
956
|
+
result.modelCapabilities = catalog.modelCapabilities;
|
|
957
|
+
const selected = target.defaultModel?.trim();
|
|
958
|
+
const selectedCaps = selected ? catalog.modelCapabilities[selected] : void 0;
|
|
959
|
+
if (selected && selectedCaps) {
|
|
960
|
+
result.discoveredCapabilities = selectedCaps;
|
|
961
|
+
result.capabilityModelId = selected;
|
|
962
|
+
}
|
|
963
|
+
}
|
|
964
|
+
return result;
|
|
965
|
+
},
|
|
966
|
+
async probeModels(target, ctx) {
|
|
967
|
+
const base = probeBase(target);
|
|
968
|
+
if (!base) return [];
|
|
969
|
+
return probeOpenAIModels(base, ctx, modelsPath);
|
|
970
|
+
},
|
|
971
|
+
async probeReasoning(target, modelId, ctx) {
|
|
972
|
+
const base = probeBase(target);
|
|
973
|
+
if (!base) return { reasoning: false, latencyMs: 0, error: "target has no url" };
|
|
974
|
+
const apiKeyEnv = target.auth?.apiKeyEnvVar;
|
|
975
|
+
const apiKey = apiKeyEnv && ctx.credentialsPresent.has(apiKeyEnv) ? process.env[apiKeyEnv] : void 0;
|
|
976
|
+
const probeOpts = {
|
|
977
|
+
baseUrl: base,
|
|
978
|
+
modelId,
|
|
979
|
+
timeoutMs: Math.max(ctx.httpTimeoutMs, 8e3)
|
|
980
|
+
};
|
|
981
|
+
if (apiKey) probeOpts.apiKey = apiKey;
|
|
982
|
+
if (ctx.signal) probeOpts.signal = ctx.signal;
|
|
983
|
+
return probeOpenAICompatReasoning(probeOpts);
|
|
984
|
+
},
|
|
985
|
+
synthesizeModel(target, wireModelId, kb) {
|
|
986
|
+
return synthesizeOpenAICompatModel({
|
|
987
|
+
target,
|
|
988
|
+
wireModelId,
|
|
989
|
+
kb,
|
|
990
|
+
defaultCapabilities: spec.defaultCapabilities,
|
|
991
|
+
apiFamily,
|
|
992
|
+
provider: spec.provider,
|
|
993
|
+
baseUrlForTarget
|
|
994
|
+
});
|
|
995
|
+
}
|
|
996
|
+
};
|
|
997
|
+
}
|
|
998
|
+
var defaultCapabilities = {
|
|
999
|
+
chat: true,
|
|
1000
|
+
tools: false,
|
|
1001
|
+
reasoning: false,
|
|
1002
|
+
vision: false,
|
|
1003
|
+
audio: false,
|
|
1004
|
+
embeddings: false,
|
|
1005
|
+
rerank: false,
|
|
1006
|
+
fim: false,
|
|
1007
|
+
contextWindow: CLIO_MIN_CONTEXT_WINDOW,
|
|
1008
|
+
maxTokens: CLIO_MIN_MAX_OUTPUT_TOKENS
|
|
1009
|
+
};
|
|
1010
|
+
var openai_compat_default = makeOpenAICompatRuntime({
|
|
1011
|
+
id: "openai-compat",
|
|
1012
|
+
displayName: "Generic OpenAI-compatible",
|
|
1013
|
+
provider: "openai-compat",
|
|
1014
|
+
auth: "api-key",
|
|
1015
|
+
tier: "protocol",
|
|
1016
|
+
defaultCapabilities
|
|
1017
|
+
});
|
|
1018
|
+
|
|
1019
|
+
// src/domains/providers/runtimes/cloud/alcf.ts
|
|
1020
|
+
var CATALOG_URL = "https://inference-api.alcf.anl.gov/resource_server/list-endpoints";
|
|
1021
|
+
var GATEWAY_ORIGIN = "https://inference-api.alcf.anl.gov/resource_server";
|
|
1022
|
+
var defaultCapabilities2 = {
|
|
1023
|
+
chat: true,
|
|
1024
|
+
tools: true,
|
|
1025
|
+
toolCallFormat: "openai",
|
|
1026
|
+
reasoning: true,
|
|
1027
|
+
vision: false,
|
|
1028
|
+
audio: false,
|
|
1029
|
+
embeddings: false,
|
|
1030
|
+
rerank: false,
|
|
1031
|
+
fim: false,
|
|
1032
|
+
contextWindow: 32768,
|
|
1033
|
+
maxTokens: 4096
|
|
1034
|
+
};
|
|
1035
|
+
var KNOWN_MODELS = [
|
|
1036
|
+
"openai/gpt-oss-120b",
|
|
1037
|
+
"openai/gpt-oss-20b",
|
|
1038
|
+
"gpt-oss-120b",
|
|
1039
|
+
"meta-llama/Llama-4-Maverick-17B-128E-Instruct-FP8",
|
|
1040
|
+
"meta-llama/Llama-4-Scout-17B-16E-Instruct"
|
|
1041
|
+
];
|
|
1042
|
+
function clusterFromUrl(url2) {
|
|
1043
|
+
if (!url2) return null;
|
|
1044
|
+
const match = /\/resource_server\/([^/]+)\//.exec(url2);
|
|
1045
|
+
return match ? match[1] ?? null : null;
|
|
1046
|
+
}
|
|
1047
|
+
function frameworkForCluster(cluster) {
|
|
1048
|
+
return cluster === "metis" ? "api" : "vllm";
|
|
1049
|
+
}
|
|
1050
|
+
function catalogModels(payload, cluster, framework) {
|
|
1051
|
+
const models = payload.clusters?.[cluster]?.frameworks?.[framework]?.models;
|
|
1052
|
+
if (!Array.isArray(models)) return [];
|
|
1053
|
+
return models.map((model) => String(model).trim()).filter((model) => model.length > 0);
|
|
1054
|
+
}
|
|
1055
|
+
function runningModels(payload) {
|
|
1056
|
+
const out = [];
|
|
1057
|
+
for (const job of payload.running ?? []) {
|
|
1058
|
+
for (const raw of String(job.Models ?? "").split(",")) {
|
|
1059
|
+
const id = raw.trim();
|
|
1060
|
+
if (id.length > 0) out.push(id);
|
|
1061
|
+
}
|
|
1062
|
+
}
|
|
1063
|
+
return out;
|
|
1064
|
+
}
|
|
1065
|
+
function dedupe(ids) {
|
|
1066
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1067
|
+
const out = [];
|
|
1068
|
+
for (const id of ids) {
|
|
1069
|
+
if (seen.has(id)) continue;
|
|
1070
|
+
seen.add(id);
|
|
1071
|
+
out.push(id);
|
|
1072
|
+
}
|
|
1073
|
+
return out;
|
|
1074
|
+
}
|
|
1075
|
+
function authHeaders(ctx) {
|
|
1076
|
+
return { Authorization: `Bearer ${ctx.authToken}`, Accept: "application/json" };
|
|
1077
|
+
}
|
|
1078
|
+
async function discover(target, ctx) {
|
|
1079
|
+
if (!target.url) return { ok: false, error: "ALCF target has no url" };
|
|
1080
|
+
const cluster = clusterFromUrl(target.url);
|
|
1081
|
+
if (!cluster) {
|
|
1082
|
+
return { ok: false, error: `cannot determine ALCF cluster from url ${target.url}` };
|
|
1083
|
+
}
|
|
1084
|
+
if (!ctx.authToken) {
|
|
1085
|
+
return { ok: false, error: "ALCF requires Globus auth; run `clio-coder auth login alcf`." };
|
|
1086
|
+
}
|
|
1087
|
+
const framework = frameworkForCluster(cluster);
|
|
1088
|
+
const headers = authHeaders(ctx);
|
|
1089
|
+
const catalog = await probeJson({
|
|
1090
|
+
url: CATALOG_URL,
|
|
1091
|
+
headers,
|
|
1092
|
+
timeoutMs: ctx.httpTimeoutMs,
|
|
1093
|
+
...ctx.signal ? { signal: ctx.signal } : {}
|
|
1094
|
+
});
|
|
1095
|
+
if (!catalog.ok || !catalog.data) {
|
|
1096
|
+
const reason = catalog.error ?? "unknown error";
|
|
1097
|
+
const hint = reason.includes("401") ? " (token expired or rejected; run `clio-coder auth login alcf` again)" : "";
|
|
1098
|
+
return {
|
|
1099
|
+
ok: false,
|
|
1100
|
+
error: `ALCF endpoint catalog unreachable: ${reason}${hint}`,
|
|
1101
|
+
...catalog.latencyMs !== void 0 ? { latencyMs: catalog.latencyMs } : {}
|
|
1102
|
+
};
|
|
1103
|
+
}
|
|
1104
|
+
const fromCatalog = catalogModels(catalog.data, cluster, framework);
|
|
1105
|
+
let live = [];
|
|
1106
|
+
try {
|
|
1107
|
+
const jobs = await probeJson({
|
|
1108
|
+
url: `${GATEWAY_ORIGIN}/${cluster}/jobs`,
|
|
1109
|
+
headers,
|
|
1110
|
+
timeoutMs: Math.min(ctx.httpTimeoutMs, 12e3),
|
|
1111
|
+
...ctx.signal ? { signal: ctx.signal } : {}
|
|
1112
|
+
});
|
|
1113
|
+
if (jobs.ok && jobs.data) live = runningModels(jobs.data);
|
|
1114
|
+
} catch {
|
|
1115
|
+
}
|
|
1116
|
+
const models = dedupe([...fromCatalog, ...live]);
|
|
1117
|
+
const result = { ok: true, models };
|
|
1118
|
+
if (catalog.latencyMs !== void 0) result.latencyMs = catalog.latencyMs;
|
|
1119
|
+
if (models.length === 0) {
|
|
1120
|
+
result.notes = [`ALCF ${cluster}/${framework} reported no models; the gateway may have no running jobs.`];
|
|
1121
|
+
}
|
|
1122
|
+
return result;
|
|
1123
|
+
}
|
|
1124
|
+
var alcfRuntime = {
|
|
1125
|
+
id: "alcf",
|
|
1126
|
+
displayName: "ALCF Inference (Globus)",
|
|
1127
|
+
kind: "http",
|
|
1128
|
+
tier: "cloud",
|
|
1129
|
+
apiFamily: "openai-completions",
|
|
1130
|
+
auth: "oauth",
|
|
1131
|
+
knownModels: KNOWN_MODELS,
|
|
1132
|
+
defaultCapabilities: defaultCapabilities2,
|
|
1133
|
+
probe(target, ctx) {
|
|
1134
|
+
return discover(target, ctx);
|
|
1135
|
+
},
|
|
1136
|
+
async probeModels(target, ctx) {
|
|
1137
|
+
const result = await discover(target, ctx);
|
|
1138
|
+
return result.models ?? [];
|
|
1139
|
+
},
|
|
1140
|
+
synthesizeModel(target, wireModelId, kb) {
|
|
1141
|
+
const model = synthesizeOpenAICompatModel({
|
|
1142
|
+
target,
|
|
1143
|
+
wireModelId,
|
|
1144
|
+
kb,
|
|
1145
|
+
defaultCapabilities: defaultCapabilities2,
|
|
1146
|
+
apiFamily: "openai-completions",
|
|
1147
|
+
provider: "alcf",
|
|
1148
|
+
baseUrlForTarget: withAsIs
|
|
1149
|
+
});
|
|
1150
|
+
const meta = model.clio;
|
|
1151
|
+
if (meta) meta.chatTemplateKwargsUnsupported = true;
|
|
1152
|
+
return model;
|
|
1153
|
+
}
|
|
1154
|
+
};
|
|
1155
|
+
var alcf_default = alcfRuntime;
|
|
1156
|
+
|
|
1157
|
+
// src/domains/providers/runtimes/cloud/anthropic.ts
|
|
1158
|
+
init_esm_shims();
|
|
1159
|
+
|
|
1160
|
+
// src/domains/providers/runtimes/protocol/anthropic-messages.ts
|
|
1161
|
+
init_esm_shims();
|
|
1162
|
+
function synthesizeAnthropicMessagesModel(input) {
|
|
1163
|
+
return synthesizeCatalogBackedModel({
|
|
1164
|
+
target: input.target,
|
|
1165
|
+
wireModelId: input.wireModelId,
|
|
1166
|
+
kb: input.kb,
|
|
1167
|
+
defaultCapabilities: input.defaultCapabilities,
|
|
1168
|
+
runtimeId: "anthropic",
|
|
1169
|
+
api: "anthropic-messages",
|
|
1170
|
+
provider: input.provider,
|
|
1171
|
+
defaultBaseUrl: input.defaultBaseUrl
|
|
1172
|
+
});
|
|
1173
|
+
}
|
|
1174
|
+
|
|
1175
|
+
// src/domains/providers/runtimes/cloud/anthropic.ts
|
|
1176
|
+
var defaultCapabilities3 = {
|
|
1177
|
+
chat: true,
|
|
1178
|
+
tools: true,
|
|
1179
|
+
toolCallFormat: "anthropic",
|
|
1180
|
+
reasoning: true,
|
|
1181
|
+
thinkingFormat: "anthropic-extended",
|
|
1182
|
+
vision: true,
|
|
1183
|
+
audio: false,
|
|
1184
|
+
embeddings: false,
|
|
1185
|
+
rerank: false,
|
|
1186
|
+
fim: false,
|
|
1187
|
+
contextWindow: 2e5,
|
|
1188
|
+
maxTokens: 8192
|
|
1189
|
+
};
|
|
1190
|
+
var anthropicRuntime = {
|
|
1191
|
+
id: "anthropic",
|
|
1192
|
+
displayName: "Anthropic",
|
|
1193
|
+
kind: "http",
|
|
1194
|
+
tier: "cloud",
|
|
1195
|
+
apiFamily: "anthropic-messages",
|
|
1196
|
+
auth: "api-key",
|
|
1197
|
+
credentialsEnvVar: "ANTHROPIC_API_KEY",
|
|
1198
|
+
defaultCapabilities: defaultCapabilities3,
|
|
1199
|
+
synthesizeModel(target, wireModelId, kb) {
|
|
1200
|
+
return synthesizeAnthropicMessagesModel({
|
|
1201
|
+
target,
|
|
1202
|
+
wireModelId,
|
|
1203
|
+
kb,
|
|
1204
|
+
defaultCapabilities: defaultCapabilities3,
|
|
1205
|
+
provider: "anthropic",
|
|
1206
|
+
defaultBaseUrl: "https://api.anthropic.com"
|
|
1207
|
+
});
|
|
1208
|
+
}
|
|
1209
|
+
};
|
|
1210
|
+
var anthropic_default = anthropicRuntime;
|
|
1211
|
+
|
|
1212
|
+
// src/domains/providers/runtimes/cloud/anthropic-max.ts
|
|
1213
|
+
init_esm_shims();
|
|
1214
|
+
var defaultCapabilities4 = {
|
|
1215
|
+
chat: true,
|
|
1216
|
+
tools: true,
|
|
1217
|
+
toolCallFormat: "anthropic",
|
|
1218
|
+
reasoning: true,
|
|
1219
|
+
thinkingFormat: "anthropic-extended",
|
|
1220
|
+
vision: true,
|
|
1221
|
+
audio: false,
|
|
1222
|
+
embeddings: false,
|
|
1223
|
+
rerank: false,
|
|
1224
|
+
fim: false,
|
|
1225
|
+
contextWindow: 2e5,
|
|
1226
|
+
maxTokens: 8192
|
|
1227
|
+
};
|
|
1228
|
+
var anthropicMaxRuntime = {
|
|
1229
|
+
id: "anthropic-max",
|
|
1230
|
+
displayName: "Anthropic (Claude Pro/Max)",
|
|
1231
|
+
kind: "http",
|
|
1232
|
+
tier: "cloud",
|
|
1233
|
+
apiFamily: "anthropic-messages",
|
|
1234
|
+
auth: "oauth",
|
|
1235
|
+
oauthProviderId: "anthropic",
|
|
1236
|
+
authNotice: "Connects with your Claude Pro/Max subscription via OAuth (the same path Claude Code uses). Using subscription credentials outside Anthropic's first-party apps may not align with their terms of service; enable at your own discretion.",
|
|
1237
|
+
defaultCapabilities: defaultCapabilities4,
|
|
1238
|
+
async probeModels(_target, _ctx) {
|
|
1239
|
+
return listCatalogModelsForRuntime("anthropic-max").map((model) => model.id);
|
|
1240
|
+
},
|
|
1241
|
+
synthesizeModel(target, wireModelId, kb) {
|
|
1242
|
+
return synthesizeCatalogBackedModel({
|
|
1243
|
+
target,
|
|
1244
|
+
wireModelId,
|
|
1245
|
+
kb,
|
|
1246
|
+
defaultCapabilities: defaultCapabilities4,
|
|
1247
|
+
runtimeId: "anthropic-max",
|
|
1248
|
+
api: "anthropic-messages",
|
|
1249
|
+
provider: "anthropic",
|
|
1250
|
+
defaultBaseUrl: "https://api.anthropic.com"
|
|
1251
|
+
});
|
|
1252
|
+
}
|
|
1253
|
+
};
|
|
1254
|
+
var anthropic_max_default = anthropicMaxRuntime;
|
|
1255
|
+
|
|
1256
|
+
// src/domains/providers/runtimes/cloud/bedrock.ts
|
|
1257
|
+
init_esm_shims();
|
|
1258
|
+
|
|
1259
|
+
// src/domains/providers/runtimes/protocol/bedrock.ts
|
|
1260
|
+
init_esm_shims();
|
|
1261
|
+
function synthesizeBedrockModel(input) {
|
|
1262
|
+
return synthesizeCatalogBackedModel({
|
|
1263
|
+
target: input.target,
|
|
1264
|
+
wireModelId: input.wireModelId,
|
|
1265
|
+
kb: input.kb,
|
|
1266
|
+
defaultCapabilities: input.defaultCapabilities,
|
|
1267
|
+
runtimeId: "bedrock",
|
|
1268
|
+
api: "bedrock-converse-stream",
|
|
1269
|
+
provider: "amazon-bedrock",
|
|
1270
|
+
defaultBaseUrl: ""
|
|
1271
|
+
});
|
|
1272
|
+
}
|
|
1273
|
+
|
|
1274
|
+
// src/domains/providers/runtimes/cloud/bedrock.ts
|
|
1275
|
+
var defaultCapabilities5 = {
|
|
1276
|
+
chat: true,
|
|
1277
|
+
tools: true,
|
|
1278
|
+
toolCallFormat: "anthropic",
|
|
1279
|
+
reasoning: true,
|
|
1280
|
+
thinkingFormat: "anthropic-extended",
|
|
1281
|
+
vision: false,
|
|
1282
|
+
audio: false,
|
|
1283
|
+
embeddings: false,
|
|
1284
|
+
rerank: false,
|
|
1285
|
+
fim: false,
|
|
1286
|
+
contextWindow: 2e5,
|
|
1287
|
+
maxTokens: 8192
|
|
1288
|
+
};
|
|
1289
|
+
var bedrockRuntime = {
|
|
1290
|
+
id: "bedrock",
|
|
1291
|
+
displayName: "Amazon Bedrock",
|
|
1292
|
+
kind: "http",
|
|
1293
|
+
tier: "cloud",
|
|
1294
|
+
apiFamily: "bedrock-converse-stream",
|
|
1295
|
+
auth: "aws-sdk",
|
|
1296
|
+
defaultCapabilities: defaultCapabilities5,
|
|
1297
|
+
synthesizeModel(target, wireModelId, kb) {
|
|
1298
|
+
return synthesizeBedrockModel({ target, wireModelId, kb, defaultCapabilities: defaultCapabilities5 });
|
|
1299
|
+
}
|
|
1300
|
+
};
|
|
1301
|
+
var bedrock_default = bedrockRuntime;
|
|
1302
|
+
|
|
1303
|
+
// src/domains/providers/runtimes/cloud/deepseek.ts
|
|
1304
|
+
init_esm_shims();
|
|
1305
|
+
var defaultCapabilities6 = {
|
|
1306
|
+
chat: true,
|
|
1307
|
+
tools: true,
|
|
1308
|
+
toolCallFormat: "openai",
|
|
1309
|
+
reasoning: true,
|
|
1310
|
+
thinkingFormat: "deepseek-r1",
|
|
1311
|
+
vision: false,
|
|
1312
|
+
audio: false,
|
|
1313
|
+
embeddings: false,
|
|
1314
|
+
rerank: false,
|
|
1315
|
+
fim: false,
|
|
1316
|
+
contextWindow: 128e3,
|
|
1317
|
+
maxTokens: 65536
|
|
1318
|
+
};
|
|
1319
|
+
var deepseekRuntime = {
|
|
1320
|
+
id: "deepseek",
|
|
1321
|
+
displayName: "DeepSeek",
|
|
1322
|
+
kind: "http",
|
|
1323
|
+
tier: "cloud",
|
|
1324
|
+
apiFamily: "openai-completions",
|
|
1325
|
+
auth: "api-key",
|
|
1326
|
+
credentialsEnvVar: "DEEPSEEK_API_KEY",
|
|
1327
|
+
defaultCapabilities: defaultCapabilities6,
|
|
1328
|
+
async probeModels(_target, _ctx) {
|
|
1329
|
+
return listCatalogModelsForRuntime("deepseek").map((model) => model.id);
|
|
1330
|
+
},
|
|
1331
|
+
synthesizeModel(target, wireModelId, kb) {
|
|
1332
|
+
return synthesizeCatalogBackedModel({
|
|
1333
|
+
target,
|
|
1334
|
+
wireModelId,
|
|
1335
|
+
kb,
|
|
1336
|
+
defaultCapabilities: defaultCapabilities6,
|
|
1337
|
+
runtimeId: "deepseek",
|
|
1338
|
+
api: "openai-completions",
|
|
1339
|
+
provider: "deepseek",
|
|
1340
|
+
defaultBaseUrl: "https://api.deepseek.com"
|
|
1341
|
+
});
|
|
1342
|
+
}
|
|
1343
|
+
};
|
|
1344
|
+
var deepseek_default = deepseekRuntime;
|
|
1345
|
+
|
|
1346
|
+
// src/domains/providers/runtimes/cloud/google.ts
|
|
1347
|
+
init_esm_shims();
|
|
1348
|
+
|
|
1349
|
+
// src/domains/providers/runtimes/protocol/google.ts
|
|
1350
|
+
init_esm_shims();
|
|
1351
|
+
function synthesizeGoogleModel(input) {
|
|
1352
|
+
return synthesizeCatalogBackedModel({
|
|
1353
|
+
target: input.target,
|
|
1354
|
+
wireModelId: input.wireModelId,
|
|
1355
|
+
kb: input.kb,
|
|
1356
|
+
defaultCapabilities: input.defaultCapabilities,
|
|
1357
|
+
runtimeId: "google",
|
|
1358
|
+
api: "google-generative-ai",
|
|
1359
|
+
provider: "google",
|
|
1360
|
+
defaultBaseUrl: input.defaultBaseUrl
|
|
1361
|
+
});
|
|
1362
|
+
}
|
|
1363
|
+
|
|
1364
|
+
// src/domains/providers/runtimes/cloud/google.ts
|
|
1365
|
+
var defaultCapabilities7 = {
|
|
1366
|
+
chat: true,
|
|
1367
|
+
tools: true,
|
|
1368
|
+
toolCallFormat: "openai",
|
|
1369
|
+
reasoning: true,
|
|
1370
|
+
vision: true,
|
|
1371
|
+
audio: false,
|
|
1372
|
+
embeddings: false,
|
|
1373
|
+
rerank: false,
|
|
1374
|
+
fim: false,
|
|
1375
|
+
contextWindow: 2e6,
|
|
1376
|
+
maxTokens: 8192
|
|
1377
|
+
};
|
|
1378
|
+
var googleRuntime = {
|
|
1379
|
+
id: "google",
|
|
1380
|
+
displayName: "Google Generative AI",
|
|
1381
|
+
kind: "http",
|
|
1382
|
+
tier: "cloud",
|
|
1383
|
+
apiFamily: "google-generative-ai",
|
|
1384
|
+
auth: "api-key",
|
|
1385
|
+
credentialsEnvVar: "GOOGLE_API_KEY",
|
|
1386
|
+
defaultCapabilities: defaultCapabilities7,
|
|
1387
|
+
synthesizeModel(target, wireModelId, kb) {
|
|
1388
|
+
return synthesizeGoogleModel({
|
|
1389
|
+
target,
|
|
1390
|
+
wireModelId,
|
|
1391
|
+
kb,
|
|
1392
|
+
defaultCapabilities: defaultCapabilities7,
|
|
1393
|
+
defaultBaseUrl: "https://generativelanguage.googleapis.com/v1beta"
|
|
1394
|
+
});
|
|
1395
|
+
}
|
|
1396
|
+
};
|
|
1397
|
+
var google_default = googleRuntime;
|
|
1398
|
+
|
|
1399
|
+
// src/domains/providers/runtimes/cloud/groq.ts
|
|
1400
|
+
init_esm_shims();
|
|
1401
|
+
var defaultCapabilities8 = {
|
|
1402
|
+
chat: true,
|
|
1403
|
+
tools: true,
|
|
1404
|
+
toolCallFormat: "openai",
|
|
1405
|
+
reasoning: false,
|
|
1406
|
+
vision: false,
|
|
1407
|
+
audio: false,
|
|
1408
|
+
embeddings: false,
|
|
1409
|
+
rerank: false,
|
|
1410
|
+
fim: false,
|
|
1411
|
+
contextWindow: 128e3,
|
|
1412
|
+
maxTokens: 8192
|
|
1413
|
+
};
|
|
1414
|
+
var groqRuntime = {
|
|
1415
|
+
id: "groq",
|
|
1416
|
+
displayName: "Groq",
|
|
1417
|
+
kind: "http",
|
|
1418
|
+
tier: "cloud",
|
|
1419
|
+
apiFamily: "openai-completions",
|
|
1420
|
+
auth: "api-key",
|
|
1421
|
+
credentialsEnvVar: "GROQ_API_KEY",
|
|
1422
|
+
defaultCapabilities: defaultCapabilities8,
|
|
1423
|
+
synthesizeModel(target, wireModelId, kb) {
|
|
1424
|
+
return synthesizeCatalogBackedModel({
|
|
1425
|
+
target,
|
|
1426
|
+
wireModelId,
|
|
1427
|
+
kb,
|
|
1428
|
+
defaultCapabilities: defaultCapabilities8,
|
|
1429
|
+
runtimeId: "groq",
|
|
1430
|
+
api: "openai-completions",
|
|
1431
|
+
provider: "groq",
|
|
1432
|
+
defaultBaseUrl: "https://api.groq.com/openai/v1"
|
|
1433
|
+
});
|
|
1434
|
+
}
|
|
1435
|
+
};
|
|
1436
|
+
var groq_default = groqRuntime;
|
|
1437
|
+
|
|
1438
|
+
// src/domains/providers/runtimes/cloud/mistral.ts
|
|
1439
|
+
init_esm_shims();
|
|
1440
|
+
var defaultCapabilities9 = {
|
|
1441
|
+
chat: true,
|
|
1442
|
+
tools: true,
|
|
1443
|
+
toolCallFormat: "mistral",
|
|
1444
|
+
reasoning: false,
|
|
1445
|
+
vision: false,
|
|
1446
|
+
audio: false,
|
|
1447
|
+
embeddings: false,
|
|
1448
|
+
rerank: false,
|
|
1449
|
+
fim: false,
|
|
1450
|
+
contextWindow: 128e3,
|
|
1451
|
+
maxTokens: 8192
|
|
1452
|
+
};
|
|
1453
|
+
var mistralRuntime = {
|
|
1454
|
+
id: "mistral",
|
|
1455
|
+
displayName: "Mistral AI",
|
|
1456
|
+
kind: "http",
|
|
1457
|
+
tier: "cloud",
|
|
1458
|
+
apiFamily: "mistral-conversations",
|
|
1459
|
+
auth: "api-key",
|
|
1460
|
+
credentialsEnvVar: "MISTRAL_API_KEY",
|
|
1461
|
+
defaultCapabilities: defaultCapabilities9,
|
|
1462
|
+
synthesizeModel(target, wireModelId, kb) {
|
|
1463
|
+
return synthesizeCatalogBackedModel({
|
|
1464
|
+
target,
|
|
1465
|
+
wireModelId,
|
|
1466
|
+
kb,
|
|
1467
|
+
defaultCapabilities: defaultCapabilities9,
|
|
1468
|
+
runtimeId: "mistral",
|
|
1469
|
+
api: "mistral-conversations",
|
|
1470
|
+
provider: "mistral",
|
|
1471
|
+
defaultBaseUrl: "https://api.mistral.ai"
|
|
1472
|
+
});
|
|
1473
|
+
}
|
|
1474
|
+
};
|
|
1475
|
+
var mistral_default = mistralRuntime;
|
|
1476
|
+
|
|
1477
|
+
// src/domains/providers/runtimes/cloud/openai.ts
|
|
1478
|
+
init_esm_shims();
|
|
1479
|
+
var defaultCapabilities10 = {
|
|
1480
|
+
chat: true,
|
|
1481
|
+
tools: true,
|
|
1482
|
+
toolCallFormat: "openai",
|
|
1483
|
+
reasoning: true,
|
|
1484
|
+
vision: true,
|
|
1485
|
+
audio: false,
|
|
1486
|
+
embeddings: false,
|
|
1487
|
+
rerank: false,
|
|
1488
|
+
fim: false,
|
|
1489
|
+
contextWindow: 272e3,
|
|
1490
|
+
maxTokens: 16384
|
|
1491
|
+
};
|
|
1492
|
+
var openaiRuntime = {
|
|
1493
|
+
id: "openai",
|
|
1494
|
+
displayName: "OpenAI",
|
|
1495
|
+
kind: "http",
|
|
1496
|
+
tier: "cloud",
|
|
1497
|
+
apiFamily: "openai-responses",
|
|
1498
|
+
auth: "api-key",
|
|
1499
|
+
credentialsEnvVar: "OPENAI_API_KEY",
|
|
1500
|
+
defaultCapabilities: defaultCapabilities10,
|
|
1501
|
+
synthesizeModel(target, wireModelId, kb) {
|
|
1502
|
+
return synthesizeCatalogBackedModel({
|
|
1503
|
+
target,
|
|
1504
|
+
wireModelId,
|
|
1505
|
+
kb,
|
|
1506
|
+
defaultCapabilities: defaultCapabilities10,
|
|
1507
|
+
runtimeId: "openai",
|
|
1508
|
+
api: "openai-responses",
|
|
1509
|
+
provider: "openai",
|
|
1510
|
+
defaultBaseUrl: "https://api.openai.com/v1"
|
|
1511
|
+
});
|
|
1512
|
+
}
|
|
1513
|
+
};
|
|
1514
|
+
var openai_default = openaiRuntime;
|
|
1515
|
+
|
|
1516
|
+
// src/domains/providers/runtimes/cloud/openai-codex.ts
|
|
1517
|
+
init_esm_shims();
|
|
1518
|
+
var defaultCapabilities11 = {
|
|
1519
|
+
chat: true,
|
|
1520
|
+
tools: true,
|
|
1521
|
+
toolCallFormat: "openai",
|
|
1522
|
+
reasoning: true,
|
|
1523
|
+
thinkingFormat: "openai-codex",
|
|
1524
|
+
vision: true,
|
|
1525
|
+
audio: false,
|
|
1526
|
+
embeddings: false,
|
|
1527
|
+
rerank: false,
|
|
1528
|
+
fim: false,
|
|
1529
|
+
contextWindow: 272e3,
|
|
1530
|
+
maxTokens: 16384
|
|
1531
|
+
};
|
|
1532
|
+
var openaiCodexRuntime = {
|
|
1533
|
+
id: "openai-codex",
|
|
1534
|
+
displayName: "OpenAI Codex",
|
|
1535
|
+
kind: "http",
|
|
1536
|
+
tier: "cloud",
|
|
1537
|
+
apiFamily: "openai-codex-responses",
|
|
1538
|
+
auth: "oauth",
|
|
1539
|
+
defaultCapabilities: defaultCapabilities11,
|
|
1540
|
+
async probeModels(_target, _ctx) {
|
|
1541
|
+
return listCatalogModelsForRuntime("openai-codex").map((model) => model.id);
|
|
1542
|
+
},
|
|
1543
|
+
synthesizeModel(target, wireModelId, kb) {
|
|
1544
|
+
return synthesizeCatalogBackedModel({
|
|
1545
|
+
target,
|
|
1546
|
+
wireModelId,
|
|
1547
|
+
kb,
|
|
1548
|
+
defaultCapabilities: defaultCapabilities11,
|
|
1549
|
+
runtimeId: "openai-codex",
|
|
1550
|
+
api: "openai-codex-responses",
|
|
1551
|
+
provider: "openai-codex",
|
|
1552
|
+
defaultBaseUrl: "https://chatgpt.com/backend-api"
|
|
1553
|
+
});
|
|
1554
|
+
}
|
|
1555
|
+
};
|
|
1556
|
+
var openai_codex_default = openaiCodexRuntime;
|
|
1557
|
+
|
|
1558
|
+
// src/domains/providers/runtimes/cloud/openrouter.ts
|
|
1559
|
+
init_esm_shims();
|
|
1560
|
+
var OPENROUTER_BASE_URL = "https://openrouter.ai/api/v1";
|
|
1561
|
+
var OPENROUTER_HEADERS = {
|
|
1562
|
+
"HTTP-Referer": "https://github.com/iowarp/clio-coder",
|
|
1563
|
+
"X-OpenRouter-Title": "Clio Coder"
|
|
1564
|
+
};
|
|
1565
|
+
var defaultCapabilities12 = {
|
|
1566
|
+
chat: true,
|
|
1567
|
+
tools: true,
|
|
1568
|
+
toolCallFormat: "openai",
|
|
1569
|
+
reasoning: false,
|
|
1570
|
+
thinkingFormat: "openrouter",
|
|
1571
|
+
vision: false,
|
|
1572
|
+
audio: false,
|
|
1573
|
+
embeddings: false,
|
|
1574
|
+
rerank: false,
|
|
1575
|
+
fim: false,
|
|
1576
|
+
contextWindow: 128e3,
|
|
1577
|
+
maxTokens: 8192
|
|
1578
|
+
};
|
|
1579
|
+
function trimTrailingSlash2(value) {
|
|
1580
|
+
return value.endsWith("/") && value.length > 1 ? value.slice(0, -1) : value;
|
|
1581
|
+
}
|
|
1582
|
+
function targetBaseUrl2(target) {
|
|
1583
|
+
return trimTrailingSlash2(target.url ?? OPENROUTER_BASE_URL);
|
|
1584
|
+
}
|
|
1585
|
+
function modelsUrl(target) {
|
|
1586
|
+
return `${targetBaseUrl2(target)}/models`;
|
|
1587
|
+
}
|
|
1588
|
+
function probeHeaders(target, ctx) {
|
|
1589
|
+
const headers = { ...OPENROUTER_HEADERS, ...target.auth?.headers ?? {} };
|
|
1590
|
+
const envName = target.auth?.apiKeyEnvVar ?? "OPENROUTER_API_KEY";
|
|
1591
|
+
if (ctx.credentialsPresent.has(envName)) {
|
|
1592
|
+
const key = process.env[envName]?.trim();
|
|
1593
|
+
if (key) headers.authorization = `Bearer ${key}`;
|
|
1594
|
+
}
|
|
1595
|
+
return headers;
|
|
1596
|
+
}
|
|
1597
|
+
async function fetchModels(target, ctx) {
|
|
1598
|
+
const opts = {
|
|
1599
|
+
url: modelsUrl(target),
|
|
1600
|
+
timeoutMs: ctx.httpTimeoutMs,
|
|
1601
|
+
headers: probeHeaders(target, ctx)
|
|
1602
|
+
};
|
|
1603
|
+
const result = await (ctx.signal ? probeJson({ ...opts, signal: ctx.signal }) : probeJson(opts));
|
|
1604
|
+
if (!result.ok) return result;
|
|
1605
|
+
const models = (result.data?.data ?? []).map((row) => typeof row?.id === "string" ? row.id : null).filter((id) => id !== null);
|
|
1606
|
+
const out = { ok: true, models };
|
|
1607
|
+
if (result.latencyMs !== void 0) out.latencyMs = result.latencyMs;
|
|
1608
|
+
const configured = target.defaultModel?.trim();
|
|
1609
|
+
if (configured && models.length > 0 && !models.includes(configured)) {
|
|
1610
|
+
out.ok = false;
|
|
1611
|
+
out.error = `configured model '${configured}' was not returned by OpenRouter`;
|
|
1612
|
+
}
|
|
1613
|
+
return out;
|
|
1614
|
+
}
|
|
1615
|
+
var openrouterRuntime = {
|
|
1616
|
+
id: "openrouter",
|
|
1617
|
+
displayName: "OpenRouter",
|
|
1618
|
+
kind: "http",
|
|
1619
|
+
tier: "cloud",
|
|
1620
|
+
apiFamily: "openai-completions",
|
|
1621
|
+
auth: "api-key",
|
|
1622
|
+
credentialsEnvVar: "OPENROUTER_API_KEY",
|
|
1623
|
+
defaultCapabilities: defaultCapabilities12,
|
|
1624
|
+
probe(target, ctx) {
|
|
1625
|
+
return fetchModels(target, ctx);
|
|
1626
|
+
},
|
|
1627
|
+
async probeModels(target, ctx) {
|
|
1628
|
+
const result = await fetchModels(target, ctx);
|
|
1629
|
+
return result.ok && result.models ? [...result.models] : [];
|
|
1630
|
+
},
|
|
1631
|
+
synthesizeModel(target, wireModelId, kb) {
|
|
1632
|
+
return synthesizeCatalogBackedModel({
|
|
1633
|
+
target,
|
|
1634
|
+
wireModelId,
|
|
1635
|
+
kb,
|
|
1636
|
+
defaultCapabilities: defaultCapabilities12,
|
|
1637
|
+
runtimeId: "openrouter",
|
|
1638
|
+
api: "openai-completions",
|
|
1639
|
+
provider: "openrouter",
|
|
1640
|
+
defaultBaseUrl: OPENROUTER_BASE_URL,
|
|
1641
|
+
defaultHeaders: OPENROUTER_HEADERS
|
|
1642
|
+
});
|
|
1643
|
+
}
|
|
1644
|
+
};
|
|
1645
|
+
var openrouter_default = openrouterRuntime;
|
|
1646
|
+
|
|
1647
|
+
// src/domains/providers/runtimes/local-native/lemonade-anthropic.ts
|
|
1648
|
+
init_esm_shims();
|
|
1649
|
+
|
|
1650
|
+
// src/domains/providers/runtimes/protocol/anthropic-compat.ts
|
|
1651
|
+
init_esm_shims();
|
|
1652
|
+
function synthesizeAnthropicCompatModel(input) {
|
|
1653
|
+
return synthLocalModel({
|
|
1654
|
+
target: input.target,
|
|
1655
|
+
wireModelId: input.wireModelId,
|
|
1656
|
+
kb: input.kb,
|
|
1657
|
+
defaultCapabilities: input.defaultCapabilities,
|
|
1658
|
+
apiFamily: "anthropic-messages",
|
|
1659
|
+
provider: input.provider,
|
|
1660
|
+
baseUrlForTarget: input.baseUrlForTarget ?? withAsIs
|
|
1661
|
+
});
|
|
1662
|
+
}
|
|
1663
|
+
function makeAnthropicCompatRuntime(spec) {
|
|
1664
|
+
const messagesPath = spec.messagesPath ?? "/v1/messages";
|
|
1665
|
+
const modelsPath = spec.modelsPath ?? "/v1/models";
|
|
1666
|
+
return {
|
|
1667
|
+
id: spec.id,
|
|
1668
|
+
displayName: spec.displayName,
|
|
1669
|
+
kind: "http",
|
|
1670
|
+
tier: spec.tier,
|
|
1671
|
+
apiFamily: "anthropic-messages",
|
|
1672
|
+
auth: spec.auth,
|
|
1673
|
+
defaultCapabilities: spec.defaultCapabilities,
|
|
1674
|
+
...spec.hidden === true ? { hidden: true } : {},
|
|
1675
|
+
async probe(target, ctx) {
|
|
1676
|
+
const base = targetBaseUrl(target);
|
|
1677
|
+
if (!base) return { ok: false, error: "target has no url" };
|
|
1678
|
+
return probeUrl(`${base}${messagesPath}`, ctx, "HEAD");
|
|
1679
|
+
},
|
|
1680
|
+
async probeModels(target, ctx) {
|
|
1681
|
+
const base = targetBaseUrl(target);
|
|
1682
|
+
if (!base) return [];
|
|
1683
|
+
return probeOpenAIModels(base, ctx, modelsPath);
|
|
1684
|
+
},
|
|
1685
|
+
synthesizeModel(target, wireModelId, kb) {
|
|
1686
|
+
return synthesizeAnthropicCompatModel({
|
|
1687
|
+
target,
|
|
1688
|
+
wireModelId,
|
|
1689
|
+
kb,
|
|
1690
|
+
defaultCapabilities: spec.defaultCapabilities,
|
|
1691
|
+
provider: spec.provider
|
|
1692
|
+
});
|
|
1693
|
+
}
|
|
1694
|
+
};
|
|
1695
|
+
}
|
|
1696
|
+
var defaultCapabilities13 = {
|
|
1697
|
+
chat: true,
|
|
1698
|
+
tools: true,
|
|
1699
|
+
toolCallFormat: "anthropic",
|
|
1700
|
+
reasoning: false,
|
|
1701
|
+
vision: false,
|
|
1702
|
+
audio: false,
|
|
1703
|
+
embeddings: false,
|
|
1704
|
+
rerank: false,
|
|
1705
|
+
fim: false,
|
|
1706
|
+
contextWindow: CLIO_MIN_CONTEXT_WINDOW,
|
|
1707
|
+
maxTokens: CLIO_MIN_MAX_OUTPUT_TOKENS
|
|
1708
|
+
};
|
|
1709
|
+
var anthropic_compat_default = makeAnthropicCompatRuntime({
|
|
1710
|
+
id: "anthropic-compat",
|
|
1711
|
+
displayName: "Generic Anthropic-compatible",
|
|
1712
|
+
provider: "anthropic-compat",
|
|
1713
|
+
auth: "api-key",
|
|
1714
|
+
tier: "protocol",
|
|
1715
|
+
defaultCapabilities: defaultCapabilities13
|
|
1716
|
+
});
|
|
1717
|
+
|
|
1718
|
+
// src/domains/providers/runtimes/local-native/lemonade-anthropic.ts
|
|
1719
|
+
var defaultCapabilities14 = {
|
|
1720
|
+
chat: true,
|
|
1721
|
+
tools: true,
|
|
1722
|
+
toolCallFormat: "anthropic",
|
|
1723
|
+
reasoning: false,
|
|
1724
|
+
vision: false,
|
|
1725
|
+
audio: false,
|
|
1726
|
+
embeddings: false,
|
|
1727
|
+
rerank: false,
|
|
1728
|
+
fim: false,
|
|
1729
|
+
contextWindow: CLIO_MIN_CONTEXT_WINDOW,
|
|
1730
|
+
maxTokens: CLIO_MIN_MAX_OUTPUT_TOKENS
|
|
1731
|
+
};
|
|
1732
|
+
var lemonade_anthropic_default = makeAnthropicCompatRuntime({
|
|
1733
|
+
id: "lemonade-anthropic",
|
|
1734
|
+
displayName: "Lemonade (Anthropic-compat)",
|
|
1735
|
+
provider: "lemonade",
|
|
1736
|
+
auth: "api-key",
|
|
1737
|
+
tier: "local-native",
|
|
1738
|
+
defaultCapabilities: defaultCapabilities14,
|
|
1739
|
+
hidden: true
|
|
1740
|
+
});
|
|
1741
|
+
|
|
1742
|
+
// src/domains/providers/runtimes/local-native/lemonade-openai.ts
|
|
1743
|
+
init_esm_shims();
|
|
1744
|
+
var defaultCapabilities15 = {
|
|
1745
|
+
chat: true,
|
|
1746
|
+
tools: true,
|
|
1747
|
+
toolCallFormat: "openai",
|
|
1748
|
+
reasoning: false,
|
|
1749
|
+
vision: false,
|
|
1750
|
+
audio: false,
|
|
1751
|
+
embeddings: false,
|
|
1752
|
+
rerank: false,
|
|
1753
|
+
fim: false,
|
|
1754
|
+
contextWindow: CLIO_MIN_CONTEXT_WINDOW,
|
|
1755
|
+
maxTokens: CLIO_MIN_MAX_OUTPUT_TOKENS
|
|
1756
|
+
};
|
|
1757
|
+
var lemonade_openai_default = makeOpenAICompatRuntime({
|
|
1758
|
+
id: "lemonade",
|
|
1759
|
+
displayName: "Lemonade (OpenAI-compat)",
|
|
1760
|
+
provider: "lemonade",
|
|
1761
|
+
auth: "api-key",
|
|
1762
|
+
tier: "local-native",
|
|
1763
|
+
defaultCapabilities: defaultCapabilities15
|
|
1764
|
+
});
|
|
1765
|
+
|
|
1766
|
+
// src/domains/providers/runtimes/local-native/llamacpp.ts
|
|
1767
|
+
init_esm_shims();
|
|
1768
|
+
var defaultCapabilities16 = {
|
|
1769
|
+
chat: true,
|
|
1770
|
+
tools: true,
|
|
1771
|
+
toolCallFormat: "openai",
|
|
1772
|
+
structuredOutputs: "json-schema",
|
|
1773
|
+
reasoning: false,
|
|
1774
|
+
vision: false,
|
|
1775
|
+
audio: false,
|
|
1776
|
+
embeddings: false,
|
|
1777
|
+
rerank: false,
|
|
1778
|
+
fim: false,
|
|
1779
|
+
contextWindow: CLIO_MIN_CONTEXT_WINDOW,
|
|
1780
|
+
maxTokens: CLIO_MIN_MAX_OUTPUT_TOKENS
|
|
1781
|
+
};
|
|
1782
|
+
function targetUrl(target) {
|
|
1783
|
+
return targetRootUrl(target);
|
|
1784
|
+
}
|
|
1785
|
+
var llamacppRuntime = {
|
|
1786
|
+
id: "llamacpp",
|
|
1787
|
+
displayName: "llama.cpp",
|
|
1788
|
+
kind: "http",
|
|
1789
|
+
tier: "local-native",
|
|
1790
|
+
apiFamily: "openai-completions",
|
|
1791
|
+
auth: "api-key",
|
|
1792
|
+
defaultCapabilities: defaultCapabilities16,
|
|
1793
|
+
async probe(target, ctx) {
|
|
1794
|
+
const base = targetUrl(target);
|
|
1795
|
+
if (!base) return { ok: false, error: "target has no url" };
|
|
1796
|
+
const healthOpts = { url: `${base}/health`, timeoutMs: ctx.httpTimeoutMs };
|
|
1797
|
+
const health = await (ctx.signal ? probeHttp({ ...healthOpts, signal: ctx.signal }) : probeHttp(healthOpts));
|
|
1798
|
+
if (!health.ok) return health;
|
|
1799
|
+
const status = await probeLlamaCppModelStatus(base, target, ctx);
|
|
1800
|
+
const props = await probeLlamaCppProps(base, ctx, status.modelId ?? target.defaultModel);
|
|
1801
|
+
const catalog = await probeOpenAIModelCatalog(base, ctx);
|
|
1802
|
+
const result = { ok: true };
|
|
1803
|
+
if (catalog.models.length > 0) result.models = catalog.models;
|
|
1804
|
+
if (Object.keys(catalog.modelCapabilities).length > 0) result.modelCapabilities = catalog.modelCapabilities;
|
|
1805
|
+
if (Object.keys(catalog.modelStates).length > 0) result.modelStates = catalog.modelStates;
|
|
1806
|
+
if (typeof health.latencyMs === "number") result.latencyMs = health.latencyMs;
|
|
1807
|
+
const discoveredCapabilities = {
|
|
1808
|
+
...props.discoveredCapabilities ?? {},
|
|
1809
|
+
...status.discoveredCapabilities ?? {},
|
|
1810
|
+
...props.discoveredCapabilities?.parallelSlots !== void 0 ? { parallelSlots: props.discoveredCapabilities.parallelSlots } : {}
|
|
1811
|
+
};
|
|
1812
|
+
if (Object.keys(discoveredCapabilities).length > 0) {
|
|
1813
|
+
result.discoveredCapabilities = discoveredCapabilities;
|
|
1814
|
+
if (status.modelId) result.capabilityModelId = status.modelId;
|
|
1815
|
+
}
|
|
1816
|
+
if (props.serverVersion) result.serverVersion = props.serverVersion;
|
|
1817
|
+
const note = await detectModelMismatch(base, target, ctx);
|
|
1818
|
+
const notes = [...status.notes ?? [], ...note ? [note] : []];
|
|
1819
|
+
if (notes.length > 0) result.notes = notes;
|
|
1820
|
+
return result;
|
|
1821
|
+
},
|
|
1822
|
+
async probeModels(target, ctx) {
|
|
1823
|
+
const base = targetUrl(target);
|
|
1824
|
+
if (!base) return [];
|
|
1825
|
+
return probeOpenAIModels(base, ctx);
|
|
1826
|
+
},
|
|
1827
|
+
synthesizeModel(target, wireModelId, kb) {
|
|
1828
|
+
return synthLocalModel({
|
|
1829
|
+
target,
|
|
1830
|
+
wireModelId,
|
|
1831
|
+
kb,
|
|
1832
|
+
defaultCapabilities: defaultCapabilities16,
|
|
1833
|
+
apiFamily: "openai-completions",
|
|
1834
|
+
provider: "llamacpp",
|
|
1835
|
+
baseUrlForTarget: withV1
|
|
1836
|
+
});
|
|
1837
|
+
}
|
|
1838
|
+
};
|
|
1839
|
+
var llamacpp_default = llamacppRuntime;
|
|
1840
|
+
|
|
1841
|
+
// src/domains/providers/runtimes/local-native/llamacpp-anthropic.ts
|
|
1842
|
+
init_esm_shims();
|
|
1843
|
+
var defaultCapabilities17 = {
|
|
1844
|
+
chat: true,
|
|
1845
|
+
tools: true,
|
|
1846
|
+
toolCallFormat: "anthropic",
|
|
1847
|
+
reasoning: false,
|
|
1848
|
+
vision: false,
|
|
1849
|
+
audio: false,
|
|
1850
|
+
embeddings: false,
|
|
1851
|
+
rerank: false,
|
|
1852
|
+
fim: true,
|
|
1853
|
+
contextWindow: CLIO_MIN_CONTEXT_WINDOW,
|
|
1854
|
+
maxTokens: CLIO_MIN_MAX_OUTPUT_TOKENS
|
|
1855
|
+
};
|
|
1856
|
+
function url(target) {
|
|
1857
|
+
return target.url ? stripTrailingSlash(target.url) : null;
|
|
1858
|
+
}
|
|
1859
|
+
var llamacppAnthropicRuntime = {
|
|
1860
|
+
id: "llamacpp-anthropic",
|
|
1861
|
+
displayName: "llama.cpp (Anthropic-compat)",
|
|
1862
|
+
kind: "http",
|
|
1863
|
+
tier: "local-native",
|
|
1864
|
+
apiFamily: "anthropic-messages",
|
|
1865
|
+
auth: "api-key",
|
|
1866
|
+
defaultCapabilities: defaultCapabilities17,
|
|
1867
|
+
hidden: true,
|
|
1868
|
+
async probe(target, ctx) {
|
|
1869
|
+
const base = url(target);
|
|
1870
|
+
if (!base) return { ok: false, error: "target has no url" };
|
|
1871
|
+
const healthOpts = { url: `${base}/health`, timeoutMs: ctx.httpTimeoutMs };
|
|
1872
|
+
const health = await (ctx.signal ? probeHttp({ ...healthOpts, signal: ctx.signal }) : probeHttp(healthOpts));
|
|
1873
|
+
if (!health.ok) return health;
|
|
1874
|
+
const headOpts = {
|
|
1875
|
+
url: `${base}/v1/messages`,
|
|
1876
|
+
method: "HEAD",
|
|
1877
|
+
timeoutMs: ctx.httpTimeoutMs
|
|
1878
|
+
};
|
|
1879
|
+
const head = await (ctx.signal ? probeHttp({ ...headOpts, signal: ctx.signal }) : probeHttp(headOpts));
|
|
1880
|
+
if (!head.ok) return head;
|
|
1881
|
+
const props = await probeLlamaCppProps(base, ctx, target.defaultModel);
|
|
1882
|
+
const enriched = { ...head };
|
|
1883
|
+
if (props.discoveredCapabilities) enriched.discoveredCapabilities = props.discoveredCapabilities;
|
|
1884
|
+
if (props.serverVersion) enriched.serverVersion = props.serverVersion;
|
|
1885
|
+
const note = await detectModelMismatch(base, target, ctx);
|
|
1886
|
+
if (note) enriched.notes = [note];
|
|
1887
|
+
return enriched;
|
|
1888
|
+
},
|
|
1889
|
+
async probeModels(target, ctx) {
|
|
1890
|
+
const base = url(target);
|
|
1891
|
+
if (!base) return [];
|
|
1892
|
+
const opts = { url: `${base}/v1/models`, timeoutMs: ctx.httpTimeoutMs };
|
|
1893
|
+
const result = await (ctx.signal ? probeJson({ ...opts, signal: ctx.signal }) : probeJson(opts));
|
|
1894
|
+
if (!result.ok || !result.data?.data) return [];
|
|
1895
|
+
return result.data.data.map((row) => typeof row?.id === "string" ? row.id : null).filter((id) => id !== null);
|
|
1896
|
+
},
|
|
1897
|
+
synthesizeModel(target, wireModelId, kb) {
|
|
1898
|
+
return synthLocalModel({
|
|
1899
|
+
target,
|
|
1900
|
+
wireModelId,
|
|
1901
|
+
kb,
|
|
1902
|
+
defaultCapabilities: defaultCapabilities17,
|
|
1903
|
+
apiFamily: "anthropic-messages",
|
|
1904
|
+
provider: "llamacpp",
|
|
1905
|
+
baseUrlForTarget: withAsIs
|
|
1906
|
+
});
|
|
1907
|
+
}
|
|
1908
|
+
};
|
|
1909
|
+
var llamacpp_anthropic_default = llamacppAnthropicRuntime;
|
|
1910
|
+
|
|
1911
|
+
// src/domains/providers/runtimes/local-native/llamacpp-completion.ts
|
|
1912
|
+
init_esm_shims();
|
|
1913
|
+
var defaultCapabilities18 = {
|
|
1914
|
+
chat: false,
|
|
1915
|
+
tools: false,
|
|
1916
|
+
reasoning: false,
|
|
1917
|
+
vision: false,
|
|
1918
|
+
audio: false,
|
|
1919
|
+
embeddings: false,
|
|
1920
|
+
rerank: false,
|
|
1921
|
+
fim: true,
|
|
1922
|
+
structuredOutputs: "gbnf",
|
|
1923
|
+
contextWindow: 8192,
|
|
1924
|
+
maxTokens: 4096
|
|
1925
|
+
};
|
|
1926
|
+
function targetUrl2(target) {
|
|
1927
|
+
return targetRootUrl(target);
|
|
1928
|
+
}
|
|
1929
|
+
function parseChunk(raw) {
|
|
1930
|
+
const chunk = {
|
|
1931
|
+
content: typeof raw.content === "string" ? raw.content : "",
|
|
1932
|
+
stop: raw.stop === true
|
|
1933
|
+
};
|
|
1934
|
+
if (raw.stop_type === "eos" || raw.stop_type === "limit" || raw.stop_type === "word" || raw.stop_type === "none") {
|
|
1935
|
+
chunk.stop_type = raw.stop_type;
|
|
1936
|
+
}
|
|
1937
|
+
if (typeof raw.tokens_predicted === "number") chunk.tokens_predicted = raw.tokens_predicted;
|
|
1938
|
+
if (typeof raw.tokens_evaluated === "number") chunk.tokens_evaluated = raw.tokens_evaluated;
|
|
1939
|
+
return chunk;
|
|
1940
|
+
}
|
|
1941
|
+
async function* streamSse(body) {
|
|
1942
|
+
const reader = body.getReader();
|
|
1943
|
+
const decoder = new TextDecoder("utf-8");
|
|
1944
|
+
let buffered = "";
|
|
1945
|
+
let droppedFrames = 0;
|
|
1946
|
+
try {
|
|
1947
|
+
while (true) {
|
|
1948
|
+
const { done, value } = await reader.read();
|
|
1949
|
+
if (done) break;
|
|
1950
|
+
buffered += decoder.decode(value, { stream: true });
|
|
1951
|
+
let nl = buffered.indexOf("\n");
|
|
1952
|
+
while (nl !== -1) {
|
|
1953
|
+
const line = buffered.slice(0, nl).trimEnd();
|
|
1954
|
+
buffered = buffered.slice(nl + 1);
|
|
1955
|
+
nl = buffered.indexOf("\n");
|
|
1956
|
+
if (line.length === 0) continue;
|
|
1957
|
+
const payload = line.startsWith("data:") ? line.slice(5).trim() : line;
|
|
1958
|
+
if (payload.length === 0 || payload === "[DONE]") continue;
|
|
1959
|
+
try {
|
|
1960
|
+
const parsed = JSON.parse(payload);
|
|
1961
|
+
const chunk = parseChunk(parsed);
|
|
1962
|
+
yield chunk;
|
|
1963
|
+
if (chunk.stop) return;
|
|
1964
|
+
} catch {
|
|
1965
|
+
droppedFrames += 1;
|
|
1966
|
+
}
|
|
1967
|
+
}
|
|
1968
|
+
}
|
|
1969
|
+
const tail = buffered.trim();
|
|
1970
|
+
if (tail.length > 0) {
|
|
1971
|
+
const payload = tail.startsWith("data:") ? tail.slice(5).trim() : tail;
|
|
1972
|
+
if (payload !== "[DONE]") {
|
|
1973
|
+
try {
|
|
1974
|
+
const parsed = JSON.parse(payload);
|
|
1975
|
+
yield parseChunk(parsed);
|
|
1976
|
+
} catch {
|
|
1977
|
+
droppedFrames += 1;
|
|
1978
|
+
}
|
|
1979
|
+
}
|
|
1980
|
+
}
|
|
1981
|
+
} finally {
|
|
1982
|
+
if (droppedFrames > 0) {
|
|
1983
|
+
process.stderr.write(`[clio:llamacpp] dropped ${droppedFrames} malformed stream frame(s)
|
|
1984
|
+
`);
|
|
1985
|
+
}
|
|
1986
|
+
reader.releaseLock();
|
|
1987
|
+
}
|
|
1988
|
+
}
|
|
1989
|
+
async function postStream(url2, body, signal) {
|
|
1990
|
+
const init = {
|
|
1991
|
+
method: "POST",
|
|
1992
|
+
headers: { "content-type": "application/json", accept: "text/event-stream" },
|
|
1993
|
+
body: JSON.stringify(body)
|
|
1994
|
+
};
|
|
1995
|
+
if (signal) init.signal = signal;
|
|
1996
|
+
const response = await fetch(url2, init);
|
|
1997
|
+
if (!response.ok || !response.body) {
|
|
1998
|
+
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
|
1999
|
+
}
|
|
2000
|
+
return response.body;
|
|
2001
|
+
}
|
|
2002
|
+
function buildCompleteBody(opts) {
|
|
2003
|
+
const body = { prompt: opts.prompt, stream: true };
|
|
2004
|
+
if (opts.n_predict !== void 0) body.n_predict = opts.n_predict;
|
|
2005
|
+
if (opts.stop && opts.stop.length > 0) body.stop = opts.stop;
|
|
2006
|
+
if (opts.grammar) body.grammar = opts.grammar;
|
|
2007
|
+
if (opts.json_schema) body.json_schema = opts.json_schema;
|
|
2008
|
+
if (opts.cache_prompt !== void 0) body.cache_prompt = opts.cache_prompt;
|
|
2009
|
+
return body;
|
|
2010
|
+
}
|
|
2011
|
+
function buildInfillBody(opts) {
|
|
2012
|
+
const body = buildCompleteBody(opts);
|
|
2013
|
+
body.input_prefix = opts.input_prefix;
|
|
2014
|
+
body.input_suffix = opts.input_suffix;
|
|
2015
|
+
if (opts.input_extra) body.input_extra = opts.input_extra;
|
|
2016
|
+
return body;
|
|
2017
|
+
}
|
|
2018
|
+
var llamacppCompletionRuntime = {
|
|
2019
|
+
id: "llamacpp-completion",
|
|
2020
|
+
displayName: "llama.cpp (completion / infill)",
|
|
2021
|
+
kind: "http",
|
|
2022
|
+
tier: "local-native",
|
|
2023
|
+
apiFamily: "openai-completions",
|
|
2024
|
+
auth: "api-key",
|
|
2025
|
+
defaultCapabilities: defaultCapabilities18,
|
|
2026
|
+
hidden: true,
|
|
2027
|
+
async probe(target, ctx) {
|
|
2028
|
+
const base = targetUrl2(target);
|
|
2029
|
+
if (!base) return { ok: false, error: "target has no url" };
|
|
2030
|
+
const healthOpts = { url: `${base}/health`, timeoutMs: ctx.httpTimeoutMs };
|
|
2031
|
+
const health = await (ctx.signal ? probeHttp({ ...healthOpts, signal: ctx.signal }) : probeHttp(healthOpts));
|
|
2032
|
+
if (!health.ok) return health;
|
|
2033
|
+
const props = await probeLlamaCppProps(base, ctx, target.defaultModel);
|
|
2034
|
+
const status = await probeLlamaCppModelStatus(base, target, ctx);
|
|
2035
|
+
const enriched = { ...health };
|
|
2036
|
+
const discoveredCapabilities = {
|
|
2037
|
+
...props.discoveredCapabilities ?? {},
|
|
2038
|
+
...status.discoveredCapabilities ?? {}
|
|
2039
|
+
};
|
|
2040
|
+
if (Object.keys(discoveredCapabilities).length > 0) {
|
|
2041
|
+
enriched.discoveredCapabilities = discoveredCapabilities;
|
|
2042
|
+
if (status.modelId) enriched.capabilityModelId = status.modelId;
|
|
2043
|
+
}
|
|
2044
|
+
if (props.serverVersion) enriched.serverVersion = props.serverVersion;
|
|
2045
|
+
const note = await detectModelMismatch(base, target, ctx);
|
|
2046
|
+
const notes = [...status.notes ?? [], ...note ? [note] : []];
|
|
2047
|
+
if (notes.length > 0) enriched.notes = notes;
|
|
2048
|
+
return enriched;
|
|
2049
|
+
},
|
|
2050
|
+
async probeModels(target, ctx) {
|
|
2051
|
+
const base = targetUrl2(target);
|
|
2052
|
+
if (!base) return [];
|
|
2053
|
+
return probeOpenAIModels(base, ctx);
|
|
2054
|
+
},
|
|
2055
|
+
synthesizeModel(target, wireModelId, kb) {
|
|
2056
|
+
return synthLocalModel({
|
|
2057
|
+
target,
|
|
2058
|
+
wireModelId,
|
|
2059
|
+
kb,
|
|
2060
|
+
defaultCapabilities: defaultCapabilities18,
|
|
2061
|
+
apiFamily: "openai-completions",
|
|
2062
|
+
provider: "llamacpp",
|
|
2063
|
+
baseUrlForTarget: withV1
|
|
2064
|
+
});
|
|
2065
|
+
},
|
|
2066
|
+
async *complete(target, opts) {
|
|
2067
|
+
const base = targetUrl2(target);
|
|
2068
|
+
if (!base) throw new Error("target has no url");
|
|
2069
|
+
const body = await postStream(`${base}/completion`, buildCompleteBody(opts), opts.signal);
|
|
2070
|
+
for await (const chunk of streamSse(body)) yield chunk;
|
|
2071
|
+
},
|
|
2072
|
+
async *infill(target, opts) {
|
|
2073
|
+
const base = targetUrl2(target);
|
|
2074
|
+
if (!base) throw new Error("target has no url");
|
|
2075
|
+
const body = await postStream(`${base}/infill`, buildInfillBody(opts), opts.signal);
|
|
2076
|
+
for await (const chunk of streamSse(body)) yield chunk;
|
|
2077
|
+
}
|
|
2078
|
+
};
|
|
2079
|
+
var llamacpp_completion_default = llamacppCompletionRuntime;
|
|
2080
|
+
|
|
2081
|
+
// src/domains/providers/runtimes/local-native/llamacpp-embed.ts
|
|
2082
|
+
init_esm_shims();
|
|
2083
|
+
var defaultCapabilities19 = {
|
|
2084
|
+
chat: false,
|
|
2085
|
+
tools: false,
|
|
2086
|
+
reasoning: false,
|
|
2087
|
+
vision: false,
|
|
2088
|
+
audio: false,
|
|
2089
|
+
embeddings: true,
|
|
2090
|
+
rerank: false,
|
|
2091
|
+
fim: false,
|
|
2092
|
+
contextWindow: 8192,
|
|
2093
|
+
maxTokens: 0
|
|
2094
|
+
};
|
|
2095
|
+
function targetUrl3(target) {
|
|
2096
|
+
return targetRootUrl(target);
|
|
2097
|
+
}
|
|
2098
|
+
function meanPool(matrix) {
|
|
2099
|
+
if (matrix.length === 0) return [];
|
|
2100
|
+
const dim = matrix[0]?.length ?? 0;
|
|
2101
|
+
const sum = new Array(dim).fill(0);
|
|
2102
|
+
for (const row of matrix) {
|
|
2103
|
+
for (let i = 0; i < dim; i++) sum[i] = (sum[i] ?? 0) + (row[i] ?? 0);
|
|
2104
|
+
}
|
|
2105
|
+
return sum.map((v) => v / matrix.length);
|
|
2106
|
+
}
|
|
2107
|
+
function flattenNativeEmbedding(entry) {
|
|
2108
|
+
const value = entry.embedding;
|
|
2109
|
+
if (!value || value.length === 0) return [];
|
|
2110
|
+
if (Array.isArray(value[0])) return meanPool(value);
|
|
2111
|
+
return value;
|
|
2112
|
+
}
|
|
2113
|
+
async function postJson(url2, body, signal) {
|
|
2114
|
+
const init = {
|
|
2115
|
+
method: "POST",
|
|
2116
|
+
headers: { "content-type": "application/json" },
|
|
2117
|
+
body: JSON.stringify(body)
|
|
2118
|
+
};
|
|
2119
|
+
if (signal) init.signal = signal;
|
|
2120
|
+
const response = await fetch(url2, init);
|
|
2121
|
+
if (!response.ok) return { status: response.status, data: null };
|
|
2122
|
+
try {
|
|
2123
|
+
const data = await response.json();
|
|
2124
|
+
return { status: response.status, data };
|
|
2125
|
+
} catch {
|
|
2126
|
+
return { status: response.status, data: null };
|
|
2127
|
+
}
|
|
2128
|
+
}
|
|
2129
|
+
var llamacppEmbedRuntime = {
|
|
2130
|
+
id: "llamacpp-embed",
|
|
2131
|
+
displayName: "llama.cpp (embeddings)",
|
|
2132
|
+
kind: "http",
|
|
2133
|
+
tier: "local-native",
|
|
2134
|
+
apiFamily: "openai-completions",
|
|
2135
|
+
auth: "api-key",
|
|
2136
|
+
defaultCapabilities: defaultCapabilities19,
|
|
2137
|
+
hidden: true,
|
|
2138
|
+
async probe(target, ctx) {
|
|
2139
|
+
const base = targetUrl3(target);
|
|
2140
|
+
if (!base) return { ok: false, error: "target has no url" };
|
|
2141
|
+
const healthOpts = { url: `${base}/health`, timeoutMs: ctx.httpTimeoutMs };
|
|
2142
|
+
const health = await (ctx.signal ? probeHttp({ ...healthOpts, signal: ctx.signal }) : probeHttp(healthOpts));
|
|
2143
|
+
if (!health.ok) return health;
|
|
2144
|
+
const probeResponse = await fetch(`${base}/embedding`, {
|
|
2145
|
+
method: "POST",
|
|
2146
|
+
headers: { "content-type": "application/json" },
|
|
2147
|
+
body: JSON.stringify({ content: "probe" }),
|
|
2148
|
+
...ctx.signal ? { signal: ctx.signal } : {}
|
|
2149
|
+
}).catch((err) => {
|
|
2150
|
+
return new Response(null, { status: 599, statusText: String(err) });
|
|
2151
|
+
});
|
|
2152
|
+
if (!probeResponse.ok) {
|
|
2153
|
+
return { ok: false, error: `/embedding not available: HTTP ${probeResponse.status}` };
|
|
2154
|
+
}
|
|
2155
|
+
const props = await probeLlamaCppProps(base, ctx, target.defaultModel);
|
|
2156
|
+
const result = { ok: true };
|
|
2157
|
+
if (health.latencyMs !== void 0) result.latencyMs = health.latencyMs;
|
|
2158
|
+
if (props.discoveredCapabilities) result.discoveredCapabilities = props.discoveredCapabilities;
|
|
2159
|
+
if (props.serverVersion) result.serverVersion = props.serverVersion;
|
|
2160
|
+
return result;
|
|
2161
|
+
},
|
|
2162
|
+
async probeModels(target, ctx) {
|
|
2163
|
+
const base = targetUrl3(target);
|
|
2164
|
+
if (!base) return [];
|
|
2165
|
+
return probeOpenAIModels(base, ctx);
|
|
2166
|
+
},
|
|
2167
|
+
synthesizeModel(target, wireModelId, kb) {
|
|
2168
|
+
return synthLocalModel({
|
|
2169
|
+
target,
|
|
2170
|
+
wireModelId,
|
|
2171
|
+
kb,
|
|
2172
|
+
defaultCapabilities: defaultCapabilities19,
|
|
2173
|
+
apiFamily: "openai-completions",
|
|
2174
|
+
provider: "llamacpp",
|
|
2175
|
+
baseUrlForTarget: withV1
|
|
2176
|
+
});
|
|
2177
|
+
},
|
|
2178
|
+
async embed(target, input, ctx) {
|
|
2179
|
+
const base = targetUrl3(target);
|
|
2180
|
+
if (!base) throw new Error("target has no url");
|
|
2181
|
+
const modelId = target.defaultModel ?? "default";
|
|
2182
|
+
const inputs = Array.isArray(input) ? input : [input];
|
|
2183
|
+
const oai = await postJson(
|
|
2184
|
+
`${base}/v1/embeddings`,
|
|
2185
|
+
{ input: inputs, model: modelId, encoding_format: "float" },
|
|
2186
|
+
ctx.signal
|
|
2187
|
+
);
|
|
2188
|
+
if (oai.data && Array.isArray(oai.data.data)) {
|
|
2189
|
+
const rows = oai.data.data;
|
|
2190
|
+
const sorted = [...rows].sort((a, b) => (a.index ?? 0) - (b.index ?? 0));
|
|
2191
|
+
const vectors2 = sorted.map((row) => row.embedding ?? []);
|
|
2192
|
+
const tokens = oai.data.usage?.total_tokens ?? oai.data.usage?.prompt_tokens ?? void 0;
|
|
2193
|
+
const dim = vectors2[0]?.length ?? 0;
|
|
2194
|
+
const result = {
|
|
2195
|
+
vectors: vectors2,
|
|
2196
|
+
model: oai.data.model ?? modelId,
|
|
2197
|
+
dimensions: dim
|
|
2198
|
+
};
|
|
2199
|
+
if (tokens !== void 0) result.tokensUsed = tokens;
|
|
2200
|
+
return result;
|
|
2201
|
+
}
|
|
2202
|
+
const probeOpts = { url: `${base}/embedding`, timeoutMs: ctx.httpTimeoutMs };
|
|
2203
|
+
const native = await (ctx.signal ? probeJson({
|
|
2204
|
+
...probeOpts,
|
|
2205
|
+
method: "POST",
|
|
2206
|
+
body: JSON.stringify({ content: inputs }),
|
|
2207
|
+
headers: { "content-type": "application/json" },
|
|
2208
|
+
signal: ctx.signal
|
|
2209
|
+
}) : probeJson({
|
|
2210
|
+
...probeOpts,
|
|
2211
|
+
method: "POST",
|
|
2212
|
+
body: JSON.stringify({ content: inputs }),
|
|
2213
|
+
headers: { "content-type": "application/json" }
|
|
2214
|
+
}));
|
|
2215
|
+
if (!native.ok || !native.data) {
|
|
2216
|
+
throw new Error(`llama.cpp embedding failed: ${native.error ?? "unknown"}`);
|
|
2217
|
+
}
|
|
2218
|
+
const items = native.data;
|
|
2219
|
+
items.sort((a, b) => (a.index ?? 0) - (b.index ?? 0));
|
|
2220
|
+
const vectors = items.map(flattenNativeEmbedding);
|
|
2221
|
+
return {
|
|
2222
|
+
vectors,
|
|
2223
|
+
model: modelId,
|
|
2224
|
+
dimensions: vectors[0]?.length ?? 0
|
|
2225
|
+
};
|
|
2226
|
+
}
|
|
2227
|
+
};
|
|
2228
|
+
var llamacpp_embed_default = llamacppEmbedRuntime;
|
|
2229
|
+
|
|
2230
|
+
// src/domains/providers/runtimes/local-native/llamacpp-rerank.ts
|
|
2231
|
+
init_esm_shims();
|
|
2232
|
+
var defaultCapabilities20 = {
|
|
2233
|
+
chat: false,
|
|
2234
|
+
tools: false,
|
|
2235
|
+
reasoning: false,
|
|
2236
|
+
vision: false,
|
|
2237
|
+
audio: false,
|
|
2238
|
+
embeddings: false,
|
|
2239
|
+
rerank: true,
|
|
2240
|
+
fim: false,
|
|
2241
|
+
contextWindow: 8192,
|
|
2242
|
+
maxTokens: 0
|
|
2243
|
+
};
|
|
2244
|
+
function targetUrl4(target) {
|
|
2245
|
+
return targetRootUrl(target);
|
|
2246
|
+
}
|
|
2247
|
+
var llamacppRerankRuntime = {
|
|
2248
|
+
id: "llamacpp-rerank",
|
|
2249
|
+
displayName: "llama.cpp (rerank)",
|
|
2250
|
+
kind: "http",
|
|
2251
|
+
tier: "local-native",
|
|
2252
|
+
apiFamily: "openai-completions",
|
|
2253
|
+
auth: "api-key",
|
|
2254
|
+
defaultCapabilities: defaultCapabilities20,
|
|
2255
|
+
hidden: true,
|
|
2256
|
+
async probe(target, ctx) {
|
|
2257
|
+
const base = targetUrl4(target);
|
|
2258
|
+
if (!base) return { ok: false, error: "target has no url" };
|
|
2259
|
+
const healthOpts = { url: `${base}/health`, timeoutMs: ctx.httpTimeoutMs };
|
|
2260
|
+
const health = await (ctx.signal ? probeHttp({ ...healthOpts, signal: ctx.signal }) : probeHttp(healthOpts));
|
|
2261
|
+
if (!health.ok) return health;
|
|
2262
|
+
const modelId = target.defaultModel ?? "default";
|
|
2263
|
+
const probeResponse = await fetch(`${base}/reranking`, {
|
|
2264
|
+
method: "POST",
|
|
2265
|
+
headers: { "content-type": "application/json" },
|
|
2266
|
+
body: JSON.stringify({ query: "probe", documents: ["a"], model: modelId }),
|
|
2267
|
+
...ctx.signal ? { signal: ctx.signal } : {}
|
|
2268
|
+
}).catch((err) => new Response(null, { status: 599, statusText: String(err) }));
|
|
2269
|
+
if (!(probeResponse.status === 200 || probeResponse.status === 202)) {
|
|
2270
|
+
return { ok: false, error: `/reranking not available: HTTP ${probeResponse.status}` };
|
|
2271
|
+
}
|
|
2272
|
+
const props = await probeLlamaCppProps(base, ctx, target.defaultModel);
|
|
2273
|
+
const result = { ok: true };
|
|
2274
|
+
if (health.latencyMs !== void 0) result.latencyMs = health.latencyMs;
|
|
2275
|
+
if (props.discoveredCapabilities) result.discoveredCapabilities = props.discoveredCapabilities;
|
|
2276
|
+
if (props.serverVersion) result.serverVersion = props.serverVersion;
|
|
2277
|
+
return result;
|
|
2278
|
+
},
|
|
2279
|
+
async probeModels(target, ctx) {
|
|
2280
|
+
const base = targetUrl4(target);
|
|
2281
|
+
if (!base) return [];
|
|
2282
|
+
return probeOpenAIModels(base, ctx);
|
|
2283
|
+
},
|
|
2284
|
+
synthesizeModel(target, wireModelId, kb) {
|
|
2285
|
+
return synthLocalModel({
|
|
2286
|
+
target,
|
|
2287
|
+
wireModelId,
|
|
2288
|
+
kb,
|
|
2289
|
+
defaultCapabilities: defaultCapabilities20,
|
|
2290
|
+
apiFamily: "openai-completions",
|
|
2291
|
+
provider: "llamacpp",
|
|
2292
|
+
baseUrlForTarget: withV1
|
|
2293
|
+
});
|
|
2294
|
+
},
|
|
2295
|
+
async rerank(target, query, documents, ctx) {
|
|
2296
|
+
const base = targetUrl4(target);
|
|
2297
|
+
if (!base) throw new Error("target has no url");
|
|
2298
|
+
const modelId = target.defaultModel ?? "default";
|
|
2299
|
+
const req = {
|
|
2300
|
+
url: `${base}/reranking`,
|
|
2301
|
+
method: "POST",
|
|
2302
|
+
timeoutMs: ctx.httpTimeoutMs,
|
|
2303
|
+
headers: { "content-type": "application/json" },
|
|
2304
|
+
body: JSON.stringify({
|
|
2305
|
+
query,
|
|
2306
|
+
documents,
|
|
2307
|
+
top_n: documents.length,
|
|
2308
|
+
model: modelId
|
|
2309
|
+
})
|
|
2310
|
+
};
|
|
2311
|
+
const result = await (ctx.signal ? probeJson({ ...req, signal: ctx.signal }) : probeJson(req));
|
|
2312
|
+
if (!result.ok || !result.data) {
|
|
2313
|
+
throw new Error(`llama.cpp rerank failed: ${result.error ?? "unknown"}`);
|
|
2314
|
+
}
|
|
2315
|
+
const rows = result.data.results ?? [];
|
|
2316
|
+
const items = rows.map((row) => {
|
|
2317
|
+
const idx = typeof row.index === "number" ? row.index : 0;
|
|
2318
|
+
const score = typeof row.relevance_score === "number" ? row.relevance_score : 0;
|
|
2319
|
+
const doc = typeof row.document === "string" ? row.document : typeof row.document?.text === "string" ? row.document.text : void 0;
|
|
2320
|
+
const item = { index: idx, score };
|
|
2321
|
+
if (doc !== void 0) item.document = doc;
|
|
2322
|
+
return item;
|
|
2323
|
+
});
|
|
2324
|
+
return { items, model: result.data.model ?? modelId };
|
|
2325
|
+
}
|
|
2326
|
+
};
|
|
2327
|
+
var llamacpp_rerank_default = llamacppRerankRuntime;
|
|
2328
|
+
|
|
2329
|
+
// src/domains/providers/runtimes/local-native/lmstudio.ts
|
|
2330
|
+
init_esm_shims();
|
|
2331
|
+
|
|
2332
|
+
// src/domains/providers/runtimes/common/lmstudio-http.ts
|
|
2333
|
+
init_esm_shims();
|
|
2334
|
+
import { performance as performance3 } from "node:perf_hooks";
|
|
2335
|
+
var catalogsByHost = /* @__PURE__ */ new Map();
|
|
2336
|
+
function isRecord3(value) {
|
|
2337
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
2338
|
+
}
|
|
2339
|
+
function positiveNumber2(value) {
|
|
2340
|
+
return typeof value === "number" && Number.isFinite(value) && value > 0 ? value : void 0;
|
|
2341
|
+
}
|
|
2342
|
+
function nonEmptyString2(value) {
|
|
2343
|
+
return typeof value === "string" && value.trim().length > 0 ? value.trim() : void 0;
|
|
2344
|
+
}
|
|
2345
|
+
function lmStudioRootUrl(url2) {
|
|
2346
|
+
const normalized = targetRootUrl({ id: "lmstudio", runtime: "lmstudio", url: url2 });
|
|
2347
|
+
if (!normalized) return "";
|
|
2348
|
+
if (normalized.startsWith("ws://")) return `http://${normalized.slice("ws://".length)}`;
|
|
2349
|
+
if (normalized.startsWith("wss://")) return `https://${normalized.slice("wss://".length)}`;
|
|
2350
|
+
return normalized;
|
|
2351
|
+
}
|
|
2352
|
+
function lmStudioRequestHeaders(base, apiKey) {
|
|
2353
|
+
const headers = { ...base ?? {} };
|
|
2354
|
+
const token = apiKey?.trim();
|
|
2355
|
+
if (token) headers.authorization = `Bearer ${token}`;
|
|
2356
|
+
return headers;
|
|
2357
|
+
}
|
|
2358
|
+
function lmStudioProbeHeaders(target, ctx) {
|
|
2359
|
+
let token = ctx.authToken?.trim();
|
|
2360
|
+
const envName = target.auth?.apiKeyEnvVar;
|
|
2361
|
+
if (!token && envName && ctx.credentialsPresent.has(envName)) token = process.env[envName]?.trim();
|
|
2362
|
+
return lmStudioRequestHeaders(target.auth?.headers, token);
|
|
2363
|
+
}
|
|
2364
|
+
function combinedSignal(timeoutMs, signal) {
|
|
2365
|
+
const controller = new AbortController();
|
|
2366
|
+
const timer = setTimeout(() => controller.abort(new Error(`timeout after ${timeoutMs}ms`)), timeoutMs);
|
|
2367
|
+
const onAbort = () => controller.abort(signal?.reason);
|
|
2368
|
+
if (signal?.aborted) controller.abort(signal.reason);
|
|
2369
|
+
else signal?.addEventListener("abort", onAbort, { once: true });
|
|
2370
|
+
return {
|
|
2371
|
+
signal: controller.signal,
|
|
2372
|
+
close() {
|
|
2373
|
+
clearTimeout(timer);
|
|
2374
|
+
signal?.removeEventListener("abort", onAbort);
|
|
2375
|
+
}
|
|
2376
|
+
};
|
|
2377
|
+
}
|
|
2378
|
+
async function requestLmStudioJson(url2, init, timeoutMs, signal) {
|
|
2379
|
+
const started = performance3.now();
|
|
2380
|
+
const bounded = combinedSignal(timeoutMs, signal);
|
|
2381
|
+
try {
|
|
2382
|
+
const response = await fetch(url2, { ...init, signal: bounded.signal });
|
|
2383
|
+
let data;
|
|
2384
|
+
try {
|
|
2385
|
+
data = await response.json();
|
|
2386
|
+
} catch {
|
|
2387
|
+
data = void 0;
|
|
2388
|
+
}
|
|
2389
|
+
const result = {
|
|
2390
|
+
ok: response.ok,
|
|
2391
|
+
status: response.status,
|
|
2392
|
+
latencyMs: Math.round(performance3.now() - started)
|
|
2393
|
+
};
|
|
2394
|
+
if (data !== void 0) result.data = data;
|
|
2395
|
+
if (!response.ok) {
|
|
2396
|
+
const message = isRecord3(data) ? nonEmptyString2(data.error) : void 0;
|
|
2397
|
+
result.error = message ?? `HTTP ${response.status}`;
|
|
2398
|
+
}
|
|
2399
|
+
return result;
|
|
2400
|
+
} catch (error) {
|
|
2401
|
+
return {
|
|
2402
|
+
ok: false,
|
|
2403
|
+
status: 0,
|
|
2404
|
+
latencyMs: Math.round(performance3.now() - started),
|
|
2405
|
+
error: error instanceof Error ? error.message : String(error)
|
|
2406
|
+
};
|
|
2407
|
+
} finally {
|
|
2408
|
+
bounded.close();
|
|
2409
|
+
}
|
|
2410
|
+
}
|
|
2411
|
+
function loadedInstances(value) {
|
|
2412
|
+
if (!Array.isArray(value)) return [];
|
|
2413
|
+
const instances = [];
|
|
2414
|
+
for (const raw of value) {
|
|
2415
|
+
if (!isRecord3(raw)) continue;
|
|
2416
|
+
const id = nonEmptyString2(raw.id);
|
|
2417
|
+
if (!id) continue;
|
|
2418
|
+
instances.push({ id, config: isRecord3(raw.config) ? { ...raw.config } : {} });
|
|
2419
|
+
}
|
|
2420
|
+
return instances;
|
|
2421
|
+
}
|
|
2422
|
+
function reasoningOptions(capabilities2) {
|
|
2423
|
+
if (!isRecord3(capabilities2) || !isRecord3(capabilities2.reasoning)) return void 0;
|
|
2424
|
+
const allowed = capabilities2.reasoning.allowed_options;
|
|
2425
|
+
if (!Array.isArray(allowed)) return void 0;
|
|
2426
|
+
const options = allowed.filter((entry) => typeof entry === "string");
|
|
2427
|
+
return options.length > 0 ? options : void 0;
|
|
2428
|
+
}
|
|
2429
|
+
function parseLmStudioV1Models(data) {
|
|
2430
|
+
if (!isRecord3(data) || !Array.isArray(data.models)) return null;
|
|
2431
|
+
const models = [];
|
|
2432
|
+
for (const raw of data.models) {
|
|
2433
|
+
if (!isRecord3(raw)) continue;
|
|
2434
|
+
const key = nonEmptyString2(raw.key);
|
|
2435
|
+
if (!key) continue;
|
|
2436
|
+
const capabilities2 = isRecord3(raw.capabilities) ? raw.capabilities : void 0;
|
|
2437
|
+
const info = {
|
|
2438
|
+
key,
|
|
2439
|
+
loadedInstances: loadedInstances(raw.loaded_instances),
|
|
2440
|
+
metadata: { ...raw }
|
|
2441
|
+
};
|
|
2442
|
+
const type = nonEmptyString2(raw.type);
|
|
2443
|
+
if (type) info.type = type;
|
|
2444
|
+
const maxContextLength = positiveNumber2(raw.max_context_length);
|
|
2445
|
+
if (maxContextLength !== void 0) info.maxContextLength = maxContextLength;
|
|
2446
|
+
if (capabilities2 && typeof capabilities2.vision === "boolean") info.vision = capabilities2.vision;
|
|
2447
|
+
else if (type) info.vision = type === "vlm";
|
|
2448
|
+
if (capabilities2 && typeof capabilities2.trained_for_tool_use === "boolean") {
|
|
2449
|
+
info.tools = capabilities2.trained_for_tool_use;
|
|
2450
|
+
}
|
|
2451
|
+
const options = reasoningOptions(capabilities2);
|
|
2452
|
+
if (options) info.reasoningOptions = options;
|
|
2453
|
+
if (capabilities2 && "reasoning" in capabilities2) {
|
|
2454
|
+
info.reasoning = capabilities2.reasoning === true || isRecord3(capabilities2.reasoning);
|
|
2455
|
+
}
|
|
2456
|
+
models.push(info);
|
|
2457
|
+
}
|
|
2458
|
+
return models;
|
|
2459
|
+
}
|
|
2460
|
+
function foldLmStudioModels(models) {
|
|
2461
|
+
const byKey = /* @__PURE__ */ new Map();
|
|
2462
|
+
for (const model of models) {
|
|
2463
|
+
const previous = byKey.get(model.key);
|
|
2464
|
+
if (!previous) {
|
|
2465
|
+
byKey.set(model.key, { ...model, loadedInstances: [...model.loadedInstances] });
|
|
2466
|
+
continue;
|
|
2467
|
+
}
|
|
2468
|
+
const knownIds = new Set(previous.loadedInstances.map((instance) => instance.id));
|
|
2469
|
+
for (const instance of model.loadedInstances) {
|
|
2470
|
+
if (!knownIds.has(instance.id)) previous.loadedInstances.push(instance);
|
|
2471
|
+
}
|
|
2472
|
+
if (previous.maxContextLength === void 0 && model.maxContextLength !== void 0) {
|
|
2473
|
+
previous.maxContextLength = model.maxContextLength;
|
|
2474
|
+
}
|
|
2475
|
+
if (previous.vision === void 0 && model.vision !== void 0) previous.vision = model.vision;
|
|
2476
|
+
if (previous.tools === void 0 && model.tools !== void 0) previous.tools = model.tools;
|
|
2477
|
+
if (previous.reasoningOptions === void 0 && model.reasoningOptions !== void 0) {
|
|
2478
|
+
previous.reasoningOptions = model.reasoningOptions;
|
|
2479
|
+
}
|
|
2480
|
+
if (previous.reasoning === void 0 && model.reasoning !== void 0) previous.reasoning = model.reasoning;
|
|
2481
|
+
}
|
|
2482
|
+
return [...byKey.values()];
|
|
2483
|
+
}
|
|
2484
|
+
function rememberHostCatalog(target, models) {
|
|
2485
|
+
const rootUrl = lmStudioRootUrl(target.url ?? "");
|
|
2486
|
+
if (!rootUrl) return;
|
|
2487
|
+
catalogsByHost.set(rootUrl, { targetId: target.id, rootUrl, models: foldLmStudioModels(models) });
|
|
2488
|
+
}
|
|
2489
|
+
function peerTargetsFor(target, instanceId) {
|
|
2490
|
+
const rootUrl = lmStudioRootUrl(target.url ?? "");
|
|
2491
|
+
const peers = [];
|
|
2492
|
+
for (const catalog of catalogsByHost.values()) {
|
|
2493
|
+
if (catalog.rootUrl === rootUrl) continue;
|
|
2494
|
+
if (catalog.models.some((model) => model.loadedInstances.some((instance) => instance.id === instanceId))) {
|
|
2495
|
+
peers.push(catalog.targetId);
|
|
2496
|
+
}
|
|
2497
|
+
}
|
|
2498
|
+
return [...new Set(peers)];
|
|
2499
|
+
}
|
|
2500
|
+
function resolveLmStudioInstance(target, models, requestedId, configuredDefault) {
|
|
2501
|
+
const folded = foldLmStudioModels(models);
|
|
2502
|
+
for (const model of folded) {
|
|
2503
|
+
const explicit = model.loadedInstances.find((instance2) => instance2.id === requestedId);
|
|
2504
|
+
if (explicit) {
|
|
2505
|
+
return {
|
|
2506
|
+
requestedId,
|
|
2507
|
+
wireModelId: explicit.id,
|
|
2508
|
+
model,
|
|
2509
|
+
instance: explicit,
|
|
2510
|
+
peerTargets: peerTargetsFor(target, explicit.id),
|
|
2511
|
+
state: "instance"
|
|
2512
|
+
};
|
|
2513
|
+
}
|
|
2514
|
+
if (model.key !== requestedId) continue;
|
|
2515
|
+
if (model.loadedInstances.length === 0) {
|
|
2516
|
+
return { requestedId, wireModelId: requestedId, model, peerTargets: [], state: "jit" };
|
|
2517
|
+
}
|
|
2518
|
+
const preferred = configuredDefault ? model.loadedInstances.find((instance2) => instance2.id === configuredDefault) : void 0;
|
|
2519
|
+
const local = model.loadedInstances.find((instance2) => peerTargetsFor(target, instance2.id).length === 0);
|
|
2520
|
+
const instance = preferred ?? local ?? model.loadedInstances[0];
|
|
2521
|
+
if (!instance) return { requestedId, wireModelId: requestedId, model, peerTargets: [], state: "jit" };
|
|
2522
|
+
return {
|
|
2523
|
+
requestedId,
|
|
2524
|
+
wireModelId: instance.id,
|
|
2525
|
+
model,
|
|
2526
|
+
instance,
|
|
2527
|
+
peerTargets: peerTargetsFor(target, instance.id),
|
|
2528
|
+
state: "instance"
|
|
2529
|
+
};
|
|
2530
|
+
}
|
|
2531
|
+
return { requestedId, wireModelId: requestedId, peerTargets: [], state: "unknown" };
|
|
2532
|
+
}
|
|
2533
|
+
function lmStudioReasoningLevels(options) {
|
|
2534
|
+
if (!options || options.length === 0) return [...THINKING_LEVELS];
|
|
2535
|
+
if (options.includes("on") && !options.includes("low") && !options.includes("medium") && !options.includes("high")) {
|
|
2536
|
+
return ["off", "low"];
|
|
2537
|
+
}
|
|
2538
|
+
const levels = ["off"];
|
|
2539
|
+
if (options.includes("low")) levels.push("minimal", "low");
|
|
2540
|
+
if (options.includes("medium")) levels.push("medium");
|
|
2541
|
+
if (options.includes("high")) levels.push("high", "xhigh", "max");
|
|
2542
|
+
return [...new Set(levels)];
|
|
2543
|
+
}
|
|
2544
|
+
function lmStudioReasoningEffort(level, options) {
|
|
2545
|
+
if (level === "off") return "none";
|
|
2546
|
+
if (options?.includes("on") && !options.includes("medium") && !options.includes("high")) return "low";
|
|
2547
|
+
if (level === "medium" && options?.includes("medium") !== false) return "medium";
|
|
2548
|
+
if ((level === "high" || level === "xhigh" || level === "max") && options?.includes("high") !== false) return "high";
|
|
2549
|
+
return "low";
|
|
2550
|
+
}
|
|
2551
|
+
function v0Models(data) {
|
|
2552
|
+
if (!isRecord3(data) || !Array.isArray(data.data)) return null;
|
|
2553
|
+
const models = [];
|
|
2554
|
+
for (const raw of data.data) {
|
|
2555
|
+
if (!isRecord3(raw)) continue;
|
|
2556
|
+
const key = nonEmptyString2(raw.id);
|
|
2557
|
+
if (!key) continue;
|
|
2558
|
+
const state = nonEmptyString2(raw.state);
|
|
2559
|
+
const loadedContext = positiveNumber2(raw.loaded_context_length);
|
|
2560
|
+
const config = loadedContext === void 0 ? {} : { context_length: loadedContext };
|
|
2561
|
+
const info = {
|
|
2562
|
+
key,
|
|
2563
|
+
loadedInstances: state === "loaded" || loadedContext !== void 0 ? [{ id: key, config }] : [],
|
|
2564
|
+
metadata: { ...raw }
|
|
2565
|
+
};
|
|
2566
|
+
const type = nonEmptyString2(raw.type);
|
|
2567
|
+
if (type) {
|
|
2568
|
+
info.type = type;
|
|
2569
|
+
info.vision = type === "vlm";
|
|
2570
|
+
}
|
|
2571
|
+
const maxContextLength = positiveNumber2(raw.max_context_length);
|
|
2572
|
+
if (maxContextLength !== void 0) info.maxContextLength = maxContextLength;
|
|
2573
|
+
if (Array.isArray(raw.capabilities)) info.tools = raw.capabilities.includes("tool_use");
|
|
2574
|
+
models.push(info);
|
|
2575
|
+
}
|
|
2576
|
+
return models;
|
|
2577
|
+
}
|
|
2578
|
+
function openAIModels(data) {
|
|
2579
|
+
if (!isRecord3(data) || !Array.isArray(data.data)) return null;
|
|
2580
|
+
const models = [];
|
|
2581
|
+
for (const raw of data.data) {
|
|
2582
|
+
if (!isRecord3(raw)) continue;
|
|
2583
|
+
const key = nonEmptyString2(raw.id);
|
|
2584
|
+
if (key) models.push({ key, loadedInstances: [], metadata: { ...raw } });
|
|
2585
|
+
}
|
|
2586
|
+
return models;
|
|
2587
|
+
}
|
|
2588
|
+
function authFailure(result) {
|
|
2589
|
+
if (result.status !== 401 && result.status !== 403) return null;
|
|
2590
|
+
return {
|
|
2591
|
+
ok: false,
|
|
2592
|
+
models: [],
|
|
2593
|
+
latencyMs: result.latencyMs,
|
|
2594
|
+
error: "LM Studio authentication required",
|
|
2595
|
+
authRequired: true
|
|
2596
|
+
};
|
|
2597
|
+
}
|
|
2598
|
+
async function listLmStudioModels(target, ctx) {
|
|
2599
|
+
if (!target.url) return { ok: false, models: [], error: "target has no url" };
|
|
2600
|
+
const root = lmStudioRootUrl(target.url);
|
|
2601
|
+
const headers = lmStudioProbeHeaders(target, ctx);
|
|
2602
|
+
const init = { headers };
|
|
2603
|
+
const v1 = await requestLmStudioJson(`${root}/api/v1/models`, init, ctx.httpTimeoutMs, ctx.signal);
|
|
2604
|
+
const v1Auth = authFailure(v1);
|
|
2605
|
+
if (v1Auth) return v1Auth;
|
|
2606
|
+
const parsedV1 = parseLmStudioV1Models(v1.data);
|
|
2607
|
+
if (v1.ok && parsedV1) {
|
|
2608
|
+
rememberHostCatalog(target, parsedV1);
|
|
2609
|
+
return { ok: true, models: parsedV1, tier: "0.4+", latencyMs: v1.latencyMs };
|
|
2610
|
+
}
|
|
2611
|
+
const v0 = await requestLmStudioJson(`${root}/api/v0/models`, init, ctx.httpTimeoutMs, ctx.signal);
|
|
2612
|
+
const v0Auth = authFailure(v0);
|
|
2613
|
+
if (v0Auth) return v0Auth;
|
|
2614
|
+
const parsedV0 = v0Models(v0.data);
|
|
2615
|
+
if (v0.ok && parsedV0) {
|
|
2616
|
+
rememberHostCatalog(target, parsedV0);
|
|
2617
|
+
return { ok: true, models: parsedV0, tier: "0.3.x", latencyMs: v0.latencyMs };
|
|
2618
|
+
}
|
|
2619
|
+
const openAI = await requestLmStudioJson(`${root}/v1/models`, init, ctx.httpTimeoutMs, ctx.signal);
|
|
2620
|
+
const openAIAuth = authFailure(openAI);
|
|
2621
|
+
if (openAIAuth) return openAIAuth;
|
|
2622
|
+
const parsedOpenAI = openAIModels(openAI.data);
|
|
2623
|
+
if (openAI.ok && parsedOpenAI) {
|
|
2624
|
+
rememberHostCatalog(target, parsedOpenAI);
|
|
2625
|
+
return { ok: true, models: parsedOpenAI, tier: "openai-compat", latencyMs: openAI.latencyMs };
|
|
2626
|
+
}
|
|
2627
|
+
return {
|
|
2628
|
+
ok: false,
|
|
2629
|
+
models: [],
|
|
2630
|
+
latencyMs: v1.latencyMs + v0.latencyMs + openAI.latencyMs,
|
|
2631
|
+
error: v1.error ?? v0.error ?? openAI.error ?? "LM Studio returned no recognized model catalog"
|
|
2632
|
+
};
|
|
2633
|
+
}
|
|
2634
|
+
async function greetLmStudio(target, ctx) {
|
|
2635
|
+
if (!target.url) return { ok: false, error: "target has no url" };
|
|
2636
|
+
const result = await requestLmStudioJson(
|
|
2637
|
+
`${lmStudioRootUrl(target.url)}/lmstudio-greeting`,
|
|
2638
|
+
{ headers: lmStudioProbeHeaders(target, ctx) },
|
|
2639
|
+
ctx.httpTimeoutMs,
|
|
2640
|
+
ctx.signal
|
|
2641
|
+
);
|
|
2642
|
+
if (result.ok && isRecord3(result.data) && result.data.lmstudio === true) {
|
|
2643
|
+
return { ok: true, latencyMs: result.latencyMs };
|
|
2644
|
+
}
|
|
2645
|
+
return { ok: false, latencyMs: result.latencyMs, error: result.error ?? "endpoint did not return {lmstudio:true}" };
|
|
2646
|
+
}
|
|
2647
|
+
function loadedContextLength(instance) {
|
|
2648
|
+
return positiveNumber2(instance?.config.context_length);
|
|
2649
|
+
}
|
|
2650
|
+
|
|
2651
|
+
// src/domains/providers/runtimes/local-native/lmstudio.ts
|
|
2652
|
+
var defaultCapabilities21 = {
|
|
2653
|
+
chat: true,
|
|
2654
|
+
tools: true,
|
|
2655
|
+
toolCallFormat: "openai",
|
|
2656
|
+
structuredOutputs: "json-schema",
|
|
2657
|
+
reasoning: true,
|
|
2658
|
+
vision: true,
|
|
2659
|
+
audio: false,
|
|
2660
|
+
embeddings: false,
|
|
2661
|
+
rerank: false,
|
|
2662
|
+
fim: false,
|
|
2663
|
+
contextWindow: CLIO_MIN_CONTEXT_WINDOW,
|
|
2664
|
+
maxTokens: CLIO_MIN_MAX_OUTPUT_TOKENS
|
|
2665
|
+
};
|
|
2666
|
+
var reasoningOptionsByTargetModel = /* @__PURE__ */ new Map();
|
|
2667
|
+
function reasoningOptionsKey(target, modelId) {
|
|
2668
|
+
const url2 = (target.url ?? "").replace(/^ws:/u, "http:").replace(/^wss:/u, "https:").replace(/\/$/u, "");
|
|
2669
|
+
return `${target.id}|${url2}|${modelId}`;
|
|
2670
|
+
}
|
|
2671
|
+
function rememberReasoningOptions(target, models) {
|
|
2672
|
+
const prefix = reasoningOptionsKey(target, "");
|
|
2673
|
+
for (const key of reasoningOptionsByTargetModel.keys()) {
|
|
2674
|
+
if (key.startsWith(prefix)) reasoningOptionsByTargetModel.delete(key);
|
|
2675
|
+
}
|
|
2676
|
+
for (const model of models) {
|
|
2677
|
+
if (!model.reasoningOptions) continue;
|
|
2678
|
+
reasoningOptionsByTargetModel.set(reasoningOptionsKey(target, model.key), model.reasoningOptions);
|
|
2679
|
+
for (const instance of model.loadedInstances) {
|
|
2680
|
+
reasoningOptionsByTargetModel.set(reasoningOptionsKey(target, instance.id), model.reasoningOptions);
|
|
2681
|
+
}
|
|
2682
|
+
}
|
|
2683
|
+
}
|
|
2684
|
+
function configuredModel(target) {
|
|
2685
|
+
const id = target.defaultModel?.trim();
|
|
2686
|
+
return id && id.length > 0 ? id : void 0;
|
|
2687
|
+
}
|
|
2688
|
+
function resolveModel(models, id) {
|
|
2689
|
+
if (id) {
|
|
2690
|
+
for (const model2 of models) {
|
|
2691
|
+
if (model2.key === id) return { model: model2, ...model2.loadedInstances[0] ? { instance: model2.loadedInstances[0] } : {} };
|
|
2692
|
+
const instance = model2.loadedInstances.find((entry) => entry.id === id);
|
|
2693
|
+
if (instance) return { model: model2, instance };
|
|
2694
|
+
}
|
|
2695
|
+
return null;
|
|
2696
|
+
}
|
|
2697
|
+
const model = models.find((entry) => entry.loadedInstances.length > 0) ?? models[0];
|
|
2698
|
+
return model ? { model, ...model.loadedInstances[0] ? { instance: model.loadedInstances[0] } : {} } : null;
|
|
2699
|
+
}
|
|
2700
|
+
function capabilities(model, instance) {
|
|
2701
|
+
const out = {};
|
|
2702
|
+
if (model.vision !== void 0) out.vision = model.vision;
|
|
2703
|
+
if (model.tools !== void 0) out.tools = model.tools;
|
|
2704
|
+
if (model.reasoning !== void 0) out.reasoning = model.reasoning;
|
|
2705
|
+
else if (model.reasoningOptions !== void 0)
|
|
2706
|
+
out.reasoning = model.reasoningOptions.some((option) => option !== "off");
|
|
2707
|
+
const contextWindow = loadedContextLength(instance) ?? model.maxContextLength;
|
|
2708
|
+
if (contextWindow !== void 0) out.contextWindow = contextWindow;
|
|
2709
|
+
const parallel = instance?.config.parallel;
|
|
2710
|
+
if (typeof parallel === "number" && Number.isInteger(parallel) && parallel > 0) out.parallelSlots = parallel;
|
|
2711
|
+
return out;
|
|
2712
|
+
}
|
|
2713
|
+
function statusFor(model, instance, reasoningLevels) {
|
|
2714
|
+
const status = {
|
|
2715
|
+
state: instance ? "loaded" : "unloaded",
|
|
2716
|
+
key: model.key,
|
|
2717
|
+
reasoningLevels
|
|
2718
|
+
};
|
|
2719
|
+
if (instance) {
|
|
2720
|
+
status.instanceId = instance.id;
|
|
2721
|
+
status.loadConfig = instance.config;
|
|
2722
|
+
const contextLength = loadedContextLength(instance);
|
|
2723
|
+
if (contextLength !== void 0) status.contextLength = contextLength;
|
|
2724
|
+
}
|
|
2725
|
+
return status;
|
|
2726
|
+
}
|
|
2727
|
+
function probeFromCatalog(catalog, target) {
|
|
2728
|
+
if (!catalog.ok) {
|
|
2729
|
+
return {
|
|
2730
|
+
ok: false,
|
|
2731
|
+
...catalog.latencyMs !== void 0 ? { latencyMs: catalog.latencyMs } : {},
|
|
2732
|
+
error: catalog.error ?? "LM Studio model listing failed"
|
|
2733
|
+
};
|
|
2734
|
+
}
|
|
2735
|
+
const models = foldLmStudioModels(catalog.models);
|
|
2736
|
+
rememberReasoningOptions(target, models);
|
|
2737
|
+
const ids = [];
|
|
2738
|
+
const modelCapabilities = {};
|
|
2739
|
+
const modelStates = {};
|
|
2740
|
+
for (const model of models) {
|
|
2741
|
+
const levels = lmStudioReasoningLevels(model.reasoningOptions);
|
|
2742
|
+
const keyInstance = model.loadedInstances[0];
|
|
2743
|
+
modelCapabilities[model.key] = capabilities(model, keyInstance);
|
|
2744
|
+
modelStates[model.key] = statusFor(model, keyInstance, levels);
|
|
2745
|
+
for (const instance of model.loadedInstances) {
|
|
2746
|
+
if (!ids.includes(instance.id)) ids.push(instance.id);
|
|
2747
|
+
modelCapabilities[instance.id] = capabilities(model, instance);
|
|
2748
|
+
const instanceStatus = statusFor(model, instance, levels);
|
|
2749
|
+
modelStates[instance.id] = instanceStatus;
|
|
2750
|
+
const resolution = resolveLmStudioInstance(target, models, instance.id, configuredModel(target));
|
|
2751
|
+
instanceStatus.detail = resolution.peerTargets.length > 0 ? `loaded on ${target.id}; also loaded on ${resolution.peerTargets.join(", ")}` : `loaded on ${target.id}`;
|
|
2752
|
+
}
|
|
2753
|
+
if (model.loadedInstances.length === 0) {
|
|
2754
|
+
ids.push(model.key);
|
|
2755
|
+
const keyStatus = modelStates[model.key];
|
|
2756
|
+
if (keyStatus) keyStatus.detail = "not loaded (LM Studio will load it on first use)";
|
|
2757
|
+
}
|
|
2758
|
+
}
|
|
2759
|
+
const selected = resolveModel(models, configuredModel(target));
|
|
2760
|
+
const result = {
|
|
2761
|
+
ok: true,
|
|
2762
|
+
discoveredCapabilities: { parallelSlots: 1 },
|
|
2763
|
+
models: ids,
|
|
2764
|
+
modelCapabilities,
|
|
2765
|
+
modelStates,
|
|
2766
|
+
serverVersion: catalog.tier === "0.4+" ? "LM Studio API 0.4+" : catalog.tier === "0.3.x" ? "LM Studio API 0.3.x" : "LM Studio OpenAI-compatible API",
|
|
2767
|
+
surfaces: {
|
|
2768
|
+
openaiChat: "/v1/chat/completions",
|
|
2769
|
+
...catalog.tier === "0.4+" ? { nativeV1: "/api/v1/models" } : {},
|
|
2770
|
+
...catalog.tier === "0.3.x" ? { nativeV0: "/api/v0/models" } : {}
|
|
2771
|
+
}
|
|
2772
|
+
};
|
|
2773
|
+
if (catalog.latencyMs !== void 0) result.latencyMs = catalog.latencyMs;
|
|
2774
|
+
if (selected) {
|
|
2775
|
+
result.discoveredCapabilities = { parallelSlots: 1, ...capabilities(selected.model, selected.instance) };
|
|
2776
|
+
result.capabilityModelId = configuredModel(target) ?? selected.model.key;
|
|
2777
|
+
}
|
|
2778
|
+
const loaded = models.flatMap(
|
|
2779
|
+
(model) => model.loadedInstances.map((instance) => {
|
|
2780
|
+
const context = loadedContextLength(instance);
|
|
2781
|
+
return `${model.key} as ${instance.id}${context ? ` at ${context} tokens` : ""}`;
|
|
2782
|
+
})
|
|
2783
|
+
);
|
|
2784
|
+
result.notes = [
|
|
2785
|
+
`LM Studio surface tier ${catalog.tier ?? "unknown"}`,
|
|
2786
|
+
`Surfaces: ${Object.values(result.surfaces ?? {}).join(", ")}`,
|
|
2787
|
+
...loaded.length > 0 ? [`Loaded instances: ${loaded.join(", ")}`] : []
|
|
2788
|
+
];
|
|
2789
|
+
return result;
|
|
2790
|
+
}
|
|
2791
|
+
var lmstudioRuntime = {
|
|
2792
|
+
id: "lmstudio",
|
|
2793
|
+
aliases: ["lmstudio-native"],
|
|
2794
|
+
displayName: "LM Studio",
|
|
2795
|
+
kind: "http",
|
|
2796
|
+
tier: "local-native",
|
|
2797
|
+
apiFamily: "openai-completions",
|
|
2798
|
+
auth: "api-key",
|
|
2799
|
+
defaultCapabilities: defaultCapabilities21,
|
|
2800
|
+
async probe(target, ctx) {
|
|
2801
|
+
const [greeting, catalog] = await Promise.all([greetLmStudio(target, ctx), listLmStudioModels(target, ctx)]);
|
|
2802
|
+
if (!greeting.ok && catalog.tier !== "0.3.x") {
|
|
2803
|
+
return {
|
|
2804
|
+
ok: false,
|
|
2805
|
+
...greeting.latencyMs !== void 0 ? { latencyMs: greeting.latencyMs } : {},
|
|
2806
|
+
error: `URL did not identify itself as LM Studio: ${greeting.error ?? "greeting missing"}`
|
|
2807
|
+
};
|
|
2808
|
+
}
|
|
2809
|
+
return probeFromCatalog(catalog, target);
|
|
2810
|
+
},
|
|
2811
|
+
async probeModels(target, ctx) {
|
|
2812
|
+
const catalog = await listLmStudioModels(target, ctx);
|
|
2813
|
+
return probeFromCatalog(catalog, target).models ?? [];
|
|
2814
|
+
},
|
|
2815
|
+
synthesizeModel(target, wireModelId, kb) {
|
|
2816
|
+
const canonicalTarget = target.runtime === "lmstudio" ? target : { ...target, runtime: "lmstudio" };
|
|
2817
|
+
const model = synthLocalModel({
|
|
2818
|
+
target: canonicalTarget,
|
|
2819
|
+
wireModelId,
|
|
2820
|
+
kb,
|
|
2821
|
+
defaultCapabilities: defaultCapabilities21,
|
|
2822
|
+
apiFamily: "openai-completions",
|
|
2823
|
+
provider: "lmstudio",
|
|
2824
|
+
baseUrlForTarget: (url2) => withV1(url2.replace(/^ws:/u, "http:").replace(/^wss:/u, "https:"))
|
|
2825
|
+
});
|
|
2826
|
+
const metadata = model.clio;
|
|
2827
|
+
if (metadata) {
|
|
2828
|
+
metadata.chatTemplateKwargsUnsupported = true;
|
|
2829
|
+
if (target.defaultModel) metadata.lmstudioDefaultModel = target.defaultModel;
|
|
2830
|
+
const options = reasoningOptionsByTargetModel.get(reasoningOptionsKey(canonicalTarget, wireModelId));
|
|
2831
|
+
if (options) metadata.lmstudioReasoningOptions = options;
|
|
2832
|
+
}
|
|
2833
|
+
return model;
|
|
2834
|
+
}
|
|
2835
|
+
};
|
|
2836
|
+
var lmstudio_default = lmstudioRuntime;
|
|
2837
|
+
|
|
2838
|
+
// src/domains/providers/runtimes/local-native/ollama-native.ts
|
|
2839
|
+
init_esm_shims();
|
|
2840
|
+
var defaultCapabilities22 = {
|
|
2841
|
+
chat: true,
|
|
2842
|
+
tools: true,
|
|
2843
|
+
toolCallFormat: "openai",
|
|
2844
|
+
reasoning: false,
|
|
2845
|
+
vision: false,
|
|
2846
|
+
audio: false,
|
|
2847
|
+
embeddings: false,
|
|
2848
|
+
rerank: false,
|
|
2849
|
+
fim: false,
|
|
2850
|
+
contextWindow: CLIO_MIN_CONTEXT_WINDOW,
|
|
2851
|
+
maxTokens: CLIO_MIN_MAX_OUTPUT_TOKENS
|
|
2852
|
+
};
|
|
2853
|
+
function positiveNumber3(value) {
|
|
2854
|
+
return typeof value === "number" && Number.isFinite(value) && value > 0 ? value : void 0;
|
|
2855
|
+
}
|
|
2856
|
+
function ollamaParallelSlots() {
|
|
2857
|
+
const parsed = Number(process.env.OLLAMA_NUM_PARALLEL);
|
|
2858
|
+
return Number.isInteger(parsed) && parsed > 0 ? parsed : 1;
|
|
2859
|
+
}
|
|
2860
|
+
async function probeResidentModelStates(base, ctx) {
|
|
2861
|
+
const opts = { url: `${base}/api/ps`, timeoutMs: ctx.httpTimeoutMs };
|
|
2862
|
+
const result = await (ctx.signal ? probeJson({ ...opts, signal: ctx.signal }) : probeJson(opts));
|
|
2863
|
+
if (!result.ok || !result.data?.models) return void 0;
|
|
2864
|
+
const states = {};
|
|
2865
|
+
for (const row of result.data.models) {
|
|
2866
|
+
const id = typeof row?.model === "string" ? row.model : typeof row?.name === "string" ? row.name : null;
|
|
2867
|
+
if (!id) continue;
|
|
2868
|
+
const status = { state: "loaded" };
|
|
2869
|
+
const sizeVram = positiveNumber3(row?.size_vram);
|
|
2870
|
+
if (sizeVram !== void 0) status.sizeVramBytes = sizeVram;
|
|
2871
|
+
const size = positiveNumber3(row?.size);
|
|
2872
|
+
if (size !== void 0) status.sizeBytes = size;
|
|
2873
|
+
states[id] = status;
|
|
2874
|
+
}
|
|
2875
|
+
return Object.keys(states).length > 0 ? states : void 0;
|
|
2876
|
+
}
|
|
2877
|
+
var ollamaNativeRuntime = {
|
|
2878
|
+
id: "ollama-native",
|
|
2879
|
+
displayName: "Ollama (native)",
|
|
2880
|
+
kind: "http",
|
|
2881
|
+
tier: "local-native",
|
|
2882
|
+
apiFamily: "ollama-native",
|
|
2883
|
+
auth: "none",
|
|
2884
|
+
defaultCapabilities: defaultCapabilities22,
|
|
2885
|
+
async probe(target, ctx) {
|
|
2886
|
+
const base = targetBaseUrl(target);
|
|
2887
|
+
if (!base) return { ok: false, error: "target has no url" };
|
|
2888
|
+
const opts = { url: `${base}/api/tags`, timeoutMs: ctx.httpTimeoutMs };
|
|
2889
|
+
const result = await (ctx.signal ? probeJson({ ...opts, signal: ctx.signal }) : probeJson(opts));
|
|
2890
|
+
if (!result.ok) {
|
|
2891
|
+
const failed = { ok: false };
|
|
2892
|
+
if (result.error) failed.error = result.error;
|
|
2893
|
+
if (result.latencyMs !== void 0) failed.latencyMs = result.latencyMs;
|
|
2894
|
+
return failed;
|
|
2895
|
+
}
|
|
2896
|
+
const out = { ok: true, discoveredCapabilities: { parallelSlots: ollamaParallelSlots() } };
|
|
2897
|
+
if (result.latencyMs !== void 0) out.latencyMs = result.latencyMs;
|
|
2898
|
+
const modelStates = await probeResidentModelStates(base, ctx);
|
|
2899
|
+
if (modelStates) out.modelStates = modelStates;
|
|
2900
|
+
return out;
|
|
2901
|
+
},
|
|
2902
|
+
async probeModels(target, ctx) {
|
|
2903
|
+
const base = targetBaseUrl(target);
|
|
2904
|
+
if (!base) return [];
|
|
2905
|
+
const opts = { url: `${base}/api/tags`, timeoutMs: ctx.httpTimeoutMs };
|
|
2906
|
+
const result = await (ctx.signal ? probeJson({ ...opts, signal: ctx.signal }) : probeJson(opts));
|
|
2907
|
+
if (!result.ok || !result.data?.models) return [];
|
|
2908
|
+
return result.data.models.map((row) => typeof row?.name === "string" ? row.name : null).filter((name) => name !== null);
|
|
2909
|
+
},
|
|
2910
|
+
synthesizeModel(target, wireModelId, kb) {
|
|
2911
|
+
return synthLocalModel({
|
|
2912
|
+
target,
|
|
2913
|
+
wireModelId,
|
|
2914
|
+
kb,
|
|
2915
|
+
defaultCapabilities: defaultCapabilities22,
|
|
2916
|
+
apiFamily: "ollama-native",
|
|
2917
|
+
provider: "ollama",
|
|
2918
|
+
baseUrlForTarget: withAsIs
|
|
2919
|
+
});
|
|
2920
|
+
}
|
|
2921
|
+
};
|
|
2922
|
+
var ollama_native_default = ollamaNativeRuntime;
|
|
2923
|
+
|
|
2924
|
+
// src/domains/providers/runtimes/local-native/sglang.ts
|
|
2925
|
+
init_esm_shims();
|
|
2926
|
+
var defaultCapabilities23 = {
|
|
2927
|
+
chat: true,
|
|
2928
|
+
tools: true,
|
|
2929
|
+
toolCallFormat: "openai",
|
|
2930
|
+
reasoning: false,
|
|
2931
|
+
vision: false,
|
|
2932
|
+
audio: false,
|
|
2933
|
+
embeddings: false,
|
|
2934
|
+
rerank: false,
|
|
2935
|
+
fim: false,
|
|
2936
|
+
contextWindow: CLIO_MIN_CONTEXT_WINDOW,
|
|
2937
|
+
maxTokens: CLIO_MIN_MAX_OUTPUT_TOKENS
|
|
2938
|
+
};
|
|
2939
|
+
var sglang_default = makeOpenAICompatRuntime({
|
|
2940
|
+
id: "sglang",
|
|
2941
|
+
displayName: "SGLang",
|
|
2942
|
+
provider: "sglang",
|
|
2943
|
+
auth: "api-key",
|
|
2944
|
+
tier: "local-native",
|
|
2945
|
+
defaultCapabilities: defaultCapabilities23
|
|
2946
|
+
});
|
|
2947
|
+
|
|
2948
|
+
// src/domains/providers/runtimes/local-native/vllm.ts
|
|
2949
|
+
init_esm_shims();
|
|
2950
|
+
var defaultCapabilities24 = {
|
|
2951
|
+
chat: true,
|
|
2952
|
+
tools: true,
|
|
2953
|
+
toolCallFormat: "openai",
|
|
2954
|
+
reasoning: false,
|
|
2955
|
+
vision: false,
|
|
2956
|
+
audio: false,
|
|
2957
|
+
embeddings: false,
|
|
2958
|
+
rerank: false,
|
|
2959
|
+
fim: false,
|
|
2960
|
+
contextWindow: CLIO_MIN_CONTEXT_WINDOW,
|
|
2961
|
+
maxTokens: CLIO_MIN_MAX_OUTPUT_TOKENS
|
|
2962
|
+
};
|
|
2963
|
+
var vllm_default = makeOpenAICompatRuntime({
|
|
2964
|
+
id: "vllm",
|
|
2965
|
+
displayName: "vLLM",
|
|
2966
|
+
provider: "vllm",
|
|
2967
|
+
auth: "api-key",
|
|
2968
|
+
tier: "local-native",
|
|
2969
|
+
defaultCapabilities: defaultCapabilities24,
|
|
2970
|
+
healthPath: "/health"
|
|
2971
|
+
});
|
|
2972
|
+
|
|
2973
|
+
// src/domains/providers/runtimes/builtins.ts
|
|
2974
|
+
var BUILTIN_RUNTIMES = [
|
|
2975
|
+
alcf_default,
|
|
2976
|
+
anthropic_default,
|
|
2977
|
+
anthropic_max_default,
|
|
2978
|
+
bedrock_default,
|
|
2979
|
+
deepseek_default,
|
|
2980
|
+
google_default,
|
|
2981
|
+
groq_default,
|
|
2982
|
+
mistral_default,
|
|
2983
|
+
openai_default,
|
|
2984
|
+
openai_codex_default,
|
|
2985
|
+
openrouter_default,
|
|
2986
|
+
lemonade_anthropic_default,
|
|
2987
|
+
lemonade_openai_default,
|
|
2988
|
+
llamacpp_default,
|
|
2989
|
+
llamacpp_anthropic_default,
|
|
2990
|
+
llamacpp_completion_default,
|
|
2991
|
+
llamacpp_embed_default,
|
|
2992
|
+
llamacpp_rerank_default,
|
|
2993
|
+
lmstudio_default,
|
|
2994
|
+
ollama_native_default,
|
|
2995
|
+
anthropic_compat_default,
|
|
2996
|
+
openai_compat_default,
|
|
2997
|
+
sglang_default,
|
|
2998
|
+
vllm_default,
|
|
2999
|
+
claude_code_default,
|
|
3000
|
+
claude_sdk_default,
|
|
3001
|
+
antigravity_code_default
|
|
3002
|
+
];
|
|
3003
|
+
function registerBuiltinRuntimes(registry) {
|
|
3004
|
+
for (const desc of BUILTIN_RUNTIMES) {
|
|
3005
|
+
if (registry.get(desc.id) !== null) continue;
|
|
3006
|
+
registry.register(desc);
|
|
3007
|
+
}
|
|
3008
|
+
}
|
|
3009
|
+
|
|
3010
|
+
export {
|
|
3011
|
+
CLIO_MIN_CONTEXT_WINDOW,
|
|
3012
|
+
CLIO_MIN_MAX_OUTPUT_TOKENS,
|
|
3013
|
+
CLIO_CONTEXT_WINDOW_WARN_BELOW,
|
|
3014
|
+
extractLocalModelQuirks,
|
|
3015
|
+
lmStudioRootUrl,
|
|
3016
|
+
requestLmStudioJson,
|
|
3017
|
+
resolveLmStudioInstance,
|
|
3018
|
+
lmStudioReasoningEffort,
|
|
3019
|
+
listLmStudioModels,
|
|
3020
|
+
greetLmStudio,
|
|
3021
|
+
formatContextWindowSlots,
|
|
3022
|
+
BUILTIN_RUNTIMES,
|
|
3023
|
+
registerBuiltinRuntimes
|
|
3024
|
+
};
|
|
3025
|
+
//# sourceMappingURL=chunk-JEQQR47K.js.map
|