@bendyline/gezel-inference 1.0.2 → 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.
Files changed (215) hide show
  1. package/dist/catalog/chat-models/de/deepseek-v4.1-flash-552b-q2/manifest.json +120 -0
  2. package/dist/catalog/chat-models/de/deepseek-v4.1-flash-552b-q2/versions/1.0.0/manifest.json +21 -0
  3. package/dist/catalog/chat-models/gl/glm-5.3-flash-320b-q2/manifest.json +6 -5
  4. package/dist/catalog/chat-models/gl/glm-5.3-flash-320b-q2/versions/1.0.2/manifest.json +27 -0
  5. package/dist/catalog/chat-models/gl/glm-5.3-flash-320b-q2/versions/1.0.3/manifest.json +27 -0
  6. package/dist/catalog/chat-models/index.json +1 -1
  7. package/dist/catalog/chat-models/ne/nemotron3.5-bolt-74b-iq2/manifest.json +157 -0
  8. package/dist/catalog/chat-models/ne/nemotron3.5-bolt-74b-iq2/versions/1.0.0/manifest.json +30 -0
  9. package/dist/catalog/chat-models/ne/nemotron3.5-super-vl-120b-nvfp4/manifest.json +156 -0
  10. package/dist/catalog/chat-models/ne/nemotron3.5-super-vl-120b-nvfp4/versions/1.0.0/manifest.json +28 -0
  11. package/dist/catalog/chat-models/raw-index.json +1 -1
  12. package/dist/catalog/knowledge-catalogs/be/bendyline-how-to-books/keywords.json +56 -0
  13. package/dist/catalog/knowledge-catalogs/ca/caselaw-alaska-part-0001/keywords.json +12 -0
  14. package/dist/catalog/knowledge-catalogs/ca/caselaw-nevada-part-0001/keywords.json +13 -0
  15. package/dist/catalog/knowledge-catalogs/ca/caselaw-us-300-399-part-0001/keywords.json +14 -0
  16. package/dist/catalog/knowledge-catalogs/ca/caselaw-us-347-349/keywords.json +17 -0
  17. package/dist/catalog/knowledge-catalogs/ca/caselaw-utah-part-0001/keywords.json +12 -0
  18. package/dist/catalog/knowledge-catalogs/ca/caselaw-utah-part-0002/keywords.json +12 -0
  19. package/dist/catalog/knowledge-catalogs/ca/caselaw-washington-part-0001/keywords.json +12 -0
  20. package/dist/catalog/knowledge-catalogs/ca/caselaw-washington-part-0002/keywords.json +12 -0
  21. package/dist/catalog/knowledge-catalogs/ca/caselaw-washington-part-0003/keywords.json +12 -0
  22. package/dist/catalog/knowledge-catalogs/ca/caselaw-washington-part-0004/keywords.json +12 -0
  23. package/dist/catalog/knowledge-catalogs/ca/caselaw-washington-part-0005/keywords.json +12 -0
  24. package/dist/catalog/knowledge-catalogs/ca/caselaw-wyoming-part-0001/keywords.json +12 -0
  25. package/dist/catalog/knowledge-catalogs/index.json +1 -1
  26. package/dist/catalog/knowledge-catalogs/mi/microsoftdocs-aspnet-core-en/keywords.json +21 -0
  27. package/dist/catalog/knowledge-catalogs/mi/microsoftdocs-azure-ai-platform-en/keywords.json +27 -0
  28. package/dist/catalog/knowledge-catalogs/mi/microsoftdocs-azure-apps-compute-en/keywords.json +23 -0
  29. package/dist/catalog/knowledge-catalogs/mi/microsoftdocs-azure-data-aiot-en/keywords.json +26 -0
  30. package/dist/catalog/knowledge-catalogs/mi/microsoftdocs-azure-management-hybrid-en/keywords.json +28 -0
  31. package/dist/catalog/knowledge-catalogs/mi/microsoftdocs-azure-network-security-en/keywords.json +29 -0
  32. package/dist/catalog/knowledge-catalogs/mi/microsoftdocs-dotnet-en/keywords.json +21 -0
  33. package/dist/catalog/knowledge-catalogs/mi/microsoftdocs-entity-framework-en/keywords.json +14 -0
  34. package/dist/catalog/knowledge-catalogs/mi/microsoftdocs-microsoft-365-en/keywords.json +20 -0
  35. package/dist/catalog/knowledge-catalogs/mi/microsoftdocs-powershell-en/keywords.json +24 -0
  36. package/dist/catalog/knowledge-catalogs/mi/microsoftdocs-sql-server-en/keywords.json +27 -0
  37. package/dist/catalog/knowledge-catalogs/mi/microsoftdocs-windows-apps-en/keywords.json +18 -0
  38. package/dist/catalog/knowledge-catalogs/mi/microsoftdocs-windows-server-en/keywords.json +28 -0
  39. package/dist/catalog/knowledge-catalogs/raw-index.json +1 -1
  40. package/dist/catalog/knowledge-catalogs/re/regional-american-south/keywords.json +1700 -0
  41. package/dist/catalog/knowledge-catalogs/re/regional-american-south/versions/2026.10.5/manifest.json +133 -0
  42. package/dist/catalog/knowledge-catalogs/re/regional-andes-amazon/keywords.json +750 -0
  43. package/dist/catalog/knowledge-catalogs/re/regional-andes-amazon/versions/2026.10.5/manifest.json +133 -0
  44. package/dist/catalog/knowledge-catalogs/re/regional-australia-nz/keywords.json +1281 -0
  45. package/dist/catalog/knowledge-catalogs/re/regional-australia-nz/versions/2026.10.5/manifest.json +133 -0
  46. package/dist/catalog/knowledge-catalogs/re/regional-brazil/keywords.json +1125 -0
  47. package/dist/catalog/knowledge-catalogs/re/regional-brazil/versions/2026.10.5/manifest.json +133 -0
  48. package/dist/catalog/knowledge-catalogs/re/regional-britain-ireland/keywords.json +3287 -0
  49. package/dist/catalog/knowledge-catalogs/re/regional-britain-ireland/versions/2026.10.5/manifest.json +133 -0
  50. package/dist/catalog/knowledge-catalogs/re/regional-california-southwest/keywords.json +1835 -0
  51. package/dist/catalog/knowledge-catalogs/re/regional-california-southwest/versions/2026.10.5/manifest.json +133 -0
  52. package/dist/catalog/knowledge-catalogs/re/regional-canada-alaska/keywords.json +1184 -0
  53. package/dist/catalog/knowledge-catalogs/re/regional-canada-alaska/versions/2026.10.5/manifest.json +133 -0
  54. package/dist/catalog/knowledge-catalogs/re/regional-central-eastern-europe/keywords.json +1503 -0
  55. package/dist/catalog/knowledge-catalogs/re/regional-central-eastern-europe/versions/2026.10.5/manifest.json +133 -0
  56. package/dist/catalog/knowledge-catalogs/re/regional-east-asia/keywords.json +2836 -0
  57. package/dist/catalog/knowledge-catalogs/re/regional-east-asia/versions/2026.10.5/manifest.json +133 -0
  58. package/dist/catalog/knowledge-catalogs/re/regional-east-southern-africa/keywords.json +813 -0
  59. package/dist/catalog/knowledge-catalogs/re/regional-east-southern-africa/versions/2026.10.5/manifest.json +133 -0
  60. package/dist/catalog/knowledge-catalogs/re/regional-mediterranean/keywords.json +2082 -0
  61. package/dist/catalog/knowledge-catalogs/re/regional-mediterranean/versions/2026.10.5/manifest.json +133 -0
  62. package/dist/catalog/knowledge-catalogs/re/regional-mexico-central-america/keywords.json +1481 -0
  63. package/dist/catalog/knowledge-catalogs/re/regional-mexico-central-america/versions/2026.10.5/manifest.json +133 -0
  64. package/dist/catalog/knowledge-catalogs/re/regional-middle-east/keywords.json +1272 -0
  65. package/dist/catalog/knowledge-catalogs/re/regional-middle-east/versions/2026.10.5/manifest.json +133 -0
  66. package/dist/catalog/knowledge-catalogs/re/regional-midwest/keywords.json +758 -0
  67. package/dist/catalog/knowledge-catalogs/re/regional-midwest/versions/2026.10.5/manifest.json +133 -0
  68. package/dist/catalog/knowledge-catalogs/re/regional-north-africa/keywords.json +896 -0
  69. package/dist/catalog/knowledge-catalogs/re/regional-north-africa/versions/2026.10.5/manifest.json +133 -0
  70. package/dist/catalog/knowledge-catalogs/re/regional-northeast/keywords.json +1281 -0
  71. package/dist/catalog/knowledge-catalogs/re/regional-northeast/versions/2026.10.5/manifest.json +133 -0
  72. package/dist/catalog/knowledge-catalogs/re/regional-northern-eurasia/keywords.json +346 -0
  73. package/dist/catalog/knowledge-catalogs/re/regional-northern-eurasia/versions/2026.10.5/manifest.json +133 -0
  74. package/dist/catalog/knowledge-catalogs/re/regional-northern-europe/keywords.json +2688 -0
  75. package/dist/catalog/knowledge-catalogs/re/regional-northern-europe/versions/2026.10.5/manifest.json +133 -0
  76. package/dist/catalog/knowledge-catalogs/re/regional-pacific-islands/keywords.json +973 -0
  77. package/dist/catalog/knowledge-catalogs/re/regional-pacific-islands/versions/2026.10.5/manifest.json +133 -0
  78. package/dist/catalog/knowledge-catalogs/re/regional-pacific-northwest/keywords.json +937 -0
  79. package/dist/catalog/knowledge-catalogs/re/regional-pacific-northwest/versions/2026.10.5/manifest.json +133 -0
  80. package/dist/catalog/knowledge-catalogs/re/regional-rockies-plains/keywords.json +608 -0
  81. package/dist/catalog/knowledge-catalogs/re/regional-rockies-plains/versions/2026.10.5/manifest.json +133 -0
  82. package/dist/catalog/knowledge-catalogs/re/regional-south-asia/keywords.json +633 -0
  83. package/dist/catalog/knowledge-catalogs/re/regional-south-asia/versions/2026.10.5/manifest.json +133 -0
  84. package/dist/catalog/knowledge-catalogs/re/regional-southeast-asia/keywords.json +2697 -0
  85. package/dist/catalog/knowledge-catalogs/re/regional-southeast-asia/versions/2026.10.5/manifest.json +133 -0
  86. package/dist/catalog/knowledge-catalogs/re/regional-southern-cone/keywords.json +606 -0
  87. package/dist/catalog/knowledge-catalogs/re/regional-southern-cone/versions/2026.10.5/manifest.json +133 -0
  88. package/dist/catalog/knowledge-catalogs/re/regional-west-central-africa/keywords.json +564 -0
  89. package/dist/catalog/knowledge-catalogs/re/regional-west-central-africa/versions/2026.10.5/manifest.json +133 -0
  90. package/dist/catalog/knowledge-catalogs/re/regional-western-europe/keywords.json +3247 -0
  91. package/dist/catalog/knowledge-catalogs/re/regional-western-europe-east/manifest.json +47 -0
  92. package/dist/catalog/knowledge-catalogs/re/regional-western-europe-east/versions/2026.10.5/manifest.json +133 -0
  93. package/dist/catalog/knowledge-catalogs/re/regional-western-europe-west/manifest.json +47 -0
  94. package/dist/catalog/knowledge-catalogs/re/regional-western-europe-west/versions/2026.10.5/manifest.json +133 -0
  95. package/dist/catalog/knowledge-catalogs/wi/wikipedia-arts/keywords.json +5437 -0
  96. package/dist/catalog/knowledge-catalogs/wi/wikipedia-arts/manifest.json +1 -1
  97. package/dist/catalog/knowledge-catalogs/wi/wikipedia-arts/versions/2026.10.1/manifest.json +181 -0
  98. package/dist/catalog/knowledge-catalogs/wi/wikipedia-astronomy/keywords.json +4009 -0
  99. package/dist/catalog/knowledge-catalogs/wi/wikipedia-astronomy/manifest.json +1 -1
  100. package/dist/catalog/knowledge-catalogs/wi/wikipedia-astronomy/versions/2026.10.1/manifest.json +181 -0
  101. package/dist/catalog/knowledge-catalogs/wi/wikipedia-biology/keywords.json +4009 -0
  102. package/dist/catalog/knowledge-catalogs/wi/wikipedia-biology/manifest.json +1 -1
  103. package/dist/catalog/knowledge-catalogs/wi/wikipedia-biology/versions/2026.10.1/manifest.json +217 -0
  104. package/dist/catalog/knowledge-catalogs/wi/wikipedia-business/keywords.json +5583 -0
  105. package/dist/catalog/knowledge-catalogs/wi/wikipedia-business/manifest.json +1 -1
  106. package/dist/catalog/knowledge-catalogs/wi/wikipedia-business/versions/2026.10.1/manifest.json +197 -0
  107. package/dist/catalog/knowledge-catalogs/wi/wikipedia-film-tv/keywords.json +6386 -0
  108. package/dist/catalog/knowledge-catalogs/wi/wikipedia-film-tv/manifest.json +2 -2
  109. package/dist/catalog/knowledge-catalogs/wi/wikipedia-film-tv/versions/2026.10.1/manifest.json +197 -0
  110. package/dist/catalog/knowledge-catalogs/wi/wikipedia-food-drink/keywords.json +4009 -0
  111. package/dist/catalog/knowledge-catalogs/wi/wikipedia-food-drink/manifest.json +1 -1
  112. package/dist/catalog/knowledge-catalogs/wi/wikipedia-food-drink/versions/2026.10.1/manifest.json +185 -0
  113. package/dist/catalog/knowledge-catalogs/wi/wikipedia-games/keywords.json +5672 -0
  114. package/dist/catalog/knowledge-catalogs/wi/wikipedia-games/manifest.json +1 -1
  115. package/dist/catalog/knowledge-catalogs/wi/wikipedia-games/versions/2026.10.1/manifest.json +137 -0
  116. package/dist/catalog/knowledge-catalogs/wi/wikipedia-geography/manifest.json +68 -0
  117. package/dist/catalog/knowledge-catalogs/wi/wikipedia-geography/versions/2026.10.1/manifest.json +217 -0
  118. package/dist/catalog/knowledge-catalogs/wi/wikipedia-history/manifest.json +68 -0
  119. package/dist/catalog/knowledge-catalogs/wi/wikipedia-history/versions/2026.10.1/manifest.json +217 -0
  120. package/dist/catalog/knowledge-catalogs/wi/wikipedia-language/keywords.json +4009 -0
  121. package/dist/catalog/knowledge-catalogs/wi/wikipedia-language/manifest.json +1 -1
  122. package/dist/catalog/knowledge-catalogs/wi/wikipedia-language/versions/2026.10.1/manifest.json +141 -0
  123. package/dist/catalog/knowledge-catalogs/wi/wikipedia-law/keywords.json +4009 -0
  124. package/dist/catalog/knowledge-catalogs/wi/wikipedia-law/manifest.json +1 -1
  125. package/dist/catalog/knowledge-catalogs/wi/wikipedia-law/versions/2026.10.1/manifest.json +185 -0
  126. package/dist/catalog/knowledge-catalogs/wi/wikipedia-literature/keywords.json +5719 -0
  127. package/dist/catalog/knowledge-catalogs/wi/wikipedia-literature/manifest.json +1 -1
  128. package/dist/catalog/knowledge-catalogs/wi/wikipedia-literature/versions/2026.10.1/manifest.json +193 -0
  129. package/dist/catalog/knowledge-catalogs/wi/wikipedia-mathematics/keywords.json +4009 -0
  130. package/dist/catalog/knowledge-catalogs/wi/wikipedia-mathematics/manifest.json +1 -1
  131. package/dist/catalog/knowledge-catalogs/wi/wikipedia-mathematics/versions/2026.10.1/manifest.json +189 -0
  132. package/dist/catalog/knowledge-catalogs/wi/wikipedia-medicine/keywords.json +16009 -0
  133. package/dist/catalog/knowledge-catalogs/wi/wikipedia-medicine/manifest.json +1 -1
  134. package/dist/catalog/knowledge-catalogs/wi/wikipedia-medicine/versions/2026.10.1/manifest.json +185 -0
  135. package/dist/catalog/knowledge-catalogs/wi/wikipedia-military/keywords.json +5843 -0
  136. package/dist/catalog/knowledge-catalogs/wi/wikipedia-military/manifest.json +1 -1
  137. package/dist/catalog/knowledge-catalogs/wi/wikipedia-military/versions/2026.10.1/manifest.json +189 -0
  138. package/dist/catalog/knowledge-catalogs/wi/wikipedia-music/keywords.json +6264 -0
  139. package/dist/catalog/knowledge-catalogs/wi/wikipedia-music/manifest.json +1 -1
  140. package/dist/catalog/knowledge-catalogs/wi/wikipedia-music/versions/2026.10.1/manifest.json +197 -0
  141. package/dist/catalog/knowledge-catalogs/wi/wikipedia-people-arts/manifest.json +66 -0
  142. package/dist/catalog/knowledge-catalogs/wi/wikipedia-people-arts/versions/2026.10.1/manifest.json +209 -0
  143. package/dist/catalog/knowledge-catalogs/wi/wikipedia-people-business/manifest.json +61 -0
  144. package/dist/catalog/knowledge-catalogs/wi/wikipedia-people-business/versions/2026.10.1/manifest.json +189 -0
  145. package/dist/catalog/knowledge-catalogs/wi/wikipedia-people-entertainment/manifest.json +64 -0
  146. package/dist/catalog/knowledge-catalogs/wi/wikipedia-people-entertainment/versions/2026.10.1/manifest.json +201 -0
  147. package/dist/catalog/knowledge-catalogs/wi/wikipedia-people-military/manifest.json +60 -0
  148. package/dist/catalog/knowledge-catalogs/wi/wikipedia-people-military/versions/2026.10.1/manifest.json +185 -0
  149. package/dist/catalog/knowledge-catalogs/wi/wikipedia-people-other/manifest.json +55 -0
  150. package/dist/catalog/knowledge-catalogs/wi/wikipedia-people-other/versions/2026.10.1/manifest.json +165 -0
  151. package/dist/catalog/knowledge-catalogs/wi/wikipedia-people-politics/manifest.json +63 -0
  152. package/dist/catalog/knowledge-catalogs/wi/wikipedia-people-politics/versions/2026.10.1/manifest.json +197 -0
  153. package/dist/catalog/knowledge-catalogs/wi/wikipedia-people-religion/manifest.json +64 -0
  154. package/dist/catalog/knowledge-catalogs/wi/wikipedia-people-religion/versions/2026.10.1/manifest.json +201 -0
  155. package/dist/catalog/knowledge-catalogs/wi/wikipedia-people-science/manifest.json +65 -0
  156. package/dist/catalog/knowledge-catalogs/wi/wikipedia-people-science/versions/2026.10.1/manifest.json +205 -0
  157. package/dist/catalog/knowledge-catalogs/wi/wikipedia-people-sports/manifest.json +73 -0
  158. package/dist/catalog/knowledge-catalogs/wi/wikipedia-people-sports/versions/2026.10.1/manifest.json +237 -0
  159. package/dist/catalog/knowledge-catalogs/wi/wikipedia-politics/keywords.json +5447 -0
  160. package/dist/catalog/knowledge-catalogs/wi/wikipedia-politics/manifest.json +1 -1
  161. package/dist/catalog/knowledge-catalogs/wi/wikipedia-politics/versions/2026.10.1/manifest.json +197 -0
  162. package/dist/catalog/knowledge-catalogs/wi/wikipedia-religion-philosophy/keywords.json +4009 -0
  163. package/dist/catalog/knowledge-catalogs/wi/wikipedia-religion-philosophy/manifest.json +1 -1
  164. package/dist/catalog/knowledge-catalogs/wi/wikipedia-religion-philosophy/versions/2026.10.1/manifest.json +189 -0
  165. package/dist/catalog/knowledge-catalogs/wi/wikipedia-science/keywords.json +4009 -0
  166. package/dist/catalog/knowledge-catalogs/wi/wikipedia-science/manifest.json +1 -1
  167. package/dist/catalog/knowledge-catalogs/wi/wikipedia-science/versions/2026.10.1/manifest.json +185 -0
  168. package/dist/catalog/knowledge-catalogs/wi/wikipedia-sports/keywords.json +5209 -0
  169. package/dist/catalog/knowledge-catalogs/wi/wikipedia-sports/manifest.json +1 -1
  170. package/dist/catalog/knowledge-catalogs/wi/wikipedia-sports/versions/2026.10.1/manifest.json +193 -0
  171. package/dist/catalog/knowledge-catalogs/wi/wikipedia-technology/keywords.json +6537 -0
  172. package/dist/catalog/knowledge-catalogs/wi/wikipedia-technology/manifest.json +1 -1
  173. package/dist/catalog/knowledge-catalogs/wi/wikipedia-technology/versions/2026.10.1/manifest.json +185 -0
  174. package/dist/catalog/knowledge-catalogs/wi/wikipedia-transportation/keywords.json +5989 -0
  175. package/dist/catalog/knowledge-catalogs/wi/wikipedia-transportation/manifest.json +1 -1
  176. package/dist/catalog/knowledge-catalogs/wi/wikipedia-transportation/versions/2026.10.1/manifest.json +189 -0
  177. package/dist/catalog/provenance.json +1 -1
  178. package/dist/engines/native-file-manifest.json +182 -112
  179. package/dist/engines/native-manifest.d.ts +4 -4
  180. package/dist/engines/native-manifest.js +36 -34
  181. package/dist/engines/resolver.js +3 -1
  182. package/dist/fs/atomic.d.ts +4 -1
  183. package/dist/fs/atomic.js +7 -1
  184. package/dist/http/openai-compat/chat-target.d.ts +1 -1
  185. package/dist/http/openai-compat/chat-target.js +1 -1
  186. package/dist/http/routes/v1-chat.js +1 -1
  187. package/dist/http/routes/v1-knowledge.js +4 -0
  188. package/dist/http/routes/v1-responses.d.ts +1 -1
  189. package/dist/inference-service.d.ts +6 -1
  190. package/dist/inference-service.js +20 -9
  191. package/dist/knowledge/manager.d.ts +7 -0
  192. package/dist/knowledge/manager.js +32 -1
  193. package/dist/perf/responsiveness.js +4 -3
  194. package/dist/providers/audio/kokoro-frontend.js +1 -1
  195. package/dist/providers/ds4/build-provider.js +6 -0
  196. package/dist/providers/llama-cpp/build-provider.js +107 -56
  197. package/dist/providers/llama-cpp/cache-adapter.d.ts +7 -1
  198. package/dist/providers/llama-cpp/cache-adapter.js +9 -0
  199. package/dist/providers/llama-cpp/devices.d.ts +13 -2
  200. package/dist/providers/llama-cpp/devices.js +43 -6
  201. package/dist/providers/llama-cpp/models.js +4 -1
  202. package/dist/providers/llama-cpp/offload-planner.d.ts +23 -0
  203. package/dist/providers/llama-cpp/offload-planner.js +27 -0
  204. package/dist/providers/llama-cpp/provider.d.ts +14 -3
  205. package/dist/providers/llama-cpp/provider.js +35 -2
  206. package/dist/providers/mlx/provider.js +2 -2
  207. package/dist/providers/mlx/reasoning-stream.d.ts +15 -0
  208. package/dist/providers/mlx/reasoning-stream.js +35 -0
  209. package/dist/providers/native/capacity-broker.js +9 -3
  210. package/dist/providers/native/local-engine-runtime.js +15 -12
  211. package/dist/providers/native/supervisor.js +3 -1
  212. package/dist/providers/queue.d.ts +9 -2
  213. package/dist/providers/queue.js +17 -2
  214. package/dist/providers/session-hooks.d.ts +4 -1
  215. package/package.json +5 -5
