@tryhamster/gerbil 1.1.2 → 1.2.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 (110) hide show
  1. package/README.md +18 -16
  2. package/dist/{architectures-wan0swXu.mjs → architectures-Ol7yUmKf.mjs} +128 -68
  3. package/dist/architectures-Ol7yUmKf.mjs.map +1 -0
  4. package/dist/cli.mjs +8 -8
  5. package/dist/cli.mjs.map +1 -1
  6. package/dist/{defaults-9komdrbY.mjs → defaults-bJcmOaRG.mjs} +2 -2
  7. package/dist/defaults-bJcmOaRG.mjs.map +1 -0
  8. package/dist/frameworks/express.mjs +1 -1
  9. package/dist/frameworks/fastify.mjs +1 -1
  10. package/dist/frameworks/hono.mjs +1 -1
  11. package/dist/frameworks/next.d.mts +2 -2
  12. package/dist/frameworks/next.mjs +1 -1
  13. package/dist/frameworks/trpc.mjs +1 -1
  14. package/dist/gerbil-BjGA5L2E.mjs +4 -0
  15. package/dist/{gerbil-DZbWbIm2.d.mts → gerbil-CCVOEU-J.d.mts} +2 -2
  16. package/dist/{gerbil-DZbWbIm2.d.mts.map → gerbil-CCVOEU-J.d.mts.map} +1 -1
  17. package/dist/{gerbil-CQspp8fS.mjs → gerbil-Cv7rXGOV.mjs} +2 -2
  18. package/dist/{gerbil-CQspp8fS.mjs.map → gerbil-Cv7rXGOV.mjs.map} +1 -1
  19. package/dist/gpu/hooks.d.mts +27 -10
  20. package/dist/gpu/hooks.d.mts.map +1 -1
  21. package/dist/gpu/hooks.mjs +19 -12
  22. package/dist/gpu/hooks.mjs.map +1 -1
  23. package/dist/gpu/index.d.mts +2 -2
  24. package/dist/gpu/index.mjs +5 -5
  25. package/dist/{gpu-BYCQ5aTI.mjs → gpu-BWLMlkVW.mjs} +78 -21
  26. package/dist/gpu-BWLMlkVW.mjs.map +1 -0
  27. package/dist/{index-CKszv3lt.d.mts → index-CSLqgNu-.d.mts} +212 -133
  28. package/dist/index-CSLqgNu-.d.mts.map +1 -0
  29. package/dist/index.d.mts +2 -2
  30. package/dist/index.mjs +6 -6
  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-CszII8GJ.mjs → mcp-C0yKaH39.mjs} +3 -3
  37. package/dist/{mcp-CszII8GJ.mjs.map → mcp-C0yKaH39.mjs.map} +1 -1
  38. package/dist/{moonshine-stt-DDUm5WfP.mjs → moonshine-stt-C4GKK-h5.mjs} +45 -5
  39. package/dist/{moonshine-stt-DDUm5WfP.mjs.map → moonshine-stt-C4GKK-h5.mjs.map} +1 -1
  40. package/dist/moonshine-stt-zJ9YEi1X.mjs +4 -0
  41. package/dist/{one-liner-DVche8Eg.mjs → one-liner-DfJh2O0X.mjs} +2 -2
  42. package/dist/{one-liner-DVche8Eg.mjs.map → one-liner-DfJh2O0X.mjs.map} +1 -1
  43. package/dist/repl-DTSxHD6t.mjs +9 -0
  44. package/dist/skills/index.d.mts +2 -2
  45. package/dist/skills/index.d.mts.map +1 -1
  46. package/dist/skills/index.mjs +3 -3
  47. package/dist/{skills-BQI-VSn2.mjs → skills-B5cDRVJ1.mjs} +2 -2
  48. package/dist/{skills-BQI-VSn2.mjs.map → skills-B5cDRVJ1.mjs.map} +1 -1
  49. package/package.json +1 -2
  50. package/dist/architectures-wan0swXu.mjs.map +0 -1
  51. package/dist/defaults-9komdrbY.mjs.map +0 -1
  52. package/dist/gerbil-tHnYb9nZ.mjs +0 -4
  53. package/dist/gpu-BYCQ5aTI.mjs.map +0 -1
  54. package/dist/index-CKszv3lt.d.mts.map +0 -1
  55. package/dist/moonshine-stt-BtR-KiSP.mjs +0 -4
  56. package/dist/repl-BYJA2U7t.mjs +0 -9
  57. package/docs/PROJECT-STATE.md +0 -321
  58. package/docs/adding-a-model-family.md +0 -280
  59. package/docs/ai-sdk.md +0 -205
  60. package/docs/architecture/README.md +0 -84
  61. package/docs/architecture/caching.md +0 -227
  62. package/docs/architecture/inference.md +0 -176
  63. package/docs/architecture/overview.md +0 -189
  64. package/docs/architecture/streaming.md +0 -261
  65. package/docs/architecture/webgpu.md +0 -213
  66. package/docs/browser.md +0 -762
  67. package/docs/cli.md +0 -155
  68. package/docs/embeddings.md +0 -156
  69. package/docs/frameworks.md +0 -90
  70. package/docs/gerbil-site-native-migration.md +0 -217
  71. package/docs/gpu-engine/architectures.md +0 -398
  72. package/docs/gpu-engine/ir.md +0 -372
  73. package/docs/gpu-engine/kernels.md +0 -718
  74. package/docs/gpu-engine/paper.html +0 -1759
  75. package/docs/gpu-engine/paper.md +0 -2109
  76. package/docs/gpu-engine/safetensors.md +0 -312
  77. package/docs/gpu-engine/tokenizer.md +0 -302
  78. package/docs/kernel-research-queue.md +0 -85
  79. package/docs/mcp-client.md +0 -224
  80. package/docs/mcp.md +0 -109
  81. package/docs/memory-rag.md +0 -91
  82. package/docs/memory.md +0 -301
  83. package/docs/metal-safari-intel.md +0 -190
  84. package/docs/mobile-failure-diagnosis.md +0 -124
  85. package/docs/mobile.md +0 -99
  86. package/docs/observability.md +0 -230
  87. package/docs/onnx-removal-plan.md +0 -339
  88. package/docs/repl.md +0 -473
  89. package/docs/research/autoresearch-portable.md +0 -933
  90. package/docs/research/dispatch-reduction-hivemind.md +0 -84
  91. package/docs/research/ios-safari-model-caching.md +0 -117
  92. package/docs/research/mobile-webgpu-speed-fusion.md +0 -135
  93. package/docs/research/native-stt-model-selection.md +0 -49
  94. package/docs/research/native-tts-model-selection.md +0 -90
  95. package/docs/research/native-vs-chromium-decision.md +0 -152
  96. package/docs/research/nemotron-mamba2-inference.md +0 -910
  97. package/docs/research/qwen35-multimodal.md +0 -293
  98. package/docs/research/qwen36-gemma4-targets.md +0 -337
  99. package/docs/research/sota-embedding-models.md +0 -179
  100. package/docs/research/sota-mobile-models-2026.md +0 -263
  101. package/docs/research/sota-modality-models.md +0 -202
  102. package/docs/research/tps-baselines.md +0 -71
  103. package/docs/research/webgpu-m4-reference.md +0 -104
  104. package/docs/site-update-plan.md +0 -155
  105. package/docs/skills.md +0 -261
  106. package/docs/structured-output.md +0 -123
  107. package/docs/stt.md +0 -111
  108. package/docs/tools.md +0 -304
  109. package/docs/tts.md +0 -147
  110. package/docs/vision.md +0 -158
