@bendyline/gezel-inference 1.0.1 → 1.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/catalog/chat-models/de/deepseek-v4.1-flash-552b-q2/manifest.json +120 -0
- package/dist/catalog/chat-models/de/deepseek-v4.1-flash-552b-q2/versions/1.0.0/manifest.json +21 -0
- package/dist/catalog/chat-models/gl/glm-5.3-flash-320b-q2/manifest.json +6 -5
- package/dist/catalog/chat-models/gl/glm-5.3-flash-320b-q2/versions/1.0.2/manifest.json +27 -0
- package/dist/catalog/chat-models/gl/glm-5.3-flash-320b-q2/versions/1.0.3/manifest.json +27 -0
- package/dist/catalog/chat-models/index.json +1 -1
- package/dist/catalog/chat-models/ne/nemotron3.5-bolt-74b-iq2/manifest.json +157 -0
- package/dist/catalog/chat-models/ne/nemotron3.5-bolt-74b-iq2/versions/1.0.0/manifest.json +30 -0
- package/dist/catalog/chat-models/ne/nemotron3.5-super-vl-120b-nvfp4/manifest.json +156 -0
- package/dist/catalog/chat-models/ne/nemotron3.5-super-vl-120b-nvfp4/versions/1.0.0/manifest.json +28 -0
- package/dist/catalog/chat-models/raw-index.json +1 -1
- package/dist/catalog/knowledge-catalogs/be/bendyline-how-to-books/keywords.json +56 -0
- package/dist/catalog/knowledge-catalogs/ca/caselaw-alaska-part-0001/keywords.json +12 -0
- package/dist/catalog/knowledge-catalogs/ca/caselaw-nevada-part-0001/keywords.json +13 -0
- package/dist/catalog/knowledge-catalogs/ca/caselaw-us-300-399-part-0001/keywords.json +14 -0
- package/dist/catalog/knowledge-catalogs/ca/caselaw-us-347-349/keywords.json +17 -0
- package/dist/catalog/knowledge-catalogs/ca/caselaw-utah-part-0001/keywords.json +12 -0
- package/dist/catalog/knowledge-catalogs/ca/caselaw-utah-part-0002/keywords.json +12 -0
- package/dist/catalog/knowledge-catalogs/ca/caselaw-washington-part-0001/keywords.json +12 -0
- package/dist/catalog/knowledge-catalogs/ca/caselaw-washington-part-0002/keywords.json +12 -0
- package/dist/catalog/knowledge-catalogs/ca/caselaw-washington-part-0003/keywords.json +12 -0
- package/dist/catalog/knowledge-catalogs/ca/caselaw-washington-part-0004/keywords.json +12 -0
- package/dist/catalog/knowledge-catalogs/ca/caselaw-washington-part-0005/keywords.json +12 -0
- package/dist/catalog/knowledge-catalogs/ca/caselaw-wyoming-part-0001/keywords.json +12 -0
- package/dist/catalog/knowledge-catalogs/index.json +1 -1
- package/dist/catalog/knowledge-catalogs/mi/microsoftdocs-aspnet-core-en/keywords.json +21 -0
- package/dist/catalog/knowledge-catalogs/mi/microsoftdocs-azure-ai-platform-en/keywords.json +27 -0
- package/dist/catalog/knowledge-catalogs/mi/microsoftdocs-azure-apps-compute-en/keywords.json +23 -0
- package/dist/catalog/knowledge-catalogs/mi/microsoftdocs-azure-data-aiot-en/keywords.json +26 -0
- package/dist/catalog/knowledge-catalogs/mi/microsoftdocs-azure-management-hybrid-en/keywords.json +28 -0
- package/dist/catalog/knowledge-catalogs/mi/microsoftdocs-azure-network-security-en/keywords.json +29 -0
- package/dist/catalog/knowledge-catalogs/mi/microsoftdocs-dotnet-en/keywords.json +21 -0
- package/dist/catalog/knowledge-catalogs/mi/microsoftdocs-entity-framework-en/keywords.json +14 -0
- package/dist/catalog/knowledge-catalogs/mi/microsoftdocs-microsoft-365-en/keywords.json +20 -0
- package/dist/catalog/knowledge-catalogs/mi/microsoftdocs-powershell-en/keywords.json +24 -0
- package/dist/catalog/knowledge-catalogs/mi/microsoftdocs-sql-server-en/keywords.json +27 -0
- package/dist/catalog/knowledge-catalogs/mi/microsoftdocs-windows-apps-en/keywords.json +18 -0
- package/dist/catalog/knowledge-catalogs/mi/microsoftdocs-windows-server-en/keywords.json +28 -0
- package/dist/catalog/knowledge-catalogs/raw-index.json +1 -1
- package/dist/catalog/knowledge-catalogs/re/regional-american-south/keywords.json +1700 -0
- package/dist/catalog/knowledge-catalogs/re/regional-american-south/versions/2026.10.5/manifest.json +133 -0
- package/dist/catalog/knowledge-catalogs/re/regional-andes-amazon/keywords.json +750 -0
- package/dist/catalog/knowledge-catalogs/re/regional-andes-amazon/versions/2026.10.5/manifest.json +133 -0
- package/dist/catalog/knowledge-catalogs/re/regional-australia-nz/keywords.json +1281 -0
- package/dist/catalog/knowledge-catalogs/re/regional-australia-nz/versions/2026.10.5/manifest.json +133 -0
- package/dist/catalog/knowledge-catalogs/re/regional-brazil/keywords.json +1125 -0
- package/dist/catalog/knowledge-catalogs/re/regional-brazil/versions/2026.10.5/manifest.json +133 -0
- package/dist/catalog/knowledge-catalogs/re/regional-britain-ireland/keywords.json +3287 -0
- package/dist/catalog/knowledge-catalogs/re/regional-britain-ireland/versions/2026.10.5/manifest.json +133 -0
- package/dist/catalog/knowledge-catalogs/re/regional-california-southwest/keywords.json +1835 -0
- package/dist/catalog/knowledge-catalogs/re/regional-california-southwest/versions/2026.10.5/manifest.json +133 -0
- package/dist/catalog/knowledge-catalogs/re/regional-canada-alaska/keywords.json +1184 -0
- package/dist/catalog/knowledge-catalogs/re/regional-canada-alaska/versions/2026.10.5/manifest.json +133 -0
- package/dist/catalog/knowledge-catalogs/re/regional-central-eastern-europe/keywords.json +1503 -0
- package/dist/catalog/knowledge-catalogs/re/regional-central-eastern-europe/versions/2026.10.5/manifest.json +133 -0
- package/dist/catalog/knowledge-catalogs/re/regional-east-asia/keywords.json +2836 -0
- package/dist/catalog/knowledge-catalogs/re/regional-east-asia/versions/2026.10.5/manifest.json +133 -0
- package/dist/catalog/knowledge-catalogs/re/regional-east-southern-africa/keywords.json +813 -0
- package/dist/catalog/knowledge-catalogs/re/regional-east-southern-africa/versions/2026.10.5/manifest.json +133 -0
- package/dist/catalog/knowledge-catalogs/re/regional-mediterranean/keywords.json +2082 -0
- package/dist/catalog/knowledge-catalogs/re/regional-mediterranean/versions/2026.10.5/manifest.json +133 -0
- package/dist/catalog/knowledge-catalogs/re/regional-mexico-central-america/keywords.json +1481 -0
- package/dist/catalog/knowledge-catalogs/re/regional-mexico-central-america/versions/2026.10.5/manifest.json +133 -0
- package/dist/catalog/knowledge-catalogs/re/regional-middle-east/keywords.json +1272 -0
- package/dist/catalog/knowledge-catalogs/re/regional-middle-east/versions/2026.10.5/manifest.json +133 -0
- package/dist/catalog/knowledge-catalogs/re/regional-midwest/keywords.json +758 -0
- package/dist/catalog/knowledge-catalogs/re/regional-midwest/versions/2026.10.5/manifest.json +133 -0
- package/dist/catalog/knowledge-catalogs/re/regional-north-africa/keywords.json +896 -0
- package/dist/catalog/knowledge-catalogs/re/regional-north-africa/versions/2026.10.5/manifest.json +133 -0
- package/dist/catalog/knowledge-catalogs/re/regional-northeast/keywords.json +1281 -0
- package/dist/catalog/knowledge-catalogs/re/regional-northeast/versions/2026.10.5/manifest.json +133 -0
- package/dist/catalog/knowledge-catalogs/re/regional-northern-eurasia/keywords.json +346 -0
- package/dist/catalog/knowledge-catalogs/re/regional-northern-eurasia/versions/2026.10.5/manifest.json +133 -0
- package/dist/catalog/knowledge-catalogs/re/regional-northern-europe/keywords.json +2688 -0
- package/dist/catalog/knowledge-catalogs/re/regional-northern-europe/versions/2026.10.5/manifest.json +133 -0
- package/dist/catalog/knowledge-catalogs/re/regional-pacific-islands/keywords.json +973 -0
- package/dist/catalog/knowledge-catalogs/re/regional-pacific-islands/versions/2026.10.5/manifest.json +133 -0
- package/dist/catalog/knowledge-catalogs/re/regional-pacific-northwest/keywords.json +937 -0
- package/dist/catalog/knowledge-catalogs/re/regional-pacific-northwest/versions/2026.10.5/manifest.json +133 -0
- package/dist/catalog/knowledge-catalogs/re/regional-rockies-plains/keywords.json +608 -0
- package/dist/catalog/knowledge-catalogs/re/regional-rockies-plains/versions/2026.10.5/manifest.json +133 -0
- package/dist/catalog/knowledge-catalogs/re/regional-south-asia/keywords.json +633 -0
- package/dist/catalog/knowledge-catalogs/re/regional-south-asia/versions/2026.10.5/manifest.json +133 -0
- package/dist/catalog/knowledge-catalogs/re/regional-southeast-asia/keywords.json +2697 -0
- package/dist/catalog/knowledge-catalogs/re/regional-southeast-asia/versions/2026.10.5/manifest.json +133 -0
- package/dist/catalog/knowledge-catalogs/re/regional-southern-cone/keywords.json +606 -0
- package/dist/catalog/knowledge-catalogs/re/regional-southern-cone/versions/2026.10.5/manifest.json +133 -0
- package/dist/catalog/knowledge-catalogs/re/regional-west-central-africa/keywords.json +564 -0
- package/dist/catalog/knowledge-catalogs/re/regional-west-central-africa/versions/2026.10.5/manifest.json +133 -0
- package/dist/catalog/knowledge-catalogs/re/regional-western-europe/keywords.json +3247 -0
- package/dist/catalog/knowledge-catalogs/re/regional-western-europe-east/manifest.json +47 -0
- package/dist/catalog/knowledge-catalogs/re/regional-western-europe-east/versions/2026.10.5/manifest.json +133 -0
- package/dist/catalog/knowledge-catalogs/re/regional-western-europe-west/manifest.json +47 -0
- package/dist/catalog/knowledge-catalogs/re/regional-western-europe-west/versions/2026.10.5/manifest.json +133 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-arts/keywords.json +5437 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-arts/manifest.json +1 -1
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-arts/versions/2026.10.1/manifest.json +181 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-astronomy/keywords.json +4009 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-astronomy/manifest.json +1 -1
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-astronomy/versions/2026.10.1/manifest.json +181 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-biology/keywords.json +4009 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-biology/manifest.json +1 -1
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-biology/versions/2026.10.1/manifest.json +217 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-business/keywords.json +5583 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-business/manifest.json +1 -1
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-business/versions/2026.10.1/manifest.json +197 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-film-tv/keywords.json +6386 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-film-tv/manifest.json +2 -2
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-film-tv/versions/2026.10.1/manifest.json +197 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-food-drink/keywords.json +4009 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-food-drink/manifest.json +1 -1
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-food-drink/versions/2026.10.1/manifest.json +185 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-games/keywords.json +5672 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-games/manifest.json +1 -1
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-games/versions/2026.10.1/manifest.json +137 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-geography/manifest.json +68 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-geography/versions/2026.10.1/manifest.json +217 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-history/manifest.json +68 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-history/versions/2026.10.1/manifest.json +217 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-language/keywords.json +4009 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-language/manifest.json +1 -1
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-language/versions/2026.10.1/manifest.json +141 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-law/keywords.json +4009 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-law/manifest.json +1 -1
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-law/versions/2026.10.1/manifest.json +185 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-literature/keywords.json +5719 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-literature/manifest.json +1 -1
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-literature/versions/2026.10.1/manifest.json +193 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-mathematics/keywords.json +4009 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-mathematics/manifest.json +1 -1
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-mathematics/versions/2026.10.1/manifest.json +189 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-medicine/keywords.json +16009 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-medicine/manifest.json +1 -1
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-medicine/versions/2026.10.1/manifest.json +185 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-military/keywords.json +5843 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-military/manifest.json +1 -1
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-military/versions/2026.10.1/manifest.json +189 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-music/keywords.json +6264 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-music/manifest.json +1 -1
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-music/versions/2026.10.1/manifest.json +197 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-people-arts/manifest.json +66 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-people-arts/versions/2026.10.1/manifest.json +209 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-people-business/manifest.json +61 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-people-business/versions/2026.10.1/manifest.json +189 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-people-entertainment/manifest.json +64 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-people-entertainment/versions/2026.10.1/manifest.json +201 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-people-military/manifest.json +60 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-people-military/versions/2026.10.1/manifest.json +185 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-people-other/manifest.json +55 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-people-other/versions/2026.10.1/manifest.json +165 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-people-politics/manifest.json +63 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-people-politics/versions/2026.10.1/manifest.json +197 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-people-religion/manifest.json +64 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-people-religion/versions/2026.10.1/manifest.json +201 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-people-science/manifest.json +65 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-people-science/versions/2026.10.1/manifest.json +205 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-people-sports/manifest.json +73 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-people-sports/versions/2026.10.1/manifest.json +237 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-politics/keywords.json +5447 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-politics/manifest.json +1 -1
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-politics/versions/2026.10.1/manifest.json +197 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-religion-philosophy/keywords.json +4009 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-religion-philosophy/manifest.json +1 -1
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-religion-philosophy/versions/2026.10.1/manifest.json +189 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-science/keywords.json +4009 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-science/manifest.json +1 -1
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-science/versions/2026.10.1/manifest.json +185 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-sports/keywords.json +5209 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-sports/manifest.json +1 -1
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-sports/versions/2026.10.1/manifest.json +193 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-technology/keywords.json +6537 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-technology/manifest.json +1 -1
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-technology/versions/2026.10.1/manifest.json +185 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-transportation/keywords.json +5989 -0
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-transportation/manifest.json +1 -1
- package/dist/catalog/knowledge-catalogs/wi/wikipedia-transportation/versions/2026.10.1/manifest.json +189 -0
- package/dist/catalog/provenance.json +1 -1
- package/dist/engines/native-file-manifest.json +483 -413
- package/dist/engines/native-manifest.d.ts +4 -4
- package/dist/engines/native-manifest.js +36 -34
- package/dist/engines/resolver.js +3 -1
- package/dist/fs/atomic.d.ts +4 -1
- package/dist/fs/atomic.js +7 -1
- package/dist/http/openai-compat/chat-target.d.ts +1 -1
- package/dist/http/openai-compat/chat-target.js +1 -1
- package/dist/http/openai-compat/engine-failure.d.ts +25 -0
- package/dist/http/openai-compat/engine-failure.js +76 -0
- package/dist/http/openai-compat/responses-streaming.js +2 -1
- package/dist/http/openai-compat/responses-translate.d.ts +1 -1
- package/dist/http/openai-compat/translate.d.ts +1 -1
- package/dist/http/routes/engines.js +35 -0
- package/dist/http/routes/v1-chat.js +11 -2
- package/dist/http/routes/v1-knowledge.js +4 -0
- package/dist/http/routes/v1-models.js +6 -4
- package/dist/http/routes/v1-responses.d.ts +1 -1
- package/dist/http/routes/v1-responses.js +7 -1
- package/dist/inference-service.d.ts +6 -1
- package/dist/inference-service.js +20 -9
- package/dist/knowledge/catalog-host.d.ts +9 -1
- package/dist/knowledge/catalog-host.js +2 -0
- package/dist/knowledge/manager.d.ts +21 -0
- package/dist/knowledge/manager.js +85 -7
- package/dist/knowledge/search-worker.d.ts +1 -1
- package/dist/knowledge/spatial-query.d.ts +2 -3
- package/dist/knowledge/spatial-query.js +12 -6
- package/dist/knowledge/worker-host.js +2 -0
- package/dist/memory/embed-core.d.ts +16 -0
- package/dist/memory/embed-core.js +31 -0
- package/dist/memory/embed-worker.d.ts +7 -3
- package/dist/memory/embed-worker.js +13 -4
- package/dist/memory/embeddings.d.ts +17 -2
- package/dist/memory/embeddings.js +36 -7
- package/dist/models/ensure.d.ts +2 -0
- package/dist/models/ensure.js +9 -0
- package/dist/perf/responsiveness.d.ts +14 -1
- package/dist/perf/responsiveness.js +81 -10
- package/dist/providers/audio/kokoro-frontend.js +1 -1
- package/dist/providers/ds4/build-provider.js +6 -0
- package/dist/providers/llama-cpp/backend-health.d.ts +30 -0
- package/dist/providers/llama-cpp/backend-health.js +64 -0
- package/dist/providers/llama-cpp/backend-quarantine.d.ts +40 -0
- package/dist/providers/llama-cpp/backend-quarantine.js +100 -0
- package/dist/providers/llama-cpp/build-provider.js +247 -199
- package/dist/providers/llama-cpp/cache-adapter.d.ts +7 -1
- package/dist/providers/llama-cpp/cache-adapter.js +11 -1
- package/dist/providers/llama-cpp/devices.d.ts +22 -2
- package/dist/providers/llama-cpp/devices.js +48 -5
- package/dist/providers/llama-cpp/engine-flags.d.ts +0 -18
- package/dist/providers/llama-cpp/engine-flags.js +12 -18
- package/dist/providers/llama-cpp/gguf-metadata.js +20 -3
- package/dist/providers/llama-cpp/gpu-startup-watch.d.ts +41 -0
- package/dist/providers/llama-cpp/gpu-startup-watch.js +58 -0
- package/dist/providers/llama-cpp/models.d.ts +6 -0
- package/dist/providers/llama-cpp/models.js +23 -2
- package/dist/providers/llama-cpp/offload-planner.d.ts +26 -18
- package/dist/providers/llama-cpp/offload-planner.js +30 -14
- package/dist/providers/llama-cpp/provider.d.ts +22 -3
- package/dist/providers/llama-cpp/provider.js +39 -3
- package/dist/providers/mlx/provider.js +5 -6
- package/dist/providers/mlx/python/qwen4_ple.py +9 -2
- package/dist/providers/mlx/reasoning-stream.d.ts +15 -0
- package/dist/providers/mlx/reasoning-stream.js +35 -0
- package/dist/providers/native/capacity-broker.d.ts +21 -15
- package/dist/providers/native/capacity-broker.js +25 -13
- package/dist/providers/native/capacity-budget.d.ts +35 -3
- package/dist/providers/native/capacity-budget.js +49 -5
- package/dist/providers/native/device-capacity.d.ts +1 -1
- package/dist/providers/native/device-capacity.js +23 -5
- package/dist/providers/native/local-engine-runtime.js +31 -31
- package/dist/providers/native/measured-budget.js +2 -0
- package/dist/providers/native/supervisor.d.ts +25 -0
- package/dist/providers/native/supervisor.js +62 -8
- package/dist/providers/queue.d.ts +9 -2
- package/dist/providers/queue.js +17 -2
- package/dist/providers/session-hooks.d.ts +4 -1
- package/dist/system/amdgpu-adapters.d.ts +18 -0
- package/dist/system/amdgpu-adapters.js +55 -0
- package/dist/system/gpu-carve-out.d.ts +84 -0
- package/dist/system/gpu-carve-out.js +111 -0
- package/dist/system/memory.d.ts +17 -1
- package/dist/system/memory.js +94 -13
- package/dist/transformers-cache.d.ts +2 -0
- package/dist/transformers-cache.js +6 -3
- package/package.json +5 -5
|
@@ -1,27 +1,30 @@
|
|
|
1
1
|
import { availableParallelism } from 'node:os';
|
|
2
2
|
import { delimiter, dirname, join } from 'node:path';
|
|
3
|
-
import { DEFAULT_LOCAL_ENGINE_IDLE_TIMEOUT_MS, createLogger, estimateLlamaCppResidentBytes, } from '@bendyline/gezel';
|
|
4
|
-
import {
|
|
3
|
+
import { DEFAULT_LOCAL_ENGINE_IDLE_TIMEOUT_MS, createLogger, estimateLlamaCppResidentBytes, llamaCppBackendExclusion, llamaCppBackendLabel, } from '@bendyline/gezel';
|
|
4
|
+
import { LLAMA_QUARANTINE_STRIKES, clearLlamaStartupStrikes, recordLlamaStartupCrash, unrunnableBuildExit, } from '@bendyline/gezel/native';
|
|
5
5
|
import { gezelPaths } from '@bendyline/gezel/paths';
|
|
6
6
|
import { mmprojBudgetBytes, nativeVisionEnabledFor } from '../../chat/vision-capability.js';
|
|
7
7
|
import { effectiveEngineRelease, isEnginePinned } from '../../engines/native-manifest.js';
|
|
8
8
|
import { engineInstallPhase } from '../../engines/registry.js';
|
|
9
9
|
import { localDeviceSettingsLabel, noModelYetMessage, notReadyError, } from '../active-install-message.js';
|
|
10
10
|
import { resolveCatalogLlamaCppEngineConfig, resolveCatalogReasoningBudget, } from '../catalog-model-config.js';
|
|
11
|
-
import { CapacityDeniedError, NOT_ENOUGH_MEMORY_MESSAGE,
|
|
11
|
+
import { CapacityDeniedError, NOT_ENOUGH_MEMORY_MESSAGE, availableSystemRamBytes, formatContextCapacityDenial, minViableLocalContextTokens, planAdaptiveContextGrowth, pressureIdleGraceMs, resolveLlamaCppContextRequirement, } from '../native/capacity-broker.js';
|
|
12
12
|
import { measureAvailableGpuBytes } from '../native/device-capacity.js';
|
|
13
13
|
import { engineApiKey, withEngineApiKey } from '../native/engine-api-key.js';
|
|
14
14
|
import { makeEngineKey } from '../native/engine-key.js';
|
|
15
15
|
import { pickFreePort } from '../native/port.js';
|
|
16
16
|
import { NativeEngineSupervisor } from '../native/supervisor.js';
|
|
17
17
|
import { patientFetch } from '../patient-fetch.js';
|
|
18
|
+
import { currentLlamaCppBackend, noteGpuStartup, noteHostOutOfMemory } from './backend-health.js';
|
|
19
|
+
import { adoptLlamaFallback } from './backend-quarantine.js';
|
|
18
20
|
import { lastArgValue, readLlamaCppBuildMetadata } from './build-metadata.js';
|
|
19
21
|
import { matchNvidiaRuntimeDevice, maxGpuVramBytes, pickBestGpuDevice, probeLlamaDevices, probeNvidiaRuntimeDevices, } from './devices.js';
|
|
20
22
|
import { buildLlamaCppEngineArgs } from './engine-flags.js';
|
|
21
23
|
import { readGgufSummaryAsync } from './gguf-metadata-async.js';
|
|
22
24
|
import { effectiveLazyTensorBytes } from './gguf-metadata.js';
|
|
25
|
+
import { GpuStartupWatch } from './gpu-startup-watch.js';
|
|
23
26
|
import { isGemmaModel, planLlamaCppKv, resolveLlamaCppKvCacheType, } from './kv-cache-type.js';
|
|
24
|
-
import { degradeDenseFfnOffloadDecision, degradeMoeOffloadDecision, estimateExactPerSlotKvBytesF16, estimateKvReserveBytes, estimateWindowedKvLinearization,
|
|
27
|
+
import { degradeDenseFfnOffloadDecision, degradeMoeOffloadDecision, estimateExactPerSlotKvBytesF16, estimateKvReserveBytes, estimateWindowedKvLinearization, planDenseFfnOffload, planMoeOffload, shedSlotsForGpuResidency, } from './offload-planner.js';
|
|
25
28
|
import { LlamaCppProvider } from './provider.js';
|
|
26
29
|
import { reasoningLaunchOverridesFromEnv } from './reasoning-launch.js';
|
|
27
30
|
import { resolveSpecDraft } from './spec-draft.js';
|
|
@@ -69,6 +72,15 @@ export async function buildLlamaCppProvider(opts) {
|
|
|
69
72
|
? undefined
|
|
70
73
|
: (process.env.GEZEL_LLAMA_SERVER_URL ?? config.llamaCppBaseUrl);
|
|
71
74
|
const binary = process.env.GEZEL_LLAMA_SERVER_BIN;
|
|
75
|
+
// Read together with the binary: after a quarantine the env points at the
|
|
76
|
+
// fallback build, and a crash of THIS build must be charged to its own
|
|
77
|
+
// backend, not to whatever the env names by then.
|
|
78
|
+
const binaryBackend = process.env.GEZEL_LLAMA_SERVER_BACKEND;
|
|
79
|
+
// What the latest startup crash did to this build's standing, for the error
|
|
80
|
+
// the failed start raises. `onExit` runs before `ensureRunning` rejects.
|
|
81
|
+
let lastStartupCrash = null;
|
|
82
|
+
// Fresh for each launch: whether this start of a GPU build got its GPU.
|
|
83
|
+
let gpuWatch = null;
|
|
72
84
|
// Preservation is a two-sided contract: launch llama-server with the
|
|
73
85
|
// explicit preserve/no-preserve flag AND replay captured
|
|
74
86
|
// `reasoning_content` only in the preserve case. v0.4.0 changed the server
|
|
@@ -269,6 +281,18 @@ export async function buildLlamaCppProvider(opts) {
|
|
|
269
281
|
}
|
|
270
282
|
throw notReadyError(noModelYetMessage('Local model', activeLlamaInstall(opts.llamaCppModels)), 'model-not-ready');
|
|
271
283
|
}
|
|
284
|
+
// Install refuses an excluded backend; this catches a model installed
|
|
285
|
+
// before the exclusion was authored, or copied in by hand.
|
|
286
|
+
if (modelCatalogInfo && opts.catalog) {
|
|
287
|
+
const engineBackend = binaryBackend ?? currentLlamaCppBackend();
|
|
288
|
+
const detail = await opts.catalog.get('chat-model', modelCatalogInfo.id).catch(() => null);
|
|
289
|
+
const excluded = llamaCppBackendExclusion(detail?.manifest.kind === 'chat-model' ? detail.manifest.llamaCpp : undefined, engineBackend);
|
|
290
|
+
if (excluded && engineBackend) {
|
|
291
|
+
const err = new Error(`Local model: ${modelCatalogInfo.name} cannot run on the ${llamaCppBackendLabel(engineBackend)} llama.cpp engine. ${excluded} Pick another local model in Settings → ${localDeviceSettingsLabel()}.`);
|
|
292
|
+
err.isActionable = true;
|
|
293
|
+
throw err;
|
|
294
|
+
}
|
|
295
|
+
}
|
|
272
296
|
// Per Phase 0 measurements on a cold Mac: Metal library compile is
|
|
273
297
|
// ~14s and model load adds model-size-dependent time. Default
|
|
274
298
|
// startupTimeoutMs is 60s which squeaks through for a 7B on a warm
|
|
@@ -323,13 +347,6 @@ export async function buildLlamaCppProvider(opts) {
|
|
|
323
347
|
// path still clamps to the native train context.
|
|
324
348
|
const explicitCtx = envNumCtx ?? perModelCtxOverride ?? config.llamaCppNumCtx;
|
|
325
349
|
const hostFloorTokens = minViableLocalContextTokens();
|
|
326
|
-
// A per-model override below the host floor is deliberate user intent —
|
|
327
|
-
// lower the admission floor to the override instead of silently raising
|
|
328
|
-
// the request back to 64K. Env / machine-wide values keep their
|
|
329
|
-
// historical floor semantics.
|
|
330
|
-
const minViableTokens = perModelCtxOverride !== undefined && explicitCtx === perModelCtxOverride
|
|
331
|
-
? Math.min(hostFloorTokens, perModelCtxOverride)
|
|
332
|
-
: hostFloorTokens;
|
|
333
350
|
const contextRequirement = resolveLlamaCppContextRequirement({
|
|
334
351
|
modelContextWindow: modelCatalogInfo?.contextWindow,
|
|
335
352
|
...(explicitCtx !== undefined ? { explicitContextWindow: explicitCtx } : {}),
|
|
@@ -338,7 +355,7 @@ export async function buildLlamaCppProvider(opts) {
|
|
|
338
355
|
? { manifestContextSize: manifestEngineConfig.contextSize }
|
|
339
356
|
: {}),
|
|
340
357
|
contextSizing: config.llamaCppContextSizing ?? 'adaptive',
|
|
341
|
-
minViableContextTokens:
|
|
358
|
+
minViableContextTokens: hostFloorTokens,
|
|
342
359
|
});
|
|
343
360
|
// `let`: RAM-aware admission below may lower this (but never below the
|
|
344
361
|
// model-aware minimum) before anything launch-visible consumes it.
|
|
@@ -621,18 +638,15 @@ export async function buildLlamaCppProvider(opts) {
|
|
|
621
638
|
// back to the engine's own `--fit` / `-ngl auto`.
|
|
622
639
|
let offloadDecision;
|
|
623
640
|
let offloadBlockCount;
|
|
624
|
-
// Whether weights + full-attention KV at the requested context fit the
|
|
625
|
-
// fast-memory pool — VRAM on a discrete GPU. Gates the Gemma
|
|
626
|
-
// `--swa-full` auto-default (see `EngineFlagInput.swaFullAutoFits`). Set
|
|
627
|
-
// false to keep the full context on the windowed cache when Full would
|
|
628
|
-
// spill or require a slot/context reduction; undefined means it fits or
|
|
629
|
-
// the exact decision could not be computed.
|
|
630
|
-
let swaFullAutoFits;
|
|
631
641
|
// Broker-ledger reservation for this launch: resident weights + the KV
|
|
632
642
|
// the engine will actually allocate at the granted window and cache
|
|
633
643
|
// mode. Undefined when the GGUF is unreadable — the pool builder then
|
|
634
644
|
// falls back to the legacy weights-multiplier reservation.
|
|
635
645
|
let plannedReservationBytes;
|
|
646
|
+
// What prices that reservation, kept for the out-of-memory ladder: when it
|
|
647
|
+
// drops a slot, the relaunch is charged for the KV it actually allocates.
|
|
648
|
+
let reservationKvFor;
|
|
649
|
+
let reservationResidentBytes;
|
|
636
650
|
// Graphics memory the MoE offload plan puts on the card. Device admission
|
|
637
651
|
// charges this rather than the whole card; undefined keeps the old charge.
|
|
638
652
|
let plannedGpuBytes;
|
|
@@ -709,21 +723,16 @@ export async function buildLlamaCppProvider(opts) {
|
|
|
709
723
|
// under GEZEL_LLAMA_NUM_CTX — eval runs lift ceilings deliberately
|
|
710
724
|
// and accept the memory consequences.
|
|
711
725
|
//
|
|
712
|
-
//
|
|
713
|
-
//
|
|
714
|
-
//
|
|
715
|
-
//
|
|
716
|
-
//
|
|
717
|
-
//
|
|
718
|
-
//
|
|
719
|
-
//
|
|
720
|
-
//
|
|
721
|
-
//
|
|
722
|
-
// ungated: admission re-plans with the windowed-KV linearization
|
|
723
|
-
// (SWA layers = fixed window-capped bytes, global layers = the only
|
|
724
|
-
// per-token cost), so a host too small even for the windowed cache
|
|
725
|
-
// still denies or clamps honestly instead of OOMing one machine
|
|
726
|
-
// class below the 2026-08-05 incident.
|
|
726
|
+
// A sliding-window model runs llama.cpp's windowed cache unless
|
|
727
|
+
// `swaFull` is pinned, and admission prices what runs: it re-plans
|
|
728
|
+
// with the windowed-KV linearization (SWA layers = fixed window-capped
|
|
729
|
+
// bytes, global layers = the only per-token cost), so a host too small
|
|
730
|
+
// even for the windowed cache still denies or clamps honestly instead
|
|
731
|
+
// of OOMing one machine class below the 2026-08-05 incident.
|
|
732
|
+
// Shared-KV layers and SWA-specific head dimensions are load-bearing
|
|
733
|
+
// in that math — E4B owns only 24 KV caches for 42 logical layers, and
|
|
734
|
+
// pricing all 42 at global dimensions overstated its two-slot 64K KV
|
|
735
|
+
// allocation as 21 GiB instead of llama.cpp's actual 7 GiB.
|
|
727
736
|
{
|
|
728
737
|
const REFERENCE_CTX = 4096;
|
|
729
738
|
const exactKvAtReference = estimateKvReserveBytes({
|
|
@@ -769,23 +778,14 @@ export async function buildLlamaCppProvider(opts) {
|
|
|
769
778
|
? {
|
|
770
779
|
unifiedMemory: liveMemory.gpuMemoryKind === 'integrated' ||
|
|
771
780
|
liveMemory.gpuMemoryKind === 'unified',
|
|
781
|
+
reservedGpuBytes: liveMemory.gpuReservedBytes ?? null,
|
|
782
|
+
gpuAddressableBytes: liveMemory.gpuAddressableBytes ?? null,
|
|
772
783
|
}
|
|
773
784
|
: {}),
|
|
774
785
|
});
|
|
775
786
|
const fastBudgetBytes = brokerSnap?.enforced
|
|
776
787
|
? (opts.broker?.fastBudgetBytes() ?? liveBudget.fastBytes)
|
|
777
788
|
: liveBudget.fastBytes;
|
|
778
|
-
const fullKvBytesAtRequested = exactKvAtReference !== undefined
|
|
779
|
-
? (exactKvAtReference / REFERENCE_CTX) * effectiveNumCtx * slots
|
|
780
|
-
: undefined;
|
|
781
|
-
const fullCacheFitsFastMemory = fullKvBytesAtRequested !== undefined
|
|
782
|
-
? fitsSwaFullInFastMemory({
|
|
783
|
-
residentWeightsBytes: residentBytes,
|
|
784
|
-
fullKvBytes: fullKvBytesAtRequested,
|
|
785
|
-
fastBudgetBytes,
|
|
786
|
-
committedOtherBytes,
|
|
787
|
-
})
|
|
788
|
-
: undefined;
|
|
789
789
|
const admission = planCtxTokensForMemory({
|
|
790
790
|
requestedPerTurnCtxTokens: effectiveNumCtx,
|
|
791
791
|
slots,
|
|
@@ -797,25 +797,13 @@ export async function buildLlamaCppProvider(opts) {
|
|
|
797
797
|
freeSystemRamBytes: availableSystemRamBytes(),
|
|
798
798
|
vramBytes: liveBudget.vramBytes,
|
|
799
799
|
});
|
|
800
|
+
// `--swa-full` runs only when pinned; every other launch of a
|
|
801
|
+
// sliding-window model gets llama.cpp's windowed cache.
|
|
800
802
|
const explicitSwaFull = config.llamaCppSwaFull ?? manifestEngineConfig?.swaFull;
|
|
801
|
-
const
|
|
802
|
-
isGemmaModel({
|
|
803
|
-
architecture: modelCatalogInfo?.architecture,
|
|
804
|
-
modelId: defaultModelId ?? undefined,
|
|
805
|
-
});
|
|
806
|
-
// A full-size cache past the automatic KV ceiling is declined even
|
|
807
|
-
// where it fits: gemma4-31b's is 55 GB at 64K, 11x its windowed
|
|
808
|
-
// cache, for a cross-request reuse gain nobody had measured.
|
|
809
|
-
const kvCeilingBytes = autoKvCacheMaxBytes();
|
|
810
|
-
const fullCacheOverCeiling = fullKvBytesAtRequested !== undefined && fullKvBytesAtRequested > kvCeilingBytes;
|
|
811
|
-
const fullKvOverBudget = fullCacheFitsFastMemory === false ||
|
|
812
|
-
fullCacheOverCeiling ||
|
|
813
|
-
!admission.minimumSatisfied ||
|
|
814
|
-
admission.slots < slots ||
|
|
815
|
-
admission.clamped;
|
|
803
|
+
const fullKvOverBudget = !admission.minimumSatisfied || admission.slots < slots || admission.clamped;
|
|
816
804
|
// The plan whose ladder (deny → shed slots → clamp) is enforced
|
|
817
805
|
// below. Defaults to the full-attention plan; the windowed-cache
|
|
818
|
-
//
|
|
806
|
+
// branch replaces it with windowed math or — only when the GGUF
|
|
819
807
|
// hides its SWA layout — null (no safe estimate; launch untouched,
|
|
820
808
|
// the pre-windowed-admission behavior).
|
|
821
809
|
let ladderPlan = admission;
|
|
@@ -833,17 +821,17 @@ export async function buildLlamaCppProvider(opts) {
|
|
|
833
821
|
// full-attention), and the strict minimum rides inside
|
|
834
822
|
// `contextRequirement.minimumPerTurnCtxTokens`, so the windowed
|
|
835
823
|
// re-plan below sheds slots or denies but never shortens the window.
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
//
|
|
839
|
-
//
|
|
840
|
-
//
|
|
841
|
-
//
|
|
842
|
-
//
|
|
843
|
-
// context
|
|
844
|
-
//
|
|
845
|
-
//
|
|
846
|
-
//
|
|
824
|
+
if (explicitSwaFull !== true) {
|
|
825
|
+
// The admission above is full-attention KV math, which overstates
|
|
826
|
+
// the windowed cache's real allocation (Gemma 4: global layers are
|
|
827
|
+
// both fewer AND cheaper per token than SWA layers — ~11× on 31b
|
|
828
|
+
// at 64K). Re-plan with the windowed linearization: SWA layers
|
|
829
|
+
// become a fixed, context-independent reservation; only global
|
|
830
|
+
// layers scale. Without it a 31b-class Gemma on a ~32 GB host
|
|
831
|
+
// would launch with NO context admission at all — the same
|
|
832
|
+
// lazy-Metal-wiring OOM this gate exists to prevent, one machine
|
|
833
|
+
// class down — and growth would price every token at the full
|
|
834
|
+
// slope.
|
|
847
835
|
const windowed = estimateWindowedKvLinearization({
|
|
848
836
|
blockCount: summary.blockCount,
|
|
849
837
|
embeddingLength: summary.embeddingLength,
|
|
@@ -864,42 +852,6 @@ export async function buildLlamaCppProvider(opts) {
|
|
|
864
852
|
ssmConvKernel: summary.ssmConvKernel,
|
|
865
853
|
kvCacheType,
|
|
866
854
|
});
|
|
867
|
-
if (swaFullAutoDefault) {
|
|
868
|
-
// Declining `--swa-full` dominates every full-math remedy:
|
|
869
|
-
// the context window is capability, the full cache is a
|
|
870
|
-
// session-switch performance trade. Weights-level admission
|
|
871
|
-
// stays with the capacity broker.
|
|
872
|
-
swaFullAutoFits = false;
|
|
873
|
-
const fastFitDetail = fullCacheFitsFastMemory === false && fullKvBytesAtRequested !== undefined
|
|
874
|
-
? `projected weights + full KV ${((residentBytes + fullKvBytesAtRequested) / 1024 ** 3).toFixed(1)} GiB exceeds available fast memory ${(Math.max(0, fastBudgetBytes - committedOtherBytes) / 1024 ** 3).toFixed(1)} GiB`
|
|
875
|
-
: undefined;
|
|
876
|
-
const overCeilingOnly = fullCacheOverCeiling &&
|
|
877
|
-
fullCacheFitsFastMemory !== false &&
|
|
878
|
-
admission.minimumSatisfied &&
|
|
879
|
-
admission.slots >= slots &&
|
|
880
|
-
!admission.clamped;
|
|
881
|
-
if (overCeilingOnly && fullKvBytesAtRequested !== undefined) {
|
|
882
|
-
// A policy choice on a machine that could hold the cache, not
|
|
883
|
-
// a shortage: info, not warn.
|
|
884
|
-
log.info([
|
|
885
|
-
`[llama-cpp] ${modelCatalogInfo?.id ?? 'model'}: the full SWA cache at the requested `,
|
|
886
|
-
`${effectiveNumCtx * slots}-token total context would take `,
|
|
887
|
-
`${(fullKvBytesAtRequested / 1024 ** 3).toFixed(1)} GiB, past the `,
|
|
888
|
-
`${(kvCeilingBytes / 1024 ** 3).toFixed(1)} GiB automatic KV ceiling — keeping the full `,
|
|
889
|
-
'context and declining the --swa-full auto-default instead; the windowed KV cache ',
|
|
890
|
-
'holds it (cross-request prefix reuse unavailable).',
|
|
891
|
-
].join(''));
|
|
892
|
-
}
|
|
893
|
-
else {
|
|
894
|
-
log.warn([
|
|
895
|
-
`[llama-cpp] ${modelCatalogInfo?.id ?? 'model'}: the full SWA working set at the requested `,
|
|
896
|
-
`${effectiveNumCtx * slots}-token total context does not fit fast memory — keeping the full `,
|
|
897
|
-
'context and declining the --swa-full auto-default instead; the windowed KV cache ',
|
|
898
|
-
'is what actually fits (cross-request prefix reuse unavailable). ',
|
|
899
|
-
`Fit detail: ${fastFitDetail ?? admission.reason ?? 'over budget at the requested slot count'}`,
|
|
900
|
-
].join(''));
|
|
901
|
-
}
|
|
902
|
-
}
|
|
903
855
|
if (windowed) {
|
|
904
856
|
ladderPlan = planCtxTokensForMemory({
|
|
905
857
|
requestedPerTurnCtxTokens: effectiveNumCtx,
|
|
@@ -917,16 +869,23 @@ export async function buildLlamaCppProvider(opts) {
|
|
|
917
869
|
fixedPerSlotBytes: windowed.fixedBytes,
|
|
918
870
|
};
|
|
919
871
|
}
|
|
920
|
-
else if (
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
872
|
+
else if (fullKvOverBudget &&
|
|
873
|
+
(explicitSwaFull === false
|
|
874
|
+
? (summary.slidingWindow ?? 0) > 0
|
|
875
|
+
: isGemmaModel({
|
|
876
|
+
architecture: modelCatalogInfo?.architecture,
|
|
877
|
+
modelId: defaultModelId ?? undefined,
|
|
878
|
+
}))) {
|
|
879
|
+
// A sliding-window model whose GGUF hides the layer layout,
|
|
880
|
+
// over budget on full math: that math over-states the real cache
|
|
881
|
+
// and there is no exact substitute — leave the launch alone
|
|
882
|
+
// rather than over-clamp.
|
|
924
883
|
ladderPlan = null;
|
|
925
884
|
ladderKvLinearization = null;
|
|
926
885
|
}
|
|
927
|
-
// else:
|
|
928
|
-
//
|
|
929
|
-
//
|
|
886
|
+
// else: no SWA layers at all, or a layout-less model that fits on
|
|
887
|
+
// full math — the full-attention plan stands (it IS the real
|
|
888
|
+
// allocation, or safely above it).
|
|
930
889
|
}
|
|
931
890
|
if (ladderPlan !== null && envNumCtx === undefined) {
|
|
932
891
|
const windowedNote = ladderPlan === admission ? '' : ' (windowed KV admission)';
|
|
@@ -989,19 +948,12 @@ export async function buildLlamaCppProvider(opts) {
|
|
|
989
948
|
}
|
|
990
949
|
}
|
|
991
950
|
// Price the KV the engine will ACTUALLY allocate. Mirrors the
|
|
992
|
-
// `--swa-full`
|
|
993
|
-
//
|
|
994
|
-
//
|
|
995
|
-
//
|
|
996
|
-
//
|
|
997
|
-
|
|
998
|
-
const effectiveSwaFull = config.llamaCppSwaFull ??
|
|
999
|
-
manifestEngineConfig?.swaFull ??
|
|
1000
|
-
(swaFullAutoFits !== false &&
|
|
1001
|
-
isGemmaModel({
|
|
1002
|
-
architecture: modelCatalogInfo?.architecture,
|
|
1003
|
-
modelId: defaultModelId ?? undefined,
|
|
1004
|
-
}));
|
|
951
|
+
// opt-in `--swa-full` in buildLlamaCppEngineArgs: an SWA model on the
|
|
952
|
+
// default windowed cache carries only its global layers per token
|
|
953
|
+
// plus a fixed window block per slot. Feeding the offload planner
|
|
954
|
+
// full-attention math for a windowed launch over-biased Gemma experts
|
|
955
|
+
// into system RAM for a cache that never materializes.
|
|
956
|
+
const effectiveSwaFull = config.llamaCppSwaFull ?? manifestEngineConfig?.swaFull ?? false;
|
|
1005
957
|
const windowedKvPlan = effectiveSwaFull
|
|
1006
958
|
? undefined
|
|
1007
959
|
: estimateWindowedKvLinearization({
|
|
@@ -1024,9 +976,9 @@ export async function buildLlamaCppProvider(opts) {
|
|
|
1024
976
|
ssmConvKernel: summary.ssmConvKernel,
|
|
1025
977
|
kvCacheType,
|
|
1026
978
|
});
|
|
1027
|
-
const
|
|
1028
|
-
? Math.round(windowedKvPlan.fixedBytes *
|
|
1029
|
-
windowedKvPlan.bytesPerToken * effectiveNumCtx *
|
|
979
|
+
const kvReserveFor = (slotCount) => windowedKvPlan
|
|
980
|
+
? Math.round(windowedKvPlan.fixedBytes * slotCount +
|
|
981
|
+
windowedKvPlan.bytesPerToken * effectiveNumCtx * slotCount)
|
|
1030
982
|
: estimateKvReserveBytes({
|
|
1031
983
|
blockCount: summary.blockCount,
|
|
1032
984
|
embeddingLength: summary.embeddingLength,
|
|
@@ -1044,43 +996,47 @@ export async function buildLlamaCppProvider(opts) {
|
|
|
1044
996
|
ssmInnerSize: summary.ssmInnerSize,
|
|
1045
997
|
ssmStateSize: summary.ssmStateSize,
|
|
1046
998
|
ssmConvKernel: summary.ssmConvKernel,
|
|
1047
|
-
ctxTokens: effectiveNumCtx *
|
|
999
|
+
ctxTokens: effectiveNumCtx * slotCount,
|
|
1048
1000
|
kvCacheType,
|
|
1049
1001
|
});
|
|
1050
|
-
//
|
|
1051
|
-
//
|
|
1052
|
-
// the
|
|
1053
|
-
//
|
|
1054
|
-
//
|
|
1055
|
-
//
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1002
|
+
// Plan against the card as it is now. Sized to the whole card, a plan
|
|
1003
|
+
// counts memory other programs hold: MoE admission then charged the
|
|
1004
|
+
// model the whole card and refused it (2026-10-11), and a dense
|
|
1005
|
+
// 31B planned into 30.3 GiB of a 32 GB card that the desktop and its
|
|
1006
|
+
// apps were already holding ~5 GB of died with a Vulkan out-of-memory
|
|
1007
|
+
// (2026-10-19).
|
|
1008
|
+
const freeGpuBytes = vramBytes > 0 ? await measureAvailableGpuBytes().catch(() => undefined) : undefined;
|
|
1009
|
+
// A lane count the person chose is not the planner's to spend, and
|
|
1010
|
+
// eval runs under GEZEL_LLAMA_NUM_CTX accept the memory consequences.
|
|
1011
|
+
const mayShedSlots = configuredSlots === undefined && envNumCtx === undefined;
|
|
1012
|
+
const placeSlots = (gpuBytes, plan) => mayShedSlots
|
|
1013
|
+
? shedSlotsForGpuResidency({ slots, vramBytes: gpuBytes, plan })
|
|
1014
|
+
: { slots, decision: plan(slots, gpuBytes), shed: false };
|
|
1015
|
+
let placement;
|
|
1059
1016
|
if (isMoE) {
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
: {}),
|
|
1017
|
+
placement = placeSlots(freeGpuBytes !== undefined ? Math.min(vramBytes, freeGpuBytes) : vramBytes, (slotCount, gpuBytes) => {
|
|
1018
|
+
const kvReserveBytes = kvReserveFor(slotCount);
|
|
1019
|
+
return planMoeOffload({
|
|
1020
|
+
isMoE,
|
|
1021
|
+
residentBytes,
|
|
1022
|
+
vramBytes: gpuBytes,
|
|
1023
|
+
...(split
|
|
1024
|
+
? {
|
|
1025
|
+
split,
|
|
1026
|
+
...(summary.blockCount !== undefined ? { blockCount: summary.blockCount } : {}),
|
|
1027
|
+
...(kvReserveBytes !== undefined ? { kvReserveBytes } : {}),
|
|
1028
|
+
}
|
|
1029
|
+
: {}),
|
|
1030
|
+
});
|
|
1075
1031
|
});
|
|
1076
|
-
offloadDecision =
|
|
1032
|
+
offloadDecision = placement.decision;
|
|
1077
1033
|
// An explicit offload setting shadows the planner's flags, so its
|
|
1078
1034
|
// footprint would describe a launch that is not the one made.
|
|
1079
1035
|
const plannerPlacesExperts = (config.llamaCppCpuMoe ?? resolvedManifestEngineConfig?.cpuMoe) === undefined &&
|
|
1080
1036
|
(config.llamaCppNCpuMoe ?? resolvedManifestEngineConfig?.nCpuMoe) === undefined &&
|
|
1081
1037
|
(config.llamaCppNGpuLayers ?? resolvedManifestEngineConfig?.nGpuLayers) === undefined;
|
|
1082
1038
|
if (plannerPlacesExperts)
|
|
1083
|
-
plannedGpuBytes =
|
|
1039
|
+
plannedGpuBytes = placement.decision.gpuBytes;
|
|
1084
1040
|
}
|
|
1085
1041
|
else {
|
|
1086
1042
|
const explicitNCpuFfn = config.llamaCppNCpuFfn ?? resolvedManifestEngineConfig?.nCpuFfn;
|
|
@@ -1089,16 +1045,21 @@ export async function buildLlamaCppProvider(opts) {
|
|
|
1089
1045
|
// A finite whole-layer GPU count is a different placement strategy;
|
|
1090
1046
|
// don't layer an automatic tensor override on top of it. `-1` means
|
|
1091
1047
|
// all and is compatible with the planner's own attention-on-GPU plan.
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1048
|
+
if (explicitNCpuFfn === undefined &&
|
|
1049
|
+
(explicitNGpuLayers === undefined || explicitNGpuLayers === -1)) {
|
|
1050
|
+
placement = placeSlots(
|
|
1051
|
+
// Respect the usable accelerator pool, any explicit capacity
|
|
1052
|
+
// ceiling, co-resident reservations, and what other programs
|
|
1053
|
+
// hold on the card now. The raw probe still gates this to a real
|
|
1054
|
+
// discrete-GPU build rather than treating a CPU/unified fast pool
|
|
1055
|
+
// as VRAM.
|
|
1056
|
+
vramBytes > 0
|
|
1057
|
+
? Math.max(0, Math.min(budgetBytes - committedOtherBytes, freeGpuBytes ?? Number.POSITIVE_INFINITY))
|
|
1058
|
+
: 0, (slotCount, gpuBytes) => {
|
|
1059
|
+
const kvReserveBytes = kvReserveFor(slotCount);
|
|
1060
|
+
return planDenseFfnOffload({
|
|
1096
1061
|
isMoE,
|
|
1097
|
-
|
|
1098
|
-
// ceiling, and co-resident reservations. The raw probe still
|
|
1099
|
-
// gates this to a real discrete-GPU build rather than treating
|
|
1100
|
-
// a CPU/unified fast pool as VRAM.
|
|
1101
|
-
vramBytes: vramBytes > 0 ? Math.max(0, budgetBytes - committedOtherBytes) : 0,
|
|
1062
|
+
vramBytes: gpuBytes,
|
|
1102
1063
|
...(denseFfnSplit ? { split: denseFfnSplit } : {}),
|
|
1103
1064
|
...(summary.blockCount !== undefined ? { blockCount: summary.blockCount } : {}),
|
|
1104
1065
|
...(kvReserveBytes !== undefined ? { kvReserveBytes } : {}),
|
|
@@ -1107,9 +1068,30 @@ export async function buildLlamaCppProvider(opts) {
|
|
|
1107
1068
|
? brokerSnap.pools.ramShareBytes
|
|
1108
1069
|
: hostCapacity.ramShareBytes,
|
|
1109
1070
|
freeSystemRamBytes: availableSystemRamBytes(),
|
|
1110
|
-
})
|
|
1111
|
-
|
|
1071
|
+
});
|
|
1072
|
+
});
|
|
1073
|
+
offloadDecision = placement.decision;
|
|
1074
|
+
}
|
|
1075
|
+
else {
|
|
1076
|
+
offloadDecision = undefined;
|
|
1077
|
+
}
|
|
1112
1078
|
}
|
|
1079
|
+
if (placement?.shed) {
|
|
1080
|
+
log.info(`[llama-cpp] ${modelCatalogInfo?.id ?? 'model'}: reducing engine slots ${slots} -> 1 to keep the model on the GPU with room to spare (other programs' graphics memory moves)`);
|
|
1081
|
+
slots = 1;
|
|
1082
|
+
}
|
|
1083
|
+
// The broker-ledger reservation for this launch: resident weights
|
|
1084
|
+
// plus the KV the engine will allocate at the granted window (M1 —
|
|
1085
|
+
// the weights-only ledger under-reserved dense models whose KV
|
|
1086
|
+
// rivals their weights: qwen3.5-4b at 64K carries more KV than
|
|
1087
|
+
// parameters). Consumed by the pool builder via
|
|
1088
|
+
// `plannedReservationBytes` so co-residency admission can see it.
|
|
1089
|
+
const kvReserveBytes = kvReserveFor(slots);
|
|
1090
|
+
if (kvReserveBytes !== undefined) {
|
|
1091
|
+
plannedReservationBytes = residentBytes + kvReserveBytes;
|
|
1092
|
+
}
|
|
1093
|
+
reservationKvFor = kvReserveFor;
|
|
1094
|
+
reservationResidentBytes = residentBytes;
|
|
1113
1095
|
if (offloadDecision?.reason) {
|
|
1114
1096
|
log.info(`[llama-cpp] offload plan (${modelCatalogInfo?.id ?? 'model'}): ${offloadDecision.reason}`);
|
|
1115
1097
|
}
|
|
@@ -1202,44 +1184,105 @@ export async function buildLlamaCppProvider(opts) {
|
|
|
1202
1184
|
if (snapshot.expected)
|
|
1203
1185
|
return;
|
|
1204
1186
|
logFile.writeIncident(snapshot);
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
// Deliberately narrow: only SIGILL, and only before readiness.
|
|
1212
|
-
// A SIGSEGV during startup can be a corrupt model file, and any
|
|
1213
|
-
// crash after readiness is attributable to the work rather than
|
|
1214
|
-
// the binary — quarantining a backend over either would demote
|
|
1215
|
-
// users to slow engines for transient reasons.
|
|
1216
|
-
if (snapshot.signal !== 'SIGILL' || snapshot.reachedReady)
|
|
1187
|
+
if (snapshot.panicKind === 'host-out-of-memory') {
|
|
1188
|
+
noteHostOutOfMemory({
|
|
1189
|
+
model: modelCatalogInfo?.id ?? defaultModelId,
|
|
1190
|
+
whileStarting: !snapshot.reachedReady,
|
|
1191
|
+
});
|
|
1192
|
+
log.warn(`[llama-server] Linux's out-of-memory killer stopped the engine (${modelCatalogInfo?.id ?? 'model'}, incident=${snapshot.incidentId}, ${snapshot.reachedReady ? 'while serving' : 'while loading'})`);
|
|
1217
1193
|
return;
|
|
1218
|
-
|
|
1219
|
-
|
|
1194
|
+
}
|
|
1195
|
+
// A build that dies before it ever answers /health, without saying
|
|
1196
|
+
// why, may not be able to run here at all — and relaunching it on every
|
|
1197
|
+
// request just reproduces the crash while a working lower-tier build
|
|
1198
|
+
// sits in the next directory. Count it; a few in a row write it down so
|
|
1199
|
+
// the next launch routes around it. Which exits qualify (a silent
|
|
1200
|
+
// SIGILL; a GPU build's silent crash status on Windows or signal on
|
|
1201
|
+
// Linux; a CUDA build with no code for this GPU) is decided in
|
|
1202
|
+
// unrunnable-build.ts, how many in llama-quarantine.ts.
|
|
1203
|
+
const backend = binaryBackend;
|
|
1204
|
+
const unrunnable = unrunnableBuildExit(snapshot, backend);
|
|
1205
|
+
if (!backend || !unrunnable)
|
|
1220
1206
|
return;
|
|
1221
|
-
const entry =
|
|
1207
|
+
const { strikes, entry } = recordLlamaStartupCrash(home, {
|
|
1222
1208
|
backend,
|
|
1223
1209
|
binaryPath: binary,
|
|
1224
|
-
signal:
|
|
1225
|
-
reason:
|
|
1226
|
-
'this machine does not support, or faulted inside GPU library startup',
|
|
1210
|
+
signal: unrunnable.signal,
|
|
1211
|
+
reason: unrunnable.reason,
|
|
1227
1212
|
});
|
|
1228
|
-
if (entry) {
|
|
1229
|
-
|
|
1213
|
+
if (!entry) {
|
|
1214
|
+
if (strikes === 0)
|
|
1215
|
+
return;
|
|
1216
|
+
lastStartupCrash = {
|
|
1217
|
+
incidentId: snapshot.incidentId,
|
|
1218
|
+
verdict: { kind: 'strike', strikes, threshold: LLAMA_QUARANTINE_STRIKES },
|
|
1219
|
+
};
|
|
1220
|
+
log.warn(`[llama-server] the ${backend} build crashed before it was ready (${unrunnable.signal}, incident=${snapshot.incidentId}); ${strikes} of ${LLAMA_QUARANTINE_STRIKES} in a row switch it off`);
|
|
1221
|
+
return;
|
|
1222
|
+
}
|
|
1223
|
+
log.warn(`[llama-server] quarantined the ${backend} build after ${strikes} crashes in a row (${unrunnable.signal}, incident=${snapshot.incidentId}); the next launch will fall back to another backend`);
|
|
1224
|
+
// Discovery reads the quarantine only at startup. Point the env at the
|
|
1225
|
+
// fallback now, so the pool's rebuild of this failed engine on the next
|
|
1226
|
+
// request launches it instead of the build just written down. A pinned
|
|
1227
|
+
// backend is a decision, and discovery never routes around one either;
|
|
1228
|
+
// an env that has already moved on belongs to someone else's fallback.
|
|
1229
|
+
const pinned = config.llamaCppBackendOverride !== undefined && config.llamaCppBackendOverride !== 'auto';
|
|
1230
|
+
const fallback = pinned || process.env.GEZEL_LLAMA_SERVER_BIN !== binary
|
|
1231
|
+
? null
|
|
1232
|
+
: adoptLlamaFallback(home, binary, backend);
|
|
1233
|
+
lastStartupCrash = {
|
|
1234
|
+
incidentId: snapshot.incidentId,
|
|
1235
|
+
verdict: { kind: 'quarantined', ...(fallback ? { switchedTo: fallback.backend } : {}) },
|
|
1236
|
+
};
|
|
1237
|
+
if (fallback) {
|
|
1238
|
+
log.warn(`[llama-server] the next launch uses the ${fallback.backend} build: ${fallback.path}`);
|
|
1230
1239
|
}
|
|
1231
1240
|
},
|
|
1232
|
-
|
|
1233
|
-
//
|
|
1234
|
-
//
|
|
1235
|
-
//
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1241
|
+
// Any start that reaches readiness proves the build runs here, so the
|
|
1242
|
+
// crashes before it were not in a row. It does not prove the build got
|
|
1243
|
+
// its GPU: a GPU backend that cannot load or initialize leaves the engine
|
|
1244
|
+
// on the CPU without crashing (gpu-startup-watch.ts).
|
|
1245
|
+
onReady: () => {
|
|
1246
|
+
if (binaryBackend)
|
|
1247
|
+
clearLlamaStartupStrikes(home, binaryBackend);
|
|
1248
|
+
const unused = gpuWatch?.verdict() ?? null;
|
|
1249
|
+
noteGpuStartup(unused);
|
|
1250
|
+
if (unused) {
|
|
1251
|
+
log.warn(`[llama-server] the ${unused.backend} build started without its GPU (${unused.reason}${unused.detail ? `: ${unused.detail}` : ''}); every token runs on the CPU`);
|
|
1252
|
+
}
|
|
1253
|
+
},
|
|
1254
|
+
onRawLine: (line) => {
|
|
1255
|
+
gpuWatch?.observe(line);
|
|
1256
|
+
providerHolder.current?.onStdoutLine(line);
|
|
1257
|
+
},
|
|
1258
|
+
// GPU-OOM recovery ladder: when a start dies of VRAM exhaustion, first
|
|
1259
|
+
// give back the extra slots' KV (every weight stays on the GPU), then, if
|
|
1260
|
+
// the planner's offload decision was in play, degrade it one step
|
|
1261
|
+
// (partial split → all expert/FFN weights to RAM → engine-owned fit) and
|
|
1262
|
+
// let the supervisor retry — `resolveLaunch` below re-reads `slots` and
|
|
1263
|
+
// `offloadDecision` on every spawn. The degraded plan sticks for later
|
|
1264
|
+
// restarts of this provider, so a recovered engine doesn't re-OOM on its
|
|
1265
|
+
// next boot.
|
|
1239
1266
|
recoverStartup: ({ panicKind }) => {
|
|
1240
1267
|
if (panicKind !== 'cuda-out-of-memory' && panicKind !== 'vulkan-out-of-memory') {
|
|
1241
1268
|
return false;
|
|
1242
1269
|
}
|
|
1270
|
+
// A full-residency plan has no offload rung below it, so before this a
|
|
1271
|
+
// two-slot launch that missed by one KV allocation failed outright
|
|
1272
|
+
// (2026-10-19, Gemma 4 31B on a 32 GB card). This rung spends one of
|
|
1273
|
+
// the supervisor's two retries; an offload rung still has the other.
|
|
1274
|
+
if (slots > 1 && configuredSlots === undefined) {
|
|
1275
|
+
const from = slots;
|
|
1276
|
+
if (providerHolder.current?.narrowEngineSlots(1)) {
|
|
1277
|
+
slots = 1;
|
|
1278
|
+
const kvReserveBytes = reservationKvFor?.(1);
|
|
1279
|
+
if (kvReserveBytes !== undefined && reservationResidentBytes !== undefined) {
|
|
1280
|
+
plannedReservationBytes = reservationResidentBytes + kvReserveBytes;
|
|
1281
|
+
}
|
|
1282
|
+
log.warn(`[llama-cpp] ${panicKind} while starting ${modelCatalogInfo?.id ?? 'model'} — retrying with one engine slot instead of ${from}`);
|
|
1283
|
+
return true;
|
|
1284
|
+
}
|
|
1285
|
+
}
|
|
1243
1286
|
// Explicit config/manifest offload settings shadow the planner
|
|
1244
1287
|
// per-field (see `buildLlamaCppEngineArgs`); when every field the
|
|
1245
1288
|
// ladder would change is pinned, a retry replays the same argv.
|
|
@@ -1275,6 +1318,13 @@ export async function buildLlamaCppProvider(opts) {
|
|
|
1275
1318
|
return true;
|
|
1276
1319
|
},
|
|
1277
1320
|
resolveLaunch: async () => {
|
|
1321
|
+
gpuWatch = new GpuStartupWatch(binaryBackend);
|
|
1322
|
+
// Again at every launch, not only at build: llama.cpp from the 0.1.51
|
|
1323
|
+
// release refuses a --slot-save-path that does not exist ("not a
|
|
1324
|
+
// directory") and exits before ready, and an eval preflight lost its
|
|
1325
|
+
// build-time directory during a 50 s capacity wait (2026-10-18). The
|
|
1326
|
+
// person saw "no model is installed yet".
|
|
1327
|
+
await mkdirAsync(slotSavePath, { recursive: true }).catch(() => { });
|
|
1278
1328
|
const port = cachedPort ?? (await pickFreePort());
|
|
1279
1329
|
cachedPort = port;
|
|
1280
1330
|
// Prepend the binary's own directory to PATH so the OS finds the
|
|
@@ -1301,9 +1351,6 @@ export async function buildLlamaCppProvider(opts) {
|
|
|
1301
1351
|
// model output reaches `delta.content` for provider-side salvage.
|
|
1302
1352
|
reasoningFormat: process.env.GEZEL_LLAMA_REASONING_FORMAT?.trim() || undefined,
|
|
1303
1353
|
reasoningPreserve,
|
|
1304
|
-
architecture: modelCatalogInfo?.architecture,
|
|
1305
|
-
modelId: defaultModelId ?? undefined,
|
|
1306
|
-
swaFullAutoFits,
|
|
1307
1354
|
backend: llamaBuildMetadata?.backend ?? process.env.GEZEL_LLAMA_SERVER_BACKEND,
|
|
1308
1355
|
hostCpuCount: availableParallelism(),
|
|
1309
1356
|
});
|
|
@@ -1454,6 +1501,7 @@ export async function buildLlamaCppProvider(opts) {
|
|
|
1454
1501
|
supervisor,
|
|
1455
1502
|
logFile,
|
|
1456
1503
|
slotSavePath,
|
|
1504
|
+
startupCrashVerdict: (incidentId) => lastStartupCrash?.incidentId === incidentId ? lastStartupCrash.verdict : undefined,
|
|
1457
1505
|
// Lets `listModels()` enumerate every installed model (not just
|
|
1458
1506
|
// the resident one) so `/v1/models` + pickers see the full set
|
|
1459
1507
|
// the engine pool can serve.
|