@@ -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.51";
43
+ export declare const NATIVE_ENGINE_RELEASE = "0.1.52";
44
44
  /** sha256 of the pinned release's `SHA256SUMS` asset. All-zeros = unpinned. */
45
- export declare const SHA256SUMS_DIGEST = "499a87aa18e113cdb52ee277bff71365e9176b63b536dbea7f3c2aa5ff5dbe68";
46
- /** Exact SHA256 values for every engine archive published by native-v0.1.51. */
45
+ export declare const SHA256SUMS_DIGEST = "1a2183ad785671be0f78a0f25816f7c802ce668ebe4fa58d640d336ebcbd7023";
46
+ /** Exact SHA256 values for every engine archive published by native-v0.1.52. */
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.51. */
48
+ /** Download size in bytes of every engine archive published by native-v0.1.52. */
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,45 +40,47 @@
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.51';
43
+ export const NATIVE_ENGINE_RELEASE = '0.1.52';
44
44
  /** sha256 of the pinned release's `SHA256SUMS` asset. All-zeros = unpinned. */
45
- export const SHA256SUMS_DIGEST = '499a87aa18e113cdb52ee277bff71365e9176b63b536dbea7f3c2aa5ff5dbe68';
45
+ export const SHA256SUMS_DIGEST = '1a2183ad785671be0f78a0f25816f7c802ce668ebe4fa58d640d336ebcbd7023';
46
46
  // BEGIN PINNED NATIVE ARCHIVE HASHES