package/README.md CHANGED
@@ -123,12 +123,12 @@ For a copy-pasteable version see [`examples/benchmark.ts`](./examples/benchmark.
123
123
 
124
124
  ## React Quickstart
125
125
 
126
- `useEngine` (from `@tryhamster/gerbil/gpu/hooks`) owns the full engine lifecycle —
126
+ `useEngine` (from `@tryhamster/gerbil/hooks`) owns the full engine lifecycle —
127
127
  load, unload, hot-swap on config change, and reference-counted sharing so multiple
128
128
  components never upload the same weights to the GPU twice.
129
129
 
130
130
  ```tsx
131
- import { useEngine } from "@tryhamster/gerbil/gpu/hooks";
131
+ import { useEngine } from "@tryhamster/gerbil/hooks";
132
132
 
133
133
  function Chat() {
134
134
  const { complete, completion, isLoading, isGenerating, tps } = useEngine({
@@ -156,7 +156,7 @@ and `dispose`. Pass `enableVision: true` or `embedding: true` to load those moda
156
156
  until the engine is ready — and keep it warm across navigation (no GPU re-upload):
157
157
 
158
158
  ```tsx
159
- import { GerbilGate } from "@tryhamster/gerbil/gpu/hooks";
159
+ import { GerbilGate } from "@tryhamster/gerbil/hooks";
160
160
 
161
161
  <GerbilGate
162
162
  model="mlx-community/Qwen3.5-0.8B-4bit"
@@ -199,10 +199,10 @@ const engine = await WebGPUEngine.create({ repo: "mlx-community/Qwen3.5-0.8B-4bi
199
199
  await engine.generateObject("…", { schema: { required: ["title"] } });
200
200
  ```
201
201
 
202
- In React, use `useObject` (from `@tryhamster/gerbil/gpu/hooks`):
202
+ In React, use `useObject` (from `@tryhamster/gerbil/hooks`):
203
203
 
204
204
  ```tsx
205
- import { useObject } from "@tryhamster/gerbil/gpu/hooks";
205
+ import { useObject } from "@tryhamster/gerbil/hooks";
206
206
 
207
207
  const { generate, object, isGenerating } = useObject<{ city: string }>();
208
208
  await generate("Extract the city from: I live in Paris", {
@@ -322,17 +322,19 @@ const skill = useSkill("my-skill");
322
322
 
323
323
  ## Tools & Agents
324
324
 
325
- Gerbil supports tool calling with Qwen3 models for agentic workflows:
325
+ Gerbil supports tool calling with Qwen3 models for agentic workflows. A tool is a
326
+ plain object (`AgentTool`) — give it a `name`, `description`, optional `parameters`,
327
+ and an `execute` function:
326
328
 
327
329
  ```typescript
328
- import { defineTool, executeToolCall } from "@tryhamster/gerbil";
330
+ import type { AgentTool } from "@tryhamster/gerbil/gpu";
329
331
 
330
- const weatherTool = defineTool({
332
+ const weatherTool: AgentTool = {
331
333
  name: "get_weather",
332
334
  description: "Get weather for a city",
333
- parameters: z.object({ city: z.string() }),
334
- execute: async ({ city }) => `Weather in ${city}: 72°F, sunny`,
335
- });
335
+ parameters: { city: "string" },
336
+ execute: ({ city }) => `Weather in ${city}: 72°F, sunny`,
337
+ };
336
338
  ```
337
339
 
338
340
  **Agentic loop, on-device.** `engine.generateWithTools` (and the `useAgent` React hook)
@@ -340,7 +342,7 @@ run the whole loop — generate → call a tool → feed the result back → rep
340
342
  step trace for UIs:
341
343
 
342
344
  ```tsx
343
- import { useAgent } from "@tryhamster/gerbil/gpu/hooks";
345
+ import { useAgent } from "@tryhamster/gerbil/hooks";
344
346
 
345
347
  const { run, steps, answer, isRunning } = useAgent({
346
348
  model: "mlx-community/Qwen3.5-0.8B-4bit",
@@ -377,7 +379,7 @@ Inline autocomplete — `engine.autocomplete(prefix)` and the debounced `useAuto
377
379
  hook return a brief single-line continuation (low-latency defaults + cleanup):
378
380
 
379
381
  ```tsx
380
- import { useAutocomplete } from "@tryhamster/gerbil/gpu/hooks";
382
+ import { useAutocomplete } from "@tryhamster/gerbil/hooks";
381
383
 
382
384
  const { suggestion, onInput, accept, dismiss } = useAutocomplete({
383
385
  model: "mlx-community/Qwen3.5-0.8B-4bit",
@@ -418,10 +420,10 @@ gerbil update # Update to latest version
418
420
  ## Browser Usage
419
421
 
420
422
  Run LLMs directly in the browser with WebGPU — no server required. The React hooks
421
- live at `@tryhamster/gerbil/gpu/hooks` and run pure WebGPU compute:
423
+ live at `@tryhamster/gerbil/hooks` and run pure WebGPU compute:
422
424
 
423
425
  ```tsx
424
- import { useChat } from "@tryhamster/gerbil/gpu/hooks";
426
+ import { useChat } from "@tryhamster/gerbil/hooks";
425
427
 
426
428
  function Chat() {
427
429
  const { messages, send, isLoading, isGenerating } = useChat();
@@ -454,7 +456,7 @@ function Chat() {
454
456
  | **LangChain** | `@tryhamster/gerbil/langchain` | [📖 LangChain](https://gerbilsdk.com/docs/frameworks/langchain) |
455
457
  | **MCP Server** | `npx @tryhamster/gerbil serve --mcp` | [📖 MCP](https://gerbilsdk.com/docs/mcp) |
456
458
 
457
- **Native engine:** `import { WebGPUEngine } from "@tryhamster/gerbil/gpu"` (or `useEngine` from `@tryhamster/gerbil/gpu/hooks` for React) is the primary surface for text, vision, embeddings, and speech.
459
+ **Native engine:** `import { WebGPUEngine } from "@tryhamster/gerbil/gpu"` (or `useEngine` from `@tryhamster/gerbil/hooks` for React) is the primary surface for text, vision, embeddings, and speech.
458
460
 
459
461
  ## Supported Models
460
462
 
@@ -148,6 +148,66 @@ function createDefaultHFKeyMapper() {
148
148
  };
149
149
  }
150
150
 
151
+ //#endregion
152
+ //#region src/gpu/quantize.ts
153
+ /**
154
+ * On-the-fly INT4 quantization for WebGPU inference.
155
+ *
156
+ * Converts F32 weight matrices to 4-bit unsigned integers with per-group
157
+ * scale/zero-point parameters. Matches the dequantization formula in the
158
+ * MatMulInt4 WGSL kernel:
159
+ *
160
+ * dequant_val = (raw_nibble - zero) * scale
161
+ *
162
+ * Packing: 8 × 4-bit values per u32, little-nibble-first order.
163
+ * Grouping: contiguous elements in row-major (K × N) layout.
164
+ */
165
+ const DEFAULT_GROUP_SIZE = 128;
166
+ /**
167
+ * Quantize a flat F32 weight array to INT4.
168
+ *
169
+ * @param data - Source F32 weight data (row-major, K × N elements)
170
+ * @param groupSize - Number of elements per quantization group (default 128)
171
+ * @returns Packed INT4 data with per-group scales and zeros
172
+ */
173
+ function quantizeInt4(data, groupSize = DEFAULT_GROUP_SIZE) {
174
+ const totalElements = data.length;
175
+ const numGroups = Math.ceil(totalElements / groupSize);
176
+ const packedSize = Math.ceil(totalElements / 8);
177
+ const packed = new Uint32Array(packedSize);
178
+ const scales = new Float32Array(numGroups);
179
+ const zeros = new Float32Array(numGroups);
180
+ for (let g = 0; g < numGroups; g++) {
181
+ const start = g * groupSize;
182
+ const end = Math.min(start + groupSize, totalElements);
183
+ let min = data[start];
184
+ let max = data[start];
185
+ for (let i = start + 1; i < end; i++) {
186
+ const v = data[i];
187
+ if (v < min) min = v;
188
+ if (v > max) max = v;
189
+ }
190
+ const range = max - min;
191
+ const scale = range > 0 ? range / 15 : 1;
192
+ const zero = range > 0 ? -min / scale : 0;
193
+ scales[g] = scale;
194
+ zeros[g] = zero;
195
+ const invRange = range > 0 ? 15 / range : 0;
196
+ for (let i = start; i < end; i++) {
197
+ const q = Math.round((data[i] - min) * invRange);
198
+ const clamped = q < 0 ? 0 : q > 15 ? 15 : q;
199
+ const packedIdx = i >>> 3;
200
+ const nibblePos = i & 7;
201
+ packed[packedIdx] |= clamped << nibblePos * 4;
202
+ }
203
+ }
204
+ return {
205
+ packed,
206
+ scales,
207
+ zeros
208
+ };
209
+ }
210
+
151
211
  //#endregion
152
212
  //#region src/gpu/architectures/kani_tts.ts
153
213
  const KANI_TOKENISER_LENGTH = 64400;
@@ -195,19 +255,23 @@ const NANOCODEC_BASE_CHANNELS = 864;
195
255
  const NANOCODEC_INPUT_DIM = 16;
196
256
  function parseKaniConfig(rawConfig) {
197
257
  const textVocabSize = rawConfig.text_vocab_size ?? KANI_TOKENISER_LENGTH;
258
+ const useLearnableRope = rawConfig.use_learnable_rope ?? false;
259
+ const archList = rawConfig.architectures ?? [];
260
+ const isKaniTTS2 = useLearnableRope || rawConfig.tokens_per_frame != null || rawConfig.audio_step != null || archList.includes("KaniTTS2ForCausalLM");
198
261
  return {
199
262
  textVocabSize,
200
263
  vocabSize: rawConfig.vocab_size,
201
264
  tokensPerFrame: rawConfig.tokens_per_frame ?? KANI_TOKENS_PER_FRAME,
202
265
  audioStep: rawConfig.audio_step ?? 1,
203
- useLearnableRope: rawConfig.use_learnable_rope ?? false,
266
+ useLearnableRope,
204
267
  alphaMin: rawConfig.alpha_min ?? .1,
205
268
  alphaMax: rawConfig.alpha_max ?? 2,
206
269
  speakerEmbDim: rawConfig.speaker_emb_dim ?? 128,
207
270
  audioTokensStart: textVocabSize + 10,
208
271
  startOfSpeech: textVocabSize + 1,
209
272
  endOfSpeech: textVocabSize + 2,
210
- codebookSize: KANI_CODEBOOK_SIZE
273
+ codebookSize: KANI_CODEBOOK_SIZE,
274
+ frameLevelPositions: isKaniTTS2
211
275
  };
212
276
  }
213
277
  /**
@@ -249,6 +313,10 @@ function kaniAttentionLayerIndices(rawConfig) {
249
313
  */
250
314
  function computeKaniPositions(tokenIds, cfg = parseKaniConfig({})) {
251
315
  const pos = new Float32Array(tokenIds.length);
316
+ if (!cfg.frameLevelPositions) {
317
+ for (let t = 0; t < tokenIds.length; t++) pos[t] = t;
318
+ return pos;
319
+ }
252
320
  let textCount = 0;
253
321
  let audioTokenCount = 0;
254
322
  for (let t = 0; t < tokenIds.length; t++) {
@@ -652,15 +720,25 @@ function computeKaniFfnDim(rawConfig) {
652
720
  return ff;
653
721
  }
654
722
  /**
655
- * Generate the KaniTTS2 codec-LM backbone graph (LFM2-350M body, full-vocab logits,
723
+ * Generate the KaniTTS codec-LM backbone graph (LFM2-350M body, full-vocab logits,
656
724
  * per-layer learnable MRoPE). Mirrors generateLfm2Graph block-for-block; the only
657
725
  * difference is that each attention layer rotates Q/K with the MRoPE op fed a
658
726
  * per-layer host cos/sin table instead of the position-counter RoPE op.
659
727
  *
660
- * f32 only (the checkpoint is bf16→f32; q4 would need the codec-LM head re-validated).
728
+ * dtype:
729
+ * • undefined / "f32" — full precision (the checkpoint is bf16/f32 → f32).
730
+ * • "q4" — weight-only group-wise INT4 (W4A16) for the LFM2 linear projections
731
+ * (q/k/v/o, gate/up/down, short-conv in/out_proj) via MatMulInt4. The tied
732
+ * embedding + LM head stay at f32 on purpose: decoder-LM heads are the most
733
+ * quantization-sensitive part of a codec-LM and the embed table is the single
734
+ * buffer shared by both, so quantizing it would degrade audio quality for no
735
+ * load-size win that the int4 projections do not already capture. Backbone
736
+ * drops from ~1.5 GB (f32) to ~0.37 GB. The NanoCodec decoder is a separate
737
+ * graph and always runs f32.
661
738
  */
662
- function generateKaniTtsGraph(rawConfig, dtype, _groupSize, kvDtype) {
663
- if (dtype === "q4") throw new Error("Kani-TTS-2 codec-LM backbone supports f32 only (load without dtype: 'q4').");
739
+ function generateKaniTtsGraph(rawConfig, dtype, groupSize, kvDtype) {
740
+ const useQ4 = dtype === "q4";
741
+ const groupSz = groupSize ?? DEFAULT_GROUP_SIZE;
664
742
  const hidden_size = rawConfig.hidden_size;
665
743
  const num_layers = rawConfig.num_hidden_layers;
666
744
  const num_heads = rawConfig.num_attention_heads;
@@ -711,6 +789,48 @@ function generateKaniTtsGraph(rawConfig, dtype, _groupSize, kvDtype) {
711
789
  executionOrder.push(node.id);
712
790
  };
713
791
  const addLinear = (id, activationInput, weightName, weightShape, outputName, K, N) => {
792
+ if (useQ4) {
793
+ const wQ = `${weightName}.q`;
794
+ const wScales = `${weightName}.scales`;
795
+ const wZeros = `${weightName}.zeros`;
796
+ const totalElements = K * N;
797
+ addTensor({
798
+ name: wQ,
799
+ shape: [Math.ceil(totalElements / 8)],
800
+ dtype: "u32",
801
+ storage: "constant"
802
+ });
803
+ addTensor({
804
+ name: wScales,
805
+ shape: [Math.ceil(totalElements / groupSz)],
806
+ dtype: "f32",
807
+ storage: "constant"
808
+ });
809
+ addTensor({
810
+ name: wZeros,
811
+ shape: [Math.ceil(totalElements / groupSz)],
812
+ dtype: "f32",
813
+ storage: "constant"
814
+ });
815
+ addNode({
816
+ id,
817
+ opType: "MatMulInt4",
818
+ inputs: [
819
+ activationInput,
820
+ wQ,
821
+ wScales,
822
+ wZeros
823
+ ],
824
+ outputs: [outputName],
825
+ attributes: {
826
+ M_tensor: activationInput,
827
+ K,
828
+ N,
829
+ group_size: groupSz
830
+ }
831
+ });
832
+ return;
833
+ }
714
834
  addTensor({
715
835
  name: weightName,
716
836
  shape: weightShape,
@@ -1239,66 +1359,6 @@ function generateKaniTtsGraph(rawConfig, dtype, _groupSize, kvDtype) {
1239
1359
  };
1240
1360
  }
1241
1361
 
1242
- //#endregion
1243
- //#region src/gpu/quantize.ts
1244
- /**
1245
- * On-the-fly INT4 quantization for WebGPU inference.
1246
- *
1247
- * Converts F32 weight matrices to 4-bit unsigned integers with per-group
1248
- * scale/zero-point parameters. Matches the dequantization formula in the
1249
- * MatMulInt4 WGSL kernel:
1250
- *
1251
- * dequant_val = (raw_nibble - zero) * scale
1252
- *
1253
- * Packing: 8 × 4-bit values per u32, little-nibble-first order.
1254
- * Grouping: contiguous elements in row-major (K × N) layout.
1255
- */
1256
- const DEFAULT_GROUP_SIZE = 128;
1257
- /**
1258
- * Quantize a flat F32 weight array to INT4.
1259
- *
1260
- * @param data - Source F32 weight data (row-major, K × N elements)
1261
- * @param groupSize - Number of elements per quantization group (default 128)
1262
- * @returns Packed INT4 data with per-group scales and zeros
1263
- */
1264
- function quantizeInt4(data, groupSize = DEFAULT_GROUP_SIZE) {
1265
- const totalElements = data.length;
1266
- const numGroups = Math.ceil(totalElements / groupSize);
1267
- const packedSize = Math.ceil(totalElements / 8);
1268
- const packed = new Uint32Array(packedSize);
1269
- const scales = new Float32Array(numGroups);
1270
- const zeros = new Float32Array(numGroups);
1271
- for (let g = 0; g < numGroups; g++) {
1272
- const start = g * groupSize;
1273
- const end = Math.min(start + groupSize, totalElements);
1274
- let min = data[start];
1275
- let max = data[start];
1276
- for (let i = start + 1; i < end; i++) {
1277
- const v = data[i];
1278
- if (v < min) min = v;
1279
- if (v > max) max = v;
1280
- }
1281
- const range = max - min;
1282
- const scale = range > 0 ? range / 15 : 1;
1283
- const zero = range > 0 ? -min / scale : 0;
1284
- scales[g] = scale;
1285
- zeros[g] = zero;
1286
- const invRange = range > 0 ? 15 / range : 0;
1287
- for (let i = start; i < end; i++) {
1288
- const q = Math.round((data[i] - min) * invRange);
1289
- const clamped = q < 0 ? 0 : q > 15 ? 15 : q;
1290
- const packedIdx = i >>> 3;
1291
- const nibblePos = i & 7;
1292
- packed[packedIdx] |= clamped << nibblePos * 4;
1293
- }
1294
- }
1295
- return {
1296
- packed,
1297
- scales,
1298
- zeros
1299
- };
1300
- }
1301
-
1302
1362
  //#endregion
1303
1363
  //#region src/gpu/architectures/gemma3_encoder.ts
1304
1364
  function generateGemma3EncoderGraph(rawConfig, dtype, groupSizeOverride, _kvDtype, _embedding) {
@@ -6059,5 +6119,5 @@ function isArchitectureSupported(name) {
6059
6119
  }
6060
6120
 
6061
6121
  //#endregion
6062
- export { parseKaniConfig as C, createDefaultHFKeyMapper as D, GEMMA4_VIS_KEYS as E, nanoCodecWeightMap as S, DTYPE_BYTES as T, generateNanoCodecDecoderGraph as _, generateMoonshineEncoderGraph as a, kaniLayerAlpha as b, DEFAULT_GROUP_SIZE as c, KANI_START_OF_HUMAN as d, audioTokensToCodes as f, generateKaniTtsGraph as g, foldNanoCodecWeightNorm as h, generateMoonshineDecoderGraph as i, quantizeInt4 as l, computeKaniPositions as m, isArchitectureSupported as n, moonshineEncoderFrames as o, buildKaniLayerCosSin as p, MOONSHINE_REMAINING_WORK as r, parseMoonshineConfig as s, generateGraph as t, KANI_END_OF_HUMAN as u, kaniAttentionLayerIndices as v, CANONICAL_KEYS as w, kaniSinTensor as x, kaniCosTensor as y };
6063
- //# sourceMappingURL=architectures-wan0swXu.mjs.map
6122
+ export { quantizeInt4 as C, createDefaultHFKeyMapper as D, GEMMA4_VIS_KEYS as E, DEFAULT_GROUP_SIZE as S, DTYPE_BYTES as T, kaniCosTensor as _, generateMoonshineEncoderGraph as a, nanoCodecWeightMap as b, KANI_END_OF_HUMAN as c, buildKaniLayerCosSin as d, computeKaniPositions as f, kaniAttentionLayerIndices as g, generateNanoCodecDecoderGraph as h, generateMoonshineDecoderGraph as i, KANI_START_OF_HUMAN as l, generateKaniTtsGraph as m, isArchitectureSupported as n, moonshineEncoderFrames as o, foldNanoCodecWeightNorm as p, MOONSHINE_REMAINING_WORK as r, parseMoonshineConfig as s, generateGraph as t, audioTokensToCodes as u, kaniLayerAlpha as v, CANONICAL_KEYS as w, parseKaniConfig as x, kaniSinTensor as y };
6123
+ //# sourceMappingURL=architectures-Ol7yUmKf.mjs.map