@tryhamster/gerbil 1.11.3 → 1.12.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 (58) hide show
  1. package/README.md +79 -0
  2. package/dist/{architectures-DmZMEFsA.mjs → architectures-BH_z6k9d.mjs} +14 -12
  3. package/dist/architectures-BH_z6k9d.mjs.map +1 -0
  4. package/dist/browser/index.d.ts.map +1 -1
  5. package/dist/browser/index.js +11 -0
  6. package/dist/browser/index.js.map +1 -1
  7. package/dist/cli.mjs +8 -8
  8. package/dist/cli.mjs.map +1 -1
  9. package/dist/frameworks/express.mjs +1 -1
  10. package/dist/frameworks/fastify.mjs +1 -1
  11. package/dist/frameworks/hono.mjs +1 -1
  12. package/dist/frameworks/next.d.mts +2 -2
  13. package/dist/frameworks/next.mjs +1 -1
  14. package/dist/frameworks/trpc.mjs +1 -1
  15. package/dist/gerbil-CZvoFo0T.mjs +4 -0
  16. package/dist/{gerbil-CYVmU8sQ.mjs → gerbil-CpS3P240.mjs} +13 -2
  17. package/dist/gerbil-CpS3P240.mjs.map +1 -0
  18. package/dist/{gerbil-Cu7YwBBz.d.mts → gerbil-DF009Waa.d.mts} +2 -2
  19. package/dist/{gerbil-Cu7YwBBz.d.mts.map → gerbil-DF009Waa.d.mts.map} +1 -1
  20. package/dist/gpu/hooks.d.mts +1 -1
  21. package/dist/gpu/index.d.mts +2 -2
  22. package/dist/gpu/index.mjs +4 -4
  23. package/dist/{gpu-EyIH7Qfc.mjs → gpu-DRFhiv4R.mjs} +836 -140
  24. package/dist/gpu-DRFhiv4R.mjs.map +1 -0
  25. package/dist/{index-DeKYzJgJ.d.mts → index-CNYoTRgr.d.mts} +1198 -550
  26. package/dist/index-CNYoTRgr.d.mts.map +1 -0
  27. package/dist/index.d.mts +3 -3
  28. package/dist/index.d.mts.map +1 -1
  29. package/dist/index.mjs +5 -5
  30. package/dist/index.mjs.map +1 -1
  31. package/dist/integrations/ai-sdk.mjs +1 -1
  32. package/dist/integrations/langchain.mjs +1 -1
  33. package/dist/integrations/llamaindex.mjs +1 -1
  34. package/dist/integrations/mcp.d.mts +2 -2
  35. package/dist/integrations/mcp.mjs +4 -4
  36. package/dist/{mcp-CAsD7eCj.mjs → mcp-DAbWO8VS.mjs} +3 -3
  37. package/dist/{mcp-CAsD7eCj.mjs.map → mcp-DAbWO8VS.mjs.map} +1 -1
  38. package/dist/{moonshine-stt-BXoZaHJE.mjs → moonshine-stt-B1kV5n1c.mjs} +5251 -1678
  39. package/dist/moonshine-stt-B1kV5n1c.mjs.map +1 -0
  40. package/dist/moonshine-stt-DA1WuiZb.mjs +4 -0
  41. package/dist/{one-liner-ppgw4jHH.mjs → one-liner-CmP9ktUn.mjs} +2 -2
  42. package/dist/{one-liner-ppgw4jHH.mjs.map → one-liner-CmP9ktUn.mjs.map} +1 -1
  43. package/dist/repl-17NVeIaJ.mjs +9 -0
  44. package/dist/skills/index.d.mts +2 -2
  45. package/dist/skills/index.mjs +3 -3
  46. package/dist/{skills-CQa1Gshd.mjs → skills-BDOEbHSx.mjs} +2 -2
  47. package/dist/{skills-CQa1Gshd.mjs.map → skills-BDOEbHSx.mjs.map} +1 -1
  48. package/dist/tune/index.d.mts.map +1 -1
  49. package/dist/tune/index.mjs +1 -1
  50. package/package.json +1 -1
  51. package/dist/architectures-DmZMEFsA.mjs.map +0 -1
  52. package/dist/gerbil-CTefAwKp.mjs +0 -4
  53. package/dist/gerbil-CYVmU8sQ.mjs.map +0 -1
  54. package/dist/gpu-EyIH7Qfc.mjs.map +0 -1
  55. package/dist/index-DeKYzJgJ.d.mts.map +0 -1
  56. package/dist/moonshine-stt-BXoZaHJE.mjs.map +0 -1
  57. package/dist/moonshine-stt-DZVnKgPO.mjs +0 -4
  58. package/dist/repl-C0Ew7_Z-.mjs +0 -9