47
- /** Exact SHA256 values for every engine archive published by native-v0.1.51. */
47
+ /** Exact SHA256 values for every engine archive published by native-v0.1.52. */
48
48
  export const NATIVE_ENGINE_ARCHIVE_SHA256 = Object.freeze({
49
- 'gezel-native-0.1.51-darwin-arm64-metal.tar.gz': '5abbfd156fbcc717da96c89dc5baa507a56d2b55b501f1a975803a763e6414c4',
50
- 'gezel-native-0.1.51-darwin-arm64.tar.gz': '799bca88b0ea10aeb2dad9ed3065c9396f42383a6fd5c7347ed76abf0706f128',
51
- 'gezel-native-0.1.51-linux-arm64-cpu.tar.gz': '1612e5928693262884bcc2c60ba3975af4dc4267c2bd75597ef91e83681fa96e',
52
- 'gezel-native-0.1.51-linux-arm64-cuda.tar.gz': '4a457df5dbb8475ca0eb2f1a2373f1960bbb3f86a0ecd938a407f884cd6026a2',
53
- 'gezel-native-0.1.51-linux-arm64.tar.gz': '2aaead65bfd42ffef9a1f45a70fa24095bc2814842750536989cbcb7a9a0db24',
54
- 'gezel-native-0.1.51-linux-x64-cpu.tar.gz': '7453d6a3ef2de7ece967a033d5bd634789e41edefa4a823b580329f0ad98abb0',
55
- 'gezel-native-0.1.51-linux-x64-cuda.tar.gz': 'ac1054a33339bcf6167c309b867f5671def58e036bb612978c4a434cd7ac39d6',
56
- 'gezel-native-0.1.51-linux-x64-vulkan.tar.gz': '6739c9dca6cbcf53fb5d69dbd342ac6be49fe2f0d86471d66975e61a64c95e9f',
57
- 'gezel-native-0.1.51-linux-x64.tar.gz': 'a176ac570131db874e0a81fdec939415dd161a639827219a82f2a610f5ebd8d3',
58
- 'gezel-native-0.1.51-win32-arm64-cpu.zip': 'f79c0c8490d46f2d60e73fd948bf74ae93dfc7c650a878f7db5e227bbdbb85b9',
59
- 'gezel-native-0.1.51-win32-arm64.zip': 'c829c9c1fd08756aff9e677ea1addcf80a8739f13df3c9b6788a6237e53efacb',
60
- 'gezel-native-0.1.51-win32-x64-cpu.zip': 'f8e0ffeacc8aeea1f2fc91024382bdcdaeeeb65b8a45935af422acb4d7027190',
61
- 'gezel-native-0.1.51-win32-x64-cuda.zip': '6bd7dc2c43443a847058a4c4f1c53281c99563c214394a92470281a70f725d1e',
62
- 'gezel-native-0.1.51-win32-x64-vulkan.zip': 'e20fb148c854f267aa50981525e337c38d3ee496fd483393a676251d9c0a496f',
63
- 'gezel-native-0.1.51-win32-x64.zip': 'ca5d7866fa2ff2e89da9267fcb409eb9aff01ef1c43ed726327e4967d3ed5e56',
49
+ 'gezel-native-0.1.52-darwin-arm64-metal.tar.gz': '8c8619530592692ad9fd905823a5bc7772a652d4257905919dac088c5fa86347',
50
+ 'gezel-native-0.1.52-darwin-arm64.tar.gz': '3088b7d97968ea206bf58a516da2a9c635d7622672da220d48d790fd5555a797',
51
+ 'gezel-native-0.1.52-linux-arm64-cpu.tar.gz': 'ec4b992eb372e735156691950eadb2aa8f7e5ef29437b53a9da6fe8cc2a7912b',
52
+ 'gezel-native-0.1.52-linux-arm64-cuda.tar.gz': '4f97fd70f0d132f0bfcaadfd113f63add7d8b63982edf8b1b7a46301702047f5',
53
+ 'gezel-native-0.1.52-linux-arm64.tar.gz': '3fa2c58ff75bea7ec0f739821250307bfba78cb026779ec3ad1ef935286af534',
54
+ 'gezel-native-0.1.52-linux-x64-cpu.tar.gz': '1fbfd06acfea1ef9e2629c121da2d7da13ee2e76a0cebb8cf07b779938817966',
55
+ 'gezel-native-0.1.52-linux-x64-cuda.tar.gz': '5c3c05f285c3922845b72e470ecfcd5e510b874a35ae841cd655a7098b541ffd',
56
+ 'gezel-native-0.1.52-linux-x64-vulkan.tar.gz': '33a6dd016bd2cf0aada7f34c364a457acc524373b52a1d3f1f6e83c1240e93a7',
57
+ 'gezel-native-0.1.52-linux-x64.tar.gz': 'f17afac30f984da17b6098bf5f9c5e88e9f9e128b8fbea0b5ff67a360a494313',
58
+ 'gezel-native-0.1.52-win32-arm64-cpu.zip': '49f011b05eec55cc3f60730fdd46e3d28de331f60b195eb29abaa04fe62835a3',
59
+ 'gezel-native-0.1.52-win32-arm64-cuda.zip': '7dbc99fd9516ea5a5cc49ad2c157bb66a240ecc2b5a5e22fae33142a6615caec',
60
+ 'gezel-native-0.1.52-win32-arm64.zip': 'dfe61d86eae932e03d92665aa42b81121e21cfa76a85424d993b5726ee5fa504',
61
+ 'gezel-native-0.1.52-win32-x64-cpu.zip': 'b1147052367daf694d6001ef0d45a8897a39a1d74cb776a42f22529d5c21f919',
62
+ 'gezel-native-0.1.52-win32-x64-cuda.zip': '3c9568591d19ba04ceb12ae2e9f9f2a4ac7ade4597458a8674d444c06407324f',
63
+ 'gezel-native-0.1.52-win32-x64-vulkan.zip': '9cb1e7721d1dbebfa830ec8cba1bbbbcb41f0145d60461e4bf50c4e347feecb2',
64
+ 'gezel-native-0.1.52-win32-x64.zip': '7c94605b0783695174773ac2327274d91bb9d7ae31e7d932a2b9df78d44424df',
64
65
  });
