@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
@@ -40,12 +40,12 @@
40
40
  * but logs that it could not anchor to a baked-in digest.
41
41
  */
42
42
  /** Native release version this build pins. Placeholder until first public release. */
43
- export declare const NATIVE_ENGINE_RELEASE = "0.1.57";
43
+ export declare const NATIVE_ENGINE_RELEASE = "0.1.62";
44
44
  /** sha256 of the pinned release's `SHA256SUMS` asset. All-zeros = unpinned. */
45
- export declare const SHA256SUMS_DIGEST = "977b0ad4cdb8983ed44d7a3223267038b1f35b2806d8a1807d7d15c5c7e94f47";
46
- /** Exact SHA256 values for every engine archive published by native-v0.1.57. */
45
+ export declare const SHA256SUMS_DIGEST = "9c2e726c1cef4152b5ffb8cee8e9970cf24127786d3fafcce3582dcf0df9badb";
46
+ /** Exact SHA256 values for every engine archive published by native-v0.1.62. */
47
47
  export declare const NATIVE_ENGINE_ARCHIVE_SHA256: Readonly<Record<string, string>>;
48
- /** Download size in bytes of every engine archive published by native-v0.1.57. */
48
+ /** Download size in bytes of every engine archive published by native-v0.1.62. */
49
49
  export declare const NATIVE_ENGINE_ARCHIVE_BYTES: Readonly<Record<string, number>>;
50
50
  /**
51
51
  * True only when the pinned release's standalone macOS archives were
@@ -40,47 +40,51 @@
40
40
  * but logs that it could not anchor to a baked-in digest.
41
41
  */
42
42
  /** Native release version this build pins. Placeholder until first public release. */
43
- export const NATIVE_ENGINE_RELEASE = '0.1.57';
43
+ export const NATIVE_ENGINE_RELEASE = '0.1.62';
44
44
  /** sha256 of the pinned release's `SHA256SUMS` asset. All-zeros = unpinned. */
45
- export const SHA256SUMS_DIGEST = '977b0ad4cdb8983ed44d7a3223267038b1f35b2806d8a1807d7d15c5c7e94f47';
45
+ export const SHA256SUMS_DIGEST = '9c2e726c1cef4152b5ffb8cee8e9970cf24127786d3fafcce3582dcf0df9badb';
46
46
  // BEGIN PINNED NATIVE ARCHIVE HASHES