package/README.md CHANGED
@@ -121,6 +121,84 @@ Reports steady-state decode tok/s, time-to-first-token, and the device it ran on
121
121
  For a copy-pasteable version see [`examples/benchmark.ts`](./examples/benchmark.ts)
122
122
  (and the rest of [`examples/`](./examples/)).
123
123
 
124
+ ### Batched decode & per-lane adapters (experimental, Node/Dawn)
125
+
126
+ On Node the engine can decode many sequences in one lockstep batch — and each lane
127
+ can run a **different LoRA adapter** over one shared base (SGMV-style). Both are
128
+ flag-gated and token-exact: every lane's output matches the same prompt run solo.
129
+
130
+ ```bash
131
+ GERBIL_BATCH=4 GERBIL_BATCH_LORA=1 node my-batch-script.mjs
132
+ ```
133
+
134
+ ```typescript
135
+ const engine = await WebGPUEngine.create({ repo: "mlx-community/Qwen3.5-0.8B-4bit" });
136
+
137
+ // Register adapters once — their factors are packed into shared GPU buffers,
138
+ // and any number of lanes can run them concurrently.
139
+ await engine.registerAdapter("pirate", "you/qwen3.5-0.8b-pirate-lora");
140
+ await engine.registerAdapter("legal", "you/qwen3.5-0.8b-legal-lora");
141
+
142
+ const results = await engine.generateBatch(
143
+ [promptA, promptB, promptC, promptD],
144
+ {
145
+ sampling: { temperature: 0 },
146
+ // Per-lane adapter selection: null = bare base model.
147
+ adapters: ["pirate", "pirate", "legal", null],
148
+ },
149
+ );
150
+
151
+ // The continuous-batching scheduler takes an adapter per request — mixed
152
+ // adapters, queueing, and slot reuse stay token-exact vs solo runs:
153
+ const scheduler = engine.createScheduler();
154
+ const reply = await scheduler.submit(prompt, {
155
+ sampling: { temperature: 0 },
156
+ adapter: "legal",
157
+ });
158
+
159
+ // And a swarm fans ONE input out across tuned members concurrently (MoTA
160
+ // mode B — one batched pass, default plan broadcasts, default reduce returns
161
+ // a member-keyed map):
162
+ const swarm = await engine.createSwarm({
163
+ members: { pirate: "you/pirate-lora", legal: "you/legal-lora", base: null },
164
+ });
165
+ const answers = await swarm.run(prompt, { sampling: { temperature: 0 } });
166
+ ```
167
+
168
+ | Env flag | Effect |
169
+ |----------|--------|
170
+ | `GERBIL_BATCH=N` | Fixed lockstep batch of N lanes (`generateBatch`), greedy decode |
171
+ | `GERBIL_BATCH_LORA=1` | Enables `registerAdapter`, the per-lane `adapters` option, per-request `adapter` on `scheduler.submit`, and `createSwarm` |
172
+ | `GERBIL_GEMM_FAST=1` | Relaxed-parity f16-accumulate GEMM tier (faster aggregate) |
173
+ | `GERBIL_DECODE_WINDOW=K` | Records K decode steps per GPU submit (2–8; Vulkan-targeted) |
174
+
175
+ ### Swarm quickstart
176
+
177
+ A swarm is a set of named specialists: LoRA adapters tuned on one shared base
178
+ model, plus optionally the bare base itself. All members decode together in one
179
+ batched pass on one GPU, so asking four specialists costs about as much as
180
+ asking the slowest one, not four times as much.
181
+
182
+ Try it with the runnable example (Node with the native GPU path):
183
+
184
+ ```bash
185
+ node scripts/engine/example-swarm.mjs
186
+ ```
187
+
188
+ With no configuration it finds tuned adapters in your local caches, or falls
189
+ back to generated demo adapters so you can see the mechanics either way. Point
190
+ it at your own tuned adapters like this:
191
+
192
+ ```bash
193
+ GERBIL_SWARM_MEMBERS="support=hf:you/support-lora,legal=hf:you/legal-lora" \
194
+ node scripts/engine/example-swarm.mjs
195
+ ```
196
+
197
+ The example shows both patterns: routing different prompts to different
198
+ members, and broadcasting one input to every member with `swarm.run()`. In
199
+ your own scripts, batched adapter decode needs `GERBIL_BATCH=N` and
200
+ `GERBIL_BATCH_LORA=1` set (the example sets them for you).
201
+
124
202
  ## React Quickstart
