@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.
- package/README.md +79 -0
- package/dist/{architectures-DmZMEFsA.mjs → architectures-BH_z6k9d.mjs} +14 -12
- package/dist/architectures-BH_z6k9d.mjs.map +1 -0
- package/dist/browser/index.d.ts.map +1 -1
- package/dist/browser/index.js +11 -0
- package/dist/browser/index.js.map +1 -1
- package/dist/cli.mjs +8 -8
- package/dist/cli.mjs.map +1 -1
- package/dist/frameworks/express.mjs +1 -1
- package/dist/frameworks/fastify.mjs +1 -1
- package/dist/frameworks/hono.mjs +1 -1
- package/dist/frameworks/next.d.mts +2 -2
- package/dist/frameworks/next.mjs +1 -1
- package/dist/frameworks/trpc.mjs +1 -1
- package/dist/gerbil-CZvoFo0T.mjs +4 -0
- package/dist/{gerbil-CYVmU8sQ.mjs → gerbil-CpS3P240.mjs} +13 -2
- package/dist/gerbil-CpS3P240.mjs.map +1 -0
- package/dist/{gerbil-Cu7YwBBz.d.mts → gerbil-DF009Waa.d.mts} +2 -2
- package/dist/{gerbil-Cu7YwBBz.d.mts.map → gerbil-DF009Waa.d.mts.map} +1 -1
- package/dist/gpu/hooks.d.mts +1 -1
- package/dist/gpu/index.d.mts +2 -2
- package/dist/gpu/index.mjs +4 -4
- package/dist/{gpu-EyIH7Qfc.mjs → gpu-DRFhiv4R.mjs} +836 -140
- package/dist/gpu-DRFhiv4R.mjs.map +1 -0
- package/dist/{index-DeKYzJgJ.d.mts → index-CNYoTRgr.d.mts} +1198 -550
- package/dist/index-CNYoTRgr.d.mts.map +1 -0
- package/dist/index.d.mts +3 -3
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +5 -5
- package/dist/index.mjs.map +1 -1
- package/dist/integrations/ai-sdk.mjs +1 -1
- package/dist/integrations/langchain.mjs +1 -1
- package/dist/integrations/llamaindex.mjs +1 -1
- package/dist/integrations/mcp.d.mts +2 -2
- package/dist/integrations/mcp.mjs +4 -4
- package/dist/{mcp-CAsD7eCj.mjs → mcp-DAbWO8VS.mjs} +3 -3
- package/dist/{mcp-CAsD7eCj.mjs.map → mcp-DAbWO8VS.mjs.map} +1 -1
- package/dist/{moonshine-stt-BXoZaHJE.mjs → moonshine-stt-B1kV5n1c.mjs} +5251 -1678
- package/dist/moonshine-stt-B1kV5n1c.mjs.map +1 -0
- package/dist/moonshine-stt-DA1WuiZb.mjs +4 -0
- package/dist/{one-liner-ppgw4jHH.mjs → one-liner-CmP9ktUn.mjs} +2 -2
- package/dist/{one-liner-ppgw4jHH.mjs.map → one-liner-CmP9ktUn.mjs.map} +1 -1
- package/dist/repl-17NVeIaJ.mjs +9 -0
- package/dist/skills/index.d.mts +2 -2
- package/dist/skills/index.mjs +3 -3
- package/dist/{skills-CQa1Gshd.mjs → skills-BDOEbHSx.mjs} +2 -2
- package/dist/{skills-CQa1Gshd.mjs.map → skills-BDOEbHSx.mjs.map} +1 -1
- package/dist/tune/index.d.mts.map +1 -1
- package/dist/tune/index.mjs +1 -1
- package/package.json +1 -1
- package/dist/architectures-DmZMEFsA.mjs.map +0 -1
- package/dist/gerbil-CTefAwKp.mjs +0 -4
- package/dist/gerbil-CYVmU8sQ.mjs.map +0 -1
- package/dist/gpu-EyIH7Qfc.mjs.map +0 -1
- package/dist/index-DeKYzJgJ.d.mts.map +0 -1
- package/dist/moonshine-stt-BXoZaHJE.mjs.map +0 -1
- package/dist/moonshine-stt-DZVnKgPO.mjs +0 -4
- 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
|
|
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 =
|
|
5833
|
-
const mamba_out_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",
|
|
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",
|
|
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, [
|
|
6471
|
-
addLinearOp(`${prefix}_b_proj`, norm1Out, inProjB_W, [
|
|
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: [
|
|
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: [
|
|
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
|
-
|
|
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:
|
|
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-
|
|
6772
|
+
//# sourceMappingURL=architectures-BH_z6k9d.mjs.map
|