@bendyline/gezel-inference 1.0.7 → 1.0.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (78) hide show
  1. package/dist/catalog/chat-models/ge/gemma4-12b-q4/manifest.json +46 -3
  2. package/dist/catalog/chat-models/ge/gemma4-12b-q4/versions/1.2.1/manifest.json +141 -0
  3. package/dist/catalog/chat-models/ge/gemma4-e4b-q4/manifest.json +5 -0
  4. package/dist/catalog/chat-models/index.json +1 -1
  5. package/dist/catalog/chat-models/or/ornith1.5-9b-q4/manifest.json +5 -0
  6. package/dist/catalog/chat-models/or/ornith1.5-9b-q8/manifest.json +5 -0
  7. package/dist/catalog/chat-models/qw/qwen3.5-9b-q4/manifest.json +5 -0
  8. package/dist/catalog/chat-models/qw/qwen3.8-27b-q4/manifest.json +5 -0
  9. package/dist/catalog/chat-models/qw/qwen3.8-flash-next-q2/manifest.json +24 -7
  10. package/dist/catalog/chat-models/qw/qwen3.8-flash-next-q2/versions/1.0.3/manifest.json +47 -0
  11. package/dist/catalog/chat-models/raw-index.json +1 -1
  12. package/dist/catalog/provenance.json +1 -1
  13. package/dist/engines/electron-native-reuse.d.ts +5 -4
  14. package/dist/engines/electron-native-reuse.js +1 -1
  15. package/dist/engines/native-file-manifest.json +12344 -698
  16. package/dist/engines/native-manifest.d.ts +4 -4
  17. package/dist/engines/native-manifest.js +40 -36
  18. package/dist/engines/resolver.d.ts +18 -17
  19. package/dist/engines/resolver.js +36 -1
  20. package/dist/http/model-inventory-cache.d.ts +1 -1
  21. package/dist/http/routes/engines.js +3 -3
  22. package/dist/http/routes/v1-images.d.ts +2 -1
  23. package/dist/http/routes/v1-images.js +36 -9
  24. package/dist/knowledge/manager.d.ts +3 -27
  25. package/dist/knowledge/manager.js +8 -364
  26. package/dist/knowledge/unified-search.d.ts +61 -0
  27. package/dist/knowledge/unified-search.js +373 -0
  28. package/dist/models/catalog-drift.d.ts +2 -0
  29. package/dist/models/catalog-drift.js +1 -1
  30. package/dist/models/catalog-payload-identity.d.ts +2 -2
  31. package/dist/models/catalog-payload-identity.js +10 -5
  32. package/dist/providers/active-install-message.js +1 -1
  33. package/dist/providers/catalog-model-config.d.ts +28 -0
  34. package/dist/providers/ds4/build-provider.js +35 -13
  35. package/dist/providers/ds4/residency.d.ts +77 -0
  36. package/dist/providers/ds4/residency.js +87 -6
  37. package/dist/providers/image/sd-cpp.js +19 -11
  38. package/dist/providers/llama-cpp/backend-health.d.ts +3 -2
  39. package/dist/providers/llama-cpp/backend-health.js +6 -3
  40. package/dist/providers/llama-cpp/backend-quarantine.js +1 -1
  41. package/dist/providers/llama-cpp/build-provider.js +168 -29
  42. package/dist/providers/llama-cpp/devices.js +4 -1
  43. package/dist/providers/llama-cpp/engine-flags.d.ts +8 -1
  44. package/dist/providers/llama-cpp/engine-flags.js +13 -8
  45. package/dist/providers/llama-cpp/gpu-startup-watch.d.ts +4 -4
  46. package/dist/providers/llama-cpp/gpu-startup-watch.js +7 -5
  47. package/dist/providers/llama-cpp/models.d.ts +10 -0
  48. package/dist/providers/llama-cpp/models.js +64 -10
  49. package/dist/providers/llama-cpp/offload-planner.d.ts +6 -0
  50. package/dist/providers/llama-cpp/offload-planner.js +1 -1
  51. package/dist/providers/llama-cpp/spec-draft.d.ts +45 -23
  52. package/dist/providers/llama-cpp/spec-draft.js +113 -24
  53. package/dist/providers/mlx/async-file-handoff.d.ts +9 -1
  54. package/dist/providers/mlx/async-file-handoff.js +32 -4
  55. package/dist/providers/mlx/provider.js +28 -16
  56. package/dist/providers/mlx/python/spec_decode.py +23 -2
  57. package/dist/providers/mlx/python/tool_args_json.py +59 -21
  58. package/dist/providers/mlx/runtime-diagnostics.d.ts +6 -0
  59. package/dist/providers/mlx/runtime-diagnostics.js +18 -1
  60. package/dist/providers/mlx/tool-call-protocol.d.ts +4 -3
  61. package/dist/providers/mlx/tool-call-protocol.js +4 -3
  62. package/dist/providers/mlx/venv.d.ts +19 -1
  63. package/dist/providers/mlx/venv.js +21 -2
  64. package/dist/providers/native/device-capacity-ledger.d.ts +4 -2
  65. package/dist/providers/native/device-capacity-ledger.js +35 -20
  66. package/dist/providers/native/device-capacity.d.ts +4 -0
  67. package/dist/providers/native/device-capacity.js +5 -0
  68. package/dist/providers/native/local-engine-runtime.d.ts +16 -1
  69. package/dist/providers/native/local-engine-runtime.js +142 -39
  70. package/dist/providers/native/process-identity.d.ts +38 -0
  71. package/dist/providers/native/process-identity.js +86 -0
  72. package/dist/providers/native/supervisor.d.ts +8 -1
  73. package/dist/providers/native/supervisor.js +16 -7
  74. package/dist/providers/types.d.ts +4 -0
  75. package/dist/remotes/types.d.ts +1 -1
  76. package/dist/runtime-lock.d.ts +3 -27
  77. package/dist/runtime-lock.js +7 -80
  78. package/package.json +4 -4