65
- /** Download size in bytes of every engine archive published by native-v0.1.51. */
66
+ /** Download size in bytes of every engine archive published by native-v0.1.52. */
66
67
  export const NATIVE_ENGINE_ARCHIVE_BYTES = Object.freeze({
67
- 'gezel-native-0.1.51-darwin-arm64-metal.tar.gz': 7056609,
68
- 'gezel-native-0.1.51-darwin-arm64.tar.gz': 41556782,
69
- 'gezel-native-0.1.51-linux-arm64-cpu.tar.gz': 8836261,
70
- 'gezel-native-0.1.51-linux-arm64-cuda.tar.gz': 619480627,
71
- 'gezel-native-0.1.51-linux-arm64.tar.gz': 41979458,
72
- 'gezel-native-0.1.51-linux-x64-cpu.tar.gz': 12914417,
73
- 'gezel-native-0.1.51-linux-x64-cuda.tar.gz': 989771250,
74
- 'gezel-native-0.1.51-linux-x64-vulkan.tar.gz': 25672179,
75
- 'gezel-native-0.1.51-linux-x64.tar.gz': 58057226,
76
- 'gezel-native-0.1.51-win32-arm64-cpu.zip': 5618599,
77
- 'gezel-native-0.1.51-win32-arm64.zip': 42055408,
78
- 'gezel-native-0.1.51-win32-x64-cpu.zip': 8714418,
79
- 'gezel-native-0.1.51-win32-x64-cuda.zip': 749850276,
80
- 'gezel-native-0.1.51-win32-x64-vulkan.zip': 21123169,
81
- 'gezel-native-0.1.51-win32-x64.zip': 56558016,
68
+ 'gezel-native-0.1.52-darwin-arm64-metal.tar.gz': 7056567,
69
+ 'gezel-native-0.1.52-darwin-arm64.tar.gz': 42206061,
70
+ 'gezel-native-0.1.52-linux-arm64-cpu.tar.gz': 8836310,
71
+ 'gezel-native-0.1.52-linux-arm64-cuda.tar.gz': 620408821,
72
+ 'gezel-native-0.1.52-linux-arm64.tar.gz': 42037958,
73
+ 'gezel-native-0.1.52-linux-x64-cpu.tar.gz': 12914985,
74
+ 'gezel-native-0.1.52-linux-x64-cuda.tar.gz': 993543364,
75
+ 'gezel-native-0.1.52-linux-x64-vulkan.tar.gz': 25672744,
76
+ 'gezel-native-0.1.52-linux-x64.tar.gz': 57183428,
77
+ 'gezel-native-0.1.52-win32-arm64-cpu.zip': 5618616,
78
+ 'gezel-native-0.1.52-win32-arm64-cuda.zip': 219555740,
79
+ 'gezel-native-0.1.52-win32-arm64.zip': 42114295,
80
+ 'gezel-native-0.1.52-win32-x64-cpu.zip': 8714442,
81
+ 'gezel-native-0.1.52-win32-x64-cuda.zip': 749856660,
82
+ 'gezel-native-0.1.52-win32-x64-vulkan.zip': 21123132,
83
+ 'gezel-native-0.1.52-win32-x64.zip': 55662940,
82
84
  });