125
203
 
126
204
  `useEngine` (from `@tryhamster/gerbil/hooks`) owns the full engine lifecycle —
@@ -469,6 +547,7 @@ via `WebGPUEngine.create({ repo })`.
469
547
  |-------|------|-------|
470
548
  | **Qwen3.5-0.8B** | `mlx-community/Qwen3.5-0.8B-4bit` | Default text model; vision-capable (`Qwen/Qwen3.5-0.8B` for the ViT) |
471
549
  | **Qwen3.5-2B** | `Qwen/Qwen3.5-2B` | Higher quality; 262k context; multimodal (vision-capable) |
550
+ | **Qwen3.5-4B** | `mlx-community/Qwen3.5-4B-4bit` | Highest quality that fits browser WebGPU (~2.5 GB INT4); 262k context; vision-capable; thinking |
472
551
  | **LFM2.5-350M** | `LiquidAI/LFM2.5-350M` | Hybrid conv/attention, very fast, ~199 MB q4 |
473
552
  | **Gemma 4 E2B** | `mlx-community/gemma-4-e2b-it-4bit` | PLE CPU-streamed; vision-capable |
474
553
 
@@ -5826,11 +5826,12 @@ function generateQwen3_5Graph(rawConfig, dtype, groupSizeOverride, kvDtype, _emb
5826
5826
  const kv_dim = num_kv_heads * head_dim;
5827
5827
  const layerTypes = textConfig.layer_types ?? [];
5828
5828
  const fullAttentionInterval = textConfig.full_attention_interval ?? 4;
5829
- const mamba_num_heads = textConfig.linear_num_key_heads ?? 16;
5829
+ const mamba_num_k_heads = textConfig.linear_num_key_heads ?? 16;
5830
+ const mamba_num_v_heads = textConfig.linear_num_value_heads ?? mamba_num_k_heads;
5830
5831
  const mamba_key_dim = textConfig.linear_key_head_dim ?? 128;
5831
5832
  const mamba_val_dim = textConfig.linear_value_head_dim ?? 128;
5832
- const mamba_qkv_dim = mamba_num_heads * (mamba_key_dim + mamba_key_dim + mamba_val_dim);
5833
- const mamba_out_dim = mamba_num_heads * mamba_val_dim;
5833
+ const mamba_qkv_dim = 2 * mamba_num_k_heads * mamba_key_dim + mamba_num_v_heads * mamba_val_dim;
5834
+ const mamba_out_dim = mamba_num_v_heads * mamba_val_dim;
5834
5835
  const conv_kernel_dim = textConfig.linear_conv_kernel_dim ?? 4;
5835
5836
  const ropeParams = textConfig.rope_parameters;
5836
5837
  const rope_base = ropeParams?.rope_theta ?? textConfig.rope_theta ?? 1e7;
@@ -6450,13 +6451,13 @@ function generateQwen3_5Graph(rawConfig, dtype, groupSizeOverride, kvDtype, _emb
6450
6451
  });
6451
6452
  addTensor({
6452
6453
  name: aProjOut,
6453
- shape: ["T", mamba_num_heads],
6454
+ shape: ["T", mamba_num_v_heads],
6454
6455
  dtype: "f32",
6455
6456
  storage: "activation"
6456
6457
  });
6457
6458
  addTensor({
6458
6459
  name: bProjOut,
6459
- shape: ["T", mamba_num_heads],
6460
+ shape: ["T", mamba_num_v_heads],
6460
6461
  dtype: "f32",
6461
6462
  storage: "activation"
6462
6463
  });
@@ -6467,8 +6468,8 @@ function generateQwen3_5Graph(rawConfig, dtype, groupSizeOverride, kvDtype, _emb
6467
6468
  storage: "activation"
6468
6469
  });
6469
6470
  addLinearOp(`${prefix}_qkv_proj`, norm1Out, inProjQKV_W, [mamba_qkv_dim, hidden_size], qkvOut, hidden_size, mamba_qkv_dim);