47
- /** Exact SHA256 values for every engine archive published by native-v0.1.57. */
47
+ /** Exact SHA256 values for every engine archive published by native-v0.1.62. */
48
48
  export const NATIVE_ENGINE_ARCHIVE_SHA256 = Object.freeze({
49
- 'gezel-native-0.1.57-darwin-arm64-metal.tar.gz': '6b97be648b032980cf73663db4424140f4cc04577972dc283b956af677ce884a',
50
- 'gezel-native-0.1.57-darwin-arm64.tar.gz': 'e8ca070c4d3961e95946ed32fe7376ddbc97e407dd3f5b78e26cab20c8fb286a',
51
- 'gezel-native-0.1.57-linux-arm64-cpu.tar.gz': 'cc87822123602a0024c63a0d65789232a665140cb2fe37b106d5bd680d12f795',
52
- 'gezel-native-0.1.57-linux-arm64-cuda.tar.gz': '315a441e5698800945f7030e9da961e20f3cf379a4b75c98e1d6ba88c8fee1c5',
53
- 'gezel-native-0.1.57-linux-arm64.tar.gz': '0684b77d23f008f8a2aa0d9d8931437bacd8569fb6c10d3ddab61a5fb25b6a06',
54
- 'gezel-native-0.1.57-linux-x64-cpu.tar.gz': 'b2100842f51c393b92667535798e49932173d52626f5ae72c40005b3408f1201',
55
- 'gezel-native-0.1.57-linux-x64-cuda.tar.gz': '2fca7720614687e8491be17366060c604551257199d395f795b27a87216bcde9',
56
- 'gezel-native-0.1.57-linux-x64-vulkan.tar.gz': 'c1014a1fe1d241ad1ee9abfa5badafcce208cbff8d38b4b4deb4779f31a95bef',
57
- 'gezel-native-0.1.57-linux-x64.tar.gz': 'a7f3dbe1941c3d03ed121c32be1bdd199aea47080b03d89989590a0f5d13c5ff',
58
- 'gezel-native-0.1.57-win32-arm64-cpu.zip': '12d66681cec1872f23b015c7d0bd45a25ed262342da6b0ecea8bea303adf2105',
59
- 'gezel-native-0.1.57-win32-arm64-cuda.zip': 'b437a9f0894673179f91a1af75d5d7d058dafa1b4f48a57eab123596f1c21ca4',
60
- 'gezel-native-0.1.57-win32-arm64.zip': '21cddb8b733f9a2669d64b1ada18002f60bb2779f2d5e2aacfb88214db00da7e',
61
- 'gezel-native-0.1.57-win32-x64-cpu.zip': 'a81f7c6754f1954a0ed5de1efc47d6194dc60d912138a9d2b8e4f992168b12c6',
62
- 'gezel-native-0.1.57-win32-x64-cuda.zip': '9e3f21713fe77c23536dd4124244ac3834f90c82d6e470cb6836a73bb4f7c592',
63
- 'gezel-native-0.1.57-win32-x64-vulkan.zip': '0d473300317b4f6cb072bdd7875ce1536a85fe50e781c435e1aef1c4cbdb08e5',
64
- 'gezel-native-0.1.57-win32-x64.zip': '89a073abcfc97e50b9a0c39f56862b51ac21139b7ca4a3e7a75105dca56292a2',
49
+ 'gezel-native-0.1.62-darwin-arm64-metal.tar.gz': '0ac76122fdc7bd33e6774fb5f62dea6ff22220c483c78026667e33ff8014936d',
50
+ 'gezel-native-0.1.62-darwin-arm64.tar.gz': '23607c3e5c3e6ac050f0594bcf4ca997cff91c57a4b65af985511e1d87843764',
51
+ 'gezel-native-0.1.62-linux-arm64-cpu.tar.gz': 'e9a69cdb07f5ad0103da8d99715e4a1bd257219c55457716ff93e34ee4a544ab',
52
+ 'gezel-native-0.1.62-linux-arm64-cuda.tar.gz': '6389e97d85a2d4b53b4a1c6735669e5cd6022f393fdccabe4c18c9957f9073fc',
53
+ 'gezel-native-0.1.62-linux-arm64.tar.gz': 'cd263de007b14be6de5b828985d3066490a339f097ef199086cd51692495b9f0',
54
+ 'gezel-native-0.1.62-linux-x64-cpu.tar.gz': '2f1b382a02082767187340f8ecd037dfa72953004977e5716ca95127429e4f0b',
55
+ 'gezel-native-0.1.62-linux-x64-cuda.tar.gz': '8f28018fdfd5a38e48dc886a92eab392f92193d3a58c322c85dcd16c6f80fd13',
56
+ 'gezel-native-0.1.62-linux-x64-rocm.tar.gz': '37b88b81bdcbe06fa3c5ebe3b07f0d0112b555449cc2d29775d5ad8373150f18',
57
+ 'gezel-native-0.1.62-linux-x64-vulkan.tar.gz': 'c39fff97dceeacb377a1948ebe9f9553a98485cf21cda9492fbfbe18dd279193',
58
+ 'gezel-native-0.1.62-linux-x64.tar.gz': '2d0c927f98379c0cd1dd05d68f2cc4b87178ede077a65e948bf36e124d560993',
59
+ 'gezel-native-0.1.62-win32-arm64-cpu.zip': 'f867d50591df2da2c2d78cbf844a5b87679da9f5abc9a29ed6b06905c5423bed',
60
+ 'gezel-native-0.1.62-win32-arm64-cuda.zip': 'd42c79845f64ee1fb5e97ea45dde44c6b4705ad6bc4cd6ce9360caffc27cf67f',
61
+ 'gezel-native-0.1.62-win32-arm64.zip': 'd4e660181cd387051d4f8728d6ae008004969786f68da15c76e44704db247af0',
62
+ 'gezel-native-0.1.62-win32-x64-cpu.zip': '85a350c01454e77d49e2a7e463089025d71b6f7cd25daa30b5b0fe8498cf3f2a',
63
+ 'gezel-native-0.1.62-win32-x64-cuda.zip': 'edddeeb820f4612453c036bccd4882c507811464520eb772dfa5bf7b4aa2658f',
64
+ 'gezel-native-0.1.62-win32-x64-rocm.zip': '8640280b49fbc4bc6152b734fcb2dd02b0b9c3375797685470da52406a46aa34',
65
+ 'gezel-native-0.1.62-win32-x64-vulkan.zip': 'a57071775f8876800d6e5689d38a3f7362c4b585e8137596ee19e45ee38b6991',
66
+ 'gezel-native-0.1.62-win32-x64.zip': '357e6c79a4d02968a2ba67299e78efed8dc2ab2d4b40a1e8f866073506b6b2b6',
65
67
  });