@@ -4,6 +4,10 @@ export { DS4_FULL_RESIDENCY_HEADROOM_BYTES };
4
4
  * Conservative floor for the full-residency working set. Exclusivity is an
5
5
  * explicit device lease at process startup, not a consequence of this number:
6
6
  * the automatic model budget can exceed 96 GiB on larger machines.
7
+ *
8
+ * Only for a launch nobody measured: an entry with `fullResidencyMemory` is
9
+ * reserved at that working set ({@link planDs4MeasuredLaunch}). Flooring a
10
+ * 45 GiB Qwen3.8 launch here put it over a 96 GiB Mac's 80 GiB budget.
7
11
  */
8
12
  export declare const DS4_FULL_RESIDENCY_RESERVATION_BYTES: number;
9
13
  /**
@@ -73,12 +77,27 @@ export interface Ds4ExpertCachePlanOptions {
73
77
  catalogCacheBytes?: number;
74
78
  catalogResidentBytes?: number;
75
79
  totalRamBytes?: number;
80
+ /**
81
+ * A measured streamed footprint at the launch window, sidecars included
82
+ * ({@link ds4StreamingFixedBytes}). With {@link budgetBytes} it replaces the
83
+ * catalog subtraction and the generic 24 GiB headroom.
84
+ */
85
+ measuredFixedBytes?: number;
86
+ /** This device's local-model budget, the ceiling the capacity broker admits under. */
87
+ budgetBytes?: number;
88
+ /** Smallest cache the entry says is worth streaming with. */
89
+ minCacheBytes?: number;
76
90
  }
77
91
  export interface Ds4ExpertCachePlan {
78
92
  cacheGb: number;
79
93
  requestedGb: number;
80
94
  clamped: boolean;
81
95
  safe: boolean;
96
+ /**
97
+ * What bounded the cache: the device's local-model budget beside a measured
98
+ * footprint, or the generic {@link DS4_FULL_RESIDENCY_HEADROOM_BYTES}.
99
+ */
100
+ limit: 'model-budget' | 'headroom';
82
101
  }