6470
- addLinearOp(`${prefix}_a_proj`, norm1Out, inProjA_W, [mamba_num_heads, hidden_size], aProjOut, hidden_size, mamba_num_heads);
6471
- addLinearOp(`${prefix}_b_proj`, norm1Out, inProjB_W, [mamba_num_heads, hidden_size], bProjOut, hidden_size, mamba_num_heads);
6471
+ addLinearOp(`${prefix}_a_proj`, norm1Out, inProjA_W, [mamba_num_v_heads, hidden_size], aProjOut, hidden_size, mamba_num_v_heads);
6472
+ addLinearOp(`${prefix}_b_proj`, norm1Out, inProjB_W, [mamba_num_v_heads, hidden_size], bProjOut, hidden_size, mamba_num_v_heads);
6472
6473
  addLinearOp(`${prefix}_z_proj`, norm1Out, inProjZ_W, [mamba_out_dim, hidden_size], zProjOut, hidden_size, mamba_out_dim);
6473
6474
  const conv1dW = CANONICAL_KEYS.mambaConv1d(i);
6474
6475
  addTensor({
@@ -6522,14 +6523,14 @@ function generateQwen3_5Graph(rawConfig, dtype, groupSizeOverride, kvDtype, _emb
6522
6523
  const dtBiasW = CANONICAL_KEYS.mambaDtBias(i);
6523
6524
  addTensor({
6524
6525
  name: aLogW,
6525
- shape: [mamba_num_heads],
6526
+ shape: [mamba_num_v_heads],
6526
6527
  dtype: "f32",
6527
6528
  storage: "constant",
6528
6529
  safetensorsKey: aLogW
6529
6530
  });
6530
6531
  addTensor({
6531
6532
  name: dtBiasW,
6532
- shape: [mamba_num_heads],
6533
+ shape: [mamba_num_v_heads],
6533
6534
  dtype: "f32",
6534
6535
  storage: "constant",
6535
6536
  safetensorsKey: dtBiasW
@@ -6538,7 +6539,7 @@ function generateQwen3_5Graph(rawConfig, dtype, groupSizeOverride, kvDtype, _emb
6538
6539
  addTensor({
6539
6540
  name: ssmState,
6540
6541
  shape: [
6541
- mamba_num_heads,
6542
+ mamba_num_v_heads,
6542
6543
  mamba_key_dim,
6543
6544
  mamba_val_dim
6544
6545
  ],
@@ -6565,7 +6566,8 @@ function generateQwen3_5Graph(rawConfig, dtype, groupSizeOverride, kvDtype, _emb
6565
6566
  ],
6566
6567
  outputs: [ssmOut],
6567
6568
  attributes: {
6568
- num_heads: mamba_num_heads,
6569
+ num_heads: mamba_num_v_heads,
6570
+ num_k_heads: mamba_num_k_heads,
6569
6571
  key_dim: mamba_key_dim,
6570
6572
  val_dim: mamba_val_dim,
6571
6573
  qkv_dim: mamba_qkv_dim,
@@ -6767,4 +6769,4 @@ function isArchitectureSupported(name) {
6767
6769
 
6768
6770
  //#endregion
6769
6771
  export { kaniSinTensor as A, computeKaniPositions as C, kaniAttentionLayerIndices as D, generateNanoCodecDecoderGraph as E, CANONICAL_KEYS as F, DTYPE_BYTES as I, GEMMA4_VIS_KEYS as L, parseKaniConfig as M, DEFAULT_GROUP_SIZE as N, kaniCosTensor as O, quantizeInt4 as P, createDefaultHFKeyMapper as R, buildKaniLayerCosSin as S, generateKaniTtsGraph as T, moonshineEncoderFrames as _, PARLER_DAC_LATENT_DIM as a, KANI_START_OF_HUMAN as b, PARLER_SAMPLE_RATE as c, generateParlerEncoderGraph as d, parseParlerConfig as f, generateMoonshineEncoderGraph as g, generateMoonshineDecoderGraph as h, PARLER_DAC_DECODER_DIM as i, nanoCodecWeightMap as j, kaniLayerAlpha as k, buildT5RelativeBias as l, MOONSHINE_REMAINING_WORK as m, isArchitectureSupported as n, PARLER_DECODER_RATES as o, revertDelayPattern as p, PARLER_BOS_TOKEN_ID as r, PARLER_EOS_TOKEN_ID as s, generateGraph as t, generateParlerDecoderGraph as u, parseMoonshineConfig as v, foldNanoCodecWeightNorm as w, audioTokensToCodes as x, KANI_END_OF_HUMAN as y };
6770
- //# sourceMappingURL=architectures-DmZMEFsA.mjs.map
6772
+ //# sourceMappingURL=architectures-BH_z6k9d.mjs.map