66
- /** Download size in bytes of every engine archive published by native-v0.1.57. */
68
+ /** Download size in bytes of every engine archive published by native-v0.1.62. */
67
69
  export const NATIVE_ENGINE_ARCHIVE_BYTES = Object.freeze({
68
- 'gezel-native-0.1.57-darwin-arm64-metal.tar.gz': 7387963,
69
- 'gezel-native-0.1.57-darwin-arm64.tar.gz': 42223786,
70
- 'gezel-native-0.1.57-linux-arm64-cpu.tar.gz': 9223249,
71
- 'gezel-native-0.1.57-linux-arm64-cuda.tar.gz': 621626283,
72
- 'gezel-native-0.1.57-linux-arm64.tar.gz': 42040003,
73
- 'gezel-native-0.1.57-linux-x64-cpu.tar.gz': 13398337,
74
- 'gezel-native-0.1.57-linux-x64-cuda.tar.gz': 1000325316,
75
- 'gezel-native-0.1.57-linux-x64-vulkan.tar.gz': 26290440,
76
- 'gezel-native-0.1.57-linux-x64.tar.gz': 57190295,
77
- 'gezel-native-0.1.57-win32-arm64-cpu.zip': 6049234,
78
- 'gezel-native-0.1.57-win32-arm64-cuda.zip': 243595554,
79
- 'gezel-native-0.1.57-win32-arm64.zip': 42236484,
80
- 'gezel-native-0.1.57-win32-x64-cpu.zip': 9131460,
81
- 'gezel-native-0.1.57-win32-x64-cuda.zip': 756439338,
82
- 'gezel-native-0.1.57-win32-x64-vulkan.zip': 21673895,
83
- 'gezel-native-0.1.57-win32-x64.zip': 55668381,
70
+ 'gezel-native-0.1.62-darwin-arm64-metal.tar.gz': 7577614,
71
+ 'gezel-native-0.1.62-darwin-arm64.tar.gz': 42917428,
72
+ 'gezel-native-0.1.62-linux-arm64-cpu.tar.gz': 9518882,
73
+ 'gezel-native-0.1.62-linux-arm64-cuda.tar.gz': 624413294,
74
+ 'gezel-native-0.1.62-linux-arm64.tar.gz': 43076642,
75
+ 'gezel-native-0.1.62-linux-x64-cpu.tar.gz': 13762290,
76
+ 'gezel-native-0.1.62-linux-x64-cuda.tar.gz': 1016218245,
77
+ 'gezel-native-0.1.62-linux-x64-rocm.tar.gz': 313875007,
78
+ 'gezel-native-0.1.62-linux-x64-vulkan.tar.gz': 26687129,
79
+ 'gezel-native-0.1.62-linux-x64.tar.gz': 58389984,
80
+ 'gezel-native-0.1.62-win32-arm64-cpu.zip': 6219263,
81
+ 'gezel-native-0.1.62-win32-arm64-cuda.zip': 245764366,
82
+ 'gezel-native-0.1.62-win32-arm64.zip': 42822090,
83
+ 'gezel-native-0.1.62-win32-x64-cpu.zip': 9357113,
84
+ 'gezel-native-0.1.62-win32-x64-cuda.zip': 761458453,
85
+ 'gezel-native-0.1.62-win32-x64-rocm.zip': 241630451,
86
+ 'gezel-native-0.1.62-win32-x64-vulkan.zip': 21898409,
87
+ 'gezel-native-0.1.62-win32-x64.zip': 56194044,
84
88
  });
85
89
  // END PINNED NATIVE ARCHIVE HASHES
86
90
  /**
@@ -24,7 +24,7 @@ export type EngineResolveEvent = NativeEngineResolveEvent | EngineExtractingEven
24
24
  export interface ResolveEngineOptions {
25
25
  engine: NativeBinaryName;
26
26
  home: string;
27
- /** GPU backend for llama-server (`cuda`/`vulkan`/`metal`/`cpu`); omit for single-variant engines. */
27
+ /** GPU backend for llama-server (`cuda`/`rocm`/`vulkan`/`metal`/`cpu`); omit for single-variant engines. */
28
28
  variant?: string;
