@bendyline/gezel-inference 0.0.0-stage → 1.0.0

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 (967) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +13 -2
  3. package/dist/cache/adapter.d.ts +115 -0
  4. package/dist/cache/adapter.js +23 -0
  5. package/dist/cache/budget.d.ts +15 -0
  6. package/dist/cache/budget.js +31 -0
  7. package/dist/cache/controller.d.ts +205 -0
  8. package/dist/cache/controller.js +377 -0
  9. package/dist/catalog/LICENSE +21 -0
  10. package/dist/catalog/chat-models/bt/btl4-35b-q4/manifest.json +146 -0
  11. package/dist/catalog/chat-models/bt/btl4-35b-q4/versions/1.0.0/manifest.json +15 -0
  12. package/dist/catalog/chat-models/bt/btl4-35b-q4/versions/1.0.1/manifest.json +15 -0
  13. package/dist/catalog/chat-models/bt/btl4-compact-iq2/manifest.json +146 -0
  14. package/dist/catalog/chat-models/bt/btl4-compact-iq2/versions/1.0.0/manifest.json +15 -0
  15. package/dist/catalog/chat-models/bt/btl4-compact-iq2/versions/1.0.1/manifest.json +15 -0
  16. package/dist/catalog/chat-models/bt/btl4-compact-iq2/versions/1.0.2/manifest.json +15 -0
  17. package/dist/catalog/chat-models/de/deepseek-r1-8b-q4/manifest.json +166 -0
  18. package/dist/catalog/chat-models/de/deepseek-r1-8b-q4/versions/1.1.0/manifest.json +62 -0
  19. package/dist/catalog/chat-models/de/deepseek-r1-8b-q4/versions/1.1.1/manifest.json +61 -0
  20. package/dist/catalog/chat-models/de/deepseek-v4-flash-284b-mxfp4/manifest.json +125 -0
  21. package/dist/catalog/chat-models/de/deepseek-v4-flash-284b-mxfp4/versions/1.0.0/manifest.json +27 -0
  22. package/dist/catalog/chat-models/de/deepseek-v4-flash-284b-q2/manifest.json +125 -0
  23. package/dist/catalog/chat-models/de/deepseek-v4-flash-284b-q2/versions/1.0.0/manifest.json +27 -0
  24. package/dist/catalog/chat-models/de/deepseek-v4-flash-284b-q2/versions/1.1.0/manifest.json +27 -0
  25. package/dist/catalog/chat-models/de/deepseek-v4-flash-284b-q2q4/manifest.json +126 -0
  26. package/dist/catalog/chat-models/de/deepseek-v4-flash-284b-q2q4/versions/1.0.0/manifest.json +27 -0
  27. package/dist/catalog/chat-models/de/deepseek-v4-flash-284b-q4/manifest.json +318 -0
  28. package/dist/catalog/chat-models/de/deepseek-v4-flash-284b-q4/versions/1.0.0/manifest.json +225 -0
  29. package/dist/catalog/chat-models/de/deepseek-v4-flash-284b-q4/versions/1.1.0/manifest.json +225 -0
  30. package/dist/catalog/chat-models/ge/gemma4-12b-q4/manifest.json +249 -0
  31. package/dist/catalog/chat-models/ge/gemma4-12b-q4/versions/1.0.0/manifest.json +70 -0
  32. package/dist/catalog/chat-models/ge/gemma4-12b-q4/versions/1.1.0/manifest.json +72 -0
  33. package/dist/catalog/chat-models/ge/gemma4-12b-q4/versions/1.1.2/manifest.json +78 -0
  34. package/dist/catalog/chat-models/ge/gemma4-12b-q4/versions/1.1.3/manifest.json +78 -0
  35. package/dist/catalog/chat-models/ge/gemma4-12b-q4/versions/1.2.0/manifest.json +98 -0
  36. package/dist/catalog/chat-models/ge/gemma4-12b-q8/manifest.json +228 -0
  37. package/dist/catalog/chat-models/ge/gemma4-12b-q8/versions/1.0.0/manifest.json +72 -0
  38. package/dist/catalog/chat-models/ge/gemma4-12b-q8/versions/1.0.2/manifest.json +78 -0
  39. package/dist/catalog/chat-models/ge/gemma4-12b-q8/versions/1.0.3/manifest.json +78 -0
  40. package/dist/catalog/chat-models/ge/gemma4-12b-q8/versions/1.1.0/manifest.json +78 -0
  41. package/dist/catalog/chat-models/ge/gemma4-26b-q4/manifest.json +220 -0
  42. package/dist/catalog/chat-models/ge/gemma4-26b-q4/versions/1.1.0/manifest.json +75 -0
  43. package/dist/catalog/chat-models/ge/gemma4-26b-q4/versions/1.2.0/manifest.json +75 -0
  44. package/dist/catalog/chat-models/ge/gemma4-26b-q4/versions/1.2.1/manifest.json +80 -0
  45. package/dist/catalog/chat-models/ge/gemma4-26b-q4/versions/1.2.2/manifest.json +80 -0
  46. package/dist/catalog/chat-models/ge/gemma4-26b-q4/versions/1.3.0/manifest.json +81 -0
  47. package/dist/catalog/chat-models/ge/gemma4-31b-q4/manifest.json +226 -0
  48. package/dist/catalog/chat-models/ge/gemma4-31b-q4/versions/1.1.0/manifest.json +80 -0
  49. package/dist/catalog/chat-models/ge/gemma4-31b-q4/versions/1.1.1/manifest.json +82 -0
  50. package/dist/catalog/chat-models/ge/gemma4-31b-q4/versions/1.2.0/manifest.json +82 -0
  51. package/dist/catalog/chat-models/ge/gemma4-31b-q4/versions/1.2.1/manifest.json +95 -0
  52. package/dist/catalog/chat-models/ge/gemma4-31b-q4/versions/1.2.2/manifest.json +95 -0
  53. package/dist/catalog/chat-models/ge/gemma4-31b-q4/versions/1.3.0/manifest.json +86 -0
  54. package/dist/catalog/chat-models/ge/gemma4-e2b-q4/manifest.json +213 -0
  55. package/dist/catalog/chat-models/ge/gemma4-e2b-q4/versions/1.1.0/manifest.json +67 -0
  56. package/dist/catalog/chat-models/ge/gemma4-e2b-q4/versions/1.1.2/manifest.json +75 -0
  57. package/dist/catalog/chat-models/ge/gemma4-e2b-q4/versions/1.2.0/manifest.json +71 -0
  58. package/dist/catalog/chat-models/ge/gemma4-e2b-q4/versions/1.2.1/manifest.json +71 -0
  59. package/dist/catalog/chat-models/ge/gemma4-e2b-q4/versions/1.3.0/manifest.json +71 -0
  60. package/dist/catalog/chat-models/ge/gemma4-e4b-q4/manifest.json +205 -0
  61. package/dist/catalog/chat-models/ge/gemma4-e4b-q4/versions/1.1.0/manifest.json +72 -0
  62. package/dist/catalog/chat-models/ge/gemma4-e4b-q4/versions/1.1.2/manifest.json +75 -0
  63. package/dist/catalog/chat-models/ge/gemma4-e4b-q4/versions/1.2.0/manifest.json +76 -0
  64. package/dist/catalog/chat-models/ge/gemma4-e4b-q4/versions/1.2.1/manifest.json +76 -0
  65. package/dist/catalog/chat-models/ge/gemma4-e4b-q4/versions/1.3.0/manifest.json +76 -0
  66. package/dist/catalog/chat-models/gl/glm-5.2-754b-q2/manifest.json +127 -0
  67. package/dist/catalog/chat-models/gl/glm-5.2-754b-q2/versions/1.0.0/manifest.json +20 -0
  68. package/dist/catalog/chat-models/gl/glm-5.3-flash-320b-q2/manifest.json +140 -0
  69. package/dist/catalog/chat-models/gl/glm-5.3-flash-320b-q2/versions/1.0.0/manifest.json +23 -0
  70. package/dist/catalog/chat-models/gl/glm-5.3-flash-320b-q2/versions/1.0.1/manifest.json +26 -0
  71. package/dist/catalog/chat-models/gp/gpt-oss-120b-q4/manifest.json +247 -0
  72. package/dist/catalog/chat-models/gp/gpt-oss-120b-q4/versions/1.0.0/manifest.json +137 -0
  73. package/dist/catalog/chat-models/gp/gpt-oss-120b-q4/versions/1.1.0/manifest.json +135 -0
  74. package/dist/catalog/chat-models/gp/gpt-oss-20b-q4/manifest.json +195 -0
  75. package/dist/catalog/chat-models/gp/gpt-oss-20b-q4/versions/1.1.0/manifest.json +72 -0
  76. package/dist/catalog/chat-models/gp/gpt-oss-20b-q4/versions/1.1.1/manifest.json +71 -0
  77. package/dist/catalog/chat-models/gr/granite4.2-30b-q4/manifest.json +200 -0
  78. package/dist/catalog/chat-models/gr/granite4.2-30b-q4/versions/1.0.0/manifest.json +72 -0
  79. package/dist/catalog/chat-models/gr/granite4.2-3b-q4/manifest.json +196 -0
  80. package/dist/catalog/chat-models/gr/granite4.2-3b-q4/versions/1.0.0/manifest.json +57 -0
  81. package/dist/catalog/chat-models/gr/granite4.2-8b-q4/manifest.json +189 -0
  82. package/dist/catalog/chat-models/gr/granite4.2-8b-q4/versions/1.0.0/manifest.json +57 -0
  83. package/dist/catalog/chat-models/index.json +1 -0
  84. package/dist/catalog/chat-models/la/laguna-s-2.1-118b-q4/manifest.json +235 -0
  85. package/dist/catalog/chat-models/la/laguna-s-2.1-118b-q4/versions/1.0.0/manifest.json +124 -0
  86. package/dist/catalog/chat-models/la/laguna-s-2.1-118b-q4/versions/1.0.1/manifest.json +124 -0
  87. package/dist/catalog/chat-models/la/laguna-s-2.1-118b-q4/versions/1.0.2/manifest.json +123 -0
  88. package/dist/catalog/chat-models/la/laguna-s-2.1-118b-q6/manifest.json +257 -0
  89. package/dist/catalog/chat-models/la/laguna-s-2.1-118b-q6/versions/1.0.0/manifest.json +145 -0
  90. package/dist/catalog/chat-models/la/laguna-s-2.1-118b-q6/versions/1.0.1/manifest.json +145 -0
  91. package/dist/catalog/chat-models/la/laguna-s-2.1-118b-q8/manifest.json +285 -0
  92. package/dist/catalog/chat-models/la/laguna-s-2.1-118b-q8/versions/1.0.0/manifest.json +174 -0
  93. package/dist/catalog/chat-models/la/laguna-s-2.1-118b-q8/versions/1.0.1/manifest.json +174 -0
  94. package/dist/catalog/chat-models/la/laguna-s-2.1-118b-q8/versions/1.0.2/manifest.json +173 -0
  95. package/dist/catalog/chat-models/lf/lfm2.5-2.6b-q4/manifest.json +162 -0
  96. package/dist/catalog/chat-models/lf/lfm2.5-2.6b-q4/versions/1.0.0/manifest.json +59 -0
  97. package/dist/catalog/chat-models/lf/lfm2.5-2.6b-q4/versions/1.0.1/manifest.json +58 -0
  98. package/dist/catalog/chat-models/ll/llama3.2-3b-q4/manifest.json +134 -0
  99. package/dist/catalog/chat-models/ll/llama3.2-3b-q4/versions/1.1.0/manifest.json +57 -0
  100. package/dist/catalog/chat-models/ll/llama3.2-3b-q4/versions/1.1.1/manifest.json +56 -0
  101. package/dist/catalog/chat-models/mi/minicpm5-1b-q4/manifest.json +156 -0
  102. package/dist/catalog/chat-models/mi/minicpm5-1b-q4/versions/1.0.0/manifest.json +57 -0
  103. package/dist/catalog/chat-models/mi/minicpm5-2b-q4/manifest.json +161 -0
  104. package/dist/catalog/chat-models/mi/minicpm5-2b-q4/versions/1.0.0/manifest.json +57 -0
  105. package/dist/catalog/chat-models/mi/mistral-7b-q4/manifest.json +159 -0
  106. package/dist/catalog/chat-models/mi/mistral-7b-q4/versions/1.1.0/manifest.json +62 -0
  107. package/dist/catalog/chat-models/mi/mistral-7b-q4/versions/1.1.1/manifest.json +61 -0
  108. package/dist/catalog/chat-models/mi/mistral-medium-3.5-128b-q4/manifest.json +275 -0
  109. package/dist/catalog/chat-models/mi/mistral-medium-3.5-128b-q4/versions/1.0.0/manifest.json +154 -0
  110. package/dist/catalog/chat-models/mi/mistral-medium-3.5-128b-q4/versions/1.0.1/manifest.json +153 -0
  111. package/dist/catalog/chat-models/mu/muse-glimmer-30b-q4/manifest.json +135 -0
  112. package/dist/catalog/chat-models/mu/muse-glimmer-30b-q4/versions/1.0.0/manifest.json +20 -0
  113. package/dist/catalog/chat-models/mu/muse-glimmer-30b-q4/versions/1.0.1/manifest.json +20 -0
  114. package/dist/catalog/chat-models/mu/muse-glimmer-30b-q4/versions/1.0.2/manifest.json +20 -0
  115. package/dist/catalog/chat-models/na/nanbeige4.2-3b-q4/manifest.json +138 -0
  116. package/dist/catalog/chat-models/na/nanbeige4.2-3b-q4/versions/1.0.0/manifest.json +14 -0
  117. package/dist/catalog/chat-models/ne/nemotron3-nano-30b-q4/manifest.json +212 -0
  118. package/dist/catalog/chat-models/ne/nemotron3-nano-30b-q4/versions/1.0.0/manifest.json +94 -0
  119. package/dist/catalog/chat-models/ne/nemotron3-nano-30b-q4/versions/1.0.1/manifest.json +94 -0
  120. package/dist/catalog/chat-models/ne/nemotron3-nano-30b-q4/versions/1.0.2/manifest.json +93 -0
  121. package/dist/catalog/chat-models/ne/nemotron3-super-120b-q4/manifest.json +135 -0
  122. package/dist/catalog/chat-models/ne/nemotron3-super-120b-q4/versions/1.0.0/manifest.json +30 -0
  123. package/dist/catalog/chat-models/ne/nemotron3-super-120b-q4/versions/1.0.1/manifest.json +30 -0
  124. package/dist/catalog/chat-models/ne/nemotron3.5-lightning-30b-q4/manifest.json +192 -0
  125. package/dist/catalog/chat-models/ne/nemotron3.5-lightning-30b-q4/versions/1.0.0/manifest.json +74 -0
  126. package/dist/catalog/chat-models/ne/nemotron3.5-lightning-30b-q4/versions/1.0.1/manifest.json +73 -0
  127. package/dist/catalog/chat-models/ne/nemotron3.5-lightning-30b-q8/manifest.json +207 -0
  128. package/dist/catalog/chat-models/ne/nemotron3.5-lightning-30b-q8/versions/1.0.0/manifest.json +89 -0
  129. package/dist/catalog/chat-models/ne/nemotron3.5-lightning-30b-q8/versions/1.0.1/manifest.json +88 -0
  130. package/dist/catalog/chat-models/or/ornith-35b-q4/manifest.json +224 -0
  131. package/dist/catalog/chat-models/or/ornith-35b-q4/versions/1.0.0/manifest.json +94 -0
  132. package/dist/catalog/chat-models/or/ornith-35b-q4/versions/1.0.1/manifest.json +93 -0
  133. package/dist/catalog/chat-models/or/ornith-35b-q8/manifest.json +244 -0
  134. package/dist/catalog/chat-models/or/ornith-35b-q8/versions/1.0.0/manifest.json +114 -0
  135. package/dist/catalog/chat-models/or/ornith-35b-q8/versions/1.0.1/manifest.json +113 -0
  136. package/dist/catalog/chat-models/or/ornith-9b-q4/manifest.json +215 -0
  137. package/dist/catalog/chat-models/or/ornith-9b-q4/versions/1.0.0/manifest.json +84 -0
  138. package/dist/catalog/chat-models/or/ornith-9b-q4/versions/1.0.1/manifest.json +83 -0
  139. package/dist/catalog/chat-models/or/ornith1.5-35b-a3b-q4/manifest.json +208 -0
  140. package/dist/catalog/chat-models/or/ornith1.5-35b-a3b-q4/versions/1.0.0/manifest.json +74 -0
  141. package/dist/catalog/chat-models/or/ornith1.5-35b-a3b-q8/manifest.json +223 -0
  142. package/dist/catalog/chat-models/or/ornith1.5-35b-a3b-q8/versions/1.0.0/manifest.json +89 -0
  143. package/dist/catalog/chat-models/or/ornith1.5-9b-q4/manifest.json +187 -0
  144. package/dist/catalog/chat-models/or/ornith1.5-9b-q4/versions/1.0.0/manifest.json +53 -0
  145. package/dist/catalog/chat-models/or/ornith1.5-9b-q4/versions/1.0.1/manifest.json +77 -0
  146. package/dist/catalog/chat-models/or/ornith1.5-9b-q8/manifest.json +192 -0
  147. package/dist/catalog/chat-models/or/ornith1.5-9b-q8/versions/1.0.0/manifest.json +58 -0
  148. package/dist/catalog/chat-models/or/ornith1.5-9b-q8/versions/1.0.1/manifest.json +82 -0
  149. package/dist/catalog/chat-models/qw/qwen3.5-0.8b-q4/manifest.json +192 -0
  150. package/dist/catalog/chat-models/qw/qwen3.5-0.8b-q4/versions/1.0.0/manifest.json +75 -0
  151. package/dist/catalog/chat-models/qw/qwen3.5-122b-a10b-q4/manifest.json +315 -0
  152. package/dist/catalog/chat-models/qw/qwen3.5-122b-a10b-q4/versions/1.0.0/manifest.json +164 -0
  153. package/dist/catalog/chat-models/qw/qwen3.5-122b-a10b-q4/versions/1.0.1/manifest.json +164 -0
  154. package/dist/catalog/chat-models/qw/qwen3.5-122b-a10b-q4/versions/1.0.2/manifest.json +164 -0
  155. package/dist/catalog/chat-models/qw/qwen3.5-122b-a10b-q4/versions/1.0.3/manifest.json +163 -0
  156. package/dist/catalog/chat-models/qw/qwen3.5-27b-q4/manifest.json +217 -0
  157. package/dist/catalog/chat-models/qw/qwen3.5-27b-q4/versions/1.0.0/manifest.json +90 -0
  158. package/dist/catalog/chat-models/qw/qwen3.5-2b-q4/manifest.json +194 -0
  159. package/dist/catalog/chat-models/qw/qwen3.5-2b-q4/versions/1.1.0/manifest.json +77 -0
  160. package/dist/catalog/chat-models/qw/qwen3.5-2b-q4/versions/1.1.2/manifest.json +76 -0
  161. package/dist/catalog/chat-models/qw/qwen3.5-2b-q4/versions/1.1.3/manifest.json +76 -0
  162. package/dist/catalog/chat-models/qw/qwen3.5-4b-q4/manifest.json +188 -0
  163. package/dist/catalog/chat-models/qw/qwen3.5-4b-q4/versions/1.1.0/manifest.json +77 -0
  164. package/dist/catalog/chat-models/qw/qwen3.5-4b-q4/versions/1.1.2/manifest.json +76 -0
  165. package/dist/catalog/chat-models/qw/qwen3.5-4b-q4/versions/1.1.3/manifest.json +76 -0
  166. package/dist/catalog/chat-models/qw/qwen3.5-9b-q4/manifest.json +205 -0
  167. package/dist/catalog/chat-models/qw/qwen3.5-9b-q4/versions/1.1.0/manifest.json +82 -0
  168. package/dist/catalog/chat-models/qw/qwen3.5-9b-q4/versions/1.1.2/manifest.json +81 -0
  169. package/dist/catalog/chat-models/qw/qwen3.5-9b-q4/versions/1.1.3/manifest.json +81 -0
  170. package/dist/catalog/chat-models/qw/qwen3.6-27b-q4/manifest.json +230 -0
  171. package/dist/catalog/chat-models/qw/qwen3.6-27b-q4/versions/1.1.0/manifest.json +92 -0
  172. package/dist/catalog/chat-models/qw/qwen3.6-27b-q4/versions/1.1.4/manifest.json +91 -0
  173. package/dist/catalog/chat-models/qw/qwen3.6-27b-q4/versions/1.1.5/manifest.json +91 -0
  174. package/dist/catalog/chat-models/qw/qwen3.6-27b-q4/versions/1.1.6/manifest.json +115 -0
  175. package/dist/catalog/chat-models/qw/qwen3.6-27b-q8/manifest.json +240 -0
  176. package/dist/catalog/chat-models/qw/qwen3.6-27b-q8/versions/1.0.0/manifest.json +102 -0
  177. package/dist/catalog/chat-models/qw/qwen3.6-27b-q8/versions/1.0.2/manifest.json +103 -0
  178. package/dist/catalog/chat-models/qw/qwen3.6-27b-q8/versions/1.0.3/manifest.json +103 -0
  179. package/dist/catalog/chat-models/qw/qwen3.6-27b-q8/versions/1.0.4/manifest.json +127 -0
  180. package/dist/catalog/chat-models/qw/qwen3.6-35b-a3b-q4/manifest.json +233 -0
  181. package/dist/catalog/chat-models/qw/qwen3.6-35b-a3b-q4/versions/1.0.0/manifest.json +92 -0
  182. package/dist/catalog/chat-models/qw/qwen3.6-35b-a3b-q4/versions/1.0.1/manifest.json +93 -0
  183. package/dist/catalog/chat-models/qw/qwen3.6-35b-a3b-q4/versions/1.0.2/manifest.json +93 -0
  184. package/dist/catalog/chat-models/qw/qwen3.6-35b-a3b-q4/versions/1.0.3/manifest.json +117 -0
  185. package/dist/catalog/chat-models/qw/qwen3.6-35b-a3b-q8/manifest.json +252 -0
  186. package/dist/catalog/chat-models/qw/qwen3.6-35b-a3b-q8/versions/1.0.0/manifest.json +112 -0
  187. package/dist/catalog/chat-models/qw/qwen3.6-35b-a3b-q8/versions/1.0.1/manifest.json +113 -0
  188. package/dist/catalog/chat-models/qw/qwen3.6-35b-a3b-q8/versions/1.0.2/manifest.json +113 -0
  189. package/dist/catalog/chat-models/qw/qwen3.6-35b-a3b-q8/versions/1.0.3/manifest.json +137 -0
  190. package/dist/catalog/chat-models/qw/qwen3.8-27b-iq1-s/manifest.json +195 -0
  191. package/dist/catalog/chat-models/qw/qwen3.8-27b-iq1-s/versions/1.0.0/manifest.json +19 -0
  192. package/dist/catalog/chat-models/qw/qwen3.8-27b-q2/manifest.json +194 -0
  193. package/dist/catalog/chat-models/qw/qwen3.8-27b-q2/versions/1.0.0/manifest.json +19 -0
  194. package/dist/catalog/chat-models/qw/qwen3.8-27b-q3/manifest.json +194 -0
  195. package/dist/catalog/chat-models/qw/qwen3.8-27b-q3/versions/1.0.0/manifest.json +19 -0
  196. package/dist/catalog/chat-models/qw/qwen3.8-27b-q3/versions/1.0.1/manifest.json +19 -0
  197. package/dist/catalog/chat-models/qw/qwen3.8-27b-q4/manifest.json +291 -0
  198. package/dist/catalog/chat-models/qw/qwen3.8-27b-q4/versions/1.0.0/manifest.json +20 -0
  199. package/dist/catalog/chat-models/qw/qwen3.8-27b-q4/versions/1.0.1/manifest.json +93 -0
  200. package/dist/catalog/chat-models/qw/qwen3.8-27b-q4/versions/1.0.2/manifest.json +92 -0
  201. package/dist/catalog/chat-models/qw/qwen3.8-27b-q4/versions/1.0.3/manifest.json +116 -0
  202. package/dist/catalog/chat-models/qw/qwen3.8-27b-q4/versions/1.0.4/manifest.json +116 -0
  203. package/dist/catalog/chat-models/qw/qwen3.8-27b-q4/versions/1.0.5/manifest.json +116 -0
  204. package/dist/catalog/chat-models/qw/qwen3.8-27b-q6/manifest.json +278 -0
  205. package/dist/catalog/chat-models/qw/qwen3.8-27b-q6/versions/1.0.0/manifest.json +20 -0
  206. package/dist/catalog/chat-models/qw/qwen3.8-27b-q6/versions/1.0.1/manifest.json +104 -0
  207. package/dist/catalog/chat-models/qw/qwen3.8-27b-q6/versions/1.0.2/manifest.json +103 -0
  208. package/dist/catalog/chat-models/qw/qwen3.8-27b-q6/versions/1.0.3/manifest.json +127 -0
  209. package/dist/catalog/chat-models/qw/qwen3.8-27b-q8/manifest.json +278 -0
  210. package/dist/catalog/chat-models/qw/qwen3.8-27b-q8/versions/1.0.0/manifest.json +113 -0
  211. package/dist/catalog/chat-models/qw/qwen3.8-27b-q8/versions/1.0.1/manifest.json +113 -0
  212. package/dist/catalog/chat-models/qw/qwen3.8-27b-q8/versions/1.0.2/manifest.json +137 -0
  213. package/dist/catalog/chat-models/qw/qwen3.8-flash-next-iq3/manifest.json +221 -0
  214. package/dist/catalog/chat-models/qw/qwen3.8-flash-next-iq3/versions/1.0.0/manifest.json +36 -0
  215. package/dist/catalog/chat-models/qw/qwen3.8-flash-next-iq4/manifest.json +429 -0
  216. package/dist/catalog/chat-models/qw/qwen3.8-flash-next-iq4/versions/1.0.0/manifest.json +36 -0
  217. package/dist/catalog/chat-models/qw/qwen3.8-flash-next-iq4/versions/1.1.0/manifest.json +205 -0
  218. package/dist/catalog/chat-models/qw/qwen3.8-flash-next-iq4/versions/1.1.1/manifest.json +244 -0
  219. package/dist/catalog/chat-models/qw/qwen3.8-flash-next-q2/manifest.json +203 -0
  220. package/dist/catalog/chat-models/qw/qwen3.8-flash-next-q2/versions/1.0.0/manifest.json +21 -0
  221. package/dist/catalog/chat-models/qw/qwen3.8-flash-next-q2/versions/1.0.1/manifest.json +31 -0
  222. package/dist/catalog/chat-models/qw/qwen3.8-flash-next-q2/versions/1.0.2/manifest.json +30 -0
  223. package/dist/catalog/chat-models/raw-index.json +1 -0
  224. package/dist/catalog/chat-models/ta/talkie-1930-13b-q4/manifest.json +79 -0
  225. package/dist/catalog/chat-models/ta/talkie-1930-13b-q4/versions/1.0.0/manifest.json +15 -0
  226. package/dist/catalog/chat-models/ta/talkie-1930-13b-q4/versions/1.0.1/manifest.json +15 -0
  227. package/dist/catalog/chat-models/te/ternary-bonsai-27b-q2/manifest.json +204 -0
  228. package/dist/catalog/chat-models/te/ternary-bonsai-27b-q2/versions/1.0.0/manifest.json +70 -0
  229. package/dist/catalog/chat-models/te/ternary-bonsai-27b-q2/versions/1.0.1/manifest.json +70 -0
  230. package/dist/catalog/chat-models/un/underdog-saluki-27b-iq2-mix/manifest.json +164 -0
  231. package/dist/catalog/chat-models/un/underdog-saluki-27b-iq2-mix/versions/1.0.0/manifest.json +14 -0
  232. package/dist/catalog/knowledge-catalogs/be/bendyline-how-to-books/manifest.json +26 -0
  233. package/dist/catalog/knowledge-catalogs/be/bendyline-how-to-books/versions/2026.10.8/manifest.json +8950 -0
  234. package/dist/catalog/knowledge-catalogs/ca/caselaw-alaska-part-0001/manifest.json +24 -0
  235. package/dist/catalog/knowledge-catalogs/ca/caselaw-alaska-part-0001/versions/2026.10.1/manifest.json +658 -0
  236. package/dist/catalog/knowledge-catalogs/ca/caselaw-nevada-part-0001/manifest.json +24 -0
  237. package/dist/catalog/knowledge-catalogs/ca/caselaw-nevada-part-0001/versions/2026.10.1/manifest.json +666 -0
  238. package/dist/catalog/knowledge-catalogs/ca/caselaw-us-300-399-part-0001/manifest.json +24 -0
  239. package/dist/catalog/knowledge-catalogs/ca/caselaw-us-300-399-part-0001/versions/2026.10.2/manifest.json +182 -0
  240. package/dist/catalog/knowledge-catalogs/ca/caselaw-us-347-349/manifest.json +25 -0
  241. package/dist/catalog/knowledge-catalogs/ca/caselaw-us-347-349/versions/2026.10.5/manifest.json +38 -0
  242. package/dist/catalog/knowledge-catalogs/ca/caselaw-utah-part-0001/manifest.json +24 -0
  243. package/dist/catalog/knowledge-catalogs/ca/caselaw-utah-part-0001/versions/2026.10.1/manifest.json +558 -0
  244. package/dist/catalog/knowledge-catalogs/ca/caselaw-utah-part-0002/manifest.json +24 -0
  245. package/dist/catalog/knowledge-catalogs/ca/caselaw-utah-part-0002/versions/2026.10.1/manifest.json +258 -0
  246. package/dist/catalog/knowledge-catalogs/ca/caselaw-washington-part-0001/manifest.json +24 -0
  247. package/dist/catalog/knowledge-catalogs/ca/caselaw-washington-part-0001/versions/2026.10.1/manifest.json +318 -0
  248. package/dist/catalog/knowledge-catalogs/ca/caselaw-washington-part-0002/manifest.json +24 -0
  249. package/dist/catalog/knowledge-catalogs/ca/caselaw-washington-part-0002/versions/2026.10.1/manifest.json +266 -0
  250. package/dist/catalog/knowledge-catalogs/ca/caselaw-washington-part-0003/manifest.json +24 -0
  251. package/dist/catalog/knowledge-catalogs/ca/caselaw-washington-part-0003/versions/2026.10.1/manifest.json +186 -0
  252. package/dist/catalog/knowledge-catalogs/ca/caselaw-washington-part-0004/manifest.json +24 -0
  253. package/dist/catalog/knowledge-catalogs/ca/caselaw-washington-part-0004/versions/2026.10.1/manifest.json +138 -0
  254. package/dist/catalog/knowledge-catalogs/ca/caselaw-washington-part-0005/manifest.json +24 -0
  255. package/dist/catalog/knowledge-catalogs/ca/caselaw-washington-part-0005/versions/2026.10.1/manifest.json +138 -0
  256. package/dist/catalog/knowledge-catalogs/ca/caselaw-wyoming-part-0001/manifest.json +24 -0
  257. package/dist/catalog/knowledge-catalogs/ca/caselaw-wyoming-part-0001/versions/2026.10.3/manifest.json +626 -0
  258. package/dist/catalog/knowledge-catalogs/index.json +1 -0
  259. package/dist/catalog/knowledge-catalogs/mi/microsoftdocs-aspnet-core-en/manifest.json +22 -0
  260. package/dist/catalog/knowledge-catalogs/mi/microsoftdocs-aspnet-core-en/versions/2026.10.16/manifest.json +18270 -0
  261. package/dist/catalog/knowledge-catalogs/mi/microsoftdocs-azure-ai-platform-en/manifest.json +23 -0
  262. package/dist/catalog/knowledge-catalogs/mi/microsoftdocs-azure-ai-platform-en/versions/2026.10.16/manifest.json +1098 -0
  263. package/dist/catalog/knowledge-catalogs/mi/microsoftdocs-azure-apps-compute-en/manifest.json +23 -0
  264. package/dist/catalog/knowledge-catalogs/mi/microsoftdocs-azure-apps-compute-en/versions/2026.10.16/manifest.json +722 -0
  265. package/dist/catalog/knowledge-catalogs/mi/microsoftdocs-azure-data-aiot-en/manifest.json +23 -0
  266. package/dist/catalog/knowledge-catalogs/mi/microsoftdocs-azure-data-aiot-en/versions/2026.10.16/manifest.json +530 -0
  267. package/dist/catalog/knowledge-catalogs/mi/microsoftdocs-azure-management-hybrid-en/manifest.json +23 -0
  268. package/dist/catalog/knowledge-catalogs/mi/microsoftdocs-azure-management-hybrid-en/versions/2026.10.16/manifest.json +602 -0
  269. package/dist/catalog/knowledge-catalogs/mi/microsoftdocs-azure-network-security-en/manifest.json +23 -0
  270. package/dist/catalog/knowledge-catalogs/mi/microsoftdocs-azure-network-security-en/versions/2026.10.16/manifest.json +250 -0
  271. package/dist/catalog/knowledge-catalogs/mi/microsoftdocs-dotnet-en/manifest.json +22 -0
  272. package/dist/catalog/knowledge-catalogs/mi/microsoftdocs-dotnet-en/versions/2026.10.16/manifest.json +16794 -0
  273. package/dist/catalog/knowledge-catalogs/mi/microsoftdocs-entity-framework-en/manifest.json +22 -0
  274. package/dist/catalog/knowledge-catalogs/mi/microsoftdocs-entity-framework-en/versions/2026.10.16/manifest.json +1106 -0
  275. package/dist/catalog/knowledge-catalogs/mi/microsoftdocs-microsoft-365-en/manifest.json +22 -0
  276. package/dist/catalog/knowledge-catalogs/mi/microsoftdocs-microsoft-365-en/versions/2026.10.16/manifest.json +234 -0
  277. package/dist/catalog/knowledge-catalogs/mi/microsoftdocs-powershell-en/manifest.json +22 -0
  278. package/dist/catalog/knowledge-catalogs/mi/microsoftdocs-powershell-en/versions/2026.10.16/manifest.json +522 -0
  279. package/dist/catalog/knowledge-catalogs/mi/microsoftdocs-sql-server-en/manifest.json +22 -0
  280. package/dist/catalog/knowledge-catalogs/mi/microsoftdocs-sql-server-en/versions/2026.10.16/manifest.json +1850 -0
  281. package/dist/catalog/knowledge-catalogs/mi/microsoftdocs-windows-apps-en/manifest.json +22 -0
  282. package/dist/catalog/knowledge-catalogs/mi/microsoftdocs-windows-apps-en/versions/2026.10.16/manifest.json +1734 -0
  283. package/dist/catalog/knowledge-catalogs/mi/microsoftdocs-windows-server-en/manifest.json +22 -0
  284. package/dist/catalog/knowledge-catalogs/mi/microsoftdocs-windows-server-en/versions/2026.10.16/manifest.json +774 -0
  285. package/dist/catalog/knowledge-catalogs/raw-index.json +1 -0
  286. package/dist/catalog/knowledge-catalogs/re/regional-american-south/art.json +12 -0
  287. package/dist/catalog/knowledge-catalogs/re/regional-american-south/logo.webp +0 -0
  288. package/dist/catalog/knowledge-catalogs/re/regional-american-south/manifest.json +48 -0
  289. package/dist/catalog/knowledge-catalogs/re/regional-american-south/versions/2026.10.3/manifest.json +133 -0
  290. package/dist/catalog/knowledge-catalogs/re/regional-andes-amazon/art.json +12 -0
  291. package/dist/catalog/knowledge-catalogs/re/regional-andes-amazon/logo.webp +0 -0
  292. package/dist/catalog/knowledge-catalogs/re/regional-andes-amazon/manifest.json +48 -0
  293. package/dist/catalog/knowledge-catalogs/re/regional-andes-amazon/versions/2026.10.3/manifest.json +133 -0
  294. package/dist/catalog/knowledge-catalogs/re/regional-australia-nz/art.json +12 -0
  295. package/dist/catalog/knowledge-catalogs/re/regional-australia-nz/logo.webp +0 -0
  296. package/dist/catalog/knowledge-catalogs/re/regional-australia-nz/manifest.json +48 -0
  297. package/dist/catalog/knowledge-catalogs/re/regional-australia-nz/versions/2026.10.3/manifest.json +133 -0
  298. package/dist/catalog/knowledge-catalogs/re/regional-brazil/art.json +12 -0
  299. package/dist/catalog/knowledge-catalogs/re/regional-brazil/logo.webp +0 -0
  300. package/dist/catalog/knowledge-catalogs/re/regional-brazil/manifest.json +48 -0
  301. package/dist/catalog/knowledge-catalogs/re/regional-brazil/versions/2026.10.3/manifest.json +133 -0
  302. package/dist/catalog/knowledge-catalogs/re/regional-britain-ireland/art.json +12 -0
  303. package/dist/catalog/knowledge-catalogs/re/regional-britain-ireland/logo.webp +0 -0
  304. package/dist/catalog/knowledge-catalogs/re/regional-britain-ireland/manifest.json +48 -0
  305. package/dist/catalog/knowledge-catalogs/re/regional-britain-ireland/versions/2026.10.3/manifest.json +133 -0
  306. package/dist/catalog/knowledge-catalogs/re/regional-california-southwest/art.json +12 -0
  307. package/dist/catalog/knowledge-catalogs/re/regional-california-southwest/logo.webp +0 -0
  308. package/dist/catalog/knowledge-catalogs/re/regional-california-southwest/manifest.json +48 -0
  309. package/dist/catalog/knowledge-catalogs/re/regional-california-southwest/versions/2026.10.3/manifest.json +133 -0
  310. package/dist/catalog/knowledge-catalogs/re/regional-canada-alaska/art.json +12 -0
  311. package/dist/catalog/knowledge-catalogs/re/regional-canada-alaska/logo.webp +0 -0
  312. package/dist/catalog/knowledge-catalogs/re/regional-canada-alaska/manifest.json +48 -0
  313. package/dist/catalog/knowledge-catalogs/re/regional-canada-alaska/versions/2026.10.3/manifest.json +133 -0
  314. package/dist/catalog/knowledge-catalogs/re/regional-central-eastern-europe/art.json +12 -0
  315. package/dist/catalog/knowledge-catalogs/re/regional-central-eastern-europe/logo.webp +0 -0
  316. package/dist/catalog/knowledge-catalogs/re/regional-central-eastern-europe/manifest.json +48 -0
  317. package/dist/catalog/knowledge-catalogs/re/regional-central-eastern-europe/versions/2026.10.3/manifest.json +133 -0
  318. package/dist/catalog/knowledge-catalogs/re/regional-east-asia/art.json +12 -0
  319. package/dist/catalog/knowledge-catalogs/re/regional-east-asia/logo.webp +0 -0
  320. package/dist/catalog/knowledge-catalogs/re/regional-east-asia/manifest.json +48 -0
  321. package/dist/catalog/knowledge-catalogs/re/regional-east-asia/versions/2026.10.3/manifest.json +133 -0
  322. package/dist/catalog/knowledge-catalogs/re/regional-east-southern-africa/art.json +12 -0
  323. package/dist/catalog/knowledge-catalogs/re/regional-east-southern-africa/logo.webp +0 -0
  324. package/dist/catalog/knowledge-catalogs/re/regional-east-southern-africa/manifest.json +48 -0
  325. package/dist/catalog/knowledge-catalogs/re/regional-east-southern-africa/versions/2026.10.3/manifest.json +133 -0
  326. package/dist/catalog/knowledge-catalogs/re/regional-mediterranean/art.json +12 -0
  327. package/dist/catalog/knowledge-catalogs/re/regional-mediterranean/logo.webp +0 -0
  328. package/dist/catalog/knowledge-catalogs/re/regional-mediterranean/manifest.json +48 -0
  329. package/dist/catalog/knowledge-catalogs/re/regional-mediterranean/versions/2026.10.3/manifest.json +133 -0
  330. package/dist/catalog/knowledge-catalogs/re/regional-mexico-central-america/art.json +12 -0
  331. package/dist/catalog/knowledge-catalogs/re/regional-mexico-central-america/logo.webp +0 -0
  332. package/dist/catalog/knowledge-catalogs/re/regional-mexico-central-america/manifest.json +48 -0
  333. package/dist/catalog/knowledge-catalogs/re/regional-mexico-central-america/versions/2026.10.3/manifest.json +133 -0
  334. package/dist/catalog/knowledge-catalogs/re/regional-middle-east/art.json +12 -0
  335. package/dist/catalog/knowledge-catalogs/re/regional-middle-east/logo.webp +0 -0
  336. package/dist/catalog/knowledge-catalogs/re/regional-middle-east/manifest.json +48 -0
  337. package/dist/catalog/knowledge-catalogs/re/regional-middle-east/versions/2026.10.3/manifest.json +133 -0
  338. package/dist/catalog/knowledge-catalogs/re/regional-midwest/art.json +12 -0
  339. package/dist/catalog/knowledge-catalogs/re/regional-midwest/logo.webp +0 -0
  340. package/dist/catalog/knowledge-catalogs/re/regional-midwest/manifest.json +48 -0
  341. package/dist/catalog/knowledge-catalogs/re/regional-midwest/versions/2026.10.3/manifest.json +133 -0
  342. package/dist/catalog/knowledge-catalogs/re/regional-north-africa/art.json +12 -0
  343. package/dist/catalog/knowledge-catalogs/re/regional-north-africa/logo.webp +0 -0
  344. package/dist/catalog/knowledge-catalogs/re/regional-north-africa/manifest.json +48 -0
  345. package/dist/catalog/knowledge-catalogs/re/regional-north-africa/versions/2026.10.3/manifest.json +133 -0
  346. package/dist/catalog/knowledge-catalogs/re/regional-northeast/art.json +12 -0
  347. package/dist/catalog/knowledge-catalogs/re/regional-northeast/logo.webp +0 -0
  348. package/dist/catalog/knowledge-catalogs/re/regional-northeast/manifest.json +48 -0
  349. package/dist/catalog/knowledge-catalogs/re/regional-northeast/versions/2026.10.3/manifest.json +133 -0
  350. package/dist/catalog/knowledge-catalogs/re/regional-northern-eurasia/art.json +12 -0
  351. package/dist/catalog/knowledge-catalogs/re/regional-northern-eurasia/logo.webp +0 -0
  352. package/dist/catalog/knowledge-catalogs/re/regional-northern-eurasia/manifest.json +48 -0
  353. package/dist/catalog/knowledge-catalogs/re/regional-northern-eurasia/versions/2026.10.3/manifest.json +133 -0
  354. package/dist/catalog/knowledge-catalogs/re/regional-northern-europe/art.json +12 -0
  355. package/dist/catalog/knowledge-catalogs/re/regional-northern-europe/logo.webp +0 -0
  356. package/dist/catalog/knowledge-catalogs/re/regional-northern-europe/manifest.json +48 -0
  357. package/dist/catalog/knowledge-catalogs/re/regional-northern-europe/versions/2026.10.3/manifest.json +133 -0
  358. package/dist/catalog/knowledge-catalogs/re/regional-pacific-islands/art.json +12 -0
  359. package/dist/catalog/knowledge-catalogs/re/regional-pacific-islands/logo.webp +0 -0
  360. package/dist/catalog/knowledge-catalogs/re/regional-pacific-islands/manifest.json +48 -0
  361. package/dist/catalog/knowledge-catalogs/re/regional-pacific-islands/versions/2026.10.3/manifest.json +133 -0
  362. package/dist/catalog/knowledge-catalogs/re/regional-pacific-northwest/art.json +12 -0
  363. package/dist/catalog/knowledge-catalogs/re/regional-pacific-northwest/logo.webp +0 -0
  364. package/dist/catalog/knowledge-catalogs/re/regional-pacific-northwest/manifest.json +48 -0
  365. package/dist/catalog/knowledge-catalogs/re/regional-pacific-northwest/versions/2026.10.3/manifest.json +133 -0
  366. package/dist/catalog/knowledge-catalogs/re/regional-rockies-plains/art.json +12 -0
  367. package/dist/catalog/knowledge-catalogs/re/regional-rockies-plains/logo.webp +0 -0
  368. package/dist/catalog/knowledge-catalogs/re/regional-rockies-plains/manifest.json +48 -0
  369. package/dist/catalog/knowledge-catalogs/re/regional-rockies-plains/versions/2026.10.3/manifest.json +133 -0
  370. package/dist/catalog/knowledge-catalogs/re/regional-south-asia/art.json +12 -0
  371. package/dist/catalog/knowledge-catalogs/re/regional-south-asia/logo.webp +0 -0
  372. package/dist/catalog/knowledge-catalogs/re/regional-south-asia/manifest.json +48 -0
  373. package/dist/catalog/knowledge-catalogs/re/regional-south-asia/versions/2026.10.3/manifest.json +133 -0
  374. package/dist/catalog/knowledge-catalogs/re/regional-southeast-asia/art.json +12 -0
  375. package/dist/catalog/knowledge-catalogs/re/regional-southeast-asia/logo.webp +0 -0
  376. package/dist/catalog/knowledge-catalogs/re/regional-southeast-asia/manifest.json +48 -0
  377. package/dist/catalog/knowledge-catalogs/re/regional-southeast-asia/versions/2026.10.3/manifest.json +133 -0
  378. package/dist/catalog/knowledge-catalogs/re/regional-southern-cone/art.json +12 -0
  379. package/dist/catalog/knowledge-catalogs/re/regional-southern-cone/logo.webp +0 -0
  380. package/dist/catalog/knowledge-catalogs/re/regional-southern-cone/manifest.json +48 -0
  381. package/dist/catalog/knowledge-catalogs/re/regional-southern-cone/versions/2026.10.3/manifest.json +133 -0
  382. package/dist/catalog/knowledge-catalogs/re/regional-west-central-africa/art.json +12 -0
  383. package/dist/catalog/knowledge-catalogs/re/regional-west-central-africa/logo.webp +0 -0
  384. package/dist/catalog/knowledge-catalogs/re/regional-west-central-africa/manifest.json +48 -0
  385. package/dist/catalog/knowledge-catalogs/re/regional-west-central-africa/versions/2026.10.3/manifest.json +133 -0
  386. package/dist/catalog/knowledge-catalogs/re/regional-western-europe/art.json +12 -0
  387. package/dist/catalog/knowledge-catalogs/re/regional-western-europe/logo.webp +0 -0
  388. package/dist/catalog/knowledge-catalogs/re/regional-western-europe/manifest.json +48 -0
  389. package/dist/catalog/knowledge-catalogs/re/regional-western-europe/versions/2026.10.3/manifest.json +133 -0
  390. package/dist/catalog/knowledge-catalogs/wi/wikipedia-arts/art.json +12 -0
  391. package/dist/catalog/knowledge-catalogs/wi/wikipedia-arts/logo.webp +0 -0
  392. package/dist/catalog/knowledge-catalogs/wi/wikipedia-arts/manifest.json +28 -0
  393. package/dist/catalog/knowledge-catalogs/wi/wikipedia-arts/versions/2026.4.2/manifest.json +53 -0
  394. package/dist/catalog/knowledge-catalogs/wi/wikipedia-arts/versions/2026.4.3/manifest.json +885 -0
  395. package/dist/catalog/knowledge-catalogs/wi/wikipedia-arts/versions/2026.4.5/manifest.json +157 -0
  396. package/dist/catalog/knowledge-catalogs/wi/wikipedia-astronomy/art.json +11 -0
  397. package/dist/catalog/knowledge-catalogs/wi/wikipedia-astronomy/logo.webp +0 -0
  398. package/dist/catalog/knowledge-catalogs/wi/wikipedia-astronomy/manifest.json +32 -0
  399. package/dist/catalog/knowledge-catalogs/wi/wikipedia-astronomy/versions/2026.4.2/manifest.json +69 -0
  400. package/dist/catalog/knowledge-catalogs/wi/wikipedia-astronomy/versions/2026.4.3/manifest.json +741 -0
  401. package/dist/catalog/knowledge-catalogs/wi/wikipedia-astronomy/versions/2026.4.5/manifest.json +173 -0
  402. package/dist/catalog/knowledge-catalogs/wi/wikipedia-biology/art.json +12 -0
  403. package/dist/catalog/knowledge-catalogs/wi/wikipedia-biology/logo.webp +0 -0
  404. package/dist/catalog/knowledge-catalogs/wi/wikipedia-biology/manifest.json +69 -0
  405. package/dist/catalog/knowledge-catalogs/wi/wikipedia-biology/versions/2026.4.4/manifest.json +217 -0
  406. package/dist/catalog/knowledge-catalogs/wi/wikipedia-biology/versions/2026.4.5/manifest.json +217 -0
  407. package/dist/catalog/knowledge-catalogs/wi/wikipedia-business/art.json +12 -0
  408. package/dist/catalog/knowledge-catalogs/wi/wikipedia-business/logo.webp +0 -0
  409. package/dist/catalog/knowledge-catalogs/wi/wikipedia-business/manifest.json +64 -0
  410. package/dist/catalog/knowledge-catalogs/wi/wikipedia-business/versions/2026.4.4/manifest.json +197 -0
  411. package/dist/catalog/knowledge-catalogs/wi/wikipedia-business/versions/2026.4.5/manifest.json +197 -0
  412. package/dist/catalog/knowledge-catalogs/wi/wikipedia-film-tv/art.json +12 -0
  413. package/dist/catalog/knowledge-catalogs/wi/wikipedia-film-tv/logo.webp +0 -0
  414. package/dist/catalog/knowledge-catalogs/wi/wikipedia-film-tv/manifest.json +64 -0
  415. package/dist/catalog/knowledge-catalogs/wi/wikipedia-film-tv/versions/2026.4.5/manifest.json +197 -0
  416. package/dist/catalog/knowledge-catalogs/wi/wikipedia-food-drink/art.json +11 -0
  417. package/dist/catalog/knowledge-catalogs/wi/wikipedia-food-drink/logo.webp +0 -0
  418. package/dist/catalog/knowledge-catalogs/wi/wikipedia-food-drink/manifest.json +29 -0
  419. package/dist/catalog/knowledge-catalogs/wi/wikipedia-food-drink/versions/2026.4.2/manifest.json +57 -0
  420. package/dist/catalog/knowledge-catalogs/wi/wikipedia-food-drink/versions/2026.4.3/manifest.json +925 -0
  421. package/dist/catalog/knowledge-catalogs/wi/wikipedia-food-drink/versions/2026.4.5/manifest.json +185 -0
  422. package/dist/catalog/knowledge-catalogs/wi/wikipedia-games/art.json +12 -0
  423. package/dist/catalog/knowledge-catalogs/wi/wikipedia-games/logo.webp +0 -0
  424. package/dist/catalog/knowledge-catalogs/wi/wikipedia-games/manifest.json +28 -0
  425. package/dist/catalog/knowledge-catalogs/wi/wikipedia-games/versions/2026.4.2/manifest.json +53 -0
  426. package/dist/catalog/knowledge-catalogs/wi/wikipedia-games/versions/2026.4.3/manifest.json +1665 -0
  427. package/dist/catalog/knowledge-catalogs/wi/wikipedia-games/versions/2026.4.5/manifest.json +133 -0
  428. package/dist/catalog/knowledge-catalogs/wi/wikipedia-language/art.json +12 -0
  429. package/dist/catalog/knowledge-catalogs/wi/wikipedia-language/logo.webp +0 -0
  430. package/dist/catalog/knowledge-catalogs/wi/wikipedia-language/manifest.json +29 -0
  431. package/dist/catalog/knowledge-catalogs/wi/wikipedia-language/versions/2026.4.2/manifest.json +57 -0
  432. package/dist/catalog/knowledge-catalogs/wi/wikipedia-language/versions/2026.4.3/manifest.json +1233 -0
  433. package/dist/catalog/knowledge-catalogs/wi/wikipedia-language/versions/2026.4.5/manifest.json +141 -0
  434. package/dist/catalog/knowledge-catalogs/wi/wikipedia-law/art.json +11 -0
  435. package/dist/catalog/knowledge-catalogs/wi/wikipedia-law/logo.webp +0 -0
  436. package/dist/catalog/knowledge-catalogs/wi/wikipedia-law/manifest.json +29 -0
  437. package/dist/catalog/knowledge-catalogs/wi/wikipedia-law/versions/2026.4.2/manifest.json +57 -0
  438. package/dist/catalog/knowledge-catalogs/wi/wikipedia-law/versions/2026.4.3/manifest.json +493 -0
  439. package/dist/catalog/knowledge-catalogs/wi/wikipedia-law/versions/2026.4.5/manifest.json +185 -0
  440. package/dist/catalog/knowledge-catalogs/wi/wikipedia-literature/art.json +12 -0
  441. package/dist/catalog/knowledge-catalogs/wi/wikipedia-literature/logo.webp +0 -0
  442. package/dist/catalog/knowledge-catalogs/wi/wikipedia-literature/manifest.json +63 -0
  443. package/dist/catalog/knowledge-catalogs/wi/wikipedia-literature/versions/2026.4.4/manifest.json +193 -0
  444. package/dist/catalog/knowledge-catalogs/wi/wikipedia-literature/versions/2026.4.5/manifest.json +193 -0
  445. package/dist/catalog/knowledge-catalogs/wi/wikipedia-mathematics/art.json +12 -0
  446. package/dist/catalog/knowledge-catalogs/wi/wikipedia-mathematics/logo.webp +0 -0
  447. package/dist/catalog/knowledge-catalogs/wi/wikipedia-mathematics/manifest.json +30 -0
  448. package/dist/catalog/knowledge-catalogs/wi/wikipedia-mathematics/versions/2026.4.2/manifest.json +61 -0
  449. package/dist/catalog/knowledge-catalogs/wi/wikipedia-mathematics/versions/2026.4.3/manifest.json +665 -0
  450. package/dist/catalog/knowledge-catalogs/wi/wikipedia-mathematics/versions/2026.4.5/manifest.json +177 -0
  451. package/dist/catalog/knowledge-catalogs/wi/wikipedia-medicine/art.json +12 -0
  452. package/dist/catalog/knowledge-catalogs/wi/wikipedia-medicine/logo.webp +0 -0
  453. package/dist/catalog/knowledge-catalogs/wi/wikipedia-medicine/manifest.json +29 -0
  454. package/dist/catalog/knowledge-catalogs/wi/wikipedia-medicine/versions/2026.4.2/manifest.json +57 -0
  455. package/dist/catalog/knowledge-catalogs/wi/wikipedia-medicine/versions/2026.4.3/manifest.json +745 -0
  456. package/dist/catalog/knowledge-catalogs/wi/wikipedia-medicine/versions/2026.4.5/manifest.json +185 -0
  457. package/dist/catalog/knowledge-catalogs/wi/wikipedia-military/art.json +12 -0
  458. package/dist/catalog/knowledge-catalogs/wi/wikipedia-military/logo.webp +0 -0
  459. package/dist/catalog/knowledge-catalogs/wi/wikipedia-military/manifest.json +62 -0
  460. package/dist/catalog/knowledge-catalogs/wi/wikipedia-military/versions/2026.4.4/manifest.json +189 -0
  461. package/dist/catalog/knowledge-catalogs/wi/wikipedia-military/versions/2026.4.5/manifest.json +189 -0
  462. package/dist/catalog/knowledge-catalogs/wi/wikipedia-music/art.json +12 -0
  463. package/dist/catalog/knowledge-catalogs/wi/wikipedia-music/logo.webp +0 -0
  464. package/dist/catalog/knowledge-catalogs/wi/wikipedia-music/manifest.json +64 -0
  465. package/dist/catalog/knowledge-catalogs/wi/wikipedia-music/versions/2026.4.5/manifest.json +197 -0
  466. package/dist/catalog/knowledge-catalogs/wi/wikipedia-politics/art.json +12 -0
  467. package/dist/catalog/knowledge-catalogs/wi/wikipedia-politics/logo.webp +0 -0
  468. package/dist/catalog/knowledge-catalogs/wi/wikipedia-politics/manifest.json +64 -0
  469. package/dist/catalog/knowledge-catalogs/wi/wikipedia-politics/versions/2026.4.4/manifest.json +197 -0
  470. package/dist/catalog/knowledge-catalogs/wi/wikipedia-politics/versions/2026.4.5/manifest.json +197 -0
  471. package/dist/catalog/knowledge-catalogs/wi/wikipedia-religion-philosophy/art.json +12 -0
  472. package/dist/catalog/knowledge-catalogs/wi/wikipedia-religion-philosophy/logo.webp +0 -0
  473. package/dist/catalog/knowledge-catalogs/wi/wikipedia-religion-philosophy/manifest.json +30 -0
  474. package/dist/catalog/knowledge-catalogs/wi/wikipedia-religion-philosophy/versions/2026.4.2/manifest.json +61 -0
  475. package/dist/catalog/knowledge-catalogs/wi/wikipedia-religion-philosophy/versions/2026.4.3/manifest.json +1253 -0
  476. package/dist/catalog/knowledge-catalogs/wi/wikipedia-religion-philosophy/versions/2026.4.5/manifest.json +189 -0
  477. package/dist/catalog/knowledge-catalogs/wi/wikipedia-science/art.json +12 -0
  478. package/dist/catalog/knowledge-catalogs/wi/wikipedia-science/logo.webp +0 -0
  479. package/dist/catalog/knowledge-catalogs/wi/wikipedia-science/manifest.json +29 -0
  480. package/dist/catalog/knowledge-catalogs/wi/wikipedia-science/versions/2026.4.2/manifest.json +57 -0
  481. package/dist/catalog/knowledge-catalogs/wi/wikipedia-science/versions/2026.4.3/manifest.json +1957 -0
  482. package/dist/catalog/knowledge-catalogs/wi/wikipedia-science/versions/2026.4.5/manifest.json +185 -0
  483. package/dist/catalog/knowledge-catalogs/wi/wikipedia-sports/art.json +12 -0
  484. package/dist/catalog/knowledge-catalogs/wi/wikipedia-sports/logo.webp +0 -0
  485. package/dist/catalog/knowledge-catalogs/wi/wikipedia-sports/manifest.json +63 -0
  486. package/dist/catalog/knowledge-catalogs/wi/wikipedia-sports/versions/2026.4.5/manifest.json +193 -0
  487. package/dist/catalog/knowledge-catalogs/wi/wikipedia-technology/art.json +11 -0
  488. package/dist/catalog/knowledge-catalogs/wi/wikipedia-technology/logo.webp +0 -0
  489. package/dist/catalog/knowledge-catalogs/wi/wikipedia-technology/manifest.json +45 -0
  490. package/dist/catalog/knowledge-catalogs/wi/wikipedia-technology/versions/2026.4.4/manifest.json +121 -0
  491. package/dist/catalog/knowledge-catalogs/wi/wikipedia-technology/versions/2026.4.5/manifest.json +173 -0
  492. package/dist/catalog/knowledge-catalogs/wi/wikipedia-transportation/art.json +12 -0
  493. package/dist/catalog/knowledge-catalogs/wi/wikipedia-transportation/logo.webp +0 -0
  494. package/dist/catalog/knowledge-catalogs/wi/wikipedia-transportation/manifest.json +62 -0
  495. package/dist/catalog/knowledge-catalogs/wi/wikipedia-transportation/versions/2026.4.4/manifest.json +189 -0
  496. package/dist/catalog/knowledge-catalogs/wi/wikipedia-transportation/versions/2026.4.5/manifest.json +189 -0
  497. package/dist/catalog/provenance.json +8 -0
  498. package/dist/chat/catalog-model-lookup.d.ts +21 -0
  499. package/dist/chat/catalog-model-lookup.js +48 -0
  500. package/dist/chat/local-model-tier.d.ts +1 -0
  501. package/dist/chat/local-model-tier.js +2 -0
  502. package/dist/chat/vision-capability.d.ts +1 -0
  503. package/dist/chat/vision-capability.js +3 -0
  504. package/dist/engine-components.d.ts +30 -0
  505. package/dist/engine-components.js +144 -0
  506. package/dist/engines/electron-native-reuse.d.ts +65 -0
  507. package/dist/engines/electron-native-reuse.js +305 -0
  508. package/dist/engines/native-file-manifest.json +1320 -0
  509. package/dist/engines/native-manifest.d.ts +70 -0
  510. package/dist/engines/native-manifest.js +98 -0
  511. package/dist/engines/registry.d.ts +88 -0
  512. package/dist/engines/registry.js +217 -0
  513. package/dist/engines/resolver.d.ts +121 -0
  514. package/dist/engines/resolver.js +894 -0
  515. package/dist/engines/signature.d.ts +85 -0
  516. package/dist/engines/signature.js +231 -0
  517. package/dist/fs/atomic.d.ts +53 -0
  518. package/dist/fs/atomic.js +202 -0
  519. package/dist/fs/config-store.d.ts +14 -0
  520. package/dist/fs/config-store.js +101 -0
  521. package/dist/fs/home-permissions.d.ts +18 -0
  522. package/dist/fs/home-permissions.js +27 -0
  523. package/dist/fs/safe-paths.d.ts +107 -0
  524. package/dist/fs/safe-paths.js +264 -0
  525. package/dist/fs/security-json.d.ts +13 -0
  526. package/dist/fs/security-json.js +67 -0
  527. package/dist/http/auth-context.d.ts +23 -0
  528. package/dist/http/auth-context.js +1 -0
  529. package/dist/http/engine-runtime-context.d.ts +30 -0
  530. package/dist/http/engine-runtime-context.js +1 -0
  531. package/dist/http/external-conversation-contract.d.ts +49 -0
  532. package/dist/http/external-conversation-contract.js +1 -0
  533. package/dist/http/external-conversation-headers.d.ts +11 -0
  534. package/dist/http/external-conversation-headers.js +11 -0
  535. package/dist/http/inference-context.d.ts +36 -0
  536. package/dist/http/inference-context.js +1 -0
  537. package/dist/http/model-inventory-cache.d.ts +8 -0
  538. package/dist/http/model-inventory-cache.js +8 -0
  539. package/dist/http/openai-compat/action-ledger.d.ts +15 -0
  540. package/dist/http/openai-compat/action-ledger.js +119 -0
  541. package/dist/http/openai-compat/apple-model.d.ts +3 -0
  542. package/dist/http/openai-compat/apple-model.js +44 -0
  543. package/dist/http/openai-compat/caller-owned-profile.d.ts +7 -0
  544. package/dist/http/openai-compat/caller-owned-profile.js +18 -0
  545. package/dist/http/openai-compat/chat-progress.d.ts +9 -0
  546. package/dist/http/openai-compat/chat-progress.js +69 -0
  547. package/dist/http/openai-compat/chat-target.d.ts +76 -0
  548. package/dist/http/openai-compat/chat-target.js +97 -0
  549. package/dist/http/openai-compat/embeddings.d.ts +37 -0
  550. package/dist/http/openai-compat/embeddings.js +86 -0
  551. package/dist/http/openai-compat/request-tuning.d.ts +35 -0
  552. package/dist/http/openai-compat/request-tuning.js +87 -0
  553. package/dist/http/openai-compat/responses-streaming.d.ts +351 -0
  554. package/dist/http/openai-compat/responses-streaming.js +717 -0
  555. package/dist/http/openai-compat/responses-translate.d.ts +215 -0
  556. package/dist/http/openai-compat/responses-translate.js +377 -0
  557. package/dist/http/openai-compat/streaming-telemetry.d.ts +30 -0
  558. package/dist/http/openai-compat/streaming-telemetry.js +88 -0
  559. package/dist/http/openai-compat/streaming.d.ts +141 -0
  560. package/dist/http/openai-compat/streaming.js +687 -0
  561. package/dist/http/openai-compat/tool-call-stream-filter.d.ts +33 -0
  562. package/dist/http/openai-compat/tool-call-stream-filter.js +110 -0
  563. package/dist/http/openai-compat/translate.d.ts +254 -0
  564. package/dist/http/openai-compat/translate.js +485 -0
  565. package/dist/http/routes/engines.d.ts +13 -0
  566. package/dist/http/routes/engines.js +366 -0
  567. package/dist/http/routes/machine-engine-proxy.d.ts +26 -0
  568. package/dist/http/routes/machine-engine-proxy.js +43 -0
  569. package/dist/http/routes/model-bundles.d.ts +4 -0
  570. package/dist/http/routes/model-bundles.js +190 -0
  571. package/dist/http/routes/v1-chat.d.ts +72 -0
  572. package/dist/http/routes/v1-chat.js +645 -0
  573. package/dist/http/routes/v1-embeddings.d.ts +3 -0
  574. package/dist/http/routes/v1-embeddings.js +82 -0
  575. package/dist/http/routes/v1-knowledge.d.ts +4 -0
  576. package/dist/http/routes/v1-knowledge.js +304 -0
  577. package/dist/http/routes/v1-models-ensure.d.ts +32 -0
  578. package/dist/http/routes/v1-models-ensure.js +122 -0
  579. package/dist/http/routes/v1-models.d.ts +8 -0
  580. package/dist/http/routes/v1-models.js +189 -0
  581. package/dist/http/routes/v1-responses.d.ts +20 -0
  582. package/dist/http/routes/v1-responses.js +327 -0
  583. package/dist/index.d.ts +2 -0
  584. package/dist/index.js +2 -0
  585. package/dist/inference-service.d.ts +28 -0
  586. package/dist/inference-service.js +275 -0
  587. package/dist/knowledge/admission.d.ts +3 -0
  588. package/dist/knowledge/admission.js +22 -0
  589. package/dist/knowledge/bundled-catalog.d.ts +2 -0
  590. package/dist/knowledge/bundled-catalog.js +2 -0
  591. package/dist/knowledge/catalog-host.d.ts +103 -0
  592. package/dist/knowledge/catalog-host.js +180 -0
  593. package/dist/knowledge/catalog-source.d.ts +22 -0
  594. package/dist/knowledge/catalog-source.js +35 -0
  595. package/dist/knowledge/install.d.ts +55 -0
  596. package/dist/knowledge/install.js +274 -0
  597. package/dist/knowledge/manager.d.ts +287 -0
  598. package/dist/knowledge/manager.js +1540 -0
  599. package/dist/knowledge/registry.d.ts +35 -0
  600. package/dist/knowledge/registry.js +123 -0
  601. package/dist/knowledge/search-worker.d.ts +17 -0
  602. package/dist/knowledge/search-worker.js +36 -0
  603. package/dist/knowledge/shared-install-contract.d.ts +19 -0
  604. package/dist/knowledge/shared-install-contract.js +1 -0
  605. package/dist/knowledge/spatial-query.d.ts +11 -0
  606. package/dist/knowledge/spatial-query.js +33 -0
  607. package/dist/knowledge/trust-anchors.d.ts +11 -0
  608. package/dist/knowledge/trust-anchors.js +51 -0
  609. package/dist/knowledge/vector-floors.d.ts +44 -0
  610. package/dist/knowledge/vector-floors.js +92 -0
  611. package/dist/knowledge/worker-host.d.ts +9 -0
  612. package/dist/knowledge/worker-host.js +179 -0
  613. package/dist/kokoro-lexicon/LICENSE +202 -0
  614. package/dist/kokoro-lexicon/lexicon-gb-en.txt.gz +0 -0
  615. package/dist/kokoro-lexicon/lexicon-us-en.txt.gz +0 -0
  616. package/dist/kokoro-lexicon/manifest.json +23 -0
  617. package/dist/machine-engine/inspect-runtime.d.ts +3 -0
  618. package/dist/machine-engine/inspect-runtime.js +48 -0
  619. package/dist/machine-engine/knowledge-assets.d.ts +79 -0
  620. package/dist/machine-engine/knowledge-assets.js +505 -0
  621. package/dist/memory/embed-core.d.ts +131 -0
  622. package/dist/memory/embed-core.js +398 -0
  623. package/dist/memory/embed-worker.d.ts +23 -0
  624. package/dist/memory/embed-worker.js +49 -0
  625. package/dist/memory/embeddings.d.ts +105 -0
  626. package/dist/memory/embeddings.js +467 -0
  627. package/dist/model-profile/behaviors/tools-mlx-template-fix.d.ts +1 -0
  628. package/dist/model-profile/behaviors/tools-mlx-template-fix.js +2 -0
  629. package/dist/model-profile/behaviors/turn-ramble-detection.d.ts +1 -0
  630. package/dist/model-profile/behaviors/turn-ramble-detection.js +2 -0
  631. package/dist/model-profile/defaults.d.ts +1 -0
  632. package/dist/model-profile/defaults.js +2 -0
  633. package/dist/model-profile/index.d.ts +9 -0
  634. package/dist/model-profile/index.js +7 -0
  635. package/dist/model-profile/registry.d.ts +15 -0
  636. package/dist/model-profile/registry.js +18 -0
  637. package/dist/model-profile/runtime.d.ts +48 -0
  638. package/dist/model-profile/runtime.js +131 -0
  639. package/dist/model-profile/tool-grammar.d.ts +1 -0
  640. package/dist/model-profile/tool-grammar.js +2 -0
  641. package/dist/model-profile/tuning.d.ts +19 -0
  642. package/dist/model-profile/tuning.js +21 -0
  643. package/dist/model-profile/types.d.ts +1 -0
  644. package/dist/model-profile/types.js +2 -0
  645. package/dist/models/bundle-storage.d.ts +28 -0
  646. package/dist/models/bundle-storage.js +80 -0
  647. package/dist/models/catalog-drift.d.ts +48 -0
  648. package/dist/models/catalog-drift.js +94 -0
  649. package/dist/models/catalog-payload-identity.d.ts +107 -0
  650. package/dist/models/catalog-payload-identity.js +254 -0
  651. package/dist/models/ensure.d.ts +125 -0
  652. package/dist/models/ensure.js +205 -0
  653. package/dist/models/gezmodel.d.ts +47 -0
  654. package/dist/models/gezmodel.js +742 -0
  655. package/dist/models/install-registry.d.ts +101 -0
  656. package/dist/models/install-registry.js +216 -0
  657. package/dist/models/model-id.d.ts +22 -0
  658. package/dist/models/model-id.js +40 -0
  659. package/dist/models/storage-roots.d.ts +274 -0
  660. package/dist/models/storage-roots.js +865 -0
  661. package/dist/native-release-entry.d.ts +16 -0
  662. package/dist/native-release-entry.js +16 -0
  663. package/dist/perf/redact-path.d.ts +2 -0
  664. package/dist/perf/redact-path.js +27 -0
  665. package/dist/perf/responsiveness.d.ts +70 -0
  666. package/dist/perf/responsiveness.js +560 -0
  667. package/dist/providers/active-install-message.d.ts +42 -0
  668. package/dist/providers/active-install-message.js +49 -0
  669. package/dist/providers/apple-foundation-models/binary.d.ts +4 -0
  670. package/dist/providers/apple-foundation-models/binary.js +18 -0
  671. package/dist/providers/apple-foundation-models/helper.d.ts +66 -0
  672. package/dist/providers/apple-foundation-models/helper.js +262 -0
  673. package/dist/providers/apple-foundation-models/provider.d.ts +82 -0
  674. package/dist/providers/apple-foundation-models/provider.js +389 -0
  675. package/dist/providers/apple-foundation-models/status.d.ts +9 -0
  676. package/dist/providers/apple-foundation-models/status.js +49 -0
  677. package/dist/providers/audio/kokoro-frontend.d.ts +50 -0
  678. package/dist/providers/audio/kokoro-frontend.js +113 -0
  679. package/dist/providers/audio/managed-speech-model.d.ts +9 -0
  680. package/dist/providers/audio/managed-speech-model.js +86 -0
  681. package/dist/providers/audio/types.d.ts +202 -0
  682. package/dist/providers/audio/types.js +17 -0
  683. package/dist/providers/audio/whisper-cpp.d.ts +99 -0
  684. package/dist/providers/audio/whisper-cpp.js +420 -0
  685. package/dist/providers/audio-persister-contract.d.ts +13 -0
  686. package/dist/providers/audio-persister-contract.js +1 -0
  687. package/dist/providers/catalog-model-config.d.ts +63 -0
  688. package/dist/providers/catalog-model-config.js +95 -0
  689. package/dist/providers/code-block-salvage.d.ts +1 -0
  690. package/dist/providers/code-block-salvage.js +2 -0
  691. package/dist/providers/codex-cli/reasoning.d.ts +8 -0
  692. package/dist/providers/codex-cli/reasoning.js +17 -0
  693. package/dist/providers/complete-tool-call.d.ts +16 -0
  694. package/dist/providers/complete-tool-call.js +25 -0
  695. package/dist/providers/constrained-turn.d.ts +1 -0
  696. package/dist/providers/constrained-turn.js +2 -0
  697. package/dist/providers/deliverable-read-pacing.d.ts +1 -0
  698. package/dist/providers/deliverable-read-pacing.js +2 -0
  699. package/dist/providers/direct-file-work-prompt.d.ts +1 -0
  700. package/dist/providers/direct-file-work-prompt.js +2 -0
  701. package/dist/providers/ds4/build-provider.d.ts +100 -0
  702. package/dist/providers/ds4/build-provider.js +539 -0
  703. package/dist/providers/ds4/cache-adapter.d.ts +42 -0
  704. package/dist/providers/ds4/cache-adapter.js +110 -0
  705. package/dist/providers/ds4/dspark.d.ts +83 -0
  706. package/dist/providers/ds4/dspark.js +107 -0
  707. package/dist/providers/ds4/mtp.d.ts +32 -0
  708. package/dist/providers/ds4/mtp.js +46 -0
  709. package/dist/providers/ds4/provider.d.ts +67 -0
  710. package/dist/providers/ds4/provider.js +104 -0
  711. package/dist/providers/ds4/residency.d.ts +143 -0
  712. package/dist/providers/ds4/residency.js +139 -0
  713. package/dist/providers/ds4/stdout-parser.d.ts +47 -0
  714. package/dist/providers/ds4/stdout-parser.js +134 -0
  715. package/dist/providers/duplicate-tool-calls.d.ts +1 -0
  716. package/dist/providers/duplicate-tool-calls.js +2 -0
  717. package/dist/providers/file-repair-policy.d.ts +1 -0
  718. package/dist/providers/file-repair-policy.js +2 -0
  719. package/dist/providers/gpu-arbiter.d.ts +159 -0
  720. package/dist/providers/gpu-arbiter.js +301 -0
  721. package/dist/providers/image-persister-contract.d.ts +15 -0
  722. package/dist/providers/image-persister-contract.js +1 -0
  723. package/dist/providers/llama-cpp/build-metadata.d.ts +13 -0
  724. package/dist/providers/llama-cpp/build-metadata.js +39 -0
  725. package/dist/providers/llama-cpp/build-provider.d.ts +66 -0
  726. package/dist/providers/llama-cpp/build-provider.js +1491 -0
  727. package/dist/providers/llama-cpp/cache-adapter.d.ts +242 -0
  728. package/dist/providers/llama-cpp/cache-adapter.js +689 -0
  729. package/dist/providers/llama-cpp/devices.d.ts +130 -0
  730. package/dist/providers/llama-cpp/devices.js +256 -0
  731. package/dist/providers/llama-cpp/disk-cache.d.ts +8 -0
  732. package/dist/providers/llama-cpp/disk-cache.js +112 -0
  733. package/dist/providers/llama-cpp/engine-flags.d.ts +181 -0
  734. package/dist/providers/llama-cpp/engine-flags.js +279 -0
  735. package/dist/providers/llama-cpp/gguf-metadata-async.d.ts +11 -0
  736. package/dist/providers/llama-cpp/gguf-metadata-async.js +180 -0
  737. package/dist/providers/llama-cpp/gguf-metadata-worker.d.ts +7 -0
  738. package/dist/providers/llama-cpp/gguf-metadata-worker.js +27 -0
  739. package/dist/providers/llama-cpp/gguf-metadata.d.ts +198 -0
  740. package/dist/providers/llama-cpp/gguf-metadata.js +615 -0
  741. package/dist/providers/llama-cpp/gguf-quantization-backfill.d.ts +32 -0
  742. package/dist/providers/llama-cpp/gguf-quantization-backfill.js +75 -0
  743. package/dist/providers/llama-cpp/index.d.ts +10 -0
  744. package/dist/providers/llama-cpp/index.js +13 -0
  745. package/dist/providers/llama-cpp/kv-cache-type.d.ts +118 -0
  746. package/dist/providers/llama-cpp/kv-cache-type.js +140 -0
  747. package/dist/providers/llama-cpp/log.d.ts +92 -0
  748. package/dist/providers/llama-cpp/log.js +280 -0
  749. package/dist/providers/llama-cpp/models.d.ts +389 -0
  750. package/dist/providers/llama-cpp/models.js +1011 -0
  751. package/dist/providers/llama-cpp/offload-planner.d.ts +339 -0
  752. package/dist/providers/llama-cpp/offload-planner.js +524 -0
  753. package/dist/providers/llama-cpp/provider.d.ts +493 -0
  754. package/dist/providers/llama-cpp/provider.js +862 -0
  755. package/dist/providers/llama-cpp/reasoning-launch.d.ts +7 -0
  756. package/dist/providers/llama-cpp/reasoning-launch.js +14 -0
  757. package/dist/providers/llama-cpp/spec-draft.d.ts +44 -0
  758. package/dist/providers/llama-cpp/spec-draft.js +44 -0
  759. package/dist/providers/llama-cpp/stdout-parser.d.ts +70 -0
  760. package/dist/providers/llama-cpp/stdout-parser.js +197 -0
  761. package/dist/providers/local-tool-call-salvage.d.ts +1 -0
  762. package/dist/providers/local-tool-call-salvage.js +2 -0
  763. package/dist/providers/local-turn-policy.d.ts +1 -0
  764. package/dist/providers/local-turn-policy.js +2 -0
  765. package/dist/providers/mlx/async-file-handoff.d.ts +11 -0
  766. package/dist/providers/mlx/async-file-handoff.js +25 -0
  767. package/dist/providers/mlx/build-provider.d.ts +65 -0
  768. package/dist/providers/mlx/build-provider.js +717 -0
  769. package/dist/providers/mlx/cache-adapter.d.ts +161 -0
  770. package/dist/providers/mlx/cache-adapter.js +445 -0
  771. package/dist/providers/mlx/chat-protocol.d.ts +48 -0
  772. package/dist/providers/mlx/chat-protocol.js +8 -0
  773. package/dist/providers/mlx/config-parser.d.ts +29 -0
  774. package/dist/providers/mlx/config-parser.js +81 -0
  775. package/dist/providers/mlx/engine-gate.d.ts +51 -0
  776. package/dist/providers/mlx/engine-gate.js +207 -0
  777. package/dist/providers/mlx/engine-hold.d.ts +41 -0
  778. package/dist/providers/mlx/engine-hold.js +59 -0
  779. package/dist/providers/mlx/engine-log-router.d.ts +84 -0
  780. package/dist/providers/mlx/engine-log-router.js +137 -0
  781. package/dist/providers/mlx/engine-stats-sampler.d.ts +36 -0
  782. package/dist/providers/mlx/engine-stats-sampler.js +59 -0
  783. package/dist/providers/mlx/index.d.ts +10 -0
  784. package/dist/providers/mlx/index.js +10 -0
  785. package/dist/providers/mlx/log.d.ts +55 -0
  786. package/dist/providers/mlx/log.js +157 -0
  787. package/dist/providers/mlx/model-geometry.d.ts +35 -0
  788. package/dist/providers/mlx/model-geometry.js +118 -0
  789. package/dist/providers/mlx/models.d.ts +289 -0
  790. package/dist/providers/mlx/models.js +1079 -0
  791. package/dist/providers/mlx/provider.d.ts +404 -0
  792. package/dist/providers/mlx/provider.js +3017 -0
  793. package/dist/providers/mlx/python/cache_persist.py +348 -0
  794. package/dist/providers/mlx/python/cache_seed.py +402 -0
  795. package/dist/providers/mlx/python/gezel_mlx_server.py +4491 -0
  796. package/dist/providers/mlx/python/lfm2_compat.py +55 -0
  797. package/dist/providers/mlx/python/qwen3_5_text_compat.py +60 -0
  798. package/dist/providers/mlx/python/qwen4_ple.py +159 -0
  799. package/dist/providers/mlx/python/spec_decode.py +775 -0
  800. package/dist/providers/mlx/python/template_stability.py +133 -0
  801. package/dist/providers/mlx/python/think_budget.py +113 -0
  802. package/dist/providers/mlx/python/tool_args_json.py +297 -0
  803. package/dist/providers/mlx/python/tool_call_stream.py +265 -0
  804. package/dist/providers/mlx/python/tool_grammar.py +794 -0
  805. package/dist/providers/mlx/python/vision_inputs.py +64 -0
  806. package/dist/providers/mlx/python/wave_policy.py +147 -0
  807. package/dist/providers/mlx/reasoning-stream.d.ts +85 -0
  808. package/dist/providers/mlx/reasoning-stream.js +196 -0
  809. package/dist/providers/mlx/request-shape.d.ts +34 -0
  810. package/dist/providers/mlx/request-shape.js +42 -0
  811. package/dist/providers/mlx/runtime-diagnostics.d.ts +29 -0
  812. package/dist/providers/mlx/runtime-diagnostics.js +162 -0
  813. package/dist/providers/mlx/spec-drafter.d.ts +25 -0
  814. package/dist/providers/mlx/spec-drafter.js +73 -0
  815. package/dist/providers/mlx/stdout-parser.d.ts +60 -0
  816. package/dist/providers/mlx/stdout-parser.js +254 -0
  817. package/dist/providers/mlx/textual-tool-call-salvage.d.ts +46 -0
  818. package/dist/providers/mlx/textual-tool-call-salvage.js +396 -0
  819. package/dist/providers/mlx/tool-call-protocol.d.ts +65 -0
  820. package/dist/providers/mlx/tool-call-protocol.js +140 -0
  821. package/dist/providers/mlx/tool-call-stripper.d.ts +68 -0
  822. package/dist/providers/mlx/tool-call-stripper.js +153 -0
  823. package/dist/providers/mlx/tool-image-retention.d.ts +23 -0
  824. package/dist/providers/mlx/tool-image-retention.js +43 -0
  825. package/dist/providers/mlx/turn-telemetry.d.ts +22 -0
  826. package/dist/providers/mlx/turn-telemetry.js +45 -0
  827. package/dist/providers/mlx/venv.d.ts +91 -0
  828. package/dist/providers/mlx/venv.js +111 -0
  829. package/dist/providers/mlx/vision-mode.d.ts +92 -0
  830. package/dist/providers/mlx/vision-mode.js +187 -0
  831. package/dist/providers/mlx/vision.d.ts +2 -0
  832. package/dist/providers/mlx/vision.js +12 -0
  833. package/dist/providers/mlx/wire-transcript.d.ts +14 -0
  834. package/dist/providers/mlx/wire-transcript.js +43 -0
  835. package/dist/providers/native/capacity-broker.d.ts +812 -0
  836. package/dist/providers/native/capacity-broker.js +1058 -0
  837. package/dist/providers/native/capacity-budget.d.ts +133 -0
  838. package/dist/providers/native/capacity-budget.js +265 -0
  839. package/dist/providers/native/device-capacity-ledger.d.ts +31 -0
  840. package/dist/providers/native/device-capacity-ledger.js +196 -0
  841. package/dist/providers/native/device-capacity.d.ts +84 -0
  842. package/dist/providers/native/device-capacity.js +431 -0
  843. package/dist/providers/native/engine-api-key.d.ts +57 -0
  844. package/dist/providers/native/engine-api-key.js +72 -0
  845. package/dist/providers/native/engine-key.d.ts +18 -0
  846. package/dist/providers/native/engine-key.js +41 -0
  847. package/dist/providers/native/engine-router.d.ts +145 -0
  848. package/dist/providers/native/engine-router.js +191 -0
  849. package/dist/providers/native/gpu-panic-guard.d.ts +54 -0
  850. package/dist/providers/native/gpu-panic-guard.js +59 -0
  851. package/dist/providers/native/inference.d.ts +33 -0
  852. package/dist/providers/native/inference.js +49 -0
  853. package/dist/providers/native/local-engine-runtime.d.ts +412 -0
  854. package/dist/providers/native/local-engine-runtime.js +1714 -0
  855. package/dist/providers/native/measured-budget.d.ts +32 -0
  856. package/dist/providers/native/measured-budget.js +54 -0
  857. package/dist/providers/native/port.d.ts +11 -0
  858. package/dist/providers/native/port.js +29 -0
  859. package/dist/providers/native/provider-pool.d.ts +474 -0
  860. package/dist/providers/native/provider-pool.js +1166 -0
  861. package/dist/providers/native/supervisor.d.ts +503 -0
  862. package/dist/providers/native/supervisor.js +1466 -0
  863. package/dist/providers/observation-context.d.ts +16 -0
  864. package/dist/providers/observation-context.js +1 -0
  865. package/dist/providers/openai-compatible/sse.d.ts +1 -0
  866. package/dist/providers/openai-compatible/sse.js +2 -0
  867. package/dist/providers/patient-fetch.d.ts +36 -0
  868. package/dist/providers/patient-fetch.js +44 -0
  869. package/dist/providers/project-macro-loop-bail.d.ts +7 -0
  870. package/dist/providers/project-macro-loop-bail.js +21 -0
  871. package/dist/providers/prose-document-salvage.d.ts +1 -0
  872. package/dist/providers/prose-document-salvage.js +2 -0
  873. package/dist/providers/provider-disposal.d.ts +1 -0
  874. package/dist/providers/provider-disposal.js +2 -0
  875. package/dist/providers/queue.d.ts +15 -0
  876. package/dist/providers/queue.js +23 -0
  877. package/dist/providers/ramble-abort-message.d.ts +1 -0
  878. package/dist/providers/ramble-abort-message.js +2 -0
  879. package/dist/providers/ramble-detector.d.ts +1 -0
  880. package/dist/providers/ramble-detector.js +2 -0
  881. package/dist/providers/reasoning-depth.d.ts +1 -0
  882. package/dist/providers/reasoning-depth.js +2 -0
  883. package/dist/providers/required-input-reads.d.ts +1 -0
  884. package/dist/providers/required-input-reads.js +2 -0
  885. package/dist/providers/session-defaults.d.ts +13 -0
  886. package/dist/providers/session-defaults.js +49 -0
  887. package/dist/providers/session-hooks.d.ts +26 -0
  888. package/dist/providers/session-hooks.js +1 -0
  889. package/dist/providers/streaming-session.d.ts +1 -0
  890. package/dist/providers/streaming-session.js +2 -0
  891. package/dist/providers/terminal-tool-policy.d.ts +1 -0
  892. package/dist/providers/terminal-tool-policy.js +2 -0
  893. package/dist/providers/tool-arg-schema-coercion.d.ts +1 -0
  894. package/dist/providers/tool-arg-schema-coercion.js +2 -0
  895. package/dist/providers/tool-executor.d.ts +12 -0
  896. package/dist/providers/tool-executor.js +20 -0
  897. package/dist/providers/tool-failure-tracker.d.ts +1 -0
  898. package/dist/providers/tool-failure-tracker.js +2 -0
  899. package/dist/providers/tool-repeat-tracker.d.ts +1 -0
  900. package/dist/providers/tool-repeat-tracker.js +2 -0
  901. package/dist/providers/turn-timeout.d.ts +1 -0
  902. package/dist/providers/turn-timeout.js +1 -0
  903. package/dist/providers/types.d.ts +834 -0
  904. package/dist/providers/types.js +42 -0
  905. package/dist/providers/usage-builder.d.ts +1 -0
  906. package/dist/providers/usage-builder.js +2 -0
  907. package/dist/providers/vision-capability.d.ts +109 -0
  908. package/dist/providers/vision-capability.js +137 -0
  909. package/dist/python/mlx-runtime-status-bus.d.ts +39 -0
  910. package/dist/python/mlx-runtime-status-bus.js +27 -0
  911. package/dist/python/uv-runtime.d.ts +176 -0
  912. package/dist/python/uv-runtime.js +492 -0
  913. package/dist/relevance/install.d.ts +28 -0
  914. package/dist/relevance/install.js +114 -0
  915. package/dist/relevance/manager.d.ts +79 -0
  916. package/dist/relevance/manager.js +211 -0
  917. package/dist/relevance/registry.d.ts +11 -0
  918. package/dist/relevance/registry.js +158 -0
  919. package/dist/relevance/relevance-core.d.ts +67 -0
  920. package/dist/relevance/relevance-core.js +189 -0
  921. package/dist/relevance/relevance-model.d.ts +42 -0
  922. package/dist/relevance/relevance-model.js +292 -0
  923. package/dist/relevance/relevance-worker.d.ts +20 -0
  924. package/dist/relevance/relevance-worker.js +57 -0
  925. package/dist/relevance/settings.d.ts +30 -0
  926. package/dist/relevance/settings.js +81 -0
  927. package/dist/remotes/identity.d.ts +121 -0
  928. package/dist/remotes/identity.js +348 -0
  929. package/dist/remotes/pinned-fetch.d.ts +45 -0
  930. package/dist/remotes/pinned-fetch.js +193 -0
  931. package/dist/remotes/types.d.ts +54 -0
  932. package/dist/remotes/types.js +1 -0
  933. package/dist/runtime-lock.d.ts +29 -0
  934. package/dist/runtime-lock.js +85 -0
  935. package/dist/search/relevance-stage.d.ts +81 -0
  936. package/dist/search/relevance-stage.js +177 -0
  937. package/dist/secrets/types.d.ts +63 -0
  938. package/dist/secrets/types.js +64 -0
  939. package/dist/speech.d.ts +1 -0
  940. package/dist/speech.js +1 -0
  941. package/dist/system/darwin-memory.d.ts +26 -0
  942. package/dist/system/darwin-memory.js +81 -0
  943. package/dist/system/gezel-process-memory.d.ts +55 -0
  944. package/dist/system/gezel-process-memory.js +156 -0
  945. package/dist/system/memory.d.ts +154 -0
  946. package/dist/system/memory.js +501 -0
  947. package/dist/transformers-cache.d.ts +112 -0
  948. package/dist/transformers-cache.js +392 -0
  949. package/dist/utils/disk-space.d.ts +55 -0
  950. package/dist/utils/disk-space.js +72 -0
  951. package/dist/utils/download-common.d.ts +138 -0
  952. package/dist/utils/download-common.js +196 -0
  953. package/dist/utils/download-with-retry.d.ts +85 -0
  954. package/dist/utils/download-with-retry.js +522 -0
  955. package/dist/utils/extract-zip.d.ts +22 -0
  956. package/dist/utils/extract-zip.js +103 -0
  957. package/dist/utils/retire-model-worker.d.ts +15 -0
  958. package/dist/utils/retire-model-worker.js +24 -0
  959. package/dist/utils/service-worker-entry.d.ts +59 -0
  960. package/dist/utils/service-worker-entry.js +69 -0
  961. package/dist/utils/xet-download.d.ts +40 -0
  962. package/dist/utils/xet-download.js +526 -0
  963. package/dist/utils/xet.d.ts +86 -0
  964. package/dist/utils/xet.js +201 -0
  965. package/package.json +103 -3
  966. package/scripts/embedding-packaging.cjs +264 -0
  967. package/scripts/embedding-packaging.d.cts +16 -0