83
102
  /**
84
103
  * Pick a bounded routed-expert cache for streaming mode. Catalog guidance is
@@ -86,8 +105,66 @@ export interface Ds4ExpertCachePlan {
86
105
  * the old RAM-tier heuristic which incorrectly gave both models 64 GiB on a
87
106
  * 128 GiB Mac. Manual values are still accepted, but clamped so fixed model
88
107
  * state + the cache cannot consume the runtime/OS reserve.
108
+ *
109
+ * The 24 GiB headroom guards a footprint guessed as `residentBytes −
110
+ * cacheExpertsBytes`, which omits graph and staging memory ds4 also holds.
111
+ * An entry with a measured streamed footprint has no such gap, so its cache
112
+ * may use whatever this device's local-model budget leaves beside it. A fixed
113
+ * 24 GiB refused Qwen3.8 on 32 GiB Macs whose budget held it with room to spare.
89
114
  */
90
115
  export declare function planDs4ExpertCache(opts: Ds4ExpertCachePlanOptions): Ds4ExpertCachePlan;
116
+ /** A measured ds4 memory line from the catalog: bytes at a window, plus a per-token slope. */
117
+ export interface Ds4MeasuredLine {
118
+ bytes: number;
119
+ ctxTokens: number;
120
+ bytesPerToken: number;
121
+ }
122
+ /** Evaluate a measured line at a window, never below its context-free part. */
123
+ export declare function ds4MeasuredBytesAt(line: Ds4MeasuredLine, ctxTokens: number): number;
124
+ /** The memory fields of a catalog `ds4` block that price a launch. */
125
+ export interface Ds4MemorySource {
126
+ cacheExpertsBytes?: number | undefined;
127
+ fullResidencyMemory?: {
128
+ workingSetBytes: number;
129
+ ctxTokens: number;
130
+ bytesPerToken: number;
131
+ } | undefined;
132
+ streamingMemory?: {
133
+ fixedBytes: number;
134
+ ctxTokens: number;
135
+ bytesPerToken: number;
136
+ minCacheBytes?: number;
137
+ } | undefined;
138
+ }
139
+ /** Measured streamed footprint without the expert cache, at a window; undefined when unmeasured. */
140
+ export declare function ds4StreamingFixedBytes(source: Ds4MemorySource | undefined, ctxTokens: number): number | undefined;
141
+ export interface Ds4MeasuredLaunchOptions {
142
+ source: Ds4MemorySource | undefined;
143
+ numCtx: number;
144
+ ssdStreaming: boolean;
145
+ totalRamBytes: number;
146
+ /** Local-model budget, needed to size a streamed launch's cache. */
147
+ budgetBytes?: number | undefined;
148
+ /** Resident memory beside the model: a vision encoder, a DSpark companion. */
149
+ sidecarBytes?: number;
150
+ configuredCacheGb?: number | undefined;
151
+ }
152
+ export interface Ds4MeasuredLaunch {
153
+ /** What the launch holds, sidecars included. The broker reserves exactly this. */
154
+ workingSetBytes: number;
155
+ /** The part of {@link workingSetBytes} the window does not move. */
156
+ contextFreeBytes: number;
157
+ bytesPerToken: number;
158
+ /** Streamed launches only. */
159
+ cache?: Ds4ExpertCachePlan;
160
+ }
161
+ /**
162
+ * Price a launch from the entry's measurement for the chosen mode. Undefined
163
+ * when that mode is unmeasured (or a streamed launch has no budget to size
164
+ * against), so callers keep their catalog-`residentBytes` path, including the
165
+ * 96 GiB full-residency floor that stands in for a missing measurement.
166
+ */
167
+ export declare function planDs4MeasuredLaunch(opts: Ds4MeasuredLaunchOptions): Ds4MeasuredLaunch | undefined;
91
168
  /** Effective capacity-broker reservation for the chosen DS4 residency mode. */
92
169
  export declare function ds4ResidentBytesForMode(catalogResidentBytes: number, ssdStreaming: boolean, ssdStreamingSupported?: boolean): number;
93
170
  /** Allowance for ds4's compute and staging buffers beyond weights and KV rows. */
@@ -6,6 +6,10 @@ export { DS4_FULL_RESIDENCY_HEADROOM_BYTES };
6
6
  * Conservative floor for the full-residency working set. Exclusivity is an
7
7
  * explicit device lease at process startup, not a consequence of this number:
8
8
  * the automatic model budget can exceed 96 GiB on larger machines.