29
29
  /** Native release version; defaults to the source pin / `GEZEL_NATIVE_ENGINE_VERSION`. */
30
30
  version?: string;
@@ -100,22 +100,23 @@ export declare function resolveEngine(opts: ResolveEngineOptions): AsyncGenerato
100
100
  */
101
101
  export declare function resolveEngineToCompletion(opts: ResolveEngineOptions, onEvent?: (e: EngineResolveEvent) => void): Promise<EngineResolveResult>;
102
102
  /**
103
- * The archive variant an engine lives in when the caller names none.
103
+ * The llama-server build an on-demand install fetches when the probe found
104
+ * `detected`: the first build down discovery's own fallback chain (ROCm and
105
+ * CUDA → Vulkan → CPU) that the pinned release publishes for this platform.
106
+ * Without this, a probe answer the release has no archive for — ROCm before
107
+ * the release that first carries it, Vulkan on Linux ARM — failed the install
108
+ * outright instead of taking the next build down.
104
109
  *
105
- * These are facts about *where the archive is*, not backend choices:
106
- *
107
- * - **ds4-server on Linux** ships only in the `-cuda` archive, sharing one
108
- * copy of the NVIDIA redistributables with llama-server's CUDA build
109
- * instead of shipping them twice (see scripts/native-payload.mjs).
110
- * - **llama-server on macOS** ships only in the `-metal` archive; there is no
111
- * `darwin-arm64-cpu` asset, and the bare `darwin-arm64` key holds
112
- * ds4/sd/whisper/uv but no llama-server. Omitting the variant there fails
113
- * the extract with "none of [gezel-llama-server, llama-server] were inside
114
- * it" — a loud error, but an avoidable one.
115
- *
116
- * Deriving both here is the point: every call site would otherwise have to
117
- * remember, and one eventually won't. Where the variant is a genuine choice
118
- * (llama-server on Linux/Windows: cuda / vulkan / cpu) this returns undefined
119
- * and the decision stays with the caller.
110
+ * ROCm also has to be worth its several hundred megabytes before anything
111
+ * downloads: `rocmWorthDownloading` (rocm-devices.ts), which says no on
112
+ * Windows. An explicit `llamaCppBackendOverride` never comes through here.
120
113
  */
114
+ export declare function llamaDownloadVariant(detected: string | undefined, opts?: {
115
+ platform?: NodeJS.Platform;
116
+ platformKey?: string | null;
117
+ version?: string;
118
+ /** Archive names the release publishes; null when unpinned (every build counts). */
119
+ archives?: Readonly<Record<string, string>> | null;
120
+ rocmWorth?: () => boolean;
121
+ }): string | undefined;
121
122
  export declare function impliedEngineVariant(engine: NativeBinaryName, platform: NodeJS.Platform): string | undefined;
@@ -3,7 +3,7 @@ import { createReadStream, existsSync, readdirSync } from 'node:fs';
3
3
  import { chmod, mkdir, readFile, rename, rm, writeFile } from 'node:fs/promises';
4
4
  import { dirname, join } from 'node:path';
5
5
  import { HttpStatusError, createLogger, nowIso, resolveDistributionProfile, retryTransient, } from '@bendyline/gezel';
6
- import { DUCKDB_APPLE_TEAM_ID, DUCKDB_ARCHIVE_SHA256, DUCKDB_ASSET, DUCKDB_BINARY_SHA256, DUCKDB_VERSION, DUCKDB_WINDOWS_PUBLISHER, MXC_EXECUTOR_NAME, MXC_EXECUTOR_SHA256, MXC_LICENSE_SHA256, MXC_TARBALL_INTEGRITY, MXC_TARBALL_LICENSE_ENTRY, MXC_TARBALL_SHA256, MXC_TARBALL_URL, MXC_VERIFIED_SENTINEL, MXC_VERSION, MXC_WINDOWS_PUBLISHER, duckdbAssetUrl, duckdbBinaryName, duckdbInstallDir, duckdbPlatformKey, mxcArch, mxcInstallDir, mxcTarballEntry, resolvePlatformKey, } from '@bendyline/gezel/native';
6
+ import { DUCKDB_APPLE_TEAM_ID, DUCKDB_ARCHIVE_SHA256, DUCKDB_ASSET, DUCKDB_BINARY_SHA256, DUCKDB_VERSION, DUCKDB_WINDOWS_PUBLISHER, MXC_EXECUTOR_NAME, MXC_EXECUTOR_SHA256, MXC_LICENSE_SHA256, MXC_TARBALL_INTEGRITY, MXC_TARBALL_LICENSE_ENTRY, MXC_TARBALL_SHA256, MXC_TARBALL_URL, MXC_VERIFIED_SENTINEL, MXC_VERSION, MXC_WINDOWS_PUBLISHER, duckdbAssetUrl, duckdbBinaryName, duckdbInstallDir, duckdbPlatformKey, mxcArch, mxcInstallDir, mxcTarballEntry, resolveAvailableLlamaBinary, resolvePlatformKey, rocmWorthDownloading, } from '@bendyline/gezel/native';
7
7
  import * as tar from 'tar';
