@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,1714 @@
|
|
|
1
|
+
import { randomUUID } from 'node:crypto';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
import { createLogger } from '@bendyline/gezel';
|
|
4
|
+
import { estimateLlamaCppResidentBytes } from '@bendyline/gezel';
|
|
5
|
+
import { resolveCatalogLlamaCppEngineConfig } from '../catalog-model-config.js';
|
|
6
|
+
import { buildDs4Provider, resolveDs4LaunchCtx, resolveDs4VisionLaunch, } from '../ds4/build-provider.js';
|
|
7
|
+
import { ds4VisionResidentBytes } from '../ds4/residency.js';
|
|
8
|
+
import { buildLlamaCppProvider, ensureLlamaEngineStatus } from '../llama-cpp/build-provider.js';
|
|
9
|
+
import { readGgufSummaryAsync } from '../llama-cpp/gguf-metadata-async.js';
|
|
10
|
+
import { effectiveLazyTensorBytes } from '../llama-cpp/gguf-metadata.js';
|
|
11
|
+
import { isGemmaModel, planLlamaCppKv, resolveLlamaCppKvCacheType, } from '../llama-cpp/kv-cache-type.js';
|
|
12
|
+
import { estimateExactPerSlotKvBytesF16, estimateKvReserveBytes, estimateWindowedKvLinearization, } from '../llama-cpp/offload-planner.js';
|
|
13
|
+
import { buildMlxProvider, resolveMlxEffectiveNumCtx } from '../mlx/build-provider.js';
|
|
14
|
+
import { readMlxModelGeometry } from '../mlx/model-geometry.js';
|
|
15
|
+
import { ModelNotInstalledError } from '../types.js';
|
|
16
|
+
import { mmprojBudgetBytes, nativeVisionEnabledFor } from '../vision-capability.js';
|
|
17
|
+
import { CapacityDeniedError, NOT_ENOUGH_MEMORY_MESSAGE, availableSystemRamBytes, minViableLocalContextTokens, resolveLlamaCppContextRequirement, } from './capacity-broker.js';
|
|
18
|
+
import { engineApiKey } from './engine-api-key.js';
|
|
19
|
+
import { isLocalProvider, makeEngineKey, parseEngineKey, } from './engine-key.js';
|
|
20
|
+
const log = createLogger('engines');
|
|
21
|
+
/** Native engine lifetime, admission, and cache control. No product sessions or tools. */
|
|
22
|
+
export class LocalEngineRuntime {
|
|
23
|
+
store;
|
|
24
|
+
constructor(opts) {
|
|
25
|
+
this.store = opts.store;
|
|
26
|
+
this.catalog = opts.catalog;
|
|
27
|
+
this.llamaCppModels = opts.llamaCppModels;
|
|
28
|
+
this.ds4Models = opts.ds4Models;
|
|
29
|
+
this.mlxModels = opts.mlxModels;
|
|
30
|
+
this.uvRuntime = opts.uvRuntime;
|
|
31
|
+
this.mlxRuntimeStatus = opts.mlxRuntimeStatus;
|
|
32
|
+
this.home = opts.home;
|
|
33
|
+
this.cacheController = opts.cacheController;
|
|
34
|
+
this.gpuArbiter = opts.gpuArbiter;
|
|
35
|
+
this.engineBinaries = opts.engineBinaries;
|
|
36
|
+
this.engineRouter = opts.engineRouter;
|
|
37
|
+
}
|
|
38
|
+
/** Product chat may prefill its own sessions; the engine runtime never resolves them. */
|
|
39
|
+
async prefillCacheSession(_sessionId) {
|
|
40
|
+
return false;
|
|
41
|
+
}
|
|
42
|
+
/** Cached provider instances keyed by provider name. */
|
|
43
|
+
providers = new Map();
|
|
44
|
+
catalog;
|
|
45
|
+
llamaCppModels;
|
|
46
|
+
ds4Models;
|
|
47
|
+
mlxModels;
|
|
48
|
+
uvRuntime;
|
|
49
|
+
mlxRuntimeStatus;
|
|
50
|
+
home;
|
|
51
|
+
cacheController;
|
|
52
|
+
gpuArbiter;
|
|
53
|
+
engineBinaries;
|
|
54
|
+
engineRouter;
|
|
55
|
+
/**
|
|
56
|
+
* Snapshot of every provider's prompt-cache state. Empty array when
|
|
57
|
+
* no controller is wired (cloud-only install, tests). Polled by the
|
|
58
|
+
* EngineStatusPill alongside `/api/queues` for the popover stats
|
|
59
|
+
* rows. Cheap — pure read of in-memory state.
|
|
60
|
+
*/
|
|
61
|
+
getCacheStats() {
|
|
62
|
+
return this.cacheController?.getAllStats() ?? [];
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Operator-driven invalidation hook. The /api/cache/evict route
|
|
66
|
+
* calls this to drop a single session's cache; same path the
|
|
67
|
+
* compaction / archive / delete hooks already use internally.
|
|
68
|
+
*/
|
|
69
|
+
invalidateSessionCache(sessionId) {
|
|
70
|
+
this.cacheController?.invalidate(sessionId);
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Operator-driven full-provider eviction. Same hook the resetClient
|
|
74
|
+
* path uses; surfaced on /api/cache/clear so an operator can punt
|
|
75
|
+
* stale state without waiting for credential rotation.
|
|
76
|
+
*/
|
|
77
|
+
invalidateProviderCache(providerName) {
|
|
78
|
+
this.cacheController?.invalidateProvider(providerName);
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Live-update the controller's per-provider budget. Called from the
|
|
82
|
+
* config PUT handler when the operator changes `cacheBudgetMb` —
|
|
83
|
+
* eviction kicks in immediately if the new budget is below current
|
|
84
|
+
* usage. No-op if no controller is wired.
|
|
85
|
+
*/
|
|
86
|
+
setCacheBudget(providerName, bytes) {
|
|
87
|
+
this.cacheController?.setBudget(providerName, bytes);
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Live-update the capacity broker's total budget for resident local
|
|
91
|
+
* engines. Called from the config PUT handler when the operator moves the
|
|
92
|
+
* memory slider (`localEngineMemoryGb`); `null` reverts to the host's
|
|
93
|
+
* auto-derived value.
|
|
94
|
+
*
|
|
95
|
+
* No-op when no router exists yet — {@link buildEngineRouter} reads the
|
|
96
|
+
* config itself, so a router built later already picks the new value up.
|
|
97
|
+
* The in-flight case is the one that needs care: a build that read the
|
|
98
|
+
* config *before* this write would otherwise install the stale budget and
|
|
99
|
+
* keep it until shutdown, so chain onto the pending promise rather than
|
|
100
|
+
* only checking the resolved cache.
|
|
101
|
+
*/
|
|
102
|
+
async setLocalEngineMemoryBudget(bytes) {
|
|
103
|
+
const live = this.engineRouter ?? this.engineRouterCache;
|
|
104
|
+
if (live) {
|
|
105
|
+
live.broker.setBudgetBytes(bytes);
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
const pending = this.engineRouterInitPromise;
|
|
109
|
+
if (!pending)
|
|
110
|
+
return;
|
|
111
|
+
const router = await pending.catch(() => null);
|
|
112
|
+
router?.broker.setBudgetBytes(bytes);
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Live-update whether co-resident local models may spill into system RAM.
|
|
116
|
+
* `null` reverts to the host's auto choice. Same in-flight care as
|
|
117
|
+
* {@link setLocalEngineMemoryBudget}, and the same non-eviction contract:
|
|
118
|
+
* turning spillover off doesn't unload anything, it changes what the next
|
|
119
|
+
* spawn is allowed to add.
|
|
120
|
+
*/
|
|
121
|
+
async setAllowRamSpillover(allow) {
|
|
122
|
+
const live = this.engineRouter ?? this.engineRouterCache;
|
|
123
|
+
if (live) {
|
|
124
|
+
live.broker.setAllowRamSpillover(allow);
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
const pending = this.engineRouterInitPromise;
|
|
128
|
+
if (!pending)
|
|
129
|
+
return;
|
|
130
|
+
const router = await pending.catch(() => null);
|
|
131
|
+
router?.broker.setAllowRamSpillover(allow);
|
|
132
|
+
}
|
|
133
|
+
/** Return the provider if it has already been initialized; never creates one. */
|
|
134
|
+
getProviderIfReady(name) {
|
|
135
|
+
return this.providers.get(name) ?? null;
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Lazily construct the multi-engine router using the engine runtime’s
|
|
139
|
+
* already-resolved deps (store, catalog, llamaCppModels, ds4Models, mlxModels,
|
|
140
|
+
* uvRuntime). Once built, the router owns the {@link ProviderPool}
|
|
141
|
+
* and {@link CapacityBroker}; subsequent calls return the cached
|
|
142
|
+
* instance.
|
|
143
|
+
*
|
|
144
|
+
* Returns `null` when {@link LocalEngineRuntimeOptions.engineRouter} was
|
|
145
|
+
* explicitly injected — that path is owned by the caller (typically
|
|
146
|
+
* tests). The lazy build is only for production wiring through
|
|
147
|
+
* `service.ts`.
|
|
148
|
+
*/
|
|
149
|
+
engineRouterCache = null;
|
|
150
|
+
engineRouterInitPromise = null;
|
|
151
|
+
/**
|
|
152
|
+
* Shut down the production-owned lazy engine router, including a router
|
|
153
|
+
* whose construction is still in flight. Pooled local providers do not live
|
|
154
|
+
* in {@link providers}, so omitting this step lets their native children
|
|
155
|
+
* outlive gezeld and become PPID-1 orphans.
|
|
156
|
+
*
|
|
157
|
+
* An explicitly injected {@link engineRouter} remains caller-owned (mostly
|
|
158
|
+
* a test seam) and is deliberately left alone.
|
|
159
|
+
*/
|
|
160
|
+
async shutdownOwnedEngineRouter() {
|
|
161
|
+
let router = this.engineRouterCache;
|
|
162
|
+
const pending = this.engineRouterInitPromise;
|
|
163
|
+
if (!router && pending) {
|
|
164
|
+
try {
|
|
165
|
+
router = await pending;
|
|
166
|
+
}
|
|
167
|
+
catch {
|
|
168
|
+
// A failed construction owns no resident providers, but clear the
|
|
169
|
+
// rejected one-flight so a live hard reset can try again later.
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
this.engineRouterCache = null;
|
|
173
|
+
this.engineRouterInitPromise = null;
|
|
174
|
+
if (!router)
|
|
175
|
+
return;
|
|
176
|
+
try {
|
|
177
|
+
await router.shutdown();
|
|
178
|
+
}
|
|
179
|
+
catch (err) {
|
|
180
|
+
log.warn(`engine router shutdown failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
/**
|
|
184
|
+
* Free the memory a live reset can free without severing anything: evict
|
|
185
|
+
* every resident engine that is idle right now and leave the rest to the
|
|
186
|
+
* pool's ordinary lifecycle. The router itself stays — dropping it while an
|
|
187
|
+
* engine is still serving a turn would orphan that process outside the
|
|
188
|
+
* broker's accounting, which is the reason the old path force-killed
|
|
189
|
+
* everything instead.
|
|
190
|
+
*
|
|
191
|
+
* An explicitly injected {@link engineRouter} remains caller-owned and is
|
|
192
|
+
* left alone, same rule as {@link shutdownOwnedEngineRouter}. A router
|
|
193
|
+
* whose construction is still in flight owns no resident engines yet, so
|
|
194
|
+
* this deliberately does not await it.
|
|
195
|
+
*/
|
|
196
|
+
async releaseIdleOwnedEngines() {
|
|
197
|
+
const router = this.engineRouterCache;
|
|
198
|
+
if (!router)
|
|
199
|
+
return;
|
|
200
|
+
try {
|
|
201
|
+
const busy = await router.releaseIdle();
|
|
202
|
+
if (busy.length > 0) {
|
|
203
|
+
log.info(`[chat] reset kept ${busy.length} busy engine(s) resident (${busy.join(', ')}) — they unload when their turns finish`);
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
catch (err) {
|
|
207
|
+
log.warn(`engine release-idle failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
/**
|
|
211
|
+
* Resolve (or build) the router. Returns `null` only when no local
|
|
212
|
+
* provider is wired up at all (cloud-only installs); production
|
|
213
|
+
* installs with `llamaCppModels`, `ds4Models`, or `mlxModels` set always get a
|
|
214
|
+
* router. Callers MUST tolerate a `null` return — the legacy
|
|
215
|
+
* singleton path takes over.
|
|
216
|
+
*/
|
|
217
|
+
async getEngineRouter() {
|
|
218
|
+
if (this.engineRouter)
|
|
219
|
+
return this.engineRouter;
|
|
220
|
+
if (this.engineRouterCache)
|
|
221
|
+
return this.engineRouterCache;
|
|
222
|
+
if (!this.llamaCppModels && !this.ds4Models && !this.mlxModels)
|
|
223
|
+
return null;
|
|
224
|
+
if (this.engineRouterInitPromise)
|
|
225
|
+
return this.engineRouterInitPromise;
|
|
226
|
+
this.engineRouterInitPromise = this.buildEngineRouter().then((r) => {
|
|
227
|
+
this.engineRouterCache = r;
|
|
228
|
+
return r;
|
|
229
|
+
});
|
|
230
|
+
return this.engineRouterInitPromise;
|
|
231
|
+
}
|
|
232
|
+
async buildEngineRouter() {
|
|
233
|
+
const { EngineRouter } = await import('./engine-router.js');
|
|
234
|
+
const { CapacityBroker } = await import('./capacity-broker.js');
|
|
235
|
+
const { ProviderPool } = await import('./provider-pool.js');
|
|
236
|
+
const { GpuPanicGuard } = await import('./gpu-panic-guard.js');
|
|
237
|
+
const gpuPanicGuard = new GpuPanicGuard();
|
|
238
|
+
const config = await this.store.readConfig();
|
|
239
|
+
const budgetBytes = typeof config.localEngineMemoryGb === 'number'
|
|
240
|
+
? Math.round(config.localEngineMemoryGb * 1024 ** 3)
|
|
241
|
+
: undefined;
|
|
242
|
+
// Measure the accelerator before deriving the budget. Without this the
|
|
243
|
+
// broker sizes a discrete-GPU host off system RAM alone — the shape that
|
|
244
|
+
// told a 64 GB / 24 GB-VRAM box its models get "60% of your 63.9 GB
|
|
245
|
+
// machine" and then refused a model that fit the card plus offload.
|
|
246
|
+
// The probe caches, and a failure degrades to the RAM-only curve.
|
|
247
|
+
const memoryProfile = await (async () => {
|
|
248
|
+
try {
|
|
249
|
+
const { detectMemoryProfileCached } = await import('../../system/memory.js');
|
|
250
|
+
return await detectMemoryProfileCached();
|
|
251
|
+
}
|
|
252
|
+
catch {
|
|
253
|
+
return null;
|
|
254
|
+
}
|
|
255
|
+
})();
|
|
256
|
+
const broker = new CapacityBroker({
|
|
257
|
+
...(budgetBytes !== undefined ? { budgetBytes } : {}),
|
|
258
|
+
gpuVramBytes: memoryProfile?.gpuVramBytes ?? null,
|
|
259
|
+
...(memoryProfile
|
|
260
|
+
? {
|
|
261
|
+
unifiedMemory: memoryProfile.gpuMemoryKind === 'integrated' ||
|
|
262
|
+
memoryProfile.gpuMemoryKind === 'unified',
|
|
263
|
+
}
|
|
264
|
+
: {}),
|
|
265
|
+
allowRamSpillover: config.allowRamSpillover ?? null,
|
|
266
|
+
});
|
|
267
|
+
const pool = new ProviderPool({ broker, builders: {} });
|
|
268
|
+
// Builders close over `this` so they can re-read config and use the
|
|
269
|
+
// already-resolved model managers / runtimes. Each replica goes
|
|
270
|
+
// through the same factories as the singleton path, with
|
|
271
|
+
// `modelOverride` set to pin the modelId + replicaIdx.
|
|
272
|
+
const llamaBuilder = async ({ modelId, replicaIdx, }) => {
|
|
273
|
+
const cfg = await this.store.readConfig();
|
|
274
|
+
const affinity = cfg.providerQueue?.affinity;
|
|
275
|
+
const eb = this.engineBinaries;
|
|
276
|
+
const provider = await buildLlamaCppProvider({
|
|
277
|
+
config: cfg,
|
|
278
|
+
affinity,
|
|
279
|
+
home: this.home,
|
|
280
|
+
...(this.llamaCppModels ? { llamaCppModels: this.llamaCppModels } : {}),
|
|
281
|
+
...(this.gpuArbiter ? { arbiter: this.gpuArbiter } : {}),
|
|
282
|
+
...(eb ? { ensureEngine: () => ensureLlamaEngineStatus(eb, cfg) } : {}),
|
|
283
|
+
catalog: this.catalog,
|
|
284
|
+
modelOverride: { modelId, replicaIdx },
|
|
285
|
+
// Pool path: lets the slot ceiling see co-resident reservations.
|
|
286
|
+
broker,
|
|
287
|
+
});
|
|
288
|
+
await this.initLocalProvider('llama-cpp', provider, cfg);
|
|
289
|
+
// Prefer the launch admission's own reservation (weights + KV at the
|
|
290
|
+
// granted window) over the catalog/weights-multiplier estimate — the
|
|
291
|
+
// ledger otherwise carries zero KV and under-reserves dense models
|
|
292
|
+
// whose KV rivals their weights (M1).
|
|
293
|
+
const bytes = provider.plannedReservationBytes?.() ??
|
|
294
|
+
(await this.resolveResidentBytes('llama-cpp', modelId));
|
|
295
|
+
const installed = await this.llamaCppModels?.resolveModel(modelId).catch(() => null);
|
|
296
|
+
return {
|
|
297
|
+
provider,
|
|
298
|
+
residentBytes: bytes,
|
|
299
|
+
...(installed?.approxSizeBytes ? { modelWeightsBytes: installed.approxSizeBytes } : {}),
|
|
300
|
+
};
|
|
301
|
+
};
|
|
302
|
+
const mlxBuilder = async ({ modelId, replicaIdx, }) => {
|
|
303
|
+
const cfg = await this.store.readConfig();
|
|
304
|
+
const affinity = cfg.providerQueue?.affinity;
|
|
305
|
+
const provider = await buildMlxProvider({
|
|
306
|
+
config: cfg,
|
|
307
|
+
affinity,
|
|
308
|
+
store: this.store,
|
|
309
|
+
...(this.mlxModels ? { mlxModels: this.mlxModels } : {}),
|
|
310
|
+
...(this.uvRuntime ? { uvRuntime: this.uvRuntime } : {}),
|
|
311
|
+
...(this.mlxRuntimeStatus ? { mlxRuntimeStatus: this.mlxRuntimeStatus } : {}),
|
|
312
|
+
...(this.gpuArbiter ? { arbiter: this.gpuArbiter } : {}),
|
|
313
|
+
modelOverride: { modelId, replicaIdx },
|
|
314
|
+
broker,
|
|
315
|
+
});
|
|
316
|
+
await this.initLocalProvider('mlx', provider, cfg);
|
|
317
|
+
// Same M1 preference as the llama-cpp builder: the launch admission's
|
|
318
|
+
// weights+KV reservation over the catalog/weights-multiplier fallback.
|
|
319
|
+
const bytes = provider.plannedReservationBytes?.() ?? (await this.resolveResidentBytes('mlx', modelId));
|
|
320
|
+
const installed = await this.mlxModels?.resolveModel(modelId).catch(() => null);
|
|
321
|
+
return {
|
|
322
|
+
provider,
|
|
323
|
+
residentBytes: bytes,
|
|
324
|
+
...(installed?.approxSizeBytes ? { modelWeightsBytes: installed.approxSizeBytes } : {}),
|
|
325
|
+
};
|
|
326
|
+
};
|
|
327
|
+
const ds4Builder = async ({ modelId, replicaIdx, }) => {
|
|
328
|
+
const cfg = await this.store.readConfig();
|
|
329
|
+
const affinity = cfg.providerQueue?.affinity;
|
|
330
|
+
const provider = await buildDs4Provider({
|
|
331
|
+
config: cfg,
|
|
332
|
+
affinity,
|
|
333
|
+
home: this.home,
|
|
334
|
+
...(this.ds4Models ? { ds4Models: this.ds4Models } : {}),
|
|
335
|
+
...(this.gpuArbiter ? { arbiter: this.gpuArbiter } : {}),
|
|
336
|
+
catalog: this.catalog,
|
|
337
|
+
modelOverride: { modelId, replicaIdx },
|
|
338
|
+
broker,
|
|
339
|
+
});
|
|
340
|
+
await this.initLocalProvider('ds4', provider, cfg);
|
|
341
|
+
const bytes = await this.resolveResidentBytes('ds4', modelId);
|
|
342
|
+
const installed = await this.ds4Models?.resolveModel(modelId).catch(() => null);
|
|
343
|
+
return {
|
|
344
|
+
provider,
|
|
345
|
+
residentBytes: bytes,
|
|
346
|
+
...(installed?.approxSizeBytes ? { modelWeightsBytes: installed.approxSizeBytes } : {}),
|
|
347
|
+
};
|
|
348
|
+
};
|
|
349
|
+
const builders = {};
|
|
350
|
+
if (this.llamaCppModels)
|
|
351
|
+
builders['llama-cpp'] = llamaBuilder;
|
|
352
|
+
if (this.mlxModels)
|
|
353
|
+
builders.mlx = mlxBuilder;
|
|
354
|
+
// ds4 has no model-manager gate (v1 resolves its GGUF from an explicit
|
|
355
|
+
// path / external URL, not the catalog dir) — always register it; the
|
|
356
|
+
// builder throws an actionable error when neither a ds4-server binary
|
|
357
|
+
// nor an external URL is configured, and the M5 availability probe hides
|
|
358
|
+
// ds4 in the UI on unsupported platforms.
|
|
359
|
+
builders.ds4 = ds4Builder;
|
|
360
|
+
// Replace the empty pool with one that holds the actual builders.
|
|
361
|
+
const realPool = new ProviderPool({
|
|
362
|
+
broker,
|
|
363
|
+
builders,
|
|
364
|
+
gpuPanicGuard,
|
|
365
|
+
// The arbiter already reads device-wide accelerator memory for the idle
|
|
366
|
+
// release hint; the pool needs the same number to refuse a spawn onto a
|
|
367
|
+
// card another process has filled.
|
|
368
|
+
...(this.gpuArbiter
|
|
369
|
+
? { vramHeadroom: () => this.gpuArbiter.getMemoryPressureStatus() }
|
|
370
|
+
: {}),
|
|
371
|
+
});
|
|
372
|
+
return new EngineRouter({
|
|
373
|
+
broker,
|
|
374
|
+
pool: realPool,
|
|
375
|
+
builders,
|
|
376
|
+
resolveResidentBytes: (provider, modelId) => {
|
|
377
|
+
// Synchronous lookup; we cache the catalog read inside
|
|
378
|
+
// `resolveResidentBytesCache` populated lazily on first
|
|
379
|
+
// builder call. Falls through to broker estimator on miss.
|
|
380
|
+
const cached = this.resolveResidentBytesCache.get(`${provider}:${modelId}`);
|
|
381
|
+
return cached;
|
|
382
|
+
},
|
|
383
|
+
});
|
|
384
|
+
}
|
|
385
|
+
/**
|
|
386
|
+
* Per-replica provider initialization + cache-controller wiring.
|
|
387
|
+
* Mirrors the singleton-path post-construction work inside
|
|
388
|
+
* {@link ensureProvider}, factored out so the pool's builder
|
|
389
|
+
* closures can share it. Cache-controller registration is gated
|
|
390
|
+
* on replica index — only replica 0 registers, because the
|
|
391
|
+
* controller is keyed by provider name and N adapters would
|
|
392
|
+
* collide.
|
|
393
|
+
*/
|
|
394
|
+
async initLocalProvider(name, provider, config) {
|
|
395
|
+
try {
|
|
396
|
+
await provider.initialize();
|
|
397
|
+
}
|
|
398
|
+
catch (err) {
|
|
399
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
400
|
+
const actionable = err instanceof Error && err.isActionable === true;
|
|
401
|
+
throw new Error(actionable
|
|
402
|
+
? message
|
|
403
|
+
: `${name} provider failed to start: ${message}. Go to Settings and check your credentials.`);
|
|
404
|
+
}
|
|
405
|
+
// Wire the engine's prompt-cache adapter. Without this, pool-built
|
|
406
|
+
// providers (the default path for local engines) have
|
|
407
|
+
// `cacheAdapter = null` — every send re-attaches cache_id to the
|
|
408
|
+
// request body, the wrapped engine clears its KV cache on stream
|
|
409
|
+
// end, and each tool-loop iteration pays the full prefill cost
|
|
410
|
+
// again. Wild-caught on a gemma4-26b/MLX Meester loop:
|
|
411
|
+
// 11+ tool-loop iterations, ~10s of prefill per turn, no cache
|
|
412
|
+
// hits in Python logs because the request body never carried
|
|
413
|
+
// `cache_id`. `ensureProvider` already had this wiring inline;
|
|
414
|
+
// pulling it out so both call sites share one source of truth.
|
|
415
|
+
await this.wireLocalProviderCacheAdapter(name, provider, config);
|
|
416
|
+
}
|
|
417
|
+
/**
|
|
418
|
+
* Construct the engine's `EngineCacheAdapter`, register it with the
|
|
419
|
+
* shared `cacheController`, and attach it to the provider so every
|
|
420
|
+
* subsequent send carries cache extras. Idempotent at the controller
|
|
421
|
+
* level — `registerAdapter` overwrites by `providerName`, so calling
|
|
422
|
+
* this for two replicas of the same provider just keeps the
|
|
423
|
+
* most-recently-registered adapter in the controller's tracking.
|
|
424
|
+
* Each provider still gets its own per-replica adapter via
|
|
425
|
+
* `setCacheAdapter`. Returns early when no controller is wired
|
|
426
|
+
* (test paths) or the provider isn't a local engine.
|
|
427
|
+
*/
|
|
428
|
+
async wireLocalProviderCacheAdapter(name, provider, config) {
|
|
429
|
+
if (!this.cacheController)
|
|
430
|
+
return;
|
|
431
|
+
// ds4 manages its own KV persistence (`--kv-disk-dir`, token-text
|
|
432
|
+
// keyed), so its adapter attaches nothing per request and can't evict
|
|
433
|
+
// or inspect — its one real capability is `warm`: a prefill-only
|
|
434
|
+
// request that runs the (minutes-long, SSD-streamed) conversation
|
|
435
|
+
// prefill while the user is still reading, so the next real turn
|
|
436
|
+
// lands on hot KV. Wired to the OUTER Ds4Provider only — the inner
|
|
437
|
+
// llama provider's send path expects the llama-specific slot adapter.
|
|
438
|
+
if (name === 'ds4') {
|
|
439
|
+
const ds4Provider = provider;
|
|
440
|
+
const { Ds4CacheAdapter } = await import('../ds4/cache-adapter.js');
|
|
441
|
+
const innerLlama = ds4Provider.llamaCpp;
|
|
442
|
+
const adapter = new Ds4CacheAdapter({
|
|
443
|
+
resolveBaseUrl: async () => innerLlama.currentBaseUrl(),
|
|
444
|
+
isBusy: () => {
|
|
445
|
+
const snap = ds4Provider.queue?.snapshot();
|
|
446
|
+
if (!snap)
|
|
447
|
+
return false;
|
|
448
|
+
return snap.running > 0 || snap.queuedInteractive > 0;
|
|
449
|
+
},
|
|
450
|
+
// Route the warm through the session's OWN request assembly so
|
|
451
|
+
// the warmed prefix is byte-identical to the next real turn's
|
|
452
|
+
// prompt (ds4 KV is prefix-keyed from token 0 — a hand-built
|
|
453
|
+
// transcript request stores a key no real turn can hit). The
|
|
454
|
+
// ensureState here also pre-builds the MCP bridge + provider
|
|
455
|
+
// session — work the real turn needs anyway, done early.
|
|
456
|
+
prefillSession: async (sessionId) => {
|
|
457
|
+
return this.prefillCacheSession(sessionId);
|
|
458
|
+
},
|
|
459
|
+
});
|
|
460
|
+
this.cacheController.registerAdapter(adapter);
|
|
461
|
+
ds4Provider.setCacheAdapter(adapter);
|
|
462
|
+
}
|
|
463
|
+
else if (name === 'llama-cpp') {
|
|
464
|
+
const llamaProvider = provider;
|
|
465
|
+
const { LlamaCppCacheAdapter } = await import('../llama-cpp/cache-adapter.js');
|
|
466
|
+
const llamaSlotSavePath = llamaProvider.getSlotSavePath();
|
|
467
|
+
const adapter = new LlamaCppCacheAdapter({
|
|
468
|
+
resolveBaseUrl: async () => llamaProvider.currentBaseUrl(),
|
|
469
|
+
// `/slots` is an AUTHENTICATED endpoint — only `/health` answers
|
|
470
|
+
// without the key (see engine-api-key.ts). The provider authenticates
|
|
471
|
+
// because `build-provider` wraps its fetch in `withEngineApiKey`, but
|
|
472
|
+
// the adapter is constructed here with a bare `fetch`, so without this
|
|
473
|
+
// it sent no Authorization header and every call 401'd: the `/slots`
|
|
474
|
+
// usage poll AND both `?action=save|restore` calls, i.e. the whole
|
|
475
|
+
// disk KV persistence layer, silently dead. It failed quietly because
|
|
476
|
+
// each call site degrades on error by design (no cache entry, `disk
|
|
477
|
+
// save: MISSED`) — the only symptom was cold prefills and a 5-second
|
|
478
|
+
// drip of `unauthorized: Invalid API Key` in the engine log, ~300 per
|
|
479
|
+
// trial. Resolved per call, not captured: the key is generated lazily.
|
|
480
|
+
resolveAuthToken: () => engineApiKey(),
|
|
481
|
+
// The ENGINE slot count (`--parallel N`), not `queue.concurrency`:
|
|
482
|
+
// the queue reserves a background lane above the engine slots, so
|
|
483
|
+
// on a single-slot launch it reads 2 and the adapter would bind
|
|
484
|
+
// sessions to slot ids the server doesn't have (wild-caught
|
|
485
|
+
// 2026-08-03 — save/restore against the phantom slot 400s
|
|
486
|
+
// silently).
|
|
487
|
+
slotCount: llamaProvider.getLaunchedSlots(),
|
|
488
|
+
diskCacheRoot: join(this.home, 'engines', 'llama-cpp', 'slots'),
|
|
489
|
+
diskCacheBudgetMb: config.llamaCppDiskCacheBudgetMb,
|
|
490
|
+
...(llamaSlotSavePath ? { slotSavePath: llamaSlotSavePath } : {}),
|
|
491
|
+
});
|
|
492
|
+
this.cacheController.registerAdapter(adapter);
|
|
493
|
+
llamaProvider.setCacheAdapter(adapter);
|
|
494
|
+
}
|
|
495
|
+
else if (name === 'mlx') {
|
|
496
|
+
const mlxProvider = provider;
|
|
497
|
+
const { MlxCacheAdapter } = await import('../mlx/cache-adapter.js');
|
|
498
|
+
const adapter = new MlxCacheAdapter({
|
|
499
|
+
resolveBaseUrl: async () => mlxProvider.currentBaseUrl(),
|
|
500
|
+
runExclusive: (label, work) => mlxProvider.runExclusiveEngineRequest(label, work),
|
|
501
|
+
});
|
|
502
|
+
this.cacheController.registerAdapter(adapter);
|
|
503
|
+
mlxProvider.setCacheAdapter(adapter);
|
|
504
|
+
}
|
|
505
|
+
}
|
|
506
|
+
/**
|
|
507
|
+
* Cache of catalog `residentBytes` per `(provider:modelId)`.
|
|
508
|
+
* Populated synchronously by `prefetchResidentBytes` so the
|
|
509
|
+
* router's sync resolver works. Falls back to the broker estimator
|
|
510
|
+
* on miss.
|
|
511
|
+
*/
|
|
512
|
+
resolveResidentBytesCache = new Map();
|
|
513
|
+
/**
|
|
514
|
+
* Drop cached reservations so the next admission re-reads the catalog and
|
|
515
|
+
* config. ds4 prices its footprint at the launch context, so a per-model
|
|
516
|
+
* context override changes what the broker must reserve — leaving the old
|
|
517
|
+
* entry cached would keep billing the pre-override number for the life of
|
|
518
|
+
* the process. Call from any route that mutates context sizing.
|
|
519
|
+
*/
|
|
520
|
+
invalidateResidentBytesCache(provider, modelId) {
|
|
521
|
+
if (!provider) {
|
|
522
|
+
this.resolveResidentBytesCache.clear();
|
|
523
|
+
return;
|
|
524
|
+
}
|
|
525
|
+
if (modelId) {
|
|
526
|
+
this.resolveResidentBytesCache.delete(`${provider}:${modelId}`);
|
|
527
|
+
return;
|
|
528
|
+
}
|
|
529
|
+
for (const key of this.resolveResidentBytesCache.keys()) {
|
|
530
|
+
if (key.startsWith(`${provider}:`))
|
|
531
|
+
this.resolveResidentBytesCache.delete(key);
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
/** Extra fixed reservation for the exact ds4 vision encoder this launch uses. */
|
|
535
|
+
async resolveDs4VisionResidentBytes(config, modelId, installed, source) {
|
|
536
|
+
const explicitModelPath = process.env.GEZEL_DS4_MODEL ?? config.ds4ModelPath;
|
|
537
|
+
const explicitVisionEncoderPath = process.env.GEZEL_DS4_VISION_ENCODER ?? config.ds4VisionEncoderPath;
|
|
538
|
+
const externalBaseUrl = process.env.GEZEL_DS4_SERVER_URL ?? config.ds4BaseUrl;
|
|
539
|
+
const vision = resolveDs4VisionLaunch({
|
|
540
|
+
modelId,
|
|
541
|
+
...(config.nativeVision ? { nativeVision: config.nativeVision } : {}),
|
|
542
|
+
...(installed?.visionEncoderPath
|
|
543
|
+
? { installedVisionEncoderPath: installed.visionEncoderPath }
|
|
544
|
+
: {}),
|
|
545
|
+
...(explicitModelPath ? { explicitModelPath } : {}),
|
|
546
|
+
...(explicitVisionEncoderPath ? { explicitVisionEncoderPath } : {}),
|
|
547
|
+
...(externalBaseUrl ? { externalBaseUrl } : {}),
|
|
548
|
+
});
|
|
549
|
+
if (!vision.enabled || !vision.visionEncoderPath)
|
|
550
|
+
return 0;
|
|
551
|
+
let sizeBytes = vision.visionEncoderPath === installed?.visionEncoderPath
|
|
552
|
+
? (installed?.visionEncoderSizeBytes ?? source?.visionEncoder?.sizeBytes)
|
|
553
|
+
: undefined;
|
|
554
|
+
if (!sizeBytes) {
|
|
555
|
+
const { stat } = await import('node:fs/promises');
|
|
556
|
+
sizeBytes = await stat(vision.visionEncoderPath)
|
|
557
|
+
.then((entry) => entry.size)
|
|
558
|
+
.catch(() => undefined);
|
|
559
|
+
}
|
|
560
|
+
return ds4VisionResidentBytes(sizeBytes);
|
|
561
|
+
}
|
|
562
|
+
async resolveResidentBytes(provider, modelId) {
|
|
563
|
+
const cacheKey = `${provider}:${modelId}`;
|
|
564
|
+
const cached = this.resolveResidentBytesCache.get(cacheKey);
|
|
565
|
+
if (cached !== undefined)
|
|
566
|
+
return cached;
|
|
567
|
+
// Read from the catalog. The chat-model manifest carries
|
|
568
|
+
// residentBytes per source block (llamaCpp / ds4 / mlx); fall back to
|
|
569
|
+
// approxSizeBytes * tier multiplier when missing.
|
|
570
|
+
let bytes;
|
|
571
|
+
try {
|
|
572
|
+
const items = await this.catalog.list('chat-model');
|
|
573
|
+
const match = items.find((m) => m.manifest.id === modelId);
|
|
574
|
+
// The discriminated `manifest` union narrows to a chat-model
|
|
575
|
+
// shape via `kind`. Cast through `unknown` because we've
|
|
576
|
+
// already filtered by id from the chat-model list — the kind
|
|
577
|
+
// check would be redundant.
|
|
578
|
+
const cm = match?.manifest;
|
|
579
|
+
if (cm) {
|
|
580
|
+
const block = provider === 'mlx' ? cm.mlx : provider === 'ds4' ? cm.ds4 : cm.llamaCpp;
|
|
581
|
+
if (block?.residentBytes) {
|
|
582
|
+
bytes = block.residentBytes;
|
|
583
|
+
if (provider === 'ds4') {
|
|
584
|
+
const config = await this.store.readConfig();
|
|
585
|
+
const externalBaseUrl = process.env.GEZEL_DS4_SERVER_URL ?? config.ds4BaseUrl;
|
|
586
|
+
if (!externalBaseUrl) {
|
|
587
|
+
const { ds4ProjectedResidentBytes, ds4ResidentBytesForMode, ds4ResidentLine, shouldUseDs4SsdStreaming, } = await import('../ds4/residency.js');
|
|
588
|
+
// Bill the window this model will actually launch with. The
|
|
589
|
+
// authored footprint is a measurement at `residentCtxTokens`, so
|
|
590
|
+
// without this a raised context reserves the old number and the
|
|
591
|
+
// broker admits a model whose KV no longer fits — the exact
|
|
592
|
+
// memory-pressure event the residency rules exist to prevent.
|
|
593
|
+
const ds4Block = cm.ds4;
|
|
594
|
+
const installed = await this.ds4Models?.resolveModel(modelId).catch(() => null);
|
|
595
|
+
const visionResidentBytes = await this.resolveDs4VisionResidentBytes(config, modelId, installed, ds4Block);
|
|
596
|
+
const line = ds4ResidentLine({
|
|
597
|
+
residentBytes: bytes,
|
|
598
|
+
kvBytesPerToken: ds4Block?.kvBytesPerToken,
|
|
599
|
+
residentCtxTokens: ds4Block?.residentCtxTokens,
|
|
600
|
+
});
|
|
601
|
+
if (line) {
|
|
602
|
+
const { totalmem } = await import('node:os');
|
|
603
|
+
bytes = ds4ProjectedResidentBytes(line, resolveDs4LaunchCtx({
|
|
604
|
+
configured: config.modelContextOverrides?.[`ds4:${modelId}`] ?? config.ds4NumCtx,
|
|
605
|
+
ramTieredCtx: totalmem() / 1024 ** 3 >= 192 ? 262_144 : 131_072,
|
|
606
|
+
catalogMaxCtx: ds4Block?.maxLaunchCtx,
|
|
607
|
+
minViableContextTokens: minViableLocalContextTokens(),
|
|
608
|
+
}));
|
|
609
|
+
}
|
|
610
|
+
bytes = ds4ResidentBytesForMode(bytes, shouldUseDs4SsdStreaming({
|
|
611
|
+
configured: config.ds4SsdStreaming,
|
|
612
|
+
...(ds4Block?.ssdStreamingSupported !== undefined
|
|
613
|
+
? { ssdStreamingSupported: ds4Block.ssdStreamingSupported }
|
|
614
|
+
: {}),
|
|
615
|
+
modelSizeBytes: ds4Block?.residentWeightBytes ?? block.approxSizeBytes,
|
|
616
|
+
...(visionResidentBytes > 0 ? { companionBytes: visionResidentBytes } : {}),
|
|
617
|
+
}), ds4Block?.ssdStreamingSupported);
|
|
618
|
+
bytes += visionResidentBytes;
|
|
619
|
+
}
|
|
620
|
+
}
|
|
621
|
+
}
|
|
622
|
+
else if (block?.approxSizeBytes) {
|
|
623
|
+
const { CapacityBroker } = await import('./capacity-broker.js');
|
|
624
|
+
// `approxSizeBytes` is the weights alone; a multimodal entry also
|
|
625
|
+
// loads its projector, which the catalog sizes separately.
|
|
626
|
+
const mmprojBytes = provider === 'llama-cpp' ? (cm.llamaCpp?.mmproj?.sizeBytes ?? 0) : 0;
|
|
627
|
+
let residentWeightFileBytes = block.approxSizeBytes;
|
|
628
|
+
if (provider === 'llama-cpp') {
|
|
629
|
+
// v0.4 can leave architecture-marked row-addressable embeddings
|
|
630
|
+
// file-backed (notably Qwen 3.8 Flash Next's 51B-parameter
|
|
631
|
+
// PLE/engram table). Inspect the installed split GGUF before the pool's
|
|
632
|
+
// preflight reservation; otherwise it rejects the model before
|
|
633
|
+
// buildLlamaCppProvider gets a chance to make the same deduction.
|
|
634
|
+
const installed = await this.llamaCppModels?.resolveModel(modelId).catch(() => null);
|
|
635
|
+
if (installed?.weightsPath) {
|
|
636
|
+
const [summary, config, perModel] = await Promise.all([
|
|
637
|
+
readGgufSummaryAsync(installed.weightsPath, { includeTensorSizes: true }).catch(() => null),
|
|
638
|
+
this.store.readConfig(),
|
|
639
|
+
resolveCatalogLlamaCppEngineConfig(this.catalog, modelId),
|
|
640
|
+
]);
|
|
641
|
+
if (summary) {
|
|
642
|
+
residentWeightFileBytes = Math.max(0, residentWeightFileBytes -
|
|
643
|
+
effectiveLazyTensorBytes(summary, config.llamaCppLazyMode ?? perModel?.lazyMode ?? 'auto'));
|
|
644
|
+
}
|
|
645
|
+
}
|
|
646
|
+
}
|
|
647
|
+
bytes = CapacityBroker.estimateResidentBytes(provider, residentWeightFileBytes, {
|
|
648
|
+
mmprojBytes,
|
|
649
|
+
});
|
|
650
|
+
}
|
|
651
|
+
}
|
|
652
|
+
}
|
|
653
|
+
catch {
|
|
654
|
+
/* fall through to default */
|
|
655
|
+
}
|
|
656
|
+
if (bytes === undefined) {
|
|
657
|
+
const { CapacityBroker } = await import('./capacity-broker.js');
|
|
658
|
+
bytes = CapacityBroker.estimateResidentBytes(provider, 8 * 1024 ** 3);
|
|
659
|
+
}
|
|
660
|
+
this.resolveResidentBytesCache.set(cacheKey, bytes);
|
|
661
|
+
return bytes;
|
|
662
|
+
}
|
|
663
|
+
/**
|
|
664
|
+
* Reconcile the pool's resident set to match a target clone-count
|
|
665
|
+
* map. Surfaces the Settings → Local Models picker's intent to the
|
|
666
|
+
* runtime: spawn missing replicas (up to capacity) and evict
|
|
667
|
+
* excess. No-op when no router is configured.
|
|
668
|
+
*/
|
|
669
|
+
async reconcileEnginePool(provider, target) {
|
|
670
|
+
const router = await this.getEngineRouter();
|
|
671
|
+
if (!router)
|
|
672
|
+
return;
|
|
673
|
+
await router.reconcileClones(provider, target);
|
|
674
|
+
}
|
|
675
|
+
/**
|
|
676
|
+
* Unload one already-resident local model replica without constructing the
|
|
677
|
+
* engine router as a side effect. The pool rejects the request if the model
|
|
678
|
+
* became busy after the UI's last lifecycle sample.
|
|
679
|
+
*/
|
|
680
|
+
async unloadIdleEngine(provider, modelId, replicaIdx) {
|
|
681
|
+
const router = this.engineRouter ?? this.engineRouterCache;
|
|
682
|
+
if (!router || !router.pool.has(makeEngineKey(provider, modelId, replicaIdx)))
|
|
683
|
+
return false;
|
|
684
|
+
return router.unloadIdle(provider, modelId, replicaIdx);
|
|
685
|
+
}
|
|
686
|
+
/**
|
|
687
|
+
* Snapshot of the live pool — committed bytes, budget, per-key
|
|
688
|
+
* resident set. Surfaced via `GET /api/engines/status`. Returns
|
|
689
|
+
* `null` for installs without a pool wired.
|
|
690
|
+
*/
|
|
691
|
+
async engineStatus() {
|
|
692
|
+
const router = await this.getEngineRouter();
|
|
693
|
+
if (!router)
|
|
694
|
+
return null;
|
|
695
|
+
return router.snapshot();
|
|
696
|
+
}
|
|
697
|
+
/**
|
|
698
|
+
* Read the already-live local-engine pool without constructing the router.
|
|
699
|
+
* Hot status endpoints use this path so opening a telemetry popover never
|
|
700
|
+
* initializes local inference as a side effect.
|
|
701
|
+
*/
|
|
702
|
+
peekEngineStatus() {
|
|
703
|
+
const router = this.engineRouter ?? this.engineRouterCache;
|
|
704
|
+
return router?.snapshot() ?? null;
|
|
705
|
+
}
|
|
706
|
+
/**
|
|
707
|
+
* Live provider-queue summaries for pool-resident local engines, keyed
|
|
708
|
+
* by provider name — the data `/api/queues` needs to reflect pooled
|
|
709
|
+
* work the singleton {@link getProviderIfReady} path can't see (chat
|
|
710
|
+
* turns AND background one-shots). See
|
|
711
|
+
* {@link ProviderPool.queueSummaries} for why the blind spot existed.
|
|
712
|
+
*
|
|
713
|
+
* Synchronous, non-building peek: reads the already-resolved router and
|
|
714
|
+
* returns an empty map when none exists yet. A poll before any local
|
|
715
|
+
* work has run has nothing resident to report anyway — and a status
|
|
716
|
+
* endpoint must never spin the router up as a side effect.
|
|
717
|
+
*/
|
|
718
|
+
localEngineQueueSummaries() {
|
|
719
|
+
const router = this.engineRouter ?? this.engineRouterCache;
|
|
720
|
+
if (!router)
|
|
721
|
+
return new Map();
|
|
722
|
+
return router.pool.queueSummaries();
|
|
723
|
+
}
|
|
724
|
+
/**
|
|
725
|
+
* Launch provenance of every live local engine — the granted context
|
|
726
|
+
* window, slots, and KV dtype each engine ACTUALLY started with, from
|
|
727
|
+
* the supervisors' retained launch payloads. Non-building and cheap:
|
|
728
|
+
* walks resident providers only, never starts an engine. Feeds
|
|
729
|
+
* `/api/system/diagnostics` `localEngines` (Settings → About), so a
|
|
730
|
+
* "model is looping" report carries the grant without log spelunking.
|
|
731
|
+
*/
|
|
732
|
+
localEngineLaunchSummaries() {
|
|
733
|
+
const router = this.engineRouter ?? this.engineRouterCache;
|
|
734
|
+
const out = router?.pool.engineLaunchSnapshots() ?? [];
|
|
735
|
+
// The singleton map can hold the same provider object (and therefore
|
|
736
|
+
// the same engine process) a pool entry already reported — dedupe by
|
|
737
|
+
// pid, the process identity the snapshot is about.
|
|
738
|
+
const seenPids = new Set(out.map((entry) => entry.snapshot.pid).filter((pid) => pid !== undefined));
|
|
739
|
+
for (const name of ['llama-cpp', 'mlx', 'ds4']) {
|
|
740
|
+
const singleton = this.providers.get(name);
|
|
741
|
+
const snapshot = singleton?.engineLaunchSnapshot?.();
|
|
742
|
+
if (!snapshot)
|
|
743
|
+
continue;
|
|
744
|
+
if (snapshot.pid !== undefined && seenPids.has(snapshot.pid))
|
|
745
|
+
continue;
|
|
746
|
+
const modelId = singleton?.getEffectiveModelId?.();
|
|
747
|
+
out.push({ provider: name, ...(modelId !== undefined ? { modelId } : {}), snapshot });
|
|
748
|
+
}
|
|
749
|
+
return out;
|
|
750
|
+
}
|
|
751
|
+
/**
|
|
752
|
+
* Non-building lookup for an already-created native provider. Unlike
|
|
753
|
+
* `getProviderForModel`, this cannot allocate a replica, evict another model,
|
|
754
|
+
* or start an engine. The caller still checks the provider's live base URL
|
|
755
|
+
* because a retained provider object may currently have no resident process.
|
|
756
|
+
*/
|
|
757
|
+
peekResidentLocalProviders(name, modelId) {
|
|
758
|
+
if (!isLocalProvider(name) || !modelId)
|
|
759
|
+
return [];
|
|
760
|
+
const singleton = this.providers.get(name);
|
|
761
|
+
const router = this.engineRouter ?? this.engineRouterCache;
|
|
762
|
+
const pooled = router?.pool.peekProvidersForModel(name, modelId) ?? [];
|
|
763
|
+
return singleton ? [singleton, ...pooled.filter((provider) => provider !== singleton)] : pooled;
|
|
764
|
+
}
|
|
765
|
+
/**
|
|
766
|
+
* Resolve the context window a native model would receive without binding a
|
|
767
|
+
* pool replica. This is the broker-side half of remote admission: focusing a
|
|
768
|
+
* chat needs the live memory clamp so the user daemon can size its prompt,
|
|
769
|
+
* but it must not load the model or evict somebody else's resident engine.
|
|
770
|
+
*
|
|
771
|
+
* `standalone` prices the target as the eventual sole resident: inventory
|
|
772
|
+
* callers use it for stable device fitness, while remote admission combines
|
|
773
|
+
* it with `liveSystemPressure` because a competing Gezel engine is
|
|
774
|
+
* evictable/queueable but memory held by other applications is not. See
|
|
775
|
+
* {@link previewLocalEnginePlan}'s `standalone` note.
|
|
776
|
+
*/
|
|
777
|
+
async previewContextWindowForModel(name, modelId, opts = {}) {
|
|
778
|
+
return (await this.previewLocalEnginePlan(name, modelId, opts)).contextWindow;
|
|
779
|
+
}
|
|
780
|
+
/**
|
|
781
|
+
* Reservations held by models OTHER than the one being previewed.
|
|
782
|
+
*
|
|
783
|
+
* `committed()` totals every replica, the previewed model's own included.
|
|
784
|
+
* Feeding that back as `committedOtherBytes` prices the launch as if a
|
|
785
|
+
* second copy had to load beside the resident one, so the model currently
|
|
786
|
+
* serving chats reports "won't fit" against its own reservation — and on a
|
|
787
|
+
* host where one big model fills most of the budget, every OTHER row is
|
|
788
|
+
* denied by a reservation that eviction would release. Every consumer of
|
|
789
|
+
* `committedOtherBytes` means co-resident models, so subtract our own
|
|
790
|
+
* replicas here. A key the parser doesn't recognise stays counted: an
|
|
791
|
+
* unattributable reservation is real memory, and over-counting only makes
|
|
792
|
+
* the preview conservative.
|
|
793
|
+
*/
|
|
794
|
+
committedOtherBytesFor(snapshot, provider, modelId) {
|
|
795
|
+
if (!snapshot?.enforced)
|
|
796
|
+
return 0;
|
|
797
|
+
const own = snapshot.byKey.reduce((sum, entry) => {
|
|
798
|
+
const parsed = parseEngineKey(entry.key);
|
|
799
|
+
return parsed?.provider === provider && parsed.modelId === modelId ? sum + entry.bytes : sum;
|
|
800
|
+
}, 0);
|
|
801
|
+
return Math.max(0, snapshot.committedBytes - own);
|
|
802
|
+
}
|
|
803
|
+
/**
|
|
804
|
+
* The memory picture every engine's launch preview prices against.
|
|
805
|
+
*
|
|
806
|
+
* One derivation because each engine branch below used to rebuild it, and
|
|
807
|
+
* they drifted: the llama.cpp branch pinned its admission clamp to usable
|
|
808
|
+
* VRAM alone on discrete hosts, so a 21 GB MoE the broker would gladly
|
|
809
|
+
* admit against a 30 GB budget reported "won't fit" — while the MLX branch,
|
|
810
|
+
* which never passed live RAM, priced the same question correctly. A 4.7 GB
|
|
811
|
+
* model was denied the same way. Adding an engine must not re-open that.
|
|
812
|
+
*
|
|
813
|
+
* Policy previews deliberately carry no `freeSystemRamBytes`: live free RAM
|
|
814
|
+
* is self-referential there — a warm engine can depress it and make every
|
|
815
|
+
* inventory row, itself included, fluctuate. Imminent placement callers may
|
|
816
|
+
* opt into `liveSystemPressure`; that is the broker `/admit` path and must
|
|
817
|
+
* use the same reclaimable-aware clamp as provider construction. Confining
|
|
818
|
+
* grown KV to fast memory is not lost for policy previews —
|
|
819
|
+
* `planAdaptiveContextGrowth` applies that clamp itself from `budgetKind` +
|
|
820
|
+
* `vramBytes`.
|
|
821
|
+
*/
|
|
822
|
+
async previewCapacityInputs(provider, modelId, opts) {
|
|
823
|
+
const { computeCapacityBudget } = await import('./capacity-broker.js');
|
|
824
|
+
const { measuredCapacityBudget } = await import('./measured-budget.js');
|
|
825
|
+
const router = this.engineRouter ?? this.engineRouterCache;
|
|
826
|
+
const snapshot = router?.broker.committed();
|
|
827
|
+
// An unenforced budget carries no usable numbers — fall back wholesale
|
|
828
|
+
// rather than per-field, so a snapshot never contributes half a picture.
|
|
829
|
+
const enforced = snapshot?.enforced ? snapshot : undefined;
|
|
830
|
+
// No broker yet means no engine has ever been placed in this process, so
|
|
831
|
+
// the ambient GPU probe may still be unpublished — measure rather than
|
|
832
|
+
// read it. See measured-budget.ts for what a missing card costs here.
|
|
833
|
+
const live = enforced ? computeCapacityBudget() : await measuredCapacityBudget();
|
|
834
|
+
const committedOtherBytes = this.committedOtherBytesFor(snapshot, provider, modelId);
|
|
835
|
+
return {
|
|
836
|
+
budgetBytes: enforced?.budgetBytes ?? live.budgetBytes,
|
|
837
|
+
fastBudgetBytes: enforced === undefined
|
|
838
|
+
? live.fastBytes
|
|
839
|
+
: (router?.broker.fastBudgetBytes() ?? enforced.pools.fastBytes),
|
|
840
|
+
concurrencySizingBytes: enforced?.pools.concurrencySizingBytes ?? live.concurrencySizingBytes,
|
|
841
|
+
vramBytes: enforced?.pools.vramBytes ?? live.vramBytes,
|
|
842
|
+
budgetKind: enforced?.pools.kind ?? live.kind,
|
|
843
|
+
committedOtherBytes: opts.standalone ? 0 : committedOtherBytes,
|
|
844
|
+
// A standalone imminent placement treats other Gezel engines as
|
|
845
|
+
// evictable: if one is busy, /infer queues until it drains. Its current
|
|
846
|
+
// process footprint is therefore not an intrinsic device-capacity
|
|
847
|
+
// denial. With no competing reservation, live pressure represents
|
|
848
|
+
// external applications / real system load and must match launch.
|
|
849
|
+
...(opts.liveSystemPressure && !(opts.standalone && committedOtherBytes > 0)
|
|
850
|
+
? { freeSystemRamBytes: availableSystemRamBytes() }
|
|
851
|
+
: {}),
|
|
852
|
+
};
|
|
853
|
+
}
|
|
854
|
+
/**
|
|
855
|
+
* Full non-binding launch preview: the context window a native model
|
|
856
|
+
* would receive AND the resident footprint at that window. Powers the
|
|
857
|
+
* models-list "size in memory" column alongside
|
|
858
|
+
* {@link previewContextWindowForModel}.
|
|
859
|
+
*
|
|
860
|
+
* Two footprints, deliberately: `plannedResidentBytes` is weights plus
|
|
861
|
+
* ONE slot's KV — what serving a single chat costs, and the only figure
|
|
862
|
+
* that tracks measured peak RSS. `reservedResidentBytes` is weights plus
|
|
863
|
+
* `plannedSlots` slots' KV — what the broker actually holds. Quoting the
|
|
864
|
+
* fleet as "size in memory" reads as the cost of using the model at all,
|
|
865
|
+
* which overstates a multi-slot host by the slot count.
|
|
866
|
+
*/
|
|
867
|
+
async previewLocalEnginePlan(name, modelId,
|
|
868
|
+
/**
|
|
869
|
+
* ds4 only: price a catalog entry that is NOT downloaded yet. The ds4 plan
|
|
870
|
+
* needs the catalog block and this device's RAM tier, never the GGUF, so
|
|
871
|
+
* the browse list can quote the window and footprint a download would land
|
|
872
|
+
* on — which is when the fit decision is actually made. Other engines keep
|
|
873
|
+
* throwing {@link ModelNotInstalledError}: their plans read the real
|
|
874
|
+
* header.
|
|
875
|
+
*/
|
|
876
|
+
opts = {}) {
|
|
877
|
+
let residentContextWindow;
|
|
878
|
+
for (const resident of this.peekResidentLocalProviders(name, modelId)) {
|
|
879
|
+
const residentModel = resident.getEffectiveModelId?.();
|
|
880
|
+
if (residentModel && residentModel !== modelId)
|
|
881
|
+
continue;
|
|
882
|
+
const prepared = await resident.prepareContextWindow?.(modelId);
|
|
883
|
+
const live = prepared ?? resident.getContextWindow?.();
|
|
884
|
+
if (live && Number.isFinite(live) && live > 0) {
|
|
885
|
+
residentContextWindow = Math.floor(live);
|
|
886
|
+
break;
|
|
887
|
+
}
|
|
888
|
+
}
|
|
889
|
+
const useResidentOr = (planned, minimum) => {
|
|
890
|
+
if (residentContextWindow === undefined)
|
|
891
|
+
return planned;
|
|
892
|
+
if (residentContextWindow < minimum) {
|
|
893
|
+
throw new CapacityDeniedError(`${modelId} is already running with only ${residentContextWindow.toLocaleString('en-US')} context tokens per turn, below its required ${minimum.toLocaleString('en-US')}-token working window. Restart the local engine so Gezel can re-admit it at the current context policy.`, { reason: 'resident-below-minimum' });
|
|
894
|
+
}
|
|
895
|
+
return residentContextWindow;
|
|
896
|
+
};
|
|
897
|
+
// Reusing an already-running target does not allocate its weights again,
|
|
898
|
+
// so current free RAM (which that same process depressed) is not a launch
|
|
899
|
+
// input. Keep the policy checks below — including resident-below-minimum
|
|
900
|
+
// and changed overrides — while skipping only the self-referential clamp.
|
|
901
|
+
const capacityOpts = residentContextWindow !== undefined && opts.liveSystemPressure
|
|
902
|
+
? { ...opts, liveSystemPressure: false }
|
|
903
|
+
: opts;
|
|
904
|
+
const config = await this.store.readConfig();
|
|
905
|
+
// The floor this host is held to — 64K, or 32K where memory forces the
|
|
906
|
+
// trade. Read once so every branch of the preview prices the same window
|
|
907
|
+
// the launch path will ask for.
|
|
908
|
+
const contextFloor = minViableLocalContextTokens();
|
|
909
|
+
if (name === 'mlx') {
|
|
910
|
+
const installed = await this.mlxModels?.resolveModel(modelId);
|
|
911
|
+
if (!installed)
|
|
912
|
+
throw new ModelNotInstalledError(name, modelId);
|
|
913
|
+
const mlxOverride = config.modelContextOverrides?.[`mlx:${modelId}`];
|
|
914
|
+
// An override below the host floor is deliberate user intent — lower
|
|
915
|
+
// the floor to the override instead of raising the request back up.
|
|
916
|
+
const mlxFloor = mlxOverride !== undefined ? Math.min(contextFloor, mlxOverride) : contextFloor;
|
|
917
|
+
const geometry = installed.modelDir ? readMlxModelGeometry(installed.modelDir) : undefined;
|
|
918
|
+
const { CapacityBroker, defaultLocalEngineSlots, kvQuantScale, localEngineSlotCeiling, planCtxTokensForMemory, plannedLocalEngineSlots, } = await import('./capacity-broker.js');
|
|
919
|
+
const capacity = await this.previewCapacityInputs('mlx', modelId, capacityOpts);
|
|
920
|
+
const { budgetBytes, fastBudgetBytes: fastBudget, committedOtherBytes, concurrencySizingBytes: concurrencySizingBudget, } = capacity;
|
|
921
|
+
const kvBits = config.mlxKvBits ?? 0;
|
|
922
|
+
const kvCacheType = kvBits === 4 ? 'q4_0' : kvBits === 8 ? 'q8_0' : 'f16';
|
|
923
|
+
const weightsResident = CapacityBroker.estimateResidentBytes('mlx', installed.approxSizeBytes);
|
|
924
|
+
// One planning pass — request resolution + memory-priced admission
|
|
925
|
+
// (M4: mirror buildMlxProvider so the advertised window is what memory
|
|
926
|
+
// admits, not the native max — before this an MLX 26B on a 16 GB Mac
|
|
927
|
+
// previewed 256K). Runs a second time with the override ignored to
|
|
928
|
+
// mark where "Automatic" lands on the slider.
|
|
929
|
+
const planPass = (configuredLimit, floor) => {
|
|
930
|
+
let effective = resolveMlxEffectiveNumCtx({
|
|
931
|
+
...(installed.contextWindow ? { modelContextWindow: installed.contextWindow } : {}),
|
|
932
|
+
...(configuredLimit !== undefined ? { configuredLimit } : {}),
|
|
933
|
+
minViableContextTokens: floor,
|
|
934
|
+
});
|
|
935
|
+
const minimum = Math.min(installed.contextWindow ?? floor, floor);
|
|
936
|
+
const exactPerSlotKvF16 = geometry
|
|
937
|
+
? estimateExactPerSlotKvBytesF16(geometry, effective)
|
|
938
|
+
: undefined;
|
|
939
|
+
if (!geometry || exactPerSlotKvF16 === undefined)
|
|
940
|
+
return { grantedCtx: effective, minimum };
|
|
941
|
+
const kvBytesPerToken = (exactPerSlotKvF16 / Math.max(1, effective)) * kvQuantScale(kvCacheType);
|
|
942
|
+
const configured = config.providerConcurrency?.mlx;
|
|
943
|
+
const ceiling = localEngineSlotCeiling({
|
|
944
|
+
engine: 'mlx',
|
|
945
|
+
budgetBytes: fastBudget,
|
|
946
|
+
sizingBudgetBytes: concurrencySizingBudget,
|
|
947
|
+
weightsBytes: installed.approxSizeBytes,
|
|
948
|
+
perTurnCtxTokens: effective,
|
|
949
|
+
kvCacheType,
|
|
950
|
+
committedOtherBytes,
|
|
951
|
+
exactPerSlotKvBytesF16: exactPerSlotKvF16,
|
|
952
|
+
});
|
|
953
|
+
let slots = plannedLocalEngineSlots({
|
|
954
|
+
configuredSlots: configured,
|
|
955
|
+
ceiling,
|
|
956
|
+
tierDefault: defaultLocalEngineSlots(fastBudget),
|
|
957
|
+
});
|
|
958
|
+
const admission = planCtxTokensForMemory({
|
|
959
|
+
requestedPerTurnCtxTokens: effective,
|
|
960
|
+
slots,
|
|
961
|
+
minimumPerTurnCtxTokens: minimum,
|
|
962
|
+
kvBytesPerToken,
|
|
963
|
+
weightsResidentBytes: weightsResident,
|
|
964
|
+
budgetBytes,
|
|
965
|
+
committedOtherBytes,
|
|
966
|
+
...(capacity.freeSystemRamBytes !== undefined
|
|
967
|
+
? { freeSystemRamBytes: capacity.freeSystemRamBytes }
|
|
968
|
+
: {}),
|
|
969
|
+
vramBytes: capacity.vramBytes,
|
|
970
|
+
});
|
|
971
|
+
if (!admission.minimumSatisfied) {
|
|
972
|
+
throw new CapacityDeniedError(NOT_ENOUGH_MEMORY_MESSAGE);
|
|
973
|
+
}
|
|
974
|
+
slots = admission.slots;
|
|
975
|
+
effective = admission.perTurnCtxTokens;
|
|
976
|
+
return { grantedCtx: effective, slots, kvBytesPerToken, minimum };
|
|
977
|
+
};
|
|
978
|
+
const plan = planPass(mlxOverride ?? config.mlxNumCtx, mlxFloor);
|
|
979
|
+
let autoContextWindow;
|
|
980
|
+
if (mlxOverride !== undefined) {
|
|
981
|
+
try {
|
|
982
|
+
autoContextWindow = planPass(config.mlxNumCtx, contextFloor).grantedCtx;
|
|
983
|
+
}
|
|
984
|
+
catch {
|
|
985
|
+
// Automatic sizing may not fit where a smaller override does — no marker.
|
|
986
|
+
}
|
|
987
|
+
}
|
|
988
|
+
// A resident engine below (or above) a freshly-set override keeps its
|
|
989
|
+
// launch window until restart; surface that as restart-required
|
|
990
|
+
// instead of quietly showing the stale window as if it were current.
|
|
991
|
+
if (mlxOverride !== undefined &&
|
|
992
|
+
residentContextWindow !== undefined &&
|
|
993
|
+
residentContextWindow !== plan.grantedCtx) {
|
|
994
|
+
throw new CapacityDeniedError(`${modelId} is running with ${residentContextWindow.toLocaleString('en-US')} context tokens per turn, but its custom context setting now resolves to ${plan.grantedCtx.toLocaleString('en-US')}. Restart the local engine to apply it.`, { reason: 'resident-below-minimum' });
|
|
995
|
+
}
|
|
996
|
+
const kvLin = geometry !== undefined
|
|
997
|
+
? (() => {
|
|
998
|
+
const a = estimateExactPerSlotKvBytesF16(geometry, 8_192);
|
|
999
|
+
const b = estimateExactPerSlotKvBytesF16(geometry, 65_536);
|
|
1000
|
+
if (a === undefined || b === undefined)
|
|
1001
|
+
return undefined;
|
|
1002
|
+
const scale = kvQuantScale(kvCacheType);
|
|
1003
|
+
const bytesPerToken = ((b - a) / (65_536 - 8_192)) * scale;
|
|
1004
|
+
return { bytesPerToken, fixedBytes: Math.max(0, a * scale - bytesPerToken * 8_192) };
|
|
1005
|
+
})()
|
|
1006
|
+
: undefined;
|
|
1007
|
+
return {
|
|
1008
|
+
contextWindow: useResidentOr(plan.grantedCtx, plan.minimum),
|
|
1009
|
+
...(plan.slots !== undefined && plan.kvBytesPerToken !== undefined
|
|
1010
|
+
? {
|
|
1011
|
+
plannedResidentBytes: Math.round(weightsResident + plan.kvBytesPerToken * plan.grantedCtx),
|
|
1012
|
+
reservedResidentBytes: Math.round(weightsResident + plan.kvBytesPerToken * plan.grantedCtx * plan.slots),
|
|
1013
|
+
plannedSlots: plan.slots,
|
|
1014
|
+
weightsResidentBytes: weightsResident,
|
|
1015
|
+
}
|
|
1016
|
+
: {}),
|
|
1017
|
+
...(installed.contextWindow ? { nativeContextWindow: installed.contextWindow } : {}),
|
|
1018
|
+
...(mlxOverride !== undefined ? { overrideContextTokens: mlxOverride } : {}),
|
|
1019
|
+
...(autoContextWindow !== undefined ? { autoContextWindow } : {}),
|
|
1020
|
+
...(kvLin !== undefined
|
|
1021
|
+
? { kvBytesPerTokenPerSlot: kvLin.bytesPerToken, kvFixedBytesPerSlot: kvLin.fixedBytes }
|
|
1022
|
+
: {}),
|
|
1023
|
+
};
|
|
1024
|
+
}
|
|
1025
|
+
if (name === 'ds4') {
|
|
1026
|
+
const installed = await this.ds4Models?.resolveModel(modelId);
|
|
1027
|
+
const hasExplicitSource = Boolean(process.env.GEZEL_DS4_MODEL ||
|
|
1028
|
+
process.env.GEZEL_DS4_SERVER_URL ||
|
|
1029
|
+
config.ds4ModelPath ||
|
|
1030
|
+
config.ds4BaseUrl);
|
|
1031
|
+
const detail = await this.catalog.get('chat-model', modelId).catch(() => null);
|
|
1032
|
+
const ds4Manifest = detail?.manifest.kind === 'chat-model' ? detail.manifest : undefined;
|
|
1033
|
+
const ds4Source = ds4Manifest?.ds4;
|
|
1034
|
+
// A catalog entry with a ds4 block is plannable before download; only a
|
|
1035
|
+
// model we know nothing about is genuinely absent.
|
|
1036
|
+
if (!installed && !hasExplicitSource && !(opts.allowUninstalled && ds4Source)) {
|
|
1037
|
+
throw new ModelNotInstalledError(name, modelId);
|
|
1038
|
+
}
|
|
1039
|
+
const { totalmem } = await import('node:os');
|
|
1040
|
+
const ramTieredCtx = totalmem() / 1024 ** 3 >= 192 ? 262_144 : 131_072;
|
|
1041
|
+
const ds4Override = config.modelContextOverrides?.[`ds4:${modelId}`];
|
|
1042
|
+
const ds4Floor = ds4Override !== undefined ? Math.min(contextFloor, ds4Override) : contextFloor;
|
|
1043
|
+
const effective = resolveDs4LaunchCtx({
|
|
1044
|
+
configured: ds4Override ?? config.ds4NumCtx,
|
|
1045
|
+
ramTieredCtx,
|
|
1046
|
+
catalogMaxCtx: ds4Source?.maxLaunchCtx,
|
|
1047
|
+
minViableContextTokens: ds4Floor,
|
|
1048
|
+
});
|
|
1049
|
+
if (ds4Override !== undefined &&
|
|
1050
|
+
residentContextWindow !== undefined &&
|
|
1051
|
+
residentContextWindow !== effective) {
|
|
1052
|
+
throw new CapacityDeniedError(`${modelId} is running with ${residentContextWindow.toLocaleString('en-US')} context tokens per turn, but its custom context setting now resolves to ${effective.toLocaleString('en-US')}. Restart the local engine to apply it.`, { reason: 'resident-below-minimum' });
|
|
1053
|
+
}
|
|
1054
|
+
// The slider's max for ds4: the authored catalog launch ceiling wins
|
|
1055
|
+
// over the advertised native window because ds4 has no ctx-vs-memory
|
|
1056
|
+
// admission to catch a window the engine cannot actually serve. The
|
|
1057
|
+
// manifest's window stands in before download, when there is no GGUF
|
|
1058
|
+
// header to read.
|
|
1059
|
+
const nativeWindow = installed?.contextWindow ?? ds4Manifest?.contextWindow;
|
|
1060
|
+
const ceilingTokens = ds4Source?.maxLaunchCtx !== undefined || nativeWindow !== undefined
|
|
1061
|
+
? Math.min(ds4Source?.maxLaunchCtx ?? Number.POSITIVE_INFINITY, nativeWindow ?? Number.POSITIVE_INFINITY)
|
|
1062
|
+
: undefined;
|
|
1063
|
+
let ds4AutoContextWindow;
|
|
1064
|
+
if (ds4Override !== undefined) {
|
|
1065
|
+
ds4AutoContextWindow = resolveDs4LaunchCtx({
|
|
1066
|
+
configured: config.ds4NumCtx,
|
|
1067
|
+
ramTieredCtx,
|
|
1068
|
+
catalogMaxCtx: ds4Source?.maxLaunchCtx,
|
|
1069
|
+
minViableContextTokens: contextFloor,
|
|
1070
|
+
});
|
|
1071
|
+
}
|
|
1072
|
+
// ds4's catalog residentBytes is an authored working set (resident
|
|
1073
|
+
// weights or expert cache + fixed weights + KV) measured at ONE window. Where
|
|
1074
|
+
// the entry also authors the per-token slope, re-base it onto the window
|
|
1075
|
+
// this device actually launches with and hand the UI the same
|
|
1076
|
+
// `fixed + slope × ctx` line llama.cpp/MLX rows carry, so the slider
|
|
1077
|
+
// prices a drag instead of claiming the footprint never moves. Entries
|
|
1078
|
+
// without a measured slope keep the flat number and say so.
|
|
1079
|
+
const { ds4ProjectedResidentBytes, ds4ResidentBytesForMode, ds4ResidentLine, shouldUseDs4SsdStreaming, } = await import('../ds4/residency.js');
|
|
1080
|
+
const ds4Line = ds4ResidentLine({
|
|
1081
|
+
residentBytes: ds4Source?.residentBytes,
|
|
1082
|
+
kvBytesPerToken: ds4Source?.kvBytesPerToken,
|
|
1083
|
+
residentCtxTokens: ds4Source?.residentCtxTokens,
|
|
1084
|
+
});
|
|
1085
|
+
const visionResidentBytes = await this.resolveDs4VisionResidentBytes(config, modelId, installed, ds4Source);
|
|
1086
|
+
const ssdStreaming = shouldUseDs4SsdStreaming({
|
|
1087
|
+
configured: config.ds4SsdStreaming,
|
|
1088
|
+
...(ds4Source?.ssdStreamingSupported !== undefined
|
|
1089
|
+
? { ssdStreamingSupported: ds4Source.ssdStreamingSupported }
|
|
1090
|
+
: {}),
|
|
1091
|
+
modelSizeBytes: ds4Source?.residentWeightBytes ??
|
|
1092
|
+
ds4Source?.approxSizeBytes ??
|
|
1093
|
+
installed?.approxSizeBytes,
|
|
1094
|
+
...(visionResidentBytes > 0 ? { companionBytes: visionResidentBytes } : {}),
|
|
1095
|
+
});
|
|
1096
|
+
const plannedResidentBytes = ds4Line
|
|
1097
|
+
? ds4ResidentBytesForMode(ds4ProjectedResidentBytes(ds4Line, effective), ssdStreaming, ds4Source?.ssdStreamingSupported) + visionResidentBytes
|
|
1098
|
+
: await this.resolveResidentBytes('ds4', modelId);
|
|
1099
|
+
return {
|
|
1100
|
+
contextWindow: useResidentOr(effective, Math.min(effective, ds4Floor)),
|
|
1101
|
+
plannedResidentBytes,
|
|
1102
|
+
...(ds4Line
|
|
1103
|
+
? {
|
|
1104
|
+
weightsResidentBytes: ds4ResidentBytesForMode(ds4Line.contextFreeBytes, ssdStreaming, ds4Source?.ssdStreamingSupported) + visionResidentBytes,
|
|
1105
|
+
kvFixedBytesPerSlot: 0,
|
|
1106
|
+
kvBytesPerTokenPerSlot: ds4Line.kvBytesPerToken,
|
|
1107
|
+
}
|
|
1108
|
+
: {}),
|
|
1109
|
+
...(nativeWindow ? { nativeContextWindow: nativeWindow } : {}),
|
|
1110
|
+
...(ds4Override !== undefined ? { overrideContextTokens: ds4Override } : {}),
|
|
1111
|
+
...(ds4AutoContextWindow !== undefined ? { autoContextWindow: ds4AutoContextWindow } : {}),
|
|
1112
|
+
...(ceilingTokens !== undefined && Number.isFinite(ceilingTokens)
|
|
1113
|
+
? { contextCeilingTokens: ceilingTokens }
|
|
1114
|
+
: {}),
|
|
1115
|
+
};
|
|
1116
|
+
}
|
|
1117
|
+
const installed = await this.llamaCppModels?.resolveModel(modelId);
|
|
1118
|
+
if (!installed)
|
|
1119
|
+
throw new ModelNotInstalledError(name, modelId);
|
|
1120
|
+
// Charge the projector against memory only when the launch will actually
|
|
1121
|
+
// load it. Every estimate below used to pass `installed.mmprojSizeBytes`
|
|
1122
|
+
// unconditionally, which was harmless while the file only existed for
|
|
1123
|
+
// models that had opted in — but the projector now ships with the model,
|
|
1124
|
+
// so an unconditional charge would quietly tax every multimodal model
|
|
1125
|
+
// (~900MB on a 27B) including the ones deliberately running text-only.
|
|
1126
|
+
const visionBudgetBytes = mmprojBudgetBytes(installed.mmprojSizeBytes, !!installed.mmprojPath && nativeVisionEnabledFor(config.nativeVision, modelId));
|
|
1127
|
+
const envNumCtx = (() => {
|
|
1128
|
+
const raw = process.env.GEZEL_LLAMA_NUM_CTX;
|
|
1129
|
+
if (!raw)
|
|
1130
|
+
return undefined;
|
|
1131
|
+
const parsed = Number.parseInt(raw, 10);
|
|
1132
|
+
return Number.isFinite(parsed) && parsed > 0 ? parsed : undefined;
|
|
1133
|
+
})();
|
|
1134
|
+
const manifestEngineConfig = await resolveCatalogLlamaCppEngineConfig(this.catalog, modelId);
|
|
1135
|
+
const perModelCtxOverride = config.modelContextOverrides?.[`llama-cpp:${modelId}`];
|
|
1136
|
+
const explicitContextWindow = envNumCtx ?? perModelCtxOverride ?? config.llamaCppNumCtx;
|
|
1137
|
+
// A per-model override below the host floor is deliberate user intent —
|
|
1138
|
+
// lower the admission floor to the override instead of silently raising
|
|
1139
|
+
// the request back to 64K. Env / machine-wide values keep their
|
|
1140
|
+
// historical floor semantics. Mirrors buildLlamaCppProvider.
|
|
1141
|
+
const overrideActive = perModelCtxOverride !== undefined && explicitContextWindow === perModelCtxOverride;
|
|
1142
|
+
const minViableTokens = overrideActive
|
|
1143
|
+
? Math.min(contextFloor, perModelCtxOverride)
|
|
1144
|
+
: contextFloor;
|
|
1145
|
+
const contextRequirement = resolveLlamaCppContextRequirement({
|
|
1146
|
+
modelContextWindow: installed.contextWindow,
|
|
1147
|
+
minViableContextTokens: minViableTokens,
|
|
1148
|
+
...(explicitContextWindow !== undefined ? { explicitContextWindow } : {}),
|
|
1149
|
+
...(manifestEngineConfig?.contextSize !== undefined
|
|
1150
|
+
? {
|
|
1151
|
+
adaptiveContextWindow: manifestEngineConfig.contextSize,
|
|
1152
|
+
manifestContextSize: manifestEngineConfig.contextSize,
|
|
1153
|
+
}
|
|
1154
|
+
: {}),
|
|
1155
|
+
contextSizing: config.llamaCppContextSizing ?? 'adaptive',
|
|
1156
|
+
});
|
|
1157
|
+
const effectiveNumCtx = contextRequirement.requestedPerTurnCtxTokens;
|
|
1158
|
+
// Resident/env short-circuits still want a footprint estimate, which
|
|
1159
|
+
// needs the header read below — the return moves after it. An active
|
|
1160
|
+
// per-model override deliberately does NOT short-circuit on a resident
|
|
1161
|
+
// engine: the full plan must run so a stale resident window surfaces as
|
|
1162
|
+
// restart-required instead of masquerading as the applied setting.
|
|
1163
|
+
const shortCircuit = (residentContextWindow !== undefined && !overrideActive) || envNumCtx !== undefined;
|
|
1164
|
+
const { defaultLocalEngineSlots, estimatePerSlotKvBytes, kvQuantScale, llamaCppSlotCeiling, planAdaptiveContextGrowth, planCtxTokensForMemory, plannedLocalEngineSlots, } = await import('./capacity-broker.js');
|
|
1165
|
+
const capacity = await this.previewCapacityInputs('llama-cpp', modelId, capacityOpts);
|
|
1166
|
+
const { budgetBytes: admissionBudgetBytes, fastBudgetBytes, committedOtherBytes } = capacity;
|
|
1167
|
+
const configuredSlots = config.providerConcurrency?.['llama-cpp'];
|
|
1168
|
+
const kvCacheType = resolveLlamaCppKvCacheType({
|
|
1169
|
+
architecture: installed.architecture,
|
|
1170
|
+
modelId,
|
|
1171
|
+
override: config.llamaCppKvCacheType,
|
|
1172
|
+
});
|
|
1173
|
+
// Header-exact per-slot KV for the slot ceiling (M2); the
|
|
1174
|
+
// weights-scaled heuristic only when the GGUF is unreadable. Tensor sizes
|
|
1175
|
+
// also expose Qwen/Gemma's v0.4 lazy embedding range, which must not be
|
|
1176
|
+
// advertised as resident RAM/VRAM in the Settings preview.
|
|
1177
|
+
let summary = null;
|
|
1178
|
+
try {
|
|
1179
|
+
summary = await readGgufSummaryAsync(installed.weightsPath, { includeTensorSizes: true });
|
|
1180
|
+
}
|
|
1181
|
+
catch {
|
|
1182
|
+
summary = null;
|
|
1183
|
+
}
|
|
1184
|
+
const lazyTensorBytes = summary
|
|
1185
|
+
? effectiveLazyTensorBytes(summary, config.llamaCppLazyMode ?? manifestEngineConfig?.lazyMode ?? 'auto')
|
|
1186
|
+
: 0;
|
|
1187
|
+
const residentWeightFileBytes = Math.max(0, installed.approxSizeBytes - lazyTensorBytes);
|
|
1188
|
+
const residentWeightsBytes = estimateLlamaCppResidentBytes(residentWeightFileBytes, {
|
|
1189
|
+
mmprojBytes: visionBudgetBytes,
|
|
1190
|
+
});
|
|
1191
|
+
const exactPerSlotKvF16 = summary
|
|
1192
|
+
? estimateExactPerSlotKvBytesF16({
|
|
1193
|
+
blockCount: summary.blockCount,
|
|
1194
|
+
embeddingLength: summary.embeddingLength,
|
|
1195
|
+
headCount: summary.headCount,
|
|
1196
|
+
headCountKv: summary.headCountKv,
|
|
1197
|
+
headCountKvPerLayer: summary.headCountKvPerLayer,
|
|
1198
|
+
slidingWindow: summary.slidingWindow,
|
|
1199
|
+
slidingWindowPattern: summary.slidingWindowPattern,
|
|
1200
|
+
sharedKvLayers: summary.sharedKvLayers,
|
|
1201
|
+
loopCount: summary.loopCount,
|
|
1202
|
+
keyLength: summary.keyLength,
|
|
1203
|
+
valueLength: summary.valueLength,
|
|
1204
|
+
keyLengthSwa: summary.keyLengthSwa,
|
|
1205
|
+
valueLengthSwa: summary.valueLengthSwa,
|
|
1206
|
+
fullAttentionInterval: summary.fullAttentionInterval,
|
|
1207
|
+
ssmInnerSize: summary.ssmInnerSize,
|
|
1208
|
+
ssmStateSize: summary.ssmStateSize,
|
|
1209
|
+
ssmConvKernel: summary.ssmConvKernel,
|
|
1210
|
+
}, effectiveNumCtx)
|
|
1211
|
+
: undefined;
|
|
1212
|
+
// Weights + KV at a given window/slot count. Two figures, because they
|
|
1213
|
+
// answer different questions: `single` is what one chat costs (the
|
|
1214
|
+
// models-list headline), `reserved` is what the broker holds for the
|
|
1215
|
+
// whole slot fleet (the launch path's reservation math).
|
|
1216
|
+
const plannedFor = (ctx, slotCount, kv) => {
|
|
1217
|
+
if (!summary)
|
|
1218
|
+
return undefined;
|
|
1219
|
+
const perSlotF16 = estimateExactPerSlotKvBytesF16({
|
|
1220
|
+
blockCount: summary.blockCount,
|
|
1221
|
+
embeddingLength: summary.embeddingLength,
|
|
1222
|
+
headCount: summary.headCount,
|
|
1223
|
+
headCountKv: summary.headCountKv,
|
|
1224
|
+
headCountKvPerLayer: summary.headCountKvPerLayer,
|
|
1225
|
+
slidingWindow: summary.slidingWindow,
|
|
1226
|
+
slidingWindowPattern: summary.slidingWindowPattern,
|
|
1227
|
+
sharedKvLayers: summary.sharedKvLayers,
|
|
1228
|
+
loopCount: summary.loopCount,
|
|
1229
|
+
keyLength: summary.keyLength,
|
|
1230
|
+
valueLength: summary.valueLength,
|
|
1231
|
+
keyLengthSwa: summary.keyLengthSwa,
|
|
1232
|
+
valueLengthSwa: summary.valueLengthSwa,
|
|
1233
|
+
fullAttentionInterval: summary.fullAttentionInterval,
|
|
1234
|
+
ssmInnerSize: summary.ssmInnerSize,
|
|
1235
|
+
ssmStateSize: summary.ssmStateSize,
|
|
1236
|
+
ssmConvKernel: summary.ssmConvKernel,
|
|
1237
|
+
}, ctx);
|
|
1238
|
+
if (perSlotF16 === undefined)
|
|
1239
|
+
return undefined;
|
|
1240
|
+
const perSlotBytes = perSlotF16 * kvQuantScale(kv);
|
|
1241
|
+
return {
|
|
1242
|
+
single: Math.round(residentWeightsBytes + perSlotBytes),
|
|
1243
|
+
reserved: Math.round(residentWeightsBytes + perSlotBytes * slotCount),
|
|
1244
|
+
slots: slotCount,
|
|
1245
|
+
};
|
|
1246
|
+
};
|
|
1247
|
+
// Post-quant single-slot KV linearization for the UI's live slider
|
|
1248
|
+
// estimate. Two-point sampling stays exact for full-attention models
|
|
1249
|
+
// and matches the windowed/hybrid piecewise slope everywhere above the
|
|
1250
|
+
// sliding window — the slider's 32K floor clears every real window.
|
|
1251
|
+
const kvLinearizationFor = (kv) => {
|
|
1252
|
+
if (!summary)
|
|
1253
|
+
return undefined;
|
|
1254
|
+
const geometry = {
|
|
1255
|
+
blockCount: summary.blockCount,
|
|
1256
|
+
embeddingLength: summary.embeddingLength,
|
|
1257
|
+
headCount: summary.headCount,
|
|
1258
|
+
headCountKv: summary.headCountKv,
|
|
1259
|
+
headCountKvPerLayer: summary.headCountKvPerLayer,
|
|
1260
|
+
slidingWindow: summary.slidingWindow,
|
|
1261
|
+
slidingWindowPattern: summary.slidingWindowPattern,
|
|
1262
|
+
sharedKvLayers: summary.sharedKvLayers,
|
|
1263
|
+
loopCount: summary.loopCount,
|
|
1264
|
+
keyLength: summary.keyLength,
|
|
1265
|
+
valueLength: summary.valueLength,
|
|
1266
|
+
keyLengthSwa: summary.keyLengthSwa,
|
|
1267
|
+
valueLengthSwa: summary.valueLengthSwa,
|
|
1268
|
+
fullAttentionInterval: summary.fullAttentionInterval,
|
|
1269
|
+
ssmInnerSize: summary.ssmInnerSize,
|
|
1270
|
+
ssmStateSize: summary.ssmStateSize,
|
|
1271
|
+
ssmConvKernel: summary.ssmConvKernel,
|
|
1272
|
+
};
|
|
1273
|
+
const a = estimateExactPerSlotKvBytesF16(geometry, 8_192);
|
|
1274
|
+
const b = estimateExactPerSlotKvBytesF16(geometry, 65_536);
|
|
1275
|
+
if (a === undefined || b === undefined)
|
|
1276
|
+
return undefined;
|
|
1277
|
+
const scale = kvQuantScale(kv);
|
|
1278
|
+
const bytesPerToken = ((b - a) / (65_536 - 8_192)) * scale;
|
|
1279
|
+
return { bytesPerToken, fixedBytes: Math.max(0, a * scale - bytesPerToken * 8_192) };
|
|
1280
|
+
};
|
|
1281
|
+
const ceilingAt = (ctx, kv) => llamaCppSlotCeiling({
|
|
1282
|
+
budgetBytes: fastBudgetBytes,
|
|
1283
|
+
sizingBudgetBytes: capacity.concurrencySizingBytes,
|
|
1284
|
+
weightsBytes: residentWeightFileBytes,
|
|
1285
|
+
perTurnCtxTokens: ctx,
|
|
1286
|
+
kvCacheType: kv,
|
|
1287
|
+
committedOtherBytes,
|
|
1288
|
+
...(exactPerSlotKvF16 !== undefined ? { exactPerSlotKvBytesF16: exactPerSlotKvF16 } : {}),
|
|
1289
|
+
});
|
|
1290
|
+
if (shortCircuit) {
|
|
1291
|
+
const contextWindow = useResidentOr(effectiveNumCtx, contextRequirement.minimumPerTurnCtxTokens);
|
|
1292
|
+
// Memory-aware slot count, same as the main path below. The raw tier
|
|
1293
|
+
// default is what a launch would *like*; on a constrained host the
|
|
1294
|
+
// ceiling is what it can actually have, and quoting the former made
|
|
1295
|
+
// this branch advertise reservations the broker would never admit.
|
|
1296
|
+
const planned = plannedFor(contextWindow, plannedLocalEngineSlots({
|
|
1297
|
+
configuredSlots,
|
|
1298
|
+
ceiling: ceilingAt(contextWindow, kvCacheType),
|
|
1299
|
+
tierDefault: defaultLocalEngineSlots(fastBudgetBytes),
|
|
1300
|
+
}), kvCacheType);
|
|
1301
|
+
const lin = kvLinearizationFor(kvCacheType);
|
|
1302
|
+
return {
|
|
1303
|
+
contextWindow,
|
|
1304
|
+
...(planned !== undefined
|
|
1305
|
+
? {
|
|
1306
|
+
plannedResidentBytes: planned.single,
|
|
1307
|
+
reservedResidentBytes: planned.reserved,
|
|
1308
|
+
plannedSlots: planned.slots,
|
|
1309
|
+
weightsResidentBytes: residentWeightsBytes,
|
|
1310
|
+
}
|
|
1311
|
+
: {}),
|
|
1312
|
+
...(installed.contextWindow ? { nativeContextWindow: installed.contextWindow } : {}),
|
|
1313
|
+
...(perModelCtxOverride !== undefined
|
|
1314
|
+
? { overrideContextTokens: perModelCtxOverride }
|
|
1315
|
+
: {}),
|
|
1316
|
+
...(lin !== undefined
|
|
1317
|
+
? { kvBytesPerTokenPerSlot: lin.bytesPerToken, kvFixedBytesPerSlot: lin.fixedBytes }
|
|
1318
|
+
: {}),
|
|
1319
|
+
};
|
|
1320
|
+
}
|
|
1321
|
+
// One planning pass: policy resolution → KV/slot plan → admission
|
|
1322
|
+
// ladder → windowed re-plan → adaptive growth, mirroring
|
|
1323
|
+
// buildLlamaCppProvider. Runs once for the live preview and — while a
|
|
1324
|
+
// per-model override is active — a second time with the override
|
|
1325
|
+
// ignored, so the slider can mark where "Automatic" lands right now.
|
|
1326
|
+
const llamaPlanPass = (explicitArg, minViableArg) => {
|
|
1327
|
+
const requirement = resolveLlamaCppContextRequirement({
|
|
1328
|
+
modelContextWindow: installed.contextWindow,
|
|
1329
|
+
minViableContextTokens: minViableArg,
|
|
1330
|
+
...(explicitArg !== undefined ? { explicitContextWindow: explicitArg } : {}),
|
|
1331
|
+
...(manifestEngineConfig?.contextSize !== undefined
|
|
1332
|
+
? {
|
|
1333
|
+
adaptiveContextWindow: manifestEngineConfig.contextSize,
|
|
1334
|
+
manifestContextSize: manifestEngineConfig.contextSize,
|
|
1335
|
+
}
|
|
1336
|
+
: {}),
|
|
1337
|
+
contextSizing: config.llamaCppContextSizing ?? 'adaptive',
|
|
1338
|
+
});
|
|
1339
|
+
let grantedCtx = requirement.requestedPerTurnCtxTokens;
|
|
1340
|
+
let kv = resolveLlamaCppKvCacheType({
|
|
1341
|
+
architecture: installed.architecture,
|
|
1342
|
+
modelId,
|
|
1343
|
+
override: config.llamaCppKvCacheType,
|
|
1344
|
+
});
|
|
1345
|
+
// Per-pass exact KV at this pass's requested window — the auto pass
|
|
1346
|
+
// may request a different window than the primary one, and a slot
|
|
1347
|
+
// ceiling fed with the other pass's bytes skews the marker.
|
|
1348
|
+
const exactAtRequested = summary
|
|
1349
|
+
? estimateExactPerSlotKvBytesF16({
|
|
1350
|
+
blockCount: summary.blockCount,
|
|
1351
|
+
embeddingLength: summary.embeddingLength,
|
|
1352
|
+
headCount: summary.headCount,
|
|
1353
|
+
headCountKv: summary.headCountKv,
|
|
1354
|
+
headCountKvPerLayer: summary.headCountKvPerLayer,
|
|
1355
|
+
slidingWindow: summary.slidingWindow,
|
|
1356
|
+
slidingWindowPattern: summary.slidingWindowPattern,
|
|
1357
|
+
sharedKvLayers: summary.sharedKvLayers,
|
|
1358
|
+
loopCount: summary.loopCount,
|
|
1359
|
+
keyLength: summary.keyLength,
|
|
1360
|
+
valueLength: summary.valueLength,
|
|
1361
|
+
keyLengthSwa: summary.keyLengthSwa,
|
|
1362
|
+
valueLengthSwa: summary.valueLengthSwa,
|
|
1363
|
+
fullAttentionInterval: summary.fullAttentionInterval,
|
|
1364
|
+
ssmInnerSize: summary.ssmInnerSize,
|
|
1365
|
+
ssmStateSize: summary.ssmStateSize,
|
|
1366
|
+
ssmConvKernel: summary.ssmConvKernel,
|
|
1367
|
+
}, grantedCtx)
|
|
1368
|
+
: undefined;
|
|
1369
|
+
const passPlanCtx = grantedCtx;
|
|
1370
|
+
const passCeiling = (kvType, ctxTokens) => llamaCppSlotCeiling({
|
|
1371
|
+
budgetBytes: fastBudgetBytes,
|
|
1372
|
+
sizingBudgetBytes: capacity.concurrencySizingBytes,
|
|
1373
|
+
weightsBytes: residentWeightFileBytes,
|
|
1374
|
+
perTurnCtxTokens: ctxTokens,
|
|
1375
|
+
kvCacheType: kvType,
|
|
1376
|
+
committedOtherBytes,
|
|
1377
|
+
...(exactAtRequested !== undefined
|
|
1378
|
+
? { exactPerSlotKvBytesF16: (exactAtRequested * ctxTokens) / passPlanCtx }
|
|
1379
|
+
: {}),
|
|
1380
|
+
});
|
|
1381
|
+
// One pricing for a candidate KV dtype, shared by the plan's fit gate
|
|
1382
|
+
// and by the admission below — a second copy is how a preview starts
|
|
1383
|
+
// promising a window the launch then denies.
|
|
1384
|
+
const referenceCtx = 4096;
|
|
1385
|
+
const exactKvAtReferenceFor = (kvType) => summary
|
|
1386
|
+
? estimateKvReserveBytes({
|
|
1387
|
+
blockCount: summary.blockCount,
|
|
1388
|
+
embeddingLength: summary.embeddingLength,
|
|
1389
|
+
headCount: summary.headCount,
|
|
1390
|
+
headCountKv: summary.headCountKv,
|
|
1391
|
+
headCountKvPerLayer: summary.headCountKvPerLayer,
|
|
1392
|
+
slidingWindowPattern: summary.slidingWindowPattern,
|
|
1393
|
+
sharedKvLayers: summary.sharedKvLayers,
|
|
1394
|
+
loopCount: summary.loopCount,
|
|
1395
|
+
keyLength: summary.keyLength,
|
|
1396
|
+
valueLength: summary.valueLength,
|
|
1397
|
+
keyLengthSwa: summary.keyLengthSwa,
|
|
1398
|
+
valueLengthSwa: summary.valueLengthSwa,
|
|
1399
|
+
fullAttentionInterval: summary.fullAttentionInterval,
|
|
1400
|
+
ssmInnerSize: summary.ssmInnerSize,
|
|
1401
|
+
ssmStateSize: summary.ssmStateSize,
|
|
1402
|
+
ssmConvKernel: summary.ssmConvKernel,
|
|
1403
|
+
ctxTokens: referenceCtx,
|
|
1404
|
+
kvCacheType: kvType,
|
|
1405
|
+
})
|
|
1406
|
+
: undefined;
|
|
1407
|
+
const kvBytesPerTokenFor = (kvType) => {
|
|
1408
|
+
const exact = exactKvAtReferenceFor(kvType);
|
|
1409
|
+
return exact !== undefined
|
|
1410
|
+
? exact / referenceCtx
|
|
1411
|
+
: estimatePerSlotKvBytes({
|
|
1412
|
+
perTurnCtxTokens: referenceCtx,
|
|
1413
|
+
weightsBytes: residentWeightFileBytes,
|
|
1414
|
+
kvCacheType: kvType,
|
|
1415
|
+
}) / referenceCtx;
|
|
1416
|
+
};
|
|
1417
|
+
const planFitsAt = (kvType, ctxTokens, slotCount) => {
|
|
1418
|
+
// `minimumPerTurnCtxTokens: ctxTokens` makes this ask for the WHOLE
|
|
1419
|
+
// window — a plan admission would only accept by clamping does not
|
|
1420
|
+
// count as a fit, which is exactly the case q8_0 has to rescue.
|
|
1421
|
+
const probe = planCtxTokensForMemory({
|
|
1422
|
+
requestedPerTurnCtxTokens: ctxTokens,
|
|
1423
|
+
slots: slotCount,
|
|
1424
|
+
minimumPerTurnCtxTokens: ctxTokens,
|
|
1425
|
+
kvBytesPerToken: kvBytesPerTokenFor(kvType),
|
|
1426
|
+
weightsResidentBytes: residentWeightsBytes,
|
|
1427
|
+
budgetBytes: admissionBudgetBytes,
|
|
1428
|
+
committedOtherBytes,
|
|
1429
|
+
...(capacity.freeSystemRamBytes !== undefined
|
|
1430
|
+
? { freeSystemRamBytes: capacity.freeSystemRamBytes }
|
|
1431
|
+
: {}),
|
|
1432
|
+
vramBytes: capacity.vramBytes,
|
|
1433
|
+
});
|
|
1434
|
+
return probe.minimumSatisfied && probe.slots >= slotCount;
|
|
1435
|
+
};
|
|
1436
|
+
const kvPlan = planLlamaCppKv({
|
|
1437
|
+
architecture: installed.architecture,
|
|
1438
|
+
modelId,
|
|
1439
|
+
override: config.llamaCppKvCacheType,
|
|
1440
|
+
slotsConfigured: configuredSlots !== undefined,
|
|
1441
|
+
...(configuredSlots !== undefined ? { configuredSlots } : {}),
|
|
1442
|
+
requestedCtxTokens: grantedCtx,
|
|
1443
|
+
minimumCtxTokens: requirement.minimumPerTurnCtxTokens,
|
|
1444
|
+
ctxConfigured: explicitArg !== undefined || (config.llamaCppContextSizing ?? 'adaptive') === 'model-max',
|
|
1445
|
+
ceilingFor: passCeiling,
|
|
1446
|
+
fitsAt: planFitsAt,
|
|
1447
|
+
maxSlots: defaultLocalEngineSlots(fastBudgetBytes),
|
|
1448
|
+
});
|
|
1449
|
+
kv = kvPlan.kvCacheType;
|
|
1450
|
+
// Mirror the launch: the f16-by-context-cap trade shrinks the granted
|
|
1451
|
+
// window here too, so the settings preview shows what will really run.
|
|
1452
|
+
if (kvPlan.ctxCapTokens !== undefined && kvPlan.ctxCapTokens < grantedCtx) {
|
|
1453
|
+
grantedCtx = kvPlan.ctxCapTokens;
|
|
1454
|
+
}
|
|
1455
|
+
let slots = plannedLocalEngineSlots({
|
|
1456
|
+
configuredSlots,
|
|
1457
|
+
ceiling: passCeiling(kv, grantedCtx),
|
|
1458
|
+
tierDefault: defaultLocalEngineSlots(fastBudgetBytes),
|
|
1459
|
+
});
|
|
1460
|
+
if ((config.llamaCppSpecType ?? manifestEngineConfig?.spec?.type) === 'draft-mtp')
|
|
1461
|
+
slots = 1;
|
|
1462
|
+
try {
|
|
1463
|
+
if (!summary)
|
|
1464
|
+
throw new Error('GGUF header unreadable');
|
|
1465
|
+
const exactKvAtReference = exactKvAtReferenceFor(kv);
|
|
1466
|
+
const kvBytesPerToken = kvBytesPerTokenFor(kv);
|
|
1467
|
+
// The linearization the accepted plan priced with, so the growth
|
|
1468
|
+
// pass cannot disagree with admission about the same launch.
|
|
1469
|
+
let ladderKvLinearization = { bytesPerToken: kvBytesPerToken, fixedPerSlotBytes: 0 };
|
|
1470
|
+
let admission = planCtxTokensForMemory({
|
|
1471
|
+
requestedPerTurnCtxTokens: grantedCtx,
|
|
1472
|
+
slots,
|
|
1473
|
+
minimumPerTurnCtxTokens: requirement.minimumPerTurnCtxTokens,
|
|
1474
|
+
kvBytesPerToken,
|
|
1475
|
+
weightsResidentBytes: residentWeightsBytes,
|
|
1476
|
+
budgetBytes: admissionBudgetBytes,
|
|
1477
|
+
committedOtherBytes,
|
|
1478
|
+
...(capacity.freeSystemRamBytes !== undefined
|
|
1479
|
+
? { freeSystemRamBytes: capacity.freeSystemRamBytes }
|
|
1480
|
+
: {}),
|
|
1481
|
+
vramBytes: capacity.vramBytes,
|
|
1482
|
+
});
|
|
1483
|
+
// Mirror the launch path's windowed-cache admission (see
|
|
1484
|
+
// buildLlamaCppProvider): when the launch will decline the Gemma
|
|
1485
|
+
// `--swa-full` auto-default (or the windowed cache is pinned), the
|
|
1486
|
+
// full-attention plan above overstates the real allocation — re-plan
|
|
1487
|
+
// with the windowed linearization so the previewed window matches
|
|
1488
|
+
// what the engine will actually grant.
|
|
1489
|
+
// Strict model-max deliberately does NOT gate this: for SWA models
|
|
1490
|
+
// the windowed cache is the only layout whose native-window KV can
|
|
1491
|
+
// fit real machines, and the strict minimum rides inside
|
|
1492
|
+
// `requirement.minimumPerTurnCtxTokens`, so the windowed
|
|
1493
|
+
// re-plan sheds slots or denies but never shortens the window.
|
|
1494
|
+
const explicitSwaFull = config.llamaCppSwaFull ?? manifestEngineConfig?.swaFull;
|
|
1495
|
+
const windowedCacheWillRun = (!admission.minimumSatisfied || admission.clamped || admission.slots < slots) &&
|
|
1496
|
+
(explicitSwaFull === false ||
|
|
1497
|
+
(explicitSwaFull === undefined &&
|
|
1498
|
+
isGemmaModel({ architecture: installed.architecture, modelId })));
|
|
1499
|
+
if (windowedCacheWillRun) {
|
|
1500
|
+
const windowed = estimateWindowedKvLinearization({
|
|
1501
|
+
blockCount: summary.blockCount,
|
|
1502
|
+
embeddingLength: summary.embeddingLength,
|
|
1503
|
+
headCount: summary.headCount,
|
|
1504
|
+
headCountKv: summary.headCountKv,
|
|
1505
|
+
headCountKvPerLayer: summary.headCountKvPerLayer,
|
|
1506
|
+
slidingWindow: summary.slidingWindow,
|
|
1507
|
+
slidingWindowPattern: summary.slidingWindowPattern,
|
|
1508
|
+
sharedKvLayers: summary.sharedKvLayers,
|
|
1509
|
+
loopCount: summary.loopCount,
|
|
1510
|
+
keyLength: summary.keyLength,
|
|
1511
|
+
valueLength: summary.valueLength,
|
|
1512
|
+
keyLengthSwa: summary.keyLengthSwa,
|
|
1513
|
+
valueLengthSwa: summary.valueLengthSwa,
|
|
1514
|
+
fullAttentionInterval: summary.fullAttentionInterval,
|
|
1515
|
+
ssmInnerSize: summary.ssmInnerSize,
|
|
1516
|
+
ssmStateSize: summary.ssmStateSize,
|
|
1517
|
+
ssmConvKernel: summary.ssmConvKernel,
|
|
1518
|
+
kvCacheType: kv,
|
|
1519
|
+
});
|
|
1520
|
+
if (windowed) {
|
|
1521
|
+
admission = planCtxTokensForMemory({
|
|
1522
|
+
requestedPerTurnCtxTokens: grantedCtx,
|
|
1523
|
+
slots,
|
|
1524
|
+
minimumPerTurnCtxTokens: requirement.minimumPerTurnCtxTokens,
|
|
1525
|
+
kvBytesPerToken: windowed.bytesPerToken,
|
|
1526
|
+
weightsResidentBytes: residentWeightsBytes + windowed.fixedBytes * slots,
|
|
1527
|
+
budgetBytes: admissionBudgetBytes,
|
|
1528
|
+
committedOtherBytes,
|
|
1529
|
+
...(capacity.freeSystemRamBytes !== undefined
|
|
1530
|
+
? { freeSystemRamBytes: capacity.freeSystemRamBytes }
|
|
1531
|
+
: {}),
|
|
1532
|
+
vramBytes: capacity.vramBytes,
|
|
1533
|
+
});
|
|
1534
|
+
ladderKvLinearization = {
|
|
1535
|
+
bytesPerToken: windowed.bytesPerToken,
|
|
1536
|
+
fixedPerSlotBytes: windowed.fixedBytes,
|
|
1537
|
+
};
|
|
1538
|
+
}
|
|
1539
|
+
else if ((summary.slidingWindow ?? 0) > 0 || explicitSwaFull === undefined) {
|
|
1540
|
+
// SWA model without a readable layout: the launch path leaves
|
|
1541
|
+
// such a launch untouched — preview the requested window.
|
|
1542
|
+
return { grantedCtx, slots, kvCacheType: kv, plannedFieldsOk: false };
|
|
1543
|
+
}
|
|
1544
|
+
}
|
|
1545
|
+
if (!admission.minimumSatisfied) {
|
|
1546
|
+
throw new CapacityDeniedError(NOT_ENOUGH_MEMORY_MESSAGE);
|
|
1547
|
+
}
|
|
1548
|
+
slots = admission.slots;
|
|
1549
|
+
grantedCtx = admission.perTurnCtxTokens;
|
|
1550
|
+
// ── Adaptive context growth ── mirror of buildLlamaCppProvider:
|
|
1551
|
+
// slots and the base grant are settled; spend leftover FAST memory
|
|
1552
|
+
// on a longer window up to the resolver's target. Exact GGUF
|
|
1553
|
+
// geometry only.
|
|
1554
|
+
if (requirement.growthTargetTokens !== undefined &&
|
|
1555
|
+
ladderKvLinearization !== null &&
|
|
1556
|
+
exactKvAtReference !== undefined) {
|
|
1557
|
+
const growth = planAdaptiveContextGrowth({
|
|
1558
|
+
basePerTurnCtxTokens: grantedCtx,
|
|
1559
|
+
targetPerTurnCtxTokens: requirement.growthTargetTokens,
|
|
1560
|
+
slots,
|
|
1561
|
+
kvBytesPerToken: ladderKvLinearization.bytesPerToken,
|
|
1562
|
+
kvFixedPerSlotBytes: ladderKvLinearization.fixedPerSlotBytes,
|
|
1563
|
+
weightsResidentBytes: residentWeightsBytes,
|
|
1564
|
+
fastBudgetBytes,
|
|
1565
|
+
committedOtherBytes,
|
|
1566
|
+
budgetKind: capacity.budgetKind,
|
|
1567
|
+
vramBytes: capacity.vramBytes,
|
|
1568
|
+
...(capacity.freeSystemRamBytes !== undefined
|
|
1569
|
+
? { freeSystemRamBytes: capacity.freeSystemRamBytes }
|
|
1570
|
+
: {}),
|
|
1571
|
+
isMoE: (summary.expertCount ?? 0) > 1,
|
|
1572
|
+
// A user-chosen lane count is not growth's to spend.
|
|
1573
|
+
allowSlotTrade: configuredSlots === undefined,
|
|
1574
|
+
});
|
|
1575
|
+
if (growth.grown) {
|
|
1576
|
+
grantedCtx = growth.perTurnCtxTokens;
|
|
1577
|
+
slots = growth.slots;
|
|
1578
|
+
}
|
|
1579
|
+
}
|
|
1580
|
+
}
|
|
1581
|
+
catch (error) {
|
|
1582
|
+
if (error instanceof CapacityDeniedError)
|
|
1583
|
+
throw error;
|
|
1584
|
+
log.warn(`[llama-cpp] could not inspect ${modelId} while previewing admission: ${error instanceof Error ? error.message : String(error)}`);
|
|
1585
|
+
}
|
|
1586
|
+
return { grantedCtx, slots, kvCacheType: kv, plannedFieldsOk: true };
|
|
1587
|
+
};
|
|
1588
|
+
const plan = llamaPlanPass(explicitContextWindow, minViableTokens);
|
|
1589
|
+
let autoContextWindow;
|
|
1590
|
+
if (overrideActive) {
|
|
1591
|
+
try {
|
|
1592
|
+
autoContextWindow = llamaPlanPass(config.llamaCppNumCtx, contextFloor).grantedCtx;
|
|
1593
|
+
}
|
|
1594
|
+
catch {
|
|
1595
|
+
// Automatic sizing may not fit where a smaller override does — no marker.
|
|
1596
|
+
}
|
|
1597
|
+
}
|
|
1598
|
+
// A resident engine holding a different window than a freshly-set
|
|
1599
|
+
// override keeps its launch window until restart; surface that as
|
|
1600
|
+
// restart-required instead of quietly showing the stale window as if
|
|
1601
|
+
// the setting had applied.
|
|
1602
|
+
if (overrideActive &&
|
|
1603
|
+
residentContextWindow !== undefined &&
|
|
1604
|
+
residentContextWindow !== plan.grantedCtx) {
|
|
1605
|
+
throw new CapacityDeniedError(`${modelId} is running with ${residentContextWindow.toLocaleString('en-US')} context tokens per turn, but its custom context setting now resolves to ${plan.grantedCtx.toLocaleString('en-US')}. Restart the local engine to apply it.`, { reason: 'resident-below-minimum' });
|
|
1606
|
+
}
|
|
1607
|
+
const planned = plan.plannedFieldsOk
|
|
1608
|
+
? plannedFor(plan.grantedCtx, plan.slots, plan.kvCacheType)
|
|
1609
|
+
: undefined;
|
|
1610
|
+
const lin = plan.plannedFieldsOk ? kvLinearizationFor(plan.kvCacheType) : undefined;
|
|
1611
|
+
return {
|
|
1612
|
+
contextWindow: plan.grantedCtx,
|
|
1613
|
+
...(planned !== undefined
|
|
1614
|
+
? {
|
|
1615
|
+
plannedResidentBytes: planned.single,
|
|
1616
|
+
reservedResidentBytes: planned.reserved,
|
|
1617
|
+
plannedSlots: planned.slots,
|
|
1618
|
+
weightsResidentBytes: residentWeightsBytes,
|
|
1619
|
+
}
|
|
1620
|
+
: {}),
|
|
1621
|
+
...(installed.contextWindow ? { nativeContextWindow: installed.contextWindow } : {}),
|
|
1622
|
+
...(perModelCtxOverride !== undefined ? { overrideContextTokens: perModelCtxOverride } : {}),
|
|
1623
|
+
...(autoContextWindow !== undefined ? { autoContextWindow } : {}),
|
|
1624
|
+
...(lin !== undefined
|
|
1625
|
+
? { kvBytesPerTokenPerSlot: lin.bytesPerToken, kvFixedBytesPerSlot: lin.fixedBytes }
|
|
1626
|
+
: {}),
|
|
1627
|
+
};
|
|
1628
|
+
}
|
|
1629
|
+
/**
|
|
1630
|
+
* Cancel a pending provider-queue entry by (provider, id). Resolves
|
|
1631
|
+
* the queue the SAME two ways {@link localEngineQueueSummaries} +
|
|
1632
|
+
* `/api/queues` surface it: the singleton `providers` map first
|
|
1633
|
+
* (cloud providers, seeded test mocks), then the engine pool for
|
|
1634
|
+
* pool-routed local engines whose queue the singleton never sees.
|
|
1635
|
+
* Returns true when an entry was removed, false when the id is
|
|
1636
|
+
* unknown (already running, already cancelled, or no such provider).
|
|
1637
|
+
*/
|
|
1638
|
+
cancelProviderQueueItem(name, id) {
|
|
1639
|
+
if (this.getProviderIfReady(name)?.queue?.cancelPending(id))
|
|
1640
|
+
return true;
|
|
1641
|
+
const router = this.engineRouter ?? this.engineRouterCache;
|
|
1642
|
+
return router ? router.pool.cancelPendingQueueItem(name, id) : false;
|
|
1643
|
+
}
|
|
1644
|
+
/** Reorder a pending provider-queue entry. Same singleton-then-pool
|
|
1645
|
+
* resolution as {@link cancelProviderQueueItem}. */
|
|
1646
|
+
moveProviderQueueItem(name, id, direction) {
|
|
1647
|
+
if (this.getProviderIfReady(name)?.queue?.movePending(id, direction))
|
|
1648
|
+
return true;
|
|
1649
|
+
const router = this.engineRouter ?? this.engineRouterCache;
|
|
1650
|
+
return router ? router.pool.movePendingQueueItem(name, id, direction) : false;
|
|
1651
|
+
}
|
|
1652
|
+
sessionsPerEngineKey() {
|
|
1653
|
+
return new Map();
|
|
1654
|
+
}
|
|
1655
|
+
async bindLocalReplica(router, name, modelId, opts) {
|
|
1656
|
+
// Pre-populate the bytes cache so the router's sync resolver
|
|
1657
|
+
// hits on the first ensure.
|
|
1658
|
+
await this.resolveResidentBytes(name, modelId);
|
|
1659
|
+
// Tally active sessions per engine key for load-balanced bind.
|
|
1660
|
+
const sessionsPerKey = this.sessionsPerEngineKey();
|
|
1661
|
+
return router.bindForSession(name, modelId, {
|
|
1662
|
+
sessionId: opts.sessionId,
|
|
1663
|
+
sessionsPerKey,
|
|
1664
|
+
...(opts.engineDrainWaitMs !== undefined ? { drainWaitMs: opts.engineDrainWaitMs } : {}),
|
|
1665
|
+
...(opts.signal ? { signal: opts.signal } : {}),
|
|
1666
|
+
...(opts.onDrainWait ? { onDrainWait: opts.onDrainWait } : {}),
|
|
1667
|
+
}, opts.priorEngineKey);
|
|
1668
|
+
}
|
|
1669
|
+
async getLocalProviderForModel(name, modelId, opts, fallback) {
|
|
1670
|
+
const seeded = this.providers.get(name);
|
|
1671
|
+
if (seeded)
|
|
1672
|
+
return seeded;
|
|
1673
|
+
const router = await this.getEngineRouter();
|
|
1674
|
+
if (!router)
|
|
1675
|
+
return fallback();
|
|
1676
|
+
const config = await this.store.readConfig();
|
|
1677
|
+
const resolved = modelId ?? config.defaultModel?.[name];
|
|
1678
|
+
if (!resolved)
|
|
1679
|
+
return fallback();
|
|
1680
|
+
const installed = name === 'llama-cpp'
|
|
1681
|
+
? await this.llamaCppModels?.resolveModel(resolved)
|
|
1682
|
+
: name === 'ds4'
|
|
1683
|
+
? // ds4 v1 also resolves weights OUTSIDE the model manager — an
|
|
1684
|
+
// explicit gguf path (GEZEL_DS4_MODEL / config.ds4ModelPath) or
|
|
1685
|
+
// an external server (GEZEL_DS4_SERVER_URL / config.ds4BaseUrl).
|
|
1686
|
+
// `buildDs4Provider` handles those directly, so don't gate the
|
|
1687
|
+
// pool on the store: falling back to the singleton here spawns
|
|
1688
|
+
// a SECOND supervisor for a server that's already running, and
|
|
1689
|
+
// ds4-server's single-instance lock refuses it — every ds4
|
|
1690
|
+
// one-shot (summaries, meester-status, extraction) then fails
|
|
1691
|
+
// with "another ds4 process is already running" (wild-caught
|
|
1692
|
+
// by validate-ambient-gate on an env-path daemon).
|
|
1693
|
+
((await this.ds4Models?.resolveModel(resolved)) ??
|
|
1694
|
+
(process.env.GEZEL_DS4_MODEL ||
|
|
1695
|
+
process.env.GEZEL_DS4_SERVER_URL ||
|
|
1696
|
+
config.ds4ModelPath ||
|
|
1697
|
+
config.ds4BaseUrl
|
|
1698
|
+
? { explicitSource: true }
|
|
1699
|
+
: undefined))
|
|
1700
|
+
: await this.mlxModels?.resolveModel(resolved);
|
|
1701
|
+
if (!installed) {
|
|
1702
|
+
throw new ModelNotInstalledError(name, resolved);
|
|
1703
|
+
}
|
|
1704
|
+
const { provider } = await this.bindLocalReplica(router, name, resolved, {
|
|
1705
|
+
// Synthetic id — one-shot requests have no session record; the
|
|
1706
|
+
// bind still load-balances across resident replicas.
|
|
1707
|
+
sessionId: `v1:${randomUUID()}`,
|
|
1708
|
+
...(opts.engineDrainWaitMs !== undefined
|
|
1709
|
+
? { engineDrainWaitMs: opts.engineDrainWaitMs }
|
|
1710
|
+
: {}),
|
|
1711
|
+
});
|
|
1712
|
+
return provider;
|
|
1713
|
+
}
|
|
1714
|
+
}
|