83
85
  // END PINNED NATIVE ARCHIVE HASHES
84
86
  /**
@@ -763,7 +763,9 @@ async function resolveGitHubToken() {
763
763
  return process.env.GITHUB_TOKEN;
764
764
  try {
765
765
  const { execFileSync } = await import('node:child_process');
766
- const out = execFileSync('gh', ['auth', 'token'], {
766
+ // Named host: a bare `gh auth token` answers for gh's default host, which
767
+ // can be a GitHub Enterprise server whose token must not go to github.com.
768
+ const out = execFileSync('gh', ['auth', 'token', '--hostname', 'github.com'], {
767
769
  encoding: 'utf8',
768
770
  stdio: ['ignore', 'pipe', 'ignore'],
769
771
  ...windowsHeadlessSpawnOptions(),
@@ -50,4 +50,7 @@ export declare function writeFileAtomic(absPath: string, content: string | Uint8
50
50
  * private staging file by their adapter, then copied to a sibling temporary
51
51
  * path and renamed into place.
52
52
  */
53
- export declare function copyFileAtomic(sourcePath: string, absPath: string): Promise<void>;
53
+ export declare function copyFileAtomic(sourcePath: string, absPath: string, opts?: {
54
+ noReplace?: boolean;
55
+ signal?: AbortSignal;
56
+ }): Promise<void>;
package/dist/fs/atomic.js CHANGED
@@ -108,10 +108,16 @@ export async function writeFileAtomic(absPath, content, opts) {
108
108
  * private staging file by their adapter, then copied to a sibling temporary
109
109
  * path and renamed into place.
110
110
  */
111
- export async function copyFileAtomic(sourcePath, absPath) {
111
+ export async function copyFileAtomic(sourcePath, absPath, opts) {
112
112
  const tmp = `${absPath}.tmp-${process.pid}-${randomUUID()}`;
113
113
  try {
114
114
  await copyFile(sourcePath, tmp);
115
+ opts?.signal?.throwIfAborted();
116
+ if (opts?.noReplace) {
117
+ await link(tmp, absPath);
118
+ await rm(tmp, { force: true }).catch(() => undefined);
119
+ return;
120
+ }
115
121
  await renameWithWindowsRetry(tmp, absPath);
116
122
  }
117
123
  catch (err) {
@@ -59,7 +59,7 @@ export declare function resolvePinnedModelTarget(ctx: ServiceContext, model: str
59
59
  * Pick the gezel that guarantees a persona-backed fallback for public
60
60
  * inference requests.
61
61
  *
62
- * The explicit Connected Apps choice wins. When it is unset or stale,
62
+ * The explicit Integrations choice wins. When it is unset or stale,
63
63
  * the install's Meester is the natural front door; the first available
64
64
  * gezel is the final recovery path for older or partially migrated
65
65
  * homes. A healthy store always has at least a Meester, but returning
@@ -29,7 +29,7 @@ export async function resolvePinnedModelTarget(ctx, model) {
29
29
  * Pick the gezel that guarantees a persona-backed fallback for public
30
30
  * inference requests.
31
31
  *
32
- * The explicit Connected Apps choice wins. When it is unset or stale,
32
+ * The explicit Integrations choice wins. When it is unset or stale,
33
33
  * the install's Meester is the natural front door; the first available
34
34
  * gezel is the final recovery path for older or partially migrated
35
35
  * homes. A healthy store always has at least a Meester, but returning
@@ -289,7 +289,7 @@ export function v1ChatRoutes(ctx, opts = {}) {
289
289
  // instruct folds, per-gezel overrides for gezel: targets) applies
290
290
  // unconditionally — it's "what the model is" — with the caller's
291
291
  // per-request knobs overlaid on top. The behavior `profile` is the
292
- // supporting layer the Connected Apps switch gates. Caller-owned
292
+ // supporting layer the Integrations switch gates. Caller-owned
293
293
  // inference keeps parsing, grammar, and transcript compatibility but
294
294
  // omits interventions which assume Gezel owns the action loop.
295
295
  // Best-effort: a resolver failure serves engine defaults rather than
@@ -222,6 +222,10 @@ export function v1KnowledgeRoutes(ctx) {
222
222
  maxResults: 24,
223
223
  queryEmbedBudgetMs: 5000,
224
224
  catalogs: enabled.map((entry) => entry.ref.catalogId),
225
+ // Let the reranker choose among an article's sections: one passage per
226
+ // article, picked by embedding similarity, sent an infobox in place of
227
+ // the history the person asked about.
228
+ chunksPerDocument: 3,
225
229
  });
226
230
  c.req.raw.signal.throwIfAborted();
227
231
  const candidates = [];
@@ -9,7 +9,7 @@ import type { InferenceContext } from '../inference-context.js';
9
9
  * and returns assistant text/tool calls in Responses wire shapes. The route
10
10
  * intentionally does not create a Gezel chat session or attach Gezel MCP.
11
11
  *
12
- * In the full service, auth is mounted in `server.ts`: the Connected Apps
12
+ * In the full service, auth is mounted in `server.ts`: the Integrations
13
13
  * master switch, bearer authentication, and the `openai` scope all apply. Codex can therefore use
14
14
  * an app-scoped token without ever learning the daemon's root credential.
15
15
  */
@@ -1,4 +1,4 @@
1
- import { type ProviderName } from '@bendyline/gezel';
1
+ import { type LogOutput, type ProviderName } from '@bendyline/gezel';
2
2
  import type { LLMProvider } from './providers/types.js';
3
3
  import './http/auth-context.js';
4
4
  /** Same shape the full service reports, so one handler serves either host. */
@@ -15,6 +15,11 @@ export interface InferenceServiceOptions {
15
15
  /** Host-provided local providers, useful for testing without downloading weights. */
16
16
  providers?: ReadonlyMap<ProviderName, LLMProvider>;
17
17
  onUnexpectedHttpError?: (event: InferenceHttpErrorEvent) => void;
18
+ /**
19
+ * Where log records go while this host runs; restored on `stop()`. An app
20
+ * embedding the host passes `'stderr'` so its own stdout stays its own.
21
+ */
22
+ logOutput?: LogOutput;
18
23
  }
19
24
  export interface RunningInferenceService {
20
25
  readonly profile: 'embedded-inference';
@@ -1,6 +1,6 @@
1
1
  import { randomBytes, randomUUID, timingSafeEqual } from 'node:crypto';
2
2
  import { join } from 'node:path';
3
- import { GEZEL_API_GENERATION, GEZEL_API_GENERATION_FLOOR, GEZEL_VERSION, GezelConfigSchema, createLogger, nowIso, startSuspendMonitor, stopSuspendMonitor, } from '@bendyline/gezel';
3
+ import { GEZEL_API_GENERATION, GEZEL_API_GENERATION_FLOOR, GEZEL_VERSION, GezelConfigSchema, createLogger, getLogOutput, nowIso, setLogOutput, startSuspendMonitor, stopSuspendMonitor, } from '@bendyline/gezel';
4
4
  import { BundledSource, CatalogService } from '@bendyline/gezel-catalog';
5
5
  import { discoverNativeBinaries } from '@bendyline/gezel/native';
6
6
  import { gezelHome } from '@bendyline/gezel/paths';
@@ -35,16 +35,27 @@ import './http/auth-context.js';
35
35
  const log = createLogger('inference');
36
36
  /** Direct Fetch host: no listener, product store, background downloads or daemon discovery. */
37
37
  export async function startService(options = {}) {
38
+ const previousLogOutput = getLogOutput();
39
+ const restoreLogOutput = () => setLogOutput(previousLogOutput);
40
+ if (options.logOutput)
41
+ setLogOutput(options.logOutput);
38
42
  const home = options.home ?? gezelHome();
39
- await ensurePrivateUserHome(home);
40
- // Model files must land in this home's managed cache: unset, transformers.js
41
- // falls back to a module-relative cache that is read-only inside a packaged
42
- // app, and the embed worker (which reads this env) has no other view of home.
43
- process.env[HF_CACHE_DIR_ENV] ??= transformersCacheDir(home);
44
- const startedAt = nowIso();
45
43
  const runtimeDir = join(home, 'runtime');
46
- const lock = await acquireSingleInstanceLock({ runtimeDir, lockPath: join(runtimeDir, 'lock') });
47
- const cleanup = [() => lock.release()];
44
+ let lock;
45
+ try {
46
+ await ensurePrivateUserHome(home);
47
+ // Model files must land in this home's managed cache: unset, transformers.js
48
+ // falls back to a module-relative cache that is read-only inside a packaged
49
+ // app, and the embed worker (which reads this env) has no other view of home.
50
+ process.env[HF_CACHE_DIR_ENV] ??= transformersCacheDir(home);
51
+ lock = await acquireSingleInstanceLock({ runtimeDir, lockPath: join(runtimeDir, 'lock') });
52
+ }
53
+ catch (error) {
54
+ restoreLogOutput();
55
+ throw error;
56
+ }
57
+ const startedAt = nowIso();
58
+ const cleanup = [restoreLogOutput, () => lock.release()];
48
59
  const requests = new InFlightRequests();
49
60
  let stopping;
50
61
  let closed = false;
@@ -260,6 +260,13 @@ export declare class KnowledgeManager {
260
260
  * their own. Explicit search asks; proactive injection does not.
261
261
  */
262
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;
263
270
  }): Promise<UnifiedSearchResult[]>;
264
271
  /** A document the lexical arms named but no chunk carries: cite it with its lead paragraph. */
265
272
  private toDocumentResult;
@@ -1315,6 +1315,20 @@ export class KnowledgeManager {
1315
1315
  }
1316
1316
  fused.set(key, entry);
1317
1317
  };
1318
+ // Every text passage the arms found, per document, best vector match first,
1319
+ // for `chunksPerDocument`. Fusion still ranks documents, not passages.
1320
+ const passagesByDocument = new Map();
1321
+ if ((opts.chunksPerDocument ?? 1) > 1) {
1322
+ for (const hit of response.chunks
1323
+ .filter((h) => !h.media)
1324
+ .sort((a, b) => (b.cosine ?? -1) - (a.cosine ?? -1))) {
1325
+ const key = `${hit.catalogKey}\u0000${hit.documentId}`;
1326
+ const passages = passagesByDocument.get(key) ?? [];
1327
+ if (!passages.some((known) => known.chunkUid === hit.chunkUid))
1328
+ passages.push(hit);
1329
+ passagesByDocument.set(key, passages);
1330
+ }
1331
+ }
1318
1332
  // Vector arm: one rank per document, in rerank-cosine order. A hit under
1319
1333
  // its profile's floor is not evidence at all — KNN always returns its
1320
1334
  // nearest rows, and a rank-0 row fuses to relevance 1.0 however far away
@@ -1446,7 +1460,24 @@ export class KnowledgeManager {
1446
1460
  continue;
1447
1461
  perCatalogCount.set(entry.catalogKey, count + 1);
1448
1462
  seenSpatial.add(spatialIdentity);
1449
- out.push({ ...result, ...matches.get(`${entry.catalogKey}\u0000${entry.documentId}`) });
1463
+ const docKey = `${entry.catalogKey}\u0000${entry.documentId}`;
1464
+ out.push({ ...result, ...matches.get(docKey) });
1465
+ if (out.length >= Math.max(10, opts.maxResults))
1466
+ break;
1467
+ // The document's other passages, each labelled by its own evidence: a
1468
+ // sibling is vector evidence only if it clears the floor by itself.
1469
+ const siblings = (passagesByDocument.get(docKey) ?? [])
1470
+ .filter((hit) => hit.chunkUid !== entry.chunk?.chunkUid)
1471
+ .slice(0, Math.max(0, (opts.chunksPerDocument ?? 1) - 1));
1472
+ const floor = this.vectorFloorFor(entry.catalogKey);
1473
+ for (const sibling of siblings) {
1474
+ const own = floor !== null && sibling.cosine !== undefined && sibling.cosine >= floor
1475
+ ? { arm: 'vector', similarity: sibling.cosine }
1476
+ : { arm: 'fts' };
1477
+ out.push(this.toResult(info, sibling, fusedRankRelevance(out.length), own));
1478
+ if (out.length >= Math.max(10, opts.maxResults))
1479
+ break;
1480
+ }
1450
1481
  if (out.length >= Math.max(10, opts.maxResults))
1451
1482
  break;
1452
1483
  }
@@ -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. In embedded mode (`pnpm app`, and the
12
- * packaged fallback) that loop is Electron's main thread, so a synchronous
13
- * block here freezes the window itself, and Windows labels it "Not Responding"
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
@@ -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;
@@ -24,7 +24,7 @@ import { readGgufSummaryAsync } from './gguf-metadata-async.js';
24
24
  import { effectiveLazyTensorBytes } from './gguf-metadata.js';
25
25
  import { GpuStartupWatch } from './gpu-startup-watch.js';
26
26
  import { isGemmaModel, planLlamaCppKv, resolveLlamaCppKvCacheType, } from './kv-cache-type.js';
27
- import { degradeDenseFfnOffloadDecision, degradeMoeOffloadDecision, estimateExactPerSlotKvBytesF16, estimateKvReserveBytes, estimateWindowedKvLinearization, planDenseFfnOffload, planMoeOffload, } from './offload-planner.js';
27
+ import { degradeDenseFfnOffloadDecision, degradeMoeOffloadDecision, estimateExactPerSlotKvBytesF16, estimateKvReserveBytes, estimateWindowedKvLinearization, planDenseFfnOffload, planMoeOffload, shedSlotsForGpuResidency, } from './offload-planner.js';
28
28
  import { LlamaCppProvider } from './provider.js';
29
29
  import { reasoningLaunchOverridesFromEnv } from './reasoning-launch.js';
30
30
  import { resolveSpecDraft } from './spec-draft.js';
@@ -347,13 +347,6 @@ export async function buildLlamaCppProvider(opts) {
347
347
  // path still clamps to the native train context.
348
348
  const explicitCtx = envNumCtx ?? perModelCtxOverride ?? config.llamaCppNumCtx;
349
349
  const hostFloorTokens = minViableLocalContextTokens();
350
- // A per-model override below the host floor is deliberate user intent —
351
- // lower the admission floor to the override instead of silently raising
352
- // the request back to 64K. Env / machine-wide values keep their
353
- // historical floor semantics.
354
- const minViableTokens = perModelCtxOverride !== undefined && explicitCtx === perModelCtxOverride
355
- ? Math.min(hostFloorTokens, perModelCtxOverride)
356
- : hostFloorTokens;
357
350
  const contextRequirement = resolveLlamaCppContextRequirement({
358
351
  modelContextWindow: modelCatalogInfo?.contextWindow,
359
352
  ...(explicitCtx !== undefined ? { explicitContextWindow: explicitCtx } : {}),
@@ -362,7 +355,7 @@ export async function buildLlamaCppProvider(opts) {
362
355
  ? { manifestContextSize: manifestEngineConfig.contextSize }
363
356
  : {}),
364
357
  contextSizing: config.llamaCppContextSizing ?? 'adaptive',
365
- minViableContextTokens: minViableTokens,
358
+ minViableContextTokens: hostFloorTokens,
366
359
  });
367
360
  // `let`: RAM-aware admission below may lower this (but never below the
368
361
  // model-aware minimum) before anything launch-visible consumes it.
@@ -650,6 +643,10 @@ export async function buildLlamaCppProvider(opts) {
650
643
  // mode. Undefined when the GGUF is unreadable — the pool builder then
651
644
  // falls back to the legacy weights-multiplier reservation.
652
645
  let plannedReservationBytes;
646
+ // What prices that reservation, kept for the out-of-memory ladder: when it
647
+ // drops a slot, the relaunch is charged for the KV it actually allocates.
648
+ let reservationKvFor;
649
+ let reservationResidentBytes;
653
650
  // Graphics memory the MoE offload plan puts on the card. Device admission
654
651
  // charges this rather than the whole card; undefined keeps the old charge.
655
652
  let plannedGpuBytes;
@@ -979,9 +976,9 @@ export async function buildLlamaCppProvider(opts) {
979
976
  ssmConvKernel: summary.ssmConvKernel,
980
977
  kvCacheType,
981
978
  });
982
- const kvReserveBytes = windowedKvPlan
983
- ? Math.round(windowedKvPlan.fixedBytes * slots +
984
- windowedKvPlan.bytesPerToken * effectiveNumCtx * slots)
979
+ const kvReserveFor = (slotCount) => windowedKvPlan
980
+ ? Math.round(windowedKvPlan.fixedBytes * slotCount +
981
+ windowedKvPlan.bytesPerToken * effectiveNumCtx * slotCount)
985
982
  : estimateKvReserveBytes({
986
983
  blockCount: summary.blockCount,
987
984
  embeddingLength: summary.embeddingLength,
@@ -999,43 +996,47 @@ export async function buildLlamaCppProvider(opts) {
999
996
  ssmInnerSize: summary.ssmInnerSize,
1000
997
  ssmStateSize: summary.ssmStateSize,
1001
998
  ssmConvKernel: summary.ssmConvKernel,
1002
- ctxTokens: effectiveNumCtx * slots,
999
+ ctxTokens: effectiveNumCtx * slotCount,
1003
1000
  kvCacheType,
1004
1001
  });
1005
- // The broker-ledger reservation for this launch: resident weights
1006
- // plus the KV the engine will allocate at the granted window (M1 —
1007
- // the weights-only ledger under-reserved dense models whose KV
1008
- // rivals their weights: qwen3.5-4b at 64K carries more KV than
1009
- // parameters). Consumed by the pool builder via
1010
- // `plannedReservationBytes` so co-residency admission can see it.
1011
- if (kvReserveBytes !== undefined) {
1012
- plannedReservationBytes = residentBytes + kvReserveBytes;
1013
- }
1002
+ // Plan against the card as it is now. Sized to the whole card, a plan
1003
+ // counts memory other programs hold: MoE admission then charged the
1004
+ // model the whole card and refused it (2026-10-11), and a dense
1005
+ // 31B planned into 30.3 GiB of a 32 GB card that the desktop and its
1006
+ // apps were already holding ~5 GB of died with a Vulkan out-of-memory
1007
+ // (2026-10-19).
1008
+ const freeGpuBytes = vramBytes > 0 ? await measureAvailableGpuBytes().catch(() => undefined) : undefined;
1009
+ // A lane count the person chose is not the planner's to spend, and
1010
+ // eval runs under GEZEL_LLAMA_NUM_CTX accept the memory consequences.
1011
+ const mayShedSlots = configuredSlots === undefined && envNumCtx === undefined;
1012
+ const placeSlots = (gpuBytes, plan) => mayShedSlots
1013
+ ? shedSlotsForGpuResidency({ slots, vramBytes: gpuBytes, plan })
1014
+ : { slots, decision: plan(slots, gpuBytes), shed: false };
1015
+ let placement;
1014
1016
  if (isMoE) {
1015
- // Plan against the card as it is now. Sized to the whole card, the
1016
- // plan counted memory other programs held, and admission then had
1017
- // to charge the model the whole card and refuse it (2026-10-11).
1018
- const freeGpuBytes = vramBytes > 0 ? await measureAvailableGpuBytes().catch(() => undefined) : undefined;
1019
- const moePlan = planMoeOffload({
1020
- isMoE,
1021
- residentBytes,
1022
- vramBytes: freeGpuBytes !== undefined ? Math.min(vramBytes, freeGpuBytes) : vramBytes,
1023
- ...(split
1024
- ? {
1025
- split,
1026
- ...(summary.blockCount !== undefined ? { blockCount: summary.blockCount } : {}),
1027
- ...(kvReserveBytes !== undefined ? { kvReserveBytes } : {}),
1028
- }
1029
- : {}),
1017
+ placement = placeSlots(freeGpuBytes !== undefined ? Math.min(vramBytes, freeGpuBytes) : vramBytes, (slotCount, gpuBytes) => {
1018
+ const kvReserveBytes = kvReserveFor(slotCount);
1019
+ return planMoeOffload({
1020
+ isMoE,
1021
+ residentBytes,
1022
+ vramBytes: gpuBytes,
1023
+ ...(split
1024
+ ? {
1025
+ split,
1026
+ ...(summary.blockCount !== undefined ? { blockCount: summary.blockCount } : {}),
1027
+ ...(kvReserveBytes !== undefined ? { kvReserveBytes } : {}),
1028
+ }
1029
+ : {}),
1030
+ });
1030
1031
  });
1031
- offloadDecision = moePlan;
1032
+ offloadDecision = placement.decision;
1032
1033
  // An explicit offload setting shadows the planner's flags, so its
1033
1034
  // footprint would describe a launch that is not the one made.
1034
1035
  const plannerPlacesExperts = (config.llamaCppCpuMoe ?? resolvedManifestEngineConfig?.cpuMoe) === undefined &&
1035
1036
  (config.llamaCppNCpuMoe ?? resolvedManifestEngineConfig?.nCpuMoe) === undefined &&
1036
1037
  (config.llamaCppNGpuLayers ?? resolvedManifestEngineConfig?.nGpuLayers) === undefined;
1037
1038
  if (plannerPlacesExperts)
1038
- plannedGpuBytes = moePlan.gpuBytes;
1039
+ plannedGpuBytes = placement.decision.gpuBytes;
1039
1040
  }
1040
1041
  else {
1041
1042
  const explicitNCpuFfn = config.llamaCppNCpuFfn ?? resolvedManifestEngineConfig?.nCpuFfn;
@@ -1044,16 +1045,21 @@ export async function buildLlamaCppProvider(opts) {
1044
1045
  // A finite whole-layer GPU count is a different placement strategy;
1045
1046
  // don't layer an automatic tensor override on top of it. `-1` means
1046
1047
  // all and is compatible with the planner's own attention-on-GPU plan.
1047
- offloadDecision =
1048
- explicitNCpuFfn === undefined &&
1049
- (explicitNGpuLayers === undefined || explicitNGpuLayers === -1)
1050
- ? planDenseFfnOffload({
1048
+ if (explicitNCpuFfn === undefined &&
1049
+ (explicitNGpuLayers === undefined || explicitNGpuLayers === -1)) {
1050
+ placement = placeSlots(
1051
+ // Respect the usable accelerator pool, any explicit capacity
1052
+ // ceiling, co-resident reservations, and what other programs
1053
+ // hold on the card now. The raw probe still gates this to a real
1054
+ // discrete-GPU build rather than treating a CPU/unified fast pool
1055
+ // as VRAM.
1056
+ vramBytes > 0
1057
+ ? Math.max(0, Math.min(budgetBytes - committedOtherBytes, freeGpuBytes ?? Number.POSITIVE_INFINITY))
1058
+ : 0, (slotCount, gpuBytes) => {
1059
+ const kvReserveBytes = kvReserveFor(slotCount);
1060
+ return planDenseFfnOffload({
1051
1061
  isMoE,
1052
- // Respect the usable accelerator pool, any explicit capacity
1053
- // ceiling, and co-resident reservations. The raw probe still
1054
- // gates this to a real discrete-GPU build rather than treating
1055
- // a CPU/unified fast pool as VRAM.
1056
- vramBytes: vramBytes > 0 ? Math.max(0, budgetBytes - committedOtherBytes) : 0,
1062
+ vramBytes: gpuBytes,
1057
1063
  ...(denseFfnSplit ? { split: denseFfnSplit } : {}),
1058
1064
  ...(summary.blockCount !== undefined ? { blockCount: summary.blockCount } : {}),
1059
1065
  ...(kvReserveBytes !== undefined ? { kvReserveBytes } : {}),
@@ -1062,9 +1068,30 @@ export async function buildLlamaCppProvider(opts) {
1062
1068
  ? brokerSnap.pools.ramShareBytes
1063
1069
  : hostCapacity.ramShareBytes,
1064
1070
  freeSystemRamBytes: availableSystemRamBytes(),
1065
- })
1066
- : undefined;
1071
+ });
1072
+ });
1073
+ offloadDecision = placement.decision;
1074
+ }
1075
+ else {
1076
+ offloadDecision = undefined;
1077
+ }
1078
+ }
1079
+ if (placement?.shed) {
1080
+ log.info(`[llama-cpp] ${modelCatalogInfo?.id ?? 'model'}: reducing engine slots ${slots} -> 1 to keep the model on the GPU with room to spare (other programs' graphics memory moves)`);
1081
+ slots = 1;
1082
+ }
1083
+ // The broker-ledger reservation for this launch: resident weights
1084
+ // plus the KV the engine will allocate at the granted window (M1 —
1085
+ // the weights-only ledger under-reserved dense models whose KV
1086
+ // rivals their weights: qwen3.5-4b at 64K carries more KV than
1087
+ // parameters). Consumed by the pool builder via
1088
+ // `plannedReservationBytes` so co-residency admission can see it.
1089
+ const kvReserveBytes = kvReserveFor(slots);
1090
+ if (kvReserveBytes !== undefined) {
1091
+ plannedReservationBytes = residentBytes + kvReserveBytes;
1067
1092
  }
1093
+ reservationKvFor = kvReserveFor;
1094
+ reservationResidentBytes = residentBytes;
1068
1095
  if (offloadDecision?.reason) {
1069
1096
  log.info(`[llama-cpp] offload plan (${modelCatalogInfo?.id ?? 'model'}): ${offloadDecision.reason}`);
1070
1097
  }
@@ -1228,16 +1255,34 @@ export async function buildLlamaCppProvider(opts) {
1228
1255
  gpuWatch?.observe(line);
1229
1256
  providerHolder.current?.onStdoutLine(line);
1230
1257
  },
1231
- // GPU-OOM recovery ladder: when a start dies of VRAM exhaustion and the
1232
- // planner's offload decision was in play, degrade it one step
1233
- // (partial split → all expert/FFN weights to RAM → engine-owned fit) and let the
1234
- // supervisor retry — `resolveLaunch` below re-reads `offloadDecision`
1235
- // on every spawn. The degraded plan sticks for later restarts of this
1236
- // provider, so a recovered engine doesn't re-OOM on its next boot.
1258
+ // GPU-OOM recovery ladder: when a start dies of VRAM exhaustion, first
1259
+ // give back the extra slots' KV (every weight stays on the GPU), then, if
1260
+ // the planner's offload decision was in play, degrade it one step
1261
+ // (partial split → all expert/FFN weights to RAM → engine-owned fit) and
1262
+ // let the supervisor retry — `resolveLaunch` below re-reads `slots` and
1263
+ // `offloadDecision` on every spawn. The degraded plan sticks for later
1264
+ // restarts of this provider, so a recovered engine doesn't re-OOM on its
1265
+ // next boot.
1237
1266
  recoverStartup: ({ panicKind }) => {
1238
1267
  if (panicKind !== 'cuda-out-of-memory' && panicKind !== 'vulkan-out-of-memory') {
1239
1268
  return false;
1240
1269
  }
1270
+ // A full-residency plan has no offload rung below it, so before this a
1271
+ // two-slot launch that missed by one KV allocation failed outright
1272
+ // (2026-10-19, Gemma 4 31B on a 32 GB card). This rung spends one of
1273
+ // the supervisor's two retries; an offload rung still has the other.
1274
+ if (slots > 1 && configuredSlots === undefined) {
1275
+ const from = slots;
1276
+ if (providerHolder.current?.narrowEngineSlots(1)) {
1277
+ slots = 1;
1278
+ const kvReserveBytes = reservationKvFor?.(1);
1279
+ if (kvReserveBytes !== undefined && reservationResidentBytes !== undefined) {
1280
+ plannedReservationBytes = reservationResidentBytes + kvReserveBytes;
1281
+ }
1282
+ log.warn(`[llama-cpp] ${panicKind} while starting ${modelCatalogInfo?.id ?? 'model'} — retrying with one engine slot instead of ${from}`);
1283
+ return true;
1284
+ }
1285
+ }
1241
1286
  // Explicit config/manifest offload settings shadow the planner
1242
1287
  // per-field (see `buildLlamaCppEngineArgs`); when every field the
1243
1288
  // ladder would change is pinned, a retry replays the same argv.
@@ -1274,6 +1319,12 @@ export async function buildLlamaCppProvider(opts) {
1274
1319
  },
1275
1320
  resolveLaunch: async () => {
1276
1321
  gpuWatch = new GpuStartupWatch(binaryBackend);
1322
+ // Again at every launch, not only at build: llama.cpp from the 0.1.51
1323
+ // release refuses a --slot-save-path that does not exist ("not a
1324
+ // directory") and exits before ready, and an eval preflight lost its
1325
+ // build-time directory during a 50 s capacity wait (2026-10-18). The
1326
+ // person saw "no model is installed yet".
1327
+ await mkdirAsync(slotSavePath, { recursive: true }).catch(() => { });
1277
1328
  const port = cachedPort ?? (await pickFreePort());
1278
1329
  cachedPort = port;
1279
1330
  // Prepend the binary's own directory to PATH so the OS finds the