@simulatte/doppler 0.1.6 → 0.1.8

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 (355) hide show
  1. package/CHANGELOG.md +145 -0
  2. package/README.md +16 -23
  3. package/package.json +30 -32
  4. package/src/adapters/adapter-registry.js +12 -1
  5. package/src/adapters/lora-loader.js +23 -6
  6. package/src/bridge/extension-client.d.ts +5 -0
  7. package/src/bridge/extension-client.js +40 -0
  8. package/src/bridge/index.d.ts +2 -1
  9. package/src/bridge/index.js +6 -4
  10. package/src/browser/browser-converter.js +31 -1
  11. package/src/browser/file-picker.js +6 -0
  12. package/src/browser/safetensors-parser-browser.js +84 -1
  13. package/src/browser/shard-io-browser.js +2 -2
  14. package/src/browser/tensor-source-download.js +8 -2
  15. package/src/browser/tensor-source-http.d.ts +1 -0
  16. package/src/browser/tensor-source-http.js +5 -1
  17. package/src/client/doppler-api.browser.js +20 -4
  18. package/src/client/doppler-api.js +19 -3
  19. package/src/client/doppler-provider/generation.js +12 -0
  20. package/src/client/doppler-provider/model-manager.d.ts +10 -0
  21. package/src/client/doppler-provider/model-manager.js +91 -19
  22. package/src/client/doppler-provider/source-runtime.d.ts +2 -1
  23. package/src/client/doppler-provider/source-runtime.js +132 -13
  24. package/src/client/doppler-registry.json +5 -20
  25. package/src/config/backward-registry-loader.js +17 -2
  26. package/src/config/execution-v0-contract-check.js +113 -15
  27. package/src/config/kernel-path-contract-check.js +57 -29
  28. package/src/config/kernel-path-loader.d.ts +5 -0
  29. package/src/config/kernel-path-loader.js +18 -36
  30. package/src/config/kernels/kernel-ref-digests.js +1 -1
  31. package/src/config/kernels/registry.js +14 -1
  32. package/src/config/kernels/registry.json +81 -5
  33. package/src/config/loader.d.ts +1 -1
  34. package/src/config/loader.js +15 -2
  35. package/src/config/merge-contract-check.js +66 -4
  36. package/src/config/merge-helpers.js +128 -7
  37. package/src/config/merge.d.ts +1 -0
  38. package/src/config/merge.js +10 -0
  39. package/src/config/param-validator.js +47 -2
  40. package/src/config/presets/kernel-paths/{gemma2-q4k-dequant-f32a.json → gemma2-q4k-dequant-f32a-nosubgroups.json} +3 -3
  41. package/src/config/presets/kernel-paths/gemma3-f16-fused-f32a-online-streamingprefill.json +223 -0
  42. package/src/config/presets/kernel-paths/{gemma3-q4k-dequant-f32a.json → gemma3-q4k-dequant-f32a-nosubgroups.json} +3 -3
  43. package/src/config/presets/kernel-paths/gemma3-q4k-dequant-f32w-f32a-online.json +56 -0
  44. package/src/config/presets/kernel-paths/lfm2-q4k-dequant-f32a-nosubgroups.json +61 -0
  45. package/src/config/presets/kernel-paths/registry.json +43 -8
  46. package/src/config/presets/models/gemma2.json +3 -2
  47. package/src/config/presets/models/gemma3.json +2 -0
  48. package/src/config/presets/models/qwen3.json +4 -3
  49. package/src/config/presets/models/qwen3_5.json +16 -0
  50. package/src/config/presets/runtime/experiments/bench/gemma3-bench-q4k.json +1 -1
  51. package/src/config/presets/runtime/experiments/debug/gemma3-debug-q4k.json +1 -1
  52. package/src/config/presets/runtime/experiments/verify/gemma3-verify.json +1 -1
  53. package/src/config/presets/runtime/kernels/dequant-f16-q4k.json +6 -13
  54. package/src/config/presets/runtime/kernels/dequant-f32-q4k.json +6 -13
  55. package/src/config/presets/runtime/kernels/embeddinggemma-q4k-dequant-f32a.json +37 -0
  56. package/src/config/presets/runtime/kernels/fused-q4k.json +6 -13
  57. package/src/config/presets/runtime/kernels/gemma2-q4k-dequant-f16a.json +33 -0
  58. package/src/config/presets/runtime/kernels/gemma2-q4k-dequant-f32a-nosubgroups.json +33 -0
  59. package/src/config/presets/runtime/kernels/gemma2-q4k-fused-f32a.json +33 -0
  60. package/src/config/presets/runtime/kernels/safe-q4k.json +6 -13
  61. package/src/config/presets/runtime/model/qwen3-5-layer-probe.json +52 -0
  62. package/src/config/presets/runtime/model/qwen3-5-linear-attn-debug.json +90 -0
  63. package/src/config/presets/runtime/platform/metal-apple-q4k.json +1 -1
  64. package/src/config/runtime.js +6 -1
  65. package/src/config/schema/conversion.schema.d.ts +1 -0
  66. package/src/config/schema/debug.schema.d.ts +5 -0
  67. package/src/config/schema/doppler.schema.js +16 -21
  68. package/src/config/schema/inference-defaults.schema.js +3 -3
  69. package/src/config/schema/kernel-path.schema.d.ts +5 -1
  70. package/src/config/schema/kernel-thresholds.schema.js +12 -4
  71. package/src/config/schema/manifest.schema.d.ts +3 -2
  72. package/src/config/schema/manifest.schema.js +17 -4
  73. package/src/config/schema/storage.schema.js +1 -1
  74. package/src/config/training-defaults.js +30 -22
  75. package/src/converter/conversion-plan.js +104 -11
  76. package/src/converter/core.d.ts +7 -0
  77. package/src/converter/core.js +16 -9
  78. package/src/converter/execution-v0-manifest.js +4 -1
  79. package/src/converter/index.d.ts +1 -0
  80. package/src/converter/index.js +1 -0
  81. package/src/converter/manifest-inference.js +50 -29
  82. package/src/converter/parsers/diffusion.js +0 -3
  83. package/src/converter/parsers/transformer.js +4 -0
  84. package/src/converter/quantization-info.js +40 -16
  85. package/src/converter/quantizer.js +19 -12
  86. package/src/converter/rope-config.js +8 -6
  87. package/src/converter/shard-packer.d.ts +1 -1
  88. package/src/converter/shard-packer.js +4 -1
  89. package/src/converter/tokenizer-utils.d.ts +1 -0
  90. package/src/converter/tokenizer-utils.js +4 -1
  91. package/src/debug/config.js +123 -11
  92. package/src/debug/reference/hf_qwen35_linear_attn_debug.py +268 -0
  93. package/src/debug/signals.js +7 -1
  94. package/src/debug/tensor.d.ts +2 -0
  95. package/src/debug/tensor.js +13 -2
  96. package/src/distribution/p2p-control-plane.js +52 -12
  97. package/src/distribution/p2p-observability.js +43 -7
  98. package/src/distribution/p2p-webrtc-browser.js +20 -0
  99. package/src/distribution/shard-delivery.js +83 -27
  100. package/src/formats/gguf/types.js +33 -16
  101. package/src/formats/rdrr/groups.d.ts +12 -4
  102. package/src/formats/rdrr/groups.js +3 -6
  103. package/src/formats/rdrr/parsing.d.ts +4 -0
  104. package/src/formats/rdrr/parsing.js +53 -3
  105. package/src/formats/rdrr/types.d.ts +2 -1
  106. package/src/gpu/command-recorder.js +86 -61
  107. package/src/gpu/device.d.ts +1 -0
  108. package/src/gpu/device.js +73 -19
  109. package/src/gpu/kernel-tuner/benchmarks.js +326 -316
  110. package/src/gpu/kernel-tuner/cache.js +71 -4
  111. package/src/gpu/kernel-tuner/tuner.js +22 -4
  112. package/src/gpu/kernels/attention.js +15 -34
  113. package/src/gpu/kernels/backward/adam.js +62 -58
  114. package/src/gpu/kernels/backward/attention_backward.js +257 -169
  115. package/src/gpu/kernels/backward/conv2d_backward.js +14 -1
  116. package/src/gpu/kernels/cast.js +191 -149
  117. package/src/gpu/kernels/check-stop.js +33 -44
  118. package/src/gpu/kernels/conv2d.js +27 -17
  119. package/src/gpu/kernels/cross_entropy_loss.js +21 -15
  120. package/src/gpu/kernels/depthwise_conv2d.js +36 -26
  121. package/src/gpu/kernels/dequant.js +178 -126
  122. package/src/gpu/kernels/energy.d.ts +3 -21
  123. package/src/gpu/kernels/energy.js +111 -88
  124. package/src/gpu/kernels/feature-check.js +1 -1
  125. package/src/gpu/kernels/fused_ffn.js +84 -65
  126. package/src/gpu/kernels/fused_matmul_residual.js +56 -33
  127. package/src/gpu/kernels/fused_matmul_rmsnorm.js +62 -45
  128. package/src/gpu/kernels/gather.js +33 -15
  129. package/src/gpu/kernels/gelu.js +19 -11
  130. package/src/gpu/kernels/grouped_pointwise_conv2d.js +33 -23
  131. package/src/gpu/kernels/groupnorm.js +34 -23
  132. package/src/gpu/kernels/index.d.ts +8 -0
  133. package/src/gpu/kernels/index.js +6 -0
  134. package/src/gpu/kernels/kv-quantize.js +5 -2
  135. package/src/gpu/kernels/layernorm.js +35 -19
  136. package/src/gpu/kernels/logit-merge.js +5 -3
  137. package/src/gpu/kernels/matmul-selection.js +47 -4
  138. package/src/gpu/kernels/matmul.d.ts +2 -0
  139. package/src/gpu/kernels/matmul.js +59 -40
  140. package/src/gpu/kernels/modulate.js +23 -15
  141. package/src/gpu/kernels/moe.js +221 -175
  142. package/src/gpu/kernels/pixel_shuffle.js +22 -14
  143. package/src/gpu/kernels/relu.js +18 -10
  144. package/src/gpu/kernels/repeat_channels.js +25 -17
  145. package/src/gpu/kernels/residual.js +37 -27
  146. package/src/gpu/kernels/rmsnorm.js +66 -43
  147. package/src/gpu/kernels/rope.js +3 -0
  148. package/src/gpu/kernels/sample.js +27 -38
  149. package/src/gpu/kernels/sana_linear_attention.js +18 -10
  150. package/src/gpu/kernels/scale.js +18 -11
  151. package/src/gpu/kernels/shader-cache.js +4 -2
  152. package/src/gpu/kernels/silu.js +120 -72
  153. package/src/gpu/kernels/softmax.js +44 -25
  154. package/src/gpu/kernels/split_qg.d.ts +50 -0
  155. package/src/gpu/kernels/split_qg.js +46 -0
  156. package/src/gpu/kernels/split_qg.wgsl +58 -0
  157. package/src/gpu/kernels/split_qg_f16.wgsl +62 -0
  158. package/src/gpu/kernels/split_qkv.js +23 -13
  159. package/src/gpu/kernels/transpose.js +18 -10
  160. package/src/gpu/kernels/transpose.wgsl +5 -3
  161. package/src/gpu/kernels/upsample2d.js +21 -13
  162. package/src/gpu/kernels/utils.js +20 -13
  163. package/src/gpu/partitioned-buffer-pool.js +10 -2
  164. package/src/gpu/perf-guards.js +2 -9
  165. package/src/gpu/profiler.js +27 -22
  166. package/src/gpu/readback-utils.d.ts +16 -0
  167. package/src/gpu/readback-utils.js +41 -0
  168. package/src/gpu/submit-tracker.js +13 -0
  169. package/src/gpu/uniform-cache.d.ts +1 -0
  170. package/src/gpu/uniform-cache.js +30 -9
  171. package/src/gpu/weight-buffer.d.ts +1 -1
  172. package/src/gpu/weight-buffer.js +1 -1
  173. package/src/hotswap/intent-bundle.js +6 -0
  174. package/src/hotswap/manifest.d.ts +10 -1
  175. package/src/hotswap/manifest.js +12 -2
  176. package/src/hotswap/runtime.js +30 -8
  177. package/src/index-browser.d.ts +44 -0
  178. package/src/index-browser.js +14 -0
  179. package/src/inference/browser-harness-contract-helpers.d.ts +5 -0
  180. package/src/inference/browser-harness-contract-helpers.js +28 -0
  181. package/src/inference/browser-harness-diffusion-energy-suites.d.ts +2 -0
  182. package/src/inference/browser-harness-diffusion-energy-suites.js +269 -0
  183. package/src/inference/browser-harness-model-helpers.d.ts +16 -0
  184. package/src/inference/browser-harness-model-helpers.js +217 -0
  185. package/src/inference/browser-harness-report-helpers.d.ts +7 -0
  186. package/src/inference/browser-harness-report-helpers.js +42 -0
  187. package/src/inference/browser-harness-runtime-helpers.d.ts +61 -0
  188. package/src/inference/browser-harness-runtime-helpers.js +415 -0
  189. package/src/inference/browser-harness-suite-helpers.d.ts +28 -0
  190. package/src/inference/browser-harness-suite-helpers.js +268 -0
  191. package/src/inference/browser-harness-text-helpers.d.ts +27 -0
  192. package/src/inference/browser-harness-text-helpers.js +788 -0
  193. package/src/inference/browser-harness.d.ts +8 -0
  194. package/src/inference/browser-harness.js +149 -1996
  195. package/src/inference/kv-cache/base.js +140 -94
  196. package/src/inference/kv-cache/tiered.js +5 -3
  197. package/src/inference/moe-router.js +88 -56
  198. package/src/inference/multi-model-network.js +5 -3
  199. package/src/inference/network-evolution.d.ts +11 -2
  200. package/src/inference/network-evolution.js +20 -21
  201. package/src/inference/pipelines/context.d.ts +3 -0
  202. package/src/inference/pipelines/context.js +142 -2
  203. package/src/inference/pipelines/diffusion/helpers.js +10 -2
  204. package/src/inference/pipelines/diffusion/pipeline.js +2 -1
  205. package/src/inference/pipelines/diffusion/sd3-transformer.js +10 -10
  206. package/src/inference/pipelines/diffusion/text-encoder-gpu.js +8 -2
  207. package/src/inference/pipelines/diffusion/vae.js +3 -7
  208. package/src/inference/pipelines/energy/pipeline.js +27 -21
  209. package/src/inference/pipelines/energy/quintel.d.ts +5 -0
  210. package/src/inference/pipelines/energy/quintel.js +11 -0
  211. package/src/inference/pipelines/energy-head/row-head-pipeline.js +17 -13
  212. package/src/inference/pipelines/structured/json-head-pipeline.js +26 -11
  213. package/src/inference/pipelines/text/attention/output-projection.d.ts +12 -0
  214. package/src/inference/pipelines/text/attention/output-projection.js +8 -0
  215. package/src/inference/pipelines/text/attention/projections.d.ts +10 -1
  216. package/src/inference/pipelines/text/attention/projections.js +192 -112
  217. package/src/inference/pipelines/text/attention/record.js +77 -14
  218. package/src/inference/pipelines/text/attention/run.js +112 -14
  219. package/src/inference/pipelines/text/config.js +17 -4
  220. package/src/inference/pipelines/text/embed.js +2 -8
  221. package/src/inference/pipelines/text/execution-plan.js +46 -23
  222. package/src/inference/pipelines/text/execution-v0-contract-helpers.d.ts +59 -0
  223. package/src/inference/pipelines/text/execution-v0-contract-helpers.js +937 -0
  224. package/src/inference/pipelines/text/execution-v0-runtime-builders.d.ts +15 -0
  225. package/src/inference/pipelines/text/execution-v0-runtime-builders.js +279 -0
  226. package/src/inference/pipelines/text/execution-v0.js +62 -1013
  227. package/src/inference/pipelines/text/generator-runtime.js +5 -0
  228. package/src/inference/pipelines/text/generator-steps.d.ts +52 -0
  229. package/src/inference/pipelines/text/generator-steps.js +340 -221
  230. package/src/inference/pipelines/text/generator.js +56 -40
  231. package/src/inference/pipelines/text/init.d.ts +13 -0
  232. package/src/inference/pipelines/text/init.js +94 -25
  233. package/src/inference/pipelines/text/kernel-path-auto-select.js +2 -0
  234. package/src/inference/pipelines/text/kernel-trace.d.ts +2 -0
  235. package/src/inference/pipelines/text/kernel-trace.js +6 -0
  236. package/src/inference/pipelines/text/layer.js +4 -9
  237. package/src/inference/pipelines/text/linear-attention.d.ts +15 -0
  238. package/src/inference/pipelines/text/linear-attention.js +113 -9
  239. package/src/inference/pipelines/text/logits/gpu.js +12 -7
  240. package/src/inference/pipelines/text/logits/index.d.ts +6 -1
  241. package/src/inference/pipelines/text/logits/index.js +13 -12
  242. package/src/inference/pipelines/text/logits/utils.d.ts +7 -0
  243. package/src/inference/pipelines/text/logits/utils.js +9 -0
  244. package/src/inference/pipelines/text/lora-apply.js +50 -32
  245. package/src/inference/pipelines/text/model-load.js +282 -104
  246. package/src/inference/pipelines/text/moe-cache.js +5 -4
  247. package/src/inference/pipelines/text/moe-cpu-gptoss.js +74 -69
  248. package/src/inference/pipelines/text/moe-cpu.js +42 -38
  249. package/src/inference/pipelines/text/moe-gpu.js +110 -86
  250. package/src/inference/pipelines/text/ops.js +90 -90
  251. package/src/inference/pipelines/text/probes.js +9 -9
  252. package/src/inference/pipelines/text/sampling.js +52 -6
  253. package/src/inference/pipelines/text/weights.js +17 -7
  254. package/src/inference/pipelines/text.js +13 -1
  255. package/src/inference/speculative.d.ts +2 -2
  256. package/src/inference/speculative.js +4 -18
  257. package/src/inference/test-harness.d.ts +1 -1
  258. package/src/inference/test-harness.js +17 -7
  259. package/src/inference/tokenizer.d.ts +0 -5
  260. package/src/inference/tokenizer.js +4 -23
  261. package/src/inference/tokenizers/bpe.js +9 -0
  262. package/src/inference/tokenizers/bundled.js +20 -0
  263. package/src/inference/tokenizers/sentencepiece.js +12 -0
  264. package/src/loader/doppler-loader.js +38 -22
  265. package/src/loader/dtype-utils.js +3 -44
  266. package/src/loader/embedding-loader.js +7 -3
  267. package/src/loader/experts/expert-cache.js +13 -6
  268. package/src/loader/experts/expert-loader.js +10 -6
  269. package/src/loader/final-weights-loader.js +10 -4
  270. package/src/loader/layer-loader.js +2 -1
  271. package/src/loader/loader-state.js +2 -2
  272. package/src/loader/memory-monitor.js +8 -0
  273. package/src/loader/multi-model-loader.d.ts +14 -0
  274. package/src/loader/multi-model-loader.js +70 -24
  275. package/src/loader/shard-cache.js +84 -14
  276. package/src/loader/shard-resolver.js +25 -3
  277. package/src/loader/tensors/tensor-loader.js +214 -144
  278. package/src/loader/tensors/tensor-reader.js +76 -19
  279. package/src/loader/weight-downcast.js +1 -1
  280. package/src/memory/buffer-pool.d.ts +9 -1
  281. package/src/memory/buffer-pool.js +109 -44
  282. package/src/memory/unified-detect.js +1 -1
  283. package/src/rules/inference/dtype.rules.json +5 -0
  284. package/src/rules/inference/kernel-path.rules.json +24 -8
  285. package/src/rules/kernels/split-qg.rules.json +6 -0
  286. package/src/rules/rule-registry.js +27 -1
  287. package/src/storage/backends/opfs-store.js +68 -24
  288. package/src/storage/downloader.js +365 -83
  289. package/src/storage/index.d.ts +3 -0
  290. package/src/storage/index.js +3 -0
  291. package/src/storage/preflight.d.ts +2 -2
  292. package/src/storage/preflight.js +24 -2
  293. package/src/storage/quickstart-downloader.js +11 -5
  294. package/src/storage/registry.js +10 -4
  295. package/src/storage/reports.js +1 -1
  296. package/src/storage/shard-manager.d.ts +15 -1
  297. package/src/storage/shard-manager.js +55 -6
  298. package/src/storage/source-artifact-store.d.ts +52 -0
  299. package/src/storage/source-artifact-store.js +234 -0
  300. package/src/tooling/command-api-constants.d.ts +9 -0
  301. package/src/tooling/command-api-constants.js +9 -0
  302. package/src/tooling/command-api-family-normalizers.d.ts +9 -0
  303. package/src/tooling/command-api-family-normalizers.js +343 -0
  304. package/src/tooling/command-api-helpers.d.ts +25 -0
  305. package/src/tooling/command-api-helpers.js +262 -0
  306. package/src/tooling/command-api.js +16 -602
  307. package/src/tooling/command-envelope.js +4 -1
  308. package/src/tooling/command-runner-shared.js +52 -18
  309. package/src/tooling/conversion-config-materializer.js +3 -5
  310. package/src/tooling/lean-execution-contract.js +150 -3
  311. package/src/tooling/node-browser-command-runner.js +161 -271
  312. package/src/tooling/node-command-runner.js +29 -3
  313. package/src/tooling/node-converter.js +30 -1
  314. package/src/tooling/node-source-runtime.d.ts +1 -1
  315. package/src/tooling/node-source-runtime.js +120 -3
  316. package/src/tooling/node-webgpu.js +24 -21
  317. package/src/tooling/opfs-cache.js +21 -4
  318. package/src/tooling/runtime-input-composition.d.ts +38 -0
  319. package/src/tooling/runtime-input-composition.js +86 -0
  320. package/src/tooling/source-runtime-bundle.d.ts +40 -5
  321. package/src/tooling/source-runtime-bundle.js +261 -34
  322. package/src/tooling/source-runtime-materializer.d.ts +6 -0
  323. package/src/tooling/source-runtime-materializer.js +93 -0
  324. package/src/training/attention-backward.js +32 -17
  325. package/src/training/autograd.js +80 -52
  326. package/src/training/checkpoint-watch.d.ts +2 -1
  327. package/src/training/checkpoint-watch.js +39 -6
  328. package/src/training/checkpoint.js +40 -11
  329. package/src/training/clip.js +2 -1
  330. package/src/training/datasets/token-batch.js +20 -8
  331. package/src/training/distillation/checkpoint-watch.js +1 -0
  332. package/src/training/distillation/student-fixture.d.ts +22 -0
  333. package/src/training/distillation/student-fixture.js +846 -0
  334. package/src/training/distillation/suite-data.d.ts +45 -0
  335. package/src/training/distillation/suite-data.js +189 -0
  336. package/src/training/lora-pipeline.js +4 -7
  337. package/src/training/lora.js +26 -12
  338. package/src/training/loss.js +5 -6
  339. package/src/training/objectives/cross_entropy.js +2 -5
  340. package/src/training/objectives/distill_kd.js +4 -8
  341. package/src/training/objectives/distill_triplet.js +4 -8
  342. package/src/training/objectives/ul_stage2_base.js +4 -8
  343. package/src/training/operator-command.js +2 -0
  344. package/src/training/optimizer.js +19 -7
  345. package/src/training/runner.js +2 -1
  346. package/src/training/suite.js +18 -978
  347. package/src/training/tensor-factory.d.ts +9 -0
  348. package/src/training/tensor-factory.js +13 -0
  349. package/src/training/trainer.js +3 -5
  350. package/src/training/ul_dataset.js +3 -5
  351. package/src/training/workloads.js +70 -79
  352. package/src/types/model.d.ts +5 -0
  353. package/src/version.js +1 -1
  354. package/tools/convert-safetensors-node.js +22 -16
  355. package/tools/doppler-cli.js +50 -26