@@ -0,0 +1,1466 @@
1
+ /**
2
+ * NativeEngineSupervisor — lifecycle for a native engine child process
3
+ * (e.g. `sd-server`, `llama-server`).
4
+ *
5
+ * Responsibilities:
6
+ * - **Lazy start** the engine on the first `ensureRunning()` call, not
7
+ * at service boot. No VRAM is held until something actually asks
8
+ * for work.
9
+ * - **Idle timeout**: after `idleTimeoutMs` with no activity the
10
+ * engine is SIGTERM'd to free GPU/VRAM. Fresh activity lazy-starts
11
+ * again.
12
+ * - **Health watch**: every `healthIntervalMs` probe `/health`. After
13
+ * three consecutive failures the process is killed and a restart
14
+ * is attempted. Restart budget is 3 attempts in 60s, matching the
15
+ * gezeld supervisor's policy.
16
+ *
17
+ * Intentionally engine-agnostic — callers (`StableDiffusionCppProvider`,
18
+ * `LlamaCppProvider`, future STT/TTS providers) ask `ensureRunning()`
19
+ * before each request, mark activity via `markUsed()`, and otherwise
20
+ * know nothing about subprocess plumbing. Tests inject a `spawn` hook
21
+ * so we can drive the lifecycle without a real binary.
22
+ */
23
+ import { spawn as nodeSpawn } from 'node:child_process';
24
+ import { basename } from 'node:path';
25
+ import { awakeNow, createLogger } from '@bendyline/gezel';
26
+ import { listProcessSnapshots } from '@bendyline/gezel-client/node';
27
+ import { windowsHeadlessSpawnOptions } from '@bendyline/gezel/native';
28
+ import { acquireNativeCapacity, } from './device-capacity.js';
29
+ const log = createLogger('native');
30
+ /**
31
+ * Convert Electron's virtual `app.asar` paths to the real files staged by
32
+ * electron-builder under `app.asar.unpacked`. Electron patches `fs`, so an
33
+ * existence check in the main process can succeed through the virtual path,
34
+ * but the OS receives native spawn paths unchanged and rejects them with
35
+ * ENOTDIR. Normalize again at the service's final launch boundary so embedded
36
+ * mode is safe even when a pre-set env var bypassed the Electron resolver.
37
+ */
38
+ export function normalizeNativeEngineLaunch(launch) {
39
+ const redirect = (value) => value.replace(/(^|[\\/])app\.asar(?=[\\/]|$)/g, '$1app.asar.unpacked');
40
+ return {
41
+ ...launch,
42
+ command: redirect(launch.command),
43
+ args: launch.args.map(redirect),
44
+ ...(launch.cwd ? { cwd: redirect(launch.cwd) } : {}),
45
+ ...(launch.env
46
+ ? {
47
+ env: Object.fromEntries(Object.entries(launch.env).map(([key, value]) => [key, redirect(value)])),
48
+ }
49
+ : {}),
50
+ };
51
+ }
52
+ const RESTART_BUDGET = 3;
53
+ const RESTART_WINDOW_MS = 60_000;
54
+ /**
55
+ * Ceiling on `recoverStartup` retries within one start. Two covers the
56
+ * full MoE degradation ladder (partial split → all experts to RAM →
57
+ * engine-owned fit); a hook that keeps asking past that is looping.
58
+ */
59
+ const MAX_STARTUP_RECOVERIES = 2;
60
+ const HEALTH_FAIL_THRESHOLD = 3;
61
+ /**
62
+ * How often to restate that the accelerator is under pressure and this engine
63
+ * cannot do anything about it. Long, because on a card sized to one model the
64
+ * condition is ordinary and steady — the point is a trail, not an alarm.
65
+ */
66
+ const PRESSURE_HELD_LOG_INTERVAL_MS = 5 * 60_000;
67
+ const RECENT_OUTPUT_MAX_BYTES = 64 * 1024;
68
+ const EXIT_ATTRIBUTION_WAIT_MS = 250;
69
+ /**
70
+ * After SIGKILLing reaped orphans, how long to wait for them to actually leave
71
+ * the process table before spawning the replacement. SIGKILL is asynchronous
72
+ * and a model-loaded engine holding tens of GB of wired GPU memory (ds4-server
73
+ * especially) takes a beat to die. ds4-server enforces a HARD singleton, so
74
+ * spawning into a still-dying orphan races straight into its "another ds4
75
+ * process is already running; refusing to start".
76
+ */
77
+ const ORPHAN_REAP_WAIT_MS = 10_000;
78
+ /**
79
+ * Process-wide set of engine child PIDs currently owned by a LIVE
80
+ * supervisor in this daemon. The orphan reaper consults it so a freshly
81
+ * constructed supervisor never reaps a *sibling* engine that another
82
+ * live supervisor is actively driving.
83
+ *
84
+ * This is the fix for a real outage: a model switch (or any second
85
+ * engine) spins up a new supervisor whose once-per-instance orphan
86
+ * sweep matches every process sharing the engine's script path —
87
+ * including the engine still mid-agentic-turn for another session. The
88
+ * old reaper SIGKILL'd it, dropping the in-flight HTTP stream, which
89
+ * surfaced to the user as a bare "terminated". A live, owned engine is
90
+ * never an orphan: its supervisor manages its lifecycle (idle stop,
91
+ * eviction, health restart) and can drain a turn cleanly. The reaper is
92
+ * only for engines whose owner is *gone* (force-quit, OS-reaped
93
+ * Electron), which by definition aren't in this set.
94
+ *
95
+ * Shared module singleton: every supervisor in the process registers
96
+ * its child here on spawn and removes it on exit.
97
+ */
98
+ const liveEnginePids = new Set();
99
+ /** Test-only: clear the live-engine registry between cases so a pid
100
+ * registered by one test can't suppress an orphan reap in the next. */
101
+ export function __resetLiveEnginePidsForTest() {
102
+ liveEnginePids.clear();
103
+ }
104
+ export class NativeEngineSupervisor {
105
+ capacity;
106
+ capacityLease;
107
+ capacityAbort;
108
+ startFlight;
109
+ activeRequests = 0;
110
+ stopFlight;
111
+ yieldFlight;
112
+ get coordinatesCapacity() {
113
+ return this.capacity !== undefined;
114
+ }
115
+ async withRequest(run, signal) {
116
+ await this.yieldForWaitingCapacity(signal);
117
+ signal?.throwIfAborted();
118
+ this.activeRequests++;
119
+ try {
120
+ return await run();
121
+ }
122
+ finally {
123
+ this.activeRequests--;
124
+ this.markUsed();
125
+ }
126
+ }
127
+ /** Stop accepting fresh GPU work while an older memory claim needs this model to drain. */
128
+ async yieldForWaitingCapacity(signal) {
129
+ if (this.yieldFlight)
130
+ return this.yieldFlight;
131
+ if (!this.capacityLease)
132
+ return;
133
+ const flight = (async () => {
134
+ if (!(await this.capacityLease?.shouldYield()))
135
+ return;
136
+ const started = awakeNow();
137
+ while (this.engineBusy() && this.state.kind === 'running') {
138
+ signal?.throwIfAborted();
139
+ if (awakeNow() - started > 5 * 60_000)
140
+ throw new Error('Engine is busy serving requests while another model waits for memory.');
141
+ await sleep(100);
142
+ }
143
+ signal?.throwIfAborted();
144
+ if (this.state.kind !== 'running')
145
+ return;
146
+ this.onLog(`${this.logPrefix} releasing idle engine for a waiting memory request`);
147
+ await this.runFreeze();
148
+ await this.stop('memory-pressure');
149
+ })().finally(() => {
150
+ if (this.yieldFlight === flight)
151
+ this.yieldFlight = undefined;
152
+ });
153
+ this.yieldFlight = flight;
154
+ return flight;
155
+ }
156
+ state = { kind: 'stopped' };
157
+ resolveLaunch;
158
+ idleTimeoutMs;
159
+ freezeTimeoutMs;
160
+ onFreeze;
161
+ beforeStop;
162
+ beforeStopTimeoutMs;
163
+ isBusy;
164
+ memoryPressure;
165
+ pressureIdleTimeoutMs;
166
+ pressureCheckInFlight = false;
167
+ pressureDeadlineAt;
168
+ /** Awake ms at which the current unbroken stretch of pressure began. */
169
+ pressureHeldSince;
170
+ /** Awake ms of the last "still pressured, cannot act" log line. */
171
+ pressureHeldLoggedAt;
172
+ freezeTimer;
173
+ /** True once the current idle window has fired its Stage-1 freeze.
174
+ * Reset on next `markUsed` so subsequent idle windows re-fire. */
175
+ freezeFired = false;
176
+ healthIntervalMs;
177
+ startupTimeoutMs;
178
+ spawn;
179
+ fetchImpl;
180
+ onLog;
181
+ onExit;
182
+ recoverStartup;
183
+ onRawLine;
184
+ logPrefix;
185
+ readinessPath;
186
+ readyOnAnyResponse;
187
+ psRunner;
188
+ killProcess;
189
+ platform;
190
+ // Ad-hoc log listeners attached at runtime (vs. the construction-time
191
+ // `onLog` / `onRawLine` hooks). Used by the owning provider to
192
+ // subscribe to engine log lines for the duration of a single request
193
+ // — e.g. `StableDiffusionCppProvider.generate` parses sd-server's
194
+ // sampling progress from each line and republishes it as chat
195
+ // events. Listeners receive the SAME prefixed line (`[sd-server] …`)
196
+ // that `onLog` would; supervisor errors thrown from a listener are
197
+ // swallowed so a buggy parser can't take down the supervisor.
198
+ logListeners = new Set();
199
+ recentStarts = [];
200
+ lastUsedAt = 0;
201
+ /**
202
+ * The same mark on the awake clock. Every idle/pressure DECISION reads this
203
+ * one; {@link lastUsedAt} stays wall-clock because it is rendered to the
204
+ * user. A host suspension advances wall clock without giving the engine any
205
+ * time, and charging that against idleness unloaded resident models on every
206
+ * dark-wake cycle — the next turn then paid a full cold load.
207
+ */
208
+ lastUsedAwakeAt = 0;
209
+ /** PID of the engine child this supervisor currently owns, registered
210
+ * in {@link liveEnginePids} so a sibling supervisor's orphan reaper
211
+ * leaves it alone. Set on spawn, cleared on exit. */
212
+ ownedPid;
213
+ // Tracks whether we've already done the once-per-process orphan
214
+ // sweep. Reaping runs ONLY before the first spawn — during restarts
215
+ // we'd risk killing our own freshly-launched child.
216
+ didOrphanSweep = false;
217
+ // When the owning provider detects a fatal error in the child's
218
+ // stdout (e.g. MLX's `ValueError: Received N parameters not in
219
+ // model`), it calls `abortStartup(err)` to short-circuit the
220
+ // `waitForReady` poll loop — otherwise the supervisor would keep
221
+ // pinging `/health` for the full startup-timeout window even
222
+ // though the worker thread has already died. Cleared on each
223
+ // fresh start.
224
+ startupAbort = null;
225
+ idleTimer;
226
+ lastStartFailureAt;
227
+ lastStartFailure;
228
+ healthTimer;
229
+ currentStartedAt = 0;
230
+ currentPid;
231
+ /** Sticky for the current child; remains true while an expected stop moves
232
+ * state to `stopped` before the OS exit event arrives. */
233
+ currentReachedReady = false;
234
+ currentDiagnostics;
235
+ currentOutput = '';
236
+ currentPanic;
237
+ expectedExitReason;
238
+ lastExit;
239
+ exitListeners = new Set();
240
+ constructor(opts) {
241
+ this.capacity = opts.capacity;
242
+ this.resolveLaunch = opts.resolveLaunch;
243
+ // 30 min by default — aligns with `OLLAMA_TURN_TIMEOUT_MS` in chat/manager.ts,
244
+ // the accepted ceiling for a single local-engine turn. The previous 10-min
245
+ // default killed llama-server mid-stream on legitimately-long Builder
246
+ // generations (tankcombat trial: 1.7 MB streamed at T+10:27 →
247
+ // VRAM-saver fired → empty assistant message). Callers that want faster
248
+ // VRAM reclaim (sd-server idle policy, tests) pass an explicit value.
249
+ this.idleTimeoutMs = opts.idleTimeoutMs ?? 30 * 60 * 1000;
250
+ // Default freeze = half of idle when both are set. Operators get
251
+ // the staged behavior automatically without further config; legacy
252
+ // callers that pass explicit idleTimeoutMs and don't want a freeze
253
+ // can pass freezeTimeoutMs:0 to disable it explicitly.
254
+ if (opts.freezeTimeoutMs !== undefined) {
255
+ this.freezeTimeoutMs = opts.freezeTimeoutMs;
256
+ }
257
+ else {
258
+ this.freezeTimeoutMs = 0; // disabled by default
259
+ }
260
+ if (opts.onFreeze)
261
+ this.onFreeze = opts.onFreeze;
262
+ if (opts.beforeStop)
263
+ this.beforeStop = opts.beforeStop;
264
+ this.beforeStopTimeoutMs = opts.beforeStopTimeoutMs ?? 30_000;
265
+ if (opts.isBusy)
266
+ this.isBusy = opts.isBusy;
267
+ if (opts.memoryPressure)
268
+ this.memoryPressure = opts.memoryPressure;
269
+ this.pressureIdleTimeoutMs = opts.pressureIdleTimeoutMs ?? 60_000;
270
+ this.healthIntervalMs = opts.healthIntervalMs ?? 15_000;
271
+ this.startupTimeoutMs = opts.startupTimeoutMs ?? 60_000;
272
+ this.spawn = opts.spawn ?? nodeSpawn;
273
+ this.fetchImpl = opts.fetchImpl ?? fetch;
274
+ this.onLog = opts.onLog ?? ((line) => log.info(line));
275
+ if (opts.onExit)
276
+ this.onExit = opts.onExit;
277
+ if (opts.recoverStartup)
278
+ this.recoverStartup = opts.recoverStartup;
279
+ if (opts.onRawLine)
280
+ this.onRawLine = opts.onRawLine;
281
+ this.logPrefix = opts.logPrefix ?? '[native]';
282
+ this.readinessPath = opts.readinessPath ?? '/health';
283
+ this.readyOnAnyResponse = opts.readyOnAnyResponse ?? false;
284
+ this.platform = opts.platform ?? process.platform;
285
+ this.psRunner = opts.psRunner ?? (() => defaultPsRunner(this.platform));
286
+ this.killProcess = opts.killProcess ?? ((pid, sig) => process.kill(pid, sig));
287
+ }
288
+ /** URL the provider should hit. Only meaningful while running. */
289
+ currentBaseUrl() {
290
+ if (this.state.kind === 'running' || this.state.kind === 'starting') {
291
+ return this.state.launch.baseUrl;
292
+ }
293
+ return undefined;
294
+ }
295
+ /**
296
+ * PID of the supervised child when running. Used by providers that
297
+ * want to poll the child's resource usage (e.g. resident-set size
298
+ * for an "engine memory" telemetry event) — the supervisor owns
299
+ * the lifetime of the pid, so consumers don't have to track
300
+ * restarts themselves.
301
+ */
302
+ currentChildPid() {
303
+ if (this.state.kind === 'running' || this.state.kind === 'starting') {
304
+ return this.state.child.pid ?? undefined;
305
+ }
306
+ return undefined;
307
+ }
308
+ /** Stable status shape for the engine pool and once-a-second memory UI. */
309
+ lifecycleSnapshot() {
310
+ const running = this.state.kind === 'running' || this.state.kind === 'starting';
311
+ const active = running && this.engineBusy();
312
+ const idleDeadline = running && !active && this.lastUsedAwakeAt > 0 && this.idleTimeoutMs > 0
313
+ ? this.wallClockFor(this.lastUsedAwakeAt + this.idleTimeoutMs)
314
+ : null;
315
+ const pressureDeadline = running && !active && this.pressureDeadlineAt !== undefined
316
+ ? this.wallClockFor(this.pressureDeadlineAt)
317
+ : null;
318
+ const usePressure = pressureDeadline !== null && (idleDeadline === null || pressureDeadline < idleDeadline);
319
+ const pid = this.currentChildPid();
320
+ return {
321
+ running,
322
+ active,
323
+ ...(pid !== undefined ? { pid } : {}),
324
+ lastUsedAt: this.lastUsedAt > 0 ? this.lastUsedAt : null,
325
+ unloadAt: usePressure ? pressureDeadline : idleDeadline,
326
+ idleTimeoutMs: this.idleTimeoutMs,
327
+ releaseReason: usePressure ? 'memory-pressure' : idleDeadline !== null ? 'idle' : null,
328
+ ...(this.lastStartFailureAt !== undefined
329
+ ? {
330
+ startFailedAt: this.lastStartFailureAt,
331
+ ...(this.lastStartFailure ? { startFailure: this.lastStartFailure } : {}),
332
+ }
333
+ : {}),
334
+ };
335
+ }
336
+ /** Most recently sealed child exit, including expected idle/shutdown exits. */
337
+ lastExitSnapshot() {
338
+ return this.lastExit
339
+ ? {
340
+ ...this.lastExit,
341
+ ...(this.lastExit.diagnostics ? { diagnostics: { ...this.lastExit.diagnostics } } : {}),
342
+ }
343
+ : undefined;
344
+ }
345
+ /**
346
+ * Launch provenance of the LIVE child: pid, start time, and the
347
+ * request-independent launch facts the spawner attached (granted context
348
+ * window, slots, KV dtype, backend — the payload behind the
349
+ * `launch {...}` log line). Undefined when no child is up, so callers
350
+ * (Settings → About, `/api/system/diagnostics`) never show a stale grant
351
+ * for an engine that already exited.
352
+ */
353
+ launchSnapshot() {
354
+ if (this.state.kind !== 'running' && this.state.kind !== 'starting')
355
+ return undefined;
356
+ const pid = this.currentChildPid();
357
+ return {
358
+ ...(pid !== undefined ? { pid } : {}),
359
+ startedAt: this.currentStartedAt,
360
+ ...(this.currentDiagnostics ? { diagnostics: { ...this.currentDiagnostics } } : {}),
361
+ };
362
+ }
363
+ /**
364
+ * Wait briefly for an unexpected exit attributable to a request that began
365
+ * at `sinceMs`. Fetch/stream teardown can race Node's child `exit` event by
366
+ * a few milliseconds; this bounded wait prevents CUDA SIGABRTs from being
367
+ * flattened into a generic undici "terminated" error.
368
+ */
369
+ async waitForUnexpectedExitSince(sinceMs, timeoutMs = EXIT_ATTRIBUTION_WAIT_MS) {
370
+ const matches = (snapshot) => !snapshot.expected && snapshot.exitedAt >= sinceMs;
371
+ if (this.lastExit && matches(this.lastExit))
372
+ return { ...this.lastExit };
373
+ if (timeoutMs <= 0)
374
+ return undefined;
375
+ return await new Promise((resolve) => {
376
+ const listener = (snapshot) => {
377
+ if (!matches(snapshot))
378
+ return;
379
+ clearTimeout(timer);
380
+ this.exitListeners.delete(listener);
381
+ resolve({ ...snapshot });
382
+ };
383
+ this.exitListeners.add(listener);
384
+ const timer = setTimeout(() => {
385
+ this.exitListeners.delete(listener);
386
+ resolve(undefined);
387
+ }, timeoutMs);
388
+ timer.unref?.();
389
+ });
390
+ }
391
+ /**
392
+ * Ensure the engine is running and reachable. If it's stopped, spawn
393
+ * it; if it's starting, await the in-flight readiness probe; if it's
394
+ * already running, no-op. Rejects if the restart budget is exhausted.
395
+ */
396
+ async ensureRunning() {
397
+ if (this.stopFlight)
398
+ await this.stopFlight;
399
+ this.lastUsedAt = Date.now();
400
+ this.lastUsedAwakeAt = awakeNow();
401
+ this.pressureDeadlineAt = undefined;
402
+ if (this.startFlight)
403
+ await this.startFlight;
404
+ if (this.state.kind === 'running') {
405
+ this.resetIdleTimer();
406
+ return this.state.launch;
407
+ }
408
+ if (this.state.kind === 'starting') {
409
+ await this.state.readyPromise;
410
+ const current = this.state;
411
+ if (current.kind === 'running')
412
+ return current.launch;
413
+ throw new Error(`${this.logPrefix} failed to start`);
414
+ }
415
+ if (this.state.kind === 'restart-budget-exhausted') {
416
+ if (Date.now() - this.state.at < RESTART_WINDOW_MS) {
417
+ throw new Error(`${this.logPrefix} failed repeatedly. Wait a minute and try again, or check logs in Settings.`);
418
+ }
419
+ this.recentStarts = [];
420
+ this.state = { kind: 'stopped' };
421
+ }
422
+ await this.startFresh();
423
+ const current = this.state;
424
+ if (current.kind === 'running')
425
+ return current.launch;
426
+ throw new Error(`${this.logPrefix} did not reach running state`);
427
+ }
428
+ /**
429
+ * Attach a transient log listener that receives every prefixed
430
+ * stdout/stderr line (`[sd-server] …`) for the duration of the
431
+ * returned unsubscribe call. Used by the owning provider to parse
432
+ * engine progress for a single in-flight request — e.g. sd-server's
433
+ * `|==> | 3/20 - 18.20s/it` sampling lines — and translate them
434
+ * into structured progress events for the UI.
435
+ *
436
+ * Listeners are independent of `onLog` / `onRawLine` (which are
437
+ * construction-time hooks for log routing + classification). Adding
438
+ * one does not suppress either.
439
+ */
440
+ subscribeLogLines(listener) {
441
+ this.logListeners.add(listener);
442
+ return () => {
443
+ this.logListeners.delete(listener);
444
+ };
445
+ }
446
+ /** Update the last-used clock without triggering a start. */
447
+ markUsed() {
448
+ this.lastUsedAt = Date.now();
449
+ this.lastUsedAwakeAt = awakeNow();
450
+ this.pressureDeadlineAt = undefined;
451
+ this.resetIdleTimer();
452
+ if (this.capacityLease)
453
+ void this.pressureProbe();
454
+ }
455
+ async stop(reason = 'stop') {
456
+ if (this.stopFlight)
457
+ return this.stopFlight;
458
+ const flight = this.stopChild(reason).finally(() => {
459
+ if (this.stopFlight === flight)
460
+ this.stopFlight = undefined;
461
+ });
462
+ this.stopFlight = flight;
463
+ return flight;
464
+ }
465
+ async stopChild(reason) {
466
+ this.capacityAbort?.abort(new Error(`${this.logPrefix} engine start cancelled`));
467
+ this.startupAbort?.abort(new Error(`${this.logPrefix} engine start cancelled`));
468
+ await this.startFlight?.catch(() => { });
469
+ this.clearIdleTimer();
470
+ this.clearFreezeTimer();
471
+ this.clearHealthTimer();
472
+ if (this.state.kind === 'stopped' || this.state.kind === 'restart-budget-exhausted')
473
+ return;
474
+ const { child } = this.state;
475
+ if (this.state.kind === 'running' && reason !== 'health-restart') {
476
+ await this.runBeforeStop(reason, this.state.launch.baseUrl);
477
+ }
478
+ this.pressureDeadlineAt = undefined;
479
+ this.expectedExitReason = reason;
480
+ this.state = { kind: 'stopped' };
481
+ await killGracefully(child);
482
+ }
483
+ async runBeforeStop(reason, baseUrl) {
484
+ if (!this.beforeStop)
485
+ return;
486
+ const started = Date.now();
487
+ let timer;
488
+ try {
489
+ await Promise.race([
490
+ Promise.resolve(this.beforeStop({ reason, baseUrl })),
491
+ new Promise((resolve) => {
492
+ timer = setTimeout(() => {
493
+ this.onLog(`${this.logPrefix} pre-stop hook still running after ${this.beforeStopTimeoutMs}ms — stopping anyway`);
494
+ resolve();
495
+ }, this.beforeStopTimeoutMs);
496
+ timer.unref?.();
497
+ }),
498
+ ]);
499
+ this.onLog(`${this.logPrefix} pre-stop hook done in ${Date.now() - started}ms (${reason})`);
500
+ }
501
+ catch (err) {
502
+ this.onLog(`${this.logPrefix} pre-stop hook failed (${reason}): ${err instanceof Error ? err.message : String(err)}`);
503
+ }
504
+ finally {
505
+ if (timer)
506
+ clearTimeout(timer);
507
+ }
508
+ }
509
+ async startFresh() {
510
+ if (this.startFlight)
511
+ return this.startFlight;
512
+ this.capacityAbort = new AbortController();
513
+ const flight = this.startFreshAttempt()
514
+ .then((result) => {
515
+ this.lastStartFailureAt = undefined;
516
+ this.lastStartFailure = undefined;
517
+ return result;
518
+ })
519
+ .catch((err) => {
520
+ this.lastStartFailureAt = Date.now();
521
+ this.lastStartFailure = err instanceof Error ? err.message : String(err);
522
+ throw err;
523
+ })
524
+ .finally(() => {
525
+ if (this.startFlight === flight)
526
+ this.startFlight = undefined;
527
+ this.capacityAbort = undefined;
528
+ });
529
+ this.startFlight = flight;
530
+ return flight;
531
+ }
532
+ async startFreshAttempt(isRetry = false, recoveryAttempt = 0) {
533
+ const now = Date.now();
534
+ this.recentStarts = this.recentStarts.filter((t) => now - t < RESTART_WINDOW_MS);
535
+ if (this.recentStarts.length >= RESTART_BUDGET) {
536
+ this.state = { kind: 'restart-budget-exhausted', at: now };
537
+ throw new Error(`${this.logPrefix} crashed too many times; stopping restart attempts for a minute`);
538
+ }
539
+ const launch = normalizeNativeEngineLaunch(await this.resolveLaunch());
540
+ // First spawn of this process? Sweep up any matching orphans from
541
+ // previous app launches that didn't get a chance to clean up
542
+ // (force-quit, OS reaped Electron, before-quit handler crashed,
543
+ // etc.). Match is anchored on the binary path so we don't touch
544
+ // unrelated processes; restarts skip the sweep so we don't shoot
545
+ // our own foot.
546
+ if (!this.didOrphanSweep) {
547
+ this.didOrphanSweep = true;
548
+ await this.reapOrphansMatching(launch).catch((err) => {
549
+ this.onLog(`${this.logPrefix} orphan sweep failed (continuing): ${err instanceof Error ? err.message : err}`);
550
+ });
551
+ }
552
+ this.capacityAbort?.signal.throwIfAborted();
553
+ if (this.capacity) {
554
+ this.capacityLease = await acquireNativeCapacity(this.capacity, launch, this.capacityAbort.signal, (message) => {
555
+ const line = `${this.logPrefix} memory-admission: ${message}`;
556
+ this.onLog(line);
557
+ try {
558
+ this.onRawLine?.(line);
559
+ }
560
+ catch {
561
+ /* progress cannot abort admission */
562
+ }
563
+ for (const listener of this.logListeners) {
564
+ try {
565
+ listener(line);
566
+ }
567
+ catch {
568
+ /* progress cannot abort admission */
569
+ }
570
+ }
571
+ });
572
+ }
573
+ this.recentStarts.push(Date.now());
574
+ let child;
575
+ try {
576
+ child = this.spawn(launch.command, launch.args, {
577
+ env: { ...process.env, ...(launch.env ?? {}) },
578
+ ...(launch.cwd ? { cwd: launch.cwd } : {}),
579
+ stdio: ['ignore', 'pipe', 'pipe'],
580
+ // The supervisor owns this engine for its entire lifetime. Keep the
581
+ // Windows console hidden without detaching the process from its
582
+ // owner; detachment is what surfaces a new terminal window.
583
+ ...windowsHeadlessSpawnOptions(),
584
+ });
585
+ }
586
+ catch (err) {
587
+ await this.releaseCapacity();
588
+ throw nativeSpawnError(this.logPrefix, launch, err);
589
+ }
590
+ // Register the child as a live, owned engine so no sibling
591
+ // supervisor's orphan reaper can SIGKILL it mid-turn. Cleared in
592
+ // handleExit. `pid` is undefined only if the spawn itself failed —
593
+ // handleExit will fire and tear the state down regardless.
594
+ this.ownedPid = typeof child.pid === 'number' ? child.pid : undefined;
595
+ if (this.ownedPid !== undefined)
596
+ liveEnginePids.add(this.ownedPid);
597
+ this.currentStartedAt = Date.now();
598
+ this.currentPid = typeof child.pid === 'number' ? child.pid : undefined;
599
+ this.currentReachedReady = false;
600
+ this.currentDiagnostics = launch.diagnostics ? { ...launch.diagnostics } : undefined;
601
+ this.currentOutput = '';
602
+ this.currentPanic = undefined;
603
+ this.expectedExitReason = undefined;
604
+ this.onLog(`${this.logPrefix} launch ${JSON.stringify({
605
+ pid: this.currentPid ?? null,
606
+ command: basename(launch.command),
607
+ ...(this.currentDiagnostics ?? {}),
608
+ })}`);
609
+ const emitLine = (line) => {
610
+ if (!line)
611
+ return;
612
+ const prefixed = `${this.logPrefix} ${line}`;
613
+ this.appendRecentOutput(prefixed);
614
+ this.onLog(prefixed);
615
+ if (this.onRawLine) {
616
+ try {
617
+ this.onRawLine(prefixed);
618
+ }
619
+ catch (err) {
620
+ // Never let a bad classifier take down the supervisor.
621
+ log.warn(`${this.logPrefix} onRawLine threw: ${err instanceof Error ? err.message : err}`);
622
+ }
623
+ }
624
+ if (this.logListeners.size > 0) {
625
+ for (const listener of this.logListeners) {
626
+ try {
627
+ listener(prefixed);
628
+ }
629
+ catch (err) {
630
+ log.warn(`${this.logPrefix} log listener threw: ${err instanceof Error ? err.message : err}`);
631
+ }
632
+ }
633
+ }
634
+ };
635
+ const chunkReader = () => {
636
+ let pending = '';
637
+ const onChunk = (buf) => {
638
+ const text = pending + buf.toString();
639
+ // Split on CR *and* LF so the optional line classifier sees one
640
+ // logical record at a time. Most engines emit line-buffered
641
+ // output (\n), but tqdm-style progress bars — notably mlx's
642
+ // chunked-prefill `Prefill: NN%|…` meter — repaint a single line
643
+ // in place with a bare `\r` and emit no `\n` until the bar hits
644
+ // 100%. Splitting on `\n` alone buffers the entire prefill arc
645
+ // into one unterminated record that only flushes at completion,
646
+ // so the classifier never sees per-step progress and the mlx
647
+ // idle watchdog kills the turn mid-prefill (it never gets the
648
+ // progress events that reset its per-chunk budget). Treating each
649
+ // `\r` repaint as its own line lets progress flow. A partial
650
+ // final line is retained across chunks and flushed on process exit.
651
+ const lines = text.split(/\r\n?|\n/);
652
+ pending = lines.pop() ?? '';
653
+ for (const line of lines)
654
+ emitLine(line);
655
+ };
656
+ return {
657
+ onChunk,
658
+ flush: () => {
659
+ if (pending)
660
+ emitLine(pending);
661
+ pending = '';
662
+ },
663
+ };
664
+ };
665
+ const stdout = chunkReader();
666
+ const stderr = chunkReader();
667
+ this.startupAbort = new AbortController();
668
+ let spawnFailed = false;
669
+ child.stdout?.on('data', stdout.onChunk);
670
+ child.stderr?.on('data', stderr.onChunk);
671
+ child.on('exit', (code, signal) => {
672
+ stdout.flush();
673
+ stderr.flush();
674
+ this.handleExit(code, signal);
675
+ });
676
+ // `child_process.spawn` reports missing/non-traversable executables through
677
+ // the child's `error` event on most Node/platform combinations. Without a
678
+ // listener this can escape as an opaque process-level exception; abort the
679
+ // readiness wait with the same actionable detail as a synchronous throw.
680
+ child.once('error', (err) => {
681
+ spawnFailed = true;
682
+ this.startupAbort?.abort(nativeSpawnError(this.logPrefix, launch, err));
683
+ });
684
+ const readyPromise = this.waitForReady(launch, this.startupAbort.signal);
685
+ this.state = { kind: 'starting', launch, child, readyPromise };
686
+ try {
687
+ const lease = this.capacityLease;
688
+ await Promise.all([
689
+ readyPromise,
690
+ child.pid !== undefined ? lease?.bind(child.pid) : Promise.resolve(),
691
+ ]);
692
+ await lease?.ready();
693
+ this.startupAbort?.signal.throwIfAborted();
694
+ this.capacityAbort?.signal.throwIfAborted();
695
+ if (child.exitCode !== null || child.signalCode !== null)
696
+ throw new Error(`${this.logPrefix} child exited before becoming ready`);
697
+ this.currentReachedReady = true;
698
+ this.state = { kind: 'running', launch, child, healthFails: 0 };
699
+ this.resetIdleTimer();
700
+ this.startHealthWatch();
701
+ }
702
+ catch (err) {
703
+ // The panic classifier state is cleared by handleExit — read it now,
704
+ // before killGracefully drives the exit, so the recovery hook below
705
+ // sees the fatal line however the failure was surfaced (stdout abort
706
+ // vs. child death vs. readiness timeout). Cast because TS narrows the
707
+ // field to `undefined` from the pre-spawn reset above and cannot see
708
+ // the stdout-callback writes in between.
709
+ const panicAtFailure = this.currentPanic;
710
+ const attemptStartedAt = this.currentStartedAt;
711
+ // A child that failed before the OS assigned a pid cannot be signalled
712
+ // and may never emit `exit`; waiting for killGracefully would wedge the
713
+ // chat turn while reporting the original spawn failure.
714
+ if (!spawnFailed) {
715
+ this.expectedExitReason ??= 'startup-abort';
716
+ await killGracefully(child);
717
+ }
718
+ await this.releaseCapacity();
719
+ this.state = { kind: 'stopped' };
720
+ // Singleton-conflict recovery: a hard-singleton engine (ds4-server)
721
+ // refuses to start while an owner-less orphan from a prior launch still
722
+ // holds the lock, surfaced as "child exited ... before becoming ready".
723
+ // On the first such failure, sweep orphans again — the first-spawn sweep
724
+ // may have raced one, or this is a RESTART (which skips the sweep) and the
725
+ // engine's own prior child lingered. Only retry if the sweep actually
726
+ // cleared a blocking process; a failure with nothing to clear is a real
727
+ // startup error (bad model, OOM), not a lock conflict, so don't burn a
728
+ // retry on it. `isRetry` caps recovery at a single extra attempt.
729
+ if (!isRetry && err instanceof Error && err.message.includes('before becoming ready')) {
730
+ const cleared = await this.reapOrphansMatching(launch).catch(() => 0);
731
+ if (cleared > 0) {
732
+ this.onLog(`${this.logPrefix} cleared ${cleared} blocking orphan(s) after a failed start — retrying once`);
733
+ this.startupAbort = null;
734
+ return await this.startFreshAttempt(true, recoveryAttempt);
735
+ }
736
+ }
737
+ // Owner-driven recovery: give the launch resolver a chance to degrade
738
+ // its plan (the MoE offload ladder after a GPU OOM) and try again.
739
+ // Spawn failures are excluded — a missing binary cannot be planned
740
+ // around, and the child never produced a diagnosable panic.
741
+ if (!spawnFailed && this.recoverStartup && recoveryAttempt < MAX_STARTUP_RECOVERIES) {
742
+ const exit = this.lastExit;
743
+ const panicKind = panicAtFailure?.kind ??
744
+ (exit && exit.exitedAt >= attemptStartedAt ? exit.panicKind : undefined);
745
+ let retry = false;
746
+ try {
747
+ retry = await this.recoverStartup({ panicKind, attempt: recoveryAttempt });
748
+ }
749
+ catch (hookErr) {
750
+ this.onLog(`${this.logPrefix} recoverStartup hook threw (not retrying): ${hookErr instanceof Error ? hookErr.message : hookErr}`);
751
+ }
752
+ if (retry) {
753
+ this.onLog(`${this.logPrefix} start failed (${panicKind ?? 'no panic classified'}) — owner degraded the launch plan, retrying (${recoveryAttempt + 1}/${MAX_STARTUP_RECOVERIES})`);
754
+ this.startupAbort = null;
755
+ return await this.startFreshAttempt(isRetry, recoveryAttempt + 1);
756
+ }
757
+ }
758
+ throw err;
759
+ }
760
+ finally {
761
+ this.startupAbort = null;
762
+ }
763
+ }
764
+ /**
765
+ * Abort an in-flight `startFresh` with a concrete error. Called by
766
+ * the owning provider when the child's stdout reveals a fatal
767
+ * condition (model-arch mismatch, OOM, missing dependency) that
768
+ * won't resolve by waiting longer — without this, the `waitForReady`
769
+ * poll would keep hitting `/health` for the full startup-timeout
770
+ * window even though the worker thread has already died.
771
+ */
772
+ abortStartup(err) {
773
+ const ac = this.startupAbort;
774
+ if (!ac)
775
+ return;
776
+ ac.abort(err);
777
+ }
778
+ /**
779
+ * Find and SIGKILL any owner-less engine process from a prior gezel
780
+ * launch that matches this engine. Best-effort: any error during the
781
+ * sweep is logged and swallowed so the spawn-on-startup path never
782
+ * aborts because of cleanup.
783
+ *
784
+ * Crucially, a process whose parent is still alive is NOT an orphan and
785
+ * is skipped. The process-local {@link liveEnginePids} registry protects
786
+ * sibling supervisors inside this daemon; the PPID check protects engines
787
+ * owned by a different live gezeld process/home. This matters for two
788
+ * concurrent isolated eval daemons: each uses the same engine binary, so a
789
+ * command-path-only sweep would otherwise SIGKILL the other's in-flight
790
+ * child and surface a bare `terminated` fetch error.
791
+ *
792
+ * Match strategy — anchor on every install-specific absolute path we
793
+ * can find in the launch spec, then check whether each `ps` row
794
+ * contains any of them:
795
+ *
796
+ * 1. `launch.command` — works directly when the binary is
797
+ * install-specific (llama-server, sd-server: a path under
798
+ * `~/.gezel/native/bin/`).
799
+ * 2. Any absolute-path argument that looks like a script or
800
+ * executable (`*.py`, `*.js`, etc.). For Python engines this is
801
+ * the case that *actually* fires: `launch.command` is the venv's
802
+ * `bin/python`, but that's typically a symlink chain to the
803
+ * system framework Python (e.g. `/Library/Frameworks/Python.../
804
+ * MacOS/Python`) — and macOS `ps` reports the resolved path, so
805
+ * the binary-path match never hits. The script path
806
+ * (`gezel_mlx_server.py` under the dist folder) appears verbatim
807
+ * in the ps command line and is unique to this install.
808
+ *
809
+ * `didOrphanSweep` gates this to one execution per supervisor instance
810
+ * (so we don't re-sweep on our own restarts). A real orphan is reparented
811
+ * to launchd/systemd (PPID 1) after its daemon exits. Any matching child
812
+ * with PPID > 1 still has a live owner and is conservatively left alone.
813
+ * Injected legacy `psRunner` rows may omit PPID and retain the historical
814
+ * match behavior; the production runner always includes it.
815
+ *
816
+ * macOS + Linux use `ps -axo pid=,ppid=,command=`. Windows uses the
817
+ * Win32_Process CIM snapshot; because Windows retains a dead creator's pid
818
+ * instead of reparenting to pid 1, absence of that ppid proves orphanhood.
819
+ */
820
+ async reapOrphansMatching(launch) {
821
+ const anchors = this.buildOrphanAnchors(launch);
822
+ if (anchors.command.length === 0 && anchors.args.length === 0)
823
+ return 0;
824
+ const procs = await this.psRunner();
825
+ const livePids = new Set(procs.map(({ pid }) => pid));
826
+ const normalizedCommandAnchors = anchors.command.map((anchor) => normalizeProcessMatch(anchor, this.platform));
827
+ const normalizedArgAnchors = anchors.args.map((anchor) => normalizeProcessMatch(anchor, this.platform));
828
+ const ourPid = process.pid;
829
+ const targets = [];
830
+ for (const { pid, ppid, command } of procs) {
831
+ if (pid === ourPid)
832
+ continue;
833
+ // Never reap an engine a live supervisor in this process owns —
834
+ // it may be mid-turn for another session. Only owner-less orphans
835
+ // (force-quit / OS-reaped prior launches) are ours to clean up.
836
+ if (liveEnginePids.has(pid))
837
+ continue;
838
+ // Cross-daemon ownership: command-path matching alone cannot
839
+ // distinguish isolated homes that share a native binary. Unix reparents
840
+ // a true orphan to pid 1. Windows leaves the creator pid on the child,
841
+ // so it is an orphan only when that pid is absent from this same atomic-
842
+ // enough snapshot. PID reuse can cause a conservative false negative,
843
+ // never a live-process kill. Missing PPID preserves legacy test seams.
844
+ if (ppid !== undefined && !isOwnerlessProcess(ppid, livePids, this.platform))
845
+ continue;
846
+ const normalizedCommand = normalizeProcessMatch(command, this.platform);
847
+ const matched = normalizedCommandAnchors.some((anchor) => normalizedCommand === anchor ||
848
+ normalizedCommand.startsWith(`${anchor} `) ||
849
+ normalizedCommand.startsWith(`"${anchor}"`)) || normalizedArgAnchors.some((anchor) => normalizedCommand.includes(anchor));
850
+ if (!matched)
851
+ continue;
852
+ targets.push(pid);
853
+ }
854
+ if (targets.length === 0)
855
+ return 0;
856
+ this.onLog(`${this.logPrefix} reaping ${targets.length} orphan(s) from prior app launches: ${targets.join(', ')}`);
857
+ for (const pid of targets) {
858
+ try {
859
+ this.killProcess(pid, 'SIGKILL');
860
+ }
861
+ catch (err) {
862
+ // Already dead, or not ours to kill — either way, ignore.
863
+ this.onLog(`${this.logPrefix} reap pid=${pid} failed (ignored): ${err instanceof Error ? err.message : err}`);
864
+ }
865
+ }
866
+ // SIGKILL only *requests* termination — block until the reaped pids are
867
+ // actually gone, so a hard-singleton engine isn't spawned while a just-
868
+ // killed orphan still holds the lock. Without this wait the new ds4-server
869
+ // saw the dying orphan and refused to start (the trial then stalled).
870
+ await this.waitForPidsGone(targets, ORPHAN_REAP_WAIT_MS);
871
+ return targets.length;
872
+ }
873
+ /**
874
+ * Poll the process table until none of `pids` remain, or `timeoutMs`
875
+ * elapses. Best-effort: a still-present pid after the timeout is logged (the
876
+ * subsequent spawn may then fail a singleton check, surfaced normally) rather
877
+ * than thrown, so cleanup never wedges startup.
878
+ */
879
+ async waitForPidsGone(pids, timeoutMs) {
880
+ if (pids.length === 0)
881
+ return;
882
+ const deadline = Date.now() + timeoutMs;
883
+ let remaining = pids;
884
+ while (remaining.length > 0 && Date.now() < deadline) {
885
+ await sleep(150);
886
+ const alive = new Set((await this.psRunner()).map((p) => p.pid));
887
+ remaining = remaining.filter((pid) => alive.has(pid));
888
+ }
889
+ if (remaining.length > 0) {
890
+ this.onLog(`${this.logPrefix} reaped orphan(s) still present after ${timeoutMs}ms: ${remaining.join(', ')} — spawn may hit the engine's singleton guard`);
891
+ }
892
+ }
893
+ /**
894
+ * Pull every install-specific absolute path out of the launch spec.
895
+ * Used by the orphan reaper to match against `ps` output. The
896
+ * filtering is deliberately conservative: only paths that look like a
897
+ * concrete file (have an extension) qualify, so flag values like
898
+ * `--port 12345` or directory paths passed via `--model` don't get
899
+ * promoted to anchors. Absolute model dirs would still be
900
+ * install-specific in practice, but matching on a directory path
901
+ * could collide with any tool that happens to have it on its command
902
+ * line (e.g. a `du -sh` invocation), so we leave them out.
903
+ */
904
+ buildOrphanAnchors(launch) {
905
+ const command = [];
906
+ const args = [];
907
+ const seen = new Set();
908
+ const add = (bucket, p) => {
909
+ if (!p || seen.has(p))
910
+ return;
911
+ seen.add(p);
912
+ bucket.push(p);
913
+ };
914
+ if (isAbsoluteProcessPath(launch.command))
915
+ add(command, launch.command);
916
+ for (const arg of launch.args) {
917
+ if (!isAbsoluteProcessPath(arg))
918
+ continue;
919
+ // File-shaped: ends with a dot-extension whose tail contains at
920
+ // least one letter (`gezel_mlx_server.py`, `model.bin`). Skips
921
+ // bare directory paths (`/Users/me/.gezel/.../models/qwen3.6`),
922
+ // including ones whose final segment looks like a version
923
+ // number — `.6`, `1.0.0`, `3.14` would all sneak through a
924
+ // letter-or-digit regex but none describe a real file extension.
925
+ if (!/\.[A-Za-z0-9]*[A-Za-z][A-Za-z0-9]{0,7}$/.test(arg))
926
+ continue;
927
+ add(args, arg);
928
+ }
929
+ return { command, args };
930
+ }
931
+ async waitForReady(launch, signal) {
932
+ const deadline = Date.now() + this.startupTimeoutMs;
933
+ let lastError;
934
+ while (Date.now() < deadline) {
935
+ if (signal.aborted) {
936
+ throw signal.reason instanceof Error
937
+ ? signal.reason
938
+ : new Error(`${this.logPrefix} startup aborted`);
939
+ }
940
+ try {
941
+ const res = await this.fetchImpl(`${launch.baseUrl}${this.readinessPath}`, { signal });
942
+ if (res.ok || this.readyOnAnyResponse) {
943
+ // For engines without a dedicated health endpoint, returning
944
+ // any HTTP status proves the port is open and accepting work
945
+ // — that's the readiness signal we care about. Drain the body
946
+ // so the connection isn't left half-open.
947
+ void res.body?.cancel?.().catch(() => { });
948
+ return;
949
+ }
950
+ lastError = new Error(`${this.readinessPath} returned ${res.status}`);
951
+ }
952
+ catch (err) {
953
+ if (signal.aborted) {
954
+ throw signal.reason instanceof Error
955
+ ? signal.reason
956
+ : new Error(`${this.logPrefix} startup aborted`);
957
+ }
958
+ lastError = err;
959
+ }
960
+ await new Promise((resolve, reject) => {
961
+ const t = setTimeout(resolve, 500);
962
+ const onAbort = () => {
963
+ clearTimeout(t);
964
+ reject(signal.reason instanceof Error ? signal.reason : new Error('startup aborted'));
965
+ };
966
+ if (signal.aborted)
967
+ onAbort();
968
+ else
969
+ signal.addEventListener('abort', onAbort, { once: true });
970
+ });
971
+ }
972
+ throw new Error(`${this.logPrefix} did not become ready within ${this.startupTimeoutMs / 1000}s: ${lastError instanceof Error ? lastError.message : String(lastError)}`);
973
+ }
974
+ appendRecentOutput(line) {
975
+ this.currentOutput += `${line}\n`;
976
+ const bytes = Buffer.byteLength(this.currentOutput, 'utf8');
977
+ if (bytes > RECENT_OUTPUT_MAX_BYTES) {
978
+ const trimmed = Buffer.from(this.currentOutput, 'utf8')
979
+ .subarray(bytes - RECENT_OUTPUT_MAX_BYTES)
980
+ .toString('utf8');
981
+ const firstNewline = trimmed.indexOf('\n');
982
+ this.currentOutput = firstNewline >= 0 ? trimmed.slice(firstNewline + 1) : trimmed;
983
+ }
984
+ const panic = classifyNativeEnginePanic(line);
985
+ if (panic &&
986
+ (!this.currentPanic || panicPriority(panic.kind) >= panicPriority(this.currentPanic.kind))) {
987
+ this.currentPanic = panic;
988
+ }
989
+ }
990
+ handleExit(code, signal) {
991
+ void this.releaseCapacity();
992
+ const priorState = this.state;
993
+ const exitedAt = Date.now();
994
+ const expectedReason = this.expectedExitReason;
995
+ const expected = priorState.kind === 'stopped' || expectedReason !== undefined;
996
+ const pid = this.currentPid;
997
+ // A SIGILL is a classification in its own right. Only claim it when
998
+ // the output didn't already explain the death more precisely: an
999
+ // engine that printed `CUDA error: …` and then took SIGILL on the
1000
+ // way down is a CUDA fault, not an unrunnable build.
1001
+ const panic = this.currentPanic ??
1002
+ (signal === 'SIGILL'
1003
+ ? {
1004
+ kind: 'illegal-instruction',
1005
+ line: 'engine terminated by SIGILL (illegal instruction) with no diagnostic output',
1006
+ }
1007
+ : undefined);
1008
+ const snapshot = {
1009
+ incidentId: `native-${pid ?? 'unknown'}-${exitedAt}`,
1010
+ ...(pid !== undefined ? { pid } : {}),
1011
+ startedAt: this.currentStartedAt || exitedAt,
1012
+ exitedAt,
1013
+ uptimeMs: Math.max(0, exitedAt - (this.currentStartedAt || exitedAt)),
1014
+ code,
1015
+ signal,
1016
+ expected,
1017
+ reachedReady: this.currentReachedReady,
1018
+ ...(expectedReason ? { expectedReason } : {}),
1019
+ ...(panic ? { panicKind: panic.kind, panicLine: panic.line } : {}),
1020
+ outputTail: this.currentOutput,
1021
+ ...(this.currentDiagnostics ? { diagnostics: { ...this.currentDiagnostics } } : {}),
1022
+ };
1023
+ this.lastExit = snapshot;
1024
+ this.onLog(`${this.logPrefix} exit ${JSON.stringify({
1025
+ incidentId: snapshot.incidentId,
1026
+ pid: snapshot.pid ?? null,
1027
+ code,
1028
+ signal: signal ?? null,
1029
+ expected,
1030
+ ...(expectedReason ? { expectedReason } : {}),
1031
+ uptimeMs: snapshot.uptimeMs,
1032
+ reachedReady: snapshot.reachedReady,
1033
+ ...(snapshot.panicKind ? { panicKind: snapshot.panicKind } : {}),
1034
+ ...(snapshot.panicLine ? { panicLine: snapshot.panicLine } : {}),
1035
+ ...(snapshot.diagnostics ?? {}),
1036
+ })}`);
1037
+ try {
1038
+ const callbackResult = this.onExit?.({ ...snapshot });
1039
+ if (callbackResult) {
1040
+ void Promise.resolve(callbackResult).catch((err) => {
1041
+ log.warn(`${this.logPrefix} onExit rejected: ${err instanceof Error ? err.message : String(err)}`);
1042
+ });
1043
+ }
1044
+ }
1045
+ catch (err) {
1046
+ log.warn(`${this.logPrefix} onExit threw: ${err instanceof Error ? err.message : String(err)}`);
1047
+ }
1048
+ for (const listener of this.exitListeners)
1049
+ listener(snapshot);
1050
+ // Deregister before any early-return: this owned engine is gone, so
1051
+ // it's free for a future reaper to clean up if it somehow outlives us.
1052
+ if (this.ownedPid !== undefined) {
1053
+ liveEnginePids.delete(this.ownedPid);
1054
+ this.ownedPid = undefined;
1055
+ }
1056
+ this.clearIdleTimer();
1057
+ this.clearFreezeTimer();
1058
+ this.clearHealthTimer();
1059
+ this.currentPid = undefined;
1060
+ this.currentStartedAt = 0;
1061
+ this.currentReachedReady = false;
1062
+ this.currentDiagnostics = undefined;
1063
+ this.currentOutput = '';
1064
+ this.currentPanic = undefined;
1065
+ this.expectedExitReason = undefined;
1066
+ if (priorState.kind === 'stopped')
1067
+ return;
1068
+ this.onLog(`${this.logPrefix} exited (code=${code} signal=${signal ?? 'none'})`);
1069
+ // If the child died while we were still waiting for /health to come
1070
+ // up, abort the startup wait immediately. Otherwise `waitForReady`
1071
+ // would keep polling a dead port for the full startup-timeout
1072
+ // budget (default 180s) — observed as a 3-minute wedge in chat
1073
+ // when an unclassified Python exception kills the engine before
1074
+ // ready. The provider's stdout classifier may still produce a
1075
+ // better-typed error a moment later via `abortStartup(err)`; that
1076
+ // call wins because it lands first (the classifier sees the leaf
1077
+ // exception line slightly before the kernel reports the exit).
1078
+ if (this.startupAbort && priorState.kind === 'starting') {
1079
+ this.startupAbort.abort(new Error(`${this.logPrefix} child exited (code=${code} signal=${signal ?? 'none'}) before becoming ready`));
1080
+ }
1081
+ this.state = { kind: 'stopped' };
1082
+ }
1083
+ startHealthWatch() {
1084
+ this.clearHealthTimer();
1085
+ this.healthTimer = setInterval(() => {
1086
+ void this.healthProbe();
1087
+ void this.pressureProbe();
1088
+ }, this.healthIntervalMs);
1089
+ this.healthTimer.unref?.();
1090
+ }
1091
+ /**
1092
+ * Accelerator pressure this engine is currently sitting inside, or null when
1093
+ * there is none. Read by callers that want to explain a symptom the engine
1094
+ * itself cannot see — a turn whose throughput collapsed has no way to know
1095
+ * the card is oversubscribed, and "the engine is slow" is the wrong story.
1096
+ */
1097
+ memoryPressureHeld() {
1098
+ if (this.pressureHeldSince === undefined)
1099
+ return null;
1100
+ return {
1101
+ sinceAwakeMs: this.pressureHeldSince,
1102
+ heldMs: Math.max(0, awakeNow() - this.pressureHeldSince),
1103
+ };
1104
+ }
1105
+ engineBusy() {
1106
+ try {
1107
+ return this.activeRequests > 0 || this.isBusy?.() === true;
1108
+ }
1109
+ catch (error) {
1110
+ this.onLog(`${this.logPrefix} busy predicate failed: ${error instanceof Error ? error.message : error}`);
1111
+ return true;
1112
+ }
1113
+ }
1114
+ async pressureProbe() {
1115
+ if ((!this.memoryPressure && !this.capacityLease) ||
1116
+ this.pressureCheckInFlight ||
1117
+ this.state.kind !== 'running')
1118
+ return;
1119
+ this.pressureCheckInFlight = true;
1120
+ try {
1121
+ const requested = (await this.capacityLease?.shouldYield()) ?? false;
1122
+ if (requested && this.yieldFlight)
1123
+ return;
1124
+ const pressure = requested
1125
+ ? { pressured: true, detail: 'another engine is waiting for memory' }
1126
+ : ((await this.memoryPressure?.()) ?? { pressured: false });
1127
+ if (!pressure.pressured || this.state.kind !== 'running') {
1128
+ this.pressureDeadlineAt = undefined;
1129
+ this.pressureHeldSince = undefined;
1130
+ this.pressureHeldLoggedAt = undefined;
1131
+ return;
1132
+ }
1133
+ const now = awakeNow();
1134
+ if (this.pressureHeldSince === undefined)
1135
+ this.pressureHeldSince = now;
1136
+ this.pressureDeadlineAt = this.lastUsedAwakeAt + this.pressureIdleTimeoutMs;
1137
+ const busy = this.engineBusy();
1138
+ if ((!requested && now < this.pressureDeadlineAt) || busy) {
1139
+ // The only lever here is "stop MY engine once MY engine is idle", and
1140
+ // a busy one is out of reach of it. Saying so beats the silence that
1141
+ // preceded it: a four-hour turn on an oversubscribed card ran this
1142
+ // probe about 960 times and emitted nothing at all, so the machine
1143
+ // state that made every other tenant unusable left no trace in the
1144
+ // log. Rate-limited because pressure is normal and steady on a card
1145
+ // sized to one model.
1146
+ if (this.pressureHeldLoggedAt === undefined ||
1147
+ now - this.pressureHeldLoggedAt >= PRESSURE_HELD_LOG_INTERVAL_MS) {
1148
+ this.pressureHeldLoggedAt = now;
1149
+ const held = Math.round((now - this.pressureHeldSince) / 1000);
1150
+ const why = busy ? 'engine is serving a turn' : 'still inside the warm-retention grace';
1151
+ const detail = pressure.detail ? ` (${pressure.detail})` : '';
1152
+ this.onLog(`${this.logPrefix} memory pressure${detail} held ${held}s — ${why}, not releasing`);
1153
+ }
1154
+ return;
1155
+ }
1156
+ if (requested) {
1157
+ // Use the same gate as incoming requests, including while flushing.
1158
+ // A new request must not enter the engine between idle detection and
1159
+ // the awaited cache flush that precedes releasing its memory.
1160
+ await this.yieldForWaitingCapacity();
1161
+ return;
1162
+ }
1163
+ this.onLog(`${this.logPrefix} memory pressure${pressure.detail ? ` (${pressure.detail})` : ''} — flushing and stopping idle engine`);
1164
+ await this.runFreeze();
1165
+ if (this.engineBusy())
1166
+ return;
1167
+ await this.stop('memory-pressure');
1168
+ }
1169
+ catch (error) {
1170
+ this.onLog(`${this.logPrefix} memory-pressure check failed: ${error instanceof Error ? error.message : error}`);
1171
+ }
1172
+ finally {
1173
+ this.pressureCheckInFlight = false;
1174
+ }
1175
+ }
1176
+ async releaseCapacity() {
1177
+ const lease = this.capacityLease;
1178
+ this.capacityLease = undefined;
1179
+ await lease
1180
+ ?.release()
1181
+ .catch((error) => this.onLog(`${this.logPrefix} memory lease release failed: ${error}`));
1182
+ }
1183
+ async healthProbe() {
1184
+ if (this.state.kind !== 'running')
1185
+ return;
1186
+ const launch = this.state.launch;
1187
+ try {
1188
+ const res = await this.fetchImpl(`${launch.baseUrl}${this.readinessPath}`);
1189
+ if (res.ok || this.readyOnAnyResponse) {
1190
+ void res.body?.cancel?.().catch(() => { });
1191
+ if (this.state.kind === 'running')
1192
+ this.state.healthFails = 0;
1193
+ return;
1194
+ }
1195
+ }
1196
+ catch {
1197
+ /* treat as failure below */
1198
+ }
1199
+ if (this.state.kind !== 'running')
1200
+ return;
1201
+ // A busy engine can be too busy to answer: a 12-image vision prefill held
1202
+ // the MLX server's event loop, three probes went unanswered, and the
1203
+ // restart threw away a 20-minute powerpoint-deck evaluate turn
1204
+ // (qwen3.8-27b, 2026-09-23). A turn in flight has its own awake-time
1205
+ // deadlines that end a genuinely wedged engine, so only an idle engine's
1206
+ // silence counts here.
1207
+ if (this.engineBusy())
1208
+ return;
1209
+ this.state.healthFails++;
1210
+ if (this.state.healthFails >= HEALTH_FAIL_THRESHOLD) {
1211
+ this.onLog(`${this.logPrefix} ${HEALTH_FAIL_THRESHOLD} health failures — restarting`);
1212
+ await this.stop('health-restart');
1213
+ try {
1214
+ await this.ensureRunning();
1215
+ }
1216
+ catch (err) {
1217
+ this.onLog(`${this.logPrefix} restart failed: ${err instanceof Error ? err.message : err}`);
1218
+ }
1219
+ }
1220
+ }
1221
+ resetIdleTimer() {
1222
+ this.clearIdleTimer();
1223
+ this.clearFreezeTimer();
1224
+ this.freezeFired = false;
1225
+ // Stage 1 (freeze): persist transient state to disk while the
1226
+ // child is still healthy. Doesn't stop the engine. Skipped when
1227
+ // freezeTimeoutMs is unset/0 (legacy single-stage behavior) or
1228
+ // when no onFreeze callback was supplied.
1229
+ if (this.freezeTimeoutMs > 0 && this.onFreeze && this.freezeTimeoutMs < this.idleTimeoutMs) {
1230
+ this.freezeTimer = setTimeout(() => {
1231
+ // Fire-and-forget; supervisor logs + swallows any error so a
1232
+ // bad callback can't crash the host.
1233
+ void this.runFreeze();
1234
+ }, this.freezeTimeoutMs + 50);
1235
+ this.freezeTimer.unref?.();
1236
+ }
1237
+ // Stage 2 (idle): full SIGTERM. Existing behavior — runs after
1238
+ // idleTimeoutMs regardless of whether Stage 1 fired.
1239
+ this.armIdleTimer(this.idleTimeoutMs);
1240
+ }
1241
+ /**
1242
+ * Arm the VRAM-release timer to fire `delayMs` from now, then re-check
1243
+ * against the AWAKE clock when it does.
1244
+ *
1245
+ * The re-check is the load-bearing part. A host suspension fires every
1246
+ * overdue timer the instant the machine resumes, so a nap longer than the
1247
+ * idle timeout used to read as "this engine has been idle that long" and
1248
+ * unload it — observed unloading a resident 27B model on each ~16 min
1249
+ * dark-wake cycle, so the next turn paid a full cold load for idleness
1250
+ * nobody could have avoided. Re-arming for the shortfall matters just as
1251
+ * much: an early return with no re-arm would leave the engine resident for
1252
+ * good, trading a spurious unload for a permanent leak.
1253
+ */
1254
+ armIdleTimer(delayMs) {
1255
+ this.clearIdleTimer();
1256
+ if (this.idleTimeoutMs <= 0)
1257
+ return;
1258
+ this.idleTimer = setTimeout(() => {
1259
+ const since = awakeNow() - this.lastUsedAwakeAt;
1260
+ if (since < this.idleTimeoutMs) {
1261
+ this.armIdleTimer(this.idleTimeoutMs - since);
1262
+ return;
1263
+ }
1264
+ // Don't interrupt an actual native request. Logical turns parked on a
1265
+ // tool or a person are intentionally not busy here; a later iteration
1266
+ // can lazy-start the engine again from its flushed disk cache.
1267
+ if (this.engineBusy()) {
1268
+ this.onLog(`${this.logPrefix} idle deadline reached but an engine request is active — deferring VRAM stop`);
1269
+ this.resetIdleTimer();
1270
+ return;
1271
+ }
1272
+ this.onLog(`${this.logPrefix} idle timeout — stopping to free VRAM`);
1273
+ void this.stop('idle');
1274
+ }, delayMs + 50);
1275
+ this.idleTimer.unref?.();
1276
+ }
1277
+ /**
1278
+ * Project an awake-clock instant onto the wall clock for display. The UI
1279
+ * renders a countdown, and a deadline held in awake time would otherwise
1280
+ * show as an already-past timestamp after any suspension.
1281
+ */
1282
+ wallClockFor(awakeInstant) {
1283
+ return Date.now() + (awakeInstant - awakeNow());
1284
+ }
1285
+ /**
1286
+ * Run the user-supplied onFreeze hook with proper guarding. Marks
1287
+ * `freezeFired` so subsequent ticks within this idle window don't
1288
+ * re-fire (idempotency for callers, e.g. a re-entrant flush would
1289
+ * double-write the same content).
1290
+ */
1291
+ async runFreeze() {
1292
+ if (this.freezeFired)
1293
+ return;
1294
+ // Cache endpoints share the native server with inference; do not flush a
1295
+ // slot while that engine is actively reading or writing it. The next idle
1296
+ // deadline (or pressure probe) gets another chance.
1297
+ if (this.engineBusy())
1298
+ return;
1299
+ this.freezeFired = true;
1300
+ if (!this.onFreeze)
1301
+ return;
1302
+ this.onLog(`${this.logPrefix} idle freeze — flushing caches to disk (model stays resident)`);
1303
+ try {
1304
+ await this.onFreeze();
1305
+ }
1306
+ catch (err) {
1307
+ this.onLog(`${this.logPrefix} freeze callback threw: ${err instanceof Error ? err.message : err}`);
1308
+ }
1309
+ }
1310
+ clearIdleTimer() {
1311
+ if (this.idleTimer) {
1312
+ clearTimeout(this.idleTimer);
1313
+ this.idleTimer = undefined;
1314
+ }
1315
+ }
1316
+ clearFreezeTimer() {
1317
+ if (this.freezeTimer) {
1318
+ clearTimeout(this.freezeTimer);
1319
+ this.freezeTimer = undefined;
1320
+ }
1321
+ }
1322
+ clearHealthTimer() {
1323
+ if (this.healthTimer) {
1324
+ clearInterval(this.healthTimer);
1325
+ this.healthTimer = undefined;
1326
+ }
1327
+ }
1328
+ }
1329
+ /** High-precision fatal signatures; attribution happens only if the child exits. */
1330
+ export function classifyNativeEnginePanic(line) {
1331
+ const clipped = line.trim().slice(0, 1_000);
1332
+ if (/CUDA error:\s*invalid (?:configuration )?argument/i.test(line)) {
1333
+ return { kind: 'cuda-invalid-argument', line: clipped };
1334
+ }
1335
+ if (/CUDA error:\s*(?:out of memory|memory allocation)/i.test(line)) {
1336
+ return { kind: 'cuda-out-of-memory', line: clipped };
1337
+ }
1338
+ // Vulkan's spellings of the same condition — the backend a non-CUDA
1339
+ // discrete card (or a CUDA card without nvidia-smi) runs on.
1340
+ if (/ErrorOutOfDeviceMemory|OutOfDeviceMemoryError|ggml_vulkan:.*(?:allocation|memory).*failed/i.test(line)) {
1341
+ return { kind: 'vulkan-out-of-memory', line: clipped };
1342
+ }
1343
+ if (/CUDA error:\s*(?:an )?illegal memory access/i.test(line)) {
1344
+ return { kind: 'cuda-illegal-memory-access', line: clipped };
1345
+ }
1346
+ if (/CUDA error:.*device-side assert/i.test(line)) {
1347
+ return { kind: 'cuda-device-assert', line: clipped };
1348
+ }
1349
+ if (/CUDA error:/i.test(line))
1350
+ return { kind: 'cuda-error', line: clipped };
1351
+ if (/assert(?:ion)? failed|GGML_ASSERT/i.test(line)) {
1352
+ return { kind: 'assertion-failed', line: clipped };
1353
+ }
1354
+ return undefined;
1355
+ }
1356
+ function panicPriority(kind) {
1357
+ if (kind === 'cuda-error')
1358
+ return 1;
1359
+ if (kind === 'assertion-failed')
1360
+ return 2;
1361
+ return 3;
1362
+ }
1363
+ /**
1364
+ * Default process snapshot. PPID is load-bearing: command paths identify
1365
+ * which engine a row belongs to, while the parent snapshot distinguishes an
1366
+ * owner-less prior-launch orphan from an engine actively owned by another
1367
+ * gezeld process. Errors remain best-effort so cleanup cannot block startup.
1368
+ */
1369
+ async function defaultPsRunner(platform) {
1370
+ try {
1371
+ return await listProcessSnapshots({ platform });
1372
+ }
1373
+ catch {
1374
+ return [];
1375
+ }
1376
+ }
1377
+ function isOwnerlessProcess(ppid, livePids, platform) {
1378
+ return platform === 'win32' ? !livePids.has(ppid) : ppid <= 1;
1379
+ }
1380
+ function normalizeProcessMatch(value, platform) {
1381
+ return platform === 'win32' ? value.replaceAll('/', '\\').toLowerCase() : value;
1382
+ }
1383
+ function isAbsoluteProcessPath(value) {
1384
+ // Accept both syntaxes independent of the host running the test/build. The
1385
+ // launch value itself is authoritative, and cross-platform fixtures exercise
1386
+ // Windows paths on Unix CI and Unix paths on Windows CI.
1387
+ return value.startsWith('/') || /^(?:[A-Za-z]:[\\/]|\\\\)/.test(value);
1388
+ }
1389
+ /** Parse the portable `ps -axo pid=,ppid=,command=` shape. */
1390
+ export function parseNativeProcessSnapshot(stdout) {
1391
+ const out = [];
1392
+ for (const rawLine of stdout.split('\n')) {
1393
+ const line = rawLine.trimStart();
1394
+ if (!line)
1395
+ continue;
1396
+ const m = line.match(/^(\d+)\s+(\d+)\s+(.*)$/);
1397
+ if (!m)
1398
+ continue;
1399
+ const pid = Number.parseInt(m[1], 10);
1400
+ const ppid = Number.parseInt(m[2], 10);
1401
+ if (!Number.isFinite(pid) || !Number.isFinite(ppid))
1402
+ continue;
1403
+ out.push({ pid, ppid, command: m[3] });
1404
+ }
1405
+ return out;
1406
+ }
1407
+ /** `code` stamped on every engine-launch failure. See {@link isEngineLaunchError}. */
1408
+ export const ENGINE_LAUNCH_ERROR_CODE = 'engine-launch';
1409
+ /**
1410
+ * True when the engine binary itself never started, however deep the error
1411
+ * was rewrapped. Matches the code first, then falls back to the stable
1412
+ * message so a rewrapped error still classifies right (same belt-and-braces
1413
+ * shape as the pool's `engine-busy` matcher).
1414
+ */
1415
+ export function isEngineLaunchError(err) {
1416
+ if (err &&
1417
+ typeof err === 'object' &&
1418
+ err.code === ENGINE_LAUNCH_ERROR_CODE) {
1419
+ return true;
1420
+ }
1421
+ const message = err instanceof Error ? err.message : String(err);
1422
+ return /could not launch /.test(message);
1423
+ }
1424
+ function nativeSpawnError(logPrefix, launch, cause) {
1425
+ const code = cause && typeof cause === 'object' && 'code' in cause && typeof cause.code === 'string'
1426
+ ? cause.code
1427
+ : undefined;
1428
+ const detail = cause instanceof Error ? cause.message : String(cause);
1429
+ const err = new Error(`${logPrefix} could not launch ${basename(launch.command)}${code ? ` (${code})` : ''}. ` +
1430
+ `Executable: ${launch.command}${launch.cwd ? `; cwd: ${launch.cwd}` : ''}. ${detail}`, { cause });
1431
+ // Consumers that report *why* a model failed need to tell "the engine
1432
+ // never came up" apart from "the model answered badly". The engine starts
1433
+ // lazily on the first turn, so without this marker a launch failure looks
1434
+ // like a generation failure — which is how the fitness proeve came to
1435
+ // report "engine spawned and served the probe session" for a model whose
1436
+ // engine had never started.
1437
+ return Object.assign(err, { code: ENGINE_LAUNCH_ERROR_CODE });
1438
+ }
1439
+ async function killGracefully(child) {
1440
+ if (child.exitCode !== null || child.signalCode !== null)
1441
+ return;
1442
+ const exited = new Promise((resolve) => child.once('exit', () => resolve()));
1443
+ try {
1444
+ child.kill('SIGTERM');
1445
+ }
1446
+ catch {
1447
+ /* already dead */
1448
+ }
1449
+ const timeout = setTimeout(() => {
1450
+ try {
1451
+ child.kill('SIGKILL');
1452
+ }
1453
+ catch {
1454
+ /* */
1455
+ }
1456
+ }, 3_000);
1457
+ timeout.unref?.();
1458
+ await exited;
1459
+ clearTimeout(timeout);
1460
+ }
1461
+ function sleep(ms) {
1462
+ return new Promise((resolve) => {
1463
+ const t = setTimeout(resolve, ms);
1464
+ t.unref?.();
1465
+ });
1466
+ }