@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
|
@@ -8,9 +8,10 @@ import { redactPathSecrets } from './redact-path.js';
|
|
|
8
8
|
/**
|
|
9
9
|
* Main-thread responsiveness monitor.
|
|
10
10
|
*
|
|
11
|
-
* The daemon runs on one event loop.
|
|
12
|
-
* packaged fallback) that loop is
|
|
13
|
-
*
|
|
11
|
+
* The daemon runs on one event loop. With an in-process embedded service (the
|
|
12
|
+
* packaged fallback, E2E, `GEZEL_SERVICE_HOST=in-process`) that loop is
|
|
13
|
+
* Electron's main thread, so a synchronous block here freezes the window
|
|
14
|
+
* itself, and Windows labels it "Not Responding"
|
|
14
15
|
* after 5 s. Before this existed a block under the suspend monitor's 10 s floor
|
|
15
16
|
* left no trace, and a longer one was logged as "host resumed after Ns
|
|
16
17
|
* suspended": sleep that never happened (two of them during one catalog
|
|
@@ -33,7 +34,7 @@ const log = createLogger('perf');
|
|
|
33
34
|
/**
|
|
34
35
|
* A gap is measured to within one beat, so this has to stay well inside
|
|
35
36
|
* `STALL_RECORD_MS`. At the same period, a pause long enough to log leaves the
|
|
36
|
-
* watchdog late by more than half the
|
|
37
|
+
* watchdog late by more than half the heartbeat's lateness, which is what `isMainThreadBlock`
|
|
37
38
|
* needs to rule the main thread out.
|
|
38
39
|
*/
|
|
39
40
|
export const BEAT_MS = 250;
|
|
@@ -55,10 +56,17 @@ const PROFILE_WINDOW_MS = 60_000;
|
|
|
55
56
|
const PROFILE_SAMPLING_US = 5_000;
|
|
56
57
|
const PROFILE_KEEP = 20;
|
|
57
58
|
const LABEL_MAX = 200;
|
|
59
|
+
/**
|
|
60
|
+
* A watchdog tick later than this is kept. Half the smallest recordable
|
|
61
|
+
* lateness: a shorter one cannot rule the main thread out. The floor was a
|
|
62
|
+
* whole period, which threw away the witness's own evidence of a sub-second
|
|
63
|
+
* pause of the whole process, so such pauses were filed as main-thread blocks
|
|
64
|
+
* (idle processes on a swapping machine collected dozens a minute).
|
|
65
|
+
*/
|
|
66
|
+
const WATCHDOG_KEEP_LATE_MS = (STALL_RECORD_MS - BEAT_MS) / 2;
|
|
58
67
|
/**
|
|
59
68
|
* The witness. It keeps its own late ticks and, asked about a gap, answers
|
|
60
|
-
* with the worst one since the gap began.
|
|
61
|
-
* not kept: it cannot reach half of a recordable gap.
|
|
69
|
+
* with the worst one since the gap began.
|
|
62
70
|
*
|
|
63
71
|
* It sleeps on a futex instead of running an event loop: a worker woken by its
|
|
64
72
|
* own timer cost about 1.6 context switches per tick on Windows, against 1.0
|
|
@@ -69,6 +77,7 @@ const LABEL_MAX = 200;
|
|
|
69
77
|
const WATCHDOG_SOURCE = `
|
|
70
78
|
const { parentPort, receiveMessageOnPort, workerData } = require('node:worker_threads');
|
|
71
79
|
const tickMs = workerData.tickMs;
|
|
80
|
+
const keepLateMs = workerData.keepLateMs;
|
|
72
81
|
const asked = new Int32Array(workerData.asked);
|
|
73
82
|
const lateTicks = [];
|
|
74
83
|
let lastTick = Date.now();
|
|
@@ -78,7 +87,7 @@ for (;;) {
|
|
|
78
87
|
if (now - lastTick >= tickMs) {
|
|
79
88
|
const lateMs = now - lastTick - tickMs;
|
|
80
89
|
lastTick = now;
|
|
81
|
-
if (lateMs >=
|
|
90
|
+
if (lateMs >= keepLateMs) {
|
|
82
91
|
lateTicks.push({ at: now, lateMs });
|
|
83
92
|
if (lateTicks.length > 32) lateTicks.shift();
|
|
84
93
|
}
|
|
@@ -98,9 +107,52 @@ for (;;) {
|
|
|
98
107
|
* A stale heartbeat is a main-thread block only when the watchdog itself kept
|
|
99
108
|
* time. When the watchdog was late by a comparable amount, the process or the
|
|
100
109
|
* host was paused, and blaming whatever was in flight would be a false lead.
|
|
110
|
+
*
|
|
111
|
+
* Lateness against lateness: both threads sleep a beat between checks, so a
|
|
112
|
+
* pause delays each by about its length. Comparing the watchdog's lateness
|
|
113
|
+
* with the whole gap, beat included, filed short pauses as blocks.
|
|
101
114
|
*/
|
|
102
115
|
export function isMainThreadBlock(report) {
|
|
103
|
-
return report.watchdogLateMs < report.durationMs / 2;
|
|
116
|
+
return report.watchdogLateMs < (report.durationMs - BEAT_MS) / 2;
|
|
117
|
+
}
|
|
118
|
+
/** Fewer page faults than this in a stall is ordinary; more, with the thread idle, is swap. */
|
|
119
|
+
const PAGING_MIN_FAULTS = 10;
|
|
120
|
+
/**
|
|
121
|
+
* Read at every beat. Both are single syscalls and add no wakeups. A stall's
|
|
122
|
+
* duration alone cannot say whether code ran: on a memory-starved machine most
|
|
123
|
+
* logged stalls were the thread waiting for its own pages to come back from
|
|
124
|
+
* swap, and their CPU profiles held no samples at all.
|
|
125
|
+
*/
|
|
126
|
+
function readStallCounters() {
|
|
127
|
+
const threadCpuUsage = process.threadCpuUsage;
|
|
128
|
+
const cpu = typeof threadCpuUsage === 'function' ? threadCpuUsage() : null;
|
|
129
|
+
return {
|
|
130
|
+
cpuMs: cpu ? (cpu.user + cpu.system) / 1_000 : null,
|
|
131
|
+
pageFaults: process.resourceUsage().majorPageFault,
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
function stallCostBetween(before, after) {
|
|
135
|
+
return {
|
|
136
|
+
cpuMs: before.cpuMs !== null && after.cpuMs !== null
|
|
137
|
+
? Math.max(0, Math.round(after.cpuMs - before.cpuMs))
|
|
138
|
+
: null,
|
|
139
|
+
pageFaults: Math.max(0, after.pageFaults - before.pageFaults),
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
/** Running code when it used at least half the stall; otherwise paging or waiting on something. */
|
|
143
|
+
export function stallVerdict(durationMs, cost) {
|
|
144
|
+
if (cost.cpuMs === null)
|
|
145
|
+
return undefined;
|
|
146
|
+
if (cost.cpuMs >= durationMs / 2)
|
|
147
|
+
return 'running code';
|
|
148
|
+
return cost.pageFaults >= PAGING_MIN_FAULTS ? 'paging' : 'blocked waiting';
|
|
149
|
+
}
|
|
150
|
+
export function describeStallCost(durationMs, cost) {
|
|
151
|
+
const faults = `${cost.pageFaults} page fault${cost.pageFaults === 1 ? '' : 's'}`;
|
|
152
|
+
const verdict = stallVerdict(durationMs, cost);
|
|
153
|
+
if (cost.cpuMs === null)
|
|
154
|
+
return faults;
|
|
155
|
+
return `cpu ${formatPerfMs(cost.cpuMs)}, ${faults}${verdict ? `: ${verdict}` : ''}`;
|
|
104
156
|
}
|
|
105
157
|
/**
|
|
106
158
|
* Work that overlapped `[start, end]`, most suspicious first. Running work
|
|
@@ -295,6 +347,10 @@ class ResponsivenessMonitor {
|
|
|
295
347
|
*/
|
|
296
348
|
awaitingVerdicts = 0;
|
|
297
349
|
rollDeferred = false;
|
|
350
|
+
/** Counters at the last beat, so a gap's cost is the difference at the next one. */
|
|
351
|
+
lastBeatCost = readStallCounters();
|
|
352
|
+
/** What each gap awaiting a verdict cost, keyed by its start. */
|
|
353
|
+
gapCosts = new Map();
|
|
298
354
|
constructor(opts) {
|
|
299
355
|
this.beatTimer = setInterval(() => this.beat(), BEAT_MS);
|
|
300
356
|
this.beatTimer.unref?.();
|
|
@@ -396,11 +452,15 @@ class ResponsivenessMonitor {
|
|
|
396
452
|
this.lastBeatAt = now;
|
|
397
453
|
const gapMs = now - startedAt;
|
|
398
454
|
this.delay.record(Math.max(1, Math.round((gapMs - BEAT_MS) * 1e6)));
|
|
455
|
+
const counters = readStallCounters();
|
|
456
|
+
const before = this.lastBeatCost;
|
|
457
|
+
this.lastBeatCost = counters;
|
|
399
458
|
if (gapMs < STALL_RECORD_MS || !this.watchdog) {
|
|
400
459
|
if (this.rollDeferred && this.awaitingVerdicts === 0)
|
|
401
460
|
this.rollProfile();
|
|
402
461
|
return;
|
|
403
462
|
}
|
|
463
|
+
this.gapCosts.set(startedAt, stallCostBetween(before, counters));
|
|
404
464
|
this.awaitingVerdicts += 1;
|
|
405
465
|
this.watchdog.postMessage({ startedAt, durationMs: gapMs });
|
|
406
466
|
Atomics.store(this.watchdogAsked, 0, 1);
|
|
@@ -420,7 +480,11 @@ class ResponsivenessMonitor {
|
|
|
420
480
|
try {
|
|
421
481
|
const worker = new Worker(WATCHDOG_SOURCE, {
|
|
422
482
|
eval: true,
|
|
423
|
-
workerData: {
|
|
483
|
+
workerData: {
|
|
484
|
+
tickMs: WATCHDOG_TICK_MS,
|
|
485
|
+
keepLateMs: WATCHDOG_KEEP_LATE_MS,
|
|
486
|
+
asked: this.watchdogAsked.buffer,
|
|
487
|
+
},
|
|
424
488
|
});
|
|
425
489
|
worker.on('message', (report) => this.onWatchdogReport(report));
|
|
426
490
|
worker.on('error', (err) => {
|
|
@@ -440,13 +504,19 @@ class ResponsivenessMonitor {
|
|
|
440
504
|
this.rollProfile();
|
|
441
505
|
}
|
|
442
506
|
handleReport(report) {
|
|
507
|
+
const cost = this.gapCosts.get(report.startedAt);
|
|
508
|
+
this.gapCosts.delete(report.startedAt);
|
|
443
509
|
if (!isMainThreadBlock(report))
|
|
444
510
|
return;
|
|
445
511
|
const now = Date.now();
|
|
512
|
+
const verdict = cost ? stallVerdict(report.durationMs, cost) : undefined;
|
|
446
513
|
const stall = {
|
|
447
514
|
at: new Date(report.startedAt).toISOString(),
|
|
448
515
|
durationMs: report.durationMs,
|
|
449
516
|
during: workDuring(report.startedAt, report.startedAt + report.durationMs, this.active.values(), this.finished, now),
|
|
517
|
+
...(cost?.cpuMs != null ? { cpuMs: cost.cpuMs } : {}),
|
|
518
|
+
...(cost ? { pageFaults: cost.pageFaults } : {}),
|
|
519
|
+
...(verdict ? { verdict } : {}),
|
|
450
520
|
};
|
|
451
521
|
pushRing(this.stalls, stall);
|
|
452
522
|
if (report.durationMs < STALL_LOG_MS)
|
|
@@ -454,7 +524,8 @@ class ResponsivenessMonitor {
|
|
|
454
524
|
const running = stall.during.length > 0
|
|
455
525
|
? stall.during.map((w) => `${w.label} (${formatPerfMs(w.durationMs)})`).join(', ')
|
|
456
526
|
: 'nothing tracked';
|
|
457
|
-
const
|
|
527
|
+
const costText = cost ? ` (${describeStallCost(report.durationMs, cost)})` : '';
|
|
528
|
+
const line = `main thread blocked for ${formatPerfMs(report.durationMs)}${costText} — running: ${running}`;
|
|
458
529
|
if (report.durationMs >= STALL_WARN_MS)
|
|
459
530
|
log.warn(line);
|
|
460
531
|
else
|
|
@@ -75,7 +75,7 @@ export class KokoroFrontend {
|
|
|
75
75
|
// put it back, because a packaging slip is the likely cause.
|
|
76
76
|
throw new Error(`Kokoro pronunciation dictionary is missing at ${file}; rebuild the service (node scripts/build-kokoro-lexicon.mjs stages it).`, { cause });
|
|
77
77
|
}
|
|
78
|
-
return parseKokoroLexicon(gunzipSync(packed).toString('utf8'));
|
|
78
|
+
return parseKokoroLexicon(gunzipSync(packed).toString('utf8'), { language });
|
|
79
79
|
})();
|
|
80
80
|
// A failed read must not be cached as a permanent failure.
|
|
81
81
|
void pending.catch(() => this.loaded.delete(language));
|
|
@@ -526,12 +526,18 @@ export async function buildDs4Provider(opts) {
|
|
|
526
526
|
return { command: binary, args, baseUrl: `http://127.0.0.1:${port}`, cwd: ds4BundleDir };
|
|
527
527
|
},
|
|
528
528
|
});
|
|
529
|
+
// Sessions budget prompts, `max_tokens`, and compaction against this window,
|
|
530
|
+
// so it must be the `--ctx` ds4 actually launches with. Left unset, it fell
|
|
531
|
+
// back to the 64K llama default: GLM 5.3 (launched at 32K) overflowed with
|
|
532
|
+
// `context_length_exceeded` long before compaction triggered, and DeepSeek
|
|
533
|
+
// (launched at 128K) compacted at a third of its window.
|
|
529
534
|
const ds4Inner = new LlamaCppProvider({
|
|
530
535
|
supervisor,
|
|
531
536
|
logFile: ds4LogFile,
|
|
532
537
|
disableThinkingRequestShape: 'deepseek',
|
|
533
538
|
classifyLine: classifyDs4Line,
|
|
534
539
|
visionEnabled: vision.enabled,
|
|
540
|
+
numCtx,
|
|
535
541
|
...baseProviderOpts,
|
|
536
542
|
});
|
|
537
543
|
ds4ProviderHolder.current = ds4Inner;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Whether llama-server is getting the hardware this machine has, as the
|
|
3
|
+
* engine process sees it: the CUDA build discovery passed over for the
|
|
4
|
+
* driver (`GEZEL_LLAMA_CUDA_BLOCKER`), a GPU build that started without its
|
|
5
|
+
* GPU (gpu-startup-watch.ts), and Linux's out-of-memory killer stopping the
|
|
6
|
+
* engine. Each is invisible otherwise — the engine keeps answering, slower,
|
|
7
|
+
* or a chat fails with a crash that reads like any other.
|
|
8
|
+
*
|
|
9
|
+
* Process-wide like the backend env it sits beside: every llama provider in
|
|
10
|
+
* this process launches the same build.
|
|
11
|
+
*/
|
|
12
|
+
import type { LlamaCppBackendHealthResponse } from '@bendyline/gezel';
|
|
13
|
+
import type { GpuUnused } from './gpu-startup-watch.js';
|
|
14
|
+
/** Record what the latest start of a build found; null clears it. */
|
|
15
|
+
export declare function noteGpuStartup(verdict: GpuUnused | null, now?: Date): void;
|
|
16
|
+
export declare function noteHostOutOfMemory(input: {
|
|
17
|
+
model?: string | undefined;
|
|
18
|
+
whileStarting: boolean;
|
|
19
|
+
}, now?: Date): void;
|
|
20
|
+
declare const BACKENDS: readonly ["cuda", "vulkan", "metal", "cpu"];
|
|
21
|
+
/**
|
|
22
|
+
* The backend this process's on-device llama-server runs, for catalog
|
|
23
|
+
* backend exclusions: the build discovery resolved, else what the probe
|
|
24
|
+
* found, else the only build macOS ships. Undefined when an external server
|
|
25
|
+
* is configured through the environment — its backend is not ours to know.
|
|
26
|
+
*/
|
|
27
|
+
export declare function currentLlamaCppBackend(): (typeof BACKENDS)[number] | undefined;
|
|
28
|
+
export declare function llamaBackendHealthView(): LlamaCppBackendHealthResponse;
|
|
29
|
+
export declare function __resetLlamaBackendHealthForTest(): void;
|
|
30
|
+
export {};
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Whether llama-server is getting the hardware this machine has, as the
|
|
3
|
+
* engine process sees it: the CUDA build discovery passed over for the
|
|
4
|
+
* driver (`GEZEL_LLAMA_CUDA_BLOCKER`), a GPU build that started without its
|
|
5
|
+
* GPU (gpu-startup-watch.ts), and Linux's out-of-memory killer stopping the
|
|
6
|
+
* engine. Each is invisible otherwise — the engine keeps answering, slower,
|
|
7
|
+
* or a chat fails with a crash that reads like any other.
|
|
8
|
+
*
|
|
9
|
+
* Process-wide like the backend env it sits beside: every llama provider in
|
|
10
|
+
* this process launches the same build.
|
|
11
|
+
*/
|
|
12
|
+
import { readLlamaCudaBlocker } from '@bendyline/gezel/native';
|
|
13
|
+
let gpuUnused = null;
|
|
14
|
+
let outOfMemory = null;
|
|
15
|
+
/** Record what the latest start of a build found; null clears it. */
|
|
16
|
+
export function noteGpuStartup(verdict, now = new Date()) {
|
|
17
|
+
gpuUnused = verdict ? { ...verdict, at: now.toISOString() } : null;
|
|
18
|
+
}
|
|
19
|
+
export function noteHostOutOfMemory(input, now = new Date()) {
|
|
20
|
+
outOfMemory = {
|
|
21
|
+
count: (outOfMemory?.count ?? 0) + 1,
|
|
22
|
+
at: now.toISOString(),
|
|
23
|
+
...(input.model ? { model: input.model } : {}),
|
|
24
|
+
whileStarting: input.whileStarting,
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
const BACKENDS = ['cuda', 'vulkan', 'metal', 'cpu'];
|
|
28
|
+
/**
|
|
29
|
+
* The backend this process's on-device llama-server runs, for catalog
|
|
30
|
+
* backend exclusions: the build discovery resolved, else what the probe
|
|
31
|
+
* found, else the only build macOS ships. Undefined when an external server
|
|
32
|
+
* is configured through the environment — its backend is not ours to know.
|
|
33
|
+
*/
|
|
34
|
+
export function currentLlamaCppBackend() {
|
|
35
|
+
if (process.env.GEZEL_LLAMA_SERVER_URL)
|
|
36
|
+
return undefined;
|
|
37
|
+
for (const raw of [
|
|
38
|
+
process.env.GEZEL_LLAMA_SERVER_BACKEND,
|
|
39
|
+
process.env.GEZEL_LLAMA_DETECTED_BACKEND,
|
|
40
|
+
]) {
|
|
41
|
+
const backend = BACKENDS.find((b) => b === raw);
|
|
42
|
+
if (backend)
|
|
43
|
+
return backend;
|
|
44
|
+
}
|
|
45
|
+
return process.platform === 'darwin' ? 'metal' : undefined;
|
|
46
|
+
}
|
|
47
|
+
export function llamaBackendHealthView() {
|
|
48
|
+
const runningRaw = process.env.GEZEL_LLAMA_SERVER_BACKEND;
|
|
49
|
+
const running = BACKENDS.find((backend) => backend === runningRaw);
|
|
50
|
+
const cudaBlocker = readLlamaCudaBlocker();
|
|
51
|
+
// A verdict about a build the process has since moved off (a quarantine
|
|
52
|
+
// fallback, a lifted quarantine) no longer describes what runs.
|
|
53
|
+
const unused = gpuUnused && gpuUnused.backend === running ? gpuUnused : null;
|
|
54
|
+
return {
|
|
55
|
+
...(running ? { running } : {}),
|
|
56
|
+
...(cudaBlocker ? { cudaBlocker } : {}),
|
|
57
|
+
...(unused ? { gpuUnused: unused } : {}),
|
|
58
|
+
...(outOfMemory ? { outOfMemory } : {}),
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
export function __resetLlamaBackendHealthForTest() {
|
|
62
|
+
gpuUnused = null;
|
|
63
|
+
outOfMemory = null;
|
|
64
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The engine process's side of the llama-server quarantine
|
|
3
|
+
* (`llama-quarantine.ts` in `@bendyline/gezel/native`): which build this
|
|
4
|
+
* process launches, kept in the env discovery stamps at startup
|
|
5
|
+
* (`GEZEL_LLAMA_SERVER_BIN`, `GEZEL_LLAMA_SERVER_BACKEND`,
|
|
6
|
+
* `GEZEL_LLAMA_QUARANTINED`), and the view and undo behind the engine's
|
|
7
|
+
* Settings tab.
|
|
8
|
+
*
|
|
9
|
+
* Discovery reads the quarantine only at startup. These move the env inside
|
|
10
|
+
* a running process, so a quarantine and its undo both take effect on the
|
|
11
|
+
* next engine launch instead of the next app start.
|
|
12
|
+
*/
|
|
13
|
+
import type { LlamaCppQuarantineResponse } from '@bendyline/gezel';
|
|
14
|
+
import { type LlamaBackend, type ResolvedLlamaBinary } from '@bendyline/gezel/native';
|
|
15
|
+
export declare function isLlamaBackend(value: string): value is LlamaBackend;
|
|
16
|
+
/**
|
|
17
|
+
* Point this process at the build that replaces `backend`'s, just
|
|
18
|
+
* quarantined, so the pool's rebuild of the failed engine launches it. Null,
|
|
19
|
+
* env untouched, when nothing usable is bundled beside `binary`.
|
|
20
|
+
*/
|
|
21
|
+
export declare function adoptLlamaFallback(home: string, binary: string, backend: LlamaBackend): ResolvedLlamaBinary | null;
|
|
22
|
+
/**
|
|
23
|
+
* The quarantined builds that still apply. An entry pins its binary's bytes,
|
|
24
|
+
* so one whose build an update replaced is left out — discovery ignores it
|
|
25
|
+
* too. Without a resolved build to measure from, entries are shown as written.
|
|
26
|
+
*/
|
|
27
|
+
export declare function llamaQuarantineView(home: string): LlamaCppQuarantineResponse;
|
|
28
|
+
/**
|
|
29
|
+
* Lift `backend`'s quarantine at a person's request. Unless they pinned a
|
|
30
|
+
* backend, also point this process back at the best build the hardware
|
|
31
|
+
* supports, so the next engine launch tries it; `restored` is that build when
|
|
32
|
+
* the env moved. A pinned backend is launched as pinned and was never routed
|
|
33
|
+
* around, so there is nothing to move back.
|
|
34
|
+
*/
|
|
35
|
+
export declare function liftLlamaQuarantine(home: string, backend: LlamaBackend, opts: {
|
|
36
|
+
pinned: boolean;
|
|
37
|
+
}): {
|
|
38
|
+
cleared: boolean;
|
|
39
|
+
restored: ResolvedLlamaBinary | null;
|
|
40
|
+
};
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The engine process's side of the llama-server quarantine
|
|
3
|
+
* (`llama-quarantine.ts` in `@bendyline/gezel/native`): which build this
|
|
4
|
+
* process launches, kept in the env discovery stamps at startup
|
|
5
|
+
* (`GEZEL_LLAMA_SERVER_BIN`, `GEZEL_LLAMA_SERVER_BACKEND`,
|
|
6
|
+
* `GEZEL_LLAMA_QUARANTINED`), and the view and undo behind the engine's
|
|
7
|
+
* Settings tab.
|
|
8
|
+
*
|
|
9
|
+
* Discovery reads the quarantine only at startup. These move the env inside
|
|
10
|
+
* a running process, so a quarantine and its undo both take effect on the
|
|
11
|
+
* next engine launch instead of the next app start.
|
|
12
|
+
*/
|
|
13
|
+
import { LLAMA_QUARANTINE_STRIKES, clearLlamaQuarantine, createLlamaBuildCheck, isBinaryQuarantined, llamaVariantBinaryPath, publishLlamaCudaBlocker, readLlamaQuarantine, resolveLlamaFallbackBinary, resolveLlamaVariantBinary, } from '@bendyline/gezel/native';
|
|
14
|
+
const BACKENDS = ['cuda', 'vulkan', 'metal', 'cpu'];
|
|
15
|
+
export function isLlamaBackend(value) {
|
|
16
|
+
return BACKENDS.some((backend) => backend === value);
|
|
17
|
+
}
|
|
18
|
+
function envBackend(name) {
|
|
19
|
+
const raw = process.env[name];
|
|
20
|
+
return raw !== undefined && isLlamaBackend(raw) ? raw : undefined;
|
|
21
|
+
}
|
|
22
|
+
function updateQuarantinedEnv(update) {
|
|
23
|
+
const backends = new Set(process.env.GEZEL_LLAMA_QUARANTINED?.split(',').filter(Boolean));
|
|
24
|
+
update(backends);
|
|
25
|
+
if (backends.size > 0)
|
|
26
|
+
process.env.GEZEL_LLAMA_QUARANTINED = [...backends].join(',');
|
|
27
|
+
else
|
|
28
|
+
delete process.env.GEZEL_LLAMA_QUARANTINED;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Point this process at the build that replaces `backend`'s, just
|
|
32
|
+
* quarantined, so the pool's rebuild of the failed engine launches it. Null,
|
|
33
|
+
* env untouched, when nothing usable is bundled beside `binary`.
|
|
34
|
+
*/
|
|
35
|
+
export function adoptLlamaFallback(home, binary, backend) {
|
|
36
|
+
const quarantine = readLlamaQuarantine(home);
|
|
37
|
+
const fallback = resolveLlamaFallbackBinary(binary, backend, (candidate, path) => !isBinaryQuarantined(quarantine, candidate, path));
|
|
38
|
+
if (!fallback)
|
|
39
|
+
return null;
|
|
40
|
+
process.env.GEZEL_LLAMA_SERVER_BIN = fallback.path;
|
|
41
|
+
process.env.GEZEL_LLAMA_SERVER_BACKEND = fallback.backend;
|
|
42
|
+
updateQuarantinedEnv((backends) => backends.add(backend));
|
|
43
|
+
return fallback;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* The quarantined builds that still apply. An entry pins its binary's bytes,
|
|
47
|
+
* so one whose build an update replaced is left out — discovery ignores it
|
|
48
|
+
* too. Without a resolved build to measure from, entries are shown as written.
|
|
49
|
+
*/
|
|
50
|
+
export function llamaQuarantineView(home) {
|
|
51
|
+
const binary = process.env.GEZEL_LLAMA_SERVER_BIN;
|
|
52
|
+
const running = envBackend('GEZEL_LLAMA_SERVER_BACKEND');
|
|
53
|
+
const entries = readLlamaQuarantine(home).filter((entry) => {
|
|
54
|
+
if (!isLlamaBackend(entry.backend))
|
|
55
|
+
return false;
|
|
56
|
+
if (!binary || !running)
|
|
57
|
+
return true;
|
|
58
|
+
const path = llamaVariantBinaryPath(binary, running, entry.backend);
|
|
59
|
+
return path === null || isBinaryQuarantined([entry], entry.backend, path);
|
|
60
|
+
});
|
|
61
|
+
return {
|
|
62
|
+
entries: entries.map(({ backend, signal, reason, at, crashes }) => ({
|
|
63
|
+
backend,
|
|
64
|
+
signal,
|
|
65
|
+
reason,
|
|
66
|
+
at,
|
|
67
|
+
...(crashes !== undefined ? { crashes } : {}),
|
|
68
|
+
})),
|
|
69
|
+
strikeThreshold: LLAMA_QUARANTINE_STRIKES,
|
|
70
|
+
...(running ? { running } : {}),
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Lift `backend`'s quarantine at a person's request. Unless they pinned a
|
|
75
|
+
* backend, also point this process back at the best build the hardware
|
|
76
|
+
* supports, so the next engine launch tries it; `restored` is that build when
|
|
77
|
+
* the env moved. A pinned backend is launched as pinned and was never routed
|
|
78
|
+
* around, so there is nothing to move back.
|
|
79
|
+
*/
|
|
80
|
+
export function liftLlamaQuarantine(home, backend, opts) {
|
|
81
|
+
const cleared = clearLlamaQuarantine(home, backend);
|
|
82
|
+
updateQuarantinedEnv((backends) => backends.delete(backend));
|
|
83
|
+
const binary = process.env.GEZEL_LLAMA_SERVER_BIN;
|
|
84
|
+
const running = envBackend('GEZEL_LLAMA_SERVER_BACKEND');
|
|
85
|
+
if (opts.pinned || !binary || !running)
|
|
86
|
+
return { cleared, restored: null };
|
|
87
|
+
// Discovery's own check: a CUDA build the driver cannot run stays passed
|
|
88
|
+
// over, whatever else was lifted.
|
|
89
|
+
const check = createLlamaBuildCheck({
|
|
90
|
+
quarantine: readLlamaQuarantine(home),
|
|
91
|
+
platform: process.platform,
|
|
92
|
+
});
|
|
93
|
+
const best = resolveLlamaVariantBinary(binary, running, envBackend('GEZEL_LLAMA_DETECTED_BACKEND') ?? backend, check.isUsable);
|
|
94
|
+
publishLlamaCudaBlocker(check.cudaBlocker());
|
|
95
|
+
if (!best || best.backend === running)
|
|
96
|
+
return { cleared, restored: null };
|
|
97
|
+
process.env.GEZEL_LLAMA_SERVER_BIN = best.path;
|
|
98
|
+
process.env.GEZEL_LLAMA_SERVER_BACKEND = best.backend;
|
|
99
|
+
return { cleared, restored: best };
|
|
100
|
+
}
|