package/CHANGELOG.md ADDED
@@ -0,0 +1,145 @@
1
+ # Changelog
2
+
3
+ All notable changes to `@simulatte/doppler` are documented in this file.
4
+
5
+ This changelog is package-facing and release-oriented. Entries before `0.1.7`
6
+ were retrofitted from package version history, release commits, and release
7
+ docs so the `0.1.x` line has one conventional npm-visible history surface.
8
+
9
+ ## [0.1.8] - 2026-03-13
10
+
11
+ ### Changed
12
+
13
+ - Simplified demo to show only verified Q4K models (Gemma 3 270M, Gemma 3 1B).
14
+ Hidden Translate, Diffusion, and Embedding tabs until models are ready.
15
+ - Trimmed hosted HF registry and quickstart registry to the two verified models.
16
+ - Aligned catalog, HF registry, and quickstart registry to the canonical
17
+ external support registry as single source of truth for HF revisions.
18
+
19
+ ### Fixed
20
+
21
+ - Fixed Qwen 3.5 conversion configs using wrong model preset (`qwen3` instead
22
+ of `qwen3_5`), which caused support matrix check failures.
23
+ - Fixed catalog lifecycle metadata inconsistencies: corrected `local`, `hf`,
24
+ `curated`, and `demo` fields to match actual artifact availability.
25
+ - Removed failing and unverified models from demo visibility (TranslateGemma 4B,
26
+ EmbeddingGemma 300M with broken HF manifest, Qwen 3.5 0.8B/2B, F16 variant).
27
+
28
+ ## [0.1.7] - 2026-03-10
29
+
30
+ ### Added
31
+
32
+ - Added a conventional npm-facing changelog and included it in the published
33
+ package file list.
34
+ - Added stronger release-claim, quickstart-registry, local-model-integrity,
35
+ and browser diagnostics regression coverage.
36
+ - Added browser OPFS registry smoke workflows for text and embedding model
37
+ validation.
38
+
39
+ ### Changed
40
+
41
+ - Tightened release-facing model claims around the verified quickstart/catalog
42
+ set and regenerated the support and release matrices from current metadata.
43
+ - Synced the public quickstart registry from canonical catalog metadata instead
44
+ of maintaining it by hand.
45
+
46
+ ### Fixed
47
+
48
+ - Fixed a tensor-loader buffer ownership bug that corrupted returned weight
49
+ buffers and broke Gemma 3 1B generation.
50
+ - Fixed quickstart Hugging Face revision drift for registry-backed model IDs.
51
+ - Fixed multiple CI contract drifts across onboarding, release metadata,
52
+ support matrices, and generated benchmark fixtures.
53
+
54
+ ## [0.1.6] - 2026-03-07
55
+
56
+ ### Added
57
+
58
+ - Added stricter config and contract tests around runtime overrides, kernel-path
59
+ semantics, and release-support metadata.
60
+ - Added distillation helper extraction coverage for training suite refactors.
61
+
62
+ ### Changed
63
+
64
+ - Continued the execution-v0 and training orchestration refactor work so public
65
+ entrypoints read more like facades and less like inline policy code.
66
+ - Refreshed package exports, repository metadata, and release-facing support
67
+ surfaces for the npm package.
68
+
69
+ ### Fixed
70
+
71
+ - Preserved explicit `null` semantics for `runtime.inference.kernelPath` through
72
+ schema, runtime config, and harness paths.
73
+ - Fixed CI drift around onboarding, registry verification aliases, release
74
+ matrix metadata, and kernel-path preset naming.
75
+
76
+ ## [0.1.5] - 2026-03-06
77
+
78
+ ### Added
79
+
80
+ - Added diffusion kernel and contract work, plus additional Lean execution
81
+ contract sweep tooling.
82
+ - Added public API reference inventory and stronger registry workflow tooling.
83
+
84
+ ### Changed
85
+
86
+ - Expanded documentation around public APIs, registry workflow, hosted model
87
+ visibility, and release metadata.
88
+ - Tightened package exports and release checks for the public package surface.
89
+
90
+ ### Fixed
91
+
92
+ - Fixed hosted TranslateGemma visibility and registry metadata alignment across
93
+ docs, demos, and package surfaces.
94
+ - Removed incorrect self-dependency metadata from the published package.
95
+
96
+ ## [0.1.4] - 2026-03-05
97
+
98
+ ### Added
99
+
100
+ - Added Lean execution contract scripts and related package commands.
101
+ - Added translation prompt validation and quickstart/demo polish.
102
+
103
+ ### Fixed
104
+
105
+ - Fixed external resolution issues in conversion publication paths.
106
+ - Fixed quickstart-facing package and demo issues ahead of publication.
107
+
108
+ ## [0.1.3] - 2026-03-05
109
+
110
+ ### Changed
111
+
112
+ - Intermediate package metadata and dependency layout refresh during early npm
113
+ packaging work.
114
+
115
+ ## [0.1.2] - 2026-03-05
116
+
117
+ ### Changed
118
+
119
+ - Aligned build scripts, tests, docs, and package conventions with the active
120
+ workspace and release process.
121
+ - Refined README messaging and compatibility notes before npm publication.
122
+
123
+ ## [0.1.1] - 2026-03-05
124
+
125
+ ### Added
126
+
127
+ - Added benchmark vendor comparison docs, runtime patch documentation, and
128
+ refreshed evidence/chart surfaces for the package release.
129
+
130
+ ### Changed
131
+
132
+ - Moved vendor benchmark dependencies to development dependencies and kept the
133
+ runtime package dependency surface leaner.
134
+ - Refreshed package metadata, exports, and README/API positioning for the first
135
+ public npm publishing cycle.
136
+
137
+ ## [0.1.0] - 2025-12-23
138
+
139
+ ### Added
140
+
141
+ - Initial npm package release for Doppler.
142
+ - Browser and Node command surfaces, CLI entrypoint, loader/storage pipeline,
143
+ RDRR manifest handling, config schemas/presets, WebGPU kernel registry, text
144
+ inference pipeline, conversion tooling, benchmark tooling, tests, and demo
145
+ infrastructure.
package/README.md CHANGED
@@ -2,13 +2,7 @@
2
2
 