9
+ *
10
+ * Only for a launch nobody measured: an entry with `fullResidencyMemory` is
11
+ * reserved at that working set ({@link planDs4MeasuredLaunch}). Flooring a
12
+ * 45 GiB Qwen3.8 launch here put it over a 96 GiB Mac's 80 GiB budget.
9
13
  */
10
14
  export const DS4_FULL_RESIDENCY_RESERVATION_BYTES = 96 * GB;
11
15
  /**
@@ -80,20 +84,97 @@ export function shouldUseDs4SsdStreaming(opts = {}) {
80
84
  * the old RAM-tier heuristic which incorrectly gave both models 64 GiB on a
81
85
  * 128 GiB Mac. Manual values are still accepted, but clamped so fixed model
82
86
  * state + the cache cannot consume the runtime/OS reserve.
87
+ *
88
+ * The 24 GiB headroom guards a footprint guessed as `residentBytes −
89
+ * cacheExpertsBytes`, which omits graph and staging memory ds4 also holds.
90
+ * An entry with a measured streamed footprint has no such gap, so its cache
91
+ * may use whatever this device's local-model budget leaves beside it. A fixed
92
+ * 24 GiB refused Qwen3.8 on 32 GiB Macs whose budget held it with room to spare.
83
93
  */
84
94
  export function planDs4ExpertCache(opts) {
85
95
  const totalRamBytes = opts.totalRamBytes ?? totalMemoryBytes();
86
96
  const catalogCacheBytes = opts.catalogCacheBytes ?? 0;
87
- const fixedResidentBytes = Math.max(0, (opts.catalogResidentBytes ?? 0) - catalogCacheBytes);
88
97
  const fallbackGb = totalRamBytes >= 120 * GB ? 64 : totalRamBytes >= 88 * GB ? 48 : 32;
89
98
  const requestedGb = opts.configuredGb ?? (catalogCacheBytes > 0 ? catalogCacheBytes / GB : fallbackGb);
90
- const safeCacheBytes = totalRamBytes - fixedResidentBytes - DS4_FULL_RESIDENCY_HEADROOM_BYTES;
99
+ const modelBudget = opts.measuredFixedBytes !== undefined && opts.budgetBytes !== undefined;
100
+ const safeCacheBytes = modelBudget
101
+ ? opts.budgetBytes - opts.measuredFixedBytes
102
+ : totalRamBytes -
103
+ Math.max(0, (opts.catalogResidentBytes ?? 0) - catalogCacheBytes) -
104
+ DS4_FULL_RESIDENCY_HEADROOM_BYTES;
91
105
  const safeCacheGb = Math.floor(safeCacheBytes / GB);
92
- if (safeCacheGb < 1) {
93
- return { cacheGb: 1, requestedGb, clamped: true, safe: false };
106
+ const minCacheGb = Math.max(1, Math.ceil((opts.minCacheBytes ?? 0) / GB));
107
+ const limit = modelBudget ? 'model-budget' : 'headroom';
108
+ if (safeCacheGb < minCacheGb) {
109
+ return { cacheGb: minCacheGb, requestedGb, clamped: true, safe: false, limit };
110
+ }
111
+ const cacheGb = Math.max(minCacheGb, Math.min(requestedGb, safeCacheGb));
112
+ return { cacheGb, requestedGb, clamped: cacheGb !== requestedGb, safe: true, limit };
113
+ }
114
+ /** Evaluate a measured line at a window, never below its context-free part. */
115
+ export function ds4MeasuredBytesAt(line, ctxTokens) {
116
+ const contextFree = Math.max(0, line.bytes - line.bytesPerToken * line.ctxTokens);
117
+ return Math.round(contextFree + line.bytesPerToken * Math.max(0, ctxTokens));
118
+ }
119
+ function fullResidencyLine(source) {
120
+ const m = source?.fullResidencyMemory;
121
+ return m
122
+ ? { bytes: m.workingSetBytes, ctxTokens: m.ctxTokens, bytesPerToken: m.bytesPerToken }
123
+ : undefined;
124
+ }
125
+ function streamingLine(source) {
126
+ const m = source?.streamingMemory;
127
+ return m
128
+ ? { bytes: m.fixedBytes, ctxTokens: m.ctxTokens, bytesPerToken: m.bytesPerToken }
129
+ : undefined;
130
+ }
131
+ /** Measured streamed footprint without the expert cache, at a window; undefined when unmeasured. */
132
+ export function ds4StreamingFixedBytes(source, ctxTokens) {
133
+ const line = streamingLine(source);
134
+ return line ? ds4MeasuredBytesAt(line, ctxTokens) : undefined;
135
+ }
136
+ /**
137
+ * Price a launch from the entry's measurement for the chosen mode. Undefined
138
+ * when that mode is unmeasured (or a streamed launch has no budget to size
139
+ * against), so callers keep their catalog-`residentBytes` path, including the
140
+ * 96 GiB full-residency floor that stands in for a missing measurement.
141
+ */
142
+ export function planDs4MeasuredLaunch(opts) {
143
+ const sidecarBytes = opts.sidecarBytes ?? 0;
144
+ if (!opts.ssdStreaming) {
145
+ const line = fullResidencyLine(opts.source);
146
+ if (!line)
147
+ return undefined;
148
+ const contextFreeBytes = ds4MeasuredBytesAt(line, 0) + sidecarBytes;
149
+ return {
150
+ workingSetBytes: contextFreeBytes + line.bytesPerToken * Math.max(0, opts.numCtx),
151
+ contextFreeBytes,
152
+ bytesPerToken: line.bytesPerToken,
153
+ };
94
154
  }
95
- const cacheGb = Math.max(1, Math.min(requestedGb, safeCacheGb));
96
- return { cacheGb, requestedGb, clamped: cacheGb !== requestedGb, safe: true };
155
+ const line = streamingLine(opts.source);
156
+ if (!line || opts.budgetBytes === undefined)
157
+ return undefined;
158
+ const fixedBytes = ds4MeasuredBytesAt(line, opts.numCtx) + sidecarBytes;
159
+ const cache = planDs4ExpertCache({
160
+ ...(opts.configuredCacheGb !== undefined ? { configuredGb: opts.configuredCacheGb } : {}),
161
+ ...(opts.source?.cacheExpertsBytes !== undefined
162
+ ? { catalogCacheBytes: opts.source.cacheExpertsBytes }
163
+ : {}),
164
+ totalRamBytes: opts.totalRamBytes,
165
+ measuredFixedBytes: fixedBytes,
166
+ budgetBytes: opts.budgetBytes,
167
+ ...(opts.source?.streamingMemory?.minCacheBytes !== undefined
168
+ ? { minCacheBytes: opts.source.streamingMemory.minCacheBytes }
169
+ : {}),
170
+ });
171
+ const cacheBytes = cache.cacheGb * GB;
172
+ return {
173
+ workingSetBytes: fixedBytes + cacheBytes,
174
+ contextFreeBytes: ds4MeasuredBytesAt(line, 0) + sidecarBytes + cacheBytes,
175
+ bytesPerToken: line.bytesPerToken,
176
+ cache,
177
+ };
97
178
  }
98
179
  /** Effective capacity-broker reservation for the chosen DS4 residency mode. */
99
180
  export function ds4ResidentBytesForMode(catalogResidentBytes, ssdStreaming, ssdStreamingSupported = true) {
@@ -273,13 +273,8 @@ export class StableDiffusionCppProvider {
273
273
  const height = input.height ?? defaultDimension;
274
274
  const resolvedLoras = await this.resolveLoras(modelId, input.loras ?? []);
275
275
  let loras = resolvedLoras.loras;
276
- // A speed LoRA's recipe is what makes its few steps valid, so it wins
277
- // over a style's.
278
- const render = loras.find((l) => l.purpose === 'speed')?.render ?? loras.find((l) => l.render)?.render;
279
- const steps = input.steps ?? render?.steps ?? (await this.defaultSampleSteps(modelId));
280
276
  const seed = input.seed ?? Math.floor(Math.random() * 2_147_483_647);
281
277
  const started = Date.now();
282
- log.info(`[sd-cpp] generate model=${modelId ?? 'default'} steps=${steps} explicitSteps=${input.steps !== undefined} size=${width}x${height}${loras.length > 0 ? ` loras=${loras.map((l) => l.id).join(',')}` : ''}`);
283
278
  // Model selection: sd-server serves one model per process. When a
284
279
  // request targets a different installed model than the one currently
285
280
  // loaded, point resolveLaunch at it (via the shared launchState) and
@@ -290,8 +285,9 @@ export class StableDiffusionCppProvider {
290
285
  this.launchState.modelId = modelId;
291
286
  await this.supervisor.stop();
292
287
  }
293
- // A render the caller abandons keeps running inside sd-server, which
294
- // cannot interrupt one it has started, so cancelling stops the engine.
288
+ // A render the caller abandons keeps running inside sd-server, whose
289
+ // `/sdapi` endpoints cannot interrupt one they have started, so
290
+ // cancelling stops the engine.
295
291
  const request = new AbortController();
296
292
  const stopRender = () => {
297
293
  request.abort();
@@ -333,6 +329,15 @@ export class StableDiffusionCppProvider {
333
329
  }
334
330
  if (signal?.aborted)
335
331
  throw new ImageGenerationCancelledError();
332
+ const settingsNotes = [...resolvedLoras.notes];
333
+ if (loras.length > 0) {
334
+ loras = await this.lorasTheEngineHas(baseUrl, loras, request.signal, settingsNotes);
335
+ }
336
+ // Read only after the engine's list: a fast mode's 4 steps and CFG 1
337
+ // on the bare model it was dropped from render mush.
338
+ const render = loraRenderOverrides(loras);
339
+ const steps = input.steps ?? render?.steps ?? (await this.defaultSampleSteps(modelId));
340
+ log.info(`[sd-cpp] generate model=${modelId ?? 'default'} steps=${steps} explicitSteps=${input.steps !== undefined} size=${width}x${height}${loras.length > 0 ? ` loras=${loras.map((l) => l.id).join(',')}` : ''}`);
336
341
  // Drive sd-server's A1111-compatible endpoints (`/sdapi/v1/txt2img`
337
342
  // and `/sdapi/v1/img2img`). Unlike the OpenAI `/v1/images/*` shape
338
343
  // — which reads only prompt/n/size and takes steps/seed/cfg from the
@@ -341,10 +346,6 @@ export class StableDiffusionCppProvider {
341
346
  // actually take effect. `cfg_scale` is set per model (distilled /
342
347
  // Flux-flow models need CFG 1; others inherit the server default).
343
348
  const cfg = render?.cfg ?? (modelId ? MODEL_CFG_DEFAULTS.get(modelId) : undefined);
344
- const settingsNotes = [...resolvedLoras.notes];
345
- if (loras.length > 0) {
346
- loras = await this.lorasTheEngineHas(baseUrl, loras, request.signal, settingsNotes);
347
- }
348
349
  let inputImages = input.inputImages ?? [];
349
350
  // Capability gate: models whose architecture doesn't honor init
350
351
  // latents on the pinned sd-server fall back to txt2img instead of
@@ -996,6 +997,13 @@ export function withoutEngineDirectives(text) {
996
997
  } while (out !== previous);
997
998
  return out;
998
999
  }
1000
+ /**
1001
+ * The render settings the applied LoRAs set. A speed LoRA's recipe is what
1002
+ * makes its few steps valid, so it wins over a style's.
1003
+ */
1004
+ function loraRenderOverrides(applied) {
1005
+ return (applied.find((l) => l.purpose === 'speed')?.render ?? applied.find((l) => l.render)?.render);
1006
+ }
999
1007
  /**
1000
1008
  * Read an installed LoRA's manifest, or nothing when it is malformed. The
1001
1009
  * filename must be a bare `.safetensors` name: the engine resolves it inside
@@ -1,7 +1,8 @@
1
1
  /**
2
2
  * Whether llama-server is getting the hardware this machine has, as the
3
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
4
+ * driver (`GEZEL_LLAMA_CUDA_BLOCKER`), the ROCm build it passed over for this
5
+ * machine's AMD GPUs (`GEZEL_LLAMA_ROCM_BLOCKER`), a GPU build that started without its
5
6
  * GPU (gpu-startup-watch.ts), and Linux's out-of-memory killer stopping the
6
7
  * engine. Each is invisible otherwise — the engine keeps answering, slower,
7
8
  * or a chat fails with a crash that reads like any other.
@@ -24,7 +25,7 @@ export declare function noteHostOutOfMemory(input: {
24
25
  model?: string | undefined;
25
26
  whileStarting: boolean;
26
27
  }, now?: Date): void;
27
- declare const BACKENDS: readonly ["cuda", "vulkan", "metal", "cpu"];
28
+ declare const BACKENDS: readonly ["cuda", "rocm", "vulkan", "metal", "cpu"];
28
29
  /**
29
30
  * The backend this process's on-device llama-server runs, for catalog
30
31
  * backend exclusions: the build discovery resolved, else what the probe
@@ -1,7 +1,8 @@
1
1
  /**
2
2
  * Whether llama-server is getting the hardware this machine has, as the
3
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
4
+ * driver (`GEZEL_LLAMA_CUDA_BLOCKER`), the ROCm build it passed over for this
5
+ * machine's AMD GPUs (`GEZEL_LLAMA_ROCM_BLOCKER`), a GPU build that started without its
5
6
  * GPU (gpu-startup-watch.ts), and Linux's out-of-memory killer stopping the
6
7
  * engine. Each is invisible otherwise — the engine keeps answering, slower,
7
8
  * or a chat fails with a crash that reads like any other.
@@ -9,7 +10,7 @@
9
10
  * Process-wide like the backend env it sits beside: every llama provider in
10
11
  * this process launches the same build.
11
12
  */
12
- import { missingMachineRuntime, readLlamaCudaBlocker, vcRedistributableUrl, } from '@bendyline/gezel/native';
13
+ import { missingMachineRuntime, readLlamaCudaBlocker, readRocmBlocker, vcRedistributableUrl, } from '@bendyline/gezel/native';
13
14
  /**
14
15
  * Reading an engine's import tables takes tens of milliseconds of synchronous
15
16
  * file reads, and the answer only changes when someone installs the runtime.
@@ -61,7 +62,7 @@ export function noteHostOutOfMemory(input, now = new Date()) {
61
62
  whileStarting: input.whileStarting,
62
63
  };
63
64
  }
64
- const BACKENDS = ['cuda', 'vulkan', 'metal', 'cpu'];
65
+ const BACKENDS = ['cuda', 'rocm', 'vulkan', 'metal', 'cpu'];
65
66
  /**
66
67
  * The backend this process's on-device llama-server runs, for catalog
67
68
  * backend exclusions: the build discovery resolved, else what the probe
@@ -85,6 +86,7 @@ export function llamaBackendHealthView() {
85
86
  const runningRaw = process.env.GEZEL_LLAMA_SERVER_BACKEND;
86
87
  const running = BACKENDS.find((backend) => backend === runningRaw);
87
88
  const cudaBlocker = readLlamaCudaBlocker();
89
+ const rocmBlocker = readRocmBlocker();
88
90
  // A verdict about a build the process has since moved off (a quarantine
89
91
  // fallback, a lifted quarantine) no longer describes what runs.
90
92
  const unused = gpuUnused && gpuUnused.backend === running ? gpuUnused : null;
@@ -92,6 +94,7 @@ export function llamaBackendHealthView() {
92
94
  return {
93
95
  ...(running ? { running } : {}),
94
96
  ...(cudaBlocker ? { cudaBlocker } : {}),
97
+ ...(rocmBlocker ? { rocmBlocker } : {}),
95
98
  ...(unused ? { gpuUnused: unused } : {}),
96
99
  ...(missingRuntime ? { missingRuntime } : {}),
97
100
  ...(outOfMemory ? { outOfMemory } : {}),
@@ -11,7 +11,7 @@
11
11
  * next engine launch instead of the next app start.
12
12
  */
13
13
  import { LLAMA_QUARANTINE_STRIKES, clearLlamaQuarantine, createLlamaBuildCheck, isBinaryQuarantined, llamaVariantBinaryPath, publishLlamaCudaBlocker, readLlamaQuarantine, resolveLlamaFallbackBinary, resolveLlamaVariantBinary, } from '@bendyline/gezel/native';
14
- const BACKENDS = ['cuda', 'vulkan', 'metal', 'cpu'];
14
+ const BACKENDS = ['cuda', 'rocm', 'vulkan', 'metal', 'cpu'];
15
15
  export function isLlamaBackend(value) {
16
16
  return BACKENDS.some((backend) => backend === value);
17
17
  }