8
8
  import { downloadWithRetry, friendlyErrors, } from '../utils/download-with-retry.js';
9
9
  import { extractZip } from '../utils/extract-zip.js';
@@ -744,6 +744,41 @@ function stripVer(v) {
744
744
  * (llama-server on Linux/Windows: cuda / vulkan / cpu) this returns undefined
745
745
  * and the decision stays with the caller.
746
746
  */
747
+ const LLAMA_DOWNLOAD_BACKENDS = ['cuda', 'rocm', 'vulkan', 'metal', 'cpu'];
748
+ /**
749
+ * The llama-server build an on-demand install fetches when the probe found
750
+ * `detected`: the first build down discovery's own fallback chain (ROCm and
751
+ * CUDA → Vulkan → CPU) that the pinned release publishes for this platform.
752
+ * Without this, a probe answer the release has no archive for — ROCm before
753
+ * the release that first carries it, Vulkan on Linux ARM — failed the install
754
+ * outright instead of taking the next build down.
755
+ *
756
+ * ROCm also has to be worth its several hundred megabytes before anything
757
+ * downloads: `rocmWorthDownloading` (rocm-devices.ts), which says no on
758
+ * Windows. An explicit `llamaCppBackendOverride` never comes through here.
759
+ */
760
+ export function llamaDownloadVariant(detected, opts = {}) {
761
+ const platform = opts.platform ?? process.platform;
762
+ if (platform === 'darwin')
763
+ return impliedEngineVariant('llama-server', platform);
764
+ const preferred = LLAMA_DOWNLOAD_BACKENDS.find((backend) => backend === detected);
765
+ if (!preferred)
766
+ return detected;
767
+ const platformKey = opts.platformKey === undefined ? resolvePlatformKey() : opts.platformKey;
768
+ const version = stripVer(opts.version ?? effectiveEngineRelease());
769
+ const ext = platform === 'win32' ? 'zip' : 'tar.gz';
770
+ const archives = opts.archives === undefined
771
+ ? isPlaceholderDigest(SHA256SUMS_DIGEST) || process.env.GEZEL_NATIVE_ENGINE_VERSION
772
+ ? null
773
+ : NATIVE_ENGINE_ARCHIVE_SHA256
774
+ : opts.archives;
775
+ const rocmWorth = opts.rocmWorth ?? (() => rocmWorthDownloading({ platform }));
776
+ const resolved = resolveAvailableLlamaBinary(preferred, (backend) => {
777
+ const name = `gezel-native-${version}-${platformKey}-${backend}.${ext}`;
778
+ return !archives || archives[name] ? name : null;
779
+ }, true, (backend) => backend !== 'rocm' || rocmWorth());
780
+ return resolved?.backend ?? preferred;
781
+ }
747
782
  export function impliedEngineVariant(engine, platform) {
748
783
  if (engine === 'ds4-server' && platform === 'linux')
749
784
  return 'cuda';
@@ -4,5 +4,5 @@ export interface CacheEntry {
4
4
  at: number;
5
5
  models: ModelInfo[];
6
6
  }
7
- export declare const cache: Map<"copilot" | "openai" | "anthropic" | "anthropic-cli" | "codex-cli" | "ollama" | "llama-cpp" | "mlx" | "ds4" | "apple-foundation-models" | "android-mlkit" | "remote", CacheEntry>;
7
+ export declare const cache: Map<"copilot" | "openai" | "anthropic" | "anthropic-cli" | "codex-cli" | "ollama" | "llama-cpp" | "mlx" | "ds4" | "remote" | "apple-foundation-models" | "android-mlkit", CacheEntry>;
8
8
  export declare function invalidateModelsCache(provider?: ProviderName): void;
@@ -40,7 +40,7 @@ export function enginesRoutes(ctx) {
40
40
  */
41
41
  app.get('/binaries/status', (c) => {
42
42
  const backendRaw = process.env.GEZEL_LLAMA_SERVER_BACKEND ?? process.env.GEZEL_LLAMA_DETECTED_BACKEND;
43
- const llamaBackend = ['cuda', 'vulkan', 'metal', 'cpu'].find((value) => value === backendRaw);
43
+ const llamaBackend = ['cuda', 'rocm', 'vulkan', 'metal', 'cpu'].find((value) => value === backendRaw);
44
44
  const platformKey = resolvePlatformKey();
45
45
  return c.json({
46
46
  release: effectiveEngineRelease(),
@@ -64,7 +64,7 @@ export function enginesRoutes(ctx) {
64
64
  });
65
65
  /**
66
66
  * Start (or attach to) a download+verify of `engine` (optionally a GPU
67
- * `?variant=cuda|vulkan|metal|cpu`) and stream progress as SSE. The
67
+ * `?variant=cuda|rocm|vulkan|metal|cpu`) and stream progress as SSE. The
68
68
  * manual trigger behind Settings → On-device → "Download engine". The
69
69
  * lazy on-device-chat path uses the same registry. Idempotent — a
70
70
  * second call while one is in flight attaches to the running job.
@@ -231,7 +231,7 @@ export function enginesRoutes(ctx) {
231
231
  app.delete('/llama-cpp/quarantine/:backend', async (c) => {
232
232
  const backend = c.req.param('backend');
233
233
  if (!isLlamaBackend(backend)) {
234
- return c.json({ error: 'backend must be "cuda", "vulkan", "metal", or "cpu"' }, 400);
234
+ return c.json({ error: 'backend must be "cuda", "rocm", "vulkan", "metal", or "cpu"' }, 400);
235
235
  }
236
236
  const override = (await ctx.store.readConfig()).llamaCppBackendOverride;
237
237
  const { restored } = liftLlamaQuarantine(ctx.home, backend, {
@@ -25,7 +25,8 @@ export interface ImagesRouteContext {
25
25
  * GET /models Installed and downloadable image models,
26
26
  * with this machine's fit. Never part of
27
27
  * `/v1/models`, so chat pickers never
28
- * offer them.
28
+ * offer them. Models that only change a
29
+ * given picture are left out.
29
30
  * POST /models/ensure `{model: "sd-cpp:<id>"}` → ready, or a
30
31
  * background download (`job_id`).
31
32
  * GET /models/ensure/:jobId Snapshot of a download.
@@ -4,8 +4,9 @@ import { streamSSE } from 'hono/streaming';
4
4
  import { z } from 'zod';
5
5
  import { imageCatalogFits, imageModelFit, wontRunRefusal } from '../../models/image-fit.js';
6
6
  import { ReadOnlyModelError, modelExistsOnlyReadOnly, modelStorageRoots, } from '../../models/storage-roots.js';
7
+ import { resolveImageEditCapability } from '../../providers/image/img2img-support.js';
7
8
  import { NoLocalImageModelError } from '../../providers/image/local-factory.js';
8
- import { ImageCapacityError, ImageGenerationCancelledError, } from '../../providers/image/types.js';
9
+ import { ImageCapacityError, ImageGenerationCancelledError, ImageSourceRequiredError, } from '../../providers/image/types.js';
9
10
  import { registerImageEnsureRoutes } from './image-ensure-routes.js';
10
11
  import { v1ImageStylesRoutes } from './v1-image-styles.js';
11
12
  const log = createLogger('v1-images');
@@ -28,6 +29,17 @@ function catalogIdOf(model) {
28
29
  function qualified(catalogId) {
29
30
  return `${ENGINE}:${catalogId}`;
30
31
  }
32
+ /**
33
+ * Made only to change a picture it is given. Generations here take no source
34
+ * picture, so such a model can never render one: it is left out of the list
35
+ * and refused by name, never handed a blank page.
36
+ */
37
+ function editsOnly(modelId, declared) {
38
+ return resolveImageEditCapability({ modelId, editOnly: declared }).editOnly;
39
+ }
40
+ function editOnlyError(name) {
41
+ return apiError('edit_only_model', `${name} only changes a picture it is given and cannot draw a new one. Pick another image model.`);
42
+ }
31
43
  function downloadBytes(manifest) {
32
44
  return (manifest.approxSizeBytes + manifest.auxiliaryFiles.reduce((n, f) => n + f.approxSizeBytes, 0));
33
45
  }
@@ -60,6 +72,8 @@ function generationError(err) {
60
72
  return { code: err.code, message };
61
73
  if (err instanceof NoLocalImageModelError)
62
74
  return { code: err.code, message };
75
+ if (err instanceof ImageSourceRequiredError)
76
+ return { code: err.code, message };
63
77
  const code = err?.code;
64
78
  if (code === 'capacity-denied')
65
79
  return { code: 'capacity_denied', message };
@@ -71,7 +85,8 @@ function generationError(err) {
71
85
  * GET /models Installed and downloadable image models,
72
86
  * with this machine's fit. Never part of
73
87
  * `/v1/models`, so chat pickers never
74
- * offer them.
88
+ * offer them. Models that only change a
89
+ * given picture are left out.
75
90
  * POST /models/ensure `{model: "sd-cpp:<id>"}` → ready, or a
76
91
  * background download (`job_id`).
77
92
  * GET /models/ensure/:jobId Snapshot of a download.
@@ -117,6 +132,8 @@ export function v1ImagesRoutes(ctx) {
117
132
  if (manifest.kind !== 'image-model')
118
133
  continue;
119
134
  seen.add(manifest.id);
135
+ if (editsOnly(manifest.id, manifest.editOnly))
136
+ continue;
120
137
  const fit = fitById.get(manifest.id);
121
138
  const isInstalled = installedIds.has(manifest.id);
122
139
  data.push({
@@ -137,7 +154,7 @@ export function v1ImagesRoutes(ctx) {
137
154
  }
138
155
  // Installed models the catalog no longer lists still render.
139
156
  for (const model of installed) {
140
- if (seen.has(model.id))
157
+ if (seen.has(model.id) || editsOnly(model.id, model.editOnly))
141
158
  continue;
142
159
  data.push({
143
160
  id: qualified(model.id),
@@ -157,8 +174,17 @@ export function v1ImagesRoutes(ctx) {
157
174
  return c.json(apiError('unsupported_backend', `Image models are ${ENGINE}:<id>`), 400);
158
175
  }
159
176
  const provider = await ctx.images.current();
160
- const installed = await provider.listInstalledModels();
161
- if (installed.some((m) => m.id === id)) {
177
+ const [installed, item] = await Promise.all([
178
+ provider.listInstalledModels(),
179
+ ctx.catalog.get('image-model', id).catch(() => null),
180
+ ]);
181
+ const local = installed.find((m) => m.id === id);
182
+ const listed = item?.manifest.kind === 'image-model' ? item.manifest : undefined;
183
+ // Downloading one would fetch gigabytes no generation here can use.
184
+ if (editsOnly(id, local?.editOnly ?? listed?.editOnly)) {
185
+ return c.json(editOnlyError(local?.name ?? listed?.name ?? model), 409);
186
+ }
187
+ if (local) {
162
188
  return c.json({ status: 'ready', model_id: qualified(id) });
163
189
  }
164
190
  const refusal = await wontRunRefusal(() => imageModelFit(fitContext, id));
@@ -209,16 +235,17 @@ export function v1ImagesRoutes(ctx) {
209
235
  return c.json(apiError('unsupported_backend', `Image models are ${ENGINE}:<id>`), 400);
210
236
  }
211
237
  const modelId = requested ?? (await provider.resolveDefaultModelId?.());
212
- if (!modelId || !installed.some((m) => m.id === modelId)) {
238
+ const chosen = modelId ? installed.find((m) => m.id === modelId) : undefined;
239
+ if (!modelId || !chosen) {
213
240
  const error = requested
214
241
  ? apiError('model_not_installed', `${request.model} is not installed; ensure it first`)
215
242
  : apiError('no_local_image_model', new NoLocalImageModelError().message);
216
243
  return c.json(error, 409);
217
244
  }
245
+ if (editsOnly(modelId, chosen.editOnly))
246
+ return c.json(editOnlyError(chosen.name), 409);
218
247
  const style = request.style
219
- ? installed
220
- .find((model) => model.id === modelId)
221
- ?.loras?.find((lora) => lora.id === request.style && lora.purpose === 'style')
248
+ ? chosen.loras?.find((lora) => lora.id === request.style && lora.purpose === 'style')
222
249
  : undefined;
223
250
  if (request.style && !style) {
224
251
  return c.json(apiError('style_not_available', 'That style is not installed for this image model.'), 409);
@@ -8,7 +8,7 @@
8
8
  * class never opens a catalog database itself.
9
9
  */
10
10
  import type { GezelConfig, IncompleteKnowledgeDownload, KnowledgeActiveInstall, KnowledgeAvailableCatalog, KnowledgeCatalogRef, KnowledgeCatalogStatus, KnowledgeEmbeddingProfile, KnowledgeInstallEvent, KnowledgeInstallJob, KnowledgeInstallRequest, KnowledgePassageRead, KnowledgeSemanticSearchMode, KnowledgeUpdateCandidate, KnowledgeUri, ProjectKnowledgeCatalogs, UnifiedSearchResult } from '@bendyline/gezel';
11
- import { type KnowledgeNearbyRequest, type KnowledgeNearbyResponse, type KnowledgeRadius } from '@bendyline/gezel';
11
+ import { type KnowledgeNearbyRequest, type KnowledgeNearbyResponse } from '@bendyline/gezel';
12
12
  import type { HistoryEvent } from '@bendyline/gezel';
13
13
  import type { CatalogService } from '@bendyline/gezel-catalog';
14
14
  import { type ModelDownloadProgress } from '@bendyline/gezel-knowledge';
@@ -22,6 +22,7 @@ import { ChatModelInstallRegistry } from '../models/install-registry.js';
22
22
  import type { KnowledgeCatalogHost, KnowledgeChunk } from './catalog-host.js';
23
23
  import { KnowledgeRegistry } from './registry.js';
24
24
  import type { SharedKnowledgeInstaller } from './shared-install-contract.js';
25
+ import { type UnifiedSearchOptions } from './unified-search.js';
25
26
  import { type KnowledgeVectorFloors } from './vector-floors.js';
26
27
  export type { KnowledgeCatalogStatus, KnowledgeInstallJob, KnowledgeSemanticSearchMode };
27
28
  export type KnowledgeInstallRequestSource = KnowledgeInstallRequest['source'];
@@ -245,31 +246,7 @@ export declare class KnowledgeManager {
245
246
  * Search each catalog in its embedding space and fuse lexical/vector ranks.
246
247
  * Spatial eligibility applies inside workers before candidate selection.
247
248
  */
248
- searchUnified(query: string, opts: {
249
- vector: number[] | null;
250
- maxResults: number;
251
- projectId?: string;
252
- spatial?: KnowledgeRadius;
253
- catalogs?: readonly string[];
254
- /** Search a profile group keyword-only when its query model is not ready by then. */
255
- queryEmbedBudgetMs?: number;
256
- /** Query cached profile models only, falling back to keywords when absent. */
257
- localModelsOnly?: boolean;
258
- /**
259
- * Include media rows (images, audio and video windows) as results of
260
- * their own. Explicit search asks; proactive injection does not.
261
- */
262
- media?: boolean;
263
- /**
264
- * Also return up to this many of a document's other passages that the
265
- * search found, after its best one. Fusion otherwise keeps one passage
266
- * per document, chosen by vector similarity alone, so an article's name-
267
- * dense infobox can stand in for the section a reranker would choose.
268
- */
269
- chunksPerDocument?: number;
270
- }): Promise<UnifiedSearchResult[]>;
271
- /** A document the lexical arms named but no chunk carries: cite it with its lead paragraph. */
272
- private toDocumentResult;
249
+ searchUnified(query: string, opts: UnifiedSearchOptions): Promise<UnifiedSearchResult[]>;
273
250
  /** A catalog's vector floor, or null when its hits are keyword-only or its scale unmeasured. */
274
251
  private vectorFloorFor;
275
252
  /**
@@ -285,7 +262,6 @@ export declare class KnowledgeManager {
285
262
  * next query gets vectors.
286
263
  */
287
264
  private embedForProfile;
288
- private toResult;
289
265
  /** Enabled+mounted catalogs, intersected with the project policy. */
290
266
  private activeCatalogKeys;
291
267
  }