3
3
  Inference and training on raw WebGPU. Pure JS + WGSL.
4
4
 
5
- **[Live Demo](https://d4da.com)** · **[npm](https://www.npmjs.com/package/@simulatte/doppler)** · **[simulatte.world](https://simulatte.world)**
6
-
7
- ## Install
8
-
9
- ```bash
10
- npm install @simulatte/doppler
11
- ```
5
+ ![Phase-latency comparison on one workload across models](https://raw.githubusercontent.com/clocksmith/doppler/main/benchmarks/vendors/results/compare_1b_multi-workload_favorable_phases.svg)
12
6
 
13
7
  ## Quick start
14
8
 
@@ -17,13 +11,25 @@ import { doppler } from '@simulatte/doppler';
17
11
 
18
12
  const model = await doppler.load('gemma3-270m');
19
13
 
20
- for await (const token of model.generate('Hello, world')) {
14
+ for await (const token of model.generate('Describe WebGPU briefly')) {
21
15
  process.stdout.write(token);
22
16
  }
23
17
  ```
24
18
 
19
+ Browser-first WebGPU inference and training with explicit manifest-driven
20
+ runtime behavior. Built for local models, streamed generation, adapter
21
+ hot-swap, and direct JS → WGSL → WebGPU execution.
22
+
25
23
  Registry IDs resolve to hosted RDRR artifacts from `Clocksmith/rdrr` by default. Tokens stream from a native `AsyncGenerator`. See [more examples](#more-examples) below or the canonical [Root API guide](https://github.com/clocksmith/doppler/blob/main/docs/api/root.md).
26
24
 
25
+ ## Install
26
+
27
+ ```bash
28
+ npm install @simulatte/doppler
29
+ ```
30
+
31
+ **[Live Demo](https://d4da.com)** · **[npm](https://www.npmjs.com/package/@simulatte/doppler)** · **[docs](https://github.com/clocksmith/doppler/blob/main/docs/INDEX.md)** · **[Project site](https://simulatte.world)**
32
+
27
33
  ## Why Doppler
28
34
 
29
35
  **JS → WGSL → WebGPU.** Direct JavaScript orchestration into native WebGPU kernels, avoiding ONNX runtimes, WASM blobs, and bridge layers.
@@ -36,8 +42,6 @@ Registry IDs resolve to hosted RDRR artifacts from `Clocksmith/rdrr` by default.
36
42
 
37
43
  ## Evidence
38
44
 
39
- ![Phase-latency comparison on one workload across models](https://raw.githubusercontent.com/clocksmith/doppler/main/benchmarks/vendors/results/compare_1b_multi-workload_favorable_phases.svg)
40
-
41
45
  Snapshot artifacts:
42
46
  - [g3-1b-p064-d064-t0-k1.compare.json](https://github.com/clocksmith/doppler/blob/main/benchmarks/vendors/fixtures/g3-1b-p064-d064-t0-k1.compare.json)
43
47
  - [lfm2-5-1-2b-p064-d064-t0-k1.compare.json](https://github.com/clocksmith/doppler/blob/main/benchmarks/vendors/fixtures/lfm2-5-1-2b-p064-d064-t0-k1.compare.json)
@@ -83,19 +87,8 @@ for await (const token of doppler('Hello', { model: 'gemma3-270m' })) {
83
87
  - Architecture: [docs/architecture.md](https://github.com/clocksmith/doppler/blob/main/docs/architecture.md)
84
88
  - Generated model support table: [docs/model-support-matrix.md](https://github.com/clocksmith/doppler/blob/main/docs/model-support-matrix.md)
85
89
 
86
- ## Current model support
87
-
88
- Verified right now:
89
- - `gemma-3-270m-it-wq4k-ef16-hf16`
90
- - `gemma-3-1b-it-wq4k-ef16-hf16`
91
- - `google-embeddinggemma-300m-wq4k-ef16`
92
- - `translategemma-4b-it-wq4k-ef16-hf16`
93
-
94
- Known failing right now:
95
- - `qwen-3-5-0-8b-wq4k-ef16-hf16-f16`
96
- - `qwen-3-5-2b-wq4k-ef16-hf16-f16`
97
-
98
- For the generated status table, including `loads but unverified` and `everything else`, see [docs/model-support-matrix.md](https://github.com/clocksmith/doppler/blob/main/docs/model-support-matrix.md).
90
+ Current model support is generated from the catalog and conversion registry.
91
+ See [docs/model-support-matrix.md](https://github.com/clocksmith/doppler/blob/main/docs/model-support-matrix.md) for the canonical verified, failing, and unverified status table.
99
92
 
100
93
  ## Environment requirements
101
94
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@simulatte/doppler",
3
- "version": "0.1.6",
3
+ "version": "0.1.8",
4
4
  "description": "Browser-native WebGPU inference engine for local intent and inference loops",
5
5
  "main": "src/index.js",
6
6
  "types": "src/index.d.ts",
@@ -29,22 +29,22 @@
29
29
  "bench:chart": "node ./benchmarks/vendors/compare-chart.js",
30
30
  "bench:chart:readme": "node ./benchmarks/vendors/compare-chart.js --preset readme-evidence",
31
31
  "bench:architecture:chart": "node ./benchmarks/vendors/generate-architecture-overview-svg.js",
32
- "ci:diffusion:contract": "node tools/ci-diffusion-contract-gates.mjs",
33
- "ci:diffusion:contract:list": "node tools/ci-diffusion-contract-gates.mjs --list",
34
- "ci:training:contract": "node tools/ci-training-contract-gates.mjs",
35
- "ci:training:contract:list": "node tools/ci-training-contract-gates.mjs --list",
36
- "training:contract:delta": "node tools/emit-training-contract-delta.mjs",
37
- "training:workloads:verify": "node tools/verify-training-workload-packs.mjs --registry tools/configs/training-workloads/registry.json",
38
- "training:report-ids:publish": "node tools/publish-training-report-ids.mjs --registry tools/configs/training-workloads/registry.json",
39
- "distill:studio:mvp": "node tools/distill-studio-mvp.mjs",
40
- "distill:quality-gate": "node tools/distill-studio-quality-gate.mjs",
41
- "p2p:observability": "node tools/p2p-delivery-observability.mjs",
42
- "p2p:drill": "node tools/p2p-resilience-drill.mjs",
32
+ "ci:diffusion:contract": "node tools/ci-diffusion-contract-gates.js",
33
+ "ci:diffusion:contract:list": "node tools/ci-diffusion-contract-gates.js --list",
34
+ "ci:training:contract": "node tools/ci-training-contract-gates.js",
35
+ "ci:training:contract:list": "node tools/ci-training-contract-gates.js --list",
36
+ "training:contract:delta": "node tools/emit-training-contract-delta.js",
37
+ "training:workloads:verify": "node tools/verify-training-workload-packs.js --registry tools/configs/training-workloads/registry.json",
38
+ "training:report-ids:publish": "node tools/publish-training-report-ids.js --registry tools/configs/training-workloads/registry.json",
39
+ "distill:studio:mvp": "node tools/distill-studio-mvp.js",
40
+ "distill:quality-gate": "node tools/distill-studio-quality-gate.js",
41
+ "p2p:observability": "node tools/p2p-delivery-observability.js",
42
+ "p2p:drill": "node tools/p2p-resilience-drill.js",
43
43
  "test": "npm run test:unit",
44
- "test:unit": "node tools/run-node-tests.mjs --suite unit",
45
- "test:gpu": "node tools/run-node-tests.mjs --suite gpu",
46
- "test:coverage": "node tools/run-node-coverage.mjs",
47
- "test:coverage:report": "node tools/run-node-coverage.mjs --no-threshold",
44
+ "test:unit": "node tools/run-node-tests.js --suite unit",
45
+ "test:gpu": "node tools/run-node-tests.js --suite gpu",
46
+ "test:coverage": "node tools/run-node-coverage.js",
47
+ "test:coverage:report": "node tools/run-node-coverage.js --no-threshold",
48
48
  "test:gpu:browser": "node tools/doppler-cli.js verify --config '{\"request\":{\"suite\":\"kernels\"},\"run\":{\"surface\":\"browser\",\"browser\":{\"opfsCache\":false,\"headless\":true,\"channel\":\"chromium\",\"browserArgs\":[\"--use-angle=swiftshader\",\"--disable-vulkan-surface\"],\"console\":true}}}'",
49
49
  "agents:verify": "node tools/verify-agent-parity.js",
50
50
  "agents:freshness": "node tools/verify-agent-freshness.js",
@@ -54,6 +54,8 @@
54
54
  "api:docs:sync": "node tools/sync-api-docs.js",
55
55
  "api:docs:check": "node tools/sync-api-docs.js --check",
56
56
  "verify:model": "node tools/doppler-cli.js verify",
57
+ "quickstart:sync": "node tools/sync-quickstart-registry.js",
58
+ "quickstart:check": "node tools/sync-quickstart-registry.js --check",
57
59
  "onboarding:check": "node tools/onboarding-tooling.js check",
58
60
  "onboarding:check:strict": "node tools/onboarding-tooling.js check --strict",
59
61
  "onboarding:scaffold": "node tools/onboarding-tooling.js scaffold",
@@ -72,26 +74,20 @@
72
74
  "ci:catalog:check": "npm run registry:sync:scripts:check && npm run support:matrix:check && npm run registry:hf:check",
73
75
  "external:rdrr:index": "node tools/sync-external-rdrr-index.js",
74
76
  "external:rdrr:index:check": "node tools/sync-external-rdrr-index.js --check",
75
- "verify:embeddinggemma-300m": "node tools/run-registry-verify.js embeddinggemma-300m",
77
+ "external:support:sync": "node tools/sync-external-support-registry.js",
78
+ "external:support:check": "node tools/sync-external-support-registry.js --check",
79
+ "catalog:sync:external": "node tools/sync-catalog-from-external-support.js",
80
+ "catalog:sync:external:check": "node tools/sync-catalog-from-external-support.js --check",
81
+ "verify:gemma-3-1b-it-q4k-ehf16-af32": "node tools/run-registry-verify.js gemma-3-1b-it-q4k-ehf16-af32",
82
+ "verify:gemma-3-1b-it-wq4k-ef16-hf16": "node tools/run-registry-verify.js gemma-3-1b-it-wq4k-ef16-hf16",
83
+ "verify:gemma-3-270m-it-q4k-ehf16-af32": "node tools/run-registry-verify.js gemma-3-270m-it-q4k-ehf16-af32",
76
84
  "verify:gemma-3-270m-it-wq4k-ef16": "node tools/run-registry-verify.js gemma-3-270m-it-wq4k-ef16",
77
85
  "verify:gemma-3-270m-it-wq4k-ef16-hf16": "node tools/run-registry-verify.js gemma-3-270m-it-wq4k-ef16-hf16",
78
86
  "verify:gemma-3-270m-it-wq4k-ef16-hf16-f32": "node tools/run-registry-verify.js gemma-3-270m-it-wq4k-ef16-hf16-f32",
87
+ "verify:gemma3-1b": "node tools/run-registry-verify.js gemma3-1b",
79
88
  "verify:gemma3-270m": "node tools/run-registry-verify.js gemma3-270m",
80
- "verify:google-embeddinggemma-300m": "node tools/run-registry-verify.js google-embeddinggemma-300m",
81
- "verify:google-embeddinggemma-300m-wq4k-ef16": "node tools/run-registry-verify.js google-embeddinggemma-300m-wq4k-ef16",
82
- "verify:google-gemma-3-270m-it": "node tools/run-registry-verify.js google-gemma-3-270m-it",
83
- "verify:google-translategemma-4b-it": "node tools/run-registry-verify.js google-translategemma-4b-it",
84
- "verify:qwen-3-5-0-8b": "node tools/run-registry-verify.js qwen-3-5-0-8b",
85
- "verify:qwen-3-5-0-8b-wq4k-ef16-hf16-f16": "node tools/run-registry-verify.js qwen-3-5-0-8b-wq4k-ef16-hf16-f16",
86
- "verify:qwen-3-5-2b": "node tools/run-registry-verify.js qwen-3-5-2b",
87
- "verify:qwen-3-5-2b-wq4k-ef16-hf16-f16": "node tools/run-registry-verify.js qwen-3-5-2b-wq4k-ef16-hf16-f16",
88
- "verify:qwen-qwen3.5-0.8b": "node tools/run-registry-verify.js qwen-qwen3.5-0.8b",
89
- "verify:qwen-qwen3.5-2b": "node tools/run-registry-verify.js qwen-qwen3.5-2b",
90
- "verify:qwen3-0.8b": "node tools/run-registry-verify.js qwen3-0.8b",
91
- "verify:qwen3-2b": "node tools/run-registry-verify.js qwen3-2b",
92
- "verify:translategemma": "node tools/run-registry-verify.js translategemma",
93
- "verify:translategemma-4b": "node tools/run-registry-verify.js translategemma-4b",
94
- "verify:translategemma-4b-it-wq4k-ef16-hf16": "node tools/run-registry-verify.js translategemma-4b-it-wq4k-ef16-hf16"
89
+ "verify:google-gemma-3-1b-it": "node tools/run-registry-verify.js google-gemma-3-1b-it",
90
+ "verify:google-gemma-3-270m-it": "node tools/run-registry-verify.js google-gemma-3-270m-it"
95
91
  },
96
92
  "exports": {
97
93
  ".": {
@@ -104,6 +100,7 @@
104
100
  },
105
101
  "./tooling": {
106
102
  "types": "./src/tooling-exports.d.ts",
103
+ "browser": "./src/tooling-exports.browser.js",
107
104
  "import": "./src/tooling-exports.js"
108
105
  },
109
106
  "./internal": {
@@ -149,6 +146,7 @@
149
146
  "src",
150
147
  "src/gpu/kernels/*.wgsl",
151
148
  "README.md",
149
+ "CHANGELOG.md",
152
150
  "LICENSE",
153
151
  "NOTICE",
154
152
  "BRANDING.md",
@@ -9,6 +9,12 @@ import { DEFAULT_ADAPTER_REGISTRY_CONFIG } from '../config/schema/index.js';
9
9
 
10
10
  const { dbName: DB_NAME, dbVersion: DB_VERSION, storeName: STORE_NAME } = DEFAULT_ADAPTER_REGISTRY_CONFIG;
11
11
 
12
+ function isNodeRuntime() {
13
+ return typeof process !== 'undefined'
14
+ && !!process.versions?.node
15
+ && typeof window === 'undefined';
16
+ }
17
+
12
18
 
13
19
  class IndexedDBStorage {
14
20
  #db = null;
@@ -163,8 +169,13 @@ export class AdapterRegistry {
163
169
  this.#storage = storage;
164
170
  } else if (typeof indexedDB !== 'undefined') {
165
171
  this.#storage = new IndexedDBStorage();
166
- } else {
172
+ } else if (isNodeRuntime()) {
167
173
  this.#storage = new MemoryStorage();
174
+ } else {
175
+ throw new Error(
176
+ 'AdapterRegistry requires IndexedDB in browser environments. ' +
177
+ 'Pass explicit storage or use createMemoryRegistry() for tests.'
178
+ );
168
179
  }
169
180
  }
170
181
 
@@ -82,6 +82,20 @@ async function computeSHA256(data) {
82
82
  return Array.from(hashArray).map(b => b.toString(16).padStart(2, '0')).join('');
83
83
  }
84
84
 
85
+ function assertCompleteAdapterLayers(adapter) {
86
+ for (const [layerIndex, layer] of adapter.layers.entries()) {
87
+ for (const [moduleName, weights] of Object.entries(layer)) {
88
+ const hasA = weights?.a instanceof Float32Array && weights.a.length > 0;
89
+ const hasB = weights?.b instanceof Float32Array && weights.b.length > 0;
90
+ if (!hasA || !hasB) {
91
+ throw new Error(
92
+ `LoRA adapter layer ${layerIndex} module ${moduleName} is incomplete; both lora_a and lora_b tensors are required.`
93
+ );
94
+ }
95
+ }
96
+ }
97
+ }
98
+
85
99
  // ============================================================================
86
100
  // Core Loading Functions
87
101
  // ============================================================================
@@ -156,14 +170,14 @@ export async function loadLoRAWeights(path, options = {}) {
156
170
  if (manifest.checksum && !options.skipVerify) {
157
171
  const algorithm = manifest.checksumAlgorithm;
158
172
  if (algorithm !== 'sha256') {
159
- log.warn('LoRA', `Unsupported checksum algorithm: ${algorithm}, skipping verification`);
173
+ throw new Error(`Unsupported LoRA checksum algorithm: ${algorithm}`);
160
174
  } else if (manifest.weightsPath) {
161
175
  // Compute checksum of the weights file
162
176
  const weightsData = await fetchWithBase(manifest.weightsPath);
163
177
  const computedHash = await computeSHA256(weightsData);
164
178
  checksumValid = computedHash.toLowerCase() === manifest.checksum.toLowerCase();
165
179
  if (!checksumValid) {
166
- log.warn('LoRA', `Checksum mismatch: expected ${manifest.checksum}, got ${computedHash}`);
180
+ throw new Error(`LoRA checksum mismatch: expected ${manifest.checksum}, got ${computedHash}`);
167
181
  }
168
182
  } else if (manifest.tensors && manifest.tensors.length > 0) {
169
183
  // For inline tensors, compute checksum over concatenated tensor data
@@ -187,7 +201,7 @@ export async function loadLoRAWeights(path, options = {}) {
187
201
  const computedHash = await computeSHA256(combined.buffer);
188
202
  checksumValid = computedHash.toLowerCase() === manifest.checksum.toLowerCase();
189
203
  if (!checksumValid) {
190
- log.warn('LoRA', `Checksum mismatch: expected ${manifest.checksum}, got ${computedHash}`);
204
+ throw new Error(`LoRA checksum mismatch: expected ${manifest.checksum}, got ${computedHash}`);
191
205
  }
192
206
  }
193
207
  }
@@ -223,8 +237,7 @@ export async function loadLoRAFromManifest(manifest, options = {}) {
223
237
  for (const tensor of tensors) {
224
238
  const parsed = parseTensorName(tensor.name);
225
239
  if (!parsed) {
226
- log.warn('LoRA', `Skipping unrecognized tensor: ${tensor.name}`);
227
- continue;
240
+ throw new Error(`Unrecognized LoRA tensor name: ${tensor.name}`);
228
241
  }
229
242
 
230
243
  const data = await toFloat32Array(tensor, options);
@@ -257,6 +270,7 @@ export async function loadLoRAFromManifest(manifest, options = {}) {
257
270
  }
258
271
  }
259
272
 
273
+ assertCompleteAdapterLayers(adapter);
260
274
  return adapter;
261
275
  }
262
276
 
@@ -312,7 +326,9 @@ export async function loadLoRAFromSafetensors(data, manifest) {
312
326
  if (tensorName === '__metadata__') continue;
313
327
 
314
328
  const parsed = parseTensorName(tensorName);
315
- if (!parsed) continue;
329
+ if (!parsed) {
330
+ throw new Error(`Unrecognized LoRA safetensors tensor name: ${tensorName}`);
331
+ }
316
332
 
317
333
  const [start, end] = tensorInfo.data_offsets;
318
334
  const tensorData = new Uint8Array(data, dataOffset + start, end - start);
@@ -359,6 +375,7 @@ export async function loadLoRAFromSafetensors(data, manifest) {
359
375
  adapter.layers.set(parsed.layer, layer);
360
376
  }
361
377
 
378
+ assertCompleteAdapterLayers(adapter);
362
379
  return adapter;
363
380
  }
364
381
 
@@ -90,6 +90,11 @@ export declare class ExtensionBridgeClient {
90
90
  */
91
91
  getStatus(): BridgeStatusType;
92
92
 
93
+ /**
94
+ * Get the connected extension target, if any.
95
+ */
96
+ getExtensionId(): string | null;
97
+
93
98
  /**
94
99
  * Check if connected
95
100
  */
@@ -64,6 +64,16 @@ export class ExtensionBridgeClient {
64
64
  throw new Error('Chrome extension API not available');
65
65
  }
66
66
 
67
+ if (this.#status === BridgeStatus.CONNECTING) {
68
+ throw new Error('Bridge client connection already in progress');
69
+ }
70
+ if (this.#status === BridgeStatus.CONNECTED) {
71
+ if ((extensionId ?? null) !== this.#extensionId) {
72
+ throw new Error('Bridge client already connected to a different extension target');
73
+ }
74
+ return;
75
+ }
76
+
67
77
  this.#extensionId = extensionId;
68
78
  this.#status = BridgeStatus.CONNECTING;
69
79
  this.#notifyStatusChange();
@@ -209,6 +219,11 @@ export class ExtensionBridgeClient {
209
219
 
210
220
 
211
221
  #handleMessage(message) {
222
+ if (message?.type === 'error') {
223
+ this.#handleExplicitError(message);
224
+ return;
225
+ }
226
+
212
227
  if (message.type !== 'binary' || !message.data) {
213
228
  log.warn('ExtensionBridge', `Unexpected message type: ${message.type}`);
214
229
  return;
@@ -308,6 +323,27 @@ export class ExtensionBridgeClient {
308
323
  }
309
324
  }
310
325
 
326
+ #handleExplicitError(message) {
327
+ const text = typeof message?.message === 'string' && message.message.length > 0
328
+ ? message.message
329
+ : 'Native bridge error';
330
+ const error = new Error(text);
331
+
332
+ this.#port = null;
333
+ this.#status = BridgeStatus.ERROR;
334
+ this.#notifyStatusChange();
335
+
336
+ for (const [, pending] of this.#pendingRequests) {
337
+ clearTimeout(pending.timeout);
338
+ pending.reject(error);
339
+ }
340
+ this.#pendingRequests.clear();
341
+
342
+ if (this.onError) {
343
+ this.onError(error);
344
+ }
345
+ }
346
+
311
347
 
312
348
  #handleDisconnect() {
313
349
  const error = chrome.runtime?.lastError;
@@ -340,6 +376,10 @@ export class ExtensionBridgeClient {
340
376
  return this.#status;
341
377
  }
342
378
 
379
+ getExtensionId() {
380
+ return this.#extensionId;
381
+ }
382
+
343
383
 
344
384
  isConnected() {
345
385
  return this.#status === BridgeStatus.CONNECTED;
@@ -64,5 +64,6 @@ export declare function createBridgeClient(
64
64
  export declare function readFileNative(
65
65
  path: string,
66
66
  offset?: number,
67
- length?: number
67
+ length?: number,
68
+ extensionId?: string | null
68
69
  ): Promise<Uint8Array>;
@@ -27,24 +27,26 @@ export {
27
27
 
28
28
 
29
29
  export async function createBridgeClient(extensionId = null) {
30
- const { ExtensionBridgeClient, isBridgeAvailable } = await import('./extension-client.js');
30
+ const { getBridgeClient, isBridgeAvailable } = await import('./extension-client.js');
31
31
 
32
32
  if (!isBridgeAvailable()) {
33
33
  throw new Error('Native bridge not available - Chrome extension API required');
34
34
  }
35
35
 
36
- const client = new ExtensionBridgeClient();
36
+ const client = getBridgeClient();
37
37
  await client.connect(extensionId);
38
38
  return client;
39
39
  }
40
40
 
41
41
 
42
- export async function readFileNative(path, offset = 0, length = 0) {
42
+ export async function readFileNative(path, offset = 0, length = 0, extensionId = null) {
43
43
  const { getBridgeClient } = await import('./extension-client.js');
44
44
  const client = getBridgeClient();
45
45
 
46
46
  if (!client.isConnected()) {
47
- await client.connect();
47
+ await client.connect(extensionId);
48
+ } else if ((extensionId ?? null) !== (client.getExtensionId?.() ?? null)) {
49
+ throw new Error('Bridge client already connected to a different extension target');
48
50
  }
49
51
 
50
52
  return client.read(path, offset, length);
@@ -160,6 +160,18 @@ function normalizePath(path) {
160
160
  return String(path || '').replace(/\\/g, '/');
161
161
  }
162
162
 
163
+ function attachRelativePath(file, relativePath) {
164
+ if (!file || !relativePath) return;
165
+ try {
166
+ Object.defineProperty(file, 'relativePath', {
167
+ value: relativePath,
168
+ configurable: true,
169
+ });
170
+ } catch {
171
+ // Ignore if File is non-extensible in this environment.
172
+ }
173
+ }
174
+
163
175
  function getBaseName(path) {
164
176
  const normalized = normalizePath(path);
165
177
  if (!normalized) return '';
@@ -396,6 +408,7 @@ export async function convertModel(files, options = {}) {
396
408
  // Parse based on format
397
409
  let modelInfo;
398
410
  let config = null;
411
+ let generationConfig = null;
399
412
  let tokenizerJson = null;
400
413
  let tokenizerConfig = null;
401
414
  let tokenizerModel = null;
@@ -443,6 +456,10 @@ export async function convertModel(files, options = {}) {
443
456
  tokenizerConfig = await parseTokenizerConfigJson(auxiliary.tokenizerConfig);
444
457
  modelInfo.tokenizerConfig = tokenizerConfig;
445
458
  }
459
+ if (auxiliary.generationConfig) {
460
+ generationConfig = await parseConfigJson(auxiliary.generationConfig);
461
+ modelInfo.generationConfig = generationConfig;
462
+ }
446
463
  if (auxiliary.tokenizerModel) {
447
464
  const source = normalizeTensorSource(auxiliary.tokenizerModel);
448
465
  tokenizerModel = await source.readRange(0, source.size);
@@ -924,8 +941,16 @@ export async function pickModelFiles() {
924
941
 
925
942
  async function collectFilesFromDirectory(
926
943
  dirHandle,
927
- files = []
944
+ files = [],
945
+ basePath = '',
946
+ depth = 0
928
947
  ) {
948
+ if (depth > 4) {
949
+ throw new Error(
950
+ `Model directory exceeds supported depth (4) near "${basePath || dirHandle?.name || '.'}". ` +
951
+ 'Choose a shallower directory root or flatten the model files.'
952
+ );
953
+ }
929
954
  const entries = dirHandle.values();
930
955
  for await (const entry of entries) {
931
956
  if (entry.kind === 'file') {
@@ -937,8 +962,13 @@ async function collectFilesFromDirectory(
937
962
  file.name.endsWith('.json') ||
938
963
  file.name === 'tokenizer.model'
939
964
  ) {
965
+ const relativePath = basePath ? `${basePath}/${entry.name}` : entry.name;
966
+ attachRelativePath(file, relativePath);
940
967
  files.push(file);
941
968
  }
969
+ } else if (entry.kind === 'directory') {
970
+ const nextBasePath = basePath ? `${basePath}/${entry.name}` : entry.name;
971
+ await collectFilesFromDirectory(entry, files, nextBasePath, depth + 1);
942
972
  }
943
973
  }
944
974
  return files;
@@ -140,6 +140,12 @@ async function collectModelFilesFromDirectory(
140
140
  const nextBasePath = basePath ? `${basePath}/${entry.name}` : entry.name;
141
141
  const subFiles = await collectModelFilesFromDirectory(subDirHandle, nextBasePath, maxDepth - 1);
142
142
  files.push(...subFiles);
143
+ } else if (entry.kind === 'directory') {
144
+ const nextBasePath = basePath ? `${basePath}/${entry.name}` : entry.name;
145
+ throw new Error(
146
+ `Model directory exceeds supported depth (${MODEL_DIRECTORY_MAX_DEPTH}) near "${nextBasePath}". ` +
147
+ 'Choose a shallower directory root or flatten the model files.'
148
+ );
143
149
  }
144
150
  }
145
151