@bendyline/gezel-inference 0.0.0-stage → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +13 -2
- package/dist/cache/adapter.d.ts +115 -0
- package/dist/cache/adapter.js +23 -0
- package/dist/cache/budget.d.ts +15 -0
- package/dist/cache/budget.js +31 -0
- package/dist/cache/controller.d.ts +205 -0
- package/dist/cache/controller.js +377 -0
- package/dist/catalog/LICENSE +21 -0
- package/dist/catalog/chat-models/bt/btl4-35b-q4/manifest.json +146 -0
- package/dist/catalog/chat-models/bt/btl4-35b-q4/versions/1.0.0/manifest.json +15 -0
- package/dist/catalog/chat-models/bt/btl4-35b-q4/versions/1.0.1/manifest.json +15 -0
- package/dist/catalog/chat-models/bt/btl4-compact-iq2/manifest.json +146 -0
- package/dist/catalog/chat-models/bt/btl4-compact-iq2/versions/1.0.0/manifest.json +15 -0
- package/dist/catalog/chat-models/bt/btl4-compact-iq2/versions/1.0.1/manifest.json +15 -0
- package/dist/catalog/chat-models/bt/btl4-compact-iq2/versions/1.0.2/manifest.json +15 -0
- package/dist/catalog/chat-models/de/deepseek-r1-8b-q4/manifest.json +166 -0
- package/dist/catalog/chat-models/de/deepseek-r1-8b-q4/versions/1.1.0/manifest.json +62 -0
- package/dist/catalog/chat-models/de/deepseek-r1-8b-q4/versions/1.1.1/manifest.json +61 -0
- package/dist/catalog/chat-models/de/deepseek-v4-flash-284b-mxfp4/manifest.json +125 -0
- package/dist/catalog/chat-models/de/deepseek-v4-flash-284b-mxfp4/versions/1.0.0/manifest.json +27 -0
- package/dist/catalog/chat-models/de/deepseek-v4-flash-284b-q2/manifest.json +125 -0
- package/dist/catalog/chat-models/de/deepseek-v4-flash-284b-q2/versions/1.0.0/manifest.json +27 -0
- package/dist/catalog/chat-models/de/deepseek-v4-flash-284b-q2/versions/1.1.0/manifest.json +27 -0
- package/dist/catalog/chat-models/de/deepseek-v4-flash-284b-q2q4/manifest.json +126 -0
- package/dist/catalog/chat-models/de/deepseek-v4-flash-284b-q2q4/versions/1.0.0/manifest.json +27 -0
- package/dist/catalog/chat-models/de/deepseek-v4-flash-284b-q4/manifest.json +318 -0
- package/dist/catalog/chat-models/de/deepseek-v4-flash-284b-q4/versions/1.0.0/manifest.json +225 -0
- package/dist/catalog/chat-models/de/deepseek-v4-flash-284b-q4/versions/1.1.0/manifest.json +225 -0
- package/dist/catalog/chat-models/ge/gemma4-12b-q4/manifest.json +249 -0
- package/dist/catalog/chat-models/ge/gemma4-12b-q4/versions/1.0.0/manifest.json +70 -0
- package/dist/catalog/chat-models/ge/gemma4-12b-q4/versions/1.1.0/manifest.json +72 -0
- package/dist/catalog/chat-models/ge/gemma4-12b-q4/versions/1.1.2/manifest.json +78 -0
- package/dist/catalog/chat-models/ge/gemma4-12b-q4/versions/1.1.3/manifest.json +78 -0
- package/dist/catalog/chat-models/ge/gemma4-12b-q4/versions/1.2.0/manifest.json +98 -0
- package/dist/catalog/chat-models/ge/gemma4-12b-q8/manifest.json +228 -0
- package/dist/catalog/chat-models/ge/gemma4-12b-q8/versions/1.0.0/manifest.json +72 -0
- package/dist/catalog/chat-models/ge/gemma4-12b-q8/versions/1.0.2/manifest.json +78 -0
- package/dist/catalog/chat-models/ge/gemma4-12b-q8/versions/1.0.3/manifest.json +78 -0
- package/dist/catalog/chat-models/ge/gemma4-12b-q8/versions/1.1.0/manifest.json +78 -0
- package/dist/catalog/chat-models/ge/gemma4-26b-q4/manifest.json +220 -0
- package/dist/catalog/chat-models/ge/gemma4-26b-q4/versions/1.1.0/manifest.json +75 -0
- package/dist/catalog/chat-models/ge/gemma4-26b-q4/versions/1.2.0/manifest.json +75 -0
- package/dist/catalog/chat-models/ge/gemma4-26b-q4/versions/1.2.1/manifest.json +80 -0
- package/dist/catalog/chat-models/ge/gemma4-26b-q4/versions/1.2.2/manifest.json +80 -0
- package/dist/catalog/chat-models/ge/gemma4-26b-q4/versions/1.3.0/manifest.json +81 -0
- package/dist/catalog/chat-models/ge/gemma4-31b-q4/manifest.json +226 -0
- package/dist/catalog/chat-models/ge/gemma4-31b-q4/versions/1.1.0/manifest.json +80 -0
- package/dist/catalog/chat-models/ge/gemma4-31b-q4/versions/1.1.1/manifest.json +82 -0
- package/dist/catalog/chat-models/ge/gemma4-31b-q4/versions/1.2.0/manifest.json +82 -0
- package/dist/catalog/chat-models/ge/gemma4-31b-q4/versions/1.2.1/manifest.json +95 -0
- package/dist/catalog/chat-models/ge/gemma4-31b-q4/versions/1.2.2/manifest.json +95 -0
- package/dist/catalog/chat-models/ge/gemma4-31b-q4/versions/1.3.0/manifest.json +86 -0
- package/dist/catalog/chat-models/ge/gemma4-e2b-q4/manifest.json +213 -0
- package/dist/catalog/chat-models/ge/gemma4-e2b-q4/versions/1.1.0/manifest.json +67 -0
- package/dist/catalog/chat-models/ge/gemma4-e2b-q4/versions/1.1.2/manifest.json +75 -0
- package/dist/catalog/chat-models/ge/gemma4-e2b-q4/versions/1.2.0/manifest.json +71 -0
- package/dist/catalog/chat-models/ge/gemma4-e2b-q4/versions/1.2.1/manifest.json +71 -0
- package/dist/catalog/chat-models/ge/gemma4-e2b-q4/versions/1.3.0/manifest.json +71 -0
- package/dist/catalog/chat-models/ge/gemma4-e4b-q4/manifest.json +205 -0
- package/dist/catalog/chat-models/ge/gemma4-e4b-q4/versions/1.1.0/manifest.json +72 -0
- package/dist/catalog/chat-models/ge/gemma4-e4b-q4/versions/1.1.2/manifest.json +75 -0
- package/dist/catalog/chat-models/ge/gemma4-e4b-q4/versions/1.2.0/manifest.json +76 -0
- package/dist/catalog/chat-models/ge/gemma4-e4b-q4/versions/1.2.1/manifest.json +76 -0
- package/dist/catalog/chat-models/ge/gemma4-e4b-q4/versions/1.3.0/manifest.json +76 -0
- package/dist/catalog/chat-models/gl/glm-5.2-754b-q2/manifest.json +127 -0
- package/dist/catalog/chat-models/gl/glm-5.2-754b-q2/versions/1.0.0/manifest.json +20 -0
- package/dist/catalog/chat-models/gl/glm-5.3-flash-320b-q2/manifest.json +140 -0
- package/dist/catalog/chat-models/gl/glm-5.3-flash-320b-q2/versions/1.0.0/manifest.json +23 -0
- package/dist/catalog/chat-models/gl/glm-5.3-flash-320b-q2/versions/1.0.1/manifest.json +26 -0
- package/dist/catalog/chat-models/gp/gpt-oss-120b-q4/manifest.json +247 -0
- package/dist/catalog/chat-models/gp/gpt-oss-120b-q4/versions/1.0.0/manifest.json +137 -0
- package/dist/catalog/chat-models/gp/gpt-oss-120b-q4/versions/1.1.0/manifest.json +135 -0
- package/dist/catalog/chat-models/gp/gpt-oss-20b-q4/manifest.json +195 -0
- package/dist/catalog/chat-models/gp/gpt-oss-20b-q4/versions/1.1.0/manifest.json +72 -0
- package/dist/catalog/chat-models/gp/gpt-oss-20b-q4/versions/1.1.1/manifest.json +71 -0
- package/dist/catalog/chat-models/gr/granite4.2-30b-q4/manifest.json +200 -0
- package/dist/catalog/chat-models/gr/granite4.2-30b-q4/versions/1.0.0/manifest.json +72 -0
- package/dist/catalog/chat-models/gr/granite4.2-3b-q4/manifest.json +196 -0
- package/dist/catalog/chat-models/gr/granite4.2-3b-q4/versions/1.0.0/manifest.json +57 -0
- package/dist/catalog/chat-models/gr/granite4.2-8b-q4/manifest.json +189 -0
- package/dist/catalog/chat-models/gr/granite4.2-8b-q4/versions/1.0.0/manifest.json +57 -0
- package/dist/catalog/chat-models/index.json +1 -0
- package/dist/catalog/chat-models/la/laguna-s-2.1-118b-q4/manifest.json +235 -0
- package/dist/catalog/chat-models/la/laguna-s-2.1-118b-q4/versions/1.0.0/manifest.json +124 -0
- package/dist/catalog/chat-models/la/laguna-s-2.1-118b-q4/versions/1.0.1/manifest.json +124 -0
- package/dist/catalog/chat-models/la/laguna-s-2.1-118b-q4/versions/1.0.2/manifest.json +123 -0
- package/dist/catalog/chat-models/la/laguna-s-2.1-118b-q6/manifest.json +257 -0
- package/dist/catalog/chat-models/la/laguna-s-2.1-118b-q6/versions/1.0.0/manifest.json +145 -0
- package/dist/catalog/chat-models/la/laguna-s-2.1-118b-q6/versions/1.0.1/manifest.json +145 -0
- package/dist/catalog/chat-models/la/laguna-s-2.1-118b-q8/manifest.json +285 -0
- package/dist/catalog/chat-models/la/laguna-s-2.1-118b-q8/versions/1.0.0/manifest.json +174 -0
- package/dist/catalog/chat-models/la/laguna-s-2.1-118b-q8/versions/1.0.1/manifest.json +174 -0
- package/dist/catalog/chat-models/la/laguna-s-2.1-118b-q8/versions/1.0.2/manifest.json +173 -0
- package/dist/catalog/chat-models/lf/lfm2.5-2.6b-q4/manifest.json +162 -0
- package/dist/catalog/chat-models/lf/lfm2.5-2.6b-q4/versions/1.0.0/manifest.json +59 -0
- package/dist/catalog/chat-models/lf/lfm2.5-2.6b-q4/versions/1.0.1/manifest.json +58 -0
- package/dist/catalog/chat-models/ll/llama3.2-3b-q4/manifest.json +134 -0
- package/dist/catalog/chat-models/ll/llama3.2-3b-q4/versions/1.1.0/manifest.json +57 -0
- package/dist/catalog/chat-models/ll/llama3.2-3b-q4/versions/1.1.1/manifest.json +56 -0
- package/dist/catalog/chat-models/mi/minicpm5-1b-q4/manifest.json +156 -0
- package/dist/catalog/chat-models/mi/minicpm5-1b-q4/versions/1.0.0/manifest.json +57 -0
- package/dist/catalog/chat-models/mi/minicpm5-2b-q4/manifest.json +161 -0
- package/dist/catalog/chat-models/mi/minicpm5-2b-q4/versions/1.0.0/manifest.json +57 -0
- package/dist/catalog/chat-models/mi/mistral-7b-q4/manifest.json +159 -0
- package/dist/catalog/chat-models/mi/mistral-7b-q4/versions/1.1.0/manifest.json +62 -0
- package/dist/catalog/chat-models/mi/mistral-7b-q4/versions/1.1.1/manifest.json +61 -0
- package/dist/catalog/chat-models/mi/mistral-medium-3.5-128b-q4/manifest.json +275 -0
- package/dist/catalog/chat-models/mi/mistral-medium-3.5-128b-q4/versions/1.0.0/manifest.json +154 -0
- package/dist/catalog/chat-models/mi/mistral-medium-3.5-128b-q4/versions/1.0.1/manifest.json +153 -0
- package/dist/catalog/chat-models/mu/muse-glimmer-30b-q4/manifest.json +135 -0
- package/dist/catalog/chat-models/mu/muse-glimmer-30b-q4/versions/1.0.0/manifest.json +20 -0
- package/dist/catalog/chat-models/mu/muse-glimmer-30b-q4/versions/1.0.1/manifest.json +20 -0
- package/dist/catalog/chat-models/mu/muse-glimmer-30b-q4/versions/1.0.2/manifest.json +20 -0
- package/dist/catalog/chat-models/na/nanbeige4.2-3b-q4/manifest.json +138 -0
- package/dist/catalog/chat-models/na/nanbeige4.2-3b-q4/versions/1.0.0/manifest.json +14 -0
- package/dist/catalog/chat-models/ne/nemotron3-nano-30b-q4/manifest.json +212 -0
- package/dist/catalog/chat-models/ne/nemotron3-nano-30b-q4/versions/1.0.0/manifest.json +94 -0
- package/dist/catalog/chat-models/ne/nemotron3-nano-30b-q4/versions/1.0.1/manifest.json +94 -0
- package/dist/catalog/chat-models/ne/nemotron3-nano-30b-q4/versions/1.0.2/manifest.json +93 -0
- package/dist/catalog/chat-models/ne/nemotron3-super-120b-q4/manifest.json +135 -0
- package/dist/catalog/chat-models/ne/nemotron3-super-120b-q4/versions/1.0.0/manifest.json +30 -0
- package/dist/catalog/chat-models/ne/nemotron3-super-120b-q4/versions/1.0.1/manifest.json +30 -0
- package/dist/catalog/chat-models/ne/nemotron3.5-lightning-30b-q4/manifest.json +192 -0
- package/dist/catalog/chat-models/ne/nemotron3.5-lightning-30b-q4/versions/1.0.0/manifest.json +74 -0
- package/dist/catalog/chat-models/ne/nemotron3.5-lightning-30b-q4/versions/1.0.1/manifest.json +73 -0
- package/dist/catalog/chat-models/ne/nemotron3.5-lightning-30b-q8/manifest.json +207 -0
- package/dist/catalog/chat-models/ne/nemotron3.5-lightning-30b-q8/versions/1.0.0/manifest.json +89 -0
- package/dist/catalog/chat-models/ne/nemotron3.5-lightning-30b-q8/versions/1.0.1/manifest.json +88 -0
- package/dist/catalog/chat-models/or/ornith-35b-q4/manifest.json +224 -0
- package/dist/catalog/chat-models/or/ornith-35b-q4/versions/1.0.0/manifest.json +94 -0
- package/dist/catalog/chat-models/or/ornith-35b-q4/versions/1.0.1/manifest.json +93 -0
- package/dist/catalog/chat-models/or/ornith-35b-q8/manifest.json +244 -0
- package/dist/catalog/chat-models/or/ornith-35b-q8/versions/1.0.0/manifest.json +114 -0
- package/dist/catalog/chat-models/or/ornith-35b-q8/versions/1.0.1/manifest.json +113 -0
- package/dist/catalog/chat-models/or/ornith-9b-q4/manifest.json +215 -0
- package/dist/catalog/chat-models/or/ornith-9b-q4/versions/1.0.0/manifest.json +84 -0
- package/dist/catalog/chat-models/or/ornith-9b-q4/versions/1.0.1/manifest.json +83 -0
- package/dist/catalog/chat-models/or/ornith1.5-35b-a3b-q4/manifest.json +208 -0
- package/dist/catalog/chat-models/or/ornith1.5-35b-a3b-q4/versions/1.0.0/manifest.json +74 -0
- package/dist/catalog/chat-models/or/ornith1.5-35b-a3b-q8/manifest.json +223 -0
- package/dist/catalog/chat-models/or/ornith1.5-35b-a3b-q8/versions/1.0.0/manifest.json +89 -0
- package/dist/catalog/chat-models/or/ornith1.5-9b-q4/manifest.json +187 -0
- package/dist/catalog/chat-models/or/ornith1.5-9b-q4/versions/1.0.0/manifest.json +53 -0
- package/dist/catalog/chat-models/or/ornith1.5-9b-q4/versions/1.0.1/manifest.json +77 -0
- package/dist/catalog/chat-models/or/ornith1.5-9b-q8/manifest.json +192 -0
- package/dist/catalog/chat-models/or/ornith1.5-9b-q8/versions/1.0.0/manifest.json +58 -0
- package/dist/catalog/chat-models/or/ornith1.5-9b-q8/versions/1.0.1/manifest.json +82 -0
- package/dist/catalog/chat-models/qw/qwen3.5-0.8b-q4/manifest.json +192 -0
- package/dist/catalog/chat-models/qw/qwen3.5-0.8b-q4/versions/1.0.0/manifest.json +75 -0
- package/dist/catalog/chat-models/qw/qwen3.5-122b-a10b-q4/manifest.json +315 -0
- package/dist/catalog/chat-models/qw/qwen3.5-122b-a10b-q4/versions/1.0.0/manifest.json +164 -0
- package/dist/catalog/chat-models/qw/qwen3.5-122b-a10b-q4/versions/1.0.1/manifest.json +164 -0
- package/dist/catalog/chat-models/qw/qwen3.5-122b-a10b-q4/versions/1.0.2/manifest.json +164 -0
- package/dist/catalog/chat-models/qw/qwen3.5-122b-a10b-q4/versions/1.0.3/manifest.json +163 -0
- package/dist/catalog/chat-models/qw/qwen3.5-27b-q4/manifest.json +217 -0
- package/dist/catalog/chat-models/qw/qwen3.5-27b-q4/versions/1.0.0/manifest.json +90 -0
- package/dist/catalog/chat-models/qw/qwen3.5-2b-q4/manifest.json +194 -0
- package/dist/catalog/chat-models/qw/qwen3.5-2b-q4/versions/1.1.0/manifest.json +77 -0
- package/dist/catalog/chat-models/qw/qwen3.5-2b-q4/versions/1.1.2/manifest.json +76 -0
- package/dist/catalog/chat-models/qw/qwen3.5-2b-q4/versions/1.1.3/manifest.json +76 -0
- package/dist/catalog/chat-models/qw/qwen3.5-4b-q4/manifest.json +188 -0
- package/dist/catalog/chat-models/qw/qwen3.5-4b-q4/versions/1.1.0/manifest.json +77 -0
- package/dist/catalog/chat-models/qw/qwen3.5-4b-q4/versions/1.1.2/manifest.json +76 -0
- package/dist/catalog/chat-models/qw/qwen3.5-4b-q4/versions/1.1.3/manifest.json +76 -0
- package/dist/catalog/chat-models/qw/qwen3.5-9b-q4/manifest.json +205 -0
- package/dist/catalog/chat-models/qw/qwen3.5-9b-q4/versions/1.1.0/manifest.json +82 -0
- package/dist/catalog/chat-models/qw/qwen3.5-9b-q4/versions/1.1.2/manifest.json +81 -0
- package/dist/catalog/chat-models/qw/qwen3.5-9b-q4/versions/1.1.3/manifest.json +81 -0
- package/dist/catalog/chat-models/qw/qwen3.6-27b-q4/manifest.json +230 -0
- package/dist/catalog/chat-models/qw/qwen3.6-27b-q4/versions/1.1.0/manifest.json +92 -0
- package/dist/catalog/chat-models/qw/qwen3.6-27b-q4/versions/1.1.4/manifest.json +91 -0
- package/dist/catalog/chat-models/qw/qwen3.6-27b-q4/versions/1.1.5/manifest.json +91 -0
- package/dist/catalog/chat-models/qw/qwen3.6-27b-q4/versions/1.1.6/manifest.json +115 -0
- package/dist/catalog/chat-models/qw/qwen3.6-27b-q8/manifest.json +240 -0
- package/dist/catalog/chat-models/qw/qwen3.6-27b-q8/versions/1.0.0/manifest.json +102 -0
- package/dist/catalog/chat-models/qw/qwen3.6-27b-q8/versions/1.0.2/manifest.json +103 -0
- package/dist/catalog/chat-models/qw/qwen3.6-27b-q8/versions/1.0.3/manifest.json +103 -0
- package/dist/catalog/chat-models/qw/qwen3.6-27b-q8/versions/1.0.4/manifest.json +127 -0
- package/dist/catalog/chat-models/qw/qwen3.6-35b-a3b-q4/manifest.json +233 -0
- package/dist/catalog/chat-models/qw/qwen3.6-35b-a3b-q4/versions/1.0.0/manifest.json +92 -0
- package/dist/catalog/chat-models/qw/qwen3.6-35b-a3b-q4/versions/1.0.1/manifest.json +93 -0
- package/dist/catalog/chat-models/qw/qwen3.6-35b-a3b-q4/versions/1.0.2/manifest.json +93 -0
- package/dist/catalog/chat-models/qw/qwen3.6-35b-a3b-q4/versions/1.0.3/manifest.json +117 -0
- package/dist/catalog/chat-models/qw/qwen3.6-35b-a3b-q8/manifest.json +252 -0
- package/dist/catalog/chat-models/qw/qwen3.6-35b-a3b-q8/versions/1.0.0/manifest.json +112 -0
- package/dist/catalog/chat-models/qw/qwen3.6-35b-a3b-q8/versions/1.0.1/manifest.json +113 -0
- package/dist/catalog/chat-models/qw/qwen3.6-35b-a3b-q8/versions/1.0.2/manifest.json +113 -0
- package/dist/catalog/chat-models/qw/qwen3.6-35b-a3b-q8/versions/1.0.3/manifest.json +137 -0
- package/dist/catalog/chat-models/qw/qwen3.8-27b-iq1-s/manifest.json +195 -0
- package/dist/catalog/chat-models/qw/qwen3.8-27b-iq1-s/versions/1.0.0/manifest.json +19 -0
- package/dist/catalog/chat-models/qw/qwen3.8-27b-q2/manifest.json +194 -0
- package/dist/catalog/chat-models/qw/qwen3.8-27b-q2/versions/1.0.0/manifest.json +19 -0
- package/dist/catalog/chat-models/qw/qwen3.8-27b-q3/manifest.json +194 -0
- package/dist/catalog/chat-models/qw/qwen3.8-27b-q3/versions/1.0.0/manifest.json +19 -0
- package/dist/catalog/chat-models/qw/qwen3.8-27b-q3/versions/1.0.1/manifest.json +19 -0
- package/dist/catalog/chat-models/qw/qwen3.8-27b-q4/manifest.json +291 -0
- package/dist/catalog/chat-models/qw/qwen3.8-27b-q4/versions/1.0.0/manifest.json +20 -0
- package/dist/catalog/chat-models/qw/qwen3.8-27b-q4/versions/1.0.1/manifest.json +93 -0
- package/dist/catalog/chat-models/qw/qwen3.8-27b-q4/versions/1.0.2/manifest.json +92 -0
- package/dist/catalog/chat-models/qw/qwen3.8-27b-q4/versions/1.0.3/manifest.json +116 -0
- package/dist/catalog/chat-models/qw/qwen3.8-27b-q4/versions/1.0.4/manifest.json +116 -0
- package/dist/catalog/chat-models/qw/qwen3.8-27b-q4/versions/1.0.5/manifest.json +116 -0
- package/dist/catalog/chat-models/qw/qwen3.8-27b-q6/manifest.json +278 -0
- package/dist/catalog/chat-models/qw/qwen3.8-27b-q6/versions/1.0.0/manifest.json +20 -0
- package/dist/catalog/chat-models/qw/qwen3.8-27b-q6/versions/1.0.1/manifest.json +104 -0
- package/dist/catalog/chat-models/qw/qwen3.8-27b-q6/versions/1.0.2/manifest.json +103 -0
- package/dist/catalog/chat-models/qw/qwen3.8-27b-q6/versions/1.0.3/manifest.json +127 -0
- package/dist/catalog/chat-models/qw/qwen3.8-27b-q8/manifest.json +278 -0
- package/dist/catalog/chat-models/qw/qwen3.8-27b-q8/versions/1.0.0/manifest.json +113 -0
- package/dist/catalog/chat-models/qw/qwen3.8-27b-q8/versions/1.0.1/manifest.json +113 -0
- package/dist/catalog/chat-models/qw/qwen3.8-27b-q8/versions/1.0.2/manifest.json +137 -0
- package/dist/catalog/chat-models/qw/qwen3.8-flash-next-iq3/manifest.json +221 -0
- package/dist/catalog/chat-models/qw/qwen3.8-flash-next-iq3/versions/1.0.0/manifest.json +36 -0
- package/dist/catalog/chat-models/qw/qwen3.8-flash-next-iq4/manifest.json +429 -0
- package/dist/catalog/chat-models/qw/qwen3.8-flash-next-iq4/versions/1.0.0/manifest.json +36 -0
- package/dist/catalog/chat-models/qw/qwen3.8-flash-next-iq4/versions/1.1.0/manifest.json +205 -0
- package/dist/catalog/chat-models/qw/qwen3.8-flash-next-iq4/versions/1.1.1/manifest.json +244 -0
- package/dist/catalog/chat-models/qw/qwen3.8-flash-next-q2/manifest.json +203 -0
- package/dist/catalog/chat-models/qw/qwen3.8-flash-next-q2/versions/1.0.0/manifest.json +21 -0
- package/dist/catalog/chat-models/qw/qwen3.8-flash-next-q2/versions/1.0.1/manifest.json +31 -0
- package/dist/catalog/chat-models/qw/qwen3.8-flash-next-q2/versions/1.0.2/manifest.json +30 -0
- package/dist/catalog/chat-models/raw-index.json +1 -0
- package/dist/catalog/chat-models/ta/talkie-1930-13b-q4/manifest.json +79 -0
- package/dist/catalog/chat-models/ta/talkie-1930-13b-q4/versions/1.0.0/manifest.json +15 -0
- package/dist/catalog/chat-models/ta/talkie-1930-13b-q4/versions/1.0.1/manifest.json +15 -0
- package/dist/catalog/chat-models/te/ternary-bonsai-27b-q2/manifest.json +204 -0
- package/dist/catalog/chat-models/te/ternary-bonsai-27b-q2/versions/1.0.0/manifest.json +70 -0
- package/dist/catalog/chat-models/te/ternary-bonsai-27b-q2/versions/1.0.1/manifest.json +70 -0
- package/dist/catalog/chat-models/un/underdog-saluki-27b-iq2-mix/manifest.json +164 -0
- package/dist/catalog/chat-models/un/underdog-saluki-27b-iq2-mix/versions/1.0.0/manifest.json +14 -0
- package/dist/catalog/knowledge-catalogs/be/bendyline-how-to-books/manifest.json +26 -0
- package/dist/catalog/knowledge-catalogs/be/bendyline-how-to-books/versions/2026.10.8/manifest.json +8950 -0
- package/dist/catalog/knowledge-catalogs/ca/caselaw-alaska-part-0001/manifest.json +24 -0
- package/dist/catalog/knowledge-catalogs/ca/caselaw-alaska-part-0001/versions/2026.10.1/manifest.json +658 -0
- package/dist/catalog/knowledge-catalogs/ca/caselaw-nevada-part-0001/manifest.json +24 -0
- package/dist/catalog/knowledge-catalogs/ca/caselaw-nevada-part-0001/versions/2026.10.1/manifest.json +666 -0
- package/dist/catalog/knowledge-catalogs/ca/caselaw-us-300-399-part-0001/manifest.json +24 -0
- package/dist/catalog/knowledge-catalogs/ca/caselaw-us-300-399-part-0001/versions/2026.10.2/manifest.json +182 -0
- package/dist/catalog/knowledge-catalogs/ca/caselaw-us-347-349/manifest.json +25 -0
- package/dist/catalog/knowledge-catalogs/ca/caselaw-us-347-349/versions/2026.10.5/manifest.json +38 -0
- package/dist/catalog/knowledge-catalogs/ca/caselaw-utah-part-0001/manifest.json +24 -0
- package/dist/catalog/knowledge-catalogs/ca/caselaw-utah-part-0001/versions/2026.10.1/manifest.json +558 -0
- package/dist/catalog/knowledge-catalogs/ca/caselaw-utah-part-0002/manifest.json +24 -0
- package/dist/catalog/knowledge-catalogs/ca/caselaw-utah-part-0002/versions/2026.10.1/manifest.json +258 -0
- package/dist/catalog/knowledge-catalogs/ca/caselaw-washington-part-0001/manifest.json +24 -0
- package/dist/catalog/knowledge-catalogs/ca/caselaw-washington-part-0001/versions/2026.10.1/manifest.json +318 -0
- package/dist/catalog/knowledge-catalogs/ca/caselaw-washington-part-0002/manifest.json +24 -0
- package/dist/catalog/knowledge-catalogs/ca/caselaw-washington-part-0002/versions/2026.10.1/manifest.json +266 -0
- package/dist/catalog/knowledge-catalogs/ca/caselaw-washington-part-0003/manifest.json +24 -0
- package/dist/catalog/knowledge-catalogs/ca/caselaw-washington-part-0003/versions/2026.10.1/manifest.json +186 -0
- package/dist/catalog/knowledge-catalogs/ca/caselaw-washington-part-0004/manifest.json +24 -0
- package/dist/catalog/knowledge-catalogs/ca/caselaw-washington-part-0004/versions/2026.10.1/manifest.json +138 -0
- package/dist/catalog/knowledge-catalogs/ca/caselaw-washington-part-0005/manifest.json +24 -0
- package/dist/catalog/knowledge-catalogs/ca/caselaw-washington-part-0005/versions/2026.10.1/manifest.json +138 -0
- package/dist/catalog/knowledge-catalogs/ca/caselaw-wyoming-part-0001/manifest.json +24 -0
- package/dist/catalog/knowledge-catalogs/ca/caselaw-wyoming-part-0001/versions/2026.10.3/manifest.json +626 -0
- package/dist/catalog/knowledge-catalogs/index.json +1 -0
- package/dist/catalog/knowledge-catalogs/mi/microsoftdocs-aspnet-core-en/manifest.json +22 -0
- package/dist/catalog/knowledge-catalogs/mi/microsoftdocs-aspnet-core-en/versions/2026.10.16/manifest.json +18270 -0
- package/dist/catalog/knowledge-catalogs/mi/microsoftdocs-azure-ai-platform-en/manifest.json +23 -0
- package/dist/catalog/knowledge-catalogs/mi/microsoftdocs-azure-ai-platform-en/versions/2026.10.16/manifest.json +1098 -0
- package/dist/catalog/knowledge-catalogs/mi/microsoftdocs-azure-apps-compute-en/manifest.json +23 -0
- package/dist/catalog/knowledge-catalogs/mi/microsoftdocs-azure-apps-compute-en/versions/2026.10.16/manifest.json +722 -0
- package/dist/catalog/knowledge-catalogs/mi/microsoftdocs-azure-data-aiot-en/manifest.json +23 -0
- package/dist/catalog/knowledge-catalogs/mi/microsoftdocs-azure-data-aiot-en/versions/2026.10.16/manifest.json +530 -0
- package/dist/catalog/knowledge-catalogs/mi/microsoftdocs-azure-management-hybrid-en/manifest.json +23 -0
- package/dist/catalog/knowledge-catalogs/mi/microsoftdocs-azure-management-hybrid-en/versions/2026.10.16/manifest.json +602 -0
- package/dist/catalog/knowledge-catalogs/mi/microsoftdocs-azure-network-security-en/manifest.json +23 -0
- package/dist/catalog/knowledge-catalogs/mi/microsoftdocs-azure-network-security-en/versions/2026.10.16/manifest.json +250 -0
- package/dist/catalog/knowledge-catalogs/mi/microsoftdocs-dotnet-en/manifest.json +22 -0
- package/dist/catalog/knowledge-catalogs/mi/microsoftdocs-dotnet-en/versions/2026.10.16/manifest.json +16794 -0
- package/dist/catalog/knowledge-catalogs/mi/microsoftdocs-entity-framework-en/manifest.json +22 -0
- package/dist/catalog/knowledge-catalogs/mi/microsoftdocs-entity-framework-en/versions/2026.10.16/manifest.json +1106 -0
- package/dist/catalog/knowledge-catalogs/mi/microsoftdocs-microsoft-365-en/manifest.json +22 -0
- package/dist/catalog/knowledge-catalogs/mi/microsoftdocs-microsoft-365-en/versions/2026.10.16/manifest.json +234 -0
- package/dist/catalog/knowledge-catalogs/mi/microsoftdocs-powershell-en/manifest.json +22 -0
- package/dist/catalog/knowledge-catalogs/mi/microsoftdocs-powershell-en/versions/2026.10.16/manifest.json +522 -0
- package/dist/catalog/knowledge-catalogs/mi/microsoftdocs-sql-server-en/manifest.json +22 -0
- package/dist/catalog/knowledge-catalogs/mi/microsoftdocs-sql-server-en/versions/2026.10.16/manifest.json +1850 -0
- package/dist/catalog/knowledge-catalogs/mi/microsoftdocs-windows-apps-en/manifest.json +22 -0
- package/dist/catalog/knowledge-catalogs/mi/microsoftdocs-windows-apps-en/versions/2026.10.16/manifest.json +1734 -0
- package/dist/catalog/knowledge-catalogs/mi/microsoftdocs-windows-server-en/manifest.json +22 -0
- package/dist/catalog/knowledge-catalogs/mi/microsoftdocs-windows-server-en/versions/2026.10.16/manifest.json +774 -0
- package/dist/catalog/knowledge-catalogs/raw-index.json +1 -0
- package/dist/catalog/knowledge-catalogs/re/regional-american-south/art.json +12 -0
- package/dist/catalog/knowledge-catalogs/re/regional-american-south/logo.webp +0 -0
- package/dist/catalog/knowledge-catalogs/re/regional-american-south/manifest.json +48 -0
- package/dist/catalog/knowledge-catalogs/re/regional-american-south/versions/2026.10.3/manifest.json +133 -0
- package/dist/catalog/knowledge-catalogs/re/regional-andes-amazon/art.json +12 -0
- package/dist/catalog/knowledge-catalogs/re/regional-andes-amazon/logo.webp +0 -0
- package/dist/catalog/knowledge-catalogs/re/regional-andes-amazon/manifest.json +48 -0
- package/dist/catalog/knowledge-catalogs/re/regional-andes-amazon/versions/2026.10.3/manifest.json +133 -0
- package/dist/catalog/knowledge-catalogs/re/regional-australia-nz/art.json +12 -0
- package/dist/catalog/knowledge-catalogs/re/regional-australia-nz/logo.webp +0 -0
- package/dist/catalog/knowledge-catalogs/re/regional-australia-nz/manifest.json +48 -0
- package/dist/catalog/knowledge-catalogs/re/regional-australia-nz/versions/2026.10.3/manifest.json +133 -0
- package/dist/catalog/knowledge-catalogs/re/regional-brazil/art.json +12 -0
- package/dist/catalog/knowledge-catalogs/re/regional-brazil/logo.webp +0 -0
- package/dist/catalog/knowledge-catalogs/re/regional-brazil/manifest.json +48 -0
- package/dist/catalog/knowledge-catalogs/re/regional-brazil/versions/2026.10.3/manifest.json +133 -0
- package/dist/catalog/knowledge-catalogs/re/regional-britain-ireland/art.json +12 -0
- package/dist/catalog/knowledge-catalogs/re/regional-britain-ireland/logo.webp +0 -0
- package/dist/catalog/knowledge-catalogs/re/regional-britain-ireland/manifest.json +48 -0
- package/dist/catalog/knowledge-catalogs/re/regional-britain-ireland/versions/2026.10.3/manifest.json +133 -0
- package/dist/catalog/knowledge-catalogs/re/regional-california-southwest/art.json +12 -0
- package/dist/catalog/knowledge-catalogs/re/regional-california-southwest/logo.webp +0 -0
- package/dist/catalog/knowledge-catalogs/re/regional-california-southwest/manifest.json +48 -0
- package/dist/catalog/knowledge-catalogs/re/regional-california-southwest/versions/2026.10.3/manifest.json +133 -0
- package/dist/catalog/knowledge-catalogs/re/regional-canada-alaska/art.json +12 -0
- package/dist/catalog/knowledge-catalogs/re/regional-canada-alaska/logo.webp +0 -0
- package/dist/catalog/knowledge-catalogs/re/regional-canada-alaska/manifest.json +48 -0
- package/dist/catalog/knowledge-catalogs/re/regional-canada-alaska/versions/2026.10.3/manifest.json +133 -0
- package/dist/catalog/knowledge-catalogs/re/regional-central-eastern-europe/art.json +12 -0
- package/dist/catalog/knowledge-catalogs/re/regional-central-eastern-europe/logo.webp +0 -0
- package/dist/catalog/knowledge-catalogs/re/regional-central-eastern-europe/manifest.json +48 -0
- package/dist/catalog/knowledge-catalogs/re/regional-central-eastern-europe/versions/2026.10.3/manifest.json +133 -0
- package/dist/catalog/knowledge-catalogs/re/regional-east-asia/art.json +12 -0
- package/dist/catalog/knowledge-catalogs/re/regional-east-asia/logo.webp +0 -0
- package/dist/catalog/knowledge-catalogs/re/regional-east-asia/manifest.json +48 -0
- package/dist/catalog/knowledge-catalogs/re/regional-east-asia/versions/2026.10.3/manifest.json +133 -0
- package/dist/catalog/knowledge-catalogs/re/regional-east-southern-africa/art.json +12 -0
- package/dist/catalog/knowledge-catalogs/re/regional-east-southern-africa/logo.webp +0 -0
- package/dist/catalog/knowledge-catalogs/re/regional-east-southern-africa/manifest.json +48 -0
- package/dist/catalog/knowledge-catalogs/re/regional-east-southern-africa/versions/2026.10.3/manifest.json +133 -0
- package/dist/catalog/knowledge-catalogs/re/regional-mediterranean/art.json +12 -0
- package/dist/catalog/knowledge-catalogs/re/regional-mediterranean/logo.webp +0 -0
- package/dist/catalog/knowledge-catalogs/re/regional-mediterranean/manifest.json +48 -0
- package/dist/catalog/knowledge-catalogs/re/regional-mediterranean/versions/2026.10.3/manifest.json +133 -0
- package/dist/catalog/knowledge-catalogs/re/regional-mexico-central-america/art.json +12 -0
- package/dist/catalog/knowledge-catalogs/re/regional-mexico-central-america/logo.webp +0 -0
- package/dist/catalog/knowledge-catalogs/re/regional-mexico-central-america/manifest.json +48 -0
- package/dist/catalog/knowledge-catalogs/re/regional-mexico-central-america/versions/2026.10.3/manifest.json +133 -0
- package/dist/catalog/knowledge-catalogs/re/regional-middle-east/art.json +12 -0
- package/dist/catalog/knowledge-catalogs/re/regional-middle-east/logo.webp +0 -0
- package/dist/catalog/knowledge-catalogs/re/regional-middle-east/manifest.json +48 -0
- package/dist/catalog/knowledge-catalogs/re/regional-middle-east/versions/2026.10.3/manifest.json +133 -0
- package/dist/catalog/knowledge-catalogs/re/regional-midwest/art.json +12 -0
- package/dist/catalog/knowledge-catalogs/re/regional-midwest/logo.webp +0 -0
- package/dist/catalog/knowledge-catalogs/re/regional-midwest/manifest.json +48 -0
- package/dist/catalog/knowledge-catalogs/re/regional-midwest/versions/2026.10.3/manifest.json +133 -0
- package/dist/catalog/knowledge-catalogs/re/regional-north-africa/art.json +12 -0
- package/dist/catalog/knowledge-catalogs/re/regional-north-africa/logo.webp +0 -0
- package/dist/catalog/knowledge-catalogs/re/regional-north-africa/manifest.json +48 -0
- package/dist/catalog/knowledge-catalogs/re/regional-north-africa/versions/2026.10.3/manifest.json +133 -0
- package/dist/catalog/knowledge-catalogs/re/regional-northeast/art.json +12 -0
- package/dist/catalog/knowledge-catalogs/re/regional-northeast/logo.webp +0 -0
- package/dist/catalog/knowledge-catalogs/re/regional-northeast/manifest.json +48 -0
- package/dist/catalog/knowledge-catalogs/re/regional-northeast/versions/2026.10.3/manifest.json +133 -0
- package/dist/catalog/knowledge-catalogs/re/regional-northern-eurasia/art.json +12 -0
- package/dist/catalog/knowledge-catalogs/re/regional-northern-eurasia/logo.webp +0 -0
- package/dist/catalog/knowledge-catalogs/re/regional-northern-eurasia/manifest.json +48 -0
- package/dist/catalog/knowledge-catalogs/re/regional-northern-eurasia/versions/2026.10.3/manifest.json +133 -0
- package/dist/catalog/knowledge-catalogs/re/regional-northern-europe/art.json +12 -0
- package/dist/catalog/knowledge-catalogs/re/regional-northern-europe/logo.webp +0 -0
- package/dist/catalog/knowledge-catalogs/re/regional-northern-europe/manifest.json +48 -0
- package/dist/catalog/knowledge-catalogs/re/regional-northern-europe/versions/2026.10.3/manifest.json +133 -0
- package/dist/catalog/knowledge-catalogs/re/regional-pacific-islands/art.json +12 -0
- package/dist/catalog/knowledge-catalogs/re/regional-pacific-islands/logo.webp +0 -0
- package/dist/catalog/knowledge-catalogs/re/regional-pacific-islands/manifest.json +48 -0
- package/dist/catalog/knowledge-catalogs/re/regional-pacific-islands/versions/2026.10.3/manifest.json +133 -0
- package/dist/catalog/knowledge-catalogs/re/regional-pacific-northwest/art.json +12 -0
- package/dist/catalog/knowledge-catalogs/re/regional-pacific-northwest/logo.webp +0 -0
- package/dist/catalog/knowledge-catalogs/re/regional-pacific-northwest/manifest.json +48 -0
- package/dist/catalog/knowledge-catalogs/re/regional-pacific-northwest/versions/2026.10.3/manifest.json +133 -0
- package/dist/catalog/knowledge-catalogs/re/regional-rockies-plains/art.json +12 -0
- package/dist/catalog/knowledge-catalogs/re/regional-rockies-plains/logo.webp +0 -0
- package/dist/catalog/knowledge-catalogs/re/regional-rockies-plains/manifest.json +48 -0
- package/dist/catalog/knowledge-catalogs/re/regional-rockies-plains/versions/2026.10.3/manifest.json +133 -0
- package/dist/catalog/knowledge-catalogs/re/regional-south-asia/art.json +12 -0
- package/dist/catalog/knowledge-catalogs/re/regional-south-asia/logo.webp +0 -0
- package/dist/catalog/knowledge-catalogs/re/regional-south-asia/manifest.json +48 -0
- package/dist/catalog/knowledge-catalogs/re/regional-south-asia/versions/2026.10.3/manifest.json +133 -0
- package/dist/catalog/knowledge-catalogs/re/regional-southeast-asia/art.json +12 -0
- package/dist/catalog/knowledge-catalogs/re/regional-southeast-asia/logo.webp +0 -0
- package/dist/catalog/knowledge-catalogs/re/regional-southeast-asia/manifest.json +48 -0
- package/dist/catalog/knowledge-catalogs/re/regional-southeast-asia/versions/2026.10.3/manifest.json +133 -0
- package/dist/catalog/knowledge-catalogs/re/regional-southern-cone/art.json +12 -0
- package/dist/catalog/knowledge-catalogs/re/regional-southern-cone/logo.webp +0 -0
- package/dist/catalog/knowledge-catalogs/re/regional-southern-cone/manifest.json +48 -0
- package/dist/catalog/knowledge-catalogs/re/regional-southern-cone/versions/2026.10.3/manifest.json +133 -0
- package/dist/catalog/knowledge-catalogs/re/regional-west-central-africa/art.json +12 -0
- package/dist/catalog/knowledge-catalogs/re/regional-west-central-africa/logo.webp +0 -0
- package/dist/catalog/knowledge-catalogs/re/regional-west-central-africa/manifest.json +48 -0
- package/dist/catalog/knowledge-catalogs/re/regional-west-central-africa/versions/2026.10.3/manifest.json +133 -0
- package/dist/catalog/knowledge-catalogs/re/regional-western-europe/art.json +12 -0
- package/dist/catalog/knowledge-catalogs/re/regional-western-europe/logo.webp +0 -0
- package/dist/catalog/knowledge-catalogs/re/regional-western-europe/manifest.json +48 -0
- package/dist/catalog/knowledge-catalogs/re/regional-western-europe/versions/2026.10.3/manifest.json +133 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-arts/art.json +12 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-arts/logo.webp +0 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-arts/manifest.json +28 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-arts/versions/2026.4.2/manifest.json +53 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-arts/versions/2026.4.3/manifest.json +885 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-arts/versions/2026.4.5/manifest.json +157 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-astronomy/art.json +11 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-astronomy/logo.webp +0 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-astronomy/manifest.json +32 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-astronomy/versions/2026.4.2/manifest.json +69 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-astronomy/versions/2026.4.3/manifest.json +741 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-astronomy/versions/2026.4.5/manifest.json +173 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-biology/art.json +12 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-biology/logo.webp +0 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-biology/manifest.json +69 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-biology/versions/2026.4.4/manifest.json +217 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-biology/versions/2026.4.5/manifest.json +217 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-business/art.json +12 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-business/logo.webp +0 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-business/manifest.json +64 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-business/versions/2026.4.4/manifest.json +197 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-business/versions/2026.4.5/manifest.json +197 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-film-tv/art.json +12 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-film-tv/logo.webp +0 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-film-tv/manifest.json +64 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-film-tv/versions/2026.4.5/manifest.json +197 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-food-drink/art.json +11 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-food-drink/logo.webp +0 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-food-drink/manifest.json +29 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-food-drink/versions/2026.4.2/manifest.json +57 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-food-drink/versions/2026.4.3/manifest.json +925 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-food-drink/versions/2026.4.5/manifest.json +185 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-games/art.json +12 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-games/logo.webp +0 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-games/manifest.json +28 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-games/versions/2026.4.2/manifest.json +53 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-games/versions/2026.4.3/manifest.json +1665 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-games/versions/2026.4.5/manifest.json +133 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-language/art.json +12 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-language/logo.webp +0 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-language/manifest.json +29 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-language/versions/2026.4.2/manifest.json +57 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-language/versions/2026.4.3/manifest.json +1233 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-language/versions/2026.4.5/manifest.json +141 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-law/art.json +11 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-law/logo.webp +0 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-law/manifest.json +29 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-law/versions/2026.4.2/manifest.json +57 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-law/versions/2026.4.3/manifest.json +493 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-law/versions/2026.4.5/manifest.json +185 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-literature/art.json +12 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-literature/logo.webp +0 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-literature/manifest.json +63 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-literature/versions/2026.4.4/manifest.json +193 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-literature/versions/2026.4.5/manifest.json +193 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-mathematics/art.json +12 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-mathematics/logo.webp +0 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-mathematics/manifest.json +30 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-mathematics/versions/2026.4.2/manifest.json +61 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-mathematics/versions/2026.4.3/manifest.json +665 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-mathematics/versions/2026.4.5/manifest.json +177 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-medicine/art.json +12 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-medicine/logo.webp +0 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-medicine/manifest.json +29 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-medicine/versions/2026.4.2/manifest.json +57 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-medicine/versions/2026.4.3/manifest.json +745 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-medicine/versions/2026.4.5/manifest.json +185 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-military/art.json +12 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-military/logo.webp +0 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-military/manifest.json +62 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-military/versions/2026.4.4/manifest.json +189 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-military/versions/2026.4.5/manifest.json +189 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-music/art.json +12 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-music/logo.webp +0 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-music/manifest.json +64 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-music/versions/2026.4.5/manifest.json +197 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-politics/art.json +12 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-politics/logo.webp +0 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-politics/manifest.json +64 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-politics/versions/2026.4.4/manifest.json +197 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-politics/versions/2026.4.5/manifest.json +197 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-religion-philosophy/art.json +12 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-religion-philosophy/logo.webp +0 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-religion-philosophy/manifest.json +30 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-religion-philosophy/versions/2026.4.2/manifest.json +61 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-religion-philosophy/versions/2026.4.3/manifest.json +1253 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-religion-philosophy/versions/2026.4.5/manifest.json +189 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-science/art.json +12 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-science/logo.webp +0 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-science/manifest.json +29 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-science/versions/2026.4.2/manifest.json +57 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-science/versions/2026.4.3/manifest.json +1957 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-science/versions/2026.4.5/manifest.json +185 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-sports/art.json +12 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-sports/logo.webp +0 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-sports/manifest.json +63 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-sports/versions/2026.4.5/manifest.json +193 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-technology/art.json +11 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-technology/logo.webp +0 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-technology/manifest.json +45 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-technology/versions/2026.4.4/manifest.json +121 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-technology/versions/2026.4.5/manifest.json +173 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-transportation/art.json +12 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-transportation/logo.webp +0 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-transportation/manifest.json +62 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-transportation/versions/2026.4.4/manifest.json +189 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-transportation/versions/2026.4.5/manifest.json +189 -0
- package/dist/catalog/provenance.json +8 -0
- package/dist/chat/catalog-model-lookup.d.ts +21 -0
- package/dist/chat/catalog-model-lookup.js +48 -0
- package/dist/chat/local-model-tier.d.ts +1 -0
- package/dist/chat/local-model-tier.js +2 -0
- package/dist/chat/vision-capability.d.ts +1 -0
- package/dist/chat/vision-capability.js +3 -0
- package/dist/engine-components.d.ts +30 -0
- package/dist/engine-components.js +144 -0
- package/dist/engines/electron-native-reuse.d.ts +65 -0
- package/dist/engines/electron-native-reuse.js +305 -0
- package/dist/engines/native-file-manifest.json +1320 -0
- package/dist/engines/native-manifest.d.ts +70 -0
- package/dist/engines/native-manifest.js +98 -0
- package/dist/engines/registry.d.ts +88 -0
- package/dist/engines/registry.js +217 -0
- package/dist/engines/resolver.d.ts +121 -0
- package/dist/engines/resolver.js +894 -0
- package/dist/engines/signature.d.ts +85 -0
- package/dist/engines/signature.js +231 -0
- package/dist/fs/atomic.d.ts +53 -0
- package/dist/fs/atomic.js +202 -0
- package/dist/fs/config-store.d.ts +14 -0
- package/dist/fs/config-store.js +101 -0
- package/dist/fs/home-permissions.d.ts +18 -0
- package/dist/fs/home-permissions.js +27 -0
- package/dist/fs/safe-paths.d.ts +107 -0
- package/dist/fs/safe-paths.js +264 -0
- package/dist/fs/security-json.d.ts +13 -0
- package/dist/fs/security-json.js +67 -0
- package/dist/http/auth-context.d.ts +23 -0
- package/dist/http/auth-context.js +1 -0
- package/dist/http/engine-runtime-context.d.ts +30 -0
- package/dist/http/engine-runtime-context.js +1 -0
- package/dist/http/external-conversation-contract.d.ts +49 -0
- package/dist/http/external-conversation-contract.js +1 -0
- package/dist/http/external-conversation-headers.d.ts +11 -0
- package/dist/http/external-conversation-headers.js +11 -0
- package/dist/http/inference-context.d.ts +36 -0
- package/dist/http/inference-context.js +1 -0
- package/dist/http/model-inventory-cache.d.ts +8 -0
- package/dist/http/model-inventory-cache.js +8 -0
- package/dist/http/openai-compat/action-ledger.d.ts +15 -0
- package/dist/http/openai-compat/action-ledger.js +119 -0
- package/dist/http/openai-compat/apple-model.d.ts +3 -0
- package/dist/http/openai-compat/apple-model.js +44 -0
- package/dist/http/openai-compat/caller-owned-profile.d.ts +7 -0
- package/dist/http/openai-compat/caller-owned-profile.js +18 -0
- package/dist/http/openai-compat/chat-progress.d.ts +9 -0
- package/dist/http/openai-compat/chat-progress.js +69 -0
- package/dist/http/openai-compat/chat-target.d.ts +76 -0
- package/dist/http/openai-compat/chat-target.js +97 -0
- package/dist/http/openai-compat/embeddings.d.ts +37 -0
- package/dist/http/openai-compat/embeddings.js +86 -0
- package/dist/http/openai-compat/request-tuning.d.ts +35 -0
- package/dist/http/openai-compat/request-tuning.js +87 -0
- package/dist/http/openai-compat/responses-streaming.d.ts +351 -0
- package/dist/http/openai-compat/responses-streaming.js +717 -0
- package/dist/http/openai-compat/responses-translate.d.ts +215 -0
- package/dist/http/openai-compat/responses-translate.js +377 -0
- package/dist/http/openai-compat/streaming-telemetry.d.ts +30 -0
- package/dist/http/openai-compat/streaming-telemetry.js +88 -0
- package/dist/http/openai-compat/streaming.d.ts +141 -0
- package/dist/http/openai-compat/streaming.js +687 -0
- package/dist/http/openai-compat/tool-call-stream-filter.d.ts +33 -0
- package/dist/http/openai-compat/tool-call-stream-filter.js +110 -0
- package/dist/http/openai-compat/translate.d.ts +254 -0
- package/dist/http/openai-compat/translate.js +485 -0
- package/dist/http/routes/engines.d.ts +13 -0
- package/dist/http/routes/engines.js +366 -0
- package/dist/http/routes/machine-engine-proxy.d.ts +26 -0
- package/dist/http/routes/machine-engine-proxy.js +43 -0
- package/dist/http/routes/model-bundles.d.ts +4 -0
- package/dist/http/routes/model-bundles.js +190 -0
- package/dist/http/routes/v1-chat.d.ts +72 -0
- package/dist/http/routes/v1-chat.js +645 -0
- package/dist/http/routes/v1-embeddings.d.ts +3 -0
- package/dist/http/routes/v1-embeddings.js +82 -0
- package/dist/http/routes/v1-knowledge.d.ts +4 -0
- package/dist/http/routes/v1-knowledge.js +304 -0
- package/dist/http/routes/v1-models-ensure.d.ts +32 -0
- package/dist/http/routes/v1-models-ensure.js +122 -0
- package/dist/http/routes/v1-models.d.ts +8 -0
- package/dist/http/routes/v1-models.js +189 -0
- package/dist/http/routes/v1-responses.d.ts +20 -0
- package/dist/http/routes/v1-responses.js +327 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2 -0
- package/dist/inference-service.d.ts +28 -0
- package/dist/inference-service.js +275 -0
- package/dist/knowledge/admission.d.ts +3 -0
- package/dist/knowledge/admission.js +22 -0
- package/dist/knowledge/bundled-catalog.d.ts +2 -0
- package/dist/knowledge/bundled-catalog.js +2 -0
- package/dist/knowledge/catalog-host.d.ts +103 -0
- package/dist/knowledge/catalog-host.js +180 -0
- package/dist/knowledge/catalog-source.d.ts +22 -0
- package/dist/knowledge/catalog-source.js +35 -0
- package/dist/knowledge/install.d.ts +55 -0
- package/dist/knowledge/install.js +274 -0
- package/dist/knowledge/manager.d.ts +287 -0
- package/dist/knowledge/manager.js +1540 -0
- package/dist/knowledge/registry.d.ts +35 -0
- package/dist/knowledge/registry.js +123 -0
- package/dist/knowledge/search-worker.d.ts +17 -0
- package/dist/knowledge/search-worker.js +36 -0
- package/dist/knowledge/shared-install-contract.d.ts +19 -0
- package/dist/knowledge/shared-install-contract.js +1 -0
- package/dist/knowledge/spatial-query.d.ts +11 -0
- package/dist/knowledge/spatial-query.js +33 -0
- package/dist/knowledge/trust-anchors.d.ts +11 -0
- package/dist/knowledge/trust-anchors.js +51 -0
- package/dist/knowledge/vector-floors.d.ts +44 -0
- package/dist/knowledge/vector-floors.js +92 -0
- package/dist/knowledge/worker-host.d.ts +9 -0
- package/dist/knowledge/worker-host.js +179 -0
- package/dist/kokoro-lexicon/LICENSE +202 -0
- package/dist/kokoro-lexicon/lexicon-gb-en.txt.gz +0 -0
- package/dist/kokoro-lexicon/lexicon-us-en.txt.gz +0 -0
- package/dist/kokoro-lexicon/manifest.json +23 -0
- package/dist/machine-engine/inspect-runtime.d.ts +3 -0
- package/dist/machine-engine/inspect-runtime.js +48 -0
- package/dist/machine-engine/knowledge-assets.d.ts +79 -0
- package/dist/machine-engine/knowledge-assets.js +505 -0
- package/dist/memory/embed-core.d.ts +131 -0
- package/dist/memory/embed-core.js +398 -0
- package/dist/memory/embed-worker.d.ts +23 -0
- package/dist/memory/embed-worker.js +49 -0
- package/dist/memory/embeddings.d.ts +105 -0
- package/dist/memory/embeddings.js +467 -0
- package/dist/model-profile/behaviors/tools-mlx-template-fix.d.ts +1 -0
- package/dist/model-profile/behaviors/tools-mlx-template-fix.js +2 -0
- package/dist/model-profile/behaviors/turn-ramble-detection.d.ts +1 -0
- package/dist/model-profile/behaviors/turn-ramble-detection.js +2 -0
- package/dist/model-profile/defaults.d.ts +1 -0
- package/dist/model-profile/defaults.js +2 -0
- package/dist/model-profile/index.d.ts +9 -0
- package/dist/model-profile/index.js +7 -0
- package/dist/model-profile/registry.d.ts +15 -0
- package/dist/model-profile/registry.js +18 -0
- package/dist/model-profile/runtime.d.ts +48 -0
- package/dist/model-profile/runtime.js +131 -0
- package/dist/model-profile/tool-grammar.d.ts +1 -0
- package/dist/model-profile/tool-grammar.js +2 -0
- package/dist/model-profile/tuning.d.ts +19 -0
- package/dist/model-profile/tuning.js +21 -0
- package/dist/model-profile/types.d.ts +1 -0
- package/dist/model-profile/types.js +2 -0
- package/dist/models/bundle-storage.d.ts +28 -0
- package/dist/models/bundle-storage.js +80 -0
- package/dist/models/catalog-drift.d.ts +48 -0
- package/dist/models/catalog-drift.js +94 -0
- package/dist/models/catalog-payload-identity.d.ts +107 -0
- package/dist/models/catalog-payload-identity.js +254 -0
- package/dist/models/ensure.d.ts +125 -0
- package/dist/models/ensure.js +205 -0
- package/dist/models/gezmodel.d.ts +47 -0
- package/dist/models/gezmodel.js +742 -0
- package/dist/models/install-registry.d.ts +101 -0
- package/dist/models/install-registry.js +216 -0
- package/dist/models/model-id.d.ts +22 -0
- package/dist/models/model-id.js +40 -0
- package/dist/models/storage-roots.d.ts +274 -0
- package/dist/models/storage-roots.js +865 -0
- package/dist/native-release-entry.d.ts +16 -0
- package/dist/native-release-entry.js +16 -0
- package/dist/perf/redact-path.d.ts +2 -0
- package/dist/perf/redact-path.js +27 -0
- package/dist/perf/responsiveness.d.ts +70 -0
- package/dist/perf/responsiveness.js +560 -0
- package/dist/providers/active-install-message.d.ts +42 -0
- package/dist/providers/active-install-message.js +49 -0
- package/dist/providers/apple-foundation-models/binary.d.ts +4 -0
- package/dist/providers/apple-foundation-models/binary.js +18 -0
- package/dist/providers/apple-foundation-models/helper.d.ts +66 -0
- package/dist/providers/apple-foundation-models/helper.js +262 -0
- package/dist/providers/apple-foundation-models/provider.d.ts +82 -0
- package/dist/providers/apple-foundation-models/provider.js +389 -0
- package/dist/providers/apple-foundation-models/status.d.ts +9 -0
- package/dist/providers/apple-foundation-models/status.js +49 -0
- package/dist/providers/audio/kokoro-frontend.d.ts +50 -0
- package/dist/providers/audio/kokoro-frontend.js +113 -0
- package/dist/providers/audio/managed-speech-model.d.ts +9 -0
- package/dist/providers/audio/managed-speech-model.js +86 -0
- package/dist/providers/audio/types.d.ts +202 -0
- package/dist/providers/audio/types.js +17 -0
- package/dist/providers/audio/whisper-cpp.d.ts +99 -0
- package/dist/providers/audio/whisper-cpp.js +420 -0
- package/dist/providers/audio-persister-contract.d.ts +13 -0
- package/dist/providers/audio-persister-contract.js +1 -0
- package/dist/providers/catalog-model-config.d.ts +63 -0
- package/dist/providers/catalog-model-config.js +95 -0
- package/dist/providers/code-block-salvage.d.ts +1 -0
- package/dist/providers/code-block-salvage.js +2 -0
- package/dist/providers/codex-cli/reasoning.d.ts +8 -0
- package/dist/providers/codex-cli/reasoning.js +17 -0
- package/dist/providers/complete-tool-call.d.ts +16 -0
- package/dist/providers/complete-tool-call.js +25 -0
- package/dist/providers/constrained-turn.d.ts +1 -0
- package/dist/providers/constrained-turn.js +2 -0
- package/dist/providers/deliverable-read-pacing.d.ts +1 -0
- package/dist/providers/deliverable-read-pacing.js +2 -0
- package/dist/providers/direct-file-work-prompt.d.ts +1 -0
- package/dist/providers/direct-file-work-prompt.js +2 -0
- package/dist/providers/ds4/build-provider.d.ts +100 -0
- package/dist/providers/ds4/build-provider.js +539 -0
- package/dist/providers/ds4/cache-adapter.d.ts +42 -0
- package/dist/providers/ds4/cache-adapter.js +110 -0
- package/dist/providers/ds4/dspark.d.ts +83 -0
- package/dist/providers/ds4/dspark.js +107 -0
- package/dist/providers/ds4/mtp.d.ts +32 -0
- package/dist/providers/ds4/mtp.js +46 -0
- package/dist/providers/ds4/provider.d.ts +67 -0
- package/dist/providers/ds4/provider.js +104 -0
- package/dist/providers/ds4/residency.d.ts +143 -0
- package/dist/providers/ds4/residency.js +139 -0
- package/dist/providers/ds4/stdout-parser.d.ts +47 -0
- package/dist/providers/ds4/stdout-parser.js +134 -0
- package/dist/providers/duplicate-tool-calls.d.ts +1 -0
- package/dist/providers/duplicate-tool-calls.js +2 -0
- package/dist/providers/file-repair-policy.d.ts +1 -0
- package/dist/providers/file-repair-policy.js +2 -0
- package/dist/providers/gpu-arbiter.d.ts +159 -0
- package/dist/providers/gpu-arbiter.js +301 -0
- package/dist/providers/image-persister-contract.d.ts +15 -0
- package/dist/providers/image-persister-contract.js +1 -0
- package/dist/providers/llama-cpp/build-metadata.d.ts +13 -0
- package/dist/providers/llama-cpp/build-metadata.js +39 -0
- package/dist/providers/llama-cpp/build-provider.d.ts +66 -0
- package/dist/providers/llama-cpp/build-provider.js +1491 -0
- package/dist/providers/llama-cpp/cache-adapter.d.ts +242 -0
- package/dist/providers/llama-cpp/cache-adapter.js +689 -0
- package/dist/providers/llama-cpp/devices.d.ts +130 -0
- package/dist/providers/llama-cpp/devices.js +256 -0
- package/dist/providers/llama-cpp/disk-cache.d.ts +8 -0
- package/dist/providers/llama-cpp/disk-cache.js +112 -0
- package/dist/providers/llama-cpp/engine-flags.d.ts +181 -0
- package/dist/providers/llama-cpp/engine-flags.js +279 -0
- package/dist/providers/llama-cpp/gguf-metadata-async.d.ts +11 -0
- package/dist/providers/llama-cpp/gguf-metadata-async.js +180 -0
- package/dist/providers/llama-cpp/gguf-metadata-worker.d.ts +7 -0
- package/dist/providers/llama-cpp/gguf-metadata-worker.js +27 -0
- package/dist/providers/llama-cpp/gguf-metadata.d.ts +198 -0
- package/dist/providers/llama-cpp/gguf-metadata.js +615 -0
- package/dist/providers/llama-cpp/gguf-quantization-backfill.d.ts +32 -0
- package/dist/providers/llama-cpp/gguf-quantization-backfill.js +75 -0
- package/dist/providers/llama-cpp/index.d.ts +10 -0
- package/dist/providers/llama-cpp/index.js +13 -0
- package/dist/providers/llama-cpp/kv-cache-type.d.ts +118 -0
- package/dist/providers/llama-cpp/kv-cache-type.js +140 -0
- package/dist/providers/llama-cpp/log.d.ts +92 -0
- package/dist/providers/llama-cpp/log.js +280 -0
- package/dist/providers/llama-cpp/models.d.ts +389 -0
- package/dist/providers/llama-cpp/models.js +1011 -0
- package/dist/providers/llama-cpp/offload-planner.d.ts +339 -0
- package/dist/providers/llama-cpp/offload-planner.js +524 -0
- package/dist/providers/llama-cpp/provider.d.ts +493 -0
- package/dist/providers/llama-cpp/provider.js +862 -0
- package/dist/providers/llama-cpp/reasoning-launch.d.ts +7 -0
- package/dist/providers/llama-cpp/reasoning-launch.js +14 -0
- package/dist/providers/llama-cpp/spec-draft.d.ts +44 -0
- package/dist/providers/llama-cpp/spec-draft.js +44 -0
- package/dist/providers/llama-cpp/stdout-parser.d.ts +70 -0
- package/dist/providers/llama-cpp/stdout-parser.js +197 -0
- package/dist/providers/local-tool-call-salvage.d.ts +1 -0
- package/dist/providers/local-tool-call-salvage.js +2 -0
- package/dist/providers/local-turn-policy.d.ts +1 -0
- package/dist/providers/local-turn-policy.js +2 -0
- package/dist/providers/mlx/async-file-handoff.d.ts +11 -0
- package/dist/providers/mlx/async-file-handoff.js +25 -0
- package/dist/providers/mlx/build-provider.d.ts +65 -0
- package/dist/providers/mlx/build-provider.js +717 -0
- package/dist/providers/mlx/cache-adapter.d.ts +161 -0
- package/dist/providers/mlx/cache-adapter.js +445 -0
- package/dist/providers/mlx/chat-protocol.d.ts +48 -0
- package/dist/providers/mlx/chat-protocol.js +8 -0
- package/dist/providers/mlx/config-parser.d.ts +29 -0
- package/dist/providers/mlx/config-parser.js +81 -0
- package/dist/providers/mlx/engine-gate.d.ts +51 -0
- package/dist/providers/mlx/engine-gate.js +207 -0
- package/dist/providers/mlx/engine-hold.d.ts +41 -0
- package/dist/providers/mlx/engine-hold.js +59 -0
- package/dist/providers/mlx/engine-log-router.d.ts +84 -0
- package/dist/providers/mlx/engine-log-router.js +137 -0
- package/dist/providers/mlx/engine-stats-sampler.d.ts +36 -0
- package/dist/providers/mlx/engine-stats-sampler.js +59 -0
- package/dist/providers/mlx/index.d.ts +10 -0
- package/dist/providers/mlx/index.js +10 -0
- package/dist/providers/mlx/log.d.ts +55 -0
- package/dist/providers/mlx/log.js +157 -0
- package/dist/providers/mlx/model-geometry.d.ts +35 -0
- package/dist/providers/mlx/model-geometry.js +118 -0
- package/dist/providers/mlx/models.d.ts +289 -0
- package/dist/providers/mlx/models.js +1079 -0
- package/dist/providers/mlx/provider.d.ts +404 -0
- package/dist/providers/mlx/provider.js +3017 -0
- package/dist/providers/mlx/python/cache_persist.py +348 -0
- package/dist/providers/mlx/python/cache_seed.py +402 -0
- package/dist/providers/mlx/python/gezel_mlx_server.py +4491 -0
- package/dist/providers/mlx/python/lfm2_compat.py +55 -0
- package/dist/providers/mlx/python/qwen3_5_text_compat.py +60 -0
- package/dist/providers/mlx/python/qwen4_ple.py +159 -0
- package/dist/providers/mlx/python/spec_decode.py +775 -0
- package/dist/providers/mlx/python/template_stability.py +133 -0
- package/dist/providers/mlx/python/think_budget.py +113 -0
- package/dist/providers/mlx/python/tool_args_json.py +297 -0
- package/dist/providers/mlx/python/tool_call_stream.py +265 -0
- package/dist/providers/mlx/python/tool_grammar.py +794 -0
- package/dist/providers/mlx/python/vision_inputs.py +64 -0
- package/dist/providers/mlx/python/wave_policy.py +147 -0
- package/dist/providers/mlx/reasoning-stream.d.ts +85 -0
- package/dist/providers/mlx/reasoning-stream.js +196 -0
- package/dist/providers/mlx/request-shape.d.ts +34 -0
- package/dist/providers/mlx/request-shape.js +42 -0
- package/dist/providers/mlx/runtime-diagnostics.d.ts +29 -0
- package/dist/providers/mlx/runtime-diagnostics.js +162 -0
- package/dist/providers/mlx/spec-drafter.d.ts +25 -0
- package/dist/providers/mlx/spec-drafter.js +73 -0
- package/dist/providers/mlx/stdout-parser.d.ts +60 -0
- package/dist/providers/mlx/stdout-parser.js +254 -0
- package/dist/providers/mlx/textual-tool-call-salvage.d.ts +46 -0
- package/dist/providers/mlx/textual-tool-call-salvage.js +396 -0
- package/dist/providers/mlx/tool-call-protocol.d.ts +65 -0
- package/dist/providers/mlx/tool-call-protocol.js +140 -0
- package/dist/providers/mlx/tool-call-stripper.d.ts +68 -0
- package/dist/providers/mlx/tool-call-stripper.js +153 -0
- package/dist/providers/mlx/tool-image-retention.d.ts +23 -0
- package/dist/providers/mlx/tool-image-retention.js +43 -0
- package/dist/providers/mlx/turn-telemetry.d.ts +22 -0
- package/dist/providers/mlx/turn-telemetry.js +45 -0
- package/dist/providers/mlx/venv.d.ts +91 -0
- package/dist/providers/mlx/venv.js +111 -0
- package/dist/providers/mlx/vision-mode.d.ts +92 -0
- package/dist/providers/mlx/vision-mode.js +187 -0
- package/dist/providers/mlx/vision.d.ts +2 -0
- package/dist/providers/mlx/vision.js +12 -0
- package/dist/providers/mlx/wire-transcript.d.ts +14 -0
- package/dist/providers/mlx/wire-transcript.js +43 -0
- package/dist/providers/native/capacity-broker.d.ts +812 -0
- package/dist/providers/native/capacity-broker.js +1058 -0
- package/dist/providers/native/capacity-budget.d.ts +133 -0
- package/dist/providers/native/capacity-budget.js +265 -0
- package/dist/providers/native/device-capacity-ledger.d.ts +31 -0
- package/dist/providers/native/device-capacity-ledger.js +196 -0
- package/dist/providers/native/device-capacity.d.ts +84 -0
- package/dist/providers/native/device-capacity.js +431 -0
- package/dist/providers/native/engine-api-key.d.ts +57 -0
- package/dist/providers/native/engine-api-key.js +72 -0
- package/dist/providers/native/engine-key.d.ts +18 -0
- package/dist/providers/native/engine-key.js +41 -0
- package/dist/providers/native/engine-router.d.ts +145 -0
- package/dist/providers/native/engine-router.js +191 -0
- package/dist/providers/native/gpu-panic-guard.d.ts +54 -0
- package/dist/providers/native/gpu-panic-guard.js +59 -0
- package/dist/providers/native/inference.d.ts +33 -0
- package/dist/providers/native/inference.js +49 -0
- package/dist/providers/native/local-engine-runtime.d.ts +412 -0
- package/dist/providers/native/local-engine-runtime.js +1714 -0
- package/dist/providers/native/measured-budget.d.ts +32 -0
- package/dist/providers/native/measured-budget.js +54 -0
- package/dist/providers/native/port.d.ts +11 -0
- package/dist/providers/native/port.js +29 -0
- package/dist/providers/native/provider-pool.d.ts +474 -0
- package/dist/providers/native/provider-pool.js +1166 -0
- package/dist/providers/native/supervisor.d.ts +503 -0
- package/dist/providers/native/supervisor.js +1466 -0
- package/dist/providers/observation-context.d.ts +16 -0
- package/dist/providers/observation-context.js +1 -0
- package/dist/providers/openai-compatible/sse.d.ts +1 -0
- package/dist/providers/openai-compatible/sse.js +2 -0
- package/dist/providers/patient-fetch.d.ts +36 -0
- package/dist/providers/patient-fetch.js +44 -0
- package/dist/providers/project-macro-loop-bail.d.ts +7 -0
- package/dist/providers/project-macro-loop-bail.js +21 -0
- package/dist/providers/prose-document-salvage.d.ts +1 -0
- package/dist/providers/prose-document-salvage.js +2 -0
- package/dist/providers/provider-disposal.d.ts +1 -0
- package/dist/providers/provider-disposal.js +2 -0
- package/dist/providers/queue.d.ts +15 -0
- package/dist/providers/queue.js +23 -0
- package/dist/providers/ramble-abort-message.d.ts +1 -0
- package/dist/providers/ramble-abort-message.js +2 -0
- package/dist/providers/ramble-detector.d.ts +1 -0
- package/dist/providers/ramble-detector.js +2 -0
- package/dist/providers/reasoning-depth.d.ts +1 -0
- package/dist/providers/reasoning-depth.js +2 -0
- package/dist/providers/required-input-reads.d.ts +1 -0
- package/dist/providers/required-input-reads.js +2 -0
- package/dist/providers/session-defaults.d.ts +13 -0
- package/dist/providers/session-defaults.js +49 -0
- package/dist/providers/session-hooks.d.ts +26 -0
- package/dist/providers/session-hooks.js +1 -0
- package/dist/providers/streaming-session.d.ts +1 -0
- package/dist/providers/streaming-session.js +2 -0
- package/dist/providers/terminal-tool-policy.d.ts +1 -0
- package/dist/providers/terminal-tool-policy.js +2 -0
- package/dist/providers/tool-arg-schema-coercion.d.ts +1 -0
- package/dist/providers/tool-arg-schema-coercion.js +2 -0
- package/dist/providers/tool-executor.d.ts +12 -0
- package/dist/providers/tool-executor.js +20 -0
- package/dist/providers/tool-failure-tracker.d.ts +1 -0
- package/dist/providers/tool-failure-tracker.js +2 -0
- package/dist/providers/tool-repeat-tracker.d.ts +1 -0
- package/dist/providers/tool-repeat-tracker.js +2 -0
- package/dist/providers/turn-timeout.d.ts +1 -0
- package/dist/providers/turn-timeout.js +1 -0
- package/dist/providers/types.d.ts +834 -0
- package/dist/providers/types.js +42 -0
- package/dist/providers/usage-builder.d.ts +1 -0
- package/dist/providers/usage-builder.js +2 -0
- package/dist/providers/vision-capability.d.ts +109 -0
- package/dist/providers/vision-capability.js +137 -0
- package/dist/python/mlx-runtime-status-bus.d.ts +39 -0
- package/dist/python/mlx-runtime-status-bus.js +27 -0
- package/dist/python/uv-runtime.d.ts +176 -0
- package/dist/python/uv-runtime.js +492 -0
- package/dist/relevance/install.d.ts +28 -0
- package/dist/relevance/install.js +114 -0
- package/dist/relevance/manager.d.ts +79 -0
- package/dist/relevance/manager.js +211 -0
- package/dist/relevance/registry.d.ts +11 -0
- package/dist/relevance/registry.js +158 -0
- package/dist/relevance/relevance-core.d.ts +67 -0
- package/dist/relevance/relevance-core.js +189 -0
- package/dist/relevance/relevance-model.d.ts +42 -0
- package/dist/relevance/relevance-model.js +292 -0
- package/dist/relevance/relevance-worker.d.ts +20 -0
- package/dist/relevance/relevance-worker.js +57 -0
- package/dist/relevance/settings.d.ts +30 -0
- package/dist/relevance/settings.js +81 -0
- package/dist/remotes/identity.d.ts +121 -0
- package/dist/remotes/identity.js +348 -0
- package/dist/remotes/pinned-fetch.d.ts +45 -0
- package/dist/remotes/pinned-fetch.js +193 -0
- package/dist/remotes/types.d.ts +54 -0
- package/dist/remotes/types.js +1 -0
- package/dist/runtime-lock.d.ts +29 -0
- package/dist/runtime-lock.js +85 -0
- package/dist/search/relevance-stage.d.ts +81 -0
- package/dist/search/relevance-stage.js +177 -0
- package/dist/secrets/types.d.ts +63 -0
- package/dist/secrets/types.js +64 -0
- package/dist/speech.d.ts +1 -0
- package/dist/speech.js +1 -0
- package/dist/system/darwin-memory.d.ts +26 -0
- package/dist/system/darwin-memory.js +81 -0
- package/dist/system/gezel-process-memory.d.ts +55 -0
- package/dist/system/gezel-process-memory.js +156 -0
- package/dist/system/memory.d.ts +154 -0
- package/dist/system/memory.js +501 -0
- package/dist/transformers-cache.d.ts +112 -0
- package/dist/transformers-cache.js +392 -0
- package/dist/utils/disk-space.d.ts +55 -0
- package/dist/utils/disk-space.js +72 -0
- package/dist/utils/download-common.d.ts +138 -0
- package/dist/utils/download-common.js +196 -0
- package/dist/utils/download-with-retry.d.ts +85 -0
- package/dist/utils/download-with-retry.js +522 -0
- package/dist/utils/extract-zip.d.ts +22 -0
- package/dist/utils/extract-zip.js +103 -0
- package/dist/utils/retire-model-worker.d.ts +15 -0
- package/dist/utils/retire-model-worker.js +24 -0
- package/dist/utils/service-worker-entry.d.ts +59 -0
- package/dist/utils/service-worker-entry.js +69 -0
- package/dist/utils/xet-download.d.ts +40 -0
- package/dist/utils/xet-download.js +526 -0
- package/dist/utils/xet.d.ts +86 -0
- package/dist/utils/xet.js +201 -0
- package/package.json +103 -3
- package/scripts/embedding-packaging.cjs +264 -0
- package/scripts/embedding-packaging.d.cts +16 -0
|
@@ -0,0 +1,1079 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MLX model storage + install pipeline.
|
|
3
|
+
*
|
|
4
|
+
* Storage layout:
|
|
5
|
+
*
|
|
6
|
+
* <home>/engines/mlx/
|
|
7
|
+
* └── models/
|
|
8
|
+
* └── <model-id>/
|
|
9
|
+
* ├── manifest.json (our install record)
|
|
10
|
+
* ├── config.json (HF model config)
|
|
11
|
+
* ├── tokenizer.json
|
|
12
|
+
* ├── tokenizer_config.json
|
|
13
|
+
* ├── model.safetensors (or sharded model-*.safetensors)
|
|
14
|
+
* └── model.safetensors.index.json (if sharded)
|
|
15
|
+
*
|
|
16
|
+
* Install flow (mirrors LlamaCppModelManager.install):
|
|
17
|
+
* 1. Look up the chat-model in the catalog; require an `mlx` source
|
|
18
|
+
* block with a file list + per-file sha256.
|
|
19
|
+
* 2. For each file, stream-download from
|
|
20
|
+
* `huggingface.co/<repo>/resolve/<revision>/<name>` (the pinned
|
|
21
|
+
* commit SHA, or `main` for legacy manifests) to a `.partial`
|
|
22
|
+
* sibling, hashing as we go.
|
|
23
|
+
* 3. Verify each file's sha256 against the manifest pin.
|
|
24
|
+
* 4. Read `config.json` / `tokenizer_config.json` to extract
|
|
25
|
+
* contextWindow + chat-template presence.
|
|
26
|
+
* 5. Atomically rename `.partial` files into place + write
|
|
27
|
+
* `manifest.json`.
|
|
28
|
+
* 6. Yield a terminal `done` or `error` event.
|
|
29
|
+
*
|
|
30
|
+
* Delete + resolve flows are identical in shape to the llama-cpp
|
|
31
|
+
* manager — "first installed, alphabetical" is the default until a
|
|
32
|
+
* proper picker UI lands.
|
|
33
|
+
*/
|
|
34
|
+
import { createHash } from 'node:crypto';
|
|
35
|
+
import { createReadStream } from 'node:fs';
|
|
36
|
+
import { mkdir, readFile, readdir, rename, rm, stat, writeFile } from 'node:fs/promises';
|
|
37
|
+
import { dirname, join, resolve as resolvePath } from 'node:path';
|
|
38
|
+
import { createLogger } from '@bendyline/gezel';
|
|
39
|
+
import { listBundleModelFiles, publishStagedModel, } from '../../models/bundle-storage.js';
|
|
40
|
+
import { evaluateCatalogDrift } from '../../models/catalog-drift.js';
|
|
41
|
+
import { catalogPayloadFingerprint, describeCatalogPayload, } from '../../models/catalog-payload-identity.js';
|
|
42
|
+
import { MODEL_HASH_READ_BUFFER_BYTES, assertModelStorePathSafe, findModelRoot, findRenamedModelId, hashModelPayloadFiles, inspectModelDirectory, listIncompleteModelDownloads, listOverlayModelIds, makeSharedModelReadable, modelExistsOnlyReadOnly, modelStorageRoots, pruneModelPayloadFiles, readOnlyModelError, removeModelDir, verifyReadOnlyModelPayload, } from '../../models/storage-roots.js';
|
|
43
|
+
import { checkDiskSpace, describeDiskShortfall } from '../../utils/disk-space.js';
|
|
44
|
+
import { downloadWithRetry } from '../../utils/download-with-retry.js';
|
|
45
|
+
import { readMlxSummary } from './config-parser.js';
|
|
46
|
+
const PROGRESS_INTERVAL_MS = 250;
|
|
47
|
+
/**
|
|
48
|
+
* How many of a model's files to download at once. MLX models ship as
|
|
49
|
+
* several safetensors shards plus tokenizer/config files; fetching a
|
|
50
|
+
* few concurrently overlaps TLS/connection setup and TCP slow-start
|
|
51
|
+
* across files, cutting wall-clock ~30–40% on multi-shard models vs a
|
|
52
|
+
* strictly-sequential loop. Kept modest so we don't saturate a slow
|
|
53
|
+
* link (which would just make every file progress slower) or trip HF
|
|
54
|
+
* rate-limiting. Single-file models are unaffected.
|
|
55
|
+
*/
|
|
56
|
+
const MLX_DOWNLOAD_CONCURRENCY = 3;
|
|
57
|
+
const log = createLogger('models');
|
|
58
|
+
/**
|
|
59
|
+
* Minimal single-consumer async queue bridging the concurrent download
|
|
60
|
+
* workers (which `push` events synchronously) to the `install()` async
|
|
61
|
+
* generator (which `yield`s them) — a generator can't `yield` from
|
|
62
|
+
* inside the worker promises, so events flow through here. Push is
|
|
63
|
+
* unbounded and non-blocking; `close()` ends iteration once buffered
|
|
64
|
+
* items drain. Exactly one consumer (`install`) iterates it.
|
|
65
|
+
*/
|
|
66
|
+
class AsyncEventQueue {
|
|
67
|
+
buffer = [];
|
|
68
|
+
pendingResolve = null;
|
|
69
|
+
closed = false;
|
|
70
|
+
push(item) {
|
|
71
|
+
if (this.closed)
|
|
72
|
+
return;
|
|
73
|
+
if (this.pendingResolve) {
|
|
74
|
+
const resolve = this.pendingResolve;
|
|
75
|
+
this.pendingResolve = null;
|
|
76
|
+
resolve({ value: item, done: false });
|
|
77
|
+
}
|
|
78
|
+
else {
|
|
79
|
+
this.buffer.push(item);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
close() {
|
|
83
|
+
if (this.closed)
|
|
84
|
+
return;
|
|
85
|
+
this.closed = true;
|
|
86
|
+
if (this.pendingResolve) {
|
|
87
|
+
const resolve = this.pendingResolve;
|
|
88
|
+
this.pendingResolve = null;
|
|
89
|
+
resolve({ value: undefined, done: true });
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
[Symbol.asyncIterator]() {
|
|
93
|
+
return {
|
|
94
|
+
next: () => {
|
|
95
|
+
if (this.buffer.length > 0) {
|
|
96
|
+
return Promise.resolve({ value: this.buffer.shift(), done: false });
|
|
97
|
+
}
|
|
98
|
+
if (this.closed) {
|
|
99
|
+
return Promise.resolve({ value: undefined, done: true });
|
|
100
|
+
}
|
|
101
|
+
return new Promise((resolve) => {
|
|
102
|
+
this.pendingResolve = resolve;
|
|
103
|
+
});
|
|
104
|
+
},
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
export class MlxModelManager {
|
|
109
|
+
modelsRoot;
|
|
110
|
+
viewsRoot;
|
|
111
|
+
storageRoots;
|
|
112
|
+
catalog;
|
|
113
|
+
fetchImpl;
|
|
114
|
+
onInstallStart;
|
|
115
|
+
onInstalled;
|
|
116
|
+
/**
|
|
117
|
+
* In-flight installs. See {@link LlamaCppModelManager.activeInstalls}
|
|
118
|
+
* — same rationale, same shape: the first-run bootstrap fires
|
|
119
|
+
* `install()` server-side and the Settings catalog UI needs a
|
|
120
|
+
* polled view of it.
|
|
121
|
+
*/
|
|
122
|
+
activeInstalls = new Map();
|
|
123
|
+
/**
|
|
124
|
+
* Model directories we've already warned about skipping. `listInstalled`
|
|
125
|
+
* runs on every picker/settings poll; a broken directory should be loud
|
|
126
|
+
* exactly once per process, not once per poll.
|
|
127
|
+
*/
|
|
128
|
+
skipWarned = new Set();
|
|
129
|
+
constructor(opts) {
|
|
130
|
+
this.storageRoots = modelStorageRoots({ home: opts.home, engine: 'mlx' });
|
|
131
|
+
this.modelsRoot = this.storageRoots.writableRoot;
|
|
132
|
+
this.viewsRoot = join(opts.home, 'engines', 'mlx', 'views');
|
|
133
|
+
this.catalog = opts.catalog;
|
|
134
|
+
this.fetchImpl = opts.fetchImpl ?? fetch;
|
|
135
|
+
if (opts.onInstallStart)
|
|
136
|
+
this.onInstallStart = opts.onInstallStart;
|
|
137
|
+
if (opts.onInstalled)
|
|
138
|
+
this.onInstalled = opts.onInstalled;
|
|
139
|
+
}
|
|
140
|
+
getActiveInstalls() {
|
|
141
|
+
return Array.from(this.activeInstalls.values()).map((entry) => ({ ...entry }));
|
|
142
|
+
}
|
|
143
|
+
async listInstalled() {
|
|
144
|
+
const entries = await listOverlayModelIds(this.storageRoots);
|
|
145
|
+
const out = [];
|
|
146
|
+
for (const id of entries) {
|
|
147
|
+
const summary = await this.loadInstalled(id);
|
|
148
|
+
if (!summary) {
|
|
149
|
+
this.warnSkip(id, 'no readable manifest.json (incomplete or interrupted download?)');
|
|
150
|
+
continue;
|
|
151
|
+
}
|
|
152
|
+
// Does the catalog now describe different weights than the ones on
|
|
153
|
+
// disk? Best-effort — a catalog miss (third-party / removed entry)
|
|
154
|
+
// leaves it un-flagged.
|
|
155
|
+
const status = await this.evaluateDrift(id, summary).catch(() => null);
|
|
156
|
+
if (status?.updateAvailable) {
|
|
157
|
+
summary.updateAvailable = true;
|
|
158
|
+
if (status.availableVersion)
|
|
159
|
+
summary.availableVersion = status.availableVersion;
|
|
160
|
+
if (status.reason)
|
|
161
|
+
summary.updateReason = status.reason;
|
|
162
|
+
}
|
|
163
|
+
out.push(summary);
|
|
164
|
+
}
|
|
165
|
+
out.sort((a, b) => a.name.localeCompare(b.name));
|
|
166
|
+
return out;
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* Whether a genuinely newer build of one installed model exists. Null when
|
|
170
|
+
* the id isn't installed for MLX. Shared with the chat manager's
|
|
171
|
+
* per-session staleness notice so a user is never told to re-download for a
|
|
172
|
+
* change that only touched metadata.
|
|
173
|
+
*/
|
|
174
|
+
async getUpdateStatus(id) {
|
|
175
|
+
const summary = await this.loadInstalled(id);
|
|
176
|
+
if (!summary)
|
|
177
|
+
return null;
|
|
178
|
+
return this.evaluateDrift(id, summary).catch(() => ({ updateAvailable: false }));
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* Compare one installed copy against the live catalog. The catalog lookup
|
|
182
|
+
* runs for every model on every inventory poll; the manifest re-read only
|
|
183
|
+
* happens for the few whose version actually moved.
|
|
184
|
+
*/
|
|
185
|
+
async evaluateDrift(id, summary) {
|
|
186
|
+
if (!summary.catalogVersion)
|
|
187
|
+
return { updateAvailable: false };
|
|
188
|
+
const detail = await this.catalog.get('chat-model', id).catch(() => null);
|
|
189
|
+
if (!detail || detail.manifest.kind !== 'chat-model')
|
|
190
|
+
return { updateAvailable: false };
|
|
191
|
+
if (detail.manifest.version === summary.catalogVersion)
|
|
192
|
+
return { updateAvailable: false };
|
|
193
|
+
const parsed = await readFile(join(summary.modelDir, 'manifest.json'), 'utf8')
|
|
194
|
+
.then((raw) => JSON.parse(raw))
|
|
195
|
+
.catch(() => null);
|
|
196
|
+
if (!parsed)
|
|
197
|
+
return { updateAvailable: false };
|
|
198
|
+
return evaluateCatalogDrift({
|
|
199
|
+
engine: 'mlx',
|
|
200
|
+
id,
|
|
201
|
+
modelDir: summary.modelDir,
|
|
202
|
+
manifest: detail.manifest,
|
|
203
|
+
installedVersion: summary.catalogVersion,
|
|
204
|
+
installed: {
|
|
205
|
+
...(parsed.huggingfaceRepo ? { huggingfaceRepo: parsed.huggingfaceRepo } : {}),
|
|
206
|
+
...(parsed.payloadFingerprint ? { payloadFingerprint: parsed.payloadFingerprint } : {}),
|
|
207
|
+
...(parsed.fileSha256 ? { fileSha256: parsed.fileSha256 } : {}),
|
|
208
|
+
},
|
|
209
|
+
healable: !summary.readOnly && !this.activeInstalls.has(id),
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
/**
|
|
213
|
+
* List incomplete MLX downloads — directories that hold bytes but no
|
|
214
|
+
* `manifest.json`, so they never surface in {@link listInstalled}. Tagged
|
|
215
|
+
* `resumable` when the id still resolves to an MLX-capable catalog entry.
|
|
216
|
+
* In-flight installs are excluded. See {@link LlamaCppModelManager.listIncomplete}.
|
|
217
|
+
*/
|
|
218
|
+
async listIncomplete() {
|
|
219
|
+
const activeIds = new Set(this.activeInstalls.keys());
|
|
220
|
+
const rows = await listIncompleteModelDownloads({ writableRoot: this.modelsRoot, activeIds });
|
|
221
|
+
const out = [];
|
|
222
|
+
for (const row of rows) {
|
|
223
|
+
let resumable = false;
|
|
224
|
+
let name;
|
|
225
|
+
if (isSafeId(row.id)) {
|
|
226
|
+
const detail = await this.catalog.get('chat-model', row.id).catch(() => null);
|
|
227
|
+
if (detail &&
|
|
228
|
+
detail.manifest.kind === 'chat-model' &&
|
|
229
|
+
detail.manifest.mlx &&
|
|
230
|
+
!detail.manifest.mlx.disabledReason) {
|
|
231
|
+
resumable = true;
|
|
232
|
+
name = detail.manifest.name;
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
out.push({ ...row, resumable, ...(name ? { name } : {}) });
|
|
236
|
+
}
|
|
237
|
+
return out;
|
|
238
|
+
}
|
|
239
|
+
/** Management-only inventory for MLX directories whose manifest exists
|
|
240
|
+
* but no longer matches the current installed-manifest contract. */
|
|
241
|
+
async listUnrecognized() {
|
|
242
|
+
const rows = [];
|
|
243
|
+
for (const id of await listOverlayModelIds(this.storageRoots)) {
|
|
244
|
+
if (!isSafeId(id))
|
|
245
|
+
continue;
|
|
246
|
+
const root = await findModelRoot(this.storageRoots, id);
|
|
247
|
+
if (!root)
|
|
248
|
+
continue;
|
|
249
|
+
if (await this.loadInstalled(id))
|
|
250
|
+
continue;
|
|
251
|
+
const profile = await inspectModelDirectory(join(root, id));
|
|
252
|
+
if (!profile || profile.bytes === 0)
|
|
253
|
+
continue;
|
|
254
|
+
const raw = await readFile(join(root, id, 'manifest.json'), 'utf8').catch(() => null);
|
|
255
|
+
let legacyName;
|
|
256
|
+
let reason = "Gezel couldn't read this model's metadata.";
|
|
257
|
+
if (raw !== null) {
|
|
258
|
+
try {
|
|
259
|
+
const parsed = JSON.parse(raw);
|
|
260
|
+
if (typeof parsed.name === 'string' && parsed.name.trim())
|
|
261
|
+
legacyName = parsed.name;
|
|
262
|
+
reason = 'This model metadata is incomplete or does not match the current format.';
|
|
263
|
+
}
|
|
264
|
+
catch {
|
|
265
|
+
reason = "This model's metadata file is not valid JSON.";
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
const detail = await this.catalog.get('chat-model', id).catch(() => null);
|
|
269
|
+
const catalogManifest = detail?.manifest.kind === 'chat-model' ? detail.manifest : undefined;
|
|
270
|
+
const canUpdate = Boolean(catalogManifest?.mlx && !catalogManifest.mlx.disabledReason);
|
|
271
|
+
const name = catalogManifest?.name ?? legacyName;
|
|
272
|
+
rows.push({
|
|
273
|
+
id,
|
|
274
|
+
...(name ? { name } : {}),
|
|
275
|
+
bytes: profile.bytes,
|
|
276
|
+
updatedAt: profile.updatedAt,
|
|
277
|
+
reason,
|
|
278
|
+
canUpdate,
|
|
279
|
+
...(resolvePath(root) !== resolvePath(this.storageRoots.writableRoot)
|
|
280
|
+
? { readOnly: true }
|
|
281
|
+
: {}),
|
|
282
|
+
});
|
|
283
|
+
}
|
|
284
|
+
rows.sort((a, b) => b.bytes - a.bytes);
|
|
285
|
+
return rows;
|
|
286
|
+
}
|
|
287
|
+
async resolveDefaultModel() {
|
|
288
|
+
const models = await this.listInstalled();
|
|
289
|
+
return models[0] ?? null;
|
|
290
|
+
}
|
|
291
|
+
async resolveDefaultModelPath() {
|
|
292
|
+
const model = await this.resolveDefaultModel();
|
|
293
|
+
return model?.modelDir ?? null;
|
|
294
|
+
}
|
|
295
|
+
async resolveModel(id) {
|
|
296
|
+
return this.loadInstalled(id);
|
|
297
|
+
}
|
|
298
|
+
async resolveModelPath(id) {
|
|
299
|
+
const summary = await this.loadInstalled(id);
|
|
300
|
+
return summary?.modelDir ?? null;
|
|
301
|
+
}
|
|
302
|
+
async delete(id) {
|
|
303
|
+
if (!isSafeId(id))
|
|
304
|
+
throw new Error(`refusing to delete with unsafe id: ${id}`);
|
|
305
|
+
if (await modelExistsOnlyReadOnly(this.storageRoots, id)) {
|
|
306
|
+
throw readOnlyModelError(id);
|
|
307
|
+
}
|
|
308
|
+
// External-PLE views hard-link the installed shards. Removing the model
|
|
309
|
+
// without its derived view would keep a 100+ GiB checkpoint allocated.
|
|
310
|
+
await rm(join(this.viewsRoot, id), { recursive: true, force: true });
|
|
311
|
+
await removeModelDir(join(this.modelsRoot, id), this.modelsRoot);
|
|
312
|
+
}
|
|
313
|
+
/** Provider-owned snapshot used by the streaming `.gezmodel` exporter. */
|
|
314
|
+
async getModelBundleSource(id) {
|
|
315
|
+
if (!isSafeId(id))
|
|
316
|
+
throw new Error(`unsafe model id: ${id}`);
|
|
317
|
+
const summary = await this.loadInstalled(id);
|
|
318
|
+
if (!summary)
|
|
319
|
+
throw new Error(`model "${id}" is not available locally for mlx`);
|
|
320
|
+
const root = await findModelRoot(this.storageRoots, id);
|
|
321
|
+
if (!root)
|
|
322
|
+
throw new Error(`model "${id}" is not available locally for mlx`);
|
|
323
|
+
const modelDir = join(root, id);
|
|
324
|
+
const installedManifest = JSON.parse(await readFile(join(modelDir, 'manifest.json'), 'utf8'));
|
|
325
|
+
return {
|
|
326
|
+
id,
|
|
327
|
+
name: summary.name,
|
|
328
|
+
modelDir,
|
|
329
|
+
installedManifest,
|
|
330
|
+
modelFiles: await listBundleModelFiles(modelDir),
|
|
331
|
+
...(summary.catalogVersion ? { catalogVersion: summary.catalogVersion } : {}),
|
|
332
|
+
};
|
|
333
|
+
}
|
|
334
|
+
/** Publish a fully-scanned MLX model directory into the provider store. */
|
|
335
|
+
async importModelBundle(opts) {
|
|
336
|
+
if (!isSafeId(opts.id))
|
|
337
|
+
throw new Error(`unsafe model id: ${opts.id}`);
|
|
338
|
+
const parsed = opts.installedManifest;
|
|
339
|
+
if (parsed.id !== opts.id || !parsed.name || !parsed.installedAt) {
|
|
340
|
+
throw new Error('installed manifest does not describe the bundled model');
|
|
341
|
+
}
|
|
342
|
+
const files = await listBundleModelFiles(opts.stagedModelDir);
|
|
343
|
+
if (!files.some((file) => file.toLowerCase().endsWith('.safetensors'))) {
|
|
344
|
+
throw new Error('MLX bundle has no safetensors weights');
|
|
345
|
+
}
|
|
346
|
+
if (!files.includes('config.json'))
|
|
347
|
+
throw new Error('MLX bundle has no config.json');
|
|
348
|
+
const summary = await readMlxSummary(opts.stagedModelDir);
|
|
349
|
+
const installed = {
|
|
350
|
+
...parsed,
|
|
351
|
+
id: opts.id,
|
|
352
|
+
name: parsed.name,
|
|
353
|
+
approxSizeBytes: parsed.approxSizeBytes ?? 0,
|
|
354
|
+
installedAt: parsed.installedAt,
|
|
355
|
+
catalogId: parsed.catalogId ?? opts.id,
|
|
356
|
+
catalogVersion: parsed.catalogVersion ?? '0.0.0',
|
|
357
|
+
huggingfaceRepo: parsed.huggingfaceRepo ?? 'imported/gezmodel',
|
|
358
|
+
contextWindow: summary.contextWindow ?? parsed.contextWindow,
|
|
359
|
+
architecture: summary.architecture ?? parsed.architecture,
|
|
360
|
+
chatTemplatePresent: summary.chatTemplatePresent,
|
|
361
|
+
files,
|
|
362
|
+
fileSha256: await hashModelPayloadFiles(opts.stagedModelDir),
|
|
363
|
+
};
|
|
364
|
+
await writeFile(join(opts.stagedModelDir, 'manifest.json'), `${JSON.stringify(installed, null, 2)}\n`, 'utf8');
|
|
365
|
+
await publishStagedModel({
|
|
366
|
+
modelsRoot: this.modelsRoot,
|
|
367
|
+
id: opts.id,
|
|
368
|
+
stagedModelDir: opts.stagedModelDir,
|
|
369
|
+
replace: opts.replace,
|
|
370
|
+
});
|
|
371
|
+
await makeSharedModelReadable(join(this.modelsRoot, opts.id));
|
|
372
|
+
try {
|
|
373
|
+
this.onInstalled?.({ engine: 'mlx', id: opts.id });
|
|
374
|
+
}
|
|
375
|
+
catch {
|
|
376
|
+
// A post-install fitness hook is best-effort, as in the download path.
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
/**
|
|
380
|
+
* Install from the catalog. Yields progress events per file; emits
|
|
381
|
+
* exactly one terminal event. Existing models at `id` are atomically
|
|
382
|
+
* replaced — files download to `.partial` siblings and rename only
|
|
383
|
+
* after sha256 verification, same as llama-cpp.
|
|
384
|
+
*/
|
|
385
|
+
async *install(catalogId, options) {
|
|
386
|
+
const skipSha = options?.skipSha === true;
|
|
387
|
+
if (!isSafeId(catalogId)) {
|
|
388
|
+
yield { type: 'error', error: `unsafe catalog id: ${catalogId}` };
|
|
389
|
+
return;
|
|
390
|
+
}
|
|
391
|
+
// Reject duplicate concurrent installs — see the matching branch
|
|
392
|
+
// on `LlamaCppModelManager.install`. MLX is even more sensitive
|
|
393
|
+
// to this because each install writes multiple `.partial` files
|
|
394
|
+
// in the same directory. Claim the slot synchronously before any
|
|
395
|
+
// `await` so a parallel caller can't pass `has() === false` in
|
|
396
|
+
// the same JS turn.
|
|
397
|
+
if (this.activeInstalls.has(catalogId)) {
|
|
398
|
+
yield {
|
|
399
|
+
type: 'error',
|
|
400
|
+
error: `install for "${catalogId}" is already in progress`,
|
|
401
|
+
};
|
|
402
|
+
return;
|
|
403
|
+
}
|
|
404
|
+
const tracked = {
|
|
405
|
+
catalogId,
|
|
406
|
+
bytesWritten: 0,
|
|
407
|
+
totalBytes: 0,
|
|
408
|
+
phase: 'downloading',
|
|
409
|
+
startedAt: new Date().toISOString(),
|
|
410
|
+
};
|
|
411
|
+
this.activeInstalls.set(catalogId, tracked);
|
|
412
|
+
try {
|
|
413
|
+
const detail = await this.catalog.get('chat-model', catalogId);
|
|
414
|
+
if (!detail || detail.manifest.kind !== 'chat-model') {
|
|
415
|
+
yield { type: 'error', error: `chat-model "${catalogId}" not in catalog` };
|
|
416
|
+
return;
|
|
417
|
+
}
|
|
418
|
+
const manifest = detail.manifest;
|
|
419
|
+
if (!manifest.mlx || manifest.mlx.disabledReason) {
|
|
420
|
+
yield {
|
|
421
|
+
type: 'error',
|
|
422
|
+
error: manifest.mlx?.disabledReason
|
|
423
|
+
? `chat-model "${catalogId}" is not available on MLX: ${manifest.mlx.disabledReason} Run it via llama instead.`
|
|
424
|
+
: `chat-model "${catalogId}" has no mlx source — not available for MLX`,
|
|
425
|
+
};
|
|
426
|
+
return;
|
|
427
|
+
}
|
|
428
|
+
const src = manifest.mlx;
|
|
429
|
+
// Start provisioning the MLX Python environment at the same time
|
|
430
|
+
// as the weights download. This belongs at the model-manager
|
|
431
|
+
// boundary (rather than one particular HTTP route) so installs
|
|
432
|
+
// from Settings, first-run bootstrap, and /v1/models/ensure all
|
|
433
|
+
// receive the same overlap. Never let host setup abort a model
|
|
434
|
+
// download; the lazy first-chat path remains authoritative.
|
|
435
|
+
try {
|
|
436
|
+
this.onInstallStart?.({ catalogId });
|
|
437
|
+
}
|
|
438
|
+
catch {
|
|
439
|
+
/* host owns setup errors */
|
|
440
|
+
}
|
|
441
|
+
const itemDir = join(this.modelsRoot, catalogId);
|
|
442
|
+
await mkdir(this.modelsRoot, { recursive: true });
|
|
443
|
+
await assertModelStorePathSafe(this.modelsRoot, itemDir);
|
|
444
|
+
await mkdir(itemDir, { recursive: true });
|
|
445
|
+
await assertModelStorePathSafe(this.modelsRoot, itemDir);
|
|
446
|
+
const files = src.files.filter((f) => f != null);
|
|
447
|
+
const fileCount = files.length;
|
|
448
|
+
const totalBytesAll = files.reduce((sum, f) => sum + (f.sizeBytes ?? 0), 0);
|
|
449
|
+
tracked.totalBytes = totalBytesAll;
|
|
450
|
+
tracked.phase = 'downloading';
|
|
451
|
+
// Files this update doesn't have to fetch because the copy on disk is
|
|
452
|
+
// already the copy the catalog pins. MLX repos are many files and a
|
|
453
|
+
// rebuild usually rotates the weight shards while config.json,
|
|
454
|
+
// tokenizer.json and friends stay byte-identical.
|
|
455
|
+
const reusable = await this.planReusableFiles(itemDir, files);
|
|
456
|
+
const verifiedDigests = {};
|
|
457
|
+
for (const [name, sha] of reusable)
|
|
458
|
+
verifiedDigests[name] = sha;
|
|
459
|
+
const toFetch = files.filter((file) => !reusable.has(file.name));
|
|
460
|
+
if (reusable.size > 0) {
|
|
461
|
+
log.info(`[models] [mlx] "${catalogId}": ${reusable.size} of ${files.length} file(s) already match the catalog and will not be downloaded`);
|
|
462
|
+
}
|
|
463
|
+
// Preflight free space before writing anything — see the matching check
|
|
464
|
+
// in `LlamaCppModelManager`. MLX installs write every shard into one
|
|
465
|
+
// directory, so a late ENOSPC strands the whole set. Only what we
|
|
466
|
+
// actually have to fetch is charged, less any `.partial` resume credit;
|
|
467
|
+
// a file being replaced is charged in full because its `.partial` lives
|
|
468
|
+
// beside the old copy until publish.
|
|
469
|
+
const needBytes = toFetch.reduce((sum, f) => sum + (f.sizeBytes ?? 0), 0) -
|
|
470
|
+
(await mlxPartialBytesOnDisk(itemDir, toFetch));
|
|
471
|
+
const space = await checkDiskSpace(itemDir, Math.max(0, needBytes));
|
|
472
|
+
if (!space.ok) {
|
|
473
|
+
yield { type: 'error', error: describeDiskShortfall(space, manifest.name) };
|
|
474
|
+
return;
|
|
475
|
+
}
|
|
476
|
+
// Download the shards concurrently (bounded by
|
|
477
|
+
// MLX_DOWNLOAD_CONCURRENCY). Per-file resume (`.partial`), sha256
|
|
478
|
+
// verification, and the atomic commit-rename below are unchanged —
|
|
479
|
+
// only the scheduling differs. Each worker writes its bytes into
|
|
480
|
+
// `perFileBytes[index]`; cumulative `bytesWrittenAll` is the live
|
|
481
|
+
// sum across all files (it stays monotonic enough to drive the one
|
|
482
|
+
// model-level progress bar even though files finish out of order).
|
|
483
|
+
// Workers push events into the queue; this generator drains it.
|
|
484
|
+
const perFileBytes = new Array(files.length).fill(0);
|
|
485
|
+
// Reused files are complete before the pool starts, so the one
|
|
486
|
+
// model-level bar opens at the bytes already present instead of
|
|
487
|
+
// pretending to re-download them.
|
|
488
|
+
files.forEach((file, index) => {
|
|
489
|
+
if (reusable.has(file.name))
|
|
490
|
+
perFileBytes[index] = file.sizeBytes ?? 0;
|
|
491
|
+
});
|
|
492
|
+
tracked.bytesWritten = perFileBytes.reduce((sum, bytes) => sum + bytes, 0);
|
|
493
|
+
const queue = new AsyncEventQueue();
|
|
494
|
+
const ac = new AbortController();
|
|
495
|
+
const push = (ev) => queue.push(ev);
|
|
496
|
+
let cursor = 0;
|
|
497
|
+
const runWorker = async () => {
|
|
498
|
+
let outcome = 'ok';
|
|
499
|
+
while (!ac.signal.aborted) {
|
|
500
|
+
const index = cursor;
|
|
501
|
+
cursor += 1;
|
|
502
|
+
if (index >= files.length)
|
|
503
|
+
break;
|
|
504
|
+
const file = files[index];
|
|
505
|
+
if (!file)
|
|
506
|
+
break;
|
|
507
|
+
if (reusable.has(file.name))
|
|
508
|
+
continue;
|
|
509
|
+
const fileResult = await this.downloadFileConcurrent(itemDir, src.huggingfaceRepo, src.revision, src.subdir, file, index, fileCount, perFileBytes, totalBytesAll, tracked, skipSha, push, ac, verifiedDigests);
|
|
510
|
+
if (fileResult === 'error') {
|
|
511
|
+
// Cancel the in-flight siblings; the error event is already
|
|
512
|
+
// queued. Other workers see the abort and unwind as 'aborted'
|
|
513
|
+
// without emitting a second terminal event.
|
|
514
|
+
outcome = 'error';
|
|
515
|
+
ac.abort();
|
|
516
|
+
break;
|
|
517
|
+
}
|
|
518
|
+
if (fileResult === 'aborted')
|
|
519
|
+
break;
|
|
520
|
+
}
|
|
521
|
+
return outcome;
|
|
522
|
+
};
|
|
523
|
+
const poolSize = Math.min(MLX_DOWNLOAD_CONCURRENCY, Math.max(files.length, 1));
|
|
524
|
+
const workers = Array.from({ length: poolSize }, () => runWorker());
|
|
525
|
+
const settled = Promise.allSettled(workers).then((results) => {
|
|
526
|
+
queue.close();
|
|
527
|
+
return results;
|
|
528
|
+
});
|
|
529
|
+
let sawError = false;
|
|
530
|
+
for await (const ev of queue) {
|
|
531
|
+
yield ev;
|
|
532
|
+
if (ev.type === 'error')
|
|
533
|
+
sawError = true;
|
|
534
|
+
}
|
|
535
|
+
const results = await settled;
|
|
536
|
+
// A worker that threw (rather than returning 'error') still has to
|
|
537
|
+
// produce a terminal event, or a subscriber would hang on a job
|
|
538
|
+
// that silently stopped emitting.
|
|
539
|
+
const threw = results.find((r) => r.status === 'rejected');
|
|
540
|
+
if (threw && !sawError) {
|
|
541
|
+
const reason = threw.reason;
|
|
542
|
+
yield {
|
|
543
|
+
type: 'error',
|
|
544
|
+
error: `MLX download failed: ${reason instanceof Error ? reason.message : String(reason)}`,
|
|
545
|
+
};
|
|
546
|
+
return;
|
|
547
|
+
}
|
|
548
|
+
const workerErrored = results.some((r) => r.status === 'fulfilled' && r.value === 'error');
|
|
549
|
+
if (sawError || workerErrored)
|
|
550
|
+
return;
|
|
551
|
+
// Commit phase first: metadata extraction needs the real filenames
|
|
552
|
+
// (readMlxSummary reads `tokenizer_config.json`, not `.partial`).
|
|
553
|
+
// If any rename fails we bail — half-renamed state is a mess.
|
|
554
|
+
for (const file of files) {
|
|
555
|
+
if (reusable.has(file.name))
|
|
556
|
+
continue;
|
|
557
|
+
const finalPath = join(itemDir, file.name);
|
|
558
|
+
const partialPath = `${finalPath}.partial`;
|
|
559
|
+
try {
|
|
560
|
+
await rm(finalPath, { force: true });
|
|
561
|
+
await rename(partialPath, finalPath);
|
|
562
|
+
}
|
|
563
|
+
catch (err) {
|
|
564
|
+
yield { type: 'error', error: `rename failed for ${file.name}: ${describeError(err)}` };
|
|
565
|
+
return;
|
|
566
|
+
}
|
|
567
|
+
}
|
|
568
|
+
// Drop files a previous install of this id left behind that the new file
|
|
569
|
+
// set no longer references (e.g. shards from a different quant). Keeps the
|
|
570
|
+
// slot from accumulating orphaned multi-GB weights.
|
|
571
|
+
const pruned = await pruneModelPayloadFiles(itemDir, new Set(files.map((f) => f.name)));
|
|
572
|
+
if (pruned.length > 0) {
|
|
573
|
+
log.info(`[models] [mlx] pruned ${pruned.length} stale file(s) from "${catalogId}": ${pruned.join(', ')}`);
|
|
574
|
+
}
|
|
575
|
+
if (src.drafter)
|
|
576
|
+
await this.installDrafter(catalogId, src.drafter);
|
|
577
|
+
tracked.phase = 'extracting-metadata';
|
|
578
|
+
yield { type: 'extracting-metadata' };
|
|
579
|
+
let summary;
|
|
580
|
+
try {
|
|
581
|
+
summary = await readMlxSummary(itemDir);
|
|
582
|
+
}
|
|
583
|
+
catch (err) {
|
|
584
|
+
await rm(itemDir, { recursive: true, force: true });
|
|
585
|
+
yield {
|
|
586
|
+
type: 'error',
|
|
587
|
+
error: `MLX metadata parse failed (install aborted): ${describeError(err)}`,
|
|
588
|
+
};
|
|
589
|
+
return;
|
|
590
|
+
}
|
|
591
|
+
// If the upstream tokenizer_config didn't ship a chat template,
|
|
592
|
+
// try to recover one before we accept the "replies may be
|
|
593
|
+
// incoherent" hazard:
|
|
594
|
+
//
|
|
595
|
+
// 1. `chat_template.jinja` sidecar — Unsloth and some other
|
|
596
|
+
// repackers ship the template as a separate file, which
|
|
597
|
+
// mlx_lm.server doesn't automatically read. Merge it in.
|
|
598
|
+
// 2. `chatTemplate` pinned on the catalog entry — last-resort
|
|
599
|
+
// safety net for curated entries where we know the right
|
|
600
|
+
// template but upstream doesn't carry it in any form.
|
|
601
|
+
//
|
|
602
|
+
// The tokenizer_config.json sha256 was verified at download time;
|
|
603
|
+
// rewriting after verification is expected (we're the ones who
|
|
604
|
+
// want the file to match the model we're actually going to run).
|
|
605
|
+
let chatTemplatePresent = summary.chatTemplatePresent;
|
|
606
|
+
let templateSource = chatTemplatePresent ? 'upstream' : null;
|
|
607
|
+
const tokenizerConfigPath = join(itemDir, 'tokenizer_config.json');
|
|
608
|
+
const chatTemplateSidecarPath = join(itemDir, 'chat_template.jinja');
|
|
609
|
+
// An override runs BEFORE the recovery ladder and short-circuits it,
|
|
610
|
+
// because the ladder asks "is a template present?" and an override
|
|
611
|
+
// exists precisely for the case where one is present and wrong.
|
|
612
|
+
//
|
|
613
|
+
// Both resolution paths get written. mlx_vlm loads the sidecar
|
|
614
|
+
// natively, so that is the file that decides behavior; but leaving a
|
|
615
|
+
// contradicting `tokenizer_config.chat_template` behind would mean
|
|
616
|
+
// the effective template depended on which loader ran, which is the
|
|
617
|
+
// kind of difference that only shows up as a model "sometimes"
|
|
618
|
+
// looping on tool calls. tokenizer_config is touched only when it
|
|
619
|
+
// already carries a template — otherwise its verified sha256 stands.
|
|
620
|
+
if (src.chatTemplateOverride) {
|
|
621
|
+
try {
|
|
622
|
+
await writeFile(chatTemplateSidecarPath, src.chatTemplateOverride, 'utf8');
|
|
623
|
+
delete verifiedDigests['chat_template.jinja'];
|
|
624
|
+
if (summary.chatTemplatePresent) {
|
|
625
|
+
await injectChatTemplate(tokenizerConfigPath, src.chatTemplateOverride);
|
|
626
|
+
delete verifiedDigests['tokenizer_config.json'];
|
|
627
|
+
}
|
|
628
|
+
chatTemplatePresent = true;
|
|
629
|
+
templateSource = 'override';
|
|
630
|
+
}
|
|
631
|
+
catch (err) {
|
|
632
|
+
// Non-fatal, but not silent: falling through leaves the model
|
|
633
|
+
// running the upstream template the catalog was trying to
|
|
634
|
+
// correct, and that is worth saying out loud.
|
|
635
|
+
log.warn(`[mlx] ${catalogId}: chat template override failed to write, ` +
|
|
636
|
+
`falling back to the upstream template: ${describeError(err)}`);
|
|
637
|
+
}
|
|
638
|
+
}
|
|
639
|
+
if (!chatTemplatePresent) {
|
|
640
|
+
// mlx_vlm reads `chat_template.jinja` natively (per-architecture
|
|
641
|
+
// processors call `load_chat_template(tokenizer, model_path)`),
|
|
642
|
+
// so when the sidecar exists the engine already has what it
|
|
643
|
+
// needs. We just record the fact for the manifest and skip
|
|
644
|
+
// rewriting tokenizer_config.json — that mutation moved files
|
|
645
|
+
// away from their pinned sha256 for no engine-side benefit.
|
|
646
|
+
try {
|
|
647
|
+
const sidecar = await readFile(join(itemDir, 'chat_template.jinja'), 'utf8');
|
|
648
|
+
if (sidecar.trim().length > 0) {
|
|
649
|
+
chatTemplatePresent = true;
|
|
650
|
+
templateSource = 'sidecar';
|
|
651
|
+
}
|
|
652
|
+
}
|
|
653
|
+
catch {
|
|
654
|
+
// No sidecar file — fall through to the catalog pin.
|
|
655
|
+
}
|
|
656
|
+
}
|
|
657
|
+
if (!chatTemplatePresent && templateSource !== 'override' && src.chatTemplate) {
|
|
658
|
+
try {
|
|
659
|
+
await injectChatTemplate(tokenizerConfigPath, src.chatTemplate);
|
|
660
|
+
// The file no longer hashes to what the download verified, so its
|
|
661
|
+
// digest has to be re-read from disk rather than carried forward.
|
|
662
|
+
delete verifiedDigests['tokenizer_config.json'];
|
|
663
|
+
chatTemplatePresent = true;
|
|
664
|
+
templateSource = 'catalog';
|
|
665
|
+
}
|
|
666
|
+
catch (err) {
|
|
667
|
+
// Non-fatal: model still works, just with the generic fallback
|
|
668
|
+
// and the usual warning. Swallow and continue.
|
|
669
|
+
void err;
|
|
670
|
+
}
|
|
671
|
+
}
|
|
672
|
+
const catalogPayload = describeCatalogPayload(manifest, 'mlx');
|
|
673
|
+
const installed = {
|
|
674
|
+
id: catalogId,
|
|
675
|
+
name: manifest.name,
|
|
676
|
+
approxSizeBytes: src.approxSizeBytes,
|
|
677
|
+
...(src.residentBytes ? { residentBytes: src.residentBytes } : {}),
|
|
678
|
+
installedAt: new Date().toISOString(),
|
|
679
|
+
catalogId,
|
|
680
|
+
catalogVersion: manifest.version,
|
|
681
|
+
huggingfaceRepo: src.huggingfaceRepo,
|
|
682
|
+
...(src.quantization ? { quantization: src.quantization } : {}),
|
|
683
|
+
...(summary.contextWindow
|
|
684
|
+
? { contextWindow: summary.contextWindow }
|
|
685
|
+
: manifest.contextWindow
|
|
686
|
+
? { contextWindow: manifest.contextWindow }
|
|
687
|
+
: {}),
|
|
688
|
+
...(summary.architecture ? { architecture: summary.architecture } : {}),
|
|
689
|
+
chatTemplatePresent,
|
|
690
|
+
files: files.map((f) => f.name),
|
|
691
|
+
// Snapshot what the catalog said this payload IS, so a later version
|
|
692
|
+
// bump that only edits metadata can be recognized as such without
|
|
693
|
+
// re-reading a byte. Skipped for a skipSha install: those bytes are
|
|
694
|
+
// knowingly not the ones the catalog describes.
|
|
695
|
+
...(!skipSha && catalogPayload
|
|
696
|
+
? { payloadFingerprint: catalogPayloadFingerprint(catalogPayload) }
|
|
697
|
+
: {}),
|
|
698
|
+
};
|
|
699
|
+
// Every file that was downloaded (or reused) has a verified digest
|
|
700
|
+
// already; hashing the whole payload back off disk would re-read tens of
|
|
701
|
+
// gigabytes to learn what we just measured.
|
|
702
|
+
installed.fileSha256 = await hashModelPayloadFiles(itemDir, verifiedDigests);
|
|
703
|
+
await writeFile(join(itemDir, 'manifest.json'), JSON.stringify(installed, null, 2), 'utf8');
|
|
704
|
+
await makeSharedModelReadable(itemDir);
|
|
705
|
+
// A completed update invalidates any view derived from the prior index.
|
|
706
|
+
// Loaded processes retain their open file handles; the next launch
|
|
707
|
+
// rebuilds the small view atomically from the new checkpoint.
|
|
708
|
+
await rm(join(this.viewsRoot, catalogId), {
|
|
709
|
+
recursive: true,
|
|
710
|
+
force: true,
|
|
711
|
+
});
|
|
712
|
+
// The sidecar case is the modern norm (Gemma 4, etc.) and mlx_vlm
|
|
713
|
+
// reads it natively — nothing actionable to surface, so no warning.
|
|
714
|
+
// The other three are rarer and worth flagging because they say
|
|
715
|
+
// something about the install: the catalog entry is filling an
|
|
716
|
+
// upstream gap, it is overriding an upstream template we believe is
|
|
717
|
+
// wrong, or the engine is about to fall back to a generic template
|
|
718
|
+
// that probably won't match the model. The override deserves a line
|
|
719
|
+
// even though it is deliberate — it is the only signal that the
|
|
720
|
+
// bytes the model runs on differ from the bytes the repo shipped.
|
|
721
|
+
const warning = chatTemplatePresent
|
|
722
|
+
? templateSource === 'catalog'
|
|
723
|
+
? 'Upstream tokenizer_config had no chat_template — injected the known-good template pinned in the catalog entry.'
|
|
724
|
+
: templateSource === 'override'
|
|
725
|
+
? 'Replaced the template shipped by this repo with the corrected one pinned in the catalog entry.'
|
|
726
|
+
: undefined
|
|
727
|
+
: 'Model has no embedded chat template (tokenizer_config.json missing chat_template and no sidecar). mlx_vlm.server will fall back to a generic template that may not match this model — replies may be incoherent.';
|
|
728
|
+
try {
|
|
729
|
+
this.onInstalled?.({ engine: 'mlx', id: catalogId });
|
|
730
|
+
}
|
|
731
|
+
catch {
|
|
732
|
+
// Fire-and-forget: a hook failure must never fail a completed install.
|
|
733
|
+
}
|
|
734
|
+
yield { type: 'done', id: catalogId, ...(warning ? { warning } : {}) };
|
|
735
|
+
}
|
|
736
|
+
finally {
|
|
737
|
+
this.activeInstalls.delete(catalogId);
|
|
738
|
+
}
|
|
739
|
+
}
|
|
740
|
+
/**
|
|
741
|
+
* Download + verify one file, pushing progress/retrying/verifying/
|
|
742
|
+
* error events through `push` rather than yielding (so it can run
|
|
743
|
+
* concurrently with sibling files inside `install`'s worker pool).
|
|
744
|
+
*
|
|
745
|
+
* Returns:
|
|
746
|
+
* - `'ok'` — downloaded and sha256-verified (or skipSha bypass).
|
|
747
|
+
* - `'error'` — download or verify failed; a terminal `error` event
|
|
748
|
+
* has already been pushed.
|
|
749
|
+
* - `'aborted'`— the shared AbortController fired (a sibling file
|
|
750
|
+
* failed); no terminal event pushed, the failing
|
|
751
|
+
* worker owns the error.
|
|
752
|
+
*/
|
|
753
|
+
/**
|
|
754
|
+
* Install a model's speculative-decoding drafter beside it, if the catalog
|
|
755
|
+
* declares one.
|
|
756
|
+
*
|
|
757
|
+
* Deliberately best-effort and deliberately AFTER the model commits: a
|
|
758
|
+
* drafter only makes decoding faster — every token it proposes is verified
|
|
759
|
+
* against the target model — so failing to fetch it must leave a working
|
|
760
|
+
* install rather than failing one. On any error the model serves normally
|
|
761
|
+
* and the launcher logs `speculative decoding off — no drafter at <path>`.
|
|
762
|
+
*
|
|
763
|
+
* Lands at `engines/mlx/drafters/<catalogId>-mtp`, the path
|
|
764
|
+
* `resolveSpecDrafter` reads, so installing IS enabling.
|
|
765
|
+
*/
|
|
766
|
+
async installDrafter(catalogId, drafter) {
|
|
767
|
+
const draftersRoot = join(dirname(this.modelsRoot), 'drafters');
|
|
768
|
+
const destDir = join(draftersRoot, `${catalogId}-${drafter.kind}`);
|
|
769
|
+
try {
|
|
770
|
+
// Create before asserting: the containment check resolves realpaths, so
|
|
771
|
+
// it needs both ends to exist. Same order the model payload uses.
|
|
772
|
+
await mkdir(draftersRoot, { recursive: true });
|
|
773
|
+
await assertModelStorePathSafe(draftersRoot, destDir);
|
|
774
|
+
await mkdir(destDir, { recursive: true });
|
|
775
|
+
await assertModelStorePathSafe(draftersRoot, destDir);
|
|
776
|
+
for (const file of drafter.files) {
|
|
777
|
+
const finalPath = join(destDir, file.name);
|
|
778
|
+
const tmpPath = `${finalPath}.partial`;
|
|
779
|
+
await mkdir(dirname(finalPath), { recursive: true });
|
|
780
|
+
const ref = drafter.revision ?? 'main';
|
|
781
|
+
const url = `https://huggingface.co/${drafter.huggingfaceRepo}/resolve/${encodeURIComponent(ref)}/${file.name
|
|
782
|
+
.split('/')
|
|
783
|
+
.map(encodeURIComponent)
|
|
784
|
+
.join('/')}?download=true`;
|
|
785
|
+
const gen = downloadWithRetry({
|
|
786
|
+
url,
|
|
787
|
+
destPath: finalPath,
|
|
788
|
+
approxSizeBytes: file.sizeBytes,
|
|
789
|
+
fetchImpl: this.fetchImpl,
|
|
790
|
+
});
|
|
791
|
+
let done = false;
|
|
792
|
+
while (!done) {
|
|
793
|
+
const step = await gen.next();
|
|
794
|
+
if (step.done) {
|
|
795
|
+
if (step.value.kind !== 'ok')
|
|
796
|
+
throw new Error(`download ${step.value.kind}`);
|
|
797
|
+
done = true;
|
|
798
|
+
}
|
|
799
|
+
}
|
|
800
|
+
const hasher = createHash('sha256');
|
|
801
|
+
await new Promise((resolveHash, reject) => {
|
|
802
|
+
const stream = createReadStream(tmpPath, { highWaterMark: MODEL_HASH_READ_BUFFER_BYTES });
|
|
803
|
+
stream.on('data', (chunk) => hasher.update(chunk));
|
|
804
|
+
stream.on('end', () => resolveHash());
|
|
805
|
+
stream.on('error', reject);
|
|
806
|
+
});
|
|
807
|
+
const actual = hasher.digest('hex');
|
|
808
|
+
if (actual !== file.sha256.toLowerCase()) {
|
|
809
|
+
await rm(tmpPath, { force: true });
|
|
810
|
+
throw new Error(`sha256 mismatch for ${file.name}: expected ${file.sha256}, got ${actual}`);
|
|
811
|
+
}
|
|
812
|
+
await rm(finalPath, { force: true });
|
|
813
|
+
await rename(tmpPath, finalPath);
|
|
814
|
+
}
|
|
815
|
+
log.info(`[models] [mlx] installed ${drafter.kind} drafter for "${catalogId}" from ${drafter.huggingfaceRepo} (speculative decoding enabled)`);
|
|
816
|
+
}
|
|
817
|
+
catch (err) {
|
|
818
|
+
// Leave no half-written drafter: a partial one would arm speculation
|
|
819
|
+
// and then fail at engine boot, which is worse than not having it.
|
|
820
|
+
await rm(destDir, { recursive: true, force: true }).catch(() => { });
|
|
821
|
+
log.warn(`[models] [mlx] drafter install skipped for "${catalogId}": ${describeError(err)} — the model works normally, without speculative decoding`);
|
|
822
|
+
}
|
|
823
|
+
}
|
|
824
|
+
async downloadFileConcurrent(itemDir, repo, revision, subdir, file, index, total, perFileBytes, totalBytesAll, tracked, skipSha, push, ac,
|
|
825
|
+
/** Digest sink, so the post-install manifest doesn't re-hash from disk. */
|
|
826
|
+
verifiedDigests) {
|
|
827
|
+
const finalPath = join(itemDir, file.name);
|
|
828
|
+
// File names are relative to the selected model root and may preserve
|
|
829
|
+
// nested layout. The catalog schema guarantees they are contained paths;
|
|
830
|
+
// create their parent directories before the resumable downloader opens
|
|
831
|
+
// the `.partial` sibling.
|
|
832
|
+
await mkdir(dirname(finalPath), { recursive: true });
|
|
833
|
+
const tmpPath = `${finalPath}.partial`;
|
|
834
|
+
// Pin to the catalog's revision (commit SHA) when present so we get
|
|
835
|
+
// the exact bytes the sha256 was computed against; fall back to
|
|
836
|
+
// `main` for legacy manifests that predate revision pinning.
|
|
837
|
+
const ref = revision ?? 'main';
|
|
838
|
+
const repoPath = subdir ? `${subdir}/${file.name}` : file.name;
|
|
839
|
+
const encodedRepoPath = repoPath.split('/').map(encodeURIComponent).join('/');
|
|
840
|
+
const url = `https://huggingface.co/${repo}/resolve/${encodeURIComponent(ref)}/${encodedRepoPath}?download=true`;
|
|
841
|
+
// Live sum across every file's bytes-so-far. Files complete out of
|
|
842
|
+
// order under concurrency, so we can't use a "bytes of prior files"
|
|
843
|
+
// baseline — recompute the running total from the shared array.
|
|
844
|
+
const sumAll = () => {
|
|
845
|
+
let sum = 0;
|
|
846
|
+
for (const b of perFileBytes)
|
|
847
|
+
sum += b;
|
|
848
|
+
return sum;
|
|
849
|
+
};
|
|
850
|
+
// Delegate network plumbing (resume, retry, chunk-stall timeout,
|
|
851
|
+
// friendly errors) to the shared helper. Passing the shared signal
|
|
852
|
+
// lets a sibling's failure cancel this in-flight transfer promptly.
|
|
853
|
+
const dlGen = downloadWithRetry({
|
|
854
|
+
url,
|
|
855
|
+
destPath: finalPath,
|
|
856
|
+
approxSizeBytes: file.sizeBytes,
|
|
857
|
+
fetchImpl: this.fetchImpl,
|
|
858
|
+
signal: ac.signal,
|
|
859
|
+
});
|
|
860
|
+
let totalBytes = file.sizeBytes;
|
|
861
|
+
while (true) {
|
|
862
|
+
const step = await dlGen.next();
|
|
863
|
+
if (step.done) {
|
|
864
|
+
if (step.value.kind === 'aborted') {
|
|
865
|
+
// Cancelled because a sibling failed — leave the `.partial` for
|
|
866
|
+
// a resumed run and let the failing worker own the error event.
|
|
867
|
+
return 'aborted';
|
|
868
|
+
}
|
|
869
|
+
if (step.value.kind === 'error') {
|
|
870
|
+
push({ type: 'error', error: `${file.name}: ${step.value.error}` });
|
|
871
|
+
return 'error';
|
|
872
|
+
}
|
|
873
|
+
break;
|
|
874
|
+
}
|
|
875
|
+
const ev = step.value;
|
|
876
|
+
if (ev.type === 'progress') {
|
|
877
|
+
if (ev.totalBytes > 0)
|
|
878
|
+
totalBytes = ev.totalBytes;
|
|
879
|
+
perFileBytes[index] = ev.bytesWritten;
|
|
880
|
+
const bytesWrittenAll = sumAll();
|
|
881
|
+
tracked.bytesWritten = bytesWrittenAll;
|
|
882
|
+
push({
|
|
883
|
+
type: 'progress',
|
|
884
|
+
fileIndex: index,
|
|
885
|
+
fileCount: total,
|
|
886
|
+
file: file.name,
|
|
887
|
+
bytesWritten: ev.bytesWritten,
|
|
888
|
+
totalBytes,
|
|
889
|
+
bytesWrittenAll,
|
|
890
|
+
totalBytesAll,
|
|
891
|
+
});
|
|
892
|
+
}
|
|
893
|
+
else if (ev.type === 'retrying') {
|
|
894
|
+
push({
|
|
895
|
+
type: 'retrying',
|
|
896
|
+
attempt: ev.attempt,
|
|
897
|
+
maxAttempts: ev.maxAttempts,
|
|
898
|
+
delayMs: ev.delayMs,
|
|
899
|
+
reason: ev.reason,
|
|
900
|
+
file: file.name,
|
|
901
|
+
});
|
|
902
|
+
}
|
|
903
|
+
}
|
|
904
|
+
push({ type: 'verifying', file: file.name });
|
|
905
|
+
// sha256 verify by streaming the .partial through a fresh hasher.
|
|
906
|
+
// Correct across resumed downloads (a chunk-time hasher would
|
|
907
|
+
// miss the resumed prefix).
|
|
908
|
+
const hasher = createHash('sha256');
|
|
909
|
+
await new Promise((resolve, reject) => {
|
|
910
|
+
// Big read buffer so the hash doesn't starve inside the busy daemon
|
|
911
|
+
// event loop. See MODEL_HASH_READ_BUFFER_BYTES.
|
|
912
|
+
const stream = createReadStream(tmpPath, { highWaterMark: MODEL_HASH_READ_BUFFER_BYTES });
|
|
913
|
+
stream.on('data', (chunk) => hasher.update(chunk));
|
|
914
|
+
stream.on('end', () => resolve());
|
|
915
|
+
stream.on('error', reject);
|
|
916
|
+
});
|
|
917
|
+
const actual = hasher.digest('hex');
|
|
918
|
+
verifiedDigests[file.name] = actual;
|
|
919
|
+
if (actual !== file.sha256.toLowerCase()) {
|
|
920
|
+
if (skipSha) {
|
|
921
|
+
// User explicitly asked to bypass after seeing a prior mismatch.
|
|
922
|
+
// Keep the `.partial` so the caller's commit-rename step still
|
|
923
|
+
// works; just stop pretending the catalog sha is authoritative.
|
|
924
|
+
return 'ok';
|
|
925
|
+
}
|
|
926
|
+
await rm(tmpPath, { force: true });
|
|
927
|
+
push({
|
|
928
|
+
type: 'error',
|
|
929
|
+
error: `The file '${file.name}' on Hugging Face has changed since this version of Gezel was published. Expected sha256 ${file.sha256}, got ${actual}.`,
|
|
930
|
+
mismatch: { file: file.name, expected: file.sha256, actual },
|
|
931
|
+
});
|
|
932
|
+
return 'error';
|
|
933
|
+
}
|
|
934
|
+
return 'ok';
|
|
935
|
+
}
|
|
936
|
+
/**
|
|
937
|
+
* Files the plan asks for that are already on disk as exactly the bytes the
|
|
938
|
+
* catalog pins, keyed by filename with the digest to carry forward. See
|
|
939
|
+
* {@link LlamaCppModelManager.planReusableFiles} — same trust model: a
|
|
940
|
+
* digest this install recorded after verifying it, plus a file still at its
|
|
941
|
+
* pinned length, is identity.
|
|
942
|
+
*/
|
|
943
|
+
async planReusableFiles(itemDir, files) {
|
|
944
|
+
const reusable = new Map();
|
|
945
|
+
const parsed = await readFile(join(itemDir, 'manifest.json'), 'utf8')
|
|
946
|
+
.then((raw) => JSON.parse(raw))
|
|
947
|
+
.catch(() => null);
|
|
948
|
+
const recorded = parsed?.fileSha256;
|
|
949
|
+
if (!recorded)
|
|
950
|
+
return reusable;
|
|
951
|
+
for (const file of files) {
|
|
952
|
+
if (file.sizeBytes === undefined)
|
|
953
|
+
continue;
|
|
954
|
+
const sha = recorded[file.name]?.toLowerCase();
|
|
955
|
+
if (!sha || sha !== file.sha256.toLowerCase())
|
|
956
|
+
continue;
|
|
957
|
+
const size = await stat(join(itemDir, file.name))
|
|
958
|
+
.then((info) => (info.isFile() ? info.size : -1))
|
|
959
|
+
.catch(() => -1);
|
|
960
|
+
if (size !== file.sizeBytes)
|
|
961
|
+
continue;
|
|
962
|
+
reusable.set(file.name, sha);
|
|
963
|
+
}
|
|
964
|
+
return reusable;
|
|
965
|
+
}
|
|
966
|
+
/** Warn once per model directory per process, then stay quiet. */
|
|
967
|
+
warnSkip(id, reason) {
|
|
968
|
+
if (this.skipWarned.has(id))
|
|
969
|
+
return;
|
|
970
|
+
this.skipWarned.add(id);
|
|
971
|
+
log.warn(`[mlx] model directory "${id}" is not runnable: ${reason}`);
|
|
972
|
+
}
|
|
973
|
+
async loadInstalled(requestedId) {
|
|
974
|
+
let id = requestedId;
|
|
975
|
+
let root = await findModelRoot(this.storageRoots, id);
|
|
976
|
+
if (!root) {
|
|
977
|
+
// A pin written before the quant-suffix rename still names the old id.
|
|
978
|
+
const renamed = await findRenamedModelId(this.storageRoots, requestedId);
|
|
979
|
+
if (!renamed)
|
|
980
|
+
return null;
|
|
981
|
+
id = renamed;
|
|
982
|
+
root = await findModelRoot(this.storageRoots, id);
|
|
983
|
+
if (!root)
|
|
984
|
+
return null;
|
|
985
|
+
}
|
|
986
|
+
const metaPath = join(root, id, 'manifest.json');
|
|
987
|
+
let raw;
|
|
988
|
+
try {
|
|
989
|
+
raw = await readFile(metaPath, 'utf8');
|
|
990
|
+
}
|
|
991
|
+
catch {
|
|
992
|
+
this.warnSkip(id, `manifest.json is unreadable at ${metaPath}`);
|
|
993
|
+
return null;
|
|
994
|
+
}
|
|
995
|
+
let parsed;
|
|
996
|
+
try {
|
|
997
|
+
parsed = JSON.parse(raw);
|
|
998
|
+
}
|
|
999
|
+
catch {
|
|
1000
|
+
this.warnSkip(id, `manifest.json is not valid JSON at ${metaPath}`);
|
|
1001
|
+
return null;
|
|
1002
|
+
}
|
|
1003
|
+
if (!parsed.id || !parsed.name || !parsed.installedAt || !Array.isArray(parsed.files)) {
|
|
1004
|
+
this.warnSkip(id, 'manifest.json is missing required fields (id/name/installedAt/files)');
|
|
1005
|
+
return null;
|
|
1006
|
+
}
|
|
1007
|
+
if (!(await verifyReadOnlyModelPayload(this.storageRoots, root, id, parsed.fileSha256, (reason) => this.warnSkip(id, reason)))) {
|
|
1008
|
+
return null;
|
|
1009
|
+
}
|
|
1010
|
+
return {
|
|
1011
|
+
id: parsed.id,
|
|
1012
|
+
name: parsed.name,
|
|
1013
|
+
approxSizeBytes: parsed.approxSizeBytes ?? 0,
|
|
1014
|
+
...(parsed.residentBytes ? { residentBytes: parsed.residentBytes } : {}),
|
|
1015
|
+
installedAt: parsed.installedAt,
|
|
1016
|
+
modelDir: join(root, id),
|
|
1017
|
+
...(parsed.contextWindow ? { contextWindow: parsed.contextWindow } : {}),
|
|
1018
|
+
...(parsed.quantization ? { quantization: parsed.quantization } : {}),
|
|
1019
|
+
chatTemplatePresent: parsed.chatTemplatePresent ?? true,
|
|
1020
|
+
...(parsed.architecture ? { architecture: parsed.architecture } : {}),
|
|
1021
|
+
...(parsed.catalogVersion ? { catalogVersion: parsed.catalogVersion } : {}),
|
|
1022
|
+
// Read-only when it resolves from a machine/shared overlay rather than
|
|
1023
|
+
// this daemon's writable root — delete refuses these; the UI shows them
|
|
1024
|
+
// as machine-provided instead of offering a Delete that only 400s.
|
|
1025
|
+
...(resolvePath(root) !== resolvePath(this.storageRoots.writableRoot)
|
|
1026
|
+
? { readOnly: true }
|
|
1027
|
+
: {}),
|
|
1028
|
+
};
|
|
1029
|
+
}
|
|
1030
|
+
}
|
|
1031
|
+
function describeError(err) {
|
|
1032
|
+
return err instanceof Error ? err.message : String(err);
|
|
1033
|
+
}
|
|
1034
|
+
/**
|
|
1035
|
+
* Resume credit: bytes of a still-to-fetch file that a `.partial` already
|
|
1036
|
+
* holds. Deliberately blind to finished files — a previous install's copy of
|
|
1037
|
+
* the same name is not credit, because the new bytes stream into a `.partial`
|
|
1038
|
+
* beside it and the old copy only goes away at publish. See the llama.cpp
|
|
1039
|
+
* sibling for the ENOSPC this used to hide.
|
|
1040
|
+
*/
|
|
1041
|
+
async function mlxPartialBytesOnDisk(itemDir, files) {
|
|
1042
|
+
let total = 0;
|
|
1043
|
+
for (const file of files) {
|
|
1044
|
+
const size = await stat(`${join(itemDir, file.name)}.partial`)
|
|
1045
|
+
.then((st) => st.size)
|
|
1046
|
+
.catch(() => 0);
|
|
1047
|
+
if (size > 0)
|
|
1048
|
+
total += file.sizeBytes ? Math.min(size, file.sizeBytes) : size;
|
|
1049
|
+
}
|
|
1050
|
+
return total;
|
|
1051
|
+
}
|
|
1052
|
+
/**
|
|
1053
|
+
* Merge a Jinja `chat_template` into an existing `tokenizer_config.json`
|
|
1054
|
+
* (or create a minimal one if the file is missing / unreadable).
|
|
1055
|
+
* Overwrites only the `chat_template` field — every other key is
|
|
1056
|
+
* preserved so mlx_lm.server still sees the original tokenizer config.
|
|
1057
|
+
*/
|
|
1058
|
+
async function injectChatTemplate(tokenizerConfigPath, template) {
|
|
1059
|
+
let current = {};
|
|
1060
|
+
try {
|
|
1061
|
+
const raw = await readFile(tokenizerConfigPath, 'utf8');
|
|
1062
|
+
const parsed = JSON.parse(raw);
|
|
1063
|
+
if (parsed && typeof parsed === 'object' && !Array.isArray(parsed)) {
|
|
1064
|
+
current = parsed;
|
|
1065
|
+
}
|
|
1066
|
+
}
|
|
1067
|
+
catch {
|
|
1068
|
+
// Missing or unreadable — fall through and write a minimal file.
|
|
1069
|
+
}
|
|
1070
|
+
current.chat_template = template;
|
|
1071
|
+
await writeFile(tokenizerConfigPath, `${JSON.stringify(current, null, 2)}\n`, 'utf8');
|
|
1072
|
+
}
|
|
1073
|
+
function isSafeId(id) {
|
|
1074
|
+
if (id.length === 0 || id.length > 64)
|
|
1075
|
+
return false;
|
|
1076
|
+
if (id.includes('/') || id.includes('\\') || id.startsWith('.'))
|
|
1077
|
+
return false;
|
|
1078
|
+
return /^[a-z0-9][a-z0-9.\-:]{0,63}$/i.test(id);
|
|
1079
|
+
}
|