@tryhamster/gerbil 1.11.4 → 1.13.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 +104 -0
- package/dist/{architectures-DmZMEFsA.mjs → architectures-DHwj9AQD.mjs} +50 -38
- package/dist/architectures-DHwj9AQD.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/{defaults-DfGx4d1m.mjs → defaults-B0aQZJTM.mjs} +3 -2
- package/dist/defaults-B0aQZJTM.mjs.map +1 -0
- 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-Bw6do78d.mjs +4 -0
- package/dist/{gerbil-5_80K0gA.d.mts → gerbil-CD_skiL3.d.mts} +2 -2
- package/dist/{gerbil-5_80K0gA.d.mts.map → gerbil-CD_skiL3.d.mts.map} +1 -1
- package/dist/{gerbil-CYVmU8sQ.mjs → gerbil-DAz_a4Jh.mjs} +33 -13
- package/dist/gerbil-DAz_a4Jh.mjs.map +1 -0
- package/dist/gpu/hooks.d.mts +1 -1
- package/dist/gpu/hooks.mjs +1 -1
- package/dist/gpu/index.d.mts +2 -2
- package/dist/gpu/index.mjs +5 -5
- package/dist/{gpu-CrzjQHv2.mjs → gpu-CU_Mldk0.mjs} +1959 -198
- package/dist/gpu-CU_Mldk0.mjs.map +1 -0
- package/dist/index-B3tjyDJI.d.mts.map +1 -1
- package/dist/{index-h8TDu1qm.d.mts → index-Fj2XkP-o.d.mts} +1946 -938
- package/dist/index-Fj2XkP-o.d.mts.map +1 -0
- package/dist/index.d.mts +3 -3
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +6 -6
- 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-CdMvLQ_9.mjs} +3 -3
- package/dist/{mcp-CAsD7eCj.mjs.map → mcp-CdMvLQ_9.mjs.map} +1 -1
- package/dist/{moonshine-stt-BXoZaHJE.mjs → moonshine-stt-COJeK2Zb.mjs} +6348 -2000
- package/dist/moonshine-stt-COJeK2Zb.mjs.map +1 -0
- package/dist/moonshine-stt-Dp4j5JEB.mjs +4 -0
- package/dist/{one-liner-ppgw4jHH.mjs → one-liner-CMiGNWJ7.mjs} +2 -2
- package/dist/{one-liner-ppgw4jHH.mjs.map → one-liner-CMiGNWJ7.mjs.map} +1 -1
- package/dist/repl-BhaLCJFb.mjs +9 -0
- package/dist/skills/index.d.mts +4 -4
- package/dist/skills/index.mjs +3 -3
- package/dist/{skills-CQa1Gshd.mjs → skills-BXybFWlG.mjs} +2 -2
- package/dist/{skills-CQa1Gshd.mjs.map → skills-BXybFWlG.mjs.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/defaults-DfGx4d1m.mjs.map +0 -1
- package/dist/gerbil-CTefAwKp.mjs +0 -4
- package/dist/gerbil-CYVmU8sQ.mjs.map +0 -1
- package/dist/gpu-CrzjQHv2.mjs.map +0 -1
- package/dist/index-h8TDu1qm.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
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gpu-CU_Mldk0.mjs","names":["tensors: Record<string, TensorDesc>","nodes: OpNode[]","executionOrder: string[]","tensors: Record<string, TensorDesc>","nodes: OpNode[]","executionOrder: string[]","DEFAULT_MAX_NEW_TOKENS","selectGraphWeights","nucleusSample","pick","softmaxInPlace","prompt: number[]","seq: number[]","audioTokens: number[]","_heapIndices: Uint32Array | null","_heapValues: Float32Array | null","argmax","penaltySet: Set<number> | null","cumulative","adapterReg: { id: number; deltas: LoRADelta[] } | null","messages: ChatMessage[]","req: Request","rows: Array<{ slot: number; req: Request }>","out: Record<string, ServeResult>","out: number[]","byIndex: number[]","config: ModelArchConfig","capabilities: ModelCapabilities","tensors: Record<string, TensorDesc>","nodes: OpNode[]","executionOrder: string[]","kvCacheDtype: DType","pendingNorm1Out: string | null","norm1Out: string","DEFAULT_MAX_FRAMES","selectGraphWeights","pick","frames: Uint32Array[]","graphOutputs: string[]","c1: number[]","c2: number[]","tensors: Record<string, TensorDesc>","nodes: OpNode[]","executionOrder: string[]","kvCacheDtype: DType","config: ModelArchConfig","out: AlignedWord[]","runs: SpeechRun[]","blocks: string[]","resp","selectGraphWeights","argmax","pick","siftDown","words: OuteSpeakerWord[]","seq: number[]","generated: number[]","scores","MAP_MODE_READ","allowed: Int32Array | null","pick","sizes: Array<[number, number, number]>","encK: Float32Array[]","encV: Float32Array[]","resolved: Record<string, number[]>","entries: Array<{ buffer: GPUBuffer }>","embedTokens: Float32Array[]","data: ArrayBufferView","sizes: Array<[number, number, number]>","batchEnc: GPUCommandEncoder | null","batchPass: GPUComputePassEncoder | null","rows","enc","p","resolved: Record<string, number[]>","entries: Array<{ buffer: GPUBuffer }>","GEMMA4_IMAGE_PROCESSOR: ImageProcessorConfig","QWEN3_5_IMAGE_PROCESSOR: ImageProcessorConfig","DEFAULT_PROBE: WebkitGroupProbe","next: WebkitGroupProbe","kvMode: KvMode","visionBundle: {\n executor: VisionExecutor;\n config: Record<string, unknown>;\n posEmbedTable: Float32Array;\n } | null","VisionExecutorImpl","maxSeqLen: number","webkitGroupSize: number | undefined","host","laneAdapters: Array<{ id: number; deltas: LoRADelta[] } | null>","messages: ChatMessage[]","inputIds: number[]","generatedIds: number[]","finishReason: GenerateResult[\"finishReason\"]","nextToken: number","steps: AgentStep[]","answer: AgentStep","callStep: AgentStep","resultText: string","resultStep: AgentStep","value: unknown","speakOpts: ParlerSpeakOptions","g4patches: Float32Array","g4gridHW: [number, number]","pre","gThw: [number, number, number]","numPatches","vision","imageTokenId","imageRun: number[]","imageRun","inputIds","patches: Float32Array","gridTHW: [number, number, number]","input","ids","cap","tokenQueue: string[]","resolve: (() => void) | null","checks: IntegrityCheckEntry[]","argmax","entry: IntegrityCheckEntry","e: any","reference: Record<string, { sum: number; first4: number[] }>","release!: () => void"],"sources":["../src/gpu/architectures/gemma4_vision.ts","../src/gpu/architectures/qwen3_5_vision.ts","../src/gpu/kani-tts.ts","../src/gpu/autocomplete-clean.ts","../src/gpu/sampler.ts","../src/gpu/batch/scheduler.ts","../src/gpu/batch/swarm.ts","../src/gpu/architectures/gepard_tts.ts","../src/gpu/gepard-tts.ts","../src/gpu/architectures/outetts.ts","../src/gpu/outetts-encode.ts","../src/gpu/outetts.ts","../src/gpu/parler-tts.ts","../src/gpu/vision-executor.ts","../src/gpu/vision-preprocess.ts","../src/browser/device-guards.ts","../src/gpu/index.ts"],"sourcesContent":["/**\n * Gemma 4 vision tower (`gemma4_vision`) graph generator.\n *\n * Builds the 16-layer SigLIP-style ViT that turns image patches into pooled,\n * projected image-embedding tokens of dim `text_hidden` (1536 for E2B), ready to\n * splice into the Gemma 4 text stream at `image_token_id`. This is the VISION\n * ENCODER ONLY — it does not splice tokens into the text stream (that is the LM\n * side, src/gpu/index.ts).\n *\n * FAMILY-GENERAL: every dimension is read from `vision_config` + `text_config`,\n * so the same generator serves Gemma 4 E2B / E4B / any sibling that ships a\n * `gemma4_vision` tower — only the dims differ.\n *\n * Architecture (verified against the live HF config.json `vision_config`, the\n * safetensors header of google/gemma-4-E2B-it + mlx-community/gemma-4-e2b-it-4bit,\n * and transformers `modeling_gemma4`):\n *\n * patch_embedder:\n * input_proj : Linear(3·patch² → hidden, NO bias) [hidden, 3·patch²]=[768,768]\n * applied to pre-flattened 16×16×3 patches → [N, 768]\n * + position embeddings: TWO learned tables [pos_size, hidden]; per patch\n * look up table[0][x] + table[1][y] (axial 2D), host-gathered → [N, 768]\n * per encoder layer (Gemma sandwich norms, BIDIRECTIONAL attention):\n * input_layernorm (RMSNorm) → q/k/v_proj (NO bias)\n * → per-head q_norm / k_norm (RMSNorm over head_dim, NO v_norm)\n * → 2D axial RoPE (θ=100) on Q,K (host cos/sin, rotate_half)\n * → Attention (NON-causal, 12 heads, head_dim 64)\n * → o_proj (NO bias) → post_attention_layernorm (RMSNorm) → residual Add\n * pre_feedforward_layernorm (RMSNorm)\n * → GeGLU: down( gelu_tanh(gate) · up ) (gate/up/down, NO bias)\n * → post_feedforward_layernorm (RMSNorm) → residual Add\n * (no extra final norm — last layer's post_feedforward_layernorm is the tail)\n * pooling:\n * spatial k×k average-pool (k = pooling_kernel_size = 3) over the patch grid,\n * expressed as a host-built sparse [Npool, N] pooling matrix · hidden → [Npool,768]\n * multimodal projector (embed_vision.embedding_projection):\n * Linear(hidden → text_hidden) → [Npool, 1536] spliced at image_token_id\n *\n * Gemma 4 RMSNorm stores the FULL gain directly (NO +1 bake — see model-loader),\n * matching the text tower. The 2D axial RoPE cos/sin and the axial position-embed\n * gather are functions of the patch grid only (not weights/pixels), so they are\n * computed on the host (vision-preprocess: buildGemma4VisionPositionTensors) and\n * fed as input activations — same discipline as the Qwen ViT.\n *\n * Mobile-safety: the only ops used are MatMul / MatMulBias / RMSNorm /\n * ApplyRotaryEmb / Attention(causal:false) / GELU / Mul / Add — all already\n * mobile-validated (≤16KB workgroup, no select(), clamped exp, no `enable f16`).\n * The pooling reuses MatMul (host pooling matrix) so NO new kernel is required.\n */\n\nimport type { ModelArchConfig, ModelCapabilities, ModelGraph, OpNode, TensorDesc } from \"../ir.js\";\nimport { GEMMA4_VIS_KEYS } from \"../ir.js\";\n\nexport interface Gemma4VisionGraphInfo {\n hiddenSize: number;\n numHeads: number;\n headDim: number;\n depth: number;\n intermediateSize: number;\n textHidden: number;\n patchSize: number;\n patchDim: number;\n poolingKernelSize: number;\n ropeTheta: number;\n rmsNormEps: number;\n}\n\n/**\n * Resolve the Gemma 4 vision dims from a raw HF config. Accepts either the\n * top-level config (reads `.vision_config` + `.text_config.hidden_size`) or a\n * bare vision_config (then `textHidden` falls back to the projector row count if\n * present, else hidden). Family-general — no E2B constants.\n */\nexport function resolveGemma4VisionInfo(rawConfig: Record<string, unknown>): Gemma4VisionGraphInfo {\n const vcfg = (rawConfig.vision_config as Record<string, unknown>) ?? rawConfig;\n const tcfg = (rawConfig.text_config as Record<string, unknown>) ?? {};\n\n const hidden_size = vcfg.hidden_size as number; // 768\n const num_heads = vcfg.num_attention_heads as number; // 12\n const head_dim = (vcfg.head_dim as number) ?? Math.floor(hidden_size / num_heads); // 64\n const depth = vcfg.num_hidden_layers as number; // 16\n const intermediate_size = vcfg.intermediate_size as number; // 3072\n const patch_size = vcfg.patch_size as number; // 16\n const in_channels = (vcfg.num_channels as number) ?? 3;\n const patch_dim = in_channels * patch_size * patch_size; // 768\n const pooling_kernel_size = (vcfg.pooling_kernel_size as number) ?? 1;\n const rope = (vcfg.rope_parameters as Record<string, unknown>) ?? {};\n const rope_theta = (rope.rope_theta as number) ?? 100.0;\n const rms_norm_eps = (vcfg.rms_norm_eps as number) ?? 1e-6;\n const text_hidden = (tcfg.hidden_size as number) ?? hidden_size;\n\n return {\n hiddenSize: hidden_size,\n numHeads: num_heads,\n headDim: head_dim,\n depth,\n intermediateSize: intermediate_size,\n textHidden: text_hidden,\n patchSize: patch_size,\n patchDim: patch_dim,\n poolingKernelSize: pooling_kernel_size,\n ropeTheta: rope_theta,\n rmsNormEps: rms_norm_eps,\n };\n}\n\n/**\n * Dequantize an MLX affine-int4 weight to a plain f32 [rows, cols] matrix.\n * MLX packs 8 int4 values per u32 (low-nibble first); each group of `groupSize`\n * columns shares one scale + bias: w[r,c] = scale[r, c/gs] * q + bias[r, c/gs].\n * Used for the Gemma 4 multimodal projector (`embed_vision.embedding_projection`)\n * in MLX-4bit checkpoints, where (unlike the BF16 ViT body) the projector is int4.\n */\nexport function dequantizeMLXProjection(\n packed: Uint32Array,\n scales: Float32Array,\n biases: Float32Array,\n rows: number,\n cols: number,\n groupSize: number,\n): Float32Array {\n const out = new Float32Array(rows * cols);\n const numGroups = cols / groupSize;\n const u32PerRow = cols / 8;\n for (let r = 0; r < rows; r++) {\n const rowPacked = r * u32PerRow;\n const rowScale = r * numGroups;\n for (let c = 0; c < cols; c++) {\n const word = packed[rowPacked + (c >> 3)];\n const q = (word >>> ((c & 7) * 4)) & 0xf;\n const g = Math.floor(c / groupSize);\n out[r * cols + c] = scales[rowScale + g] * q + biases[rowScale + g];\n }\n }\n return out;\n}\n\n/**\n * If the Gemma 4 multimodal projector arrived as an MLX affine-int4 triplet\n * (`embed_vision.embedding_projection.{weight(U32), scales, biases}`), dequantize\n * it in-place to a plain f32 `embed_vision.embedding_projection.weight` and drop\n * the scales/biases, so the vision graph's plain MatMul on the projector works for\n * MLX-4bit checkpoints too. No-op for BF16 (HF) checkpoints (weight already f32).\n */\nexport function dequantizeGemma4VisionProjection(\n weights: Map<string, { data: ArrayBufferView; shape: number[] }>,\n groupSize: number,\n rows: number,\n cols: number,\n): void {\n const wKey = GEMMA4_VIS_KEYS.projW;\n const w = weights.get(wKey);\n const sc = weights.get(\"embed_vision.embedding_projection.scales\");\n const bi = weights.get(\"embed_vision.embedding_projection.biases\");\n // Already f32 (BF16 source) or missing quant sidecars → nothing to do.\n if (!w || !(w.data instanceof Uint32Array) || !sc || !bi) return;\n const scales =\n sc.data instanceof Float32Array\n ? sc.data\n : new Float32Array(sc.data.buffer, sc.data.byteOffset, sc.data.byteLength / 4);\n const biases =\n bi.data instanceof Float32Array\n ? bi.data\n : new Float32Array(bi.data.buffer, bi.data.byteOffset, bi.data.byteLength / 4);\n const f32 = dequantizeMLXProjection(w.data, scales, biases, rows, cols, groupSize);\n weights.set(wKey, { data: f32, shape: [rows, cols] });\n weights.delete(\"embed_vision.embedding_projection.scales\");\n weights.delete(\"embed_vision.embedding_projection.biases\");\n}\n\n/**\n * Ensure the Gemma3n multimodal-embedder norm weights exist in the weights map.\n *\n * `embed_vision.embedding_post_projection_norm` is a no-scale RMSNorm in HF\n * (Gemma3nRMSNorm(..., with_scale=False)), so the checkpoint ships NO weight for\n * it — we synthesize a ones gain (matching the kernel's `(x/rms)*weight`).\n *\n * `embed_vision.soft_embedding_norm` IS a learned RMSNorm; the full BF16 repo ships\n * its gain. Lean exports (e.g. some MLX-4bit conversions) omit it — we fall back to\n * a ones gain so the model still loads and produces coherent (if not bit-exact)\n * output. Call BEFORE VisionExecutor.uploadWeights().\n *\n * Gemma 4 vision RMSNorm stores the FULL gain (no +1 bake), so a ones gain is a\n * true identity scale.\n */\nexport function ensureGemma4VisionEmbedderNorms(\n weights: Map<string, { data: ArrayBufferView; shape: number[] }>,\n visionHidden: number,\n textHidden: number,\n): void {\n const ones = (n: number) => ({ data: new Float32Array(n).fill(1), shape: [n] });\n if (!weights.has(GEMMA4_VIS_KEYS.postProjNormW)) {\n weights.set(GEMMA4_VIS_KEYS.postProjNormW, ones(textHidden));\n }\n if (!weights.has(GEMMA4_VIS_KEYS.softEmbNormW)) {\n weights.set(GEMMA4_VIS_KEYS.softEmbNormW, ones(visionHidden));\n }\n}\n\n/**\n * Patch the ClippedMatMul nodes of a Gemma 4 vision graph with the calibrated clip\n * scalars from the checkpoint (Gemma4ClippableLinear's per-tensor input/output\n * min/max buffers), then drop those scalar tensors from the weights map so the\n * vision executor doesn't try to upload them as GPU buffers. Call BEFORE\n * VisionExecutor.uploadWeights(). Missing scalars default to ±inf (clip = identity),\n * so a checkpoint without calibration still loads.\n */\nexport function patchGemma4VisionClips(\n graph: ModelGraph,\n weights: Map<string, { data: ArrayBufferView; shape: number[] }>,\n): void {\n const readScalar = (key: string | undefined): number | undefined => {\n if (!key) return undefined;\n const e = weights.get(key);\n if (!e) return undefined;\n const d =\n e.data instanceof Float32Array\n ? e.data\n : new Float32Array(e.data.buffer, e.data.byteOffset, e.data.byteLength / 4);\n return d.length > 0 ? d[0] : undefined;\n };\n for (const node of graph.nodes) {\n if (node.opType !== \"ClippedMatMul\") continue;\n const a = node.attributes;\n const imin = readScalar(a.clip_input_min_key as string | undefined);\n const imax = readScalar(a.clip_input_max_key as string | undefined);\n const omin = readScalar(a.clip_output_min_key as string | undefined);\n const omax = readScalar(a.clip_output_max_key as string | undefined);\n if (imin !== undefined) a.imin = imin;\n if (imax !== undefined) a.imax = imax;\n if (omin !== undefined) a.omin = omin;\n if (omax !== undefined) a.omax = omax;\n for (const k of [\n a.clip_input_min_key,\n a.clip_input_max_key,\n a.clip_output_min_key,\n a.clip_output_max_key,\n ] as Array<string | undefined>) {\n if (k) weights.delete(k);\n }\n }\n}\n\n/**\n * Build the Gemma 4 ViT graph. Shaped by symbolic \"N\" (number of patches, runtime)\n * and \"Np\" (number of pooled tokens = ceil(grid_h/k)·ceil(grid_w/k), runtime),\n * resolved from input tensor dims — like the Qwen ViT's \"N\"/\"Nm\".\n */\nexport function generateGemma4VisionGraph(rawConfig: Record<string, unknown>): ModelGraph {\n const info = resolveGemma4VisionInfo(rawConfig);\n const {\n hiddenSize: hidden_size,\n numHeads: num_heads,\n headDim: head_dim,\n depth,\n intermediateSize: intermediate_size,\n textHidden: text_hidden,\n patchDim: patch_dim,\n rmsNormEps: eps,\n } = info;\n\n const qkv_dim = num_heads * head_dim; // 768 (== hidden for E2B)\n\n const tensors: Record<string, TensorDesc> = {};\n const nodes: OpNode[] = [];\n const executionOrder: string[] = [];\n\n function addTensor(desc: TensorDesc): void {\n tensors[desc.name] = desc;\n }\n function addNode(node: OpNode): void {\n nodes.push(node);\n executionOrder.push(node.id);\n }\n function constant(name: string, shape: (number | string)[], safetensorsKey = name): void {\n addTensor({ name, shape, dtype: \"f32\", storage: \"constant\", safetensorsKey });\n }\n function activation(name: string, shape: (number | string)[]): void {\n addTensor({ name, shape, dtype: \"f32\", storage: \"activation\" });\n }\n\n /** MatMul (no bias): out[M,N] = in[M,K] @ W[N,K]^T. M from `mTensor`. */\n function matmul(\n id: string,\n input: string,\n weight: string,\n output: string,\n K: number,\n N: number,\n mTensor: string,\n ): void {\n addNode({\n id,\n opType: \"MatMul\",\n inputs: [input, weight],\n outputs: [output],\n attributes: { M_tensor: mTensor, K, N },\n });\n }\n /**\n * Gemma4ClippableLinear: out = clamp(clamp(x,imin,imax) @ W^T, omin, omax).\n * The four clip scalars live in the checkpoint as per-tensor tensors under\n * `<projBase>.{input_min,input_max,output_min,output_max}`; the loader reads\n * them and patches the op's imin/imax/omin/omax attributes (and drops the\n * scalar tensors), like Gemma4's layer_scalar. `projBase` is the canonical\n * key prefix of the projection (e.g. `vision_tower.encoder.layers.0.self_attn.q_proj`).\n */\n function clippedMatmul(\n id: string,\n input: string,\n weight: string,\n output: string,\n K: number,\n N: number,\n mTensor: string,\n projBase: string,\n ): void {\n addNode({\n id,\n opType: \"ClippedMatMul\",\n inputs: [input, weight],\n outputs: [output],\n attributes: {\n M_tensor: mTensor,\n K,\n N,\n clip_input_min_key: `${projBase}.input_min`,\n clip_input_max_key: `${projBase}.input_max`,\n clip_output_min_key: `${projBase}.output_min`,\n clip_output_max_key: `${projBase}.output_max`,\n },\n });\n }\n /** RMSNorm over `hidden` (per row), Gemma full-gain (no +1; baked elsewhere=none). */\n function rmsnorm(\n id: string,\n input: string,\n w: string,\n output: string,\n hidden: number,\n seqTensor: string,\n ): void {\n addNode({\n id,\n opType: \"RMSNorm\",\n inputs: [input, w],\n outputs: [output],\n attributes: { hidden_size: hidden, eps, seq_len_tensor: seqTensor },\n });\n }\n function residualAdd(id: string, a: string, b: string, output: string): void {\n addNode({\n id,\n opType: \"Add\",\n inputs: [a, b],\n outputs: [output],\n attributes: { count_tensor: a, hidden_size },\n });\n }\n\n // ── Inputs (host-written activations) ──\n activation(\"g4v_patches\", [\"N\", patch_dim]); // [N, 768] pre-flattened patches\n activation(\"g4v_pos_embeds\", [\"N\", hidden_size]); // [N, 768] axial pos-embed (host gather)\n activation(\"g4v_cos\", [\"N\", head_dim]); // [N, 64] 2D-axial rotary cos\n activation(\"g4v_sin\", [\"N\", head_dim]); // [N, 64] 2D-axial rotary sin\n // Pooling matrix [Np, N], host-built (avg-pool weights). Multiplied as MatMul:\n // pooled[Np, hidden] = poolW[Np, N] @ hidden[N, hidden] (K=N, output N=hidden)\n // N is symbolic, so the pooling matrix is declared [Np, N] and resolved at run.\n activation(\"g4v_pool_w\", [\"Np\", \"N\"]);\n\n // ── Patch embed: input_proj (no bias) + axial position embeddings ──\n // input_proj.weight is [hidden, patch_dim]=[768,768]. Linear, no bias.\n constant(GEMMA4_VIS_KEYS.patchEmbedProjW, [hidden_size, patch_dim]);\n activation(\"g4v_patch_mm\", [\"N\", hidden_size]);\n activation(\"g4v_h0\", [\"N\", hidden_size]);\n\n matmul(\n \"g4v_patch_proj\",\n \"g4v_patches\",\n GEMMA4_VIS_KEYS.patchEmbedProjW,\n \"g4v_patch_mm\",\n patch_dim,\n hidden_size,\n \"g4v_patches\",\n );\n addNode({\n id: \"g4v_add_pos\",\n opType: \"Add\",\n inputs: [\"g4v_patch_mm\", \"g4v_pos_embeds\"],\n outputs: [\"g4v_h0\"],\n attributes: { count_tensor: \"g4v_patch_mm\", hidden_size },\n });\n\n let prev = \"g4v_h0\";\n\n for (let i = 0; i < depth; i++) {\n const p = `g4v_b${i}`;\n\n // ── input_layernorm (RMSNorm) ──\n constant(GEMMA4_VIS_KEYS.inputNorm(i), [hidden_size]);\n activation(`${p}_n1`, [\"N\", hidden_size]);\n rmsnorm(`${p}_input_norm`, prev, GEMMA4_VIS_KEYS.inputNorm(i), `${p}_n1`, hidden_size, prev);\n\n // ── q/k/v projections (NO bias) ──\n constant(GEMMA4_VIS_KEYS.qProjW(i), [qkv_dim, hidden_size]);\n constant(GEMMA4_VIS_KEYS.kProjW(i), [qkv_dim, hidden_size]);\n constant(GEMMA4_VIS_KEYS.vProjW(i), [qkv_dim, hidden_size]);\n activation(`${p}_q`, [\"N\", qkv_dim]);\n activation(`${p}_k`, [\"N\", qkv_dim]);\n activation(`${p}_v`, [\"N\", qkv_dim]);\n const saBase = `vision_tower.encoder.layers.${i}.self_attn`;\n clippedMatmul(\n `${p}_q_proj`,\n `${p}_n1`,\n GEMMA4_VIS_KEYS.qProjW(i),\n `${p}_q`,\n hidden_size,\n qkv_dim,\n `${p}_n1`,\n `${saBase}.q_proj`,\n );\n clippedMatmul(\n `${p}_k_proj`,\n `${p}_n1`,\n GEMMA4_VIS_KEYS.kProjW(i),\n `${p}_k`,\n hidden_size,\n qkv_dim,\n `${p}_n1`,\n `${saBase}.k_proj`,\n );\n clippedMatmul(\n `${p}_v_proj`,\n `${p}_n1`,\n GEMMA4_VIS_KEYS.vProjW(i),\n `${p}_v`,\n hidden_size,\n qkv_dim,\n `${p}_n1`,\n `${saBase}.v_proj`,\n );\n\n // ── per-head q_norm / k_norm (RMSNorm over head_dim) ──\n constant(GEMMA4_VIS_KEYS.qNormW(i), [head_dim]);\n constant(GEMMA4_VIS_KEYS.kNormW(i), [head_dim]);\n activation(`${p}_qn`, [\"N\", qkv_dim]);\n activation(`${p}_kn`, [\"N\", qkv_dim]);\n rmsnorm(`${p}_q_norm`, `${p}_q`, GEMMA4_VIS_KEYS.qNormW(i), `${p}_qn`, head_dim, `${p}_q`);\n rmsnorm(`${p}_k_norm`, `${p}_k`, GEMMA4_VIS_KEYS.kNormW(i), `${p}_kn`, head_dim, `${p}_k`);\n\n // ── 2D axial RoPE on Q, K (host cos/sin, rotate_half) ──\n activation(`${p}_qr`, [\"N\", qkv_dim]);\n activation(`${p}_kr`, [\"N\", qkv_dim]);\n addNode({\n id: `${p}_rope_q`,\n opType: \"ApplyRotaryEmb\",\n inputs: [`${p}_qn`, \"g4v_cos\", \"g4v_sin\"],\n outputs: [`${p}_qr`],\n attributes: { num_heads, head_dim },\n });\n addNode({\n id: `${p}_rope_k`,\n opType: \"ApplyRotaryEmb\",\n inputs: [`${p}_kn`, \"g4v_cos\", \"g4v_sin\"],\n outputs: [`${p}_kr`],\n attributes: { num_heads, head_dim },\n });\n\n // ── bidirectional attention ──\n activation(`${p}_attn`, [\"N\", qkv_dim]);\n addNode({\n id: `${p}_attention`,\n opType: \"Attention\",\n inputs: [`${p}_qr`, `${p}_kr`, `${p}_v`],\n outputs: [`${p}_attn`],\n attributes: { num_q_heads: num_heads, num_kv_heads: num_heads, head_dim, causal: false },\n });\n\n // ── o_proj (NO bias) ──\n constant(GEMMA4_VIS_KEYS.oProjW(i), [hidden_size, qkv_dim]);\n activation(`${p}_o`, [\"N\", hidden_size]);\n clippedMatmul(\n `${p}_o_proj`,\n `${p}_attn`,\n GEMMA4_VIS_KEYS.oProjW(i),\n `${p}_o`,\n qkv_dim,\n hidden_size,\n `${p}_attn`,\n `${saBase}.o_proj`,\n );\n\n // ── post_attention_layernorm (RMSNorm, applied to the attn-block output BEFORE\n // the residual add — Gemma \"post-norm\" sandwich) ──\n constant(GEMMA4_VIS_KEYS.postAttnNorm(i), [hidden_size]);\n activation(`${p}_post_attn`, [\"N\", hidden_size]);\n rmsnorm(\n `${p}_post_attn_norm`,\n `${p}_o`,\n GEMMA4_VIS_KEYS.postAttnNorm(i),\n `${p}_post_attn`,\n hidden_size,\n `${p}_o`,\n );\n\n // residual 1\n activation(`${p}_res1`, [\"N\", hidden_size]);\n residualAdd(`${p}_residual1`, prev, `${p}_post_attn`, `${p}_res1`);\n\n // ── pre_feedforward_layernorm (RMSNorm) ──\n constant(GEMMA4_VIS_KEYS.preFfNorm(i), [hidden_size]);\n activation(`${p}_n2`, [\"N\", hidden_size]);\n rmsnorm(\n `${p}_pre_ff_norm`,\n `${p}_res1`,\n GEMMA4_VIS_KEYS.preFfNorm(i),\n `${p}_n2`,\n hidden_size,\n `${p}_res1`,\n );\n\n // ── GeGLU MLP: down( gelu_tanh(gate) · up ) (gate/up/down, NO bias) ──\n constant(GEMMA4_VIS_KEYS.gateProjW(i), [intermediate_size, hidden_size]);\n constant(GEMMA4_VIS_KEYS.upProjW(i), [intermediate_size, hidden_size]);\n constant(GEMMA4_VIS_KEYS.downProjW(i), [hidden_size, intermediate_size]);\n activation(`${p}_gate`, [\"N\", intermediate_size]);\n activation(`${p}_up`, [\"N\", intermediate_size]);\n activation(`${p}_gelu`, [\"N\", intermediate_size]);\n activation(`${p}_geglu`, [\"N\", intermediate_size]);\n activation(`${p}_mlp`, [\"N\", hidden_size]);\n\n const mlpBase = `vision_tower.encoder.layers.${i}.mlp`;\n clippedMatmul(\n `${p}_gate_proj`,\n `${p}_n2`,\n GEMMA4_VIS_KEYS.gateProjW(i),\n `${p}_gate`,\n hidden_size,\n intermediate_size,\n `${p}_n2`,\n `${mlpBase}.gate_proj`,\n );\n clippedMatmul(\n `${p}_up_proj`,\n `${p}_n2`,\n GEMMA4_VIS_KEYS.upProjW(i),\n `${p}_up`,\n hidden_size,\n intermediate_size,\n `${p}_n2`,\n `${mlpBase}.up_proj`,\n );\n addNode({\n id: `${p}_gelu_op`,\n opType: \"GELU\", // gelu_pytorch_tanh\n inputs: [`${p}_gate`],\n outputs: [`${p}_gelu`],\n attributes: { count_tensor: `${p}_gate` },\n });\n addNode({\n id: `${p}_geglu_mul`,\n opType: \"Mul\",\n inputs: [`${p}_gelu`, `${p}_up`],\n outputs: [`${p}_geglu`],\n attributes: { count_tensor: `${p}_gelu`, hidden_size: intermediate_size },\n });\n clippedMatmul(\n `${p}_down_proj`,\n `${p}_geglu`,\n GEMMA4_VIS_KEYS.downProjW(i),\n `${p}_mlp`,\n intermediate_size,\n hidden_size,\n `${p}_geglu`,\n `${mlpBase}.down_proj`,\n );\n\n // ── post_feedforward_layernorm (RMSNorm, before residual add) ──\n constant(GEMMA4_VIS_KEYS.postFfNorm(i), [hidden_size]);\n activation(`${p}_post_ff`, [\"N\", hidden_size]);\n rmsnorm(\n `${p}_post_ff_norm`,\n `${p}_mlp`,\n GEMMA4_VIS_KEYS.postFfNorm(i),\n `${p}_post_ff`,\n hidden_size,\n `${p}_res1`,\n );\n\n // residual 2\n activation(`${p}_res2`, [\"N\", hidden_size]);\n residualAdd(`${p}_residual2`, `${p}_res1`, `${p}_post_ff`, `${p}_res2`);\n\n prev = `${p}_res2`;\n }\n\n // ── Spatial average pooling → pooled tokens [Np, hidden] ──\n // pooled = poolW[Np, N] @ hidden[N, hidden]. Reuse MatMul: input=poolW (the\n // \"activation\" matrix), weight=encoder output viewed as [hidden, N]? No — MatMul\n // is out[M,K]@W[Nout,K]^T. We instead treat poolW as the LHS [Np, N] and the\n // encoder hidden as the RHS, but MatMul transposes the 2nd operand. To compute\n // poolW @ hidden directly we use a dedicated AvgPoolMatMul that does\n // out[r, c] = sum_k poolW[r, k] * hidden[k, c] (no transpose on hidden).\n activation(\"g4v_pooled\", [\"Np\", hidden_size]);\n addNode({\n id: \"g4v_pool\",\n opType: \"PoolMatMul\",\n inputs: [\"g4v_pool_w\", prev],\n outputs: [\"g4v_pooled\"],\n attributes: { K_tensor: prev, hidden_size, np_tensor: \"g4v_pool_w\" },\n });\n\n // ── Multimodal embedder (Gemma3nMultimodalEmbedder), soft/image path ──\n // HF forward for image features:\n // x = pooled * sqrt(vision_hidden) # scale-invariant before RMSNorm → omitted\n // x = soft_embedding_norm(x) # RMSNorm over vision hidden (WITH gain)\n // x = embedding_projection(x) # Linear(vision_hidden → text_hidden), no bias\n // x = embedding_post_projection_norm(x) # RMSNorm over text_hidden, with_scale=False (gain=1)\n // The post-projection RMSNorm is what brings the image-soft tokens to the same\n // ~unit-RMS scale as the ×sqrt(text_hidden) text embeddings they are spliced into;\n // without it the projector output is ~sqrt(text_hidden)× too large and the LM\n // ignores the image. The post-proj norm has no learned gain, so the loader\n // synthesizes a ones weight; soft_embedding_norm's gain is a real weight (loader\n // falls back to ones if a lean checkpoint omits it).\n constant(GEMMA4_VIS_KEYS.softEmbNormW, [hidden_size]);\n activation(\"g4v_soft_normed\", [\"Np\", hidden_size]);\n rmsnorm(\n \"g4v_soft_emb_norm\",\n \"g4v_pooled\",\n GEMMA4_VIS_KEYS.softEmbNormW,\n \"g4v_soft_normed\",\n hidden_size,\n \"g4v_pooled\",\n );\n\n // embed_vision.embedding_projection.weight is [text_hidden, hidden]=[1536,768].\n // No bias in the released checkpoint (weight/scales/biases are the int4 quant\n // triplet for the WEIGHT, dequantized by dequantizeGemma4VisionProjection).\n constant(GEMMA4_VIS_KEYS.projW, [text_hidden, hidden_size]);\n activation(\"g4v_proj_out\", [\"Np\", text_hidden]);\n matmul(\n \"g4v_proj\",\n \"g4v_soft_normed\",\n GEMMA4_VIS_KEYS.projW,\n \"g4v_proj_out\",\n hidden_size,\n text_hidden,\n \"g4v_proj_out\",\n );\n\n constant(GEMMA4_VIS_KEYS.postProjNormW, [text_hidden]);\n activation(\"g4v_image_embeds\", [\"Np\", text_hidden]);\n rmsnorm(\n \"g4v_post_proj_norm\",\n \"g4v_proj_out\",\n GEMMA4_VIS_KEYS.postProjNormW,\n \"g4v_image_embeds\",\n text_hidden,\n \"g4v_proj_out\",\n );\n\n const config: ModelArchConfig = {\n hidden_size,\n num_layers: depth,\n num_heads,\n num_kv_heads: num_heads,\n head_dim,\n intermediate_size,\n vocab_size: 0,\n context_length:\n ((rawConfig.vision_config as Record<string, unknown> | undefined)\n ?.max_position_embeddings as number) ?? 0,\n rms_norm_eps: eps,\n norm_type: \"rmsnorm\",\n rope_base: info.ropeTheta,\n rope_dim: head_dim,\n kv_layout: \"LHSd\",\n is_moe: false,\n has_vision_tower: true,\n vision_architecture: \"gemma4_vision\",\n vision_patch_size: info.patchSize,\n vision_embed_dim: hidden_size,\n };\n\n const capabilities: ModelCapabilities = { text: true, vision: true, moe: false };\n\n return {\n architecture: \"Gemma4VisionModel\",\n config,\n capabilities,\n tensors,\n nodes,\n executionOrder,\n inputs: [\"g4v_patches\", \"g4v_pos_embeds\", \"g4v_cos\", \"g4v_sin\", \"g4v_pool_w\"],\n outputs: [\"g4v_image_embeds\"],\n };\n}\n","/**\n * Qwen3.5 vision tower (ViT) graph generator.\n *\n * Builds the 12-layer ViT that turns image patches into merged image-embedding\n * tokens of dim `out_hidden_size` (1024, matching the LM hidden size). This is\n * the VISION ENCODER ONLY — it does not splice tokens into the text stream.\n *\n * Architecture (verified against transformers 5.12 modeling_qwen3_5.py):\n *\n * patch_embed: MatMul(patches[N,1536], proj_w[768,1536]) + proj_b → [N,768]\n * then + pos_embeds (bilinear-interpolated, host-precomputed)\n * per block (pre-norm, bidirectional):\n * norm1 (LayerNorm) → qkv (MatMul[2304,768]+bias) → split Q/K/V [N,768]\n * → ApplyRotaryEmb(Q), ApplyRotaryEmb(K) (precomputed cos/sin, rotate_half)\n * → Attention (NON-causal, 12 heads, head_dim 64)\n * → proj (MatMul[768,768]+bias) → residual Add\n * norm2 (LayerNorm) → fc1 (MatMul[3072,768]+bias) → GELU(tanh)\n * → fc2 (MatMul[768,3072]+bias) → residual Add\n * merger:\n * norm (LayerNorm over 768) → reshape [N,768]→[N/4,3072] (free, row-major)\n * → fc1 (MatMul[3072,3072]+bias) → GELU(exact erf) → fc2 (MatMul[1024,3072]+bias)\n * → merged image tokens [N/4, 1024]\n *\n * The bilinear pos-embed interpolation and the 2D rotary cos/sin are position-\n * (grid-)dependent only — they're cheap and computed on the host (see\n * vision-preprocess.ts), then fed as input activations. This keeps the GPU graph\n * to the weight-dependent math while staying byte-identical to HF.\n *\n * Patches must already be ordered into spatial_merge_size×spatial_merge_size\n * groups (the HF image processor does this), so the merger's reshape picks up\n * correct 2×2 blocks with no gather.\n */\n\nimport type { ModelArchConfig, ModelCapabilities, ModelGraph, OpNode, TensorDesc } from \"../ir.js\";\nimport { CANONICAL_KEYS } from \"../ir.js\";\n\nconst VIS_NORM_EPS = 1e-6;\n\nexport interface VisionGraphInfo {\n hiddenSize: number;\n numHeads: number;\n headDim: number;\n depth: number;\n intermediateSize: number;\n outHiddenSize: number;\n spatialMergeSize: number;\n patchDim: number;\n mergedDim: number;\n}\n\n/**\n * Build the ViT graph. The graph is shaped by symbolic \"N\" (number of patches),\n * resolved at run time from the input tensor's first dim — exactly like the LM's\n * symbolic \"T\".\n */\nexport function generateQwen3_5VisionGraph(rawConfig: Record<string, unknown>): ModelGraph {\n const vcfg = (rawConfig.vision_config as Record<string, unknown>) ?? rawConfig;\n\n const hidden_size = vcfg.hidden_size as number; // 768\n const num_heads = vcfg.num_heads as number; // 12\n const head_dim = Math.floor(hidden_size / num_heads); // 64\n const depth = vcfg.depth as number; // 12\n const intermediate_size = vcfg.intermediate_size as number; // 3072\n const out_hidden_size = vcfg.out_hidden_size as number; // 1024\n const spatial_merge_size = vcfg.spatial_merge_size as number; // 2\n const in_channels = vcfg.in_channels as number; // 3\n const temporal_patch_size = vcfg.temporal_patch_size as number; // 2\n const patch_size = vcfg.patch_size as number; // 16\n const patch_dim = in_channels * temporal_patch_size * patch_size * patch_size; // 1536\n const merge_unit = spatial_merge_size * spatial_merge_size; // 4\n const merged_in = hidden_size * merge_unit; // 3072\n\n const tensors: Record<string, TensorDesc> = {};\n const nodes: OpNode[] = [];\n const executionOrder: string[] = [];\n\n function addTensor(desc: TensorDesc): void {\n tensors[desc.name] = desc;\n }\n function addNode(node: OpNode): void {\n nodes.push(node);\n executionOrder.push(node.id);\n }\n function constant(name: string, shape: (number | string)[]): void {\n addTensor({ name, shape, dtype: \"f32\", storage: \"constant\", safetensorsKey: name });\n }\n function activation(name: string, shape: (number | string)[]): void {\n addTensor({ name, shape, dtype: \"f32\", storage: \"activation\" });\n }\n\n /** MatMul (no bias) → out[N, Nout] = in[N,K] @ W[Nout,K]^T. M resolved from `mTensor`. */\n function matmul(\n id: string,\n input: string,\n weight: string,\n output: string,\n K: number,\n N: number,\n mTensor?: string,\n mStatic?: number,\n ): void {\n addNode({\n id,\n opType: \"MatMul\",\n inputs: [input, weight],\n outputs: [output],\n attributes: mTensor ? { M_tensor: mTensor, K, N } : { M: mStatic, K, N },\n });\n }\n /** out[r,c] = in[r,c] + bias[c]. */\n function addBias(id: string, input: string, bias: string, output: string, width: number): void {\n addNode({\n id,\n opType: \"AddBias\",\n inputs: [input, bias],\n outputs: [output],\n attributes: { width },\n });\n }\n /**\n * Fused MatMul + row-broadcast bias → out = in @ W^T + bias. Replaces a MatMul\n * followed by a separate AddBias, removing a full read+write of the matmul\n * output per ViT linear layer.\n */\n function matmulBias(\n id: string,\n input: string,\n weight: string,\n bias: string,\n output: string,\n K: number,\n N: number,\n mTensor: string,\n ): void {\n addNode({\n id,\n opType: \"MatMulBias\",\n inputs: [input, weight, bias],\n outputs: [output],\n attributes: { M_tensor: mTensor, K, N },\n });\n }\n function layernorm(\n id: string,\n input: string,\n w: string,\n b: string,\n output: string,\n hidden: number,\n seqTensor: string,\n ): void {\n addNode({\n id,\n opType: \"LayerNorm\",\n inputs: [input, w, b],\n outputs: [output],\n attributes: { hidden_size: hidden, eps: VIS_NORM_EPS, seq_len_tensor: seqTensor },\n });\n }\n\n // ── Inputs (host-written activations) ──\n activation(\"vis_patches\", [\"N\", patch_dim]); // [N, 1536]\n activation(\"vis_pos_embeds\", [\"N\", hidden_size]); // [N, 768]\n activation(\"vis_cos\", [\"N\", head_dim]); // [N, 64]\n activation(\"vis_sin\", [\"N\", head_dim]); // [N, 64]\n\n // ── Patch embed: MatMul + bias + pos_embeds ──\n constant(CANONICAL_KEYS.visPatchEmbedWeight, [hidden_size, patch_dim]);\n constant(CANONICAL_KEYS.visPatchEmbedBias, [hidden_size]);\n activation(\"vis_patch_mm\", [\"N\", hidden_size]);\n activation(\"vis_patch_bias\", [\"N\", hidden_size]);\n activation(\"vis_h0\", [\"N\", hidden_size]);\n\n matmulBias(\n \"vis_patch_mm\",\n \"vis_patches\",\n CANONICAL_KEYS.visPatchEmbedWeight,\n CANONICAL_KEYS.visPatchEmbedBias,\n \"vis_patch_bias\",\n patch_dim,\n hidden_size,\n \"vis_patches\",\n );\n addNode({\n id: \"vis_add_pos\",\n opType: \"Add\",\n inputs: [\"vis_patch_bias\", \"vis_pos_embeds\"],\n outputs: [\"vis_h0\"],\n attributes: { count_tensor: \"vis_patch_bias\", hidden_size },\n });\n\n let prev = \"vis_h0\";\n const qkv_dim = hidden_size * 3; // 2304\n\n for (let i = 0; i < depth; i++) {\n const p = `vis_b${i}`;\n\n // norm1\n constant(CANONICAL_KEYS.visBlockNorm1W(i), [hidden_size]);\n constant(CANONICAL_KEYS.visBlockNorm1B(i), [hidden_size]);\n activation(`${p}_n1`, [\"N\", hidden_size]);\n layernorm(\n `${p}_norm1`,\n prev,\n CANONICAL_KEYS.visBlockNorm1W(i),\n CANONICAL_KEYS.visBlockNorm1B(i),\n `${p}_n1`,\n hidden_size,\n prev,\n );\n\n // qkv projection + bias\n constant(CANONICAL_KEYS.visBlockQkvW(i), [qkv_dim, hidden_size]);\n constant(CANONICAL_KEYS.visBlockQkvB(i), [qkv_dim]);\n activation(`${p}_qkv_mm`, [\"N\", qkv_dim]);\n activation(`${p}_qkv`, [\"N\", qkv_dim]);\n matmulBias(\n `${p}_qkv_proj`,\n `${p}_n1`,\n CANONICAL_KEYS.visBlockQkvW(i),\n CANONICAL_KEYS.visBlockQkvB(i),\n `${p}_qkv`,\n hidden_size,\n qkv_dim,\n `${p}_n1`,\n );\n\n // split Q/K/V [N,768] from fused [N,2304]\n activation(`${p}_q`, [\"N\", hidden_size]);\n activation(`${p}_k`, [\"N\", hidden_size]);\n activation(`${p}_v`, [\"N\", hidden_size]);\n const sliceCols = (id: string, output: string, offset: number) =>\n addNode({\n id,\n opType: \"SliceCols\",\n inputs: [`${p}_qkv`],\n outputs: [output],\n attributes: {\n in_width: qkv_dim,\n out_width: hidden_size,\n col_offset: offset,\n seq_len_tensor: `${p}_qkv`,\n },\n });\n sliceCols(`${p}_split_q`, `${p}_q`, 0);\n sliceCols(`${p}_split_k`, `${p}_k`, hidden_size);\n sliceCols(`${p}_split_v`, `${p}_v`, 2 * hidden_size);\n\n // rotary on Q, K\n activation(`${p}_qr`, [\"N\", hidden_size]);\n activation(`${p}_kr`, [\"N\", hidden_size]);\n addNode({\n id: `${p}_rope_q`,\n opType: \"ApplyRotaryEmb\",\n inputs: [`${p}_q`, \"vis_cos\", \"vis_sin\"],\n outputs: [`${p}_qr`],\n attributes: { num_heads, head_dim },\n });\n addNode({\n id: `${p}_rope_k`,\n opType: \"ApplyRotaryEmb\",\n inputs: [`${p}_k`, \"vis_cos\", \"vis_sin\"],\n outputs: [`${p}_kr`],\n attributes: { num_heads, head_dim },\n });\n\n // bidirectional attention\n activation(`${p}_attn`, [\"N\", hidden_size]);\n addNode({\n id: `${p}_attention`,\n opType: \"Attention\",\n inputs: [`${p}_qr`, `${p}_kr`, `${p}_v`],\n outputs: [`${p}_attn`],\n attributes: { num_q_heads: num_heads, num_kv_heads: num_heads, head_dim, causal: false },\n });\n\n // output projection + bias\n constant(CANONICAL_KEYS.visBlockProjW(i), [hidden_size, hidden_size]);\n constant(CANONICAL_KEYS.visBlockProjB(i), [hidden_size]);\n activation(`${p}_proj_mm`, [\"N\", hidden_size]);\n activation(`${p}_proj`, [\"N\", hidden_size]);\n matmulBias(\n `${p}_proj_op`,\n `${p}_attn`,\n CANONICAL_KEYS.visBlockProjW(i),\n CANONICAL_KEYS.visBlockProjB(i),\n `${p}_proj`,\n hidden_size,\n hidden_size,\n `${p}_attn`,\n );\n\n // residual 1\n activation(`${p}_res1`, [\"N\", hidden_size]);\n addNode({\n id: `${p}_residual1`,\n opType: \"Add\",\n inputs: [prev, `${p}_proj`],\n outputs: [`${p}_res1`],\n attributes: { count_tensor: prev, hidden_size },\n });\n\n // norm2 + MLP (GELU tanh)\n constant(CANONICAL_KEYS.visBlockNorm2W(i), [hidden_size]);\n constant(CANONICAL_KEYS.visBlockNorm2B(i), [hidden_size]);\n constant(CANONICAL_KEYS.visBlockFc1W(i), [intermediate_size, hidden_size]);\n constant(CANONICAL_KEYS.visBlockFc1B(i), [intermediate_size]);\n constant(CANONICAL_KEYS.visBlockFc2W(i), [hidden_size, intermediate_size]);\n constant(CANONICAL_KEYS.visBlockFc2B(i), [hidden_size]);\n activation(`${p}_n2`, [\"N\", hidden_size]);\n activation(`${p}_fc1_mm`, [\"N\", intermediate_size]);\n activation(`${p}_fc1`, [\"N\", intermediate_size]);\n activation(`${p}_gelu`, [\"N\", intermediate_size]);\n activation(`${p}_fc2_mm`, [\"N\", hidden_size]);\n activation(`${p}_fc2`, [\"N\", hidden_size]);\n activation(`${p}_res2`, [\"N\", hidden_size]);\n\n layernorm(\n `${p}_norm2`,\n `${p}_res1`,\n CANONICAL_KEYS.visBlockNorm2W(i),\n CANONICAL_KEYS.visBlockNorm2B(i),\n `${p}_n2`,\n hidden_size,\n `${p}_res1`,\n );\n matmulBias(\n `${p}_fc1_op`,\n `${p}_n2`,\n CANONICAL_KEYS.visBlockFc1W(i),\n CANONICAL_KEYS.visBlockFc1B(i),\n `${p}_fc1`,\n hidden_size,\n intermediate_size,\n `${p}_n2`,\n );\n addNode({\n id: `${p}_gelu_op`,\n opType: \"GELU\",\n inputs: [`${p}_fc1`],\n outputs: [`${p}_gelu`],\n attributes: { count_tensor: `${p}_fc1` },\n });\n matmulBias(\n `${p}_fc2_op`,\n `${p}_gelu`,\n CANONICAL_KEYS.visBlockFc2W(i),\n CANONICAL_KEYS.visBlockFc2B(i),\n `${p}_fc2`,\n intermediate_size,\n hidden_size,\n `${p}_gelu`,\n );\n addNode({\n id: `${p}_residual2`,\n opType: \"Add\",\n inputs: [`${p}_res1`, `${p}_fc2`],\n outputs: [`${p}_res2`],\n attributes: { count_tensor: `${p}_res1`, hidden_size },\n });\n\n prev = `${p}_res2`;\n }\n\n // ── Merger ──\n // norm over 768 (per-patch), then view [N,768]→[N/4,3072] (free), fc1 → erf-GELU → fc2.\n // M for merger matmuls is N/4 (resolved from the [N/4,*] output tensor via M_tensor).\n constant(CANONICAL_KEYS.visMergerNormW, [hidden_size]);\n constant(CANONICAL_KEYS.visMergerNormB, [hidden_size]);\n constant(CANONICAL_KEYS.visMergerFc1W, [merged_in, merged_in]);\n constant(CANONICAL_KEYS.visMergerFc1B, [merged_in]);\n constant(CANONICAL_KEYS.visMergerFc2W, [out_hidden_size, merged_in]);\n constant(CANONICAL_KEYS.visMergerFc2B, [out_hidden_size]);\n\n activation(\"vis_merge_norm\", [\"N\", hidden_size]);\n // Reshaped views: these alias the same memory as the [N,768] norm output but\n // are addressed as [N/4, 3072]. The executor allocates per-name buffers, so we\n // declare them with the merged row count and copy is implicit (same byte layout).\n activation(\"vis_merge_fc1_mm\", [\"Nm\", merged_in]);\n activation(\"vis_merge_fc1\", [\"Nm\", merged_in]);\n activation(\"vis_merge_gelu\", [\"Nm\", merged_in]);\n activation(\"vis_merge_fc2_mm\", [\"Nm\", out_hidden_size]);\n activation(\"vis_image_embeds\", [\"Nm\", out_hidden_size]);\n\n layernorm(\n \"vis_merger_norm\",\n prev,\n CANONICAL_KEYS.visMergerNormW,\n CANONICAL_KEYS.visMergerNormB,\n \"vis_merge_norm\",\n hidden_size,\n prev,\n );\n // fc1: input is vis_merge_norm viewed as [Nm, 3072]. K=3072, N=3072, M=Nm.\n matmulBias(\n \"vis_merger_fc1\",\n \"vis_merge_norm\",\n CANONICAL_KEYS.visMergerFc1W,\n CANONICAL_KEYS.visMergerFc1B,\n \"vis_merge_fc1\",\n merged_in,\n merged_in,\n \"vis_merge_fc1\",\n );\n addNode({\n id: \"vis_merger_gelu\",\n opType: \"GeluErf\",\n inputs: [\"vis_merge_fc1\"],\n outputs: [\"vis_merge_gelu\"],\n attributes: { count_tensor: \"vis_merge_fc1\" },\n });\n matmulBias(\n \"vis_merger_fc2\",\n \"vis_merge_gelu\",\n CANONICAL_KEYS.visMergerFc2W,\n CANONICAL_KEYS.visMergerFc2B,\n \"vis_image_embeds\",\n merged_in,\n out_hidden_size,\n \"vis_image_embeds\",\n );\n\n const config: ModelArchConfig = {\n hidden_size,\n num_layers: depth,\n num_heads,\n num_kv_heads: num_heads,\n head_dim,\n intermediate_size,\n vocab_size: 0,\n context_length: vcfg.num_position_embeddings as number,\n rms_norm_eps: VIS_NORM_EPS,\n norm_type: \"layernorm\",\n rope_base: 10000.0,\n rope_dim: head_dim,\n kv_layout: \"LHSd\",\n is_moe: false,\n has_vision_tower: true,\n vision_architecture: \"qwen3_5_vit\",\n vision_patch_size: patch_size,\n vision_embed_dim: hidden_size,\n };\n\n const capabilities: ModelCapabilities = { text: true, vision: true, moe: false };\n\n return {\n architecture: \"Qwen3_5VisionModel\",\n config,\n capabilities,\n tensors,\n nodes,\n executionOrder,\n inputs: [\"vis_patches\", \"vis_pos_embeds\", \"vis_cos\", \"vis_sin\"],\n outputs: [\"vis_image_embeds\"],\n };\n}\n","/**\n * KaniTTS — native text-to-speech engine for Gerbil's WebGPU backend.\n *\n * Kani-TTS-2 (nineninesix/kani-tts-2-en) is a two-stage TTS model that, like\n * Moonshine, needs more than one graph:\n *\n * 1. CODEC-LM BACKBONE (LFM2-350M body): autoregressively emits NanoCodec audio\n * tokens (4 per frame) into the same vocab as text. Reuses LFM2's block math\n * with two KaniTTS2 deltas — frame-level position IDs (the 4 audio tokens of a\n * frame share a position) and learnable per-layer RoPE (α^(l)-scaled freqs) —\n * both folded host-side into per-layer cos/sin tables fed to the MRoPE op.\n * 2. NANOCODEC DECODER (NVIDIA NeMo 22 kHz): FSQ dequant + causal HiFi-GAN conv\n * decoder → 22 kHz PCM. Validated bit-exact vs MLX (test-nanocodec-decode.mjs).\n *\n * The AR loop runs on the host with full-logit readback so each frame's 4 audio\n * tokens are sampled per-codebook (constrained to the valid codebook window), then\n * the collected codes are decoded once through the NanoCodec graph.\n *\n * Validated on Dawn (desktop) via scripts/engine/test-kani-speak.mjs.\n */\n\nimport {\n audioTokensToCodes,\n buildKaniLayerCosSin,\n computeKaniPositions,\n generateKaniTtsGraph,\n generateNanoCodecDecoderGraph,\n KANI_END_OF_HUMAN,\n KANI_START_OF_HUMAN,\n type KaniConfig,\n kaniAttentionLayerIndices,\n kaniCosTensor,\n kaniLayerAlpha,\n kaniSinTensor,\n parseKaniConfig,\n} from \"./architectures/kani_tts.js\";\nimport type { GPUContext } from \"./device.js\";\nimport { initGPU } from \"./device.js\";\nimport { Executor } from \"./executor.js\";\nimport { type LoadedKaniTTS, loadKaniTTS, quantizeKaniBackbone } from \"./model-loader.js\";\nimport type { Tokenizer } from \"./tokenizer.js\";\n\n/** Backbone weight precision for the codec-LM. */\nexport type KaniDType = \"q4\" | \"f32\";\n\nconst KANI_SAMPLE_RATE = 22_050;\nconst KANI_HOP = 1764; // PCM samples per frame (product of up-sample rates)\nconst KANI_END_OF_TEXT = 2; // tokenizer end-of-text marker spliced after the text\n/** NanoCodec decode chunking (keeps per-dispatch under WebGPU's 65535 cap). */\nconst KANI_CODEC_CHUNK_FRAMES = 32;\nconst KANI_CODEC_LOOKBACK_FRAMES = 32;\n/** Hard cap so a stuck decode cannot loop forever (reference uses 3000). */\nconst DEFAULT_MAX_NEW_TOKENS = 3000;\n\nexport interface KaniTTSOptions {\n /** Backbone repo (default nineninesix/kani-tts-450m-0.2-ft, Apache-2.0). */\n repo?: string;\n /** NanoCodec repo (default the NeMo 22 kHz MLX checkpoint). */\n codecRepo?: string;\n revision?: string;\n hfToken?: string;\n cacheDir?: string;\n /**\n * Codec-LM backbone weight precision (default \"q4\"):\n * • \"q4\" — group-wise INT4 (W4A16) on the LFM2 linear projections; embedding +\n * LM head stay f32. Backbone ~1.5 GB → ~0.37 GB. Recommended default.\n * • \"f32\" — full precision (largest, marginally highest fidelity).\n * The NanoCodec decoder always runs f32 regardless.\n */\n dtype?: KaniDType;\n /** Max self-attn KV-cache length (prompt + generated). Default 2048. */\n maxSeqLen?: number;\n onProgress?: (loaded: number, total: number, message: string) => void;\n}\n\nexport interface SpeakOptions {\n /**\n * Language/accent tag for KaniTTS2 multi-accent checkpoints (e.g. \"en_us\",\n * \"en_nyork\", \"en_glasg\"). Applied as a `\"{tag}: {text}\"` prefix ONLY when the\n * loaded checkpoint advertises accent tags (config.language_settings). On the\n * plain LFM2 family (the Apache default kani-tts-450m-0.2-ft) there is a single\n * trained voice and the raw text is tokenized verbatim — the tag is ignored.\n * See `availableVoices()` for what the loaded model actually supports.\n */\n languageTag?: string;\n /** Sampling temperature for the codec-LM AR decode (default 1.0). Higher = more varied prosody. */\n temperature?: number;\n /** Top-p nucleus threshold (default 0.95). */\n topP?: number;\n /** Top-k cutoff for the per-codebook sample (default 0 = disabled; keep all valid codes). */\n topK?: number;\n /** Repetition penalty (default 1.1). */\n repetitionPenalty?: number;\n /** Max audio frames to generate (caps duration). Default unbounded (maxSeqLen). */\n maxFrames?: number;\n /** Override max generated tokens (default 3000). */\n maxNewTokens?: number;\n}\n\nexport interface SpeakResult {\n /** Mono PCM in [-1, 1]. */\n pcm: Float32Array;\n /** Sample rate (22050). */\n sampleRate: number;\n /** Number of audio frames decoded. */\n frames: number;\n /** Audio duration in seconds. */\n audioSeconds: number;\n}\n\n/** Build a fresh map of just the constant weights a graph references (see moonshine-stt). */\nfunction selectGraphWeights(\n graph: { tensors: Record<string, { storage: string; safetensorsKey?: string }> },\n weights: Map<string, { data: ArrayBufferView; shape: number[] }>,\n): Map<string, { data: ArrayBufferView; shape: number[] }> {\n const out = new Map<string, { data: ArrayBufferView; shape: number[] }>();\n for (const [name, desc] of Object.entries(graph.tensors)) {\n if (desc.storage !== \"constant\") {\n continue;\n }\n // Resolve by name, falling back to the tensor's safetensorsKey alias (handles\n // LFM2's embedding_norm→norm rename — the aliasing loadModel() normally does,\n // which this dedicated loader bypasses). The tied LM head shares the embed\n // buffer directly (the head MatMul binds `embed_tokens.weight`), so there is no\n // separate lm_head tensor to alias here.\n const w =\n weights.get(name) ?? (desc.safetensorsKey ? weights.get(desc.safetensorsKey) : undefined);\n if (w) {\n out.set(name, w);\n }\n }\n return out;\n}\n\n/**\n * Top-p nucleus sample from a (already softmaxed) probability array over `ids`.\n * Sorts by prob desc, keeps the smallest prefix whose cumulative mass ≥ topP,\n * renormalizes, and samples one id.\n */\nfunction nucleusSample(probs: Float32Array, ids: Int32Array, topP: number): number {\n const n = probs.length;\n const order = Array.from({ length: n }, (_, i) => i).sort((a, b) => probs[b] - probs[a]);\n let cum = 0;\n let cutoff = n;\n for (let r = 0; r < n; r++) {\n cum += probs[order[r]];\n if (cum >= topP) {\n cutoff = r + 1;\n break;\n }\n }\n let keepSum = 0;\n for (let r = 0; r < cutoff; r++) {\n keepSum += probs[order[r]];\n }\n let pick = Math.random() * keepSum;\n for (let r = 0; r < cutoff; r++) {\n pick -= probs[order[r]];\n if (pick <= 0) {\n return ids[order[r]];\n }\n }\n return ids[order[0]];\n}\n\n/**\n * In-place top-k filter over a probability array: keep only the `k` highest, zero\n * the rest, and renormalize. No-op when k <= 0 or k >= length (keep everything).\n */\nfunction applyTopK(scores: Float32Array, k: number): void {\n const n = scores.length;\n if (k <= 0 || k >= n) {\n return;\n }\n const order = Array.from({ length: n }, (_, i) => i).sort((a, b) => scores[b] - scores[a]);\n let keepSum = 0;\n for (let r = 0; r < k; r++) {\n keepSum += scores[order[r]];\n }\n for (let r = k; r < n; r++) {\n scores[order[r]] = 0;\n }\n if (keepSum > 0) {\n for (let i = 0; i < n; i++) {\n scores[i] /= keepSum;\n }\n }\n}\n\n/** In-place softmax of `scores`. */\nfunction softmaxInPlace(scores: Float32Array): void {\n let maxV = Number.NEGATIVE_INFINITY;\n for (let i = 0; i < scores.length; i++) {\n if (scores[i] > maxV) {\n maxV = scores[i];\n }\n }\n let sum = 0;\n for (let i = 0; i < scores.length; i++) {\n const e = Math.exp(scores[i] - maxV);\n scores[i] = e;\n sum += e;\n }\n for (let i = 0; i < scores.length; i++) {\n scores[i] /= sum;\n }\n}\n\nexport class KaniTTS {\n private ctx: GPUContext;\n private loaded: LoadedKaniTTS;\n private tokenizer: Tokenizer;\n private cfg: KaniConfig;\n private rawConfig: Record<string, unknown>;\n private maxSeqLen: number;\n /** Backbone executor (built once; reused across speak() calls). */\n private backboneExec: Executor;\n /** The attention layer indices (carry learnable α) and their α values. */\n private attnLayers: number[];\n private layerAlpha: Map<number, number>;\n private headDim: number;\n private ropeBase: number;\n private _destroyed = false;\n /** Accent/voice tags the loaded checkpoint advertises (empty = single voice). */\n private voiceTags: string[];\n\n /** The loaded checkpoint's architecture string (\"KaniTTS2ForCausalLM\" or \"Lfm2ForCausalLM\"). */\n readonly architecture: string;\n /** The selected backbone precision (\"q4\" or \"f32\"). */\n readonly dtype: KaniDType;\n\n private constructor(ctx: GPUContext, loaded: LoadedKaniTTS, maxSeqLen: number, dtype: KaniDType) {\n this.ctx = ctx;\n this.loaded = loaded;\n this.tokenizer = loaded.tokenizer;\n this.rawConfig = loaded.rawConfig;\n this.cfg = parseKaniConfig(loaded.rawConfig);\n this.maxSeqLen = maxSeqLen;\n // A gerbil-int4 checkpoint ships the linear projections already packed as\n // .q/.scales/.zeros — it can ONLY be run as q4 (there are no f32 projection\n // sources to feed an f32 MatMul graph). Force q4 regardless of the requested\n // dtype so an offline-quantized R2 mirror loads directly without re-quantizing\n // (quantizeKaniBackbone below is idempotent and becomes a no-op).\n this.dtype = loaded.preQuantized ? \"q4\" : dtype;\n const archList = (loaded.rawConfig.architectures as string[] | undefined) ?? [];\n this.architecture = archList[0] ?? \"Lfm2ForCausalLM\";\n // Accent tags live under config.language_settings.language_tags_list on the\n // multi-accent KaniTTS2 checkpoints; the plain LFM2 family omits it (single voice).\n const langSettings = loaded.rawConfig.language_settings as\n | { language_tags_list?: unknown }\n | undefined;\n this.voiceTags = Array.isArray(langSettings?.language_tags_list)\n ? (langSettings.language_tags_list as unknown[]).filter(\n (v): v is string => typeof v === \"string\",\n )\n : [];\n\n const hidden = this.rawConfig.hidden_size as number;\n const heads = this.rawConfig.num_attention_heads as number;\n this.headDim = (this.rawConfig.head_dim as number) ?? Math.floor(hidden / heads);\n this.ropeBase = (this.rawConfig.rope_theta as number) ?? 1_000_000.0;\n\n // ── Resolve per-layer learnable α from the alpha_weight scalars. ──\n this.attnLayers = kaniAttentionLayerIndices(this.rawConfig);\n this.layerAlpha = new Map<number, number>();\n const useLearnable = (this.rawConfig.use_learnable_rope as boolean) ?? false;\n for (const layer of this.attnLayers) {\n let alpha = 1.0;\n if (useLearnable) {\n const w = loaded.backboneWeights.get(`learnable_rope_layers.${layer}.alpha_weight`);\n const aw = w ? ((w.data as Float32Array)[0] ?? 0) : 0;\n alpha = kaniLayerAlpha(aw, this.cfg);\n }\n this.layerAlpha.set(layer, alpha);\n }\n\n // ── Build + upload the backbone graph once. ──\n this.backboneExec = this.buildBackbone(ctx, loaded, maxSeqLen);\n }\n\n /**\n * Build the codec-LM backbone graph, quantize it when q4, and upload its weights\n * into a fresh Executor. For a pre-quantized (gerbil-int4) checkpoint the linear\n * projections already carry `.q`/`.scales`/`.zeros`, so quantizeKaniBackbone is an\n * idempotent no-op (it skips any projection whose `.q` is already present) and the\n * int4 weights are uploaded verbatim — no on-device re-quantization.\n */\n private buildBackbone(ctx: GPUContext, loaded: LoadedKaniTTS, maxSeqLen: number): Executor {\n const useQ4 = this.dtype === \"q4\";\n const graph = generateKaniTtsGraph(this.rawConfig, useQ4 ? \"q4\" : undefined);\n if (useQ4) {\n quantizeKaniBackbone(graph, loaded.backboneWeights);\n }\n const exec = new Executor(ctx, graph, { maxSeqLen, kvMode: \"f32\" });\n exec.uploadWeightsMap(selectGraphWeights(graph, loaded.backboneWeights));\n exec.initBindGroups();\n return exec;\n }\n\n static async create(options: KaniTTSOptions = {}): Promise<KaniTTS> {\n const ctx = await initGPU();\n const loaded = await loadKaniTTS({\n repo: options.repo,\n codecRepo: options.codecRepo,\n revision: options.revision,\n hfToken: options.hfToken,\n cacheDir: options.cacheDir,\n onProgress: options.onProgress,\n });\n const ctxLen = (loaded.rawConfig.max_position_embeddings as number) ?? 4096;\n const maxSeqLen = Math.min(options.maxSeqLen ?? 2048, ctxLen);\n return new KaniTTS(ctx, loaded, maxSeqLen, options.dtype ?? \"q4\");\n }\n\n /** Write per-layer cos/sin for token rows [rowStart, rowStart+positions.length). */\n private writeCosSin(positions: Float32Array, rowStart: number): void {\n const rowBytes = this.headDim * 4; // rope_dim == head_dim, f32\n for (const layer of this.attnLayers) {\n const alpha = this.layerAlpha.get(layer) ?? 1.0;\n const { cos, sin } = buildKaniLayerCosSin(positions, this.headDim, this.ropeBase, alpha);\n if (rowStart === 0) {\n this.backboneExec.writeInput(kaniCosTensor(layer), cos);\n this.backboneExec.writeInput(kaniSinTensor(layer), sin);\n } else {\n this.backboneExec.writeInputAt(kaniCosTensor(layer), cos, rowStart * rowBytes);\n this.backboneExec.writeInputAt(kaniSinTensor(layer), sin, rowStart * rowBytes);\n }\n }\n }\n\n /**\n * Accent/voice tags the loaded checkpoint supports. Multi-accent KaniTTS2\n * checkpoints (kani-tts-2-en) return e.g. [\"en_us\",\"en_nyork\",\"en_glasg\", …];\n * the plain LFM2 family (the Apache default) returns [] (one trained voice,\n * selectable only by fine-tuning the backbone — there is no runtime voice/\n * speaker-prompt knob, and zero-shot cloning is not wired).\n */\n availableVoices(): string[] {\n return [...this.voiceTags];\n }\n\n /** NanoCodec's fixed output sample rate (Hz). Not selectable — see SpeakResult. */\n get sampleRate(): number {\n return KANI_SAMPLE_RATE;\n }\n\n /**\n * Synthesize speech for `text`. Returns 22 kHz mono PCM.\n *\n * Pipeline: build the [SOH]+text+[EOT,EOH] prompt → prefill the codec-LM →\n * AR-decode 4-token frames (per-codebook constrained sampling) until end_of_speech\n * → strip markers → codes → NanoCodec decode → PCM.\n */\n async speak(text: string, opts: SpeakOptions = {}): Promise<SpeakResult> {\n if (this._destroyed) {\n throw new Error(\"KaniTTS has been destroyed.\");\n }\n const temperature = opts.temperature ?? 1.0;\n const topP = opts.topP ?? 0.95;\n const topK = opts.topK ?? 0;\n const repetitionPenalty = opts.repetitionPenalty ?? 1.1;\n const maxNewTokens = Math.min(opts.maxNewTokens ?? DEFAULT_MAX_NEW_TOKENS, this.maxSeqLen);\n\n // ── Build prompt: [SOH] + tokenizer(text) + [EOT, EOH]. ──\n // Multi-accent KaniTTS2 checkpoints take a \"{tag}: {text}\" prefix; the plain\n // LFM2 family tokenizes the raw text verbatim (matching the HF reference's\n // prepare_input). The tokenizer prepends BOS (= start_of_text = 1) per its config.\n const promptText =\n this.voiceTags.length > 0\n ? `${(opts.languageTag ?? this.voiceTags[0]).trim()}: ${text}`\n : text;\n const textIds = this.tokenizer.encode(promptText);\n const prompt: number[] = [KANI_START_OF_HUMAN, ...textIds, KANI_END_OF_TEXT, KANI_END_OF_HUMAN];\n if (prompt.length >= this.maxSeqLen) {\n throw new Error(`Kani prompt is ${prompt.length} tokens >= maxSeqLen ${this.maxSeqLen}.`);\n }\n\n // ── Prefill. ──\n this.backboneExec.reset();\n const promptPos = computeKaniPositions(prompt, this.cfg);\n this.writeCosSin(promptPos, 0);\n const { logits } = await this.backboneExec.forward(new Uint32Array(prompt));\n\n // ── AR decode loop. ──\n const startTime = performance.now();\n const { audioTokens, finished } = await this.runDecodeLoop(prompt, logits, {\n temperature,\n topP,\n topK,\n repetitionPenalty,\n maxNewTokens,\n maxFrames: opts.maxFrames ?? Number.POSITIVE_INFINITY,\n });\n\n // ── Strip to whole frames, convert to codes, NanoCodec decode. ──\n const usable = audioTokens.length - (audioTokens.length % this.cfg.tokensPerFrame);\n if (usable === 0) {\n throw new Error(\n `Kani produced no complete audio frames (finished=${finished}, ` +\n `audioTokens=${audioTokens.length}). The codec-LM emitted no speech.`,\n );\n }\n const { codes, numFrames } = audioTokensToCodes(audioTokens.slice(0, usable), this.cfg);\n const pcm = await this.decodeCodes(codes, numFrames);\n\n const totalTime = (performance.now() - startTime) / 1000;\n const audioSeconds = (numFrames * KANI_HOP) / KANI_SAMPLE_RATE;\n console.log(\n `[kani] frames=${numFrames} audio=${audioSeconds.toFixed(2)}s wall=${totalTime.toFixed(\n 2,\n )}s RTF=${(audioSeconds / totalTime).toFixed(2)}x`,\n );\n\n return { pcm, sampleRate: KANI_SAMPLE_RATE, frames: numFrames, audioSeconds };\n }\n\n /**\n * Autoregressive decode: from the prefill logits, emit one token per step —\n * greedy for the structural markers ([SOA][SOS]) and per-codebook constrained\n * sampling once in speech — collecting the audio tokens between SOS and EOS.\n * Writes each step's per-layer cos/sin row (frame-level logical position) before\n * the forward. Returns the collected audio tokens and whether EOS/cap was hit.\n */\n private async runDecodeLoop(\n prompt: number[],\n prefillLogits: Float32Array,\n p: {\n temperature: number;\n topP: number;\n topK: number;\n repetitionPenalty: number;\n maxNewTokens: number;\n maxFrames: number;\n },\n ): Promise<{ audioTokens: number[]; finished: boolean }> {\n const seq: number[] = [...prompt];\n const audioTokens: number[] = [];\n const frameCap = p.maxFrames * this.cfg.tokensPerFrame;\n let logits = prefillLogits;\n let inSpeech = false;\n let finished = false;\n\n for (let step = 0; step < p.maxNewTokens; step++) {\n const nextToken = inSpeech\n ? this.sampleAudioToken(logits, audioTokens.length % this.cfg.tokensPerFrame, {\n temperature: p.temperature,\n topP: p.topP,\n topK: p.topK,\n repetitionPenalty: p.repetitionPenalty,\n previous: seq,\n })\n : this.argmax(logits);\n\n if (nextToken === this.cfg.startOfSpeech) {\n inSpeech = true;\n } else if (nextToken === this.cfg.endOfSpeech) {\n seq.push(nextToken);\n finished = true;\n break;\n } else if (inSpeech && nextToken >= this.cfg.audioTokensStart) {\n audioTokens.push(nextToken);\n }\n seq.push(nextToken);\n\n if (inSpeech && audioTokens.length >= frameCap) {\n finished = true;\n break;\n }\n if (seq.length >= this.maxSeqLen) {\n break;\n }\n\n // cos/sin row for the next physical position = current seqPos, at the logical\n // (frame-level) position of the token we are about to feed.\n this.writeCosSin(\n Float32Array.of(this.logicalPositionAt(seq)),\n this.backboneExec.currentSeqPos,\n );\n const res = await this.backboneExec.forward(new Uint32Array([nextToken]));\n logits = res.logits;\n }\n return { audioTokens, finished };\n }\n\n /** Logical (frame-level) position of the LAST token in `seq`. */\n private logicalPositionAt(seq: number[]): number {\n // computeKaniPositions returns positions BEFORE counting each token; the last\n // entry is the position the final token should be rotated at.\n const positions = computeKaniPositions(seq, this.cfg);\n return positions[positions.length - 1];\n }\n\n /** Greedy argmax over a logits row. */\n private argmax(logits: Float32Array): number {\n let best = 0;\n let bestVal = logits[0];\n for (let i = 1; i < logits.length; i++) {\n if (logits[i] > bestVal) {\n bestVal = logits[i];\n best = i;\n }\n }\n return best;\n }\n\n /**\n * Sample one audio token for codebook position `codebook`, constrained to that\n * codebook's valid window [audio_tokens_start + 4032*c, +4032). Allows end_of_speech\n * only at codebook 0 (frame boundary). Applies repetition penalty, temperature,\n * optional top-k, then top-p nucleus sampling.\n */\n private sampleAudioToken(\n logits: Float32Array,\n codebook: number,\n p: {\n temperature: number;\n topP: number;\n topK: number;\n repetitionPenalty: number;\n previous: number[];\n },\n ): number {\n const winStart = this.cfg.audioTokensStart + this.cfg.codebookSize * codebook;\n const winLen = this.cfg.codebookSize;\n // Candidate window: the codebook's valid tokens (+ end_of_speech at a frame\n // boundary, codebook 0), so the sampled token is always a valid audio code.\n const allowEos = codebook === 0;\n const n = winLen + (allowEos ? 1 : 0);\n const ids = new Int32Array(n);\n for (let i = 0; i < winLen; i++) {\n ids[i] = winStart + i;\n }\n if (allowEos) {\n ids[winLen] = this.cfg.endOfSpeech;\n }\n // Repetition penalty + temperature → softmax → optional top-k → top-p sample.\n const prev = p.repetitionPenalty !== 1.0 ? new Set(p.previous) : null;\n const scores = new Float32Array(n);\n for (let i = 0; i < n; i++) {\n let s = logits[ids[i]];\n if (prev?.has(ids[i])) {\n s = s > 0 ? s / p.repetitionPenalty : s * p.repetitionPenalty;\n }\n scores[i] = s / p.temperature;\n }\n softmaxInPlace(scores);\n applyTopK(scores, p.topK); // no-op when topK <= 0\n return nucleusSample(scores, ids, p.topP);\n }\n\n /**\n * Decode NanoCodec codes [groups, T] (group-major) → PCM.\n *\n * The decoder graph carries concrete lengths, and the upsampled conv activations\n * for long clips overflow WebGPU's 65535 per-dimension dispatch cap. The decoder\n * is fully causal with a small (≤ a few frames) receptive field, so we decode in\n * frame chunks with a left-context lookback and keep only each chunk's own output\n * samples — numerically identical to a single decode, but bounded per dispatch.\n */\n private async decodeCodes(codes: Uint32Array, numFrames: number): Promise<Float32Array> {\n const groups = 4; // FSQ_NUM_GROUPS (codes are group-major [groups, T])\n const lookback = KANI_CODEC_LOOKBACK_FRAMES;\n const chunk = KANI_CODEC_CHUNK_FRAMES;\n const pcm = new Float32Array(numFrames * KANI_HOP);\n\n for (let start = 0; start < numFrames; start += chunk) {\n const ctxStart = Math.max(0, start - lookback);\n const ctxFrames = start - ctxStart; // discarded warmup frames\n const end = Math.min(numFrames, start + chunk);\n const winFrames = end - ctxStart;\n\n // Slice the codes window [ctxStart, end) for all groups, group-major.\n const winCodes = new Uint32Array(groups * winFrames);\n for (let g = 0; g < groups; g++) {\n for (let t = 0; t < winFrames; t++) {\n winCodes[g * winFrames + t] = codes[g * numFrames + (ctxStart + t)];\n }\n }\n\n const win = await this.decodeCodesWindow(winCodes, winFrames);\n // Keep only this chunk's samples (drop the lookback warmup).\n const dropSamples = ctxFrames * KANI_HOP;\n const keepSamples = (end - start) * KANI_HOP;\n pcm.set(win.subarray(dropSamples, dropSamples + keepSamples), start * KANI_HOP);\n }\n\n // Clamp to [-1, 1] (NanoCodec's output activation).\n for (let i = 0; i < pcm.length; i++) {\n pcm[i] = Math.min(1, Math.max(-1, pcm[i]));\n }\n return pcm;\n }\n\n /** Run the NanoCodec decoder graph for a single (bounded) code window → PCM. */\n private async decodeCodesWindow(winCodes: Uint32Array, winFrames: number): Promise<Float32Array> {\n const graph = generateNanoCodecDecoderGraph({ numFrames: winFrames });\n const exec = new Executor(this.ctx, graph, { maxSeqLen: winFrames, kvMode: \"f32\" });\n try {\n exec.uploadWeightsMap(selectGraphWeights(graph, this.loaded.codecWeights));\n exec.initBindGroups();\n exec.reset();\n exec.writeInput(\"audio_codes\", winCodes);\n return await exec.runGraphOutput(graph.outputs[0], winFrames * KANI_HOP);\n } finally {\n exec.destroy();\n }\n }\n\n destroy(): void {\n if (this._destroyed) {\n return;\n }\n this._destroyed = true;\n this.backboneExec.destroy();\n this.loaded.backboneWeights.clear();\n this.loaded.codecWeights.clear();\n }\n}\n","// Post-processing for on-device ghost-text autocomplete suggestions.\n//\n// Small quantized models (e.g. Qwen3.5-0.8B) love to (a) restate the text the\n// user already typed and (b) loop on a phrase. Naive cleanup that only drops an\n// output which echoes the WHOLE typed string verbatim lets a partial\n// tail-overlap (\"…the game is\" → \"the game is to…\") or a restatement of an\n// EARLIER phrase slip straight through, showing up as duplicated ghost text.\n// These pure helpers make the suggestion a clean, novel continuation regardless\n// of what the model emits. They are deliberately dependency-free and\n// side-effect-free so they are trivial to reason about and unit-test.\n\nconst DEFAULT_MAX_SUGGESTION_CHARS = 140;\nconst DEFAULT_RESTATEMENT_MIN_WORDS = 3;\nconst DEFAULT_INTERNAL_REPEAT_MIN_RUN = 6;\nconst LEADING_PUNCT = /^[.,;:!?)\\]}'\"”’%]/;\nconst WRAPPING_QUOTES_START = /^[\"'“”‘’`]+/;\nconst WRAPPING_QUOTES_END = /[\"'“”‘’`]+$/;\nconst TRAILING_WHITESPACE = /\\s+$/;\nconst WHITESPACE_RUN = /\\s+/g;\nconst AFTER_FIRST_NEWLINE = /\\r?\\n[\\s\\S]*$/;\nconst ENDS_WITH_SPACE = /\\s$/;\n\n/**\n * Longest span of characters that is both a suffix of `typed` and a prefix of\n * `suggestion`, dropped from the start of `suggestion`. Trailing whitespace on\n * `typed` is ignored so a duplicated word at the cursor (\"the \" + \"the store\")\n * is caught. Returns `suggestion` unchanged when there is no overlap.\n */\nexport function stripLeadingOverlap(typed: string, suggestion: string): string {\n const t = typed.replace(TRAILING_WHITESPACE, \"\");\n const max = Math.min(t.length, suggestion.length);\n for (let k = max; k > 0; k--) {\n if (t.slice(t.length - k) === suggestion.slice(0, k)) {\n return suggestion.slice(k);\n }\n }\n return suggestion;\n}\n\n/**\n * Drop a leading run of words from `suggestion` when that run already appears as\n * a contiguous phrase anywhere in `typed`. This catches the model restating an\n * EARLIER phrase (not just the immediate tail). Matching is case-insensitive,\n * whitespace-normalized, and word-boundary aware so it never strips on a\n * partial-word coincidence. Only strips runs of at least `minWords` words to\n * avoid nuking a legitimate short continuation.\n */\nexport function stripRestatement(\n typed: string,\n suggestion: string,\n minWords = DEFAULT_RESTATEMENT_MIN_WORDS,\n): string {\n const normTyped = ` ${typed.toLowerCase().replace(WHITESPACE_RUN, \" \").trim()} `;\n const words = suggestion.split(WHITESPACE_RUN).filter(Boolean);\n let matched = 0;\n for (let n = 1; n <= words.length; n++) {\n const phrase = ` ${words.slice(0, n).join(\" \").toLowerCase()} `;\n if (normTyped.includes(phrase)) {\n matched = n;\n } else {\n break;\n }\n }\n if (matched >= minWords) {\n return words.slice(matched).join(\" \");\n }\n return suggestion;\n}\n\n/**\n * Truncate `text` right before the first point where a span of `minRun` or more\n * consecutive words repeats a span seen earlier — the classic small-model loop\n * (\"…endless sands …endless sands…\"). Returns `text` unchanged (spacing\n * preserved) when no such repeat exists.\n */\nexport function truncateInternalRepeat(\n text: string,\n minRun = DEFAULT_INTERNAL_REPEAT_MIN_RUN,\n): string {\n const words = text.split(WHITESPACE_RUN).filter(Boolean);\n const seen = new Set<string>();\n for (let j = 0; j + minRun <= words.length; j++) {\n const gram = words\n .slice(j, j + minRun)\n .join(\" \")\n .toLowerCase();\n if (seen.has(gram)) {\n return words.slice(0, j).join(\" \");\n }\n seen.add(gram);\n }\n return text;\n}\n\n/**\n * Cap `text` to at most `max` characters, cutting on a word boundary when a\n * reasonable one exists in the back half of the window.\n */\nexport function capLength(text: string, max: number): string {\n if (text.length <= max) {\n return text;\n }\n const cut = text.slice(0, max);\n const lastSpace = cut.lastIndexOf(\" \");\n return (lastSpace > max * 0.5 ? cut.slice(0, lastSpace) : cut).trimEnd();\n}\n\nexport interface CleanSuggestionOptions {\n /** Keep only the first line of the raw output (default true). */\n singleLine?: boolean;\n /** Character cap for the returned continuation (default 140). */\n maxChars?: number;\n}\n\n/**\n * Turn a raw model completion into a clean inline ghost continuation:\n * 1. keep only the first line (when `singleLine`),\n * 2. strip wrapping quotes,\n * 3. drop a full verbatim echo of the typed text,\n * 4. drop a leading character overlap with the typed tail,\n * 5. drop a leading word-run that restates an earlier typed phrase,\n * 6. truncate an internal phrase loop,\n * 7. cap the length,\n * 8. add a single smart leading space so the ghost joins the caret naturally.\n *\n * Returns \"\" when nothing novel is left — the ghost then simply shows nothing,\n * which is the correct behavior for a suggestion that only repeats the input.\n */\nexport function cleanSuggestion(\n raw: string,\n typed: string,\n options: CleanSuggestionOptions = {},\n): string {\n const { singleLine = true, maxChars = DEFAULT_MAX_SUGGESTION_CHARS } = options;\n\n let s = singleLine ? raw.replace(AFTER_FIRST_NEWLINE, \"\") : raw;\n s = s.replace(WRAPPING_QUOTES_START, \"\").replace(WRAPPING_QUOTES_END, \"\");\n s = s.trim();\n if (!s) {\n return \"\";\n }\n\n const typedTrim = typed.trim();\n if (typedTrim && s.startsWith(typedTrim)) {\n s = s.slice(typedTrim.length).trimStart();\n }\n s = stripLeadingOverlap(typed, s).trimStart();\n s = stripRestatement(typed, s);\n s = truncateInternalRepeat(s);\n s = capLength(s.trim(), maxChars).trim();\n if (!s) {\n return \"\";\n }\n\n const startsWithPunct = LEADING_PUNCT.test(s);\n const typedEndsWithSpace = ENDS_WITH_SPACE.test(typed) || typed.length === 0;\n return startsWithPunct || typedEndsWithSpace ? s : ` ${s}`;\n}\n","/**\n * CPU-side token sampling from logits.\n *\n * Applies temperature, top-k, and top-p (nucleus) filtering,\n * then samples from the resulting probability distribution.\n *\n * Uses typed arrays and min-heap for zero-allocation top-K selection.\n * For vocab_size ~152K with topK=50, this avoids creating 152K JS tuples.\n */\n\nexport interface SamplingParams {\n temperature?: number; // Default: 0.7\n topK?: number; // Default: 50\n topP?: number; // Default: 0.9\n repetitionPenalty?: number; // Default: 1.0 (disabled)\n /**\n * Seed for the sampling RNG. When set, sampled decoding is reproducible:\n * the same params object draws a deterministic random stream (seeded on its\n * first use — pass a fresh options object per generation for run-to-run\n * reproducibility). Unset: Math.random() (non-deterministic, the default).\n */\n seed?: number;\n}\n\n/** mulberry32 — tiny deterministic PRNG for seeded sampling. */\nfunction mulberry32(seed: number): () => number {\n let a = seed >>> 0;\n return () => {\n a = (a + 0x6d2b79f5) | 0;\n let t = Math.imul(a ^ (a >>> 15), 1 | a);\n t = (t + Math.imul(t ^ (t >>> 7), 61 | t)) ^ t;\n return ((t ^ (t >>> 14)) >>> 0) / 4294967296;\n };\n}\n\n/** Per-params seeded RNG streams (one stream per options object identity). */\nconst seededStreams = new WeakMap<SamplingParams, () => number>();\n\nfunction nextRandom(params: SamplingParams): number {\n if (params.seed === undefined) return Math.random();\n let rng = seededStreams.get(params);\n if (!rng) {\n rng = mulberry32(params.seed);\n seededStreams.set(params, rng);\n }\n return rng();\n}\n\n// Pre-allocated buffers for top-K selection (avoid GC pressure in hot loop)\nlet _heapIndices: Uint32Array | null = null;\nlet _heapValues: Float32Array | null = null;\n\n/**\n * Sample a token ID from logits.\n *\n * Pipeline: repetition penalty → temperature → top-k (min-heap) → softmax → top-p → sample.\n */\nexport function sampleToken(\n logits: Float32Array,\n params: SamplingParams = {},\n previousTokens?: number[],\n): number {\n const temperature = params.temperature ?? 0.7;\n const topK = params.topK ?? 50;\n const topP = params.topP ?? 0.9;\n const repetitionPenalty = params.repetitionPenalty ?? 1.0;\n\n // Greedy decoding when temperature is ~0\n if (temperature < 1e-6) {\n return argmax(logits);\n }\n\n const N = logits.length;\n const K = Math.min(topK > 0 ? topK : N, N);\n\n // Ensure pre-allocated buffers are large enough\n if (!_heapIndices || _heapIndices.length < K) {\n _heapIndices = new Uint32Array(K);\n _heapValues = new Float32Array(K);\n }\n const hIdx = _heapIndices;\n const hVal = _heapValues!;\n\n // Apply repetition penalty set (built once)\n let penaltySet: Set<number> | null = null;\n if (repetitionPenalty !== 1.0 && previousTokens?.length) {\n penaltySet = new Set(previousTokens);\n }\n\n // Single pass: apply temperature + repetition penalty + top-K min-heap\n let heapSize = 0;\n\n for (let i = 0; i < N; i++) {\n let s = logits[i];\n\n // Repetition penalty\n if (penaltySet?.has(i)) {\n s = s > 0 ? s / repetitionPenalty : s * repetitionPenalty;\n }\n\n // Temperature\n s /= temperature;\n\n if (heapSize < K) {\n // Fill the heap\n hIdx[heapSize] = i;\n hVal[heapSize] = s;\n heapSize++;\n if (heapSize === K) {\n // Build min-heap\n for (let j = (K >> 1) - 1; j >= 0; j--) {\n siftDown(hIdx, hVal, j, K);\n }\n }\n } else if (s > hVal[0]) {\n // Replace min and sift down\n hIdx[0] = i;\n hVal[0] = s;\n siftDown(hIdx, hVal, 0, K);\n }\n }\n\n // Sort top-K by value descending (K is small, ~50)\n // Simple insertion sort for small K\n for (let i = 1; i < heapSize; i++) {\n const vi = hVal[i];\n const ii = hIdx[i];\n let j = i - 1;\n while (j >= 0 && hVal[j] < vi) {\n hVal[j + 1] = hVal[j];\n hIdx[j + 1] = hIdx[j];\n j--;\n }\n hVal[j + 1] = vi;\n hIdx[j + 1] = ii;\n }\n\n // Softmax over top-K candidates\n const maxScore = hVal[0];\n let sumExp = 0;\n for (let i = 0; i < heapSize; i++) {\n const p = Math.exp(hVal[i] - maxScore);\n hVal[i] = p; // Reuse hVal for probabilities\n sumExp += p;\n }\n const invSum = 1 / sumExp;\n for (let i = 0; i < heapSize; i++) {\n hVal[i] *= invSum;\n }\n\n // Apply top-p (nucleus): keep smallest set whose cumulative prob >= topP\n let candidateCount = heapSize;\n if (topP < 1.0) {\n let cumulative = 0;\n for (let i = 0; i < heapSize; i++) {\n cumulative += hVal[i];\n if (cumulative >= topP) {\n candidateCount = i + 1;\n break;\n }\n }\n // Re-normalize\n let sum = 0;\n for (let i = 0; i < candidateCount; i++) sum += hVal[i];\n const inv = 1 / sum;\n for (let i = 0; i < candidateCount; i++) hVal[i] *= inv;\n }\n\n // Weighted random sample\n const r = nextRandom(params);\n let cumulative = 0;\n for (let i = 0; i < candidateCount; i++) {\n cumulative += hVal[i];\n if (r <= cumulative) return hIdx[i];\n }\n\n return hIdx[candidateCount - 1];\n}\n\n/**\n * Return the index of the maximum value (greedy decoding).\n */\nexport function argmax(arr: Float32Array): number {\n let maxIdx = 0;\n let maxVal = arr[0];\n for (let i = 1; i < arr.length; i++) {\n if (arr[i] > maxVal) {\n maxVal = arr[i];\n maxIdx = i;\n }\n }\n return maxIdx;\n}\n\n/** Min-heap sift down on parallel index/value typed arrays. */\nfunction siftDown(indices: Uint32Array, values: Float32Array, i: number, n: number): void {\n while (true) {\n let smallest = i;\n const left = 2 * i + 1;\n const right = 2 * i + 2;\n if (left < n && values[left] < values[smallest]) smallest = left;\n if (right < n && values[right] < values[smallest]) smallest = right;\n if (smallest === i) break;\n // Swap\n const ti = indices[i];\n indices[i] = indices[smallest];\n indices[smallest] = ti;\n const tv = values[i];\n values[i] = values[smallest];\n values[smallest] = tv;\n i = smallest;\n }\n}\n","/**\n * RequestScheduler — continuous-batching serving loop (Phase 5 of the\n * batching campaign, `GERBIL_BATCH=N`, Dawn only).\n *\n * Turns the Phase 2/4 static lockstep batch into a real serving loop:\n *\n * - **Dynamic admission.** Requests queue at submit(); each iteration admits\n * the next queued request into a FREE batch slot, bounded by the batch\n * width AND KV-pool capacity (worst-case block need vs unreserved blocks).\n * Admission control is the OOM defense — WebGPU has no memory\n * introspection, so the scheduler never admits a request whose worst-case\n * KV footprint could exhaust the block pool mid-flight.\n * - **Lane retirement.** A sequence that hits EOS / max_tokens / a stop\n * sequence is retired the moment its token is read: its KV blocks are\n * freed, its slot is marked free for the next admit, and subsequent steps\n * mask the lane (seq_lens = 0) — finished lanes stop being stepped instead\n * of burning until the whole batch drains (the Phase 2 waste).\n * - **Chunked prefill.** A newly admitted request's prompt is prefilled in\n * bounded chunks (GERBIL_PREFILL_CHUNK tokens per iteration, default 32)\n * on the single-sequence path INTO its slot's block-table row (tableBase),\n * interleaved with masked decode steps for the lanes already decoding — a\n * long prompt no longer stalls the batch. Only the final chunk reads\n * logits back (the first sampled token); intermediate chunks are\n * submit-only. Chunking never changes the math: same positions, same KV,\n * same kernels — just split across iterations — so per-request greedy\n * output is token-exact vs single-sequence generation.\n *\n * Decode steps are pipelined depth-2 like the single-sequence path; each\n * submitted step snapshots its active (slot → request) rows so tokens read\n * one step behind are delivered to the right request even when lanes were\n * retired or re-admitted in between. In-flight steps submitted before a\n * retirement still step the dead lane once — their stray KV append lands in\n * blocks that are either still owned by the lane or (if re-allocated) are\n * fully rewritten by the new owner's queue-ordered prefill before any read.\n *\n * - **Per-request adapters** (`GERBIL_BATCH_LORA=1` on top of `GERBIL_BATCH`).\n * `submit(prompt, { adapter: \"name\" })` decodes the request with a\n * registered LoRA adapter (SGMV): its prefill runs under the single-sequence\n * runtime overlay (like generateBatch's per-lane prefill) and every decode\n * step re-derives the slot→adapter assignment from the CURRENTLY active\n * lanes, so admissions, retirements, and slot reuse can never leak one\n * request's adapter into another. Unregistered names fail at submit().\n *\n * Greedy-only (like generateBatch): sampling.temperature must be 0.\n */\n\nimport type { Executor } from \"../executor.js\";\nimport type { LoRADelta } from \"../lora.js\";\nimport { sampleToken } from \"../sampler.js\";\nimport type { ChatMessage } from \"../tokenizer.js\";\n\n/** Options for a single scheduled request. */\nexport interface ServeOptions {\n /** Max new tokens (clamped to context; default 128). */\n maxTokens?: number;\n stopSequences?: string[];\n systemPrompt?: string;\n /** Greedy-only in Phase 5: temperature must be 0 (or omitted). */\n sampling?: { temperature?: number };\n /**\n * Registered adapter name this request decodes with (SGMV — requires\n * `GERBIL_BATCH_LORA=1` and a prior `registerAdapter` call on the engine);\n * undefined = bare base. Requests with different adapters (or none) decode\n * concurrently over the shared base, each token-exact vs a solo run with\n * that adapter loaded.\n */\n adapter?: string;\n /** Streamed per-token callback (decoded text piece). */\n onToken?: (\n token: string,\n meta: { requestId: number; tokenId: number; generated: number },\n ) => void;\n}\n\n/** Per-request result + serving timings (all performance.now() ms). */\nexport interface ServeResult {\n requestId: number;\n text: string;\n tokenIds: number[];\n tokensGenerated: number;\n finishReason: \"eos\" | \"max_tokens\" | \"stop_sequence\";\n /** The adapter name the request decoded with (echoed through), if any. */\n adapter?: string;\n /** submit() call time. */\n submittedAt: number;\n /** Admission into a batch slot (prefill start). */\n admittedAt: number;\n /** First token available (end of prefill). */\n firstTokenAt: number;\n finishedAt: number;\n /** Time-to-first-token from submission (queue wait + prefill). */\n ttftMs: number;\n e2eMs: number;\n}\n\n/** Wiring the engine hands the scheduler (see WebGPUEngine.createScheduler). */\nexport interface SchedulerHost {\n executor: Executor;\n encodeChat(messages: ChatMessage[]): number[];\n decodeToken(id: number): string;\n eosTokenId: number | null;\n eotTokenId: number | null;\n /** Vocab-prune remap for CPU-sampled tokens (identity when unpruned). */\n remapToken(id: number): number;\n /**\n * Resolve a registered batch-adapter name to its executor adapter id +\n * parsed deltas. Must throw a clear error for unregistered names (surfaced\n * at submit() time, before the request is queued).\n */\n resolveAdapter(name: string): { id: number; deltas: LoRADelta[] };\n /** Serialize against generate()/embed() on the same engine. */\n acquireLock(): Promise<() => void>;\n}\n\ninterface Request {\n id: number;\n promptIds: Uint32Array;\n maxTokens: number;\n stopSequences: string[];\n /** Registered adapter name, or null for the bare base. */\n adapterName: string | null;\n /** Executor adapter id for decode steps (-1 = bare base). */\n adapterId: number;\n /** Adapter deltas applied as the runtime overlay during this request's prefill. */\n adapterDeltas: LoRADelta[] | null;\n onToken?: ServeOptions[\"onToken\"];\n resolve: (r: ServeResult) => void;\n reject: (e: Error) => void;\n state: \"queued\" | \"prefilling\" | \"decoding\" | \"done\";\n slot: number;\n /** Prompt tokens prefilled so far (chunked prefill cursor). */\n prefillPos: number;\n /** Worst-case KV blocks reserved at admission. */\n blocksReserved: number;\n generatedIds: number[];\n text: string;\n finishReason: ServeResult[\"finishReason\"];\n submittedAt: number;\n admittedAt: number;\n firstTokenAt: number;\n}\n\ninterface InFlightStep {\n readbackSlot: number;\n rows: Array<{ slot: number; req: Request }>;\n}\n\nconst PIPELINE_DEPTH = 2;\n\nexport interface SchedulerStats {\n submitted: number;\n completed: number;\n stepsSubmitted: number;\n prefillChunks: number;\n tokensGenerated: number;\n /** Wall-clock ms the serving loop was live (work outstanding). */\n busyMs: number;\n peakActiveLanes: number;\n}\n\nexport class RequestScheduler {\n private readonly host: SchedulerHost;\n private readonly batchSize: number;\n private readonly maxSeqLen: number;\n private readonly blockSize: number;\n private readonly prefillChunk: number;\n /** Free KV blocks kept unreserved as safety headroom. */\n private readonly blockHeadroom: number;\n\n private nextId = 1;\n private queue: Request[] = [];\n /** slot → occupying request (prefilling or decoding). */\n private slots: Array<Request | null>;\n /** Sum of blocksReserved across live (admitted, unfinished) requests. */\n private reservedBlocks = 0;\n private prefilling: Request | null = null;\n private inFlight: InFlightStep[] = [];\n /**\n * The slot→adapter-id assignment last uploaded to the executor (null =\n * nothing uploaded this batch session). Steps only re-upload when the\n * assignment changes (admissions/retirements), and the very first upload is\n * skipped entirely while every lane is bare base — an adapter-free serving\n * session never touches the LoRA machinery.\n */\n private lastLaneAdapterIds: Int32Array | null = null;\n private stepCounter = 0;\n private loop: Promise<void> | null = null;\n private closed = false;\n\n private stats: SchedulerStats = {\n submitted: 0,\n completed: 0,\n stepsSubmitted: 0,\n prefillChunks: 0,\n tokensGenerated: 0,\n busyMs: 0,\n peakActiveLanes: 0,\n };\n\n constructor(host: SchedulerHost, options: { prefillChunkTokens?: number } = {}) {\n this.host = host;\n this.batchSize = host.executor.batchSize;\n if (this.batchSize <= 0) {\n throw new Error(\"RequestScheduler requires GERBIL_BATCH=N (N >= 2) on the Dawn path\");\n }\n this.maxSeqLen = host.executor.maxSequenceLength;\n this.blockSize = host.executor.kvBlockSizeTokens;\n this.slots = new Array(this.batchSize).fill(null);\n const envChunk =\n typeof process !== \"undefined\" ? Number(process.env?.GERBIL_PREFILL_CHUNK) : Number.NaN;\n // 128 balances per-forward fixed costs (small chunks tax prefill ~40% on\n // ~100-token prompts — measured at load) against the decode stall a chunk\n // inserts (~one 128-token prefill between decode steps, still bounded).\n this.prefillChunk =\n options.prefillChunkTokens ?? (Number.isFinite(envChunk) && envChunk >= 8 ? envChunk : 128);\n this.blockHeadroom = 2;\n }\n\n /**\n * Submit a request; resolves with the full result when it finishes.\n * Tokens stream through options.onToken as they are decoded.\n */\n submit(prompt: string | ChatMessage[], options: ServeOptions = {}): Promise<ServeResult> {\n if (this.closed) {\n return Promise.reject(new Error(\"RequestScheduler is closed\"));\n }\n if ((options.sampling?.temperature ?? 0) >= 1e-6) {\n return Promise.reject(\n new Error(\"RequestScheduler: Phase 5 is greedy-only — pass sampling: { temperature: 0 }\"),\n );\n }\n // Resolve the adapter NOW so an unregistered name fails the caller with a\n // clear error instead of poisoning the serving loop later.\n let adapterReg: { id: number; deltas: LoRADelta[] } | null = null;\n if (options.adapter != null) {\n if (!this.host.executor.batchLoraEnabled) {\n return Promise.reject(\n new Error(\n \"RequestScheduler: per-request adapters require GERBIL_BATCH_LORA=1 (with GERBIL_BATCH=N)\",\n ),\n );\n }\n try {\n adapterReg = this.host.resolveAdapter(options.adapter);\n } catch (err) {\n return Promise.reject(err instanceof Error ? err : new Error(String(err)));\n }\n }\n const messages: ChatMessage[] =\n typeof prompt === \"string\"\n ? [\n ...(options.systemPrompt\n ? [{ role: \"system\" as const, content: options.systemPrompt }]\n : []),\n { role: \"user\" as const, content: prompt },\n ]\n : options.systemPrompt\n ? [{ role: \"system\" as const, content: options.systemPrompt }, ...prompt]\n : prompt;\n const promptIds = new Uint32Array(this.host.encodeChat(messages));\n // Clamp so the sequence (+ up to PIPELINE_DEPTH overshoot tokens from\n // steps already in flight when the lane finishes) always fits the context.\n const roomFor = this.maxSeqLen - promptIds.length - PIPELINE_DEPTH - 1;\n if (roomFor < 1) {\n return Promise.reject(\n new Error(\n `RequestScheduler: prompt (${promptIds.length} tokens) leaves no room in maxSeqLen ${this.maxSeqLen}`,\n ),\n );\n }\n const maxTokens = Math.min(options.maxTokens ?? 128, roomFor);\n\n return new Promise<ServeResult>((resolve, reject) => {\n const req: Request = {\n id: this.nextId++,\n promptIds,\n maxTokens,\n stopSequences: options.stopSequences ?? [],\n adapterName: options.adapter ?? null,\n adapterId: adapterReg?.id ?? -1,\n adapterDeltas: adapterReg?.deltas ?? null,\n onToken: options.onToken,\n resolve,\n reject,\n state: \"queued\",\n slot: -1,\n prefillPos: 0,\n blocksReserved: 0,\n generatedIds: [],\n text: \"\",\n finishReason: \"max_tokens\",\n submittedAt: performance.now(),\n admittedAt: 0,\n firstTokenAt: 0,\n };\n this.queue.push(req);\n this.stats.submitted++;\n this.pump();\n });\n }\n\n /** Resolves when every submitted request has completed. */\n async drain(): Promise<void> {\n while (this.loop) await this.loop;\n }\n\n /** Stop accepting requests; resolves when in-flight work drains. */\n async close(): Promise<void> {\n this.closed = true;\n await this.drain();\n }\n\n getStats(): SchedulerStats {\n return { ...this.stats };\n }\n\n private pump(): void {\n if (this.loop) return;\n this.loop = this.run().finally(() => {\n this.loop = null;\n // Work may have arrived while the loop was tearing down.\n if (this.hasWork()) this.pump();\n });\n }\n\n private hasWork(): boolean {\n return (\n this.queue.length > 0 ||\n this.prefilling !== null ||\n this.inFlight.length > 0 ||\n this.slots.some((s) => s !== null)\n );\n }\n\n private activeMask(): { mask: Uint8Array; rows: Array<{ slot: number; req: Request }> } {\n const mask = new Uint8Array(this.batchSize);\n const rows: Array<{ slot: number; req: Request }> = [];\n for (let b = 0; b < this.batchSize; b++) {\n const req = this.slots[b];\n if (req && req.state === \"decoding\") {\n mask[b] = 1;\n rows.push({ slot: b, req });\n }\n }\n return { mask, rows };\n }\n\n /** The serving loop. Holds the engine generation lock while live. */\n private async run(): Promise<void> {\n const release = await this.host.acquireLock();\n const ex = this.host.executor;\n const loopStart = performance.now();\n // Fresh batch session: every slot/block free (nothing can be live here —\n // the loop only exits when fully drained).\n ex.resetBatch();\n this.stepCounter = 0;\n this.lastLaneAdapterIds = null;\n\n try {\n while (this.hasWork()) {\n this.admit();\n\n // Submit a masked decode step for the decoding lanes (pipelined).\n const { mask, rows } = this.activeMask();\n if (rows.length > 0 && this.inFlight.length < PIPELINE_DEPTH) {\n const readbackSlot = this.stepCounter % PIPELINE_DEPTH;\n this.syncLaneAdapters();\n ex.submitBatchDecodeStepMasked(mask, readbackSlot);\n this.stepCounter++;\n this.inFlight.push({ readbackSlot, rows });\n this.stats.stepsSubmitted++;\n if (rows.length > this.stats.peakActiveLanes) {\n this.stats.peakActiveLanes = rows.length;\n }\n }\n\n // One chunk of the pending prefill, overlapping the step above.\n if (this.prefilling) await this.prefillChunkStep();\n\n // Read the oldest in-flight step once the pipeline is full (depth-2:\n // step k+1 runs on the GPU while k's tokens are processed), or when\n // no step could be submitted and one is outstanding.\n const pipelineFull = this.inFlight.length >= PIPELINE_DEPTH;\n const idleLanes = rows.length === 0 && this.prefilling === null;\n if (this.inFlight.length > 0 && (pipelineFull || idleLanes)) {\n await this.readStep();\n }\n }\n } catch (err) {\n // Fail every live request rather than hanging their promises.\n const error = err instanceof Error ? err : new Error(String(err));\n if (this.prefilling?.adapterDeltas) {\n try {\n ex.clearRuntimeLoRA();\n } catch {\n // best-effort — the overlay must not outlive its request's prefill\n }\n }\n for (const req of [...this.queue, ...this.slots.filter((s): s is Request => s !== null)]) {\n if (req.state !== \"done\") {\n req.state = \"done\";\n req.reject(error);\n }\n }\n this.queue = [];\n this.slots.fill(null);\n this.prefilling = null;\n this.inFlight = [];\n this.reservedBlocks = 0;\n throw error;\n } finally {\n this.stats.busyMs += performance.now() - loopStart;\n release();\n }\n }\n\n /**\n * Upload the slot→adapter assignment for the step about to be submitted,\n * when it differs from the last uploaded one. Called immediately before\n * every decode-step submit: `queue.writeBuffer` is queue-ordered, so steps\n * already in flight keep the assignment they were submitted under, and a\n * retiring lane's slot can never leak its adapter into the slot's next\n * occupant — the next occupant's assignment is re-derived from `slots`\n * before its first decode step. Masked (free/prefilling) lanes are pinned\n * to bare base; their output is discarded regardless.\n */\n private syncLaneAdapters(): void {\n if (!this.host.executor.batchLoraEnabled) return;\n const ids = new Int32Array(this.batchSize).fill(-1);\n let anyAdapter = false;\n for (let b = 0; b < this.batchSize; b++) {\n const req = this.slots[b];\n if (req && req.state === \"decoding\" && req.adapterId >= 0) {\n ids[b] = req.adapterId;\n anyAdapter = true;\n }\n }\n const last = this.lastLaneAdapterIds;\n if (last === null) {\n // Nothing uploaded yet this session: an all-base assignment needs no\n // upload at all (the plain batch entry list is already in effect).\n if (!anyAdapter) return;\n } else if (ids.every((id, b) => id === last[b])) {\n return;\n }\n this.host.executor.setBatchLaneAdapters(ids);\n this.lastLaneAdapterIds = ids;\n }\n\n /**\n * Admission: move the next queued request into a free slot when (a) a slot\n * is free, (b) no other prefill is staged (the single-sequence prefill path\n * stages SSM state in singleton buffers — one at a time), and (c) its\n * worst-case block need fits the unreserved KV pool with headroom.\n */\n private admit(): void {\n if (this.prefilling || this.queue.length === 0) return;\n const slot = this.slots.indexOf(null);\n if (slot === -1) return;\n\n const req = this.queue[0];\n const worstTokens = req.promptIds.length + req.maxTokens + PIPELINE_DEPTH;\n const blocksNeeded = Math.ceil(worstTokens / this.blockSize);\n const totalBlocks = this.host.executor.kvTotalBlocks;\n if (this.reservedBlocks + blocksNeeded + this.blockHeadroom > totalBlocks) {\n // Not enough KV capacity for this request's worst case — hold it (and\n // everything behind it: FIFO) until retirements free blocks.\n return;\n }\n\n this.queue.shift();\n req.state = \"prefilling\";\n req.slot = slot;\n req.blocksReserved = blocksNeeded;\n req.admittedAt = performance.now();\n this.reservedBlocks += blocksNeeded;\n this.slots[slot] = req;\n this.prefilling = req;\n // Adapter requests prefill with the proven single-sequence runtime\n // overlay (exactly how generateBatch's per-lane prefill applies it), so\n // the KV/SSM state and first sampled token match a solo run with that\n // adapter loaded. The overlay only swaps the single-sequence entry lists;\n // the interleaved batched decode steps use the batch entry lists and are\n // untouched. Cleared after the final chunk (or on loop failure).\n if (req.adapterDeltas) {\n const { applied } = this.host.executor.applyRuntimeLoRA(req.adapterDeltas);\n if (applied === 0) {\n throw new Error(\n `RequestScheduler: adapter \"${req.adapterName}\" resolved to 0 applicable prefill targets`,\n );\n }\n }\n this.host.executor.beginBatchSlot(slot);\n }\n\n /**\n * Run one bounded prefill chunk for the staged request on the\n * single-sequence path (into its slot's block-table row via tableBase).\n * Intermediate chunks are submit-only; the final chunk reads logits, adopts\n * the singleton SSM state into the slot's pool row, seeds the lane's first\n * token, and flips the lane to decoding.\n */\n private async prefillChunkStep(): Promise<void> {\n const req = this.prefilling;\n if (!req) return;\n const ex = this.host.executor;\n const end = Math.min(req.prefillPos + this.prefillChunk, req.promptIds.length);\n const isLast = end === req.promptIds.length;\n const chunk = req.promptIds.subarray(req.prefillPos, end);\n const { logits } = await ex.forward(chunk, { readLogits: isLast });\n req.prefillPos = end;\n this.stats.prefillChunks++;\n if (!isLast) return;\n\n ex.finishBatchSlot(req.slot);\n if (req.adapterDeltas) ex.clearRuntimeLoRA();\n this.prefilling = null;\n const first = this.host.remapToken(sampleToken(logits, { temperature: 0 }));\n ex.injectBatchToken(req.slot, first);\n req.state = \"decoding\";\n req.firstTokenAt = performance.now();\n this.consumeToken(req, first);\n }\n\n /** Read the oldest in-flight step and deliver its tokens. */\n private async readStep(): Promise<void> {\n const step = this.inFlight.shift();\n if (!step) return;\n const tokens = await this.host.executor.readBatchTokens(step.readbackSlot);\n for (const { slot, req } of step.rows) {\n // The lane may have been retired (and even re-admitted) after this step\n // was submitted — deliver only to the request that was stepped.\n if (this.slots[slot] !== req || req.state !== \"decoding\") continue;\n this.consumeToken(req, tokens[slot]);\n }\n }\n\n /** Append one generated token; finish + retire the lane when terminal. */\n private consumeToken(req: Request, tokenId: number): void {\n req.generatedIds.push(tokenId);\n this.stats.tokensGenerated++;\n if (req.firstTokenAt === 0) req.firstTokenAt = performance.now();\n\n const { eosTokenId, eotTokenId } = this.host;\n if (\n (eosTokenId !== null && tokenId === eosTokenId) ||\n (eotTokenId !== null && tokenId === eotTokenId)\n ) {\n req.finishReason = \"eos\";\n this.finish(req);\n return;\n }\n const piece = this.host.decodeToken(tokenId);\n req.text += piece;\n if (req.stopSequences.some((s) => req.text.includes(s))) {\n for (const s of req.stopSequences) {\n const idx = req.text.indexOf(s);\n if (idx !== -1) req.text = req.text.slice(0, idx);\n }\n req.finishReason = \"stop_sequence\";\n this.finish(req);\n return;\n }\n req.onToken?.(piece, {\n requestId: req.id,\n tokenId,\n generated: req.generatedIds.length,\n });\n if (req.generatedIds.length >= req.maxTokens) {\n req.finishReason = \"max_tokens\";\n this.finish(req);\n }\n }\n\n /** Retire the lane immediately: free KV blocks, open the slot, resolve. */\n private finish(req: Request): void {\n req.state = \"done\";\n if (req.slot >= 0 && this.slots[req.slot] === req) {\n this.host.executor.retireBatchSlot(req.slot);\n this.slots[req.slot] = null;\n }\n this.reservedBlocks -= req.blocksReserved;\n this.stats.completed++;\n const finishedAt = performance.now();\n req.resolve({\n requestId: req.id,\n text: req.text,\n tokenIds: [...req.generatedIds],\n tokensGenerated: req.generatedIds.length,\n finishReason: req.finishReason,\n adapter: req.adapterName ?? undefined,\n submittedAt: req.submittedAt,\n admittedAt: req.admittedAt,\n firstTokenAt: req.firstTokenAt,\n finishedAt,\n ttftMs: req.firstTokenAt - req.submittedAt,\n e2eMs: finishedAt - req.submittedAt,\n });\n }\n}\n","/**\n * Swarm — the MoTA (Mixture of Tuned Adapters) mode-B primitive\n * (docs/research/slm-swarms.md §8): a set of named members (LoRA adapters on\n * one shared base, or the bare base itself), a plan that fans one input out\n * into per-member sub-tasks, and a reduce that joins the results.\n *\n * `swarm.run(input)` submits every planned sub-task to the engine's\n * RequestScheduler with that member's per-request adapter — all sub-tasks\n * decode CONCURRENTLY in the same batched pass over the shared base, so the\n * fan-out costs roughly the slowest lane, not the sum of lanes. The\n * orchestration itself stays user-supplied and thin: default plan broadcasts\n * the input to every member; default reduce returns a member-keyed map of\n * results.\n *\n * Requires `GERBIL_BATCH=N` + `GERBIL_BATCH_LORA=1` (Node/Dawn) — created via\n * `WebGPUEngine.createSwarm()`, which registers every member's adapter first.\n * Greedy-only, like the scheduler underneath.\n */\n\nimport type { ChatMessage } from \"../tokenizer.js\";\nimport type { RequestScheduler, ServeOptions, ServeResult } from \"./scheduler.js\";\n\n/** Per-request options a swarm sub-task may set (the member picks the adapter). */\nexport type SwarmTaskOptions = Omit<ServeOptions, \"adapter\">;\n\n/** One planned sub-task: which member decodes which prompt. */\nexport interface SwarmTask {\n /** Member name (a key of the swarm's `members`). */\n member: string;\n prompt: string | ChatMessage[];\n /** Per-task overrides merged over the run's options. */\n options?: SwarmTaskOptions;\n}\n\n/** One member's completed sub-task (plan order is preserved). */\nexport interface SwarmMemberResult {\n member: string;\n result: ServeResult;\n}\n\n/**\n * Swarm configuration.\n *\n * @template R The reduced result type (defaults to the member-keyed map the\n * default reduce produces).\n */\nexport interface SwarmOptions<R = Record<string, ServeResult>> {\n /**\n * Member name → adapter source (`hf:owner/repo`, URL, or `file:./dir`), or\n * null for a member that decodes on the bare base. Every non-null source is\n * registered on the engine (factors packed into shared GPU buffers once).\n */\n members: Record<string, string | null>;\n /**\n * input → sub-tasks routed to members. Default: broadcast the input to\n * every member (one sub-task each, declaration order).\n */\n plan?: (input: string, members: string[]) => SwarmTask[] | Promise<SwarmTask[]>;\n /**\n * Joined sub-results → final answer. Default: a member-keyed map of\n * ServeResults (a duplicated member's later tasks get `name#2`, `name#3`…).\n */\n reduce?: (results: SwarmMemberResult[]) => R | Promise<R>;\n}\n\n/** Default reduce: member-keyed map, disambiguating duplicated members. */\nfunction reduceToKeyedMap(results: SwarmMemberResult[]): Record<string, ServeResult> {\n const out: Record<string, ServeResult> = {};\n const seen = new Map<string, number>();\n for (const { member, result } of results) {\n const n = (seen.get(member) ?? 0) + 1;\n seen.set(member, n);\n out[n === 1 ? member : `${member}#${n}`] = result;\n }\n return out;\n}\n\n/**\n * A swarm handle: registered members + plan/reduce over the engine's\n * scheduler. Create via {@link WebGPUEngine.createSwarm}.\n */\nexport class Swarm<R = Record<string, ServeResult>> {\n private readonly scheduler: RequestScheduler;\n private readonly memberSources: Record<string, string | null>;\n private readonly plan: SwarmOptions<R>[\"plan\"];\n private readonly reduce: SwarmOptions<R>[\"reduce\"];\n\n constructor(scheduler: RequestScheduler, options: SwarmOptions<R>) {\n if (Object.keys(options.members).length === 0) {\n throw new Error(\"Swarm: members must contain at least one member\");\n }\n this.scheduler = scheduler;\n this.memberSources = { ...options.members };\n this.plan = options.plan;\n this.reduce = options.reduce;\n }\n\n /** Member names, declaration order. */\n get members(): string[] {\n return Object.keys(this.memberSources);\n }\n\n /**\n * Run one input through the swarm: plan → concurrent fan-out (one batched\n * pass across the scheduler's lanes) → reduce.\n *\n * @param input The task input handed to the plan (default plan: broadcast\n * it to every member as the prompt).\n * @param options Per-request options applied to every sub-task (a task's\n * own `options` win field-by-field).\n */\n async run(input: string, options: SwarmTaskOptions = {}): Promise<R> {\n const tasks = this.plan\n ? await this.plan(input, this.members)\n : this.members.map((member): SwarmTask => ({ member, prompt: input }));\n if (tasks.length === 0) {\n throw new Error(\"Swarm: plan produced no sub-tasks\");\n }\n const results = await Promise.all(\n tasks.map(async (task): Promise<SwarmMemberResult> => {\n const result = await this.submitFor(task.member, task.prompt, {\n ...options,\n ...task.options,\n });\n return { member: task.member, result };\n }),\n );\n if (this.reduce) return this.reduce(results);\n // No custom reduce ⇒ R is the default map type.\n return reduceToKeyedMap(results) as R;\n }\n\n /**\n * Mode-A access: decode one prompt with a single member (no plan/reduce).\n * Still rides the shared scheduler, so it batches with any concurrent work.\n */\n generate(\n member: string,\n prompt: string | ChatMessage[],\n options: SwarmTaskOptions = {},\n ): Promise<ServeResult> {\n return this.submitFor(member, prompt, options);\n }\n\n private submitFor(\n member: string,\n prompt: string | ChatMessage[],\n options: SwarmTaskOptions,\n ): Promise<ServeResult> {\n if (!Object.hasOwn(this.memberSources, member)) {\n throw new Error(`Swarm: unknown member \"${member}\" (members: ${this.members.join(\", \")})`);\n }\n // Null source = bare-base member: submit without an adapter.\n const adapter = this.memberSources[member] == null ? undefined : member;\n return this.scheduler.submit(prompt, { ...options, adapter });\n }\n}\n","/**\n * Gepard-1.0 — native streaming TTS architecture (nineninesix/gepard-1.0, Apache-2.0).\n *\n * Gepard is a frame-synchronous multihead codec-LM TTS:\n * 1. BACKBONE: a stock Qwen3.5 transformer body (Qwen3_5ForCausalLM export\n * `nineninesix/qwen3_5-full-attn-only-14`) whose 14 layers are ALL\n * `full_attention` — a strict subset of the hybrid graph qwen3_5.ts builds\n * (same fused-q/gate attention, QK norms, sigmoid output gate, SwiGLU MLP).\n * hidden 1024, 8 Q heads / 2 KV heads, head_dim 256, rope_theta 1e7,\n * partial_rotary_factor 1.0 (full-head rotation — the nested rope_parameters\n * copy is authoritative per the reference implementation), vocab 248320\n * (tied embeddings; the lm_head is discarded — text generation is not a task).\n * 2. OVERLAY (host-side, tiny): 32 parallel classifier heads\n * (`codebook_heads.{0..31}`, cardinalities [8,7,6,6] repeating → 216 logits\n * total) emit ONE WHOLE AUDIO FRAME per forward pass, plus a binary\n * `stop_head` (end-of-speech). The sampled 32 FSQ codes feed back through\n * per-channel embeddings (`audio_embeddings.{i}` [L_i, 32]) → concat(1024) →\n * Linear→GELU→Linear→affine-free LayerNorm → × audio_embed_scale into the\n * next step's input embedding. All overlay math runs on the host (≈2 M MACs\n * per frame — negligible next to the backbone forward).\n * 3. CODEC: NVIDIA NeMo NanoCodec 22 kHz 1.89 kbps 21.5 fps\n * (nvidia/nemo-nano-codec-22khz-1.89kbps-21.5fps): GroupFSQ with 8 groups ×\n * 4 dims (levels [8,7,6,6], 2016 codes/group) + the SAME CausalHiFiGANDecoder\n * family the validated Kani NanoCodec graph implements — only the geometry\n * differs (up_sample_rates [8,8,4,2,2] → hop 1024, input_dim 32). The model\n * emits per-dimension codes directly, so dequantization is a trivial host-side\n * `(code − L//2)/(L//2)` and the decoder graph takes the latent as input.\n *\n * ── STEP-0 verification (live HF, July 2026) ─────────────────────────────────\n * config.json: Qwen3_5ForCausalLM, 14×full_attention, hidden 1024, GQA 8/2,\n * head_dim 256, intermediate 3584, attn_output_gate true, tie_word_embeddings,\n * vocab 248320, rope_parameters { rope_theta 1e7, partial_rotary_factor 1.0,\n * mrope_interleaved [11,11,10] } — with sequential text positions the three\n * mRoPE position streams are equal, so it reduces exactly to 1-D RoPE.\n * gepard_config.json: audio_heads level_audio_0..31 = [8,7,6,6]×8,\n * audio_embed_dim 32, special_tokens { start_of_text 248073, end_of_text 248074,\n * start_of_speech 248070, tts_pad 248076 }, text_repetition { enabled, target 16,\n * apply_below 13, max_repeats 8 }, codec { nvidia/nemo-nano-codec-22khz-1.89kbps-\n * 21.5fps, 8 layers, fsq_levels [8,7,6,6], 22050 Hz }.\n * model.safetensors: model.* = stock Qwen3.5 keys (q_proj fused [4096,1024] —\n * per-head interleaved Q|gate, deinterleaved by the loader like the main Qwen3.5\n * path; RMSNorm weights zero-centered → +1 offset applied at load). Overlay keys:\n * audio_embeddings.{i}.weight [L_i,32], audio_embed_proj.{0,2}.{weight,bias},\n * audio_embed_scale (scalar), codebook_heads.{i}.{weight,bias}, stop_head.*.\n * Voice-cloning stack (ref_compressor.*, null_prefix, supcon_head.*) is present\n * in the checkpoint but NOT wired here (deferred; default voice ships first).\n *\n * Generation (mirrors gepard-inference runner.py):\n * text ids → adaptive repetition layout [ (SOT text EOT)×(R−1) | SOT text EOT SOS ]\n * → prefill → hidden state at SOS seeds frame 0 → frame loop: embed previous\n * frame → one cached decode step → stop head (sigmoid > threshold) → sample all\n * 32 heads independently (temperature/top-k/repetition penalty, fp32) → …\n * → per-channel codes [32, T] → host dequant → NanoCodec decode → 22.05 kHz PCM.\n * Positions are plain sequential (no frame-grouped position ids).\n *\n * The backbone graph takes a host-written `inputs_embeds` [T, 1024] activation\n * instead of `input_ids` (text rows are gathered host-side from the bf16 embed\n * table; audio rows come from the overlay MLP), so the ~1 GB embedding matrix\n * never touches the GPU. Its single output is the LAST position's final-norm\n * hidden state — exposed under the tensor name \"logits\" with config.vocab_size =\n * hidden_size so Executor.forward()'s standard logits readback returns it as-is.\n */\n\nimport type {\n DType,\n ModelArchConfig,\n ModelCapabilities,\n ModelGraph,\n OpNode,\n TensorDesc,\n} from \"../ir.js\";\nimport { CANONICAL_KEYS } from \"../ir.js\";\nimport { DEFAULT_GROUP_SIZE } from \"../quantize.js\";\nimport type { GraphDType, KVDType } from \"./index.js\";\n\n// ── Token / codec layout constants (verified against gepard_config.json) ──\nexport const GEPARD_START_OF_TEXT = 248_073;\nexport const GEPARD_END_OF_TEXT = 248_074;\nexport const GEPARD_START_OF_SPEECH = 248_070;\nexport const GEPARD_END_OF_SPEECH = 248_071;\nexport const GEPARD_TTS_PAD = 248_076;\n\n/** FSQ levels per dimension within each codec group (repeats per group). */\nexport const GEPARD_FSQ_LEVEL_PATTERN = [8, 7, 6, 6] as const;\n/** Number of codec groups (codebooks). */\nexport const GEPARD_NUM_GROUPS = 8;\n/** Total per-dimension channels per frame = groups × dims/group. */\nexport const GEPARD_NUM_CHANNELS = 32;\n/** NanoCodec 21.5 fps decoder geometry (codec_config.yaml, mlx-community mirror). */\nexport const GEPARD_CODEC_UP_SAMPLE_RATES = [8, 8, 4, 2, 2] as const;\nexport const GEPARD_CODEC_INPUT_DIM = 32;\n/** PCM samples per audio frame (product of the up-sample rates). */\nexport const GEPARD_HOP = 1024;\nexport const GEPARD_SAMPLE_RATE = 22_050;\n\n/** Per-channel FSQ cardinalities in head order (channel c = group⌊c/4⌋, dim c%4). */\nexport function gepardChannelLevels(): number[] {\n const out: number[] = [];\n for (let g = 0; g < GEPARD_NUM_GROUPS; g++) {\n out.push(...GEPARD_FSQ_LEVEL_PATTERN);\n }\n return out;\n}\n\n/** Text-repetition layout config (stamped into gepard_config.json). */\nexport interface GepardTextRepetition {\n enabled: boolean;\n targetTextTokens: number;\n applyBelow: number;\n maxRepeats: number;\n}\n\n/** Parsed gepard_config.json — everything the host driver needs. */\nexport interface GepardConfig {\n /** The nested Qwen3.5 backbone config (fed to generateGepardBackboneGraph). */\n backboneConfig: Record<string, unknown>;\n /** Per-head vocab sizes in channel order (level_audio_0..31). */\n vocabSizes: number[];\n audioEmbedDim: number;\n startOfText: number;\n endOfText: number;\n startOfSpeech: number;\n textRepetition: GepardTextRepetition;\n /** Codec identity + geometry from the config's codec block. */\n codecId: string;\n fsqLevels: number[];\n sampleRate: number;\n}\n\n/** Matches `level_audio_{i}` head names (channel index = numeric suffix). */\nconst LEVEL_AUDIO_RE = /^level_audio_(\\d+)$/;\n\n/**\n * Parse gepard_config.json. Head order is recovered from the numeric suffix of\n * each `level_audio_{i}` key (NOT the serialized key order), so the wiring is\n * immune to any JSON round-trip that re-sorts keys.\n */\nexport function parseGepardConfig(raw: Record<string, unknown>): GepardConfig {\n const backboneConfig = raw.backbone_config as Record<string, unknown> | undefined;\n if (!backboneConfig) {\n throw new Error(\"gepard_config.json has no backbone_config — not a Gepard checkpoint.\");\n }\n const audioHeads = (raw.audio_heads as Record<string, number>) ?? {};\n const byIndex: number[] = [];\n for (const [name, size] of Object.entries(audioHeads)) {\n const m = LEVEL_AUDIO_RE.exec(name);\n if (!m) {\n throw new Error(`Unexpected audio head name \"${name}\" in gepard_config.json.`);\n }\n byIndex[Number(m[1])] = size;\n }\n if (byIndex.length === 0) {\n throw new Error(\"gepard_config.json has no audio_heads.\");\n }\n for (let i = 0; i < byIndex.length; i++) {\n if (byIndex[i] == null) {\n throw new Error(`gepard_config.json audio_heads is missing level_audio_${i}.`);\n }\n }\n const special = (raw.special_tokens as Record<string, number>) ?? {};\n const rep = (raw.text_repetition as Record<string, unknown>) ?? {};\n const codec = (raw.codec as Record<string, unknown>) ?? {};\n return {\n backboneConfig,\n vocabSizes: byIndex,\n audioEmbedDim: (raw.audio_embed_dim as number) ?? 32,\n startOfText: special.start_of_text ?? GEPARD_START_OF_TEXT,\n endOfText: special.end_of_text ?? GEPARD_END_OF_TEXT,\n startOfSpeech: special.start_of_speech ?? GEPARD_START_OF_SPEECH,\n textRepetition: {\n enabled: (rep.enabled as boolean) ?? false,\n targetTextTokens: (rep.target_text_tokens as number) ?? 16,\n applyBelow: (rep.apply_below as number) ?? 13,\n maxRepeats: (rep.max_repeats as number) ?? 8,\n },\n codecId: (codec.codec_id as string) ?? \"nvidia/nemo-nano-codec-22khz-1.89kbps-21.5fps\",\n fsqLevels: (codec.fsq_levels as number[]) ?? [...GEPARD_FSQ_LEVEL_PATTERN],\n sampleRate: (codec.sample_rate as number) ?? GEPARD_SAMPLE_RATE,\n };\n}\n\n/**\n * Build the (possibly repeated) text-id layout — mirrors the reference\n * TextRepeater byte-for-byte (text_repetition.py):\n * R == 1 → [ SOT, *text, EOT, SOS ]\n * R > 1 → [ SOT, *text, EOT ] × (R−1) + [ SOT, *text, EOT, SOS ]\n * Only the final (canonical) copy carries SOS. R is deterministic from the\n * text-token count: ceil(target / n) capped at maxRepeats, applied only when\n * n < applyBelow (short prompts derail without the extra text mass).\n */\nexport function buildGepardTextLayout(textTokenIds: number[], cfg: GepardConfig): number[] {\n const rep = cfg.textRepetition;\n const n = textTokenIds.length;\n let repeats = 1;\n if (rep.enabled && n > 0 && n < rep.applyBelow && n < rep.targetTextTokens) {\n repeats = Math.max(1, Math.min(Math.ceil(rep.targetTextTokens / n), rep.maxRepeats));\n }\n const block = [cfg.startOfText, ...textTokenIds, cfg.endOfText];\n const out: number[] = [];\n for (let r = 0; r < repeats - 1; r++) {\n out.push(...block);\n }\n out.push(...block, cfg.startOfSpeech);\n return out;\n}\n\n/**\n * Dequantize per-channel FSQ codes [32, T] (channel-major) into the decoder\n * latent [32, T] f32: value = (code − L//2) / (L//2), matching\n * UnfoldedCodecModel.decode_from_codes / codec_ops.dequantize_codes.\n */\nexport function gepardCodesToLatent(codes: Uint32Array, numFrames: number): Float32Array {\n const levels = gepardChannelLevels();\n const latent = new Float32Array(GEPARD_NUM_CHANNELS * numFrames);\n for (let c = 0; c < GEPARD_NUM_CHANNELS; c++) {\n const scale = Math.max(1, Math.floor(levels[c] / 2));\n const base = c * numFrames;\n for (let t = 0; t < numFrames; t++) {\n latent[base + t] = (codes[base + t] - scale) / scale;\n }\n }\n return latent;\n}\n\n// ════════════════════════════════════════════════════════════════════════════\n// Backbone graph (stock Qwen3.5 full-attention body, embeds in → hidden out).\n//\n// Mirrors qwen3_5.ts's full-attention block exactly (fused Residual+RMSNorm\n// chaining included) with three deltas:\n// • input is a host-written `inputs_embeds` [T, hidden] activation (the text\n// rows are gathered from the bf16 embed table host-side; audio-frame rows\n// come from the overlay MLP) — no Embedding op, no embed table on the GPU;\n// • no Mamba branch (every Gepard layer is full_attention);\n// • no lm_head — the output is SliceLastRow(final_norm) exposed as \"logits\"\n// [1, hidden] with config.vocab_size = hidden_size, so Executor.forward()'s\n// standard logits readback returns the final hidden state of the last\n// position (which the host-side 32+1 heads consume).\n// ════════════════════════════════════════════════════════════════════════════\n\nexport function generateGepardBackboneGraph(\n backboneConfig: Record<string, unknown>,\n dtype?: GraphDType,\n groupSizeOverride?: number,\n kvDtype?: KVDType,\n): ModelGraph {\n const hidden_size = backboneConfig.hidden_size as number;\n const num_layers = backboneConfig.num_hidden_layers as number;\n const num_heads = backboneConfig.num_attention_heads as number;\n const num_kv_heads = (backboneConfig.num_key_value_heads as number) ?? num_heads;\n const intermediate_size = backboneConfig.intermediate_size as number;\n const context_length = (backboneConfig.max_position_embeddings as number) ?? 262_144;\n const rms_norm_eps = (backboneConfig.rms_norm_eps as number) ?? 1e-6;\n const head_dim = (backboneConfig.head_dim as number) ?? Math.floor(hidden_size / num_heads);\n\n const q_dim = num_heads * head_dim;\n const kv_dim = num_kv_heads * head_dim;\n\n // RoPE: the nested rope_parameters copy is authoritative (the reference\n // implementation forces partial_rotary_factor into it; Gepard ships 1.0 =\n // full-head rotation). With sequential positions the interleaved mRoPE\n // sections reduce exactly to 1-D RoPE, so the standard RoPE op applies.\n const ropeParams = backboneConfig.rope_parameters as Record<string, unknown> | undefined;\n const rope_base =\n (ropeParams?.rope_theta as number) ?? (backboneConfig.rope_theta as number) ?? 10_000_000.0;\n const partialRotaryFactor =\n (ropeParams?.partial_rotary_factor as number) ??\n (backboneConfig.partial_rotary_factor as number) ??\n 1.0;\n const rope_dim = Math.floor(head_dim * partialRotaryFactor);\n\n const layerTypes = (backboneConfig.layer_types as string[]) ?? [];\n for (let i = 0; i < num_layers; i++) {\n if (layerTypes.length > i && layerTypes[i] !== \"full_attention\") {\n throw new Error(\n `Gepard backbone expects all-full-attention layers; layer ${i} is \"${layerTypes[i]}\".`,\n );\n }\n }\n\n // vocab_size is set to hidden_size ON PURPOSE: the graph's \"logits\" output is\n // the [1, hidden] final hidden state, and Executor.forward() reads back\n // config.vocab_size floats from the tensor named \"logits\".\n const config: ModelArchConfig = {\n hidden_size,\n num_layers,\n num_heads,\n num_kv_heads,\n head_dim,\n intermediate_size,\n vocab_size: hidden_size,\n context_length,\n rms_norm_eps,\n norm_type: \"rmsnorm\",\n rope_base,\n rope_dim,\n kv_layout: \"LHSd\",\n is_moe: false,\n has_vision_tower: false,\n };\n const capabilities: ModelCapabilities = { text: true, vision: false, moe: false };\n\n const tensors: Record<string, TensorDesc> = {};\n const nodes: OpNode[] = [];\n const executionOrder: string[] = [];\n const addTensor = (desc: TensorDesc): void => {\n tensors[desc.name] = desc;\n };\n const addNode = (node: OpNode): void => {\n nodes.push(node);\n executionOrder.push(node.id);\n };\n\n const useQ4 = dtype === \"q4\";\n const groupSize = groupSizeOverride ?? DEFAULT_GROUP_SIZE;\n\n const addLinearOp = (\n id: string,\n activationInput: string,\n weightName: string,\n weightShape: number[],\n outputName: string,\n K: number,\n N: number,\n ): void => {\n if (useQ4) {\n const wQ = `${weightName}.q`;\n const wScales = `${weightName}.scales`;\n const wZeros = `${weightName}.zeros`;\n const totalElements = K * N;\n addTensor({\n name: wQ,\n shape: [Math.ceil(totalElements / 8)],\n dtype: \"u32\",\n storage: \"constant\",\n });\n addTensor({\n name: wScales,\n shape: [Math.ceil(totalElements / groupSize)],\n dtype: \"f32\",\n storage: \"constant\",\n });\n addTensor({\n name: wZeros,\n shape: [Math.ceil(totalElements / groupSize)],\n dtype: \"f32\",\n storage: \"constant\",\n });\n addNode({\n id,\n opType: \"MatMulInt4\",\n inputs: [activationInput, wQ, wScales, wZeros],\n outputs: [outputName],\n attributes: { M_tensor: activationInput, K, N, group_size: groupSize },\n });\n return;\n }\n addTensor({\n name: weightName,\n shape: weightShape,\n dtype: \"f32\",\n storage: \"constant\",\n safetensorsKey: weightName,\n });\n addNode({\n id,\n opType: \"MatMul\",\n inputs: [activationInput, weightName],\n outputs: [outputName],\n attributes: { M_tensor: activationInput, K, N },\n });\n };\n\n // ── Input: host-written embeddings (read before written → persistent) ──\n addTensor({\n name: \"inputs_embeds\",\n shape: [\"T\", hidden_size],\n dtype: \"f32\",\n storage: \"activation\",\n });\n\n // ── Full-attention block (identical math to qwen3_5.ts buildFullAttentionBlock) ──\n const buildAttentionBlock = (i: number, prefix: string, norm1Out: string): string => {\n const qOut = `${prefix}_q`;\n const gateOut = `${prefix}_attn_gate`;\n const kOut = `${prefix}_k`;\n const vOut = `${prefix}_v`;\n addTensor({ name: qOut, shape: [\"T\", q_dim], dtype: \"f32\", storage: \"activation\" });\n addTensor({ name: gateOut, shape: [\"T\", q_dim], dtype: \"f32\", storage: \"activation\" });\n addTensor({ name: kOut, shape: [\"T\", kv_dim], dtype: \"f32\", storage: \"activation\" });\n addTensor({ name: vOut, shape: [\"T\", kv_dim], dtype: \"f32\", storage: \"activation\" });\n\n addLinearOp(\n `${prefix}_q_proj`,\n norm1Out,\n CANONICAL_KEYS.qProj(i),\n [q_dim, hidden_size],\n qOut,\n hidden_size,\n q_dim,\n );\n addLinearOp(\n `${prefix}_gate_proj`,\n norm1Out,\n CANONICAL_KEYS.attnGate(i),\n [q_dim, hidden_size],\n gateOut,\n hidden_size,\n q_dim,\n );\n addLinearOp(\n `${prefix}_k_proj`,\n norm1Out,\n CANONICAL_KEYS.kProj(i),\n [kv_dim, hidden_size],\n kOut,\n hidden_size,\n kv_dim,\n );\n addLinearOp(\n `${prefix}_v_proj`,\n norm1Out,\n CANONICAL_KEYS.vProj(i),\n [kv_dim, hidden_size],\n vOut,\n hidden_size,\n kv_dim,\n );\n\n const qNormW = CANONICAL_KEYS.qNorm(i);\n const kNormW = CANONICAL_KEYS.kNorm(i);\n addTensor({\n name: qNormW,\n shape: [head_dim],\n dtype: \"f32\",\n storage: \"constant\",\n safetensorsKey: qNormW,\n });\n addTensor({\n name: kNormW,\n shape: [head_dim],\n dtype: \"f32\",\n storage: \"constant\",\n safetensorsKey: kNormW,\n });\n const qNormed = `${prefix}_q_normed`;\n const kNormed = `${prefix}_k_normed`;\n addTensor({ name: qNormed, shape: [\"T\", q_dim], dtype: \"f32\", storage: \"activation\" });\n addTensor({ name: kNormed, shape: [\"T\", kv_dim], dtype: \"f32\", storage: \"activation\" });\n addNode({\n id: `${prefix}_q_norm`,\n opType: \"RMSNorm\",\n inputs: [qOut, qNormW],\n outputs: [qNormed],\n attributes: { hidden_size: head_dim, eps: rms_norm_eps, seq_len_tensor: qOut },\n });\n addNode({\n id: `${prefix}_k_norm`,\n opType: \"RMSNorm\",\n inputs: [kOut, kNormW],\n outputs: [kNormed],\n attributes: { hidden_size: head_dim, eps: rms_norm_eps, seq_len_tensor: kOut },\n });\n\n addNode({\n id: `${prefix}_rope`,\n opType: \"RoPE\",\n inputs: [qNormed, kNormed],\n outputs: [qNormed, kNormed],\n attributes: {\n head_dim,\n num_q_heads: num_heads,\n num_kv_heads,\n rope_base,\n rope_dim,\n partial_rotary: true,\n seq_len_tensor: qNormed,\n },\n });\n\n const kvCacheDtype: DType = kvDtype ?? \"f32\";\n const kCache = `${prefix}_k_cache`;\n const vCache = `${prefix}_v_cache`;\n addTensor({ name: kCache, shape: [\"L_max\", kv_dim], dtype: kvCacheDtype, storage: \"kv_cache\" });\n addTensor({ name: vCache, shape: [\"L_max\", kv_dim], dtype: kvCacheDtype, storage: \"kv_cache\" });\n addNode({\n id: `${prefix}_kv_cache_k`,\n opType: \"KVCacheAppend\",\n inputs: [kNormed],\n outputs: [kCache],\n attributes: { width: kv_dim, T_tensor: kNormed },\n });\n addNode({\n id: `${prefix}_kv_cache_v`,\n opType: \"KVCacheAppend\",\n inputs: [vOut],\n outputs: [vCache],\n attributes: { width: kv_dim, T_tensor: vOut },\n });\n\n const attnOut = `${prefix}_attn_out`;\n addTensor({ name: attnOut, shape: [\"T\", q_dim], dtype: \"f32\", storage: \"activation\" });\n addNode({\n id: `${prefix}_attn`,\n opType: \"Attention\",\n inputs: [qNormed, kCache, vCache],\n outputs: [attnOut],\n attributes: {\n hidden_size: q_dim,\n num_q_heads: num_heads,\n num_kv_heads,\n head_dim,\n causal: true,\n layer_index: i,\n },\n });\n\n const gatedOut = `${prefix}_gated`;\n addTensor({ name: gatedOut, shape: [\"T\", q_dim], dtype: \"f32\", storage: \"activation\" });\n addNode({\n id: `${prefix}_sigmoid_gate`,\n opType: \"SigmoidGate\",\n inputs: [attnOut, gateOut],\n outputs: [gatedOut],\n attributes: { count_tensor: attnOut },\n });\n\n const oProjOut = `${prefix}_o_proj_out`;\n addTensor({ name: oProjOut, shape: [\"T\", hidden_size], dtype: \"f32\", storage: \"activation\" });\n addLinearOp(\n `${prefix}_o_proj`,\n gatedOut,\n CANONICAL_KEYS.oProj(i),\n [hidden_size, q_dim],\n oProjOut,\n q_dim,\n hidden_size,\n );\n return oProjOut;\n };\n\n // ── Transformer layers (fused ResidualRMSNorm chaining like qwen3_5.ts) ──\n let prevOutput = \"inputs_embeds\";\n let pendingNorm1Out: string | null = null;\n\n for (let i = 0; i < num_layers; i++) {\n const prefix = `layer${i}`;\n\n let norm1Out: string;\n if (pendingNorm1Out) {\n norm1Out = pendingNorm1Out;\n } else {\n const normWeightName = CANONICAL_KEYS.layerInputNorm(i);\n addTensor({\n name: normWeightName,\n shape: [hidden_size],\n dtype: \"f32\",\n storage: \"constant\",\n safetensorsKey: normWeightName,\n });\n norm1Out = `${prefix}_norm1_out`;\n addTensor({ name: norm1Out, shape: [\"T\", hidden_size], dtype: \"f32\", storage: \"activation\" });\n addNode({\n id: `${prefix}_norm1`,\n opType: \"RMSNorm\",\n inputs: [prevOutput, normWeightName],\n outputs: [norm1Out],\n attributes: { hidden_size, eps: rms_norm_eps, seq_len_tensor: prevOutput },\n });\n }\n\n const attnOutput = buildAttentionBlock(i, prefix, norm1Out);\n\n const resid1Out = `${prefix}_resid1`;\n const postNormW = CANONICAL_KEYS.layerPostAttnNorm(i);\n const norm2Out = `${prefix}_norm2_out`;\n addTensor({ name: resid1Out, shape: [\"T\", hidden_size], dtype: \"f32\", storage: \"activation\" });\n addTensor({\n name: postNormW,\n shape: [hidden_size],\n dtype: \"f32\",\n storage: \"constant\",\n safetensorsKey: postNormW,\n });\n addTensor({ name: norm2Out, shape: [\"T\", hidden_size], dtype: \"f32\", storage: \"activation\" });\n addNode({\n id: `${prefix}_resid1_norm2`,\n opType: \"ResidualRMSNorm\",\n inputs: [prevOutput, attnOutput, postNormW],\n outputs: [resid1Out, norm2Out],\n attributes: { hidden_size, eps: rms_norm_eps, seq_len_tensor: prevOutput },\n });\n\n const gateW = CANONICAL_KEYS.gateProj(i);\n const upW = CANONICAL_KEYS.upProj(i);\n const downW = CANONICAL_KEYS.downProj(i);\n const mlpGateOut = `${prefix}_gate_out`;\n const upOut = `${prefix}_up_out`;\n const swigluOut = `${prefix}_swiglu_out`;\n const mlpOut = `${prefix}_mlp_out`;\n addTensor({\n name: mlpGateOut,\n shape: [\"T\", intermediate_size],\n dtype: \"f32\",\n storage: \"activation\",\n });\n addTensor({\n name: upOut,\n shape: [\"T\", intermediate_size],\n dtype: \"f32\",\n storage: \"activation\",\n });\n addTensor({\n name: swigluOut,\n shape: [\"T\", intermediate_size],\n dtype: \"f32\",\n storage: \"activation\",\n });\n addTensor({ name: mlpOut, shape: [\"T\", hidden_size], dtype: \"f32\", storage: \"activation\" });\n addLinearOp(\n `${prefix}_gate`,\n norm2Out,\n gateW,\n [intermediate_size, hidden_size],\n mlpGateOut,\n hidden_size,\n intermediate_size,\n );\n addLinearOp(\n `${prefix}_up`,\n norm2Out,\n upW,\n [intermediate_size, hidden_size],\n upOut,\n hidden_size,\n intermediate_size,\n );\n addNode({\n id: `${prefix}_swiglu`,\n opType: \"SwiGLU\",\n inputs: [mlpGateOut, upOut],\n outputs: [swigluOut],\n attributes: { count_tensor: mlpGateOut },\n });\n addLinearOp(\n `${prefix}_down`,\n swigluOut,\n downW,\n [hidden_size, intermediate_size],\n mlpOut,\n intermediate_size,\n hidden_size,\n );\n\n const resid2Out = `${prefix}_resid2`;\n addTensor({ name: resid2Out, shape: [\"T\", hidden_size], dtype: \"f32\", storage: \"activation\" });\n if (i < num_layers - 1) {\n const nextNormW = CANONICAL_KEYS.layerInputNorm(i + 1);\n addTensor({\n name: nextNormW,\n shape: [hidden_size],\n dtype: \"f32\",\n storage: \"constant\",\n safetensorsKey: nextNormW,\n });\n const nextNorm1Out = `layer${i + 1}_norm1_out`;\n addTensor({\n name: nextNorm1Out,\n shape: [\"T\", hidden_size],\n dtype: \"f32\",\n storage: \"activation\",\n });\n addNode({\n id: `${prefix}_resid2_norm1`,\n opType: \"ResidualRMSNorm\",\n inputs: [resid1Out, mlpOut, nextNormW],\n outputs: [resid2Out, nextNorm1Out],\n attributes: { hidden_size, eps: rms_norm_eps, seq_len_tensor: resid1Out },\n });\n pendingNorm1Out = nextNorm1Out;\n } else {\n addNode({\n id: `${prefix}_resid2`,\n opType: \"Add\",\n inputs: [resid1Out, mlpOut],\n outputs: [resid2Out],\n attributes: { count_tensor: resid1Out, hidden_size },\n });\n pendingNorm1Out = null;\n }\n prevOutput = resid2Out;\n }\n\n // ── Final norm → last row = the hidden state the host-side heads consume ──\n addTensor({\n name: CANONICAL_KEYS.FINAL_NORM,\n shape: [hidden_size],\n dtype: \"f32\",\n storage: \"constant\",\n safetensorsKey: CANONICAL_KEYS.FINAL_NORM,\n });\n addTensor({\n name: \"final_norm_out\",\n shape: [\"T\", hidden_size],\n dtype: \"f32\",\n storage: \"activation\",\n });\n addNode({\n id: \"final_norm\",\n opType: \"RMSNorm\",\n inputs: [prevOutput, CANONICAL_KEYS.FINAL_NORM],\n outputs: [\"final_norm_out\"],\n attributes: { hidden_size, eps: rms_norm_eps, seq_len_tensor: prevOutput },\n });\n\n // \"logits\" is the LAST position's final-norm hidden state [1, hidden] — named\n // so Executor.forward()'s standard readback (config.vocab_size == hidden_size\n // floats from the \"logits\" buffer) returns it without any executor change.\n addTensor({ name: \"logits\", shape: [1, hidden_size], dtype: \"f32\", storage: \"activation\" });\n addNode({\n id: \"slice_last_row\",\n opType: \"SliceLastRow\",\n inputs: [\"final_norm_out\"],\n outputs: [\"logits\"],\n attributes: { width: hidden_size },\n });\n\n return {\n architecture: \"GepardForTTS\",\n config,\n capabilities,\n tensors,\n nodes,\n executionOrder,\n inputs: [\"inputs_embeds\"],\n outputs: [\"logits\"],\n };\n}\n","/**\n * Gepard-1.0 — native streaming text-to-speech engine for Gerbil's WebGPU backend.\n *\n * Gepard (nineninesix/gepard-1.0, Apache-2.0) is a frame-synchronous multihead\n * codec-LM TTS. Unlike the token-serial Kani/Oute engines (which emit one codec\n * token per forward), Gepard emits ONE WHOLE AUDIO FRAME per backbone forward:\n *\n * 1. BACKBONE (GPU): stock Qwen3.5 full-attention body (14 layers, hidden 1024)\n * run through generateGepardBackboneGraph — input is a host-written\n * `inputs_embeds` row, output is the last position's final-norm hidden state.\n * 2. OVERLAY (host): 32 parallel classifier heads (cardinalities [8,7,6,6]×8,\n * 216 logits total) + a binary stop head read the hidden state; the sampled\n * 32 FSQ codes feed back through per-channel embeddings → concat → GELU MLP\n * → affine-free LayerNorm → × audio_embed_scale as the next step's input.\n * 3. CODEC (GPU): NanoCodec 21.5 fps decoder (same validated CausalHiFiGAN\n * graph family as Kani's codec, rates [8,8,4,2,2], hop 1024) turns the\n * per-channel codes into 22.05 kHz PCM — decoded incrementally in chunks\n * with left-context lookback, so audio streams out while the model is\n * still generating (≈1.5 s of audio per 32-frame chunk).\n *\n * Mirrors gepard-inference (runner.py) semantics: adaptive text repetition,\n * SOS-seeded first frame, stop-head termination, independent per-head sampling\n * (temperature / top-k / windowed repetition penalty) in fp32. Voice cloning\n * (the ref_compressor speaker prefix) is NOT wired yet — the default voice ships\n * first; cloning is a documented follow-up.\n */\n\nimport {\n buildGepardTextLayout,\n GEPARD_CODEC_INPUT_DIM,\n GEPARD_CODEC_UP_SAMPLE_RATES,\n GEPARD_HOP,\n GEPARD_NUM_CHANNELS,\n type GepardConfig,\n generateGepardBackboneGraph,\n gepardCodesToLatent,\n parseGepardConfig,\n} from \"./architectures/gepard_tts.js\";\nimport { generateNanoCodecDecoderGraph } from \"./architectures/kani_tts.js\";\nimport type { GPUContext } from \"./device.js\";\nimport { initGPU } from \"./device.js\";\nimport { Executor } from \"./executor.js\";\nimport { type LoadedGepardTTS, loadGepardTTS, quantizeBackboneInt4 } from \"./model-loader.js\";\nimport type { Tokenizer } from \"./tokenizer.js\";\n\n/** Backbone weight precision for the codec-LM. */\nexport type GepardDType = \"q4\" | \"f32\";\n\n/** Codec decode chunking: 32 frames ≈ 1.49 s of audio per streamed chunk. */\nconst GEPARD_CODEC_CHUNK_FRAMES = 32;\n/**\n * Left-context warm-up frames re-decoded (and discarded) per chunk. The decoder\n * is fully causal with a bounded receptive field; 64 frames (≈65k samples) of\n * lookback keeps chunked output numerically identical to a monolithic decode\n * while staying under the WebGPU per-dimension dispatch cap.\n */\nconst GEPARD_CODEC_LOOKBACK_FRAMES = 64;\n/** Hard ceiling on generated frames (the reference runner's max_frames). */\nconst DEFAULT_MAX_FRAMES = 2000;\n/** PyTorch nn.LayerNorm default epsilon (audio_embed_proj's affine-free LN). */\nconst LAYERNORM_EPS = 1e-5;\n\nexport interface GepardTTSOptions {\n /** Backbone repo (default nineninesix/gepard-1.0, Apache-2.0). */\n repo?: string;\n /** NanoCodec repo (default the mlx-community 21.5 fps MLX mirror). */\n codecRepo?: string;\n revision?: string;\n hfToken?: string;\n cacheDir?: string;\n /**\n * Backbone weight precision (default \"q4\"):\n * • \"q4\" — group-wise INT4 (W4A16) on the Qwen3.5 linear projections\n * (backbone ~1.05 GB f32 → ~0.13 GB). Recommended default.\n * • \"f32\" — full precision (largest, highest fidelity).\n * The overlay always runs f32 on the host; the codec decoder always runs f32.\n */\n dtype?: GepardDType;\n /** Max KV-cache length: text layout + 1 position per audio frame. Default 2048. */\n maxSeqLen?: number;\n onProgress?: (loaded: number, total: number, message: string) => void;\n}\n\n/** One streamed audio chunk (decoded incrementally during generation). */\nexport interface GepardAudioChunk {\n /** Mono PCM in [-1, 1] for this chunk only. */\n pcm: Float32Array;\n /** Sample rate (22050). */\n sampleRate: number;\n /** Index of the first audio frame this chunk covers. */\n frameIndex: number;\n /** True for the last chunk of the utterance. */\n isFinal: boolean;\n}\n\nexport interface GepardSpeakOptions {\n /** Sampling temperature (default 0.4 — the reference production operating point). */\n temperature?: number;\n /** Top-k cutoff per head (default 0 = disabled). */\n topK?: number;\n /** Stop-head sigmoid threshold (default 0.5). */\n stopThreshold?: number;\n /** Max audio frames to generate (caps duration; default 2000, ~93 s). */\n maxFrames?: number;\n /** Per-head repetition penalty over a recent-frame window (default 1.0 = off). */\n repetitionPenalty?: number;\n /** Number of recent frames tracked for repetitionPenalty (default 32). */\n repetitionWindow?: number;\n /**\n * Streaming callback: called with each decoded audio chunk while generation is\n * still running (frame-synchronous decode → real streaming, not post-hoc\n * chunking). The final chunk carries `isFinal: true`. The returned SpeakResult\n * still contains the full assembled PCM.\n */\n onChunk?: (chunk: GepardAudioChunk) => void;\n}\n\nexport interface GepardSpeakResult {\n /** Mono PCM in [-1, 1]. */\n pcm: Float32Array;\n /** Sample rate (22050). */\n sampleRate: number;\n /** Number of audio frames decoded. */\n frames: number;\n /** Audio duration in seconds. */\n audioSeconds: number;\n}\n\n/** Build a fresh map of just the constant weights a graph references. */\nfunction selectGraphWeights(\n graph: { tensors: Record<string, { storage: string; safetensorsKey?: string }> },\n weights: Map<string, { data: ArrayBufferView; shape: number[] }>,\n): Map<string, { data: ArrayBufferView; shape: number[] }> {\n const out = new Map<string, { data: ArrayBufferView; shape: number[] }>();\n for (const [name, desc] of Object.entries(graph.tensors)) {\n if (desc.storage !== \"constant\") {\n continue;\n }\n const w =\n weights.get(name) ?? (desc.safetensorsKey ? weights.get(desc.safetensorsKey) : undefined);\n if (w) {\n out.set(name, w);\n }\n }\n return out;\n}\n\n/** Abramowitz–Stegun 7.1.26 erf approximation (max |err| ≈ 1.5e-7). */\nfunction erf(x: number): number {\n const sign = x < 0 ? -1 : 1;\n const ax = Math.abs(x);\n const t = 1 / (1 + 0.3275911 * ax);\n const y =\n 1 -\n ((((1.061405429 * t - 1.453152027) * t + 1.421413741) * t - 0.284496736) * t + 0.254829592) *\n t *\n Math.exp(-ax * ax);\n return sign * y;\n}\n\n/** Exact (erf-based) GELU, matching PyTorch nn.GELU()'s default. */\nfunction gelu(x: number): number {\n return 0.5 * x * (1 + erf(x / Math.SQRT2));\n}\n\n/** y = W·x + b for a row-major [out, in] weight. */\nfunction linear(\n w: Float32Array,\n b: Float32Array | null,\n x: Float32Array,\n outDim: number,\n inDim: number,\n out: Float32Array,\n): void {\n for (let o = 0; o < outDim; o++) {\n let acc = b ? b[o] : 0;\n const base = o * inDim;\n for (let k = 0; k < inDim; k++) {\n acc += w[base + k] * x[k];\n }\n out[o] = acc;\n }\n}\n\nexport class GepardTTS {\n private ctx: GPUContext;\n private loaded: LoadedGepardTTS;\n private tokenizer: Tokenizer;\n private cfg: GepardConfig;\n private maxSeqLen: number;\n private hidden: number;\n /** Backbone executor (built once; reused across speak() calls). */\n private backboneExec: Executor;\n /** Cached codec executor for the steady-state window size (chunk + lookback). */\n private codecExecCache = new Map<number, Executor>();\n private _destroyed = false;\n\n /** The selected backbone precision (\"q4\" or \"f32\"). */\n readonly dtype: GepardDType;\n\n // ── Overlay weights resolved once (f32) ──\n private audioEmbTables: Float32Array[]; // [L_i, audio_embed_dim] per channel\n private projW0: Float32Array;\n private projB0: Float32Array;\n private projW2: Float32Array;\n private projB2: Float32Array;\n private audioEmbedScale: number;\n private headW: Float32Array[]; // [L_i, hidden] per channel\n private headB: Float32Array[];\n private stopW: Float32Array;\n private stopB: number;\n\n private constructor(\n ctx: GPUContext,\n loaded: LoadedGepardTTS,\n maxSeqLen: number,\n dtype: GepardDType,\n ) {\n this.ctx = ctx;\n this.loaded = loaded;\n this.tokenizer = loaded.tokenizer;\n this.cfg = parseGepardConfig(loaded.gepardConfig);\n this.maxSeqLen = maxSeqLen;\n this.hidden = this.cfg.backboneConfig.hidden_size as number;\n this.dtype = dtype;\n\n // ── Resolve the host-side overlay weights once. ──\n const overlay = loaded.overlayWeights;\n const need = (key: string): Float32Array => {\n const w = overlay.get(key);\n if (!w) {\n throw new Error(`Gepard overlay weight missing: ${key}`);\n }\n return w.data;\n };\n const n = this.cfg.vocabSizes.length;\n if (n !== GEPARD_NUM_CHANNELS) {\n throw new Error(`Gepard expects ${GEPARD_NUM_CHANNELS} audio heads, config has ${n}.`);\n }\n this.audioEmbTables = [];\n this.headW = [];\n this.headB = [];\n for (let i = 0; i < n; i++) {\n this.audioEmbTables.push(need(`audio_embeddings.${i}.weight`));\n this.headW.push(need(`codebook_heads.${i}.weight`));\n this.headB.push(need(`codebook_heads.${i}.bias`));\n }\n this.projW0 = need(\"audio_embed_proj.0.weight\");\n this.projB0 = need(\"audio_embed_proj.0.bias\");\n this.projW2 = need(\"audio_embed_proj.2.weight\");\n this.projB2 = need(\"audio_embed_proj.2.bias\");\n this.audioEmbedScale = need(\"audio_embed_scale\")[0];\n this.stopW = need(\"stop_head.weight\");\n this.stopB = need(\"stop_head.bias\")[0];\n\n // ── Build + upload the backbone graph once. ──\n const graph = generateGepardBackboneGraph(\n this.cfg.backboneConfig,\n this.dtype === \"q4\" ? \"q4\" : undefined,\n );\n if (this.dtype === \"q4\") {\n quantizeBackboneInt4(graph, loaded.backboneWeights);\n }\n this.backboneExec = new Executor(ctx, graph, { maxSeqLen, kvMode: \"f32\" });\n this.backboneExec.uploadWeightsMap(selectGraphWeights(graph, loaded.backboneWeights));\n this.backboneExec.initBindGroups();\n }\n\n static async create(options: GepardTTSOptions = {}): Promise<GepardTTS> {\n const ctx = await initGPU();\n const loaded = await loadGepardTTS({\n repo: options.repo,\n codecRepo: options.codecRepo,\n revision: options.revision,\n hfToken: options.hfToken,\n cacheDir: options.cacheDir,\n onProgress: options.onProgress,\n });\n const ctxLen = (loaded.rawConfig.max_position_embeddings as number) ?? 262_144;\n const maxSeqLen = Math.min(options.maxSeqLen ?? 2048, ctxLen);\n return new GepardTTS(ctx, loaded, maxSeqLen, options.dtype ?? \"q4\");\n }\n\n /** NanoCodec's fixed output sample rate (Hz). */\n get sampleRate(): number {\n return this.cfg.sampleRate;\n }\n\n /** Preset voices. Gepard ships one default voice (cloning is a follow-up). */\n availableVoices(): string[] {\n return [];\n }\n\n /** Gather text-token rows from the raw BF16 embed table → f32 [T, hidden]. */\n private embedTextTokens(ids: number[]): Float32Array {\n const h = this.hidden;\n const table = this.loaded.embedTokensBF16;\n const out = new Float32Array(ids.length * h);\n const view = new DataView(out.buffer);\n for (let t = 0; t < ids.length; t++) {\n const rowBase = ids[t] * h;\n const dstBase = t * h;\n for (let k = 0; k < h; k++) {\n // bf16 → f32: the bf16 word is the top 16 bits of the f32 pattern.\n view.setUint32((dstBase + k) * 4, table[rowBase + k] << 16, true);\n }\n }\n return out;\n }\n\n /**\n * Embed one audio frame (32 FSQ codes) through the overlay stack:\n * per-channel lookup → concat → Linear→GELU→Linear → affine-free LayerNorm →\n * × audio_embed_scale. Mirrors GepardModel._embed_audio.\n */\n private embedAudioFrame(codes: Uint32Array): Float32Array {\n const h = this.hidden;\n const dim = this.cfg.audioEmbedDim;\n const x = new Float32Array(GEPARD_NUM_CHANNELS * dim);\n for (let c = 0; c < GEPARD_NUM_CHANNELS; c++) {\n const table = this.audioEmbTables[c];\n const base = codes[c] * dim;\n x.set(table.subarray(base, base + dim), c * dim);\n }\n const h1 = new Float32Array(h);\n linear(this.projW0, this.projB0, x, h, x.length, h1);\n for (let i = 0; i < h; i++) {\n h1[i] = gelu(h1[i]);\n }\n const h2 = new Float32Array(h);\n linear(this.projW2, this.projB2, h1, h, h, h2);\n // Affine-free LayerNorm pins the frame-embedding scale.\n let mean = 0;\n for (let i = 0; i < h; i++) {\n mean += h2[i];\n }\n mean /= h;\n let variance = 0;\n for (let i = 0; i < h; i++) {\n const d = h2[i] - mean;\n variance += d * d;\n }\n variance /= h;\n const inv = this.audioEmbedScale / Math.sqrt(variance + LAYERNORM_EPS);\n for (let i = 0; i < h; i++) {\n h2[i] = (h2[i] - mean) * inv;\n }\n return h2;\n }\n\n /** Stop-head probability for a hidden state. */\n private stopProbability(hidden: Float32Array): number {\n let acc = this.stopB;\n for (let k = 0; k < this.hidden; k++) {\n acc += this.stopW[k] * hidden[k];\n }\n return 1 / (1 + Math.exp(-acc));\n }\n\n /**\n * Sample one audio frame: all 32 heads independently in fp32 —\n * windowed repetition penalty → temperature → top-k → softmax → multinomial.\n * Mirrors GepardRunner._sample_frame / _sample_head_logits.\n */\n private sampleFrame(\n hidden: Float32Array,\n p: { temperature: number; topK: number; repetitionPenalty: number },\n recentFrames: Uint32Array[] | null,\n ): Uint32Array {\n const frame = new Uint32Array(GEPARD_NUM_CHANNELS);\n for (let c = 0; c < GEPARD_NUM_CHANNELS; c++) {\n const L = this.cfg.vocabSizes[c];\n const w = this.headW[c];\n const b = this.headB[c];\n const logits = new Float32Array(L);\n for (let j = 0; j < L; j++) {\n let acc = b[j];\n const base = j * this.hidden;\n for (let k = 0; k < this.hidden; k++) {\n acc += w[base + k] * hidden[k];\n }\n logits[j] = acc;\n }\n if (p.repetitionPenalty !== 1.0 && recentFrames) {\n for (const prev of recentFrames) {\n const tok = prev[c];\n logits[tok] =\n logits[tok] > 0 ? logits[tok] / p.repetitionPenalty : logits[tok] * p.repetitionPenalty;\n }\n }\n if (p.temperature !== 1.0) {\n for (let j = 0; j < L; j++) {\n logits[j] /= p.temperature;\n }\n }\n if (p.topK > 0 && p.topK < L) {\n const sorted = [...logits].sort((a, b2) => b2 - a);\n const threshold = sorted[p.topK - 1];\n for (let j = 0; j < L; j++) {\n if (logits[j] < threshold) {\n logits[j] = Number.NEGATIVE_INFINITY;\n }\n }\n }\n // Softmax + multinomial.\n let maxV = Number.NEGATIVE_INFINITY;\n for (let j = 0; j < L; j++) {\n if (logits[j] > maxV) {\n maxV = logits[j];\n }\n }\n let sum = 0;\n for (let j = 0; j < L; j++) {\n const e = Math.exp(logits[j] - maxV);\n logits[j] = e;\n sum += e;\n }\n let pick = Math.random() * sum;\n let chosen = L - 1;\n for (let j = 0; j < L; j++) {\n pick -= logits[j];\n if (pick <= 0) {\n chosen = j;\n break;\n }\n }\n frame[c] = chosen;\n }\n return frame;\n }\n\n /**\n * Synthesize speech for `text`. Returns 22.05 kHz mono PCM; when\n * `opts.onChunk` is set, audio streams out chunk-by-chunk during generation.\n *\n * Pipeline: adaptive-repetition text layout → prefill (host-gathered text\n * embeddings) → frame-synchronous AR loop (one frame = 32 codes per forward,\n * stop head decides termination) → incremental NanoCodec decode → PCM.\n */\n async speak(text: string, opts: GepardSpeakOptions = {}): Promise<GepardSpeakResult> {\n if (this._destroyed) {\n throw new Error(\"GepardTTS has been destroyed.\");\n }\n const temperature = opts.temperature ?? 0.4;\n const topK = opts.topK ?? 0;\n const stopThreshold = opts.stopThreshold ?? 0.5;\n const repetitionPenalty = opts.repetitionPenalty ?? 1.0;\n const repetitionWindow = opts.repetitionWindow ?? 32;\n\n // ── Text layout: [ (SOT text EOT) × (R−1) | SOT text EOT SOS ]. ──\n const textIds = this.tokenizer.encode(text);\n const layout = buildGepardTextLayout(textIds, this.cfg);\n if (layout.length + 2 >= this.maxSeqLen) {\n throw new Error(`Gepard prompt is ${layout.length} tokens >= maxSeqLen ${this.maxSeqLen}.`);\n }\n const maxFrames = Math.min(\n opts.maxFrames ?? DEFAULT_MAX_FRAMES,\n this.maxSeqLen - layout.length - 1,\n );\n\n // ── Prefill: host-gathered text embeddings → hidden state at SOS. ──\n const startTime = performance.now();\n this.backboneExec.reset();\n this.backboneExec.writeInput(\"inputs_embeds\", this.embedTextTokens(layout));\n // input_ids content is unused (the graph reads inputs_embeds); only the\n // length matters — it sets T for shape resolution and seqPos advancement.\n let { logits: hidden } = await this.backboneExec.forward(new Uint32Array(layout.length));\n\n // ── Frame-synchronous AR loop. ──\n const frames: Uint32Array[] = [\n this.sampleFrame(hidden, { temperature, topK, repetitionPenalty }, null),\n ];\n const streamer = new GepardChunkStreamer(this, opts.onChunk);\n const sampleOpts = { temperature, topK, repetitionPenalty };\n for (let step = 1; step < maxFrames; step++) {\n const frameEmbed = this.embedAudioFrame(frames[frames.length - 1]);\n this.backboneExec.writeInput(\"inputs_embeds\", frameEmbed);\n const res = await this.backboneExec.forward(new Uint32Array(1));\n hidden = res.logits;\n\n // Stop decision precedes sampling (the reference runner's ordering).\n if (this.stopProbability(hidden) > stopThreshold) {\n break;\n }\n const window =\n repetitionPenalty !== 1.0\n ? frames.slice(repetitionWindow > 0 ? -repetitionWindow : 0)\n : null;\n frames.push(this.sampleFrame(hidden, sampleOpts, window));\n await streamer.maybeEmit(frames, false);\n }\n\n // ── Final decode of any remaining frames + assembly. ──\n await streamer.maybeEmit(frames, true);\n const pcm = streamer.assembled(frames.length);\n\n const totalTime = (performance.now() - startTime) / 1000;\n const audioSeconds = (frames.length * GEPARD_HOP) / this.cfg.sampleRate;\n console.log(\n `[gepard] frames=${frames.length} audio=${audioSeconds.toFixed(2)}s ` +\n `wall=${totalTime.toFixed(2)}s RTF=${(audioSeconds / totalTime).toFixed(2)}x`,\n );\n return { pcm, sampleRate: this.cfg.sampleRate, frames: frames.length, audioSeconds };\n }\n\n /**\n * Decode frames [from, to) of the utterance to PCM, re-decoding up to\n * `GEPARD_CODEC_LOOKBACK_FRAMES` of left context as warm-up (discarded).\n * The decoder is causal with a bounded receptive field, so chunked output\n * matches a monolithic decode.\n */\n async decodeFrameRange(frames: Uint32Array[], from: number, to: number): Promise<Float32Array> {\n const ctxStart = Math.max(0, from - GEPARD_CODEC_LOOKBACK_FRAMES);\n const winFrames = to - ctxStart;\n // Channel-major codes [32, winFrames] → dequantized latent.\n const codes = new Uint32Array(GEPARD_NUM_CHANNELS * winFrames);\n for (let t = 0; t < winFrames; t++) {\n const frame = frames[ctxStart + t];\n for (let c = 0; c < GEPARD_NUM_CHANNELS; c++) {\n codes[c * winFrames + t] = frame[c];\n }\n }\n const latent = gepardCodesToLatent(codes, winFrames);\n const win = await this.decodeLatentWindow(latent, winFrames);\n const drop = (from - ctxStart) * GEPARD_HOP;\n const keep = (to - from) * GEPARD_HOP;\n const out = win.slice(drop, drop + keep);\n for (let i = 0; i < out.length; i++) {\n out[i] = Math.min(1, Math.max(-1, out[i]));\n }\n return out;\n }\n\n /** Run the codec graph for one latent window → raw PCM (pre-clamp). */\n private async decodeLatentWindow(latent: Float32Array, winFrames: number): Promise<Float32Array> {\n // The steady-state window size (chunk + lookback) recurs every chunk, so its\n // executor (graph + uploaded weights) is cached; odd sizes are ephemeral.\n const steady = winFrames === GEPARD_CODEC_CHUNK_FRAMES + GEPARD_CODEC_LOOKBACK_FRAMES;\n let exec = steady ? this.codecExecCache.get(winFrames) : undefined;\n let graphOutputs: string[];\n if (exec) {\n graphOutputs = exec.graphOutputs;\n } else {\n const graph = generateNanoCodecDecoderGraph({\n numFrames: winFrames,\n geometry: {\n upSampleRates: GEPARD_CODEC_UP_SAMPLE_RATES,\n inputDim: GEPARD_CODEC_INPUT_DIM,\n },\n latentInput: true,\n });\n exec = new Executor(this.ctx, graph, { maxSeqLen: winFrames, kvMode: \"f32\" });\n exec.uploadWeightsMap(selectGraphWeights(graph, this.loaded.codecWeights));\n exec.initBindGroups();\n graphOutputs = graph.outputs;\n if (steady) {\n this.codecExecCache.set(winFrames, exec);\n }\n }\n try {\n exec.reset();\n exec.writeInput(\"nc_latent\", latent);\n return await exec.runGraphOutput(graphOutputs[0], winFrames * GEPARD_HOP);\n } finally {\n if (!steady) {\n exec.destroy();\n }\n }\n }\n\n destroy(): void {\n if (this._destroyed) {\n return;\n }\n this._destroyed = true;\n this.backboneExec.destroy();\n for (const exec of this.codecExecCache.values()) {\n exec.destroy();\n }\n this.codecExecCache.clear();\n this.loaded.backboneWeights.clear();\n this.loaded.overlayWeights.clear();\n this.loaded.codecWeights.clear();\n }\n}\n\n/**\n * Incremental chunk decoder: every GEPARD_CODEC_CHUNK_FRAMES completed frames\n * it decodes the new span (with lookback) and emits it via `onChunk`, keeping\n * all emitted PCM so the final result is assembled without a second decode.\n */\nclass GepardChunkStreamer {\n private tts: GepardTTS;\n private onChunk?: (chunk: GepardAudioChunk) => void;\n private decodedUpTo = 0;\n private chunks: Float32Array[] = [];\n\n constructor(tts: GepardTTS, onChunk?: (chunk: GepardAudioChunk) => void) {\n this.tts = tts;\n this.onChunk = onChunk;\n }\n\n /** Decode + emit any complete pending chunk (or everything when `final`). */\n async maybeEmit(frames: Uint32Array[], final: boolean): Promise<void> {\n // Without a chunk consumer we still decode once at the end (final=true) —\n // decoding lazily in one pass per chunk boundary would waste GPU work.\n if (!(final || this.onChunk)) {\n return;\n }\n while (frames.length - this.decodedUpTo >= GEPARD_CODEC_CHUNK_FRAMES || final) {\n const from = this.decodedUpTo;\n const to = final ? frames.length : Math.min(frames.length, from + GEPARD_CODEC_CHUNK_FRAMES);\n if (to <= from) {\n break;\n }\n const pcm = await this.tts.decodeFrameRange(frames, from, to);\n this.chunks.push(pcm);\n this.decodedUpTo = to;\n this.onChunk?.({\n pcm,\n sampleRate: this.tts.sampleRate,\n frameIndex: from,\n isFinal: final && this.decodedUpTo >= frames.length,\n });\n if (final && this.decodedUpTo >= frames.length) {\n break;\n }\n }\n }\n\n /** Concatenate all emitted chunks into the full utterance PCM. */\n assembled(totalFrames: number): Float32Array {\n const pcm = new Float32Array(totalFrames * GEPARD_HOP);\n let offset = 0;\n for (const chunk of this.chunks) {\n pcm.set(chunk, offset);\n offset += chunk.length;\n }\n return pcm;\n }\n}\n","/**\n * OuteTTS-1.0-0.6B — native text-to-speech architecture (OuteAI/OuteTTS-1.0-0.6B).\n *\n * Two-stage codec-LM TTS, the same shape as Kani-TTS but with a plain Qwen3 backbone\n * and a descript-audio-codec (DAC) decoder instead of LFM2 + NanoCodec:\n *\n * 1. CODEC-LM BACKBONE = a plain Qwen3-0.6B `Qwen3ForCausalLM` (hidden 1024, 28\n * layers, GQA 16/8 heads, head_dim 128, SwiGLU, QK-RMSNorm, full RoPE θ=1e6,\n * tied embeddings, vocab 157760). The audio codes live in the SAME vocab as\n * text: two interleaved codebooks `<|c1_i|>` (ids 151669..152693) and\n * `<|c2_i|>` (ids 152694..153718). The backbone autoregressively emits one\n * (c1,c2) pair per 512-sample frame between `<|audio_start|>` and `<|audio_end|>`.\n * Reuses the existing Qwen2/3 graph generator with a KV-cache attention path\n * (generateOuteTtsBackboneGraph) — SIMPLER than Kani's LFM2 hybrid (no short\n * conv, no learnable RoPE, no frame-level positions: standard sequential RoPE).\n *\n * 2. DAC.speech.v1.0 DECODER (ibm-research/DAC.speech.v1.0, 24 kHz, 2-codebook\n * 1.5 kbps): RVQ dequant (2× codebook lookup [1024,8] + out_proj Conv1d(8→1024,\n * k1) + sum) → latent z[1024,T] → DacDecoder (Conv1d 1024→1536 k7 → 4 upsample\n * blocks rates [8,5,4,2] → Snake → Conv1d 96→1 k7 → tanh) → 24 kHz PCM.\n * hop_length 512 (token rate ≈ 46.875 Hz). FFT-free; every op maps to an\n * EXISTING validated kernel (Conv1dFull / ConvTranspose1d / Snake1d / Tanh /\n * Add) plus one new RVQDequant kernel (codebook lookup + out_proj sum).\n *\n * ── STEP-0 verification (live HF + .pth metadata, June 2026) ─────────────────\n * Backbone config.json (OuteAI/OuteTTS-1.0-0.6B):\n * architectures [\"Qwen3ForCausalLM\"], model_type \"qwen3\",\n * hidden_size 1024, num_hidden_layers 28, num_attention_heads 16,\n * num_key_value_heads 8, head_dim 128, intermediate_size 3072, vocab_size 157760,\n * rope_theta 1e6, rms_norm_eps 1e-6, tie_word_embeddings true, max_position 40960.\n * added_tokens.json: <|c1_0..1024|> = ids 151669..152693 (1025 each), <|c2_0..1024|>\n * = ids 152694..153718; <|text_start|>156722 <|text_end|>156723 <|audio_start|>156728\n * <|audio_end|>156729 <|code|>156730 <|word_start|>156731 <|word_end|>156732\n * <|features|>156733. (Index 1024 is a reserved vocab slot; real DAC codes are 0..1023.)\n *\n * DAC.speech.v1.0 weights_24khz_1.5kbps_v1.0.pth metadata.kwargs (descript-audio-codec):\n * latent_dim 1024, decoder_dim 1536, decoder_rates [8,5,4,2], n_codebooks 2,\n * codebook_size 1024, codebook_dim 8, sample_rate 24000 (hop_length 512).\n * State-dict (decoder.model.*): plain descript layout, NOT the HF DacModel rename —\n * decoder.model.0 Conv1d(1024→1536, k7, pad3) [weight_g/v + bias]\n * decoder.model.{1..4} DecoderBlock(rate r ∈ [8,5,4,2]):\n * .block.0.alpha Snake1d on Cin [1,Cin,1]\n * .block.1 ConvTranspose1d(Cin→Cin/2, k=2r, stride r,\n * pad=ceil(r/2), output_padding 0)\n * .block.{2,3,4} 3× ResidualUnit(dilation d ∈ [1,3,9]):\n * .block.0.alpha Snake1d [1,C,1]\n * .block.1 Conv1d(C→C, k7, dilation d, pad=((7-1)*d)//2)\n * .block.2.alpha Snake1d\n * .block.3 Conv1d(C→C, k1) (residual add)\n * decoder.model.5.alpha final Snake1d on 96 [1,96,1]\n * decoder.model.6 Conv1d(96→1, k7, pad3)\n * + tanh (host-side after readback)\n * Quantizer (quantizer.quantizers.{0,1}.*): codebook.weight [1024,8],\n * out_proj.weight_g/v → [1024,8,1] (Cout 1024, Cin 8, K1), out_proj.bias [1024].\n * Conv weights are weight-norm parametrizations (weight_g/weight_v); folded offline\n * (W = g·v/‖v‖, L2 over dims except dim0) by the prep script into plain conv weights.\n *\n * ── DAC stage length arithmetic (verified against torch reference) ───────────\n * ConvTranspose1d Lout = (L-1)*stride - 2*pad + (K-1) + output_padding + 1.\n * With K=2r, pad=ceil(r/2), output_padding=0: even r → L*r exactly; odd r (rate 5)\n * loses a sample (e.g. T=48 → 384 → 1919 → 7676 → 15352). The full decoded length is\n * 320·T − 8 (interior hop = ∏rates = 8·5·4·2 = 320, a constant 8-sample edge deficit),\n * so DAC runs at 24000/320 = 75 fps — NOT the config's hop_length 512 (that is a\n * different DAC variant's STFT hop). The residual convs are length-preserving\n * (symmetric padding), so no center-crop is needed. The decoder is NON-causal and the\n * odd-rate transpose makes interior windows position-dependent, so the whole clip is\n * decoded in ONE pass — the codec conv/Snake/Add kernels use 2D dispatch to stay under\n * WebGPU's 65535 per-dim workgroup cap (no chunking).\n *\n * ── STATUS ───────────────────────────────────────────────────────────────────\n * FOUNDATION (this file): RVQDequant + DAC decoder graph (generateDacSpeechDecoderGraph),\n * config + token-layout parsing, and audioTokensToDacCodes. Backbone reuses the\n * Qwen3 graph via the KV-cached generator. Validated bit-exact vs the torch DAC\n * reference (scripts/engine/dac-speech-ref.py) by scripts/engine/test-outetts.mjs.\n * NOT in this phase: speaker/voice-clone prompt-prefix API, int4 backbone, the\n * speak()/useTTS surface, R2 mirror, playground/docs.\n */\n\nimport type { DType, ModelArchConfig, ModelGraph, OpNode, TensorDesc } from \"../ir.js\";\nimport { CANONICAL_KEYS } from \"../ir.js\";\nimport { DEFAULT_GROUP_SIZE } from \"../quantize.js\";\nimport type { GraphDType, KVDType } from \"./index.js\";\n\n// ── OuteTTS-1.0 token layout (added_tokens.json, Interface Version 3) ──\nexport const OUTETTS_C1_BASE = 151_669; // <|c1_0|>\nexport const OUTETTS_C2_BASE = 152_694; // <|c2_0|>\nexport const OUTETTS_CODES_PER_CODEBOOK = 1025; // <|cN_0|>..<|cN_1024|> (1024 = reserved slot)\nexport const OUTETTS_TEXT_START = 156_722;\nexport const OUTETTS_TEXT_END = 156_723;\nexport const OUTETTS_AUDIO_START = 156_728;\nexport const OUTETTS_AUDIO_END = 156_729; // generation stop token\nexport const OUTETTS_CODE = 156_730;\nexport const OUTETTS_WORD_START = 156_731;\nexport const OUTETTS_WORD_END = 156_732;\nexport const OUTETTS_FEATURES = 156_733;\nexport const OUTETTS_IM_START = 151_644; // <|im_start|> (bos)\nexport const OUTETTS_IM_END = 151_645; // <|im_end|> (eos)\n\n// ── DAC.speech.v1.0 (24 kHz, 2-codebook 1.5 kbps) constants ──\nexport const DAC_SAMPLE_RATE = 24_000;\n// Decoder upsampling is the PRODUCT of decoder_rates (8·5·4·2 = 320), so the token\n// grid is 24000/320 = 75 fps. (config.json's hop_length 512 is the encoder/STFT hop\n// of a different DAC variant; the shipped .pth decoder_rates give the true 320× hop —\n// matching outetts' speaker-encoder tps=75.) The full decoded length is 320·T − 8\n// (a constant 8-sample edge deficit from the odd rate-5 padding); interior frames are\n// a clean 320 samples apart, which keeps chunked decode exactly placeable.\nexport const DAC_HOP = 320;\nexport const DAC_NUM_CODEBOOKS = 2;\nexport const DAC_CODEBOOK_SIZE = 1024;\nexport const DAC_CODEBOOK_DIM = 8;\nexport const DAC_LATENT_DIM = 1024; // quantizer out_proj output / decoder.conv1 input\nexport const DAC_DECODER_DIM = 1536; // decoder.conv1 output channels\nexport const DAC_DECODER_RATES = [8, 5, 4, 2] as const;\nexport const DAC_RESBLOCK_DILATIONS = [1, 3, 9] as const;\n// Encoder is the mirror of the decoder: downsampling strides [2,4,5,8] (the decoder\n// rates reversed). encoder_dim 64 → doubles per block (64→128→256→512→1024). The\n// final Conv1d(1024→1024, k3) emits the continuous latent the quantizer encodes.\nexport const DAC_ENCODER_DIM = 64;\nexport const DAC_ENCODER_RATES = [2, 4, 5, 8] as const;\n\n/** Parsed OuteTTS backbone config (the Qwen3 dims). Reuses the generic Qwen path. */\nexport interface OuteTtsConfig {\n hidden_size: number;\n num_layers: number;\n num_heads: number;\n num_kv_heads: number;\n head_dim: number;\n intermediate_size: number;\n vocab_size: number;\n rope_base: number;\n rms_norm_eps: number;\n max_position_embeddings: number;\n}\n\nexport function parseOuteTtsConfig(rawConfig: Record<string, unknown>): OuteTtsConfig {\n const hidden_size = rawConfig.hidden_size as number;\n const num_heads = rawConfig.num_attention_heads as number;\n return {\n hidden_size,\n num_layers: rawConfig.num_hidden_layers as number,\n num_heads,\n num_kv_heads: (rawConfig.num_key_value_heads as number) ?? num_heads,\n head_dim: (rawConfig.head_dim as number) ?? Math.floor(hidden_size / num_heads),\n intermediate_size: rawConfig.intermediate_size as number,\n vocab_size: rawConfig.vocab_size as number,\n rope_base: (rawConfig.rope_theta as number) ?? 1_000_000,\n rms_norm_eps: (rawConfig.rms_norm_eps as number) ?? 1e-6,\n max_position_embeddings: (rawConfig.max_position_embeddings as number) ?? 40_960,\n };\n}\n\n/**\n * Convert the flat generated token stream (the run BETWEEN <|audio_start|> and\n * <|audio_end|>) into a DAC code grid [NUM_CODEBOOKS, T] (codebook-major [c*T + t]).\n *\n * Mirrors outetts v3 `extract_audio_from_tokens`: filter the stream into two ordered\n * lists by membership of the c1 / c2 ranges, recover the raw code\n * (id − base), drop the reserved index 1024, and truncate to the shorter list. The\n * model emits c1,c2 interleaved per frame, but the parse is membership-based (it does\n * not assume strict pairing) so a stray token cannot desync the grid.\n */\nexport function audioTokensToDacCodes(tokenIds: number[]): {\n codes: Uint32Array;\n numFrames: number;\n} {\n const c1: number[] = [];\n const c2: number[] = [];\n for (const id of tokenIds) {\n if (id >= OUTETTS_C1_BASE && id < OUTETTS_C1_BASE + OUTETTS_CODES_PER_CODEBOOK) {\n const code = id - OUTETTS_C1_BASE;\n if (code < DAC_CODEBOOK_SIZE) {\n c1.push(code);\n }\n } else if (id >= OUTETTS_C2_BASE && id < OUTETTS_C2_BASE + OUTETTS_CODES_PER_CODEBOOK) {\n const code = id - OUTETTS_C2_BASE;\n if (code < DAC_CODEBOOK_SIZE) {\n c2.push(code);\n }\n }\n }\n const numFrames = Math.min(c1.length, c2.length);\n const codes = new Uint32Array(DAC_NUM_CODEBOOKS * numFrames); // codebook-major [c*T + t]\n for (let t = 0; t < numFrames; t++) {\n codes[t] = c1[t];\n codes[numFrames + t] = c2[t];\n }\n return { codes, numFrames };\n}\n\n/** ConvTranspose1d output length: (L-1)*stride - 2*pad + (K-1) + output_padding + 1. */\nfunction convTransposeLen(\n L: number,\n stride: number,\n K: number,\n pad: number,\n outPad: number,\n): number {\n return (L - 1) * stride - 2 * pad + (K - 1) + outPad + 1;\n}\n\n// ════════════════════════════════════════════════════════════════════════════\n// DAC.speech.v1.0 decoder graph (RVQ dequant + DacDecoder), codes → PCM.\n//\n// Input: audio codes [NUM_CODEBOOKS, T] (u32, codebook-major). Output: pcm [1, Lout]\n// (the raw conv output; the final tanh is applied host-side after readback). Weight\n// tensors carry the canonical `dac.*` names the prep script writes (weight-norm\n// already folded). Channels halve per stage (1536 → 768 → 384 → 192 → 96).\n// ════════════════════════════════════════════════════════════════════════════\n\n/** Canonical DAC decoder weight name. */\nfunction dacKey(name: string): string {\n return `dac.${name}`;\n}\n\nexport interface DacSpeechGraphOptions {\n /** Number of audio frames T (the code-grid width). */\n numFrames: number;\n /**\n * Number of RVQ codebooks. Default 2 (DAC.speech.v1.0). Parler-TTS's\n * dac_44khz_8kbps uses 9 — the RVQDequant kernel loops over NCB so the only\n * change is the codebook/out_proj tensor first-dim and the codes grid height.\n */\n numCodebooks?: number;\n /**\n * Decoder upsampling rates (the DecoderBlock strides). Default [8,5,4,2]\n * (DAC.speech.v1.0). Parler's dac_44khz uses [8,8,4,2] (hop 512). Channels\n * still halve per stage from `decoderDim`.\n */\n decoderRates?: readonly number[];\n /** First-conv output channels (decoder_dim). Default 1536. */\n decoderDim?: number;\n /** Quantizer out_proj output / first-conv input dim (latent_dim). Default 1024. */\n latentDim?: number;\n}\n\nexport function generateDacSpeechDecoderGraph(opts: DacSpeechGraphOptions): ModelGraph {\n const T = opts.numFrames;\n const NCB = opts.numCodebooks ?? DAC_NUM_CODEBOOKS;\n const rates = opts.decoderRates ?? DAC_DECODER_RATES;\n const decoderDim = opts.decoderDim ?? DAC_DECODER_DIM;\n const latentDim = opts.latentDim ?? DAC_LATENT_DIM;\n const tensors: Record<string, TensorDesc> = {};\n const nodes: OpNode[] = [];\n const executionOrder: string[] = [];\n\n const addTensor = (desc: TensorDesc): void => {\n tensors[desc.name] = desc;\n };\n const addNode = (node: OpNode): void => {\n nodes.push(node);\n executionOrder.push(node.id);\n };\n\n // ── Input: audio codes [NCB, T] (u32, codebook-major) ──\n addTensor({\n name: \"audio_codes\",\n shape: [NCB, T],\n dtype: \"u32\",\n storage: \"activation\",\n });\n\n // ── RVQ dequant → latent z[latentDim, T] ──\n // codebook[NCB, codebook_size, dim], out_proj_w[NCB, Cout, dim], out_proj_b[NCB, Cout].\n addTensor({\n name: dacKey(\"quantizer.codebook\"),\n shape: [NCB, DAC_CODEBOOK_SIZE, DAC_CODEBOOK_DIM],\n dtype: \"f32\",\n storage: \"constant\",\n safetensorsKey: dacKey(\"quantizer.codebook\"),\n });\n addTensor({\n name: dacKey(\"quantizer.out_proj.weight\"),\n shape: [NCB, latentDim, DAC_CODEBOOK_DIM],\n dtype: \"f32\",\n storage: \"constant\",\n safetensorsKey: dacKey(\"quantizer.out_proj.weight\"),\n });\n addTensor({\n name: dacKey(\"quantizer.out_proj.bias\"),\n shape: [NCB, latentDim],\n dtype: \"f32\",\n storage: \"constant\",\n safetensorsKey: dacKey(\"quantizer.out_proj.bias\"),\n });\n addTensor({\n name: \"dac_latent\",\n shape: [latentDim, T],\n dtype: \"f32\",\n storage: \"activation\",\n });\n addNode({\n id: \"dac_rvq\",\n opType: \"RVQDequant\",\n inputs: [\n \"audio_codes\",\n dacKey(\"quantizer.codebook\"),\n dacKey(\"quantizer.out_proj.weight\"),\n dacKey(\"quantizer.out_proj.bias\"),\n ],\n outputs: [\"dac_latent\"],\n attributes: {\n NCB,\n Cout: latentDim,\n T,\n D: DAC_CODEBOOK_DIM,\n codebook_size: DAC_CODEBOOK_SIZE,\n },\n });\n\n /** Emit a full (non-causal) Conv1dFull with symmetric padding. */\n function conv1dFull(\n id: string,\n input: string,\n weightKey: string,\n biasKey: string,\n Cin: number,\n Cout: number,\n K: number,\n L: number,\n dilation: number,\n padding: number,\n output: string,\n ): number {\n const Lout = Math.floor((L + 2 * padding - dilation * (K - 1) - 1) / 1) + 1;\n addTensor({\n name: weightKey,\n shape: [Cout, Cin, K],\n dtype: \"f32\",\n storage: \"constant\",\n safetensorsKey: weightKey,\n });\n addTensor({\n name: biasKey,\n shape: [Cout],\n dtype: \"f32\",\n storage: \"constant\",\n safetensorsKey: biasKey,\n });\n addTensor({ name: output, shape: [Cout, Lout], dtype: \"f32\", storage: \"activation\" });\n addNode({\n id,\n opType: \"Conv1dFull\",\n inputs: [input, weightKey, biasKey],\n outputs: [output],\n attributes: { Cin, Cout, L, Lout, K, stride: 1, padding, dilation },\n });\n return Lout;\n }\n\n /** Emit a full-channel Snake1d (alpha is [C], stored [1,C,1] → C). */\n function snake(\n id: string,\n input: string,\n C: number,\n L: number,\n alphaKey: string,\n output: string,\n ): void {\n addTensor({\n name: alphaKey,\n shape: [C],\n dtype: \"f32\",\n storage: \"constant\",\n safetensorsKey: alphaKey,\n });\n addTensor({ name: output, shape: [C, L], dtype: \"f32\", storage: \"activation\" });\n addNode({\n id,\n opType: \"Snake1d\",\n inputs: [input, alphaKey],\n outputs: [output],\n attributes: { C, L },\n });\n }\n\n /** Emit a strided ConvTranspose1d (weight [Cin, Cout, K]). */\n function convTranspose(\n id: string,\n input: string,\n weightKey: string,\n biasKey: string,\n Cin: number,\n Cout: number,\n K: number,\n L: number,\n stride: number,\n padding: number,\n outPad: number,\n output: string,\n ): number {\n const Lout = convTransposeLen(L, stride, K, padding, outPad);\n addTensor({\n name: weightKey,\n shape: [Cin, Cout, K],\n dtype: \"f32\",\n storage: \"constant\",\n safetensorsKey: weightKey,\n });\n addTensor({\n name: biasKey,\n shape: [Cout],\n dtype: \"f32\",\n storage: \"constant\",\n safetensorsKey: biasKey,\n });\n addTensor({ name: output, shape: [Cout, Lout], dtype: \"f32\", storage: \"activation\" });\n addNode({\n id,\n opType: \"ConvTranspose1d\",\n inputs: [input, weightKey, biasKey],\n outputs: [output],\n attributes: { Cin, Cout, L, Lout, K, stride, padding, output_padding: outPad },\n });\n return Lout;\n }\n\n /** Element-wise residual add of two equal-shape [C, L] activations. */\n function add(id: string, a: string, b: string, C: number, L: number, output: string): void {\n addTensor({ name: output, shape: [C, L], dtype: \"f32\", storage: \"activation\" });\n addNode({\n id,\n opType: \"Add\",\n inputs: [a, b],\n outputs: [output],\n attributes: { count_tensor: a, hidden_size: C * L },\n });\n }\n\n // ── decoder.model.0: Conv1d(latentDim → decoderDim, k7, pad3) ──\n let cur = \"dac_conv1_out\";\n let length = conv1dFull(\n \"dac_conv1\",\n \"dac_latent\",\n dacKey(\"decoder.model.0.weight\"),\n dacKey(\"decoder.model.0.bias\"),\n latentDim,\n decoderDim,\n 7,\n T,\n 1,\n 3,\n cur,\n );\n let channels = decoderDim;\n\n // ── decoder.model.{1..N}: DecoderBlocks (N = rates.length) ──\n for (let stage = 0; stage < rates.length; stage++) {\n const m = stage + 1; // decoder.model index\n const rate = rates[stage];\n const outCh = channels / 2;\n const upK = 2 * rate;\n const upPad = Math.ceil(rate / 2);\n\n // .block.0: Snake on `channels`\n const snakeOut = `dac_s${stage}_snake`;\n snake(\n `dac_s${stage}_snake_op`,\n cur,\n channels,\n length,\n dacKey(`decoder.model.${m}.block.0.alpha`),\n snakeOut,\n );\n\n // .block.1: ConvTranspose1d(channels → outCh, k=2*rate, stride=rate, pad=ceil/2, out_pad=0)\n const upOut = `dac_s${stage}_up`;\n length = convTranspose(\n `dac_s${stage}_convt`,\n snakeOut,\n dacKey(`decoder.model.${m}.block.1.weight`),\n dacKey(`decoder.model.${m}.block.1.bias`),\n channels,\n outCh,\n upK,\n length,\n rate,\n upPad,\n 0,\n upOut,\n );\n channels = outCh;\n\n // .block.{2,3,4}: 3× ResidualUnit (dilations [1,3,9]) — sequential.\n let h = upOut;\n for (let r = 0; r < DAC_RESBLOCK_DILATIONS.length; r++) {\n const ru = r + 2; // .block index of this residual unit\n const dil = DAC_RESBLOCK_DILATIONS[r];\n const p = `decoder.model.${m}.block.${ru}.block`;\n const pad = Math.floor(((7 - 1) * dil) / 2);\n // .block.0 Snake → .block.1 Conv1d(C→C, k7, dilation) → .block.2 Snake → .block.3 Conv1d(k1)\n const ia = `dac_s${stage}_r${r}_ia`;\n snake(`${ia}_op`, h, channels, length, dacKey(`${p}.0.alpha`), ia);\n const ic = `dac_s${stage}_r${r}_ic`;\n conv1dFull(\n `${ic}_op`,\n ia,\n dacKey(`${p}.1.weight`),\n dacKey(`${p}.1.bias`),\n channels,\n channels,\n 7,\n length,\n dil,\n pad,\n ic,\n );\n const sa = `dac_s${stage}_r${r}_sa`;\n snake(`${sa}_op`, ic, channels, length, dacKey(`${p}.2.alpha`), sa);\n const sc = `dac_s${stage}_r${r}_sc`;\n conv1dFull(\n `${sc}_op`,\n sa,\n dacKey(`${p}.3.weight`),\n dacKey(`${p}.3.bias`),\n channels,\n channels,\n 1,\n length,\n 1,\n 0,\n sc,\n );\n // residual: h = h + sc (length-preserving convs → no center-crop)\n const resAdd = `dac_s${stage}_r${r}_res`;\n add(`${resAdd}_op`, h, sc, channels, length, resAdd);\n h = resAdd;\n }\n cur = h;\n }\n\n // ── decoder.model.{N+1}: final Snake on the last channel count ──\n // After N DecoderBlocks (decoder.model.1..N), the final Snake is at index N+1 and\n // the output conv at N+2 (DAC.speech N=4 → model.5 / model.6; same for dac_44khz).\n const finalSnakeIdx = rates.length + 1;\n const finalConvIdx = rates.length + 2;\n const postSnake = \"dac_post_snake\";\n snake(\n \"dac_post_snake_op\",\n cur,\n channels,\n length,\n dacKey(`decoder.model.${finalSnakeIdx}.alpha`),\n postSnake,\n );\n\n // ── decoder.model.{N+2}: Conv1d(channels → 1, k7, pad3) ──\n const pcm = \"dac_pcm\";\n const pcmLen = conv1dFull(\n \"dac_conv2\",\n postSnake,\n dacKey(`decoder.model.${finalConvIdx}.weight`),\n dacKey(`decoder.model.${finalConvIdx}.bias`),\n channels,\n 1,\n 7,\n length,\n 1,\n 3,\n pcm,\n );\n // NOTE: the final tanh is applied host-side after readback (Math.tanh per sample),\n // matching DAC's decoder.model.{N+3} Tanh. PCM = tanh(dac_pcm).\n\n return {\n architecture: \"DacSpeechDecoder\",\n config: {\n hidden_size: decoderDim,\n num_layers: rates.length,\n num_heads: 0,\n num_kv_heads: 0,\n head_dim: 0,\n intermediate_size: 0,\n vocab_size: 0,\n context_length: pcmLen,\n rms_norm_eps: 0,\n norm_type: \"rmsnorm\",\n rope_base: 0,\n rope_dim: 0,\n kv_layout: \"LHSd\",\n is_moe: false,\n has_vision_tower: false,\n },\n capabilities: { text: true, vision: false, moe: false },\n tensors,\n nodes,\n executionOrder,\n inputs: [\"audio_codes\"],\n outputs: [pcm],\n };\n}\n\n/**\n * Final decoded PCM length (samples) for a T-frame code grid, via the DAC stage chain.\n * `rates` defaults to DAC.speech.v1.0 ([8,5,4,2]); pass [8,8,4,2] for Parler's dac_44khz.\n */\nexport function dacOutputLength(\n numFrames: number,\n rates: readonly number[] = DAC_DECODER_RATES,\n): number {\n let length = numFrames; // after conv1 (k7 pad3 → length-preserving)\n for (const rate of rates) {\n length = convTransposeLen(length, rate, 2 * rate, Math.ceil(rate / 2), 0);\n }\n return length; // conv2 (k7 pad3) is length-preserving\n}\n\n/** Strided/dilated Conv1d output length: floor((L + 2*pad - dilation*(K-1) - 1)/stride) + 1. */\nfunction conv1dLen(L: number, K: number, stride: number, pad: number, dilation: number): number {\n return Math.floor((L + 2 * pad - dilation * (K - 1) - 1) / stride) + 1;\n}\n\n/** Number of latent frames the encoder produces for `numSamples` of padded 24 kHz PCM. */\nexport function dacEncoderFrames(numSamples: number): number {\n let length = numSamples; // after block.0 (k7 pad3 → length-preserving)\n for (const rate of DAC_ENCODER_RATES) {\n // 3 residual units are length-preserving; the downsample conv is k=2r, stride r, pad=ceil(r/2).\n length = conv1dLen(length, 2 * rate, rate, Math.ceil(rate / 2), 1);\n }\n return length; // block.6 (k3 pad1) is length-preserving\n}\n\n// ════════════════════════════════════════════════════════════════════════════\n// DAC.speech.v1.0 ENCODER + RVQ-encode graph (raw audio → c1/c2 codes), the voice-\n// cloning mirror of the decoder graph above. Input: pcm [1, L] (f32, 24 kHz mono,\n// already loudness-normalized + hop-padded host-side). Output: codes [NCB, T] (u32,\n// codebook-major). The encoder is descript-audio-codec's Encoder: Conv1d(1→64,k7) →\n// 4 EncoderBlocks (downsample strides [2,4,5,8], channels 64→128→256→512→1024) →\n// Snake → Conv1d(1024→1024,k3) → latent z[1024,T]; then a single RVQEncode op runs\n// the residual argmin over the 2 codebooks. Reuses Conv1dFull / Snake1d / Add. Every\n// weight carries its canonical `dac.encoder.*` / `dac.quantizer.*` name (weight-norm\n// already folded by prep-dac-speech.py). Validated <1e-4 vs torch DAC.encode.\n// ════════════════════════════════════════════════════════════════════════════\n\nexport interface DacEncoderGraphOptions {\n /** Number of (hop-padded) input PCM samples L. */\n numSamples: number;\n}\n\nexport function generateDacSpeechEncoderGraph(opts: DacEncoderGraphOptions): ModelGraph {\n const L0 = opts.numSamples;\n const tensors: Record<string, TensorDesc> = {};\n const nodes: OpNode[] = [];\n const executionOrder: string[] = [];\n\n const addTensor = (desc: TensorDesc): void => {\n tensors[desc.name] = desc;\n };\n const addNode = (node: OpNode): void => {\n nodes.push(node);\n executionOrder.push(node.id);\n };\n\n // ── Input: pcm [1, L] (f32, 24 kHz mono, host-padded to a hop multiple) ──\n addTensor({ name: \"pcm_in\", shape: [1, L0], dtype: \"f32\", storage: \"activation\" });\n\n /** Emit a Conv1dFull (symmetric padding) and return its output length. */\n function conv1dFull(\n id: string,\n input: string,\n weightKey: string,\n biasKey: string,\n Cin: number,\n Cout: number,\n K: number,\n L: number,\n stride: number,\n dilation: number,\n padding: number,\n output: string,\n ): number {\n const Lout = conv1dLen(L, K, stride, padding, dilation);\n addTensor({\n name: weightKey,\n shape: [Cout, Cin, K],\n dtype: \"f32\",\n storage: \"constant\",\n safetensorsKey: weightKey,\n });\n addTensor({\n name: biasKey,\n shape: [Cout],\n dtype: \"f32\",\n storage: \"constant\",\n safetensorsKey: biasKey,\n });\n addTensor({ name: output, shape: [Cout, Lout], dtype: \"f32\", storage: \"activation\" });\n addNode({\n id,\n opType: \"Conv1dFull\",\n inputs: [input, weightKey, biasKey],\n outputs: [output],\n attributes: { Cin, Cout, L, Lout, K, stride, padding, dilation },\n });\n return Lout;\n }\n\n /** Emit a full-channel Snake1d (alpha is [C], stored [1,C,1] → C). */\n function snake(\n id: string,\n input: string,\n C: number,\n L: number,\n alphaKey: string,\n output: string,\n ): void {\n addTensor({\n name: alphaKey,\n shape: [C],\n dtype: \"f32\",\n storage: \"constant\",\n safetensorsKey: alphaKey,\n });\n addTensor({ name: output, shape: [C, L], dtype: \"f32\", storage: \"activation\" });\n addNode({\n id,\n opType: \"Snake1d\",\n inputs: [input, alphaKey],\n outputs: [output],\n attributes: { C, L },\n });\n }\n\n /** Element-wise residual add of two equal-shape [C, L] activations. */\n function add(id: string, a: string, b: string, C: number, L: number, output: string): void {\n addTensor({ name: output, shape: [C, L], dtype: \"f32\", storage: \"activation\" });\n addNode({\n id,\n opType: \"Add\",\n inputs: [a, b],\n outputs: [output],\n attributes: { count_tensor: a, hidden_size: C * L },\n });\n }\n\n const encKey = (name: string): string => dacKey(`encoder.${name}`);\n\n // ── block.0: Conv1d(1 → 64, k7, pad3) ──\n let cur = \"dac_enc_conv0\";\n let length = conv1dFull(\n \"dac_enc_conv0_op\",\n \"pcm_in\",\n encKey(\"block.0.weight\"),\n encKey(\"block.0.bias\"),\n 1,\n DAC_ENCODER_DIM,\n 7,\n L0,\n 1,\n 1,\n 3,\n cur,\n );\n let channels = DAC_ENCODER_DIM;\n\n // ── block.{1..4}: EncoderBlocks (3 residual units → Snake → strided downsample conv) ──\n for (let stage = 0; stage < DAC_ENCODER_RATES.length; stage++) {\n const m = stage + 1; // encoder.block index\n const rate = DAC_ENCODER_RATES[stage];\n\n // .block.{0,1,2}: 3× ResidualUnit (dilations [1,3,9]) — sequential, length-preserving.\n let h = cur;\n for (let r = 0; r < DAC_RESBLOCK_DILATIONS.length; r++) {\n const dil = DAC_RESBLOCK_DILATIONS[r];\n const p = `block.${m}.block.${r}.block`;\n const pad = Math.floor(((7 - 1) * dil) / 2);\n // .block.0 Snake → .block.1 Conv1d(C→C, k7, dilation) → .block.2 Snake → .block.3 Conv1d(k1)\n const ia = `dac_enc_s${stage}_r${r}_ia`;\n snake(`${ia}_op`, h, channels, length, encKey(`${p}.0.alpha`), ia);\n const ic = `dac_enc_s${stage}_r${r}_ic`;\n conv1dFull(\n `${ic}_op`,\n ia,\n encKey(`${p}.1.weight`),\n encKey(`${p}.1.bias`),\n channels,\n channels,\n 7,\n length,\n 1,\n dil,\n pad,\n ic,\n );\n const sa = `dac_enc_s${stage}_r${r}_sa`;\n snake(`${sa}_op`, ic, channels, length, encKey(`${p}.2.alpha`), sa);\n const sc = `dac_enc_s${stage}_r${r}_sc`;\n conv1dFull(\n `${sc}_op`,\n sa,\n encKey(`${p}.3.weight`),\n encKey(`${p}.3.bias`),\n channels,\n channels,\n 1,\n length,\n 1,\n 1,\n 0,\n sc,\n );\n const resAdd = `dac_enc_s${stage}_r${r}_res`;\n add(`${resAdd}_op`, h, sc, channels, length, resAdd);\n h = resAdd;\n }\n\n // .block.3: Snake on `channels`\n const snakeOut = `dac_enc_s${stage}_snake`;\n snake(`${snakeOut}_op`, h, channels, length, encKey(`block.${m}.block.3.alpha`), snakeOut);\n\n // .block.4: strided Conv1d(channels → 2*channels, k=2*rate, stride=rate, pad=ceil(rate/2))\n const outCh = channels * 2;\n const downOut = `dac_enc_s${stage}_down`;\n length = conv1dFull(\n `${downOut}_op`,\n snakeOut,\n encKey(`block.${m}.block.4.weight`),\n encKey(`block.${m}.block.4.bias`),\n channels,\n outCh,\n 2 * rate,\n length,\n rate,\n 1,\n Math.ceil(rate / 2),\n downOut,\n );\n channels = outCh;\n cur = downOut;\n }\n\n // ── block.5: final Snake on 1024 ──\n const postSnake = \"dac_enc_post_snake\";\n snake(\"dac_enc_post_snake_op\", cur, channels, length, encKey(\"block.5.alpha\"), postSnake);\n\n // ── block.6: Conv1d(1024 → 1024, k3, pad1) → latent z[1024, T] ──\n const latent = \"dac_enc_latent\";\n const T = conv1dFull(\n \"dac_enc_conv6_op\",\n postSnake,\n encKey(\"block.6.weight\"),\n encKey(\"block.6.bias\"),\n channels,\n DAC_LATENT_DIM,\n 3,\n length,\n 1,\n 1,\n 1,\n latent,\n );\n\n // ── RVQ encode: latent z[1024, T] → codes[NCB, T] (residual argmin over codebooks) ──\n addTensor({\n name: dacKey(\"quantizer.in_proj.weight\"),\n shape: [DAC_NUM_CODEBOOKS, DAC_CODEBOOK_DIM, DAC_LATENT_DIM],\n dtype: \"f32\",\n storage: \"constant\",\n safetensorsKey: dacKey(\"quantizer.in_proj.weight\"),\n });\n addTensor({\n name: dacKey(\"quantizer.in_proj.bias\"),\n shape: [DAC_NUM_CODEBOOKS, DAC_CODEBOOK_DIM],\n dtype: \"f32\",\n storage: \"constant\",\n safetensorsKey: dacKey(\"quantizer.in_proj.bias\"),\n });\n addTensor({\n name: dacKey(\"quantizer.codebook\"),\n shape: [DAC_NUM_CODEBOOKS, DAC_CODEBOOK_SIZE, DAC_CODEBOOK_DIM],\n dtype: \"f32\",\n storage: \"constant\",\n safetensorsKey: dacKey(\"quantizer.codebook\"),\n });\n addTensor({\n name: dacKey(\"quantizer.out_proj.weight\"),\n shape: [DAC_NUM_CODEBOOKS, DAC_LATENT_DIM, DAC_CODEBOOK_DIM],\n dtype: \"f32\",\n storage: \"constant\",\n safetensorsKey: dacKey(\"quantizer.out_proj.weight\"),\n });\n addTensor({\n name: dacKey(\"quantizer.out_proj.bias\"),\n shape: [DAC_NUM_CODEBOOKS, DAC_LATENT_DIM],\n dtype: \"f32\",\n storage: \"constant\",\n safetensorsKey: dacKey(\"quantizer.out_proj.bias\"),\n });\n addTensor({\n name: \"dac_codes\",\n shape: [DAC_NUM_CODEBOOKS, T],\n dtype: \"u32\",\n storage: \"activation\",\n });\n addNode({\n id: \"dac_rvq_encode\",\n opType: \"RVQEncode\",\n inputs: [\n latent,\n dacKey(\"quantizer.in_proj.weight\"),\n dacKey(\"quantizer.in_proj.bias\"),\n dacKey(\"quantizer.codebook\"),\n dacKey(\"quantizer.out_proj.weight\"),\n dacKey(\"quantizer.out_proj.bias\"),\n ],\n outputs: [\"dac_codes\"],\n attributes: {\n NCB: DAC_NUM_CODEBOOKS,\n Cout: DAC_LATENT_DIM,\n T,\n D: DAC_CODEBOOK_DIM,\n codebook_size: DAC_CODEBOOK_SIZE,\n },\n });\n\n return {\n architecture: \"DacSpeechEncoder\",\n config: {\n hidden_size: DAC_LATENT_DIM,\n num_layers: DAC_ENCODER_RATES.length,\n num_heads: 0,\n num_kv_heads: 0,\n head_dim: 0,\n intermediate_size: 0,\n vocab_size: 0,\n context_length: T,\n rms_norm_eps: 0,\n norm_type: \"rmsnorm\",\n rope_base: 0,\n rope_dim: 0,\n kv_layout: \"LHSd\",\n is_moe: false,\n has_vision_tower: false,\n },\n capabilities: { text: true, vision: false, moe: false },\n tensors,\n nodes,\n executionOrder,\n inputs: [\"pcm_in\"],\n outputs: [\"dac_codes\"],\n };\n}\n\n// ════════════════════════════════════════════════════════════════════════════\n// OuteTTS codec-LM backbone graph (plain Qwen3-0.6B + KV cache).\n//\n// A standard Qwen3ForCausalLM decoder with an INCREMENTAL KV-cache attention path\n// (KVCacheAppend + cached Attention), so the AR speak() loop decodes one token per\n// forward instead of re-prefilling. The generic Qwen2/3 generator (qwen2.ts) is\n// prefill-only; this is the same block math (RMSNorm → QKV → QK-RMSNorm → full RoPE\n// → GQA → SwiGLU) wired for cached decode, matching the Kani/Gemma backbone pattern.\n// Tied embeddings; full-vocab logits (the AR driver picks c1/c2 on the host). f32.\n// ════════════════════════════════════════════════════════════════════════════\n\nexport function generateOuteTtsBackboneGraph(\n rawConfig: Record<string, unknown>,\n dtype?: GraphDType,\n groupSize?: number,\n kvDtype?: KVDType,\n): ModelGraph {\n const cfg = parseOuteTtsConfig(rawConfig);\n const useQ4 = dtype === \"q4\";\n const groupSz = groupSize ?? DEFAULT_GROUP_SIZE;\n const hidden_size = cfg.hidden_size;\n const num_layers = cfg.num_layers;\n const num_heads = cfg.num_heads;\n const num_kv_heads = cfg.num_kv_heads;\n const head_dim = cfg.head_dim;\n const rope_dim = head_dim; // Qwen3 uses full-head RoPE\n const rope_base = cfg.rope_base;\n const rms_norm_eps = cfg.rms_norm_eps;\n const intermediate_size = cfg.intermediate_size;\n const vocab_size = cfg.vocab_size;\n const q_dim = num_heads * head_dim;\n const kv_dim = num_kv_heads * head_dim;\n const kvCacheDtype: DType = kvDtype ?? \"f32\";\n\n const config: ModelArchConfig = {\n hidden_size,\n num_layers,\n num_heads,\n num_kv_heads,\n head_dim,\n intermediate_size,\n vocab_size,\n context_length: cfg.max_position_embeddings,\n rms_norm_eps,\n norm_type: \"rmsnorm\",\n rope_base,\n rope_dim,\n kv_layout: \"LHSd\",\n is_moe: false,\n has_vision_tower: false,\n };\n\n const tensors: Record<string, TensorDesc> = {};\n const nodes: OpNode[] = [];\n const executionOrder: string[] = [];\n const addTensor = (desc: TensorDesc): void => {\n tensors[desc.name] = desc;\n };\n const addNode = (node: OpNode): void => {\n nodes.push(node);\n executionOrder.push(node.id);\n };\n // Linear projections: MatMulInt4 (weight-only W4A16) when q4, else plain MatMul. The\n // q4 weight tensors (.q/.scales/.zeros) are produced by the loader from the f32 source\n // under `weightName` (see model-loader.ts quantizeKaniBackbone, which is generic over\n // MatMulInt4 nodes). The tied embedding + LM head are kept f32.\n const addLinear = (\n id: string,\n activationInput: string,\n weightName: string,\n weightShape: number[],\n outputName: string,\n K: number,\n N: number,\n ): void => {\n if (useQ4) {\n const totalElements = K * N;\n addTensor({\n name: `${weightName}.q`,\n shape: [Math.ceil(totalElements / 8)],\n dtype: \"u32\",\n storage: \"constant\",\n });\n addTensor({\n name: `${weightName}.scales`,\n shape: [Math.ceil(totalElements / groupSz)],\n dtype: \"f32\",\n storage: \"constant\",\n });\n addTensor({\n name: `${weightName}.zeros`,\n shape: [Math.ceil(totalElements / groupSz)],\n dtype: \"f32\",\n storage: \"constant\",\n });\n addNode({\n id,\n opType: \"MatMulInt4\",\n inputs: [activationInput, `${weightName}.q`, `${weightName}.scales`, `${weightName}.zeros`],\n outputs: [outputName],\n attributes: { M_tensor: activationInput, K, N, group_size: groupSz },\n });\n return;\n }\n addTensor({\n name: weightName,\n shape: weightShape,\n dtype: \"f32\",\n storage: \"constant\",\n safetensorsKey: weightName,\n });\n addNode({\n id,\n opType: \"MatMul\",\n inputs: [activationInput, weightName],\n outputs: [outputName],\n attributes: { M_tensor: activationInput, K, N },\n });\n };\n\n // ── Input + embedding ──\n addTensor({ name: \"input_ids\", shape: [\"T\"], dtype: \"u32\", storage: \"activation\" });\n addTensor({ name: \"embed_out\", shape: [\"T\", hidden_size], dtype: \"f32\", storage: \"activation\" });\n addTensor({\n name: CANONICAL_KEYS.EMBED,\n shape: [vocab_size, hidden_size],\n dtype: \"f32\",\n storage: \"constant\",\n safetensorsKey: CANONICAL_KEYS.EMBED,\n });\n addNode({\n id: \"embed\",\n opType: \"Embedding\",\n inputs: [\"input_ids\", CANONICAL_KEYS.EMBED],\n outputs: [\"embed_out\"],\n attributes: { vocab_size, hidden_size },\n });\n\n let prevOutput = \"embed_out\";\n for (let i = 0; i < num_layers; i++) {\n const prefix = `layer${i}`;\n\n // ── input_layernorm ──\n const normW = CANONICAL_KEYS.layerInputNorm(i);\n addTensor({\n name: normW,\n shape: [hidden_size],\n dtype: \"f32\",\n storage: \"constant\",\n safetensorsKey: normW,\n });\n const norm1Out = `${prefix}_norm1_out`;\n addTensor({ name: norm1Out, shape: [\"T\", hidden_size], dtype: \"f32\", storage: \"activation\" });\n addNode({\n id: `${prefix}_norm1`,\n opType: \"RMSNorm\",\n inputs: [prevOutput, normW],\n outputs: [norm1Out],\n attributes: { hidden_size, eps: rms_norm_eps, seq_len_tensor: prevOutput },\n });\n\n // ── Q/K/V projections ──\n const qOut = `${prefix}_q`;\n const kOut = `${prefix}_k`;\n const vOut = `${prefix}_v`;\n addTensor({ name: qOut, shape: [\"T\", q_dim], dtype: \"f32\", storage: \"activation\" });\n addTensor({ name: kOut, shape: [\"T\", kv_dim], dtype: \"f32\", storage: \"activation\" });\n addTensor({ name: vOut, shape: [\"T\", kv_dim], dtype: \"f32\", storage: \"activation\" });\n addLinear(\n `${prefix}_q_proj`,\n norm1Out,\n CANONICAL_KEYS.qProj(i),\n [q_dim, hidden_size],\n qOut,\n hidden_size,\n q_dim,\n );\n addLinear(\n `${prefix}_k_proj`,\n norm1Out,\n CANONICAL_KEYS.kProj(i),\n [kv_dim, hidden_size],\n kOut,\n hidden_size,\n kv_dim,\n );\n addLinear(\n `${prefix}_v_proj`,\n norm1Out,\n CANONICAL_KEYS.vProj(i),\n [kv_dim, hidden_size],\n vOut,\n hidden_size,\n kv_dim,\n );\n\n // ── QK per-head RMSNorm (Qwen3) ──\n const qNormW = CANONICAL_KEYS.qNorm(i);\n const kNormW = CANONICAL_KEYS.kNorm(i);\n addTensor({\n name: qNormW,\n shape: [head_dim],\n dtype: \"f32\",\n storage: \"constant\",\n safetensorsKey: qNormW,\n });\n addTensor({\n name: kNormW,\n shape: [head_dim],\n dtype: \"f32\",\n storage: \"constant\",\n safetensorsKey: kNormW,\n });\n const qNormed = `${prefix}_q_normed`;\n const kNormed = `${prefix}_k_normed`;\n addTensor({ name: qNormed, shape: [\"T\", q_dim], dtype: \"f32\", storage: \"activation\" });\n addTensor({ name: kNormed, shape: [\"T\", kv_dim], dtype: \"f32\", storage: \"activation\" });\n addNode({\n id: `${prefix}_q_norm`,\n opType: \"RMSNorm\",\n inputs: [qOut, qNormW],\n outputs: [qNormed],\n attributes: { hidden_size: head_dim, eps: rms_norm_eps, seq_len_tensor: qOut },\n });\n addNode({\n id: `${prefix}_k_norm`,\n opType: \"RMSNorm\",\n inputs: [kOut, kNormW],\n outputs: [kNormed],\n attributes: { hidden_size: head_dim, eps: rms_norm_eps, seq_len_tensor: kOut },\n });\n\n // ── Full RoPE on Q and K (in place) ──\n addNode({\n id: `${prefix}_rope`,\n opType: \"RoPE\",\n inputs: [qNormed, kNormed],\n outputs: [qNormed, kNormed],\n attributes: {\n head_dim,\n num_q_heads: num_heads,\n num_kv_heads,\n rope_base,\n rope_dim,\n seq_len_tensor: qNormed,\n },\n });\n\n // ── KV cache append (RoPE'd K, raw V) ──\n const kCache = `${prefix}_k_cache`;\n const vCache = `${prefix}_v_cache`;\n addTensor({ name: kCache, shape: [\"L_max\", kv_dim], dtype: kvCacheDtype, storage: \"kv_cache\" });\n addTensor({ name: vCache, shape: [\"L_max\", kv_dim], dtype: kvCacheDtype, storage: \"kv_cache\" });\n addNode({\n id: `${prefix}_kv_cache_k`,\n opType: \"KVCacheAppend\",\n inputs: [kNormed],\n outputs: [kCache],\n attributes: { width: kv_dim, T_tensor: kNormed },\n });\n addNode({\n id: `${prefix}_kv_cache_v`,\n opType: \"KVCacheAppend\",\n inputs: [vOut],\n outputs: [vCache],\n attributes: { width: kv_dim, T_tensor: vOut },\n });\n\n // ── Causal GQA attention (reads KV cache) ──\n const attnOut = `${prefix}_attn_out`;\n addTensor({ name: attnOut, shape: [\"T\", q_dim], dtype: \"f32\", storage: \"activation\" });\n addNode({\n id: `${prefix}_attn`,\n opType: \"Attention\",\n inputs: [qNormed, kCache, vCache],\n outputs: [attnOut],\n attributes: {\n hidden_size: q_dim,\n num_q_heads: num_heads,\n num_kv_heads,\n head_dim,\n causal: true,\n layer_index: i,\n },\n });\n\n // ── O projection ──\n const oProjOut = `${prefix}_o_proj_out`;\n addTensor({ name: oProjOut, shape: [\"T\", hidden_size], dtype: \"f32\", storage: \"activation\" });\n addLinear(\n `${prefix}_o_proj`,\n attnOut,\n CANONICAL_KEYS.oProj(i),\n [hidden_size, q_dim],\n oProjOut,\n q_dim,\n hidden_size,\n );\n\n // ── Residual 1 + post_attention_layernorm (fused) ──\n const resid1Out = `${prefix}_resid1`;\n const postNormW = CANONICAL_KEYS.layerPostAttnNorm(i);\n const norm2Out = `${prefix}_norm2_out`;\n addTensor({ name: resid1Out, shape: [\"T\", hidden_size], dtype: \"f32\", storage: \"activation\" });\n addTensor({\n name: postNormW,\n shape: [hidden_size],\n dtype: \"f32\",\n storage: \"constant\",\n safetensorsKey: postNormW,\n });\n addTensor({ name: norm2Out, shape: [\"T\", hidden_size], dtype: \"f32\", storage: \"activation\" });\n addNode({\n id: `${prefix}_resid1_norm2`,\n opType: \"ResidualRMSNorm\",\n inputs: [prevOutput, oProjOut, postNormW],\n outputs: [resid1Out, norm2Out],\n attributes: { hidden_size, eps: rms_norm_eps, seq_len_tensor: prevOutput },\n });\n\n // ── SwiGLU MLP ──\n const gateOut = `${prefix}_gate_out`;\n const upOut = `${prefix}_up_out`;\n const swigluOut = `${prefix}_swiglu_out`;\n const mlpOut = `${prefix}_mlp_out`;\n addTensor({\n name: gateOut,\n shape: [\"T\", intermediate_size],\n dtype: \"f32\",\n storage: \"activation\",\n });\n addTensor({\n name: upOut,\n shape: [\"T\", intermediate_size],\n dtype: \"f32\",\n storage: \"activation\",\n });\n addTensor({\n name: swigluOut,\n shape: [\"T\", intermediate_size],\n dtype: \"f32\",\n storage: \"activation\",\n });\n addTensor({ name: mlpOut, shape: [\"T\", hidden_size], dtype: \"f32\", storage: \"activation\" });\n addLinear(\n `${prefix}_gate`,\n norm2Out,\n CANONICAL_KEYS.gateProj(i),\n [intermediate_size, hidden_size],\n gateOut,\n hidden_size,\n intermediate_size,\n );\n addLinear(\n `${prefix}_up`,\n norm2Out,\n CANONICAL_KEYS.upProj(i),\n [intermediate_size, hidden_size],\n upOut,\n hidden_size,\n intermediate_size,\n );\n addNode({\n id: `${prefix}_swiglu`,\n opType: \"SwiGLU\",\n inputs: [gateOut, upOut],\n outputs: [swigluOut],\n attributes: { count_tensor: gateOut },\n });\n addLinear(\n `${prefix}_down`,\n swigluOut,\n CANONICAL_KEYS.downProj(i),\n [hidden_size, intermediate_size],\n mlpOut,\n intermediate_size,\n hidden_size,\n );\n\n // ── Residual 2 ──\n const resid2Out = `${prefix}_resid2`;\n addTensor({ name: resid2Out, shape: [\"T\", hidden_size], dtype: \"f32\", storage: \"activation\" });\n addNode({\n id: `${prefix}_resid2`,\n opType: \"Add\",\n inputs: [resid1Out, mlpOut],\n outputs: [resid2Out],\n attributes: { count_tensor: resid1Out, hidden_size },\n });\n prevOutput = resid2Out;\n }\n\n // ── Final norm ──\n addTensor({\n name: CANONICAL_KEYS.FINAL_NORM,\n shape: [hidden_size],\n dtype: \"f32\",\n storage: \"constant\",\n safetensorsKey: CANONICAL_KEYS.FINAL_NORM,\n });\n addTensor({\n name: \"final_norm_out\",\n shape: [\"T\", hidden_size],\n dtype: \"f32\",\n storage: \"activation\",\n });\n addNode({\n id: \"final_norm\",\n opType: \"RMSNorm\",\n inputs: [prevOutput, CANONICAL_KEYS.FINAL_NORM],\n outputs: [\"final_norm_out\"],\n attributes: { hidden_size, eps: rms_norm_eps, seq_len_tensor: prevOutput },\n });\n\n // ── LM head (tied embeddings): last-row slice → full-vocab logits ──\n addTensor({\n name: \"final_norm_last\",\n shape: [1, hidden_size],\n dtype: \"f32\",\n storage: \"activation\",\n });\n addNode({\n id: \"slice_last_row\",\n opType: \"SliceLastRow\",\n inputs: [\"final_norm_out\"],\n outputs: [\"final_norm_last\"],\n attributes: { width: hidden_size },\n });\n addTensor({ name: \"logits\", shape: [1, vocab_size], dtype: \"f32\", storage: \"activation\" });\n addNode({\n id: \"lm_head\",\n opType: \"MatMul\",\n inputs: [\"final_norm_last\", CANONICAL_KEYS.EMBED],\n outputs: [\"logits\"],\n attributes: { M_tensor: \"final_norm_last\", K: hidden_size, N: vocab_size },\n });\n\n return {\n architecture: \"Qwen3ForCausalLM\",\n config,\n capabilities: { text: true, vision: false, moe: false },\n tensors,\n nodes,\n executionOrder,\n inputs: [\"input_ids\"],\n outputs: [\"logits\"],\n };\n}\n","/**\n * OuteTTS voice-clone helpers — prosody feature extraction + word alignment for\n * `OuteTTS.encodeSpeaker` (raw audio → OuteSpeaker). These are a faithful port of\n * outetts v3 `audio_processor.Features` (energy / spectral_centroid / pitch) and the\n * `create_speaker_from_dict` word loop, so the per-word feature tokens the prompt\n * builder emits match the reference speaker JSONs the presets ship.\n *\n * The DAC encode (audio → c1/c2 codes) is done bit-exact on the GPU\n * (generateDacSpeechEncoderGraph + RVQEncode, validated 450/450 vs torch). The codes\n * are EXACT; only the word→frame boundaries are estimated. outetts uses Whisper\n * word-level timestamps to slice the code stream per word. We provide two on-device\n * estimators (both leave the codes untouched — they only decide which frames map to\n * which word, and which audio span each word's prosody is computed over):\n *\n * 1. alignWordsByEnergy (default) — a forced-segmentation aligner driven by the\n * clip's OWN short-time energy envelope. It finds the silence gaps (low-energy\n * runs) between utterances and snaps word boundaries onto them, distributing the\n * transcript words across the detected speech runs (char-weighted within a run).\n * This is audio-driven: boundaries land on real pauses instead of being guessed.\n *\n * 2. alignWordsProportional (fallback) — the original audio-BLIND estimator that\n * spreads frames across words proportionally to char length. Used when the energy\n * envelope yields no usable structure (one continuous speech run, or fewer gaps\n * than word boundaries).\n *\n * On-device STT note: Gerbil's Moonshine STT (MoonshineSTT, src/gpu/moonshine-stt.ts)\n * is an encoder-decoder ASR that emits a transcript but does NOT expose Whisper-style\n * word timestamps — its decoder cross-attention scores are consumed inside the kernel\n * and never read back, so there is no per-token→frame map to slice on. Energy-based\n * forced segmentation is therefore the closest achievable on-device alignment; STT is\n * used (when wired by the caller) to obtain/confirm the WORD SEQUENCE, and the energy\n * aligner places the boundaries. See `OuteTTS.encodeSpeaker`.\n */\n\nconst DAC_TPS = 75; // DAC.speech latent frame rate (24000 / hop 320).\n\nconst WHITESPACE_RE = /\\s+/;\n\nconst PITCH_MIN_FREQ = 75.0;\nconst PITCH_MAX_FREQ = 600.0;\nconst PITCH_FRAME_LEN = 400;\nconst PITCH_HOP = 160;\nconst PITCH_THRESHOLD = 0.3;\nconst FEATURE_EPS = 1e-10;\n\n/** Round a [0,1] value to the [0,100] integer bucket the prompt builder expects. */\nfunction scaleValue(value: number): number {\n return Math.round(Math.min(Math.max(value, 0), 1) * 100);\n}\n\n/** Naive DFT magnitude spectrum of a real signal (length N → ⌊N/2⌋+1 bins). */\nfunction rfftMag(x: Float32Array): Float32Array {\n const N = x.length;\n const bins = Math.floor(N / 2) + 1;\n const mag = new Float32Array(bins);\n for (let k = 0; k < bins; k++) {\n let re = 0;\n let im = 0;\n const w = (-2 * Math.PI * k) / N;\n for (let n = 0; n < N; n++) {\n const a = w * n;\n re += x[n] * Math.cos(a);\n im += x[n] * Math.sin(a);\n }\n mag[k] = Math.hypot(re, im);\n }\n return mag;\n}\n\n/**\n * RMS energy of a clip, normalized to [0,1] (the reference clamps via scaleValue).\n * Matches `Features.extract_audio_features` energy = sqrt(mean(x^2)).\n */\nfunction rmsEnergy(audio: Float32Array): number {\n let sum = 0;\n for (let i = 0; i < audio.length; i++) {\n sum += audio[i] * audio[i];\n }\n return audio.length ? Math.sqrt(sum / audio.length) : 0;\n}\n\n/**\n * Spectral centroid normalized to [0,1] of (sr/2). Matches the reference:\n * centroid = Σ f·|rfft(x)| / Σ|rfft(x)|, then / (sr/2).\n */\nfunction spectralCentroid(audio: Float32Array, sr: number): number {\n if (audio.length === 0) {\n return 0;\n }\n const spec = rfftMag(audio);\n const nyquist = sr / 2;\n const bins = spec.length;\n let specSum = FEATURE_EPS;\n let weighted = 0;\n for (let k = 0; k < bins; k++) {\n // freqs = linspace(0, sr/2, bins): freq[k] = k/(bins-1) * nyquist.\n const freq = bins > 1 ? (k / (bins - 1)) * nyquist : 0;\n weighted += freq * spec[k];\n specSum += spec[k];\n }\n return weighted / specSum / nyquist;\n}\n\n/** Hann window of length N (periodic=false, matching torch.hann_window default). */\nfunction hannWindow(N: number): Float32Array {\n const w = new Float32Array(N);\n for (let n = 0; n < N; n++) {\n w[n] = 0.5 - 0.5 * Math.cos((2 * Math.PI * n) / (N - 1));\n }\n return w;\n}\n\n/**\n * Autocorrelation-based average pitch normalized to [0,1] over [min,max] freq.\n * Faithful port of `calculate_pitch` + `extract_single_pitch_value`: framed Hann-\n * windowed autocorrelation, per-frame parabolic-interpolated peak in the valid lag\n * range, voicing threshold, then the mean over frames mapped to [0,1].\n */\n/** Hann-windowed autocorrelation of one frame into `autocorr` (lag 0..frameLen-1). */\nfunction frameAutocorr(\n padded: Float32Array,\n off: number,\n window: Float32Array,\n frame: Float32Array,\n autocorr: Float32Array,\n): void {\n for (let i = 0; i < PITCH_FRAME_LEN; i++) {\n frame[i] = padded[off + i] * window[i];\n }\n for (let lag = 0; lag < PITCH_FRAME_LEN; lag++) {\n let acc = 0;\n for (let i = 0; i + lag < PITCH_FRAME_LEN; i++) {\n acc += frame[i] * frame[i + lag];\n }\n autocorr[lag] = acc;\n }\n}\n\n/** Voiced pitch (Hz) of one autocorrelation frame, or 0 if unvoiced. */\nfunction framePitch(autocorr: Float32Array, minIdx: number, maxIdx: number, sr: number): number {\n let peakIdx = minIdx;\n let peakVal = Number.NEGATIVE_INFINITY;\n for (let lag = minIdx; lag < maxIdx; lag++) {\n if (autocorr[lag] > peakVal) {\n peakVal = autocorr[lag];\n peakIdx = lag;\n }\n }\n // Parabolic interpolation for sub-sample accuracy.\n const idx = Math.min(Math.max(peakIdx, 1), PITCH_FRAME_LEN - 2);\n const alpha = autocorr[idx - 1];\n const beta = autocorr[idx];\n const gamma = autocorr[idx + 1];\n let delta = (0.5 * (alpha - gamma)) / (alpha - 2 * beta + gamma + 1e-8);\n if (!(peakIdx > 0 && peakIdx < PITCH_FRAME_LEN - 1)) {\n delta = 0;\n }\n const period = (peakIdx + delta) / sr;\n let pitch = period > 0 ? 1 / period : 0;\n const voiced = peakVal / (autocorr[0] + 1e-8) > PITCH_THRESHOLD;\n if (!voiced) {\n pitch = 0;\n }\n // Match torch: clamp AFTER the voicing mask, so unvoiced (0) clamps up to min_freq.\n return Math.min(Math.max(pitch, PITCH_MIN_FREQ), PITCH_MAX_FREQ);\n}\n\nfunction averagePitch(audio: Float32Array, sr: number): number {\n const N = audio.length;\n if (N < PITCH_FRAME_LEN) {\n return 0;\n }\n const padLen = (PITCH_FRAME_LEN - (N % PITCH_HOP)) % PITCH_HOP;\n const padded = new Float32Array(N + padLen);\n padded.set(audio);\n const numFrames = Math.floor((padded.length - PITCH_FRAME_LEN) / PITCH_HOP) + 1;\n if (numFrames <= 0) {\n return 0;\n }\n const window = hannWindow(PITCH_FRAME_LEN);\n const minIdx = Math.max(1, Math.floor(sr / PITCH_MAX_FREQ));\n const maxIdx = Math.min(PITCH_FRAME_LEN, Math.floor(sr / PITCH_MIN_FREQ));\n\n const frame = new Float32Array(PITCH_FRAME_LEN);\n const autocorr = new Float32Array(PITCH_FRAME_LEN);\n let pitchSum = 0;\n for (let f = 0; f < numFrames; f++) {\n frameAutocorr(padded, f * PITCH_HOP, window, frame, autocorr);\n pitchSum += framePitch(autocorr, minIdx, maxIdx, sr);\n }\n const avg = pitchSum / numFrames;\n return (avg - PITCH_MIN_FREQ) / (PITCH_MAX_FREQ - PITCH_MIN_FREQ);\n}\n\nexport interface OuteProsodyFeatures {\n energy: number;\n spectral_centroid: number;\n pitch: number;\n}\n\n/**\n * Port of `Features.extract_audio_features`: energy (RMS), spectral_centroid (FFT\n * centroid), pitch (autocorrelation), each scaled to the [0,100] integer bucket.\n * Returns all-zero defaults for an empty/invalid clip (matching the reference).\n */\nexport function extractAudioFeatures(audio: Float32Array, sr: number): OuteProsodyFeatures {\n if (audio.length === 0) {\n return { energy: 0, spectral_centroid: 0, pitch: 0 };\n }\n return {\n energy: scaleValue(rmsEnergy(audio)),\n spectral_centroid: scaleValue(spectralCentroid(audio, sr)),\n pitch: scaleValue(averagePitch(audio, sr)),\n };\n}\n\nexport interface AlignedWord {\n word: string;\n startFrame: number;\n endFrame: number;\n}\n\n/**\n * Pragmatic word→frame alignment (no on-device Whisper): split the transcript into\n * whitespace words and distribute the `numFrames` encoded frames across them\n * proportionally to each word's character length. Returns contiguous [start,end)\n * frame spans covering the whole clip. This stands in for outetts' Whisper word-\n * timestamp slicing — the codes themselves are exact; only the per-word boundaries\n * are approximate.\n */\nexport function alignWordsProportional(transcript: string, numFrames: number): AlignedWord[] {\n const words = transcript.split(WHITESPACE_RE).filter((w) => w.length > 0);\n if (words.length === 0) {\n return [];\n }\n const weights = words.map((w) => w.length);\n const totalWeight = weights.reduce((a, b) => a + b, 0);\n const out: AlignedWord[] = [];\n let acc = 0;\n for (let i = 0; i < words.length; i++) {\n const startFrame = i === 0 ? 0 : Math.round((acc / totalWeight) * numFrames);\n acc += weights[i];\n const endFrame =\n i === words.length - 1 ? numFrames : Math.round((acc / totalWeight) * numFrames);\n out.push({ word: words[i], startFrame, endFrame: Math.max(endFrame, startFrame) });\n }\n return out;\n}\n\n/**\n * Short-time RMS energy envelope sampled at the DAC frame rate (one value per code\n * frame). frame f covers audio samples [f·hop, f·hop + win). Used by the energy\n * aligner to locate silence gaps. `hop` is DAC_HOP (320 samples ≈ 13.3 ms @ 24 kHz),\n * matching the DAC frame stride so envelope index == code-frame index.\n */\nexport function frameEnergyEnvelope(\n audio: Float32Array,\n hop: number,\n numFrames: number,\n): Float32Array {\n const env = new Float32Array(numFrames);\n const win = hop; // one-hop window keeps env index aligned 1:1 with code frames.\n for (let f = 0; f < numFrames; f++) {\n const start = f * hop;\n const end = Math.min(start + win, audio.length);\n let sum = 0;\n let n = 0;\n for (let i = start; i < end; i++) {\n sum += audio[i] * audio[i];\n n++;\n }\n env[f] = n > 0 ? Math.sqrt(sum / n) : 0;\n }\n return env;\n}\n\n/**\n * A contiguous run of speech frames [start, end) detected in the energy envelope.\n */\ninterface SpeechRun {\n start: number;\n end: number;\n}\n\n/**\n * Segment the energy envelope into speech runs separated by silence gaps. A frame is\n * \"silent\" when its energy is below `floor + (peak-floor)*silenceRatio`; a run of\n * silent frames at least `minGapFrames` long is treated as a word/phrase boundary.\n * Leading/trailing silence is trimmed. Returns the speech runs in order.\n */\nfunction detectSpeechRuns(\n env: Float32Array,\n silenceRatio: number,\n minGapFrames: number,\n): SpeechRun[] {\n const numFrames = env.length;\n if (numFrames === 0) {\n return [];\n }\n let peak = 0;\n let floor = Number.POSITIVE_INFINITY;\n for (let f = 0; f < numFrames; f++) {\n peak = Math.max(peak, env[f]);\n floor = Math.min(floor, env[f]);\n }\n if (peak <= 0) {\n return [];\n }\n const threshold = floor + (peak - floor) * silenceRatio;\n const runs: SpeechRun[] = [];\n let runStart = -1;\n let silentRun = 0;\n for (let f = 0; f < numFrames; f++) {\n const voiced = env[f] > threshold;\n if (voiced) {\n if (runStart < 0) {\n runStart = f;\n }\n silentRun = 0;\n } else {\n silentRun++;\n // Close the current run only once the silence is long enough to be a real gap.\n if (runStart >= 0 && silentRun >= minGapFrames) {\n runs.push({ start: runStart, end: f - silentRun + 1 });\n runStart = -1;\n }\n }\n }\n if (runStart >= 0) {\n runs.push({ start: runStart, end: numFrames });\n }\n return runs.filter((r) => r.end > r.start);\n}\n\nconst ENERGY_SILENCE_RATIO = 0.15; // frames under 15% of dynamic range are \"silence\".\nconst ENERGY_MIN_GAP_FRAMES = 4; // ≥4 DAC frames (~53 ms) of silence = a boundary.\n\n/**\n * Distribute `numWords` whole words across speech runs proportionally to each run's\n * frame length, giving every run ≥1 word and summing to exactly `numWords`. Surplus\n * (from the per-run floor) is handed to the longest runs first; any overshoot is taken\n * back from the shortest runs (never below 1). Returns the per-run word count.\n */\nfunction distributeWordCounts(runLens: number[], numWords: number): number[] {\n const totalRunLen = runLens.reduce((a, b) => a + b, 0) || 1;\n const targets = runLens.map((len) => Math.max(1, Math.floor((len / totalRunLen) * numWords)));\n const order = runLens.map((_, i) => i).sort((a, b) => runLens[b] - runLens[a]);\n let assigned = targets.reduce((a, b) => a + b, 0);\n let oi = 0;\n while (assigned < numWords) {\n targets[order[oi % order.length]]++;\n assigned++;\n oi++;\n }\n while (assigned > numWords) {\n const idx = order[order.length - 1 - (oi % order.length)];\n if (targets[idx] > 1) {\n targets[idx]--;\n assigned--;\n }\n oi++;\n }\n return targets;\n}\n\n/**\n * Split a contiguous frame span [spanStart, spanEnd) among `groupWords` char-\n * proportionally, appending the resulting {@link AlignedWord}s to `out`. Boundaries\n * are contiguous within the span (the last word reaches spanEnd exactly).\n */\nfunction splitRunWords(\n groupWords: string[],\n spanStart: number,\n spanEnd: number,\n out: AlignedWord[],\n): void {\n const span = Math.max(1, spanEnd - spanStart);\n const chars = groupWords.map((w) => w.length || 1);\n const groupTotal = chars.reduce((a, b) => a + b, 0) || groupWords.length;\n let acc = 0;\n for (let g = 0; g < groupWords.length; g++) {\n const wStart = g === 0 ? spanStart : spanStart + Math.round((acc / groupTotal) * span);\n acc += chars[g];\n const wEnd =\n g === groupWords.length - 1 ? spanEnd : spanStart + Math.round((acc / groupTotal) * span);\n out.push({ word: groupWords[g], startFrame: wStart, endFrame: Math.max(wEnd, wStart) });\n }\n}\n\n/**\n * Forced word→frame alignment driven by the clip's energy envelope. Detects the\n * silence gaps in `audio` (at DAC frame resolution) and distributes the transcript's\n * words across the detected speech runs so that word boundaries land on real pauses.\n * Within a run, words are split char-proportionally (same local rule as the fallback).\n * Run spans are made contiguous across the silence gaps (a run owns the frames up to\n * the next run's start) so the per-word c1/c2 slices still tile the full [0, numFrames)\n * code stream with no dropped frames.\n *\n * Falls back to {@link alignWordsProportional} when the envelope has no usable\n * structure (≤1 speech run). The DAC codes are never touched; only the boundaries move.\n */\nexport function alignWordsByEnergy(\n transcript: string,\n numFrames: number,\n audio: Float32Array,\n hop: number,\n): AlignedWord[] {\n const words = transcript.split(WHITESPACE_RE).filter((w) => w.length > 0);\n if (words.length === 0) {\n return [];\n }\n if (words.length === 1 || numFrames <= 0) {\n return alignWordsProportional(transcript, numFrames);\n }\n\n const env = frameEnergyEnvelope(audio, hop, numFrames);\n const runs = detectSpeechRuns(env, ENERGY_SILENCE_RATIO, ENERGY_MIN_GAP_FRAMES);\n // Need at least 2 runs to beat the audio-blind estimator; otherwise fall back.\n if (runs.length < 2) {\n return alignWordsProportional(transcript, numFrames);\n }\n\n const runLens = runs.map((r) => r.end - r.start);\n const targets = distributeWordCounts(runLens, words.length);\n\n // Walk the words run-by-run, splitting each run's contiguous frame span among its\n // words. The span extends to the next run's start (or the clip end), so the silence\n // frames are absorbed into the preceding word and the slices tile [0, numFrames).\n const out: AlignedWord[] = [];\n let wordIdx = 0;\n for (let r = 0; r < runs.length; r++) {\n const spanStart = r === 0 ? 0 : runs[r].start;\n const spanEnd = r === runs.length - 1 ? numFrames : runs[r + 1].start;\n splitRunWords(words.slice(wordIdx, wordIdx + targets[r]), spanStart, spanEnd, out);\n wordIdx += targets[r];\n }\n return out;\n}\n\nexport { DAC_TPS };\n","/**\n * OuteTTS — native text-to-speech engine for Gerbil's WebGPU backend.\n *\n * OuteTTS-1.0-0.6B (OuteAI/OuteTTS-1.0-0.6B) is a two-stage codec-LM TTS, the same\n * shape as Kani-TTS but with a plain Qwen3-0.6B backbone and the descript-audio-codec\n * DAC.speech.v1.0 decoder (24 kHz, 2 codebooks):\n *\n * 1. CODEC-LM BACKBONE (Qwen3-0.6B): autoregressively emits interleaved audio codes\n * <|c1_i|>/<|c2_i|> (one pair per 512-sample frame) into the same vocab as text,\n * between <|audio_start|> and <|audio_end|>. Standard Qwen3 block math\n * (RMSNorm/QK-RMSNorm/full RoPE/GQA/SwiGLU) with a KV-cache decode path\n * (generateOuteTtsBackboneGraph) — simpler than Kani's LFM2 hybrid.\n * 2. DAC.speech.v1.0 DECODER: RVQ dequant (2× codebook lookup + out_proj) → latent\n * [1024,T] → DacDecoder (Conv1d + 4 upsample blocks + Snake + tanh) → 24 kHz PCM.\n * Validated bit-exact vs the torch DAC reference (scripts/engine/test-outetts-codec.mjs,\n * latent max|err| 2.9e-6, PCM max|err| 1.3e-6, cos 1.0).\n *\n * The AR loop runs on the host with full-logit readback; each step samples the next\n * audio token constrained to the current codebook's valid window (c1 on even\n * positions, c2 on odd), until <|audio_end|>. The collected tokens are split into a\n * [2, T] code grid (audioTokensToDacCodes) and decoded once through the DAC graph.\n *\n * This is the FOUNDATION: a single preset voice (OuteTTS's bundled en-female-1-neutral\n * speaker, embedded as in-context reference codes). Cloning, int4, the speak()/useTTS\n * public surface, R2 mirror, and the playground are a later phase.\n */\n\nimport {\n audioTokensToDacCodes,\n DAC_HOP,\n DAC_NUM_CODEBOOKS,\n DAC_SAMPLE_RATE,\n dacEncoderFrames,\n dacOutputLength,\n generateDacSpeechDecoderGraph,\n generateDacSpeechEncoderGraph,\n generateOuteTtsBackboneGraph,\n OUTETTS_AUDIO_END,\n OUTETTS_IM_END,\n} from \"./architectures/outetts.js\";\nimport type { GPUContext } from \"./device.js\";\nimport { initGPU } from \"./device.js\";\nimport { Executor } from \"./executor.js\";\nimport { type LoadedOuteTTS, loadOuteTTS, quantizeBackboneInt4 } from \"./model-loader.js\";\nimport { alignWordsByEnergy, DAC_TPS, extractAudioFeatures } from \"./outetts-encode.js\";\nimport type { Tokenizer } from \"./tokenizer.js\";\n\nconst DEFAULT_MAX_NEW_TOKENS = 4096; // 2 tokens/frame → up to ~2048 frames (~27 s)\n\n/** A single word's reference codes in a speaker prompt (the bundled default voice). */\nexport interface OuteSpeakerWord {\n word: string;\n duration?: number;\n c1: number[];\n c2: number[];\n features?: { energy?: number; spectral_centroid?: number; pitch?: number };\n}\nexport interface OuteSpeaker {\n text: string;\n words: OuteSpeakerWord[];\n}\n\n// ── OuteTTS v3 prompt-string builders (verbatim port of outetts'\n// PromptProcessor: text_normalizations / merge_speaker_text / create_codes /\n// get_completion_prompt). The whole prompt is assembled as a STRING with the\n// literal <|...|> special-token markers, then tokenized in ONE pass — Gerbil's\n// tokenizer splits on every added token, mirroring HF AutoTokenizer.encode(\n// prompt, add_special_tokens=False). This reproduces the reference token layout\n// EXACTLY (time/energy/spectral_centroid/pitch features per word), which the\n// earlier foundation omitted (the cause of the incoherent speech). ──\n\nconst CONTROL_CHARS_RE =\n // biome-ignore lint/suspicious/noControlCharactersInRegex: matches the reference control-char set\n /[\\x00-\\x1F\\x7F-\\x9F-]/g;\nconst HIRAGANA_RE = /[-ゟ]/;\nconst KATAKANA_RE = /[゠-ヿ]/;\nconst HAN_RE = /[一-鿿]/;\nconst HTTP_URL_RE = /^https?:\\/\\//;\nconst TRAILING_SLASH_RE = /\\/$/;\n\n/** Port of PromptProcessor.text_normalizations (the ftfy step is approximated). */\nfunction normalizeOuteText(input: string): string {\n let text = input.normalize(\"NFKC\");\n text = text.replace(/…/g, \"...\");\n text = text.replace(/\\.{2,}/g, \"...\");\n text = text.replace(/[“”„‟«»]/g, '\"');\n text = text.replace(/[‘’‛‹›`´]/g, \"'\");\n text = text.replace(/[–—―−‐]/g, \"-\");\n text = text.replace(/-{2,}/g, \"-\");\n text = text.replace(CONTROL_CHARS_RE, \"\");\n text = text.replace(/\\s+/g, \" \");\n text = text.replace(/\\s+([,.?!:;])/g, \"$1\");\n text = text.replace(/([,.?!:;])(?=[^\\s,.?!:;])/g, \"$1 \");\n text = text.replace(/(\\w)\\s+'\\s*(\\w)/g, \"$1'$2\");\n text = text.replace(/(\\w)\\s+'\\s*([,.?!:;\\s]|$)/g, \"$1'$2\");\n text = text.replace(/(\\w)\\s*'\\s*([tsdmreSNTDMRE])\\b/gi, \"$1'$2\");\n text = text.replace(/([?!])\\1+/g, \"$1\");\n text = text.replace(/\\s+/g, \" \");\n text = text.replace(/\"/g, \"\").trim();\n return text;\n}\n\n/** Port of PromptProcessor._get_separator (CJK-aware). */\nfunction outeSeparator(text: string): string {\n const hasHiragana = HIRAGANA_RE.test(text);\n const hasKatakana = KATAKANA_RE.test(text);\n const hasHan = HAN_RE.test(text);\n if (hasHiragana || hasKatakana || hasHan) {\n return \"。\";\n }\n return \". \";\n}\n\n/**\n * Port of PromptProcessor.merge_speaker_text: prepend the (normalized) speaker\n * transcript in front of the target text, joined by the right separator, and return\n * the trailing-separator string that outetts appends to the speaker's LAST word.\n */\nfunction mergeSpeakerText(inputText: string, speakerText: string): { merged: string; sep: string } {\n const sp = speakerText.trim();\n const separator = outeSeparator(sp);\n const allowedEnds = separator === \"。\" ? [\"。\", \"?\", \"!\", \"?\", \"!\"] : [\".\", \"?\", \"!\"];\n let rs = \"\";\n if (sp) {\n const last = sp[sp.length - 1];\n if (!allowedEnds.includes(last)) {\n rs = separator;\n } else if (separator !== \"。\") {\n rs = \" \";\n }\n }\n return { merged: sp + rs + inputText.trim(), sep: rs.trim() };\n}\n\n/** Format one word's feature tokens (energy / spectral_centroid / pitch). */\nfunction outeFeatureTokens(f?: {\n energy?: number;\n spectral_centroid?: number;\n pitch?: number;\n}): string {\n const energy = f?.energy ?? 0;\n const sc = f?.spectral_centroid ?? 0;\n const pitch = f?.pitch ?? 0;\n return `<|energy_${energy}|><|spectral_centroid_${sc}|><|pitch_${pitch}|>`;\n}\n\n/** Port of PromptProcessor.create_codes: one <|word_start|>…<|word_end|> block per word, \"\\n\"-joined. */\nfunction createSpeakerCodes(words: OuteSpeakerWord[]): string {\n const blocks: string[] = [];\n for (const w of words) {\n const duration = (w.duration ?? 0).toFixed(2);\n let block = `${w.word}<|features|><|t_${duration}|>${outeFeatureTokens(w.features)}`;\n const n = Math.min(w.c1.length, w.c2.length);\n let pairs = \"\";\n for (let i = 0; i < n; i++) {\n pairs += `<|c1_${w.c1[i]}|><|c2_${w.c2[i]}|>`;\n }\n block += `<|code|>${pairs}`;\n blocks.push(`<|word_start|>${block}<|word_end|>`);\n }\n return blocks.join(\"\\n\");\n}\n\n/**\n * Build the OuteTTS v3 completion prompt STRING (outetts get_completion_prompt). The\n * whole prompt — text section, speaker word blocks (word + time/energy/spectral/pitch\n * features + interleaved c1/c2 codes), and the dangling <|word_start|> cue — is\n * assembled with literal <|...|> markers; the caller tokenizes it in one pass. Exposed\n * for token-level validation against the Python reference (test-outetts-prompt.mjs).\n */\nexport function buildOutePromptString(text: string, speaker?: OuteSpeaker): string {\n const normalized = normalizeOuteText(text);\n let promptText = normalized;\n let codes = \"\";\n if (speaker) {\n const { merged, sep } = mergeSpeakerText(normalized, speaker.text);\n promptText = merged;\n // outetts appends the trailing separator to the LAST speaker word's `word`.\n const words = speaker.words.map((w, i) =>\n i === speaker.words.length - 1 ? { ...w, word: w.word + sep } : w,\n );\n codes = createSpeakerCodes(words);\n }\n let prompt = `<|im_start|>\\n<|text_start|>${promptText}<|text_end|>\\n<|audio_start|>\\n`;\n if (speaker) {\n prompt += `${codes}\\n<|word_start|>`;\n }\n return prompt;\n}\n\n/**\n * Load an OuteTTS preset speaker (the in-context reference voice). Accepts a full URL\n * (mirror), a local file path (Node), or a bare preset name resolved against\n * `baseURL/{name}.json`. The returned object is the OuteSpeaker the prompt builder\n * embeds (transcript + per-word c1/c2 reference codes + prosody features).\n */\nexport async function loadOuteSpeaker(voiceOrUrl: string, baseURL?: string): Promise<OuteSpeaker> {\n // Already a parsed speaker passed through? (defensive — callers pass strings)\n if (HTTP_URL_RE.test(voiceOrUrl)) {\n const resp = await fetch(voiceOrUrl);\n if (!resp.ok) {\n throw new Error(`Failed to fetch OuteTTS speaker ${voiceOrUrl}: ${resp.status}`);\n }\n return (await resp.json()) as OuteSpeaker;\n }\n // Local file path (Node): read + parse.\n if (voiceOrUrl.includes(\"/\") || voiceOrUrl.endsWith(\".json\")) {\n const fs = await import(\"node:fs\").catch(() => null);\n if (fs) {\n return JSON.parse(fs.readFileSync(voiceOrUrl, \"utf8\")) as OuteSpeaker;\n }\n }\n // Bare preset name → resolve against the mirror base URL.\n if (!baseURL) {\n throw new Error(\n `loadOuteSpeaker: \"${voiceOrUrl}\" is a preset name but no baseURL was provided.`,\n );\n }\n const url = `${baseURL.replace(TRAILING_SLASH_RE, \"\")}/${voiceOrUrl}.json`;\n const resp = await fetch(url);\n if (!resp.ok) {\n throw new Error(`Failed to fetch OuteTTS preset \"${voiceOrUrl}\" from ${url}: ${resp.status}`);\n }\n return (await resp.json()) as OuteSpeaker;\n}\n\nexport interface OuteTTSOptions {\n /** Backbone repo (default OuteAI/OuteTTS-1.0-0.6B). */\n repo?: string;\n /**\n * Folded DAC.speech codec weights: a local path to scripts/engine/prep-dac-speech.py's\n * output, or a mirror URL. Required (the official DAC repo ships only `.pth`).\n */\n codecWeightsPath: string;\n /**\n * The preset speaker (in-context reference). Pass OuteTTS's bundled\n * en-female-1-neutral.json (text + words[].c1/c2). When omitted, synthesis runs\n * text-only (the model free-runs a less-stable voice).\n */\n speaker?: OuteSpeaker;\n /**\n * Backbone precision. \"q4\" (default) loads/runs the 1.2 GB f32 backbone as group-wise\n * weight-only INT4 (~400 MB, tied embedding kept f32). \"f32\" keeps full precision.\n */\n dtype?: OuteDType;\n revision?: string;\n hfToken?: string;\n cacheDir?: string;\n maxSeqLen?: number;\n onProgress?: (loaded: number, total: number, message: string) => void;\n}\n\nexport type OuteDType = \"q4\" | \"f32\";\n\nexport interface OuteSpeakOptions {\n /** Sampling temperature (OuteTTS default 0.4). */\n temperature?: number;\n /** Top-p nucleus threshold (default 0.9). */\n topP?: number;\n /** Top-k cutoff (default 40). */\n topK?: number;\n /** Repetition penalty (default 1.1) over the last `repetitionRange` tokens. */\n repetitionPenalty?: number;\n /** Repetition-penalty window (default 64). */\n repetitionRange?: number;\n /** Override max generated tokens (default 4096). */\n maxNewTokens?: number;\n /**\n * Greedy (argmax) decode over the full vocab, matching HF do_sample=False. Used for\n * deterministic reference validation (test-outetts-greedy.mjs). Default false\n * (sampled).\n */\n greedy?: boolean;\n /**\n * Override the in-context speaker for this call (voice cloning / preset swap). When\n * set, this speaker's reference word blocks are embedded in the prompt instead of the\n * one the engine was created with. Build it from a reference clip via\n * {@link OuteTTS.encodeSpeaker} (transcript + DAC codes), or pass a preset JSON.\n */\n speaker?: OuteSpeaker;\n}\n\nexport interface OuteSpeakResult {\n /** Mono PCM in [-1, 1]. */\n pcm: Float32Array;\n /** Sample rate (24000). */\n sampleRate: number;\n /** Number of audio frames decoded. */\n frames: number;\n /** Audio duration in seconds. */\n audioSeconds: number;\n}\n\n/** Build a fresh map of just the constant weights a graph references (see kani-tts). */\nfunction selectGraphWeights(\n graph: { tensors: Record<string, { storage: string; safetensorsKey?: string }> },\n weights: Map<string, { data: ArrayBufferView; shape: number[] }>,\n): Map<string, { data: ArrayBufferView; shape: number[] }> {\n const out = new Map<string, { data: ArrayBufferView; shape: number[] }>();\n for (const [name, desc] of Object.entries(graph.tensors)) {\n if (desc.storage !== \"constant\") {\n continue;\n }\n const w =\n weights.get(name) ?? (desc.safetensorsKey ? weights.get(desc.safetensorsKey) : undefined);\n if (w) {\n out.set(name, w);\n }\n }\n return out;\n}\n\n/** Index of the maximum logit (greedy / argmax decode). */\nfunction argmax(logits: Float32Array): number {\n let best = 0;\n let bestV = logits[0];\n for (let i = 1; i < logits.length; i++) {\n if (logits[i] > bestV) {\n bestV = logits[i];\n best = i;\n }\n }\n return best;\n}\n\n/** In-place softmax of `scores`. */\nfunction softmaxInPlace(scores: Float32Array): void {\n let maxV = Number.NEGATIVE_INFINITY;\n for (const v of scores) {\n if (v > maxV) {\n maxV = v;\n }\n }\n let sum = 0;\n for (let i = 0; i < scores.length; i++) {\n const e = Math.exp(scores[i] - maxV);\n scores[i] = e;\n sum += e;\n }\n for (let i = 0; i < scores.length; i++) {\n scores[i] /= sum;\n }\n}\n\n/** Top-p nucleus sample from a softmaxed prob array over `ids`. */\nfunction nucleusSample(probs: Float32Array, ids: Int32Array, topP: number): number {\n const n = probs.length;\n const order = Array.from({ length: n }, (_, i) => i).sort((a, b) => probs[b] - probs[a]);\n let cum = 0;\n let cutoff = n;\n for (let r = 0; r < n; r++) {\n cum += probs[order[r]];\n if (cum >= topP) {\n cutoff = r + 1;\n break;\n }\n }\n let keepSum = 0;\n for (let r = 0; r < cutoff; r++) {\n keepSum += probs[order[r]];\n }\n let pick = Math.random() * keepSum;\n for (let r = 0; r < cutoff; r++) {\n pick -= probs[order[r]];\n if (pick <= 0) {\n return ids[order[r]];\n }\n }\n return ids[order[0]];\n}\n\n/**\n * Select the `k` highest-scoring token ids in a single O(n·logk) pass (bounded\n * min-heap), applying the repetition penalty to `previous` tokens inline so a\n * penalized token can drop out of the shortlist. Returns the kept ids and their\n * (penalized, pre-temperature) logits, unsorted.\n *\n * This replaces the two full-vocab `Array.from(...).sort(...)` passes the sampler\n * ran PER TOKEN over OuteTTS's ~157k vocab (the top-k filter + the nucleus sort):\n * a codec-LM emits hundreds-to-thousands of tokens per utterance, so those two\n * O(n·logn) sorts — plus their two fresh 157k-element allocations every step —\n * dominated host-side decode and made the browser SPEECH tab look stalled\n * (\"SYNTHESIZING…\" for minutes). Restricting the softmax + nucleus to the kept\n * top-k is distribution-identical to the old full-vocab path (softmax is\n * monotonic and the discarded tail is renormalized away either way).\n */\nfunction selectTopKPenalized(\n logits: Float32Array,\n k: number,\n penalized: Set<number> | null,\n penalty: number,\n): { ids: Int32Array; vals: Float32Array } {\n const n = logits.length;\n const cap = Math.min(k, n);\n const heapVal = new Float32Array(cap);\n const heapId = new Int32Array(cap);\n let size = 0;\n\n const penalize = (i: number, v: number): number => {\n if (penalized?.has(i)) {\n return v > 0 ? v / penalty : v * penalty;\n }\n return v;\n };\n const siftDown = (): void => {\n let root = 0;\n for (;;) {\n let smallest = root;\n const l = 2 * root + 1;\n const r = 2 * root + 2;\n if (l < size && heapVal[l] < heapVal[smallest]) smallest = l;\n if (r < size && heapVal[r] < heapVal[smallest]) smallest = r;\n if (smallest === root) break;\n const tv = heapVal[root];\n const ti = heapId[root];\n heapVal[root] = heapVal[smallest];\n heapId[root] = heapId[smallest];\n heapVal[smallest] = tv;\n heapId[smallest] = ti;\n root = smallest;\n }\n };\n const siftUp = (node0: number): void => {\n let node = node0;\n while (node > 0) {\n const parent = (node - 1) >> 1;\n if (heapVal[parent] <= heapVal[node]) break;\n const tv = heapVal[node];\n const ti = heapId[node];\n heapVal[node] = heapVal[parent];\n heapId[node] = heapId[parent];\n heapVal[parent] = tv;\n heapId[parent] = ti;\n node = parent;\n }\n };\n\n for (let i = 0; i < n; i++) {\n const v = penalize(i, logits[i]);\n if (size < cap) {\n heapVal[size] = v;\n heapId[size] = i;\n size++;\n siftUp(size - 1);\n } else if (v > heapVal[0]) {\n heapVal[0] = v;\n heapId[0] = i;\n siftDown();\n }\n }\n return { ids: heapId.subarray(0, size), vals: heapVal.subarray(0, size) };\n}\n\n/**\n * Resample interleaved-or-mono PCM to mono at `targetRate` via linear interpolation.\n * Audio is assumed already mono (Float32 [-1,1]); if `srcRate === targetRate` the\n * input is returned as-is. Linear resampling is sufficient for codec conditioning\n * (the DAC encoder is robust to the small interpolation error vs torchaudio's\n * sinc resampler — the cloned codes are stable).\n */\nfunction resampleMono(audio: Float32Array, srcRate: number, targetRate: number): Float32Array {\n if (srcRate === targetRate) {\n return audio;\n }\n const ratio = targetRate / srcRate;\n const outLen = Math.max(1, Math.round(audio.length * ratio));\n const out = new Float32Array(outLen);\n for (let i = 0; i < outLen; i++) {\n const srcPos = i / ratio;\n const i0 = Math.floor(srcPos);\n const i1 = Math.min(i0 + 1, audio.length - 1);\n const frac = srcPos - i0;\n out[i] = audio[i0] * (1 - frac) + audio[i1] * frac;\n }\n return out;\n}\n\nexport class OuteTTS {\n private ctx: GPUContext;\n private loaded: LoadedOuteTTS;\n private tokenizer: Tokenizer;\n private maxSeqLen: number;\n private backboneExec: Executor;\n private speaker?: OuteSpeaker;\n private _destroyed = false;\n\n readonly sampleRate = DAC_SAMPLE_RATE;\n /** The selected backbone precision (\"q4\" or \"f32\"). */\n readonly dtype: OuteDType;\n\n private constructor(\n ctx: GPUContext,\n loaded: LoadedOuteTTS,\n maxSeqLen: number,\n dtype: OuteDType,\n speaker?: OuteSpeaker,\n ) {\n this.ctx = ctx;\n this.loaded = loaded;\n this.tokenizer = loaded.tokenizer;\n this.maxSeqLen = maxSeqLen;\n this.speaker = speaker;\n this.dtype = dtype;\n\n const useQ4 = dtype === \"q4\";\n const graph = generateOuteTtsBackboneGraph(loaded.rawConfig, useQ4 ? \"q4\" : undefined);\n if (useQ4) {\n // Quantize the Qwen3 linear projections to INT4 in place (tied embedding stays f32).\n quantizeBackboneInt4(graph, loaded.backboneWeights);\n }\n const exec = new Executor(ctx, graph, { maxSeqLen, kvMode: \"f32\" });\n exec.uploadWeightsMap(selectGraphWeights(graph, loaded.backboneWeights));\n exec.initBindGroups();\n this.backboneExec = exec;\n }\n\n static async create(options: OuteTTSOptions): Promise<OuteTTS> {\n const ctx = await initGPU();\n const loaded = await loadOuteTTS({\n repo: options.repo,\n codecWeightsPath: options.codecWeightsPath,\n revision: options.revision,\n hfToken: options.hfToken,\n cacheDir: options.cacheDir,\n onProgress: options.onProgress,\n });\n const ctxLen = (loaded.rawConfig.max_position_embeddings as number) ?? 40_960;\n const maxSeqLen = Math.min(options.maxSeqLen ?? 4096, ctxLen);\n return new OuteTTS(ctx, loaded, maxSeqLen, options.dtype ?? \"q4\", options.speaker);\n }\n\n /**\n * Build the synthesis prompt as a STRING (outetts v3 get_completion_prompt) and\n * tokenize in one pass. With a speaker, the speaker transcript is merged in front of\n * the target text (merge_speaker_text), the speaker's reference word blocks\n * (word + <|features|> + <|t_dur|> + energy/spectral_centroid/pitch + <|code|> +\n * c1/c2 pairs) are embedded in-context, and the prompt ends with a dangling\n * <|word_start|> to cue generation. Without a speaker, a plain text-only prompt.\n *\n * <|im_start|>\\n<|text_start|>{text}<|text_end|>\\n<|audio_start|>\\n\n * [ {speaker word blocks \"\\n\"-joined} \\n <|word_start|> ]\n *\n * This reproduces the reference token layout EXACTLY (validated to the byte vs\n * outetts.PromptProcessor — see scripts/engine/outetts-ref-prompt.py and\n * test-outetts-prompt.mjs). The per-word time/feature tokens were the gating fix:\n * the earlier foundation dropped them and the backbone produced incoherent audio.\n */\n private buildPrompt(text: string, speaker?: OuteSpeaker): number[] {\n return this.tokenizer.encode(buildOutePromptString(text, speaker ?? this.speaker));\n }\n\n /**\n * Synthesize speech for `text`. Returns 24 kHz mono PCM.\n *\n * Pipeline: build prompt → prefill backbone → AR-decode interleaved c1/c2 audio\n * tokens until <|audio_end|> → split to a [2, T] DAC code grid → DAC decode → tanh\n * → PCM.\n */\n async speak(text: string, opts: OuteSpeakOptions = {}): Promise<OuteSpeakResult> {\n if (this._destroyed) {\n throw new Error(\"OuteTTS has been destroyed.\");\n }\n const startTime = performance.now();\n const audioTokens = await this.generateTokens(text, opts);\n\n const { codes, numFrames } = audioTokensToDacCodes(audioTokens);\n if (numFrames === 0) {\n throw new Error(\n `OuteTTS produced no complete audio frames (audioTokens=${audioTokens.length}).`,\n );\n }\n const pcm = await this.decodeCodes(codes, numFrames);\n\n const totalTime = (performance.now() - startTime) / 1000;\n // True duration uses the actual decoded sample count (320·T − 8), not the nominal hop.\n const audioSeconds = pcm.length / DAC_SAMPLE_RATE;\n console.log(\n `[outetts] frames=${numFrames} audio=${audioSeconds.toFixed(2)}s wall=${totalTime.toFixed(\n 2,\n )}s RTF=${(audioSeconds / totalTime).toFixed(2)}x`,\n );\n\n return { pcm, sampleRate: DAC_SAMPLE_RATE, frames: numFrames, audioSeconds };\n }\n\n /**\n * Build an in-context speaker reference for voice cloning.\n *\n * Two inputs are supported:\n * 1. A pre-encoded {@link OuteSpeaker} (transcript + per-word c1/c2 DAC codes +\n * prosody features — the preset-JSON shape). Returned verbatim.\n * 2. Raw audio (Float32 PCM + transcript). The clip is resampled to 24 kHz mono,\n * hop-padded, run through the DAC.speech ENCODER + RVQ-encode on the GPU\n * (generateDacSpeechEncoderGraph; encoder latent validated bit-exact and codes\n * 450/450 vs torch DAC.encode — scripts/engine/test-outetts-encode.mjs), then\n * split into per-word {@link OuteSpeakerWord} blocks with prosody features.\n *\n * Fidelity vs outetts `create_speaker`: the DAC-encode (audio → c1/c2 codes) and the\n * energy/spectral_centroid/pitch feature math are a faithful port. Two documented\n * approximations: (a) word→frame ALIGNMENT — outetts uses Whisper word timestamps to\n * slice the code stream. Gerbil's on-device Moonshine STT does not expose word\n * timestamps (its decoder cross-attention is never read back), so we instead run an\n * energy-forced aligner ({@link alignWordsByEnergy}) that snaps word boundaries onto\n * the clip's own silence gaps — audio-driven, tighter than the old char-proportional\n * guess, and exact when each word is pause-separated; it falls back to proportional\n * for continuous speech. (b) we skip outetts' pyloudnorm pre-normalization (it mainly\n * rescales absolute level / the energy bucket). The cloned voice timbre and prosody\n * come through; only the per-word boundaries remain an estimate.\n */\n async encodeSpeaker(\n ref: OuteSpeaker | { audio: Float32Array; sampleRate: number; transcript: string },\n ): Promise<OuteSpeaker> {\n if (\"words\" in ref && \"text\" in ref) {\n return ref;\n }\n if (this._destroyed) {\n throw new Error(\"OuteTTS has been destroyed.\");\n }\n const { audio, sampleRate, transcript } = ref;\n if (!audio || audio.length === 0) {\n throw new Error(\"OuteTTS.encodeSpeaker: empty audio.\");\n }\n if (!transcript || transcript.trim().length === 0) {\n throw new Error(\"OuteTTS.encodeSpeaker: a transcript of the clip is required.\");\n }\n\n // Resample to 24 kHz mono and hop-pad (DAC.preprocess: ceil(L/hop)*hop).\n const mono = resampleMono(audio, sampleRate, DAC_SAMPLE_RATE);\n const paddedLen = Math.ceil(mono.length / DAC_HOP) * DAC_HOP;\n const pcm = new Float32Array(paddedLen);\n pcm.set(mono);\n\n // DAC.speech encode (Conv downsample stack + RVQ argmin) → codes[NCB, T].\n const numFrames = dacEncoderFrames(paddedLen);\n const codes = await this.encodeAudioToCodes(pcm, numFrames);\n const c1All = codes.subarray(0, numFrames);\n const c2All = codes.subarray(numFrames, 2 * numFrames);\n\n // Per-word blocks: energy-forced frame alignment (snaps boundaries to the clip's\n // own silence gaps; falls back to char-proportional when the envelope is flat) +\n // per-word prosody features sliced from the matching audio span.\n const aligned = alignWordsByEnergy(transcript, numFrames, mono, DAC_HOP);\n const words: OuteSpeakerWord[] = aligned.map((a) => {\n const startSample = Math.min(a.startFrame * DAC_HOP, mono.length);\n const endSample = Math.min(a.endFrame * DAC_HOP, mono.length);\n const wordAudio = mono.subarray(startSample, endSample);\n const features = extractAudioFeatures(wordAudio, DAC_SAMPLE_RATE);\n return {\n word: a.word,\n duration: Math.round(((a.endFrame - a.startFrame) / DAC_TPS) * 100) / 100,\n c1: Array.from(c1All.subarray(a.startFrame, a.endFrame)),\n c2: Array.from(c2All.subarray(a.startFrame, a.endFrame)),\n features,\n };\n });\n\n return { text: transcript.trim(), words };\n }\n\n /** Run the DAC.speech encoder + RVQ-encode graph → codebook-major codes[NCB·T] (u32). */\n private async encodeAudioToCodes(pcm: Float32Array, numFrames: number): Promise<Uint32Array> {\n const graph = generateDacSpeechEncoderGraph({ numSamples: pcm.length });\n const exec = new Executor(this.ctx, graph, { maxSeqLen: numFrames, kvMode: \"f32\" });\n try {\n exec.uploadWeightsMap(selectGraphWeights(graph, this.loaded.codecWeights));\n exec.initBindGroups();\n exec.reset();\n exec.writeInput(\"pcm_in\", pcm);\n // The codes buffer is u32; runGraphOutput returns an f32 view of the same bytes.\n const raw = await exec.runGraphOutput(\"dac_codes\", DAC_NUM_CODEBOOKS * numFrames);\n return new Uint32Array(raw.buffer, raw.byteOffset, DAC_NUM_CODEBOOKS * numFrames).slice();\n } finally {\n exec.destroy();\n }\n }\n\n /** Build the prompt, prefill, and AR-decode the raw generated token stream. */\n private async generateTokens(text: string, opts: OuteSpeakOptions): Promise<number[]> {\n const prompt = this.buildPrompt(text, opts.speaker);\n if (prompt.length >= this.maxSeqLen) {\n throw new Error(`OuteTTS prompt is ${prompt.length} tokens >= maxSeqLen ${this.maxSeqLen}.`);\n }\n this.backboneExec.reset();\n const { logits } = await this.backboneExec.forward(new Uint32Array(prompt));\n return this.runDecodeLoop(prompt, logits, {\n temperature: opts.temperature ?? 0.4,\n topP: opts.topP ?? 0.9,\n topK: opts.topK ?? 40,\n repetitionPenalty: opts.repetitionPenalty ?? 1.1,\n repetitionRange: opts.repetitionRange ?? 64,\n maxNewTokens: Math.min(opts.maxNewTokens ?? DEFAULT_MAX_NEW_TOKENS, this.maxSeqLen),\n greedy: opts.greedy ?? false,\n });\n }\n\n /** Test hook: return the raw generated token stream (no DAC decode). */\n async generateTokensForTest(text: string, opts: OuteSpeakOptions = {}): Promise<number[]> {\n return this.generateTokens(text, opts);\n }\n\n /**\n * Autoregressive decode: from the prefill logits, sample one token per step over the\n * full vocab (greedy argmax, or temperature/top-k/top-p with repetition penalty).\n * Stops at <|audio_end|>/<|im_end|> or the token cap. Returns the raw token stream\n * (word-block structure + interleaved c1/c2 codes); audioTokensToDacCodes extracts\n * the codes.\n */\n private async runDecodeLoop(\n prompt: number[],\n prefillLogits: Float32Array,\n p: {\n temperature: number;\n topP: number;\n topK: number;\n repetitionPenalty: number;\n repetitionRange: number;\n maxNewTokens: number;\n greedy: boolean;\n },\n ): Promise<number[]> {\n const seq: number[] = [...prompt];\n const generated: number[] = [];\n let logits = prefillLogits;\n\n for (let step = 0; step < p.maxNewTokens; step++) {\n // OuteTTS does NOT decode in a rigid c1/c2 window: after the cued\n // <|word_start|>, the backbone emits a full word block\n // (word-text <|features|> <|t_..|> energy/spectral/pitch <|code|> c1 c2 … <|word_end|>)\n // per word, then <|audio_end|>. So the loop samples over the FULL vocab (greedy\n // argmax, or temp/top-k/top-p with repetition penalty) and lets the model produce\n // its native structure; audioTokensToDacCodes() filters the c1/c2 codes out of the\n // stream. (Constraining to the codebook window — the foundation's bug — starved the\n // model of its structural tokens and produced incoherent audio.)\n const next = p.greedy\n ? argmax(logits)\n : this.sampleToken(logits, {\n temperature: p.temperature,\n topP: p.topP,\n topK: p.topK,\n repetitionPenalty: p.repetitionPenalty,\n previous: seq.slice(-p.repetitionRange),\n });\n\n if (next === OUTETTS_AUDIO_END || next === OUTETTS_IM_END) {\n break;\n }\n generated.push(next);\n seq.push(next);\n\n if (seq.length >= this.maxSeqLen) {\n break;\n }\n const res = await this.backboneExec.forward(new Uint32Array([next]));\n logits = res.logits;\n }\n return generated;\n }\n\n /**\n * Sample one token over the FULL vocab: repetition penalty over the recent window,\n * then temperature → top-k → top-p nucleus. (OuteTTS emits structural word-block\n * tokens interleaved with audio codes, so the sampler must not be window-restricted.)\n */\n private sampleToken(\n logits: Float32Array,\n p: {\n temperature: number;\n topP: number;\n topK: number;\n repetitionPenalty: number;\n previous: number[];\n },\n ): number {\n const n = logits.length;\n const prev = p.repetitionPenalty !== 1.0 ? new Set(p.previous) : null;\n\n // Fast path (the common case — the SDK/site default is topK=40): shortlist the\n // top-k candidates in one O(n·logk) pass instead of two full-vocab sorts, then\n // softmax + nucleus over just those k. Distribution-identical to the old path.\n if (p.topK > 0 && p.topK < n) {\n const { ids: kIds, vals: kVals } = selectTopKPenalized(\n logits,\n p.topK,\n prev,\n p.repetitionPenalty,\n );\n const scores = new Float32Array(kVals.length);\n for (let i = 0; i < kVals.length; i++) {\n scores[i] = kVals[i] / p.temperature;\n }\n softmaxInPlace(scores);\n return nucleusSample(scores, Int32Array.from(kIds), p.topP);\n }\n\n // Fallback (top-k disabled): full-vocab temperature → softmax → nucleus.\n const ids = new Int32Array(n);\n const scores = new Float32Array(n);\n for (let i = 0; i < n; i++) {\n ids[i] = i;\n let s = logits[i];\n if (prev?.has(i)) {\n s = s > 0 ? s / p.repetitionPenalty : s * p.repetitionPenalty;\n }\n scores[i] = s / p.temperature;\n }\n softmaxInPlace(scores);\n return nucleusSample(scores, ids, p.topP);\n }\n\n /**\n * Decode the [2, T] DAC code grid (codebook-major) → PCM, applying the final tanh.\n * The DAC decoder is non-causal (symmetric padding) and its odd rate-5 transpose\n * makes interior windows position-dependent, so the whole clip is decoded in ONE\n * pass (no chunking). The codec conv/Snake/Add kernels use 2D dispatch (the\n * dispatch2D helper) so even multi-second clips stay under WebGPU's 65535 per-dim\n * workgroup cap.\n */\n private async decodeCodes(codes: Uint32Array, numFrames: number): Promise<Float32Array> {\n const graph = generateDacSpeechDecoderGraph({ numFrames });\n const pcmLen = dacOutputLength(numFrames);\n const exec = new Executor(this.ctx, graph, { maxSeqLen: numFrames, kvMode: \"f32\" });\n try {\n exec.uploadWeightsMap(selectGraphWeights(graph, this.loaded.codecWeights));\n exec.initBindGroups();\n exec.reset();\n exec.writeInput(\"audio_codes\", codes);\n const raw = await exec.runGraphOutput(graph.outputs[0], pcmLen);\n const pcm = new Float32Array(raw.length);\n for (let i = 0; i < raw.length; i++) {\n pcm[i] = Math.tanh(raw[i]);\n }\n return pcm;\n } finally {\n exec.destroy();\n }\n }\n\n destroy(): void {\n if (this._destroyed) {\n return;\n }\n this._destroyed = true;\n this.backboneExec.destroy();\n this.loaded.backboneWeights.clear();\n this.loaded.codecWeights.clear();\n }\n}\n","/**\n * ParlerTTS — native describe-your-voice text-to-speech for Gerbil's WebGPU backend.\n *\n * Parler-TTS (parler-tts/parler-tts-mini-v1) is an encoder-decoder codec-LM: you\n * describe the voice in natural language and a Flan-T5 encoder turns that DESCRIPTION\n * into cross-attention states, while a 24-layer decoder LM cross-attends to them and\n * autoregressively emits DAC audio codes for the TRANSCRIPT. Same dual-graph shape as\n * MoonshineSTT (encoder once → frozen cross-attn K/V → AR decode), and the same DAC\n * codec family as OuteTTS (the shared generateDacSpeechDecoderGraph, here with 9\n * codebooks + rates [8,8,4,2]).\n *\n * Pipeline (engine.speak(text, { describeVoice })):\n * 1. Tokenize the DESCRIPTION with the T5 tokenizer; build the relative-position\n * bias; run the T5 encoder once → encoder_out + per-decoder-layer frozen K/V.\n * 2. Tokenize the TRANSCRIPT (embed_prompts); prefill its embeddings (+ sinusoidal\n * positions) through the decoder so the self-attn KV-cache holds the prompt.\n * 3. AR-decode 9 interleaved codebooks under the delay pattern: each step the host\n * sums the 9 per-codebook embeddings of the current (delayed) codes + the\n * sinusoidal position, forwards one step, and samples each of the 9 lm_head logit\n * rows. Stop on EOS in codebook 0 (or the frame cap).\n * 4. Revert the delay pattern → [9, frames] code grid → shared DAC decode → 44.1 kHz\n * PCM (tanh applied host-side).\n *\n * STATUS — WIRED + RUNS END-TO-END. Typechecks + builds, and the full pipeline runs\n * on Dawn (node): parler-tts/parler-tts-mini-v1 loads, the T5 encoder runs, the prompt\n * prefills, the 9-codebook delay-pattern AR loop decodes, and the shared DAC decoder\n * produces finite, non-silent, in-range 44.1 kHz PCM (verified via\n * scripts/engine/test-parler-speak.mjs). Reached from the high-level engine through\n * `g.speak(text, { model: DEFAULT_MODELS.ttsParler, describeVoice })`, which routes\n * Parler repos here directly (bypassing the single-graph text loader, the same way\n * MoonshineSTT is reached for STT). A bit-exact reference diff vs transformers\n * ParlerTTSForConditionalGeneration (T5 encoder cosine + a decoder forward; see\n * scripts/engine/parler-*-ref.py stubs) remains as a follow-up for numerical parity.\n * The architecture, weight layout, tokenization, delay pattern, and DAC config are all\n * verified against the live config.json + safetensors header.\n */\n\nimport { dacOutputLength, generateDacSpeechDecoderGraph } from \"./architectures/outetts.js\";\nimport {\n buildT5RelativeBias,\n generateParlerDecoderGraph,\n generateParlerEncoderGraph,\n PARLER_BOS_TOKEN_ID,\n PARLER_DAC_DECODER_DIM,\n PARLER_DAC_LATENT_DIM,\n PARLER_DECODER_RATES,\n PARLER_EOS_TOKEN_ID,\n PARLER_SAMPLE_RATE,\n parseParlerConfig,\n revertDelayPattern,\n} from \"./architectures/parler.js\";\nimport {\n createBindGroup,\n createStorageBuffer,\n createUniformBuffer,\n destroyBuffers,\n type GPUContext,\n getOrCreatePipeline,\n initGPU,\n} from \"./device.js\";\nimport { Executor } from \"./executor.js\";\nimport { DTYPE_BYTES, type ModelGraph, type OpNode } from \"./ir.js\";\nimport { KERNEL_REGISTRY, type KernelSpec } from \"./kernels/registry.js\";\nimport { type LoadedParlerTTS, loadParlerTTS } from \"./model-loader.js\";\n\nconst MAP_MODE_READ = 0x0001;\n/** Default voice description when the caller doesn't supply one. */\nconst DEFAULT_VOICE_DESCRIPTION =\n \"A clear, neutral voice speaking at a moderate pace with good audio quality.\";\n/** Hard cap on decoded audio frames (~86 fps → ~30 s at 2600). */\nconst DEFAULT_MAX_FRAMES = 2600;\n\nexport interface ParlerTTSOptions {\n /** Repo (default parler-tts/parler-tts-mini-v1). */\n repo?: string;\n revision?: string;\n hfToken?: string;\n cacheDir?: string;\n maxSeqLen?: number;\n onProgress?: (loaded: number, total: number, message: string) => void;\n}\n\nexport interface ParlerSpeakOptions {\n /** Natural-language voice description (the Parler hook). */\n describeVoice?: string;\n /** Sampling temperature (Parler default 1.0). */\n temperature?: number;\n /** Top-k cutoff (default 0 = off; Parler uses sampling with do_sample=True). */\n topK?: number;\n /** Greedy (argmax per codebook) for deterministic reference validation. */\n greedy?: boolean;\n /** Override the max decoded frames. */\n maxFrames?: number;\n /**\n * Debug hook: receives the reverted [numCodebooks, frames] code grid (codebook-major)\n * just before DAC decode. Used by the reference token-match test; no production effect.\n */\n onCodes?: (codes: Uint32Array, numCodebooks: number, frames: number) => void;\n}\n\nexport interface ParlerSpeakResult {\n /** Mono PCM in [-1, 1]. */\n pcm: Float32Array;\n /** Sample rate (44100). */\n sampleRate: number;\n /** Number of acoustic frames decoded. */\n frames: number;\n /** Audio duration in seconds. */\n audioSeconds: number;\n}\n\n/** Build a fresh map of just the constant weights a graph references. */\nfunction selectGraphWeights(\n graph: { tensors: Record<string, { storage: string; safetensorsKey?: string }> },\n weights: Map<string, { data: ArrayBufferView; shape: number[] }>,\n): Map<string, { data: ArrayBufferView; shape: number[] }> {\n const out = new Map<string, { data: ArrayBufferView; shape: number[] }>();\n for (const [name, desc] of Object.entries(graph.tensors)) {\n if (desc.storage !== \"constant\") {\n continue;\n }\n const w =\n weights.get(name) ?? (desc.safetensorsKey ? weights.get(desc.safetensorsKey) : undefined);\n if (w) {\n out.set(name, w);\n }\n }\n return out;\n}\n\n/** Argmax over a logit row. */\nfunction argmax(logits: Float32Array): number {\n let best = 0;\n let bestV = logits[0];\n for (let i = 1; i < logits.length; i++) {\n if (logits[i] > bestV) {\n bestV = logits[i];\n best = i;\n }\n }\n return best;\n}\n\n/** Temperature + optional top-k sample over a logit row. */\nfunction sampleLogits(logits: Float32Array, temperature: number, topK: number): number {\n const n = logits.length;\n const scaled = new Float32Array(n);\n let maxV = Number.NEGATIVE_INFINITY;\n const invT = 1 / Math.max(temperature, 1e-5);\n for (let i = 0; i < n; i++) {\n scaled[i] = logits[i] * invT;\n if (scaled[i] > maxV) {\n maxV = scaled[i];\n }\n }\n // top-k mask (keep indices of the k largest).\n let allowed: Int32Array | null = null;\n if (topK > 0 && topK < n) {\n const order = Array.from({ length: n }, (_, i) => i).sort((a, b) => scaled[b] - scaled[a]);\n allowed = new Int32Array(order.slice(0, topK));\n }\n let sum = 0;\n const probs = new Float32Array(n);\n if (allowed) {\n for (const idx of allowed) {\n const e = Math.exp(scaled[idx] - maxV);\n probs[idx] = e;\n sum += e;\n }\n } else {\n for (let i = 0; i < n; i++) {\n const e = Math.exp(scaled[i] - maxV);\n probs[i] = e;\n sum += e;\n }\n }\n let pick = Math.random() * sum;\n if (allowed) {\n for (const idx of allowed) {\n pick -= probs[idx];\n if (pick <= 0) {\n return idx;\n }\n }\n return allowed[0];\n }\n for (let i = 0; i < n; i++) {\n pick -= probs[i];\n if (pick <= 0) {\n return i;\n }\n }\n return n - 1;\n}\n\n// ════════════════════════════════════════════════════════════════════════════\n// Encoder executor — runs the T5 encoder graph once and reads back encoder_out +\n// the per-decoder-layer frozen cross-attn K/V (modeled on MoonshineEncoderExecutor).\n// ════════════════════════════════════════════════════════════════════════════\n\ninterface EncDispatch {\n node: OpNode;\n spec: KernelSpec;\n pipeline: GPUComputePipeline;\n bindGroup: GPUBindGroup;\n uniformBuffer: GPUBuffer;\n}\n\nclass ParlerEncoderExecutor {\n private ctx: GPUContext;\n private graph: ModelGraph;\n private decLayers: number;\n private hidden: number;\n private sDesc: number;\n private weightBuffers = new Map<string, GPUBuffer>();\n private activationBuffers = new Map<string, GPUBuffer>();\n private dispatches: EncDispatch[] = [];\n\n constructor(ctx: GPUContext, graph: ModelGraph, decLayers: number, sDesc: number) {\n this.ctx = ctx;\n this.graph = graph;\n this.decLayers = decLayers;\n this.hidden = graph.config.hidden_size;\n this.sDesc = sDesc;\n for (const [name, desc] of Object.entries(graph.tensors)) {\n if (desc.storage !== \"activation\") {\n continue;\n }\n // Resolve symbolic dims (e.g. input_ids' \"T\") to the concrete description length.\n const count = desc.shape.reduce(\n (a: number, dim) => a * (typeof dim === \"number\" ? dim : sDesc),\n 1,\n );\n this.activationBuffers.set(\n name,\n createStorageBuffer(this.ctx, `penc_${name}`, count * DTYPE_BYTES[desc.dtype]),\n );\n }\n }\n\n uploadWeights(weights: Map<string, { data: ArrayBufferView; shape: number[] }>): void {\n for (const [name, desc] of Object.entries(this.graph.tensors)) {\n if (desc.storage !== \"constant\") {\n continue;\n }\n const w = weights.get(name);\n if (!w) {\n throw new Error(`ParlerEncoderExecutor: missing weight \"${name}\"`);\n }\n this.weightBuffers.set(\n name,\n createStorageBuffer(this.ctx, `pencw_${name}`, w.data.byteLength, w.data),\n );\n }\n }\n\n initBindGroups(): void {\n const shapes = this.resolveShapes();\n for (const nodeId of this.graph.executionOrder) {\n const node = this.graph.nodes.find((n) => n.id === nodeId)!;\n const spec = KERNEL_REGISTRY[node.opType];\n if (!spec) {\n throw new Error(`ParlerEncoderExecutor: no kernel for op \"${node.opType}\"`);\n }\n const pipeline = getOrCreatePipeline(\n this.ctx,\n `penck_${nodeId}`,\n spec.shaderCode,\n spec.entryPoint,\n );\n const paramsData = spec.buildParams(node, shapes, { seqPos: 0 });\n const uniformBuffer = createUniformBuffer(this.ctx, `pencu_${nodeId}`, paramsData);\n const bufferEntries = this.gatherBuffers(spec, node, uniformBuffer);\n const bindGroup = createBindGroup(this.ctx, pipeline, bufferEntries, `pencbg_${nodeId}`);\n this.dispatches.push({ node, spec, pipeline, bindGroup, uniformBuffer });\n }\n }\n\n /** Run the encoder. `inputIds` u32 [S], `relBias` f32 [heads,S,S]. */\n async encode(\n inputIds: Uint32Array,\n relBias: Float32Array,\n ): Promise<{ encK: Float32Array[]; encV: Float32Array[] }> {\n const q = this.ctx.device.queue;\n const inputBuf = this.activationBuffers.get(\"input_ids\");\n const biasBuf = this.activationBuffers.get(\"t5_rel_bias\");\n if (!(inputBuf && biasBuf)) {\n throw new Error(\"ParlerEncoderExecutor: input_ids / t5_rel_bias buffers missing.\");\n }\n q.writeBuffer(inputBuf, 0, inputIds as BufferSource);\n q.writeBuffer(biasBuf, 0, relBias as BufferSource);\n\n const shapes = this.resolveShapes();\n const sizes: Array<[number, number, number]> = [];\n for (const d of this.dispatches) {\n const params = d.spec.buildParams(d.node, shapes, { seqPos: 0 });\n q.writeBuffer(d.uniformBuffer, 0, params);\n sizes.push(d.spec.getDispatchSize(d.node, shapes, { seqPos: 0 }));\n }\n\n if (this.ctx.isWebKitWebGPU) {\n for (let i = 0; i < this.dispatches.length; i++) {\n const enc = this.ctx.device.createCommandEncoder();\n const p = enc.beginComputePass();\n p.setPipeline(this.dispatches[i].pipeline);\n p.setBindGroup(0, this.dispatches[i].bindGroup);\n p.dispatchWorkgroups(...sizes[i]);\n p.end();\n q.submit([enc.finish()]);\n await q.onSubmittedWorkDone();\n }\n } else {\n const enc = this.ctx.device.createCommandEncoder({ label: \"parler_encode\" });\n const pass = enc.beginComputePass({ label: \"parler_enc_pass\" });\n for (let i = 0; i < this.dispatches.length; i++) {\n pass.setPipeline(this.dispatches[i].pipeline);\n pass.setBindGroup(0, this.dispatches[i].bindGroup);\n pass.dispatchWorkgroups(...sizes[i]);\n }\n pass.end();\n q.submit([enc.finish()]);\n }\n\n const encK: Float32Array[] = [];\n const encV: Float32Array[] = [];\n for (let i = 0; i < this.decLayers; i++) {\n encK.push(await this.readBack(`enc_k_layer${i}`, this.sDesc * this.hidden));\n encV.push(await this.readBack(`enc_v_layer${i}`, this.sDesc * this.hidden));\n }\n return { encK, encV };\n }\n\n destroy(): void {\n destroyBuffers([...this.weightBuffers.values()]);\n destroyBuffers([...this.activationBuffers.values()]);\n for (const d of this.dispatches) {\n d.uniformBuffer.destroy();\n }\n this.weightBuffers.clear();\n this.activationBuffers.clear();\n this.dispatches = [];\n }\n\n private resolveShapes(): Record<string, number[]> {\n const resolved: Record<string, number[]> = {};\n for (const [name, desc] of Object.entries(this.graph.tensors)) {\n resolved[name] = desc.shape.map((dim) => (typeof dim === \"number\" ? dim : this.sDesc));\n }\n return resolved;\n }\n\n private gatherBuffers(\n spec: KernelSpec,\n node: OpNode,\n uniformBuffer: GPUBuffer,\n ): Array<{ buffer: GPUBuffer }> {\n const entries: Array<{ buffer: GPUBuffer }> = [];\n const tensorNames = [...node.inputs, ...node.outputs];\n let tensorIdx = 0;\n for (const binding of spec.bindings) {\n if (binding.type === \"uniform\") {\n entries.push({ buffer: uniformBuffer });\n } else {\n const tensorName = tensorNames[tensorIdx++];\n const buffer = this.weightBuffers.get(tensorName) ?? this.activationBuffers.get(tensorName);\n if (!buffer) {\n throw new Error(`ParlerEncoderExecutor: no buffer for \"${tensorName}\" in op ${node.id}`);\n }\n entries.push({ buffer });\n }\n }\n return entries;\n }\n\n private async readBack(name: string, elements: number): Promise<Float32Array> {\n const buffer = this.activationBuffers.get(name);\n if (!buffer) {\n throw new Error(`ParlerEncoderExecutor: no buffer \"${name}\"`);\n }\n const byteLen = Math.min(elements * 4, buffer.size);\n const readback = this.ctx.device.createBuffer({ size: byteLen, usage: 0x0001 | 0x0008 });\n const enc = this.ctx.device.createCommandEncoder();\n enc.copyBufferToBuffer(buffer, 0, readback, 0, byteLen);\n this.ctx.device.queue.submit([enc.finish()]);\n await readback.mapAsync(MAP_MODE_READ, 0, byteLen);\n const data = new Float32Array(readback.getMappedRange(0, byteLen).slice(0));\n readback.unmap();\n readback.destroy();\n return data;\n }\n}\n\n// ════════════════════════════════════════════════════════════════════════════\n// ParlerTTS engine\n// ════════════════════════════════════════════════════════════════════════════\n\nexport class ParlerTTS {\n private ctx: GPUContext;\n private loaded: LoadedParlerTTS;\n private cfg: ReturnType<typeof parseParlerConfig>;\n private maxSeqLen: number;\n private _destroyed = false;\n\n readonly sampleRate = PARLER_SAMPLE_RATE;\n\n private constructor(ctx: GPUContext, loaded: LoadedParlerTTS, maxSeqLen: number) {\n this.ctx = ctx;\n this.loaded = loaded;\n this.cfg = parseParlerConfig(loaded.rawConfig);\n this.maxSeqLen = maxSeqLen;\n }\n\n static async create(options: ParlerTTSOptions = {}): Promise<ParlerTTS> {\n const ctx = await initGPU();\n const loaded = await loadParlerTTS({\n repo: options.repo,\n revision: options.revision,\n hfToken: options.hfToken,\n cacheDir: options.cacheDir,\n onProgress: options.onProgress,\n });\n const cfg = parseParlerConfig(loaded.rawConfig);\n const maxSeqLen = Math.min(options.maxSeqLen ?? 4096, cfg.max_position);\n return new ParlerTTS(ctx, loaded, maxSeqLen);\n }\n\n /**\n * Generate a random natural-language voice description using a host-side template\n * bank (no model call). Pass the result as `describeVoice` for variety. A loaded\n * text model can write richer ones — exposed on the Gerbil class as\n * {@link inventVoiceDescription}.\n */\n static randomVoiceDescription(): string {\n const gender = pick([\"male\", \"female\"]);\n const tone = pick([\"warm\", \"bright\", \"calm\", \"energetic\", \"gentle\", \"confident\", \"soft\"]);\n const pace = pick([\"slightly slow\", \"moderate\", \"slightly fast\"]);\n const quality = pick([\n \"very clear, studio-quality recording\",\n \"clean recording with minimal background noise\",\n \"close-sounding, high-quality audio\",\n ]);\n return `A ${tone} ${gender} voice speaking at a ${pace} pace, in a ${quality}.`;\n }\n\n /** Synthesize `text` in the described voice. Returns 44.1 kHz mono PCM. */\n async speak(text: string, opts: ParlerSpeakOptions = {}): Promise<ParlerSpeakResult> {\n if (this._destroyed) {\n throw new Error(\"ParlerTTS has been destroyed.\");\n }\n const startTime = performance.now();\n const description = (opts.describeVoice ?? DEFAULT_VOICE_DESCRIPTION).trim();\n\n // ── 1. Encoder: tokenize description, build rel bias, run once. ──\n const descIds = this.loaded.tokenizer.encode(description);\n const sDesc = descIds.length;\n const biasTable = this.loaded.modelWeights.get(\n \"text_encoder.encoder.block.0.layer.0.SelfAttention.relative_attention_bias.weight\",\n );\n if (!biasTable) {\n throw new Error(\"ParlerTTS: relative_attention_bias.weight missing from checkpoint.\");\n }\n const relBias = buildT5RelativeBias(\n biasTable.data as Float32Array,\n this.cfg.rel_num_buckets,\n this.cfg.rel_max_distance,\n this.cfg.enc_heads,\n sDesc,\n );\n\n const encGraph = generateParlerEncoderGraph(this.loaded.rawConfig, sDesc);\n const encExec = new ParlerEncoderExecutor(this.ctx, encGraph, this.cfg.dec_layers, sDesc);\n let encK: Float32Array[];\n let encV: Float32Array[];\n try {\n encExec.uploadWeights(selectGraphWeights(encGraph, this.loaded.modelWeights));\n encExec.initBindGroups();\n const enc = await encExec.encode(new Uint32Array(descIds), relBias);\n encK = enc.encK;\n encV = enc.encV;\n } finally {\n encExec.destroy();\n }\n\n // ── 2/3. Decoder: prompt prefill + AR delay-pattern decode. ──\n const promptIds = this.loaded.tokenizer.encode(text);\n const delayed = await this.decodeAudioTokens(promptIds, encK, encV, sDesc, opts);\n\n // ── 4. Revert the delay pattern → [9, frames] → DAC decode. ──\n const { codes, frames } = revertDelayPattern(\n delayed.codes,\n this.cfg.num_codebooks,\n delayed.steps,\n );\n if (frames <= 0) {\n throw new Error(`ParlerTTS produced no audio frames (steps=${delayed.steps}).`);\n }\n opts.onCodes?.(codes, this.cfg.num_codebooks, frames);\n const pcm = await this.decodeCodes(codes, frames);\n\n const totalTime = (performance.now() - startTime) / 1000;\n const audioSeconds = pcm.length / PARLER_SAMPLE_RATE;\n console.log(\n `[parler] desc=${sDesc} frames=${frames} audio=${audioSeconds.toFixed(2)}s wall=${totalTime.toFixed(2)}s`,\n );\n return { pcm, sampleRate: PARLER_SAMPLE_RATE, frames, audioSeconds };\n }\n\n /**\n * Run the decoder: prefill the transcript prompt rows, then AR-decode the 9-codebook\n * delay-pattern stream. Returns the DELAYED code grid [9, steps] (codebook-major)\n * plus the step count, for revertDelayPattern.\n *\n * Each step the host sums the 9 per-codebook embeddings of the current delayed codes\n * + the sinusoidal position, writes that single [1,H] row to `dec_input_embed`,\n * forwards one step (KV-cache grows over [prompt ++ audio]), and reads back 9 logit\n * rows — one per codebook lm_head.\n */\n private async decodeAudioTokens(\n promptIds: number[],\n encK: Float32Array[],\n encV: Float32Array[],\n sEnc: number,\n opts: ParlerSpeakOptions,\n ): Promise<{ codes: Uint32Array; steps: number }> {\n const cfg = this.cfg;\n const H = cfg.dec_hidden;\n const NCB = cfg.num_codebooks;\n const graph = generateParlerDecoderGraph(this.loaded.rawConfig, sEnc);\n const maxFrames = Math.min(\n opts.maxFrames ?? DEFAULT_MAX_FRAMES,\n this.maxSeqLen - promptIds.length,\n );\n const maxSteps = maxFrames + (NCB - 1);\n const exec = new Executor(this.ctx, graph, {\n maxSeqLen: this.maxSeqLen,\n kvMode: \"f32\",\n });\n\n // Host-side embedding tables.\n const embedTokens: Float32Array[] = [];\n for (let cb = 0; cb < NCB; cb++) {\n const t = this.loaded.modelWeights.get(`decoder.model.decoder.embed_tokens.${cb}.weight`);\n if (!t) {\n throw new Error(`ParlerTTS: embed_tokens.${cb} missing.`);\n }\n embedTokens.push(t.data as Float32Array);\n }\n const embedPositions = this.loaded.modelWeights.get(\n \"decoder.model.decoder.embed_positions.weights\",\n );\n const embedPrompts = this.loaded.modelWeights.get(\"embed_prompts.weight\");\n if (!(embedPositions && embedPrompts)) {\n throw new Error(\"ParlerTTS: embed_positions / embed_prompts missing.\");\n }\n const posTable = embedPositions.data as Float32Array;\n const promptTable = embedPrompts.data as Float32Array;\n\n const grid = new Uint32Array(NCB * maxSteps); // codebook-major delayed codes\n let steps = 0;\n try {\n exec.uploadWeightsMap(selectGraphWeights(graph, this.loaded.modelWeights));\n exec.initBindGroups();\n for (let i = 0; i < cfg.dec_layers; i++) {\n exec.writeInput(`enc_k_layer${i}`, encK[i]);\n exec.writeInput(`enc_v_layer${i}`, encV[i]);\n }\n exec.reset();\n\n let pos = 0;\n const row = new Float32Array(H);\n const logitOutputs = graph.outputs.map((name) => ({ name, elemCount: cfg.audio_vocab }));\n\n // ── Prompt prefill: feed each transcript-token embedding (+ position) one row at\n // a time so the self-attn KV-cache fills with the prompt span (positions\n // 0..promptLen-1) before audio decode. (One row per step keeps the T=1 graph;\n // runGraphStep advances seqPos per call.) ──\n for (const tokenId of promptIds) {\n addRow(row, promptTable, tokenId, H, true);\n addPosition(row, posTable, pos, H);\n exec.writeInput(\"dec_input_embed\", row);\n await exec.runGraphStep([logitOutputs[0]], 1);\n pos++;\n }\n\n // ── AR audio decode with delay pattern. ──\n // Codebook cb is \"active\" only once step >= cb; before that it stays at the bos\n // fill so its stream is delayed by cb frames. Step 0 is seeded with bos across all\n // codebooks (decoder_start_token_id).\n //\n // EOS propagation mirrors ParlerTTSLogitsProcessor: when the first not-yet-finished\n // codebook emits EOS, the \"frontier\" advances one codebook; every codebook strictly\n // beyond the frontier is forbidden from emitting EOS (its EOS logit is masked to\n // -inf before argmax/sampling). Once the frontier reaches the last codebook and it\n // emits EOS, all codebooks are finished and we stop. This decodes exactly the\n // (NCB-1)-step delay tail the reference completes after codebook 0's EOS, so the\n // de-delayed grid trims cleanly instead of trailing post-EOS junk.\n let prevCodes = new Uint32Array(NCB).fill(PARLER_BOS_TOKEN_ID);\n let frontier = 0; // index of the first codebook not yet finished (allowed to EOS).\n let finished = false;\n for (let step = 0; step < maxSteps && !finished; step++) {\n // Sum the 9 per-codebook embeddings of the current step's input codes.\n row.fill(0);\n for (let cb = 0; cb < NCB; cb++) {\n addRow(row, embedTokens[cb], prevCodes[cb], H, false);\n }\n addPosition(row, posTable, pos, H);\n exec.writeInput(\"dec_input_embed\", row);\n const logitRows = await exec.runGraphStep(logitOutputs, 1);\n pos++;\n\n const nextCodes = new Uint32Array(NCB);\n for (let cb = 0; cb < NCB; cb++) {\n if (step < cb) {\n nextCodes[cb] = PARLER_BOS_TOKEN_ID;\n continue;\n }\n // Forbid EOS for codebooks beyond the frontier (delay-pattern constraint).\n if (cb > frontier) {\n logitRows[cb][PARLER_EOS_TOKEN_ID] = Number.NEGATIVE_INFINITY;\n }\n const code = opts.greedy\n ? argmax(logitRows[cb])\n : sampleLogits(logitRows[cb], opts.temperature ?? 1.0, opts.topK ?? 0);\n nextCodes[cb] = code;\n grid[cb * maxSteps + step] = code < PARLER_CODEBOOK_SIZE ? code : 0;\n }\n\n // Advance the frontier if the current first-unfinished codebook emitted EOS.\n if (frontier < NCB - 1 && nextCodes[frontier] === PARLER_EOS_TOKEN_ID) {\n frontier++;\n } else if (frontier === NCB - 1 && nextCodes[frontier] === PARLER_EOS_TOKEN_ID) {\n finished = true;\n }\n\n steps = step + 1;\n prevCodes = nextCodes;\n if (pos >= this.maxSeqLen) {\n break;\n }\n }\n } finally {\n exec.destroy();\n }\n\n // Re-pack the [NCB, maxSteps] grid to a tight [NCB, steps] codebook-major grid; the\n // delay pattern is reverted by the caller (revertDelayPattern reads with stride steps).\n const tight = new Uint32Array(NCB * steps);\n for (let cb = 0; cb < NCB; cb++) {\n for (let s = 0; s < steps; s++) {\n tight[cb * steps + s] = grid[cb * maxSteps + s];\n }\n }\n return { codes: tight, steps };\n }\n\n /** Decode the [9, frames] code grid → 44.1 kHz PCM (tanh host-side). */\n private async decodeCodes(codes: Uint32Array, numFrames: number): Promise<Float32Array> {\n const graph = generateDacSpeechDecoderGraph({\n numFrames,\n numCodebooks: this.cfg.num_codebooks,\n decoderRates: PARLER_DECODER_RATES,\n decoderDim: PARLER_DAC_DECODER_DIM,\n latentDim: PARLER_DAC_LATENT_DIM,\n });\n const pcmLen = dacOutputLength(numFrames, PARLER_DECODER_RATES);\n const exec = new Executor(this.ctx, graph, { maxSeqLen: numFrames, kvMode: \"f32\" });\n try {\n exec.uploadWeightsMap(selectGraphWeights(graph, this.loaded.codecWeights));\n exec.initBindGroups();\n exec.reset();\n exec.writeInput(\"audio_codes\", codes);\n const raw = await exec.runGraphOutput(graph.outputs[0], pcmLen);\n const pcm = new Float32Array(raw.length);\n for (let i = 0; i < raw.length; i++) {\n pcm[i] = Math.tanh(raw[i]);\n }\n return pcm;\n } finally {\n exec.destroy();\n }\n }\n\n destroy(): void {\n if (this._destroyed) {\n return;\n }\n this._destroyed = true;\n this.loaded.modelWeights.clear();\n this.loaded.codecWeights.clear();\n }\n}\n\nconst PARLER_CODEBOOK_SIZE = 1024;\n\n/** Random pick from a list. */\nfunction pick<T>(arr: readonly T[]): T {\n return arr[Math.floor(Math.random() * arr.length)];\n}\n\n/** Add (or set) the embedding row for `tokenId` into `row`. */\nfunction addRow(\n row: Float32Array,\n table: Float32Array,\n tokenId: number,\n H: number,\n set: boolean,\n): void {\n const base = tokenId * H;\n if (set) {\n for (let i = 0; i < H; i++) {\n row[i] = table[base + i];\n }\n } else {\n for (let i = 0; i < H; i++) {\n row[i] += table[base + i];\n }\n }\n}\n\n/** Add the sinusoidal position row (from the learned embed_positions table). */\nfunction addPosition(row: Float32Array, posTable: Float32Array, pos: number, H: number): void {\n const base = pos * H;\n for (let i = 0; i < H; i++) {\n row[i] += posTable[base + i];\n }\n}\n","/**\n * VisionExecutor — runs the Qwen3.5 ViT graph on WebGPU.\n *\n * Kept separate from the text `Executor` (which is specialized for\n * input_ids / logits / argmax / KV-cache decode). The vision tower is a single\n * non-autoregressive prefill over `N` patches, so this executor is deliberately\n * simple: one buffer per tensor, dispatch in executionOrder, read back the\n * merged image embeddings. It reuses the shared kernel registry and device\n * helpers, so kernel math is identical to the text path.\n *\n * Symbolic dims:\n * \"N\" → number of patches (runtime)\n * \"Nm\" → N / spatial_merge_unit (merged token count)\n */\n\nimport type { GPUContext } from \"./device.js\";\nimport {\n createBindGroup,\n createStorageBuffer,\n createUniformBuffer,\n destroyBuffers,\n getOrCreatePipeline,\n} from \"./device.js\";\nimport { CANONICAL_KEYS, DTYPE_BYTES, type ModelGraph, type OpNode } from \"./ir.js\";\nimport { KERNEL_REGISTRY, type KernelSpec, MATMUL_BIAS_F16C_SPEC } from \"./kernels/registry.js\";\n\nconst MAP_MODE_READ = 0x0001;\n\n/** Pack an f32 array to IEEE half (f16) bits (round-to-nearest-even). */\nconst _f16scratch = new ArrayBuffer(4);\nconst _f16f32 = new Float32Array(_f16scratch);\nconst _f16u32 = new Uint32Array(_f16scratch);\nfunction packF16(src: Float32Array): Uint16Array {\n const out = new Uint16Array(src.length);\n for (let i = 0; i < src.length; i++) {\n _f16f32[0] = src[i];\n const f = _f16u32[0];\n const sign = (f >>> 16) & 0x8000;\n const exp = ((f >>> 23) & 0xff) - 112; // 127 - 15\n const mant = f & 0x7fffff;\n if (exp <= 0) {\n out[i] = sign;\n } else if (exp >= 0x1f) {\n out[i] = sign | 0x7c00;\n } else {\n const round = (mant & 0x1000) !== 0;\n let half = sign | (exp << 10) | (mant >>> 13);\n if (round) half += 1;\n out[i] = half;\n }\n }\n return out;\n}\n\ninterface VisionDispatch {\n node: OpNode;\n spec: KernelSpec;\n pipeline: GPUComputePipeline;\n bindGroup: GPUBindGroup;\n uniformBuffer: GPUBuffer;\n}\n\nexport interface VisionInputs {\n /** Flattened patches [N, patch_dim]. */\n patches: Float32Array;\n /** Bilinear-interpolated learned pos embeddings [N, hidden_size]. */\n posEmbeds: Float32Array;\n /** Precomputed rotary cos [N, head_dim]. */\n cos: Float32Array;\n /** Precomputed rotary sin [N, head_dim]. */\n sin: Float32Array;\n /** Number of patches (rows). */\n numPatches: number;\n}\n\n/**\n * Coarse stage callback for the ViT encode. Fires before each transformer layer\n * (and the pre/post stages) so a host harness can localize a mobile GPU-process\n * crash to a specific layer instead of seeing only \"crashed after load\". Kept\n * synchronous and cheap; throwing is the caller's responsibility.\n */\nexport type VisionStageCallback = (\n stage: string,\n info?: { layer?: number; total?: number },\n) => void;\n\n/**\n * WebKit only: the ViT bidirectional Attention op is a single dispatch whose\n * grid is [N query rows, heads], each row looping over all N keys — O(N²) work in\n * one submission. Past a few hundred rows that can exceed Metal's ~few-second GPU\n * watchdog and kill the web-content process (indistinguishable from OOM). We split\n * the attention grid into windows of this many query rows, each its own\n * submit + onSubmittedWorkDone() drain, so no single submission runs long enough\n * to trip the watchdog. Math is unchanged: every query row computes identically\n * regardless of how the grid is partitioned.\n */\nconst WEBKIT_ATTN_CHUNK_ROWS = 64;\n\nexport class VisionExecutor {\n private ctx: GPUContext;\n private graph: ModelGraph;\n private mergeUnit: number;\n\n private weightBuffers = new Map<string, GPUBuffer>();\n private activationBuffers = new Map<string, GPUBuffer>();\n private dispatches: VisionDispatch[] = [];\n private maxPatches: number;\n /** Weight (B) names of MatMulBias nodes stored as f16 (empty without shader-f16). */\n private f16WeightNames = new Set<string>();\n\n /** Runtime pooled-token count for the Gemma 4 ViT (\"Np\" dim); 0 for Qwen. */\n private gemma4Np = 0;\n /** True when this graph is the Gemma 4 vision tower (uses \"Np\" + PoolMatMul). */\n private readonly isGemma4: boolean;\n\n constructor(ctx: GPUContext, graph: ModelGraph, maxPatches: number) {\n this.ctx = ctx;\n this.graph = graph;\n this.maxPatches = maxPatches;\n this.isGemma4 = graph.architecture === \"Gemma4VisionModel\";\n // merge unit = merger fc1 in-width / block hidden size (3072 / 768 = 4).\n // Gemma 4 has no merger (it pools via a host matrix), so fall back to 1.\n const mergedIn = graph.tensors[CANONICAL_KEYS.visMergerFc1W]?.shape[1] as number;\n const hidden = graph.config.hidden_size;\n this.mergeUnit = mergedIn && hidden ? mergedIn / hidden : 1;\n if (ctx.hasF16) {\n for (const node of graph.nodes) {\n if (node.opType === \"MatMulBias\" && node.inputs[1]) {\n this.f16WeightNames.add(node.inputs[1]);\n }\n }\n }\n this.allocateActivationBuffers();\n }\n\n uploadWeights(weights: Map<string, { data: ArrayBufferView; shape: number[] }>): void {\n for (const [name, desc] of Object.entries(this.graph.tensors)) {\n if (desc.storage !== \"constant\") continue;\n const w = weights.get(name);\n if (!w) throw new Error(`VisionExecutor: missing weight \"${name}\"`);\n let data: ArrayBufferView = w.data;\n if (this.f16WeightNames.has(name) && w.data instanceof Float32Array) {\n data = packF16(w.data);\n }\n const buffer = createStorageBuffer(this.ctx, `vweight_${name}`, data.byteLength, data);\n this.weightBuffers.set(name, buffer);\n }\n }\n\n initBindGroups(): void {\n const dummyShapes = this.resolveShapes(this.maxPatches);\n for (const nodeId of this.graph.executionOrder) {\n const node = this.graph.nodes.find((n) => n.id === nodeId)!;\n let spec = KERNEL_REGISTRY[node.opType];\n if (!spec) throw new Error(`VisionExecutor: no kernel for op \"${node.opType}\"`);\n if (node.opType === \"MatMulBias\" && this.f16WeightNames.has(node.inputs[1])) {\n spec = MATMUL_BIAS_F16C_SPEC;\n }\n\n const pipeline = getOrCreatePipeline(\n this.ctx,\n `vkernel_${nodeId}`,\n spec.shaderCode,\n spec.entryPoint,\n );\n const paramsData = spec.buildParams(node, dummyShapes, { seqPos: 0 });\n const uniformBuffer = createUniformBuffer(this.ctx, `vuniform_${nodeId}`, paramsData);\n const bufferEntries = this.gatherBuffers(spec, node, uniformBuffer);\n const bindGroup = createBindGroup(this.ctx, pipeline, bufferEntries, `vbg_${nodeId}`);\n this.dispatches.push({ node, spec, pipeline, bindGroup, uniformBuffer });\n }\n }\n\n /**\n * Encode patches → merged image embeddings [Nm, out_hidden_size].\n *\n * `onStage` (optional) fires coarse phase breadcrumbs during the WebKit path so\n * a host can localize a GPU-process crash to a specific layer.\n */\n async encode(\n inputs: VisionInputs,\n onStage?: VisionStageCallback,\n ): Promise<{ embeds: Float32Array; rows: number; dim: number }> {\n const N = inputs.numPatches;\n if (N > this.maxPatches) {\n throw new Error(`VisionExecutor: ${N} patches exceeds maxPatches=${this.maxPatches}`);\n }\n const q = this.ctx.device.queue;\n q.writeBuffer(this.activationBuffers.get(\"vis_patches\")!, 0, inputs.patches as BufferSource);\n q.writeBuffer(\n this.activationBuffers.get(\"vis_pos_embeds\")!,\n 0,\n inputs.posEmbeds as BufferSource,\n );\n q.writeBuffer(this.activationBuffers.get(\"vis_cos\")!, 0, inputs.cos as BufferSource);\n q.writeBuffer(this.activationBuffers.get(\"vis_sin\")!, 0, inputs.sin as BufferSource);\n\n const resolvedShapes = this.resolveShapes(N);\n const ctxRt = { seqPos: 0 };\n\n // Update uniforms + dispatch sizes. Attention params build with qOffset=0 here\n // (correct for the Dawn single-pass path); the WebKit path re-writes the\n // Attention uniform per query-row chunk with a nonzero q_offset below.\n const sizes: Array<[number, number, number]> = [];\n for (const d of this.dispatches) {\n const params = d.spec.buildParams(d.node, resolvedShapes, ctxRt);\n q.writeBuffer(d.uniformBuffer, 0, params);\n sizes.push(d.spec.getDispatchSize(d.node, resolvedShapes, ctxRt));\n }\n\n const multiEncoder = this.ctx.isWebKitWebGPU;\n // V1 (GERBIL_VIT_BATCH): batch consecutive non-attention dispatches into one\n // command buffer per stretch, draining only at attention boundaries — the\n // stretches are ~14 dispatches/layer, keeping each submission watchdog-safe\n // while cutting the submit+drain count from ~366 to ~2/layer + attn chunks.\n // Command order is identical either way (single queue), so output is\n // bit-exact; the drains only cost latency. Flag-gated pending an on-device\n // watchdog verdict.\n const batchVit = (globalThis as { GERBIL_VIT_BATCH?: unknown }).GERBIL_VIT_BATCH != null;\n let batchEnc: GPUCommandEncoder | null = null;\n let batchPass: GPUComputePassEncoder | null = null;\n const flushBatch = async () => {\n if (!batchEnc || !batchPass) return;\n batchPass.end();\n q.submit([batchEnc.finish()]);\n await q.onSubmittedWorkDone();\n batchEnc = null;\n batchPass = null;\n };\n if (multiEncoder) {\n onStage?.(\"vit-encode-start\", { total: this.dispatches.length });\n for (let i = 0; i < this.dispatches.length; i++) {\n const d = this.dispatches[i];\n if (d.node.opType === \"Attention\") {\n await flushBatch();\n // Split the O(N²) attention grid into watchdog-safe query-row windows.\n // Each window: write the uniform with its q_offset, submit, drain. The\n // drain guarantees the chunk completes before the next overwrites the\n // shared uniform buffer.\n const [gridX, gridY, gridZ] = sizes[i];\n const layer = Number.parseInt(d.node.id.replace(/\\D+/g, \"\"), 10);\n if (!Number.isNaN(layer)) onStage?.(\"vit-attn\", { layer });\n for (let start = 0; start < gridX; start += WEBKIT_ATTN_CHUNK_ROWS) {\n const rows = Math.min(WEBKIT_ATTN_CHUNK_ROWS, gridX - start);\n const params = d.spec.buildParams(d.node, resolvedShapes, {\n seqPos: 0,\n qOffset: start,\n });\n q.writeBuffer(d.uniformBuffer, 0, params);\n const enc = this.ctx.device.createCommandEncoder();\n const p = enc.beginComputePass();\n p.setPipeline(d.pipeline);\n p.setBindGroup(0, d.bindGroup);\n p.dispatchWorkgroups(rows, gridY, gridZ);\n p.end();\n q.submit([enc.finish()]);\n await q.onSubmittedWorkDone();\n }\n continue;\n }\n if (batchVit) {\n if (!batchEnc) {\n batchEnc = this.ctx.device.createCommandEncoder();\n batchPass = batchEnc.beginComputePass();\n }\n batchPass!.setPipeline(d.pipeline);\n batchPass!.setBindGroup(0, d.bindGroup);\n batchPass!.dispatchWorkgroups(...sizes[i]);\n continue;\n }\n const enc = this.ctx.device.createCommandEncoder();\n const p = enc.beginComputePass();\n p.setPipeline(d.pipeline);\n p.setBindGroup(0, d.bindGroup);\n p.dispatchWorkgroups(...sizes[i]);\n p.end();\n q.submit([enc.finish()]);\n await q.onSubmittedWorkDone();\n }\n await flushBatch();\n onStage?.(\"vit-encode-done\");\n } else {\n const enc = this.ctx.device.createCommandEncoder({ label: \"vision_encode\" });\n const pass = enc.beginComputePass({ label: \"vision_pass\" });\n for (let i = 0; i < this.dispatches.length; i++) {\n pass.setPipeline(this.dispatches[i].pipeline);\n pass.setBindGroup(0, this.dispatches[i].bindGroup);\n pass.dispatchWorkgroups(...sizes[i]);\n }\n pass.end();\n q.submit([enc.finish()]);\n }\n\n // Read back the merged embeddings.\n const rows = N / this.mergeUnit;\n const dim = this.graph.config.vision_embed_dim\n ? (this.graph.tensors.vis_image_embeds.shape[1] as number)\n : (this.graph.tensors.vis_image_embeds.shape[1] as number);\n const byteLen = rows * dim * 4;\n const out = this.activationBuffers.get(\"vis_image_embeds\")!;\n const readback = this.ctx.device.createBuffer({ size: byteLen, usage: 0x0001 | 0x0008 });\n const enc = this.ctx.device.createCommandEncoder();\n enc.copyBufferToBuffer(out, 0, readback, 0, byteLen);\n this.ctx.device.queue.submit([enc.finish()]);\n await readback.mapAsync(MAP_MODE_READ, 0, byteLen);\n const embeds = new Float32Array(readback.getMappedRange(0, byteLen).slice(0));\n readback.unmap();\n readback.destroy();\n return { embeds, rows, dim };\n }\n\n /**\n * Encode patches through the Gemma 4 ViT → projected image tokens [Np, text_hidden].\n *\n * Distinct from the Qwen `encode()`: the Gemma graph has 5 inputs (patches,\n * axial pos-embeds, axial rotary cos/sin, and a host-built [Np,N] pooling matrix)\n * and its output rows (Np) are the pooled soft-token count, resolved from the\n * pooling matrix rather than an N/mergeUnit ratio. Reuses the same dispatch\n * machinery + WebKit per-dispatch-drain discipline.\n */\n async encodeGemma4(\n inputs: {\n patches: Float32Array; // [N, patch_dim]\n posEmbeds: Float32Array; // [N, hidden]\n cos: Float32Array; // [N, head_dim]\n sin: Float32Array; // [N, head_dim]\n poolMatrix: Float32Array; // [Np, N]\n numPatches: number;\n numPooled: number;\n },\n onStage?: VisionStageCallback,\n ): Promise<{ embeds: Float32Array; rows: number; dim: number }> {\n const N = inputs.numPatches;\n if (N > this.maxPatches) {\n throw new Error(`VisionExecutor(Gemma4): ${N} patches exceeds maxPatches=${this.maxPatches}`);\n }\n this.gemma4Np = inputs.numPooled;\n const q = this.ctx.device.queue;\n q.writeBuffer(this.activationBuffers.get(\"g4v_patches\")!, 0, inputs.patches as BufferSource);\n q.writeBuffer(\n this.activationBuffers.get(\"g4v_pos_embeds\")!,\n 0,\n inputs.posEmbeds as BufferSource,\n );\n q.writeBuffer(this.activationBuffers.get(\"g4v_cos\")!, 0, inputs.cos as BufferSource);\n q.writeBuffer(this.activationBuffers.get(\"g4v_sin\")!, 0, inputs.sin as BufferSource);\n q.writeBuffer(this.activationBuffers.get(\"g4v_pool_w\")!, 0, inputs.poolMatrix as BufferSource);\n\n const resolvedShapes = this.resolveShapes(N);\n const ctxRt = { seqPos: 0 };\n const sizes: Array<[number, number, number]> = [];\n for (const d of this.dispatches) {\n const params = d.spec.buildParams(d.node, resolvedShapes, ctxRt);\n q.writeBuffer(d.uniformBuffer, 0, params);\n sizes.push(d.spec.getDispatchSize(d.node, resolvedShapes, ctxRt));\n }\n\n const multiEncoder = this.ctx.isWebKitWebGPU;\n if (multiEncoder) {\n onStage?.(\"vit-encode-start\", { total: this.dispatches.length });\n for (let i = 0; i < this.dispatches.length; i++) {\n const d = this.dispatches[i];\n if (d.node.opType === \"Attention\") {\n const [gridX, gridY, gridZ] = sizes[i];\n const layer = Number.parseInt(d.node.id.replace(/\\D+/g, \"\"), 10);\n if (!Number.isNaN(layer)) onStage?.(\"vit-attn\", { layer });\n for (let start = 0; start < gridX; start += WEBKIT_ATTN_CHUNK_ROWS) {\n const rows = Math.min(WEBKIT_ATTN_CHUNK_ROWS, gridX - start);\n const params = d.spec.buildParams(d.node, resolvedShapes, {\n seqPos: 0,\n qOffset: start,\n });\n q.writeBuffer(d.uniformBuffer, 0, params);\n const enc = this.ctx.device.createCommandEncoder();\n const p = enc.beginComputePass();\n p.setPipeline(d.pipeline);\n p.setBindGroup(0, d.bindGroup);\n p.dispatchWorkgroups(rows, gridY, gridZ);\n p.end();\n q.submit([enc.finish()]);\n await q.onSubmittedWorkDone();\n }\n continue;\n }\n const enc = this.ctx.device.createCommandEncoder();\n const p = enc.beginComputePass();\n p.setPipeline(d.pipeline);\n p.setBindGroup(0, d.bindGroup);\n p.dispatchWorkgroups(...sizes[i]);\n p.end();\n q.submit([enc.finish()]);\n await q.onSubmittedWorkDone();\n }\n onStage?.(\"vit-encode-done\");\n } else {\n const enc = this.ctx.device.createCommandEncoder({ label: \"gemma4_vision_encode\" });\n const pass = enc.beginComputePass({ label: \"gemma4_vision_pass\" });\n for (let i = 0; i < this.dispatches.length; i++) {\n pass.setPipeline(this.dispatches[i].pipeline);\n pass.setBindGroup(0, this.dispatches[i].bindGroup);\n pass.dispatchWorkgroups(...sizes[i]);\n }\n pass.end();\n q.submit([enc.finish()]);\n }\n\n const rows = inputs.numPooled;\n const dim = this.graph.tensors.g4v_image_embeds.shape[1] as number;\n const byteLen = rows * dim * 4;\n const out = this.activationBuffers.get(\"g4v_image_embeds\")!;\n const readback = this.ctx.device.createBuffer({ size: byteLen, usage: 0x0001 | 0x0008 });\n const enc = this.ctx.device.createCommandEncoder();\n enc.copyBufferToBuffer(out, 0, readback, 0, byteLen);\n this.ctx.device.queue.submit([enc.finish()]);\n await readback.mapAsync(MAP_MODE_READ, 0, byteLen);\n const embeds = new Float32Array(readback.getMappedRange(0, byteLen).slice(0));\n readback.unmap();\n readback.destroy();\n return { embeds, rows, dim };\n }\n\n /** True if this executor is the Gemma 4 vision tower. */\n get gemma4(): boolean {\n return this.isGemma4;\n }\n\n /** Read back any named activation (debug). Must be called right after encode(). */\n async debugReadBuffer(name: string, maxElements?: number): Promise<Float32Array> {\n const buffer = this.activationBuffers.get(name) ?? this.weightBuffers.get(name);\n if (!buffer) throw new Error(`VisionExecutor: no buffer \"${name}\"`);\n const byteLen = maxElements ? Math.min(maxElements * 4, buffer.size) : buffer.size;\n const readback = this.ctx.device.createBuffer({ size: byteLen, usage: 0x0001 | 0x0008 });\n const enc = this.ctx.device.createCommandEncoder();\n enc.copyBufferToBuffer(buffer, 0, readback, 0, byteLen);\n this.ctx.device.queue.submit([enc.finish()]);\n await readback.mapAsync(MAP_MODE_READ, 0, byteLen);\n const data = new Float32Array(readback.getMappedRange(0, byteLen).slice(0));\n readback.unmap();\n readback.destroy();\n return data;\n }\n\n destroy(): void {\n destroyBuffers([...this.weightBuffers.values()]);\n destroyBuffers([...this.activationBuffers.values()]);\n for (const d of this.dispatches) d.uniformBuffer.destroy();\n this.weightBuffers.clear();\n this.activationBuffers.clear();\n this.dispatches = [];\n }\n\n // ── Private ──\n\n /** Max pooled tokens for buffer sizing: maxPatches with no merge/pool ratio applied. */\n private maxPooled(): number {\n // Gemma 4 pools by k² (k = pooling_kernel_size). With no merger key we cannot\n // read k here, so reserve maxPatches rows (an upper bound — Np ≤ N always).\n return this.maxPatches;\n }\n\n private resolveShapes(N: number): Record<string, number[]> {\n const Nm = N / this.mergeUnit;\n const Np = this.gemma4Np || N; // resolved per-encode for Gemma 4; ≤ N\n const resolved: Record<string, number[]> = {};\n for (const [name, desc] of Object.entries(this.graph.tensors)) {\n resolved[name] = desc.shape.map((d) => {\n if (d === \"N\") return N;\n if (d === \"Nm\") return Nm;\n if (d === \"Np\") return Np;\n return d as number;\n });\n }\n return resolved;\n }\n\n private allocateActivationBuffers(): void {\n // One dedicated buffer per activation tensor sized at maxPatches. Vision\n // graphs are tiny (≤ a few thousand patches × ≤3072 floats), so no pooling.\n // Only tensors actually referenced by a node get a buffer: the vision arch\n // files declare orphan `*_mm` intermediates from a pre-fused design, and\n // blindly allocating them costs ~331 MB on WebKit (~1.3 GB desktop) — a\n // large slice of the iPhone vision OOM for zero work.\n const referenced = new Set<string>();\n for (const node of this.graph.nodes) {\n for (const t of node.inputs) referenced.add(t);\n for (const t of node.outputs) referenced.add(t);\n }\n let skippedBytes = 0;\n for (const [name, desc] of Object.entries(this.graph.tensors)) {\n if (desc.storage !== \"activation\") continue;\n if (!referenced.has(name)) {\n const shape = desc.shape.map((d) => {\n if (d === \"N\") return this.maxPatches;\n if (d === \"Nm\") return this.maxPatches / this.mergeUnit;\n if (d === \"Np\") return this.maxPooled();\n return d as number;\n });\n skippedBytes += shape.reduce((a, b) => a * b, 1) * DTYPE_BYTES[desc.dtype];\n continue;\n }\n const shape = desc.shape.map((d) => {\n if (d === \"N\") return this.maxPatches;\n if (d === \"Nm\") return this.maxPatches / this.mergeUnit;\n if (d === \"Np\") return this.maxPooled();\n return d as number;\n });\n const bytes = shape.reduce((a, b) => a * b, 1) * DTYPE_BYTES[desc.dtype];\n this.activationBuffers.set(name, createStorageBuffer(this.ctx, `vact_${name}`, bytes));\n }\n if (skippedBytes > 0) {\n console.log(\n `[vision] skipped ${(skippedBytes / 1e6).toFixed(0)} MB of unreferenced activation tensors`,\n );\n }\n }\n\n private gatherBuffers(\n spec: KernelSpec,\n node: OpNode,\n uniformBuffer: GPUBuffer,\n ): Array<{ buffer: GPUBuffer }> {\n const entries: Array<{ buffer: GPUBuffer }> = [];\n const tensorNames = [...node.inputs, ...node.outputs];\n let tensorIdx = 0;\n for (const binding of spec.bindings) {\n if (binding.type === \"uniform\") {\n entries.push({ buffer: uniformBuffer });\n } else {\n const tensorName = tensorNames[tensorIdx++];\n const buffer = this.weightBuffers.get(tensorName) ?? this.activationBuffers.get(tensorName);\n if (!buffer)\n throw new Error(`VisionExecutor: no buffer for \"${tensorName}\" in op ${node.id}`);\n entries.push({ buffer });\n }\n }\n return entries;\n }\n}\n","/**\n * Host-side vision preprocessing for the Qwen3.5 ViT.\n *\n * The learned position embeddings (bilinear-interpolated over the patch grid)\n * and the 2D rotary cos/sin tables are functions of the image grid (t, h, w)\n * ONLY — not of the model weights or pixel values. They are cheap to compute on\n * the CPU and fed to the GPU graph as input activations, keeping the graph to\n * weight-dependent math while staying byte-identical to HF transformers.\n *\n * Ports (verified against transformers 5.12 vision_utils.py + modeling_qwen3_5):\n * - get_vision_bilinear_indices_and_weights → buildPosEmbeds()\n * - get_vision_position_ids → buildPositionIds()\n * - Qwen3_5VisionRotaryEmbedding → buildRotaryCosSin()\n *\n * Patch ordering: both the pos-embed gather and the position ids reorder patches\n * into spatial_merge_size×spatial_merge_size groups, matching the HF image\n * processor's output ordering, so the merger's [N,h]→[N/u,h*u] reshape lines up.\n */\n\nexport interface VisionGridConfig {\n hiddenSize: number; // 768\n numHeads: number; // 12\n numPositionEmbeddings: number; // 2304 → num_grid_per_side = 48\n spatialMergeSize: number; // 2\n ropeTheta?: number; // 10000\n}\n\nexport interface VisionPositionTensors {\n /** [N, hidden_size] bilinear-interpolated learned position embeddings. */\n posEmbeds: Float32Array;\n /** [N, head_dim] rotary cosines. */\n cos: Float32Array;\n /** [N, head_dim] rotary sines. */\n sin: Float32Array;\n numPatches: number;\n}\n\n/** linspace(0, n-1, count) matching torch.linspace. */\nfunction linspace(stop: number, count: number): Float64Array {\n const out = new Float64Array(count);\n if (count === 1) {\n out[0] = 0;\n return out;\n }\n const step = stop / (count - 1);\n for (let i = 0; i < count; i++) out[i] = i * step;\n return out;\n}\n\n/**\n * Compute the spatial-merge reorder index for a (h, w) grid:\n * reorder[k] gives the source patch index (row-major h*w) for output slot k,\n * grouping 2×2 (merge×merge) spatial blocks contiguously. Matches the `reorder`\n * in get_vision_bilinear_indices_and_weights and the position-id reshape.\n */\nfunction spatialMergeReorder(h: number, w: number, merge: number): Int32Array {\n // HF: h_idx[h//m, m], w_idx[w//m, m];\n // (h_idx[:,:,None,None]*w + w_idx[None,None,:,:]).transpose(1,2).flatten()\n // Result dims (after transpose): [h//m, w//m, m(h), m(w)].\n const hb = h / merge;\n const wb = w / merge;\n const out = new Int32Array(h * w);\n let k = 0;\n for (let bh = 0; bh < hb; bh++) {\n for (let bw = 0; bw < wb; bw++) {\n for (let ih = 0; ih < merge; ih++) {\n for (let iw = 0; iw < merge; iw++) {\n const hh = bh * merge + ih;\n const ww = bw * merge + iw;\n out[k++] = hh * w + ww;\n }\n }\n }\n }\n return out;\n}\n\n/**\n * Build bilinear-interpolated learned position embeddings [N, hidden].\n * posEmbedTable is the raw pos_embed.weight [num_position_embeddings, hidden].\n */\nexport function buildPosEmbeds(\n gridTHW: [number, number, number],\n posEmbedTable: Float32Array,\n cfg: VisionGridConfig,\n): Float32Array {\n const [t, h, w] = gridTHW;\n const hidden = cfg.hiddenSize;\n const side = Math.round(Math.sqrt(cfg.numPositionEmbeddings)); // 48\n const merge = cfg.spatialMergeSize;\n\n const hGrid = linspace(side - 1, h);\n const wGrid = linspace(side - 1, w);\n const hFloor = new Int32Array(h);\n const hCeil = new Int32Array(h);\n const hFrac = new Float64Array(h);\n for (let i = 0; i < h; i++) {\n hFloor[i] = Math.trunc(hGrid[i]);\n hCeil[i] = Math.min(hFloor[i] + 1, side - 1);\n hFrac[i] = hGrid[i] - hFloor[i];\n }\n const wFloor = new Int32Array(w);\n const wCeil = new Int32Array(w);\n const wFrac = new Float64Array(w);\n for (let j = 0; j < w; j++) {\n wFloor[j] = Math.trunc(wGrid[j]);\n wCeil[j] = Math.min(wFloor[j] + 1, side - 1);\n wFrac[j] = wGrid[j] - wFloor[j];\n }\n\n // Per (row-major h*w) patch: 4 corner indices + weights.\n const hw = h * w;\n const cornerIdx = [\n new Int32Array(hw),\n new Int32Array(hw),\n new Int32Array(hw),\n new Int32Array(hw),\n ];\n const cornerW = [\n new Float64Array(hw),\n new Float64Array(hw),\n new Float64Array(hw),\n new Float64Array(hw),\n ];\n let p = 0;\n for (let i = 0; i < h; i++) {\n const hf = hFloor[i] * side;\n const hc = hCeil[i] * side;\n const hfr = hFrac[i];\n for (let j = 0; j < w; j++) {\n cornerIdx[0][p] = hf + wFloor[j];\n cornerIdx[1][p] = hf + wCeil[j];\n cornerIdx[2][p] = hc + wFloor[j];\n cornerIdx[3][p] = hc + wCeil[j];\n cornerW[0][p] = (1 - hfr) * (1 - wFrac[j]);\n cornerW[1][p] = (1 - hfr) * wFrac[j];\n cornerW[2][p] = hfr * (1 - wFrac[j]);\n cornerW[3][p] = hfr * wFrac[j];\n p++;\n }\n }\n\n const reorder = spatialMergeReorder(h, w, merge);\n const N = t * hw;\n const out = new Float32Array(N * hidden);\n // For each temporal repeat and reordered patch, gather the 4 weighted corners.\n for (let tt = 0; tt < t; tt++) {\n for (let k = 0; k < hw; k++) {\n const src = reorder[k];\n const dstRow = tt * hw + k;\n const dstBase = dstRow * hidden;\n for (let corner = 0; corner < 4; corner++) {\n const tableRow = cornerIdx[corner][src] * hidden;\n const wgt = cornerW[corner][src];\n if (wgt === 0) continue;\n for (let d = 0; d < hidden; d++) {\n out[dstBase + d] += posEmbedTable[tableRow + d] * wgt;\n }\n }\n }\n }\n return out;\n}\n\n/**\n * Build the reordered (row, col) position ids [N, 2] for rotary, matching\n * get_vision_position_ids.\n */\nexport function buildPositionIds(gridTHW: [number, number, number], merge: number): Int32Array {\n const [t, h, w] = gridTHW;\n const hb = h / merge;\n const wb = w / merge;\n const hw = h * w;\n const perFrame = new Int32Array(hw * 2);\n let k = 0;\n // hpos/wpos reshaped [h//m, m, w//m, m].transpose(1,2).flatten() → block-major.\n for (let bh = 0; bh < hb; bh++) {\n for (let bw = 0; bw < wb; bw++) {\n for (let ih = 0; ih < merge; ih++) {\n for (let iw = 0; iw < merge; iw++) {\n perFrame[k * 2] = bh * merge + ih; // row (h) position\n perFrame[k * 2 + 1] = bw * merge + iw; // col (w) position\n k++;\n }\n }\n }\n }\n const out = new Int32Array(t * hw * 2);\n for (let tt = 0; tt < t; tt++) out.set(perFrame, tt * hw * 2);\n return out;\n}\n\n/**\n * Build rotary cos/sin tables [N, head_dim] from position ids, matching\n * Qwen3_5VisionRotaryEmbedding + the cat((rotary, rotary)) in VisionModel.forward.\n *\n * rotary_pos_emb(position_ids) = (position_ids[..,None] * inv_freq).flatten(1)\n * where inv_freq has length (head_dim/2)/2 = head_dim/4, computed over dim=head_dim/2.\n * For each token the two position components (h, w) each produce head_dim/4 freqs,\n * concatenated → head_dim/2, then duplicated → head_dim for cos/sin.\n */\nexport function buildRotaryCosSin(\n positionIds: Int32Array,\n headDim: number,\n theta = 10000.0,\n): { cos: Float32Array; sin: Float32Array; numPatches: number } {\n // rotary embedding dim = head_dim / 2; inv_freq over arange(0, dim, 2)/dim.\n const rotaryDim = headDim / 2; // 32\n const half = rotaryDim / 2; // 16 freqs per position component\n const invFreq = new Float64Array(half);\n for (let i = 0; i < half; i++) {\n invFreq[i] = 1.0 / theta ** ((2 * i) / rotaryDim);\n }\n\n const N = positionIds.length / 2;\n // rotary_pos_emb per token = [h*invFreq (half), w*invFreq (half)] → length rotaryDim.\n // emb = cat(rotary, rotary) → length head_dim. cos/sin = cos/sin(emb).\n const cos = new Float32Array(N * headDim);\n const sin = new Float32Array(N * headDim);\n for (let n = 0; n < N; n++) {\n const hp = positionIds[n * 2];\n const wp = positionIds[n * 2 + 1];\n const base = n * headDim;\n for (let i = 0; i < half; i++) {\n const fh = hp * invFreq[i];\n const fw = wp * invFreq[i];\n // emb layout: [h-freqs(16), w-freqs(16), h-freqs(16), w-freqs(16)] = head_dim(64)\n const ch = Math.cos(fh);\n const sh = Math.sin(fh);\n const cw = Math.cos(fw);\n const sw = Math.sin(fw);\n cos[base + i] = ch;\n sin[base + i] = sh;\n cos[base + half + i] = cw;\n sin[base + half + i] = sw;\n cos[base + rotaryDim + i] = ch;\n sin[base + rotaryDim + i] = sh;\n cos[base + rotaryDim + half + i] = cw;\n sin[base + rotaryDim + half + i] = sw;\n }\n }\n return { cos, sin, numPatches: N };\n}\n\n/**\n * Build all host position tensors for a single image grid in one call.\n */\nexport function buildVisionPositionTensors(\n gridTHW: [number, number, number],\n posEmbedTable: Float32Array,\n cfg: VisionGridConfig,\n): VisionPositionTensors {\n const headDim = Math.floor(cfg.hiddenSize / cfg.numHeads);\n const posEmbeds = buildPosEmbeds(gridTHW, posEmbedTable, cfg);\n const positionIds = buildPositionIds(gridTHW, cfg.spatialMergeSize);\n const { cos, sin, numPatches } = buildRotaryCosSin(\n positionIds,\n headDim,\n cfg.ropeTheta ?? 10000.0,\n );\n return { posEmbeds, cos, sin, numPatches };\n}\n\n// ───────────────────────────────────────────────────────────────────────────\n// GEMMA 4 vision tower (`gemma4_vision`) host preprocessing.\n//\n// Distinct from the Qwen ViT above: Gemma 4 is a SigLIP-style encoder with\n// - pre-flattened [N, 3·16·16] patches (Linear patch-embed, no Conv2d),\n// - AXIAL learned position embeddings: per patch (x,y), pos = table[0][x]+table[1][y],\n// - 2D axial RoPE (θ=100): spatial_dim = head_dim/2; inv_freq over arange(0,spatial_dim,2)/spatial_dim;\n// per spatial dim emb=cat(f,f); final cos/sin = cat([emb_x, emb_y]) of length head_dim,\n// applied with the standard global-half rotate_half (the existing ApplyRotaryEmb kernel),\n// - k×k average pooling (k=pooling_kernel_size) → soft tokens, as a [Np, N] matrix.\n// Verified against transformers modeling_gemma4 + image_processing_gemma4 and the\n// live config/safetensors of google/gemma-4-E2B-it (+ MLX 4bit convert).\n// ───────────────────────────────────────────────────────────────────────────\n\nexport interface Gemma4VisionGridConfig {\n hiddenSize: number; // 768\n numHeads: number; // 12\n headDim: number; // 64\n ropeTheta: number; // 100\n poolingKernelSize: number; // 3\n}\n\nexport interface Gemma4VisionPositionTensors {\n /** [N, hidden] axial position embeddings (table[0][x] + table[1][y]). */\n posEmbeds: Float32Array;\n /** [N, headDim] axial rotary cosines. */\n cos: Float32Array;\n /** [N, headDim] axial rotary sines. */\n sin: Float32Array;\n /** [Np, N] average-pooling matrix (1/k² in-cell, 0 elsewhere). */\n poolMatrix: Float32Array;\n /** number of patches N (= gridH*gridW). */\n numPatches: number;\n /** number of pooled (soft) tokens Np (= ceil(gridH/k)*ceil(gridW/k)). */\n numPooled: number;\n}\n\n/**\n * Per-patch (x, y) grid coordinates in row-major order, matching the Gemma4\n * image processor's meshgrid(arange(width), arange(height)) reshape: patch p at\n * row r (0..gridH-1), col c (0..gridW-1) → x=c, y=r, index = r*gridW + c.\n */\nfunction gemma4PatchXY(gridH: number, gridW: number): { x: Int32Array; y: Int32Array } {\n const n = gridH * gridW;\n const x = new Int32Array(n);\n const y = new Int32Array(n);\n let p = 0;\n for (let r = 0; r < gridH; r++) {\n for (let c = 0; c < gridW; c++) {\n x[p] = c;\n y[p] = r;\n p++;\n }\n }\n return { x, y };\n}\n\n/**\n * Build axial learned position embeddings [N, hidden] from the [2, posSize, hidden]\n * table: pos[p] = table[0][x_p] + table[1][y_p]. Direct lookup, no interpolation\n * (HF F.embedding on clamped positions).\n */\nexport function buildGemma4PosEmbeds(\n gridH: number,\n gridW: number,\n posEmbedTable: Float32Array, // [2, posSize, hidden] flattened\n hidden: number,\n posSize: number,\n): Float32Array {\n const { x, y } = gemma4PatchXY(gridH, gridW);\n const n = gridH * gridW;\n const out = new Float32Array(n * hidden);\n const yPlane = posSize * hidden; // table[1] base offset\n for (let p = 0; p < n; p++) {\n const xi = Math.max(0, x[p]);\n const yi = Math.max(0, y[p]);\n const xBase = xi * hidden;\n const yBase = yPlane + yi * hidden;\n const dst = p * hidden;\n for (let d = 0; d < hidden; d++) {\n out[dst + d] = posEmbedTable[xBase + d] + posEmbedTable[yBase + d];\n }\n }\n return out;\n}\n\n/**\n * Build the 2D axial rotary cos/sin tables [N, headDim].\n * spatial_dim = headDim / 2; inv_freq[j] = 1/theta^((2j)/spatial_dim), j in [0, spatial_dim/2)\n * per spatial dim: f = pos * inv_freq (spatial_dim/2 values); emb = cat(f, f) (spatial_dim values)\n * cos/sin = cat([emb_x, emb_y]) → headDim values, layout [fx,fx,fy,fy].\n * Applied with the global-half rotate_half kernel (ApplyRotaryEmb), which computes\n * out = x*cos + rotate_half(x)*sin element-wise — exact for this layout.\n */\nexport function buildGemma4RotaryCosSin(\n gridH: number,\n gridW: number,\n headDim: number,\n theta: number,\n): { cos: Float32Array; sin: Float32Array } {\n const { x, y } = gemma4PatchXY(gridH, gridW);\n const n = gridH * gridW;\n const spatialDim = headDim / 2; // 32\n const half = spatialDim / 2; // 16 freqs per spatial dim\n const invFreq = new Float64Array(half);\n for (let j = 0; j < half; j++) {\n invFreq[j] = 1.0 / theta ** ((2 * j) / spatialDim);\n }\n const cos = new Float32Array(n * headDim);\n const sin = new Float32Array(n * headDim);\n for (let p = 0; p < n; p++) {\n const xp = Math.max(0, x[p]);\n const yp = Math.max(0, y[p]);\n const base = p * headDim;\n for (let j = 0; j < half; j++) {\n const fx = xp * invFreq[j];\n const fy = yp * invFreq[j];\n const cx = Math.cos(fx);\n const sx = Math.sin(fx);\n const cy = Math.cos(fy);\n const sy = Math.sin(fy);\n // layout: [fx(0..15), fx(16..31), fy(32..47), fy(48..63)]\n cos[base + j] = cx;\n sin[base + j] = sx;\n cos[base + half + j] = cx;\n sin[base + half + j] = sx;\n cos[base + spatialDim + j] = cy;\n sin[base + spatialDim + j] = sy;\n cos[base + spatialDim + half + j] = cy;\n sin[base + spatialDim + half + j] = sy;\n }\n }\n return { cos, sin };\n}\n\n/**\n * Build the [Np, N] average-pooling matrix for k×k spatial pooling over the real\n * (unpadded) grid, matching modeling_gemma4's kernel_idxs/one_hot pooling:\n * cell(p) = floor(x_p/k) + ceil(gridW/k) * floor(y_p/k)\n * poolMatrix[cell, p] = 1/k² (so pooled = poolMatrix @ hidden = mean over the k×k block)\n * Np = ceil(gridH/k) * ceil(gridW/k). Each pooled cell averages exactly the patches\n * that fall in it (edge cells with fewer than k² patches still divide by k², matching\n * HF's fixed 1/k² normalization).\n */\nexport function buildGemma4PoolMatrix(\n gridH: number,\n gridW: number,\n k: number,\n): { poolMatrix: Float32Array; numPooled: number } {\n const n = gridH * gridW;\n const cellsW = Math.ceil(gridW / k);\n const cellsH = Math.ceil(gridH / k);\n const np = cellsW * cellsH;\n const inv = 1.0 / (k * k);\n const poolMatrix = new Float32Array(np * n);\n const { x, y } = gemma4PatchXY(gridH, gridW);\n for (let p = 0; p < n; p++) {\n const cx = Math.floor(x[p] / k);\n const cy = Math.floor(y[p] / k);\n const cell = cx + cellsW * cy;\n poolMatrix[cell * n + p] = inv;\n }\n return { poolMatrix, numPooled: np };\n}\n\n/**\n * Build all Gemma 4 vision host tensors for one image grid in one call.\n * `posEmbedTable` is the raw [2, posSize, hidden] flattened table.\n */\nexport function buildGemma4VisionPositionTensors(\n gridH: number,\n gridW: number,\n posEmbedTable: Float32Array,\n posSize: number,\n cfg: Gemma4VisionGridConfig,\n): Gemma4VisionPositionTensors {\n const posEmbeds = buildGemma4PosEmbeds(gridH, gridW, posEmbedTable, cfg.hiddenSize, posSize);\n const { cos, sin } = buildGemma4RotaryCosSin(gridH, gridW, cfg.headDim, cfg.ropeTheta);\n const { poolMatrix, numPooled } = buildGemma4PoolMatrix(gridH, gridW, cfg.poolingKernelSize);\n return { posEmbeds, cos, sin, poolMatrix, numPatches: gridH * gridW, numPooled };\n}\n\n/** Gemma 4 image processor config (from processor_config.json). */\nexport const GEMMA4_IMAGE_PROCESSOR: ImageProcessorConfig = {\n patchSize: 16,\n temporalPatchSize: 1, // single frame, not duplicated (Gemma is not temporal)\n mergeSize: 1, // pooling (k=3) replaces Qwen's spatial-merge reshape\n imageMean: [0.0, 0.0, 0.0],\n imageStd: [1.0, 1.0, 1.0],\n rescaleFactor: 1 / 255,\n minPixels: 16 * 16, // a single 48×48-divisible tile minimum\n maxPixels: 2520 * 16 * 16, // max_patches(280·9) · patch²\n};\n\nexport interface Gemma4PreprocessedImage {\n /** Flattened patches [N, 3·patch²] row-major (row-major patch grid). */\n patches: Float32Array;\n /** Patch grid (gridH, gridW). */\n gridHW: [number, number];\n}\n\n/**\n * Preprocess a decoded RGB image for the Gemma 4 ViT: aspect-preserving resize so\n * the patch grid is ≤ max_soft_tokens·k² patches and H,W divisible by k·patch,\n * rescale ×1/255 (no normalize), patchify row-major into [N, 3·16·16].\n *\n * @param pixels row-major HWC RGB (0..255), length width*height*3.\n */\nexport function preprocessImageGemma4(\n pixels: Float32Array | Uint8ClampedArray | Uint8Array,\n width: number,\n height: number,\n maxSoftTokens = 280,\n poolingKernelSize = 3,\n patchSize = 16,\n): Gemma4PreprocessedImage {\n const factor = poolingKernelSize * patchSize; // 48\n const maxPatches = maxSoftTokens * poolingKernelSize * poolingKernelSize; // 2520\n // Largest aspect-preserving (H',W') divisible by `factor` with (H'/16)*(W'/16) ≤ maxPatches.\n const floorByFactor = (n: number) => Math.max(factor, Math.floor(n / factor) * factor);\n let outH = floorByFactor(height);\n let outW = floorByFactor(width);\n // Shrink (preserving aspect) until the patch budget is met.\n while ((outH / patchSize) * (outW / patchSize) > maxPatches) {\n const beta = Math.sqrt(((outH / patchSize) * (outW / patchSize)) / maxPatches);\n outH = floorByFactor(outH / beta);\n outW = floorByFactor(outW / beta);\n if (outH <= factor && outW <= factor) break;\n }\n const resized = bilinearResize(pixels, height, width, outH, outW);\n\n const gridH = outH / patchSize;\n const gridW = outW / patchSize;\n const ch = 3;\n const ps = patchSize;\n const patchDim = ch * ps * ps; // 768\n const numP = gridH * gridW;\n const patches = new Float32Array(numP * patchDim);\n const rescale = 1 / 255;\n\n // Row-major patch grid; per patch flatten layout [C, ps_h, ps_w] (channel-major)\n // to match the processor's (num_channels, ph, pw) → flatten ordering.\n let pIdx = 0;\n for (let pr = 0; pr < gridH; pr++) {\n for (let pc = 0; pc < gridW; pc++) {\n const base = pIdx * patchDim;\n let kk = 0;\n for (let c = 0; c < ch; c++) {\n for (let py = 0; py < ps; py++) {\n const row = (pr * ps + py) * outW;\n for (let px = 0; px < ps; px++) {\n patches[base + kk] = resized[(row + pc * ps + px) * 3 + c] * rescale;\n kk++;\n }\n }\n }\n pIdx++;\n }\n }\n return { patches, gridHW: [gridH, gridW] };\n}\n\n// ───────────────────────────────────────────────────────────────────────────\n// LM-SIDE multimodal preprocessing: image → patches, M-RoPE position ids & cos/sin.\n// These feed the text model (not the ViT). Ported from transformers 5.12:\n// - Qwen2VLImageProcessor.smart_resize / _preprocess → preprocessImage()\n// - Qwen3_5Model.get_rope_index / get_vision_position_ids → buildMRoPEPositionIds()\n// - Qwen3_5TextRotaryEmbedding.forward (interleaved M-RoPE) → buildMRoPECosSin()\n// ───────────────────────────────────────────────────────────────────────────\n\nexport interface ImageProcessorConfig {\n patchSize: number; // 16\n temporalPatchSize: number; // 2\n mergeSize: number; // 2\n imageMean: [number, number, number]; // (0.5, 0.5, 0.5)\n imageStd: [number, number, number]; // (0.5, 0.5, 0.5)\n /** rescale factor applied to raw 0..255 pixels before normalization (1/255). */\n rescaleFactor: number; // 1/255\n /** min total pixels after resize (shortest_edge). */\n minPixels: number; // 65536 (4*16*16*... HF default: 256*28*28 family → here shortest_edge)\n /** max total pixels after resize (longest_edge). */\n maxPixels: number; // 16777216\n}\n\nexport const QWEN3_5_IMAGE_PROCESSOR: ImageProcessorConfig = {\n patchSize: 16,\n temporalPatchSize: 2,\n mergeSize: 2,\n imageMean: [0.5, 0.5, 0.5],\n imageStd: [0.5, 0.5, 0.5],\n rescaleFactor: 1 / 255,\n minPixels: 65_536,\n maxPixels: 16_777_216,\n};\n\nexport interface PreprocessedImage {\n /** Flattened patches [N, 1536] in the spatial-merge order encodeImage expects. */\n patches: Float32Array;\n /** (t, h, w) patch grid. t=1 for a single image, h/w in patch units. */\n gridTHW: [number, number, number];\n}\n\n/**\n * Qwen2-VL smart-resize: round H and W to multiples of factor=patch*merge,\n * keeping aspect ratio and clamping the total pixel budget to [minPixels, maxPixels].\n * Matches transformers.models.qwen2_vl.image_processing.smart_resize.\n */\nexport function smartResize(\n height: number,\n width: number,\n factor: number,\n minPixels: number,\n maxPixels: number,\n): [number, number] {\n if (height < factor || width < factor) {\n // HF raises; clamp up to one factor so tiny images still produce a grid.\n const scale = factor / Math.min(height, width);\n height = Math.max(factor, Math.round(height * scale));\n width = Math.max(factor, Math.round(width * scale));\n }\n const roundByFactor = (n: number) => Math.round(n / factor) * factor;\n const floorByFactor = (n: number) => Math.floor(n / factor) * factor;\n const ceilByFactor = (n: number) => Math.ceil(n / factor) * factor;\n\n let hBar = Math.max(factor, roundByFactor(height));\n let wBar = Math.max(factor, roundByFactor(width));\n if (hBar * wBar > maxPixels) {\n const beta = Math.sqrt((height * width) / maxPixels);\n hBar = Math.max(factor, floorByFactor(height / beta));\n wBar = Math.max(factor, floorByFactor(width / beta));\n } else if (hBar * wBar < minPixels) {\n const beta = Math.sqrt(minPixels / (height * width));\n hBar = ceilByFactor(height * beta);\n wBar = ceilByFactor(width * beta);\n }\n return [hBar, wBar];\n}\n\n/**\n * Bilinear-resample an RGB image (HWC, 0..255 or 0..1) to (outH, outW).\n * Half-pixel-centered sampling to match PIL/torchvision BILINEAR closely.\n * `pixels` is row-major [H, W, 3].\n */\nfunction bilinearResize(\n pixels: Float32Array | Uint8ClampedArray | Uint8Array,\n inH: number,\n inW: number,\n outH: number,\n outW: number,\n): Float32Array {\n const out = new Float32Array(outH * outW * 3);\n const scaleH = inH / outH;\n const scaleW = inW / outW;\n for (let oy = 0; oy < outH; oy++) {\n let sy = (oy + 0.5) * scaleH - 0.5;\n if (sy < 0) sy = 0;\n if (sy > inH - 1) sy = inH - 1;\n const y0 = Math.floor(sy);\n const y1 = Math.min(y0 + 1, inH - 1);\n const fy = sy - y0;\n for (let ox = 0; ox < outW; ox++) {\n let sx = (ox + 0.5) * scaleW - 0.5;\n if (sx < 0) sx = 0;\n if (sx > inW - 1) sx = inW - 1;\n const x0 = Math.floor(sx);\n const x1 = Math.min(x0 + 1, inW - 1);\n const fx = sx - x0;\n const i00 = (y0 * inW + x0) * 3;\n const i01 = (y0 * inW + x1) * 3;\n const i10 = (y1 * inW + x0) * 3;\n const i11 = (y1 * inW + x1) * 3;\n const od = (oy * outW + ox) * 3;\n for (let c = 0; c < 3; c++) {\n const top = pixels[i00 + c] * (1 - fx) + pixels[i01 + c] * fx;\n const bot = pixels[i10 + c] * (1 - fx) + pixels[i11 + c] * fx;\n out[od + c] = top * (1 - fy) + bot * fy;\n }\n }\n }\n return out;\n}\n\n/**\n * Preprocess a decoded RGB image into the [N, 1536] patch tensor + grid_thw that\n * `encodeImage()` expects, matching the HF Qwen2-VL image processor:\n * smart_resize → rescale (×1/255) → normalize → temporal-pair (×temporal_patch_size)\n * → patchify into spatial_merge×spatial_merge blocks → flatten to [N, C·T·P·P].\n *\n * @param pixels row-major HWC RGB, length width*height*3. Values 0..255 (default)\n * or already 0..1 if `rescaled` is true.\n * @param width source pixel width\n * @param height source pixel height\n */\nexport function preprocessImage(\n pixels: Float32Array | Uint8ClampedArray | Uint8Array,\n width: number,\n height: number,\n cfg: ImageProcessorConfig = QWEN3_5_IMAGE_PROCESSOR,\n rescaled = false,\n): PreprocessedImage {\n const factor = cfg.patchSize * cfg.mergeSize; // 32\n const [outH, outW] = smartResize(height, width, factor, cfg.minPixels, cfg.maxPixels);\n const resized = bilinearResize(pixels, height, width, outH, outW);\n\n // rescale + normalize per channel → CHW float\n const [mr, mg, mb] = cfg.imageMean;\n const [sr, sg, sb] = cfg.imageStd;\n const mean = [mr, mg, mb];\n const std = [sr, sg, sb];\n const rescale = rescaled ? 1 : cfg.rescaleFactor;\n const chw = new Float32Array(3 * outH * outW);\n const plane = outH * outW;\n for (let y = 0; y < outH; y++) {\n for (let x = 0; x < outW; x++) {\n const src = (y * outW + x) * 3;\n const dst = y * outW + x;\n for (let c = 0; c < 3; c++) {\n chw[c * plane + dst] = (resized[src + c] * rescale - mean[c]) / std[c];\n }\n }\n }\n\n // Patchify exactly like the HF processor's reshape/transpose chain.\n // grid: t=1 (single frame, duplicated to temporal_patch_size), h/w in patches.\n const t = 1;\n const gridH = outH / cfg.patchSize;\n const gridW = outW / cfg.patchSize;\n const ps = cfg.patchSize;\n const tps = cfg.temporalPatchSize;\n const ch = 3;\n const merge = cfg.mergeSize;\n const gridHm = gridH / merge;\n const gridWm = gridW / merge;\n const patchDim = ch * tps * ps * ps; // 1536\n const numPatches = t * gridH * gridW;\n const patches = new Float32Array(numPatches * patchDim);\n\n // HF flatten layout (per patch row, contiguous): [C, T, ps_h, ps_w].\n // Output patch ordering: blocks of merge×merge, matching get_vision_*: see\n // qwen2_vl reshape (grid_t, gridHm, merge, gridWm, merge, C, tps, ps, ps).\n let pIdx = 0;\n for (let gt = 0; gt < t; gt++) {\n for (let bh = 0; bh < gridHm; bh++) {\n for (let bw = 0; bw < gridWm; bw++) {\n for (let mh = 0; mh < merge; mh++) {\n for (let mw = 0; mw < merge; mw++) {\n const patchRow = (bh * merge + mh) * ps;\n const patchCol = (bw * merge + mw) * ps;\n const base = pIdx * patchDim;\n let k = 0;\n for (let c = 0; c < ch; c++) {\n for (let tt = 0; tt < tps; tt++) {\n // single frame duplicated across the temporal dim\n for (let py = 0; py < ps; py++) {\n const row = (patchRow + py) * outW;\n for (let px = 0; px < ps; px++) {\n patches[base + k] = chw[c * plane + row + (patchCol + px)];\n k++;\n }\n }\n void tt;\n }\n }\n pIdx++;\n }\n }\n }\n }\n }\n\n return { patches, gridTHW: [t, gridH, gridW] };\n}\n\n/**\n * Build the 3D M-RoPE position ids [3, seq] for a text sequence that contains\n * `image_token_id` runs, matching Qwen3_5Model.get_rope_index for a single image.\n *\n * Text tokens advance all three (t,h,w) components together (standard 1D RoPE).\n * Each image run uses the vision grid: temporal=start (t=1), height=start+h_block,\n * width=start+w_block, in row-major (h outer, w inner) order; after the image the\n * cursor jumps by max(h_merged, w_merged). Returns Int32Array of length 3*seq\n * laid out as [T-row(seq), H-row(seq), W-row(seq)].\n */\n/**\n * Fill the 3D position rows for one image run starting at sequence index `at`\n * and logical `start`. Returns the next sequence index and the post-image cursor.\n */\nfunction fillImagePositions(\n rows: { t: Int32Array; h: Int32Array; w: Int32Array },\n at: number,\n start: number,\n grid: [number, number, number],\n mergeSize: number,\n): { next: number; cursor: number } {\n const [gt, gh, gw] = grid;\n const hm = gh / mergeSize;\n const wm = gw / mergeSize;\n let i = at;\n for (let tt = 0; tt < gt; tt++) {\n for (let h = 0; h < hm; h++) {\n for (let w = 0; w < wm; w++) {\n rows.t[i] = start + tt;\n rows.h[i] = start + h;\n rows.w[i] = start + w;\n i++;\n }\n }\n }\n return { next: i, cursor: start + Math.max(hm, wm) };\n}\n\nexport function buildMRoPEPositionIds(\n inputIds: Int32Array | Uint32Array | number[],\n imageGrids: Array<[number, number, number]>,\n imageTokenId: number,\n mergeSize: number,\n): Int32Array {\n const seq = inputIds.length;\n const rows = { t: new Int32Array(seq), h: new Int32Array(seq), w: new Int32Array(seq) };\n\n let i = 0;\n let cursor = 0;\n let imageIdx = 0;\n while (i < seq) {\n if (inputIds[i] === imageTokenId) {\n const res = fillImagePositions(rows, i, cursor, imageGrids[imageIdx++], mergeSize);\n i = res.next;\n cursor = res.cursor;\n } else {\n rows.t[i] = cursor;\n rows.h[i] = cursor;\n rows.w[i] = cursor;\n cursor++;\n i++;\n }\n }\n\n const out = new Int32Array(3 * seq);\n out.set(rows.t, 0);\n out.set(rows.h, seq);\n out.set(rows.w, 2 * seq);\n return out;\n}\n\n/**\n * Per-pair frequency→dimension assignment for interleaved M-RoPE, matching\n * Qwen3_5TextRotaryEmbedding.apply_interleaved_mrope. For pair index i in\n * [0, sum(section)) the position component is section-cyclic: T,H,W,T,H,W,...\n * but each component capped at its section count. Returns an array of length\n * (rope_dim/2) with values 0=T, 1=H, 2=W.\n */\nexport function mropeFreqDims(mropeSection: [number, number, number]): Int32Array {\n const total = mropeSection[0] + mropeSection[1] + mropeSection[2];\n const dims = new Int32Array(total); // default 0 (T)\n for (let d = 1; d <= 2; d++) {\n const length = mropeSection[d] * 3;\n for (let idx = d; idx < length && idx < total; idx += 3) {\n dims[idx] = d;\n }\n }\n return dims;\n}\n\n/**\n * Build the interleaved-M-RoPE cos/sin tables [seq, rope_dim] from 3D position\n * ids, matching Qwen3_5TextRotaryEmbedding.forward:\n * freqs[d][i] = pos[d] * inv_freq[i], inv_freq[i] = 1/theta^(2i/rope_dim)\n * freq[i] picks component mropeFreqDims[i]; emb = cat(freqs, freqs).\n * cos/sin have length seq*rope_dim. For text-only (all 3 pos rows equal) this\n * reduces exactly to standard 1D partial RoPE.\n *\n * @param positionIds3 [3, seq] as produced by buildMRoPEPositionIds.\n * @param ropeDim number of rotated dims per head (head_dim * partial_factor).\n */\nexport function buildMRoPECosSin(\n positionIds3: Int32Array,\n seq: number,\n ropeDim: number,\n theta: number,\n mropeSection: [number, number, number],\n): { cos: Float32Array; sin: Float32Array } {\n const half = ropeDim / 2; // == sum(mropeSection)\n const freqDims = mropeFreqDims(mropeSection);\n const invFreq = new Float64Array(half);\n for (let i = 0; i < half; i++) {\n invFreq[i] = 1.0 / theta ** ((2 * i) / ropeDim);\n }\n const cos = new Float32Array(seq * ropeDim);\n const sin = new Float32Array(seq * ropeDim);\n for (let n = 0; n < seq; n++) {\n const base = n * ropeDim;\n for (let i = 0; i < half; i++) {\n const dim = freqDims[i]; // 0=T,1=H,2=W\n const pos = positionIds3[dim * seq + n];\n const angle = pos * invFreq[i];\n const c = Math.cos(angle);\n const s = Math.sin(angle);\n // emb = cat(freqs, freqs): duplicate into [0,half) and [half,ropeDim)\n cos[base + i] = c;\n sin[base + i] = s;\n cos[base + half + i] = c;\n sin[base + half + i] = s;\n }\n }\n return { cos, sin };\n}\n","// ============================================\n// iOS Model Guards & Device Capability Detection\n// ============================================\n\n// ============================================\n// Real native-engine model ids\n// ============================================\n//\n// The website loads models by their actual repo id (MLX 4-bit on-device builds,\n// or the upstream Qwen/Liquid repos on desktop). The guard matches on those ids\n// — NOT the old ONNX-era shorthands — so it must stay in sync with the real\n// checkpoints the engine can run. Matching is substring-based on a normalized\n// id so both `mlx-community/Qwen3.5-0.8B-4bit` and `Qwen/Qwen3.5-0.8B` resolve.\n\n/** Recommended safe model ids per modality (used as fallbacks on mobile). */\nconst SAFE_MOBILE_CHAT = \"mlx-community/Qwen3.5-0.8B-4bit\";\n\n/**\n * Approximate on-device (INT4) memory footprint in MB for the models the native\n * engine actually ships. Used for memory-aware selection and messaging.\n */\nexport const MODEL_SIZES: Record<string, number> = {\n // Chat models (INT4, on-device)\n \"qwen3.5-0.8b\": 650, // ~0.65GB\n \"qwen3.5-2b\": 1700, // ~1.7GB\n \"gemma-4-e2b\": 3600, // ~3.6GB\n \"lfm2.5-350m\": 300, // ~0.3GB\n // TTS models\n \"kokoro-82m\": 350,\n \"supertonic-66m\": 300,\n // STT models\n \"whisper-tiny\": 150,\n \"whisper-tiny.en\": 150,\n \"whisper-small\": 500,\n // Embedding models\n \"all-minilm-l6-v2\": 100,\n};\n\n/**\n * Normalize a repo/model id to a lowercase token stream for substring matching\n * (strips org prefixes' punctuation while preserving the model name tokens).\n */\nfunction normalizeId(modelId: string): string {\n return modelId.toLowerCase().replace(/[^a-z0-9]/g, \"-\");\n}\n\n/**\n * iOS (WKWebView) model classification keyed off the REAL native-engine ids.\n *\n * - blocked: too large for the WKWebView memory ceiling on iPhone — will crash.\n * gemma-4-e2b (~3.6GB) plus any vision checkpoint (the vision encoder pushes\n * the working set well past what an iPhone can hold).\n * - risky: Qwen3.5-2B (~1.7GB) OOM-crashes iPhone WKWebView in practice — now\n * treated as unsafe to auto-load (flagged `risky` so a UI can offer to force it).\n * - everything else (Qwen3.5-0.8B ~0.65GB, LFM2.5-350M) is allowed everywhere.\n */\nconst IOS_MODEL_LIMITS = {\n /** Substrings (normalized) of ids that HARD-BLOCK on iPhone. */\n blocked: [\"gemma-4-e2b\", \"gemma-4-e4b\"],\n /** Substrings that mark a vision checkpoint (blocked on iPhone). */\n visionMarkers: [\"vision\", \"-vl-\", \"-vl\", \"vlm\", \"image-text\", \"-it-vision\"],\n /** Substrings of ids that WARN on iPhone (Qwen3.5-2B class). */\n risky: [\"qwen3.5-2b\", \"qwen3-5-2b\"],\n /** Maximum total memory budget in MB for iOS WKWebView. */\n maxBudgetMB: 1800,\n} as const;\n\n/**\n * Check if a model is safe to load on the current device.\n * Returns guidance specific to iOS memory constraints. Matches on the real\n * native-engine repo ids (MLX 4-bit / upstream Qwen / Liquid).\n */\nexport function isModelSafeForDevice(modelId: string): {\n safe: boolean;\n /**\n * Borderline: may run on the newest hardware but is prone to OOM. Reported\n * unsafe (`safe: false`) so callers block by default; a UI can use `risky` to\n * offer an explicit \"load anyway\" on capable devices.\n */\n risky: boolean;\n reason: string;\n recommendation?: string;\n maxSafeModel?: string;\n} {\n const ua = typeof navigator !== \"undefined\" ? navigator.userAgent : \"\";\n const isIPhone = /iPhone|iPod/.test(ua);\n const isIPad = /iPad/.test(ua);\n const normalizedId = normalizeId(modelId);\n\n const isVision = IOS_MODEL_LIMITS.visionMarkers.some((m) =>\n normalizedId.includes(normalizeId(m)),\n );\n const isBlocked =\n IOS_MODEL_LIMITS.blocked.some((m) => normalizedId.includes(normalizeId(m))) || isVision;\n const isRisky = IOS_MODEL_LIMITS.risky.some((m) => normalizedId.includes(normalizeId(m)));\n\n // iPhone is the hard constraint (smallest WKWebView budget). iPad has more\n // headroom, so only the genuinely huge / vision checkpoints are blocked there.\n if (isIPhone) {\n if (isBlocked) {\n if (isVision) {\n return {\n safe: false,\n risky: false,\n reason:\n \"This model can also read images, which needs more memory than an iPhone gives a web page — it would run out of memory and crash.\",\n recommendation:\n \"Use the standard model for chat on your phone, or open this on a Mac or PC to work with images. On newer iPhones, adding this site to your Home Screen can unlock extra memory and may let image models run.\",\n maxSafeModel: SAFE_MOBILE_CHAT,\n };\n }\n return {\n safe: false,\n risky: false,\n reason: \"This model is too large to fit in an iPhone's memory and would crash.\",\n recommendation:\n \"Use the standard model on your phone — it's fast and fully supported. The larger models need a Mac or PC. Adding this site to your Home Screen can also unlock extra memory on newer iPhones.\",\n maxSafeModel: SAFE_MOBILE_CHAT,\n };\n }\n if (isRisky) {\n return {\n safe: false,\n risky: true,\n reason: \"This model is on the large side for an iPhone and may run out of memory.\",\n recommendation:\n \"The standard model runs smoothly on iPhone. You can use this larger one on an iPad or computer.\",\n maxSafeModel: SAFE_MOBILE_CHAT,\n };\n }\n return { safe: true, risky: false, reason: \"Model is within iPhone memory limits.\" };\n }\n\n if (isIPad) {\n // iPad tolerates the 2B class; only block the huge / vision checkpoints.\n if (isBlocked) {\n const reason = isVision\n ? \"This model can also read images, which needs a lot of memory — it may run out and crash on iPad.\"\n : \"This model is very large and may run out of memory on iPad.\";\n return {\n safe: false,\n risky: false,\n reason,\n recommendation: \"Use the standard model or Qwen3.5 2B on iPad.\",\n maxSafeModel: \"mlx-community/Qwen3.5-2B-4bit\",\n };\n }\n return { safe: true, risky: false, reason: \"Model is within iPad memory limits.\" };\n }\n\n // Android - block the huge / vision checkpoints, allow the rest.\n const isAndroid = /Android/.test(ua);\n if (isAndroid && isBlocked) {\n return {\n safe: false,\n risky: false,\n reason: \"This model is very large and may run out of memory on this phone.\",\n recommendation: \"Use the standard model or Qwen3.5 2B instead.\",\n maxSafeModel: \"mlx-community/Qwen3.5-2B-4bit\",\n };\n }\n\n // Desktop - all models are safe.\n return { safe: true, risky: false, reason: \"Desktop browser has sufficient memory.\" };\n}\n\n/**\n * Get recommended models based on device memory and capabilities.\n * Helps prevent OOM crashes on low-memory mobile devices.\n */\nexport function getRecommendedModels(): {\n chat: string;\n tts: string;\n stt: string;\n embedding: string;\n reason: string;\n deviceMemory: number | null;\n isMobile: boolean;\n} {\n const ua = typeof navigator !== \"undefined\" ? navigator.userAgent : \"\";\n const deviceMemory = typeof navigator !== \"undefined\" ? (navigator as any).deviceMemory : null;\n const isMobile = /iPhone|iPad|iPod|Android|Mobile/.test(ua);\n\n // Estimate available memory (deviceMemory reports total GB, not available)\n // Mobile devices typically have less free memory due to OS overhead\n const effectiveMemory = deviceMemory ? (isMobile ? deviceMemory * 0.4 : deviceMemory * 0.6) : 4;\n const availableMB = effectiveMemory * 1024;\n\n let chat: string;\n let reason: string;\n\n if (availableMB < 600) {\n chat = \"LiquidAI/LFM2.5-350M\";\n reason = \"Very low memory device - using smallest model (LFM2.5-350M)\";\n } else if (isMobile && availableMB < 2200) {\n chat = SAFE_MOBILE_CHAT;\n reason = \"Mobile device - using Qwen3.5-0.8B to stay within the WKWebView memory limit\";\n } else if (availableMB < 2200) {\n chat = SAFE_MOBILE_CHAT;\n reason = \"Standard model for moderate memory (Qwen3.5-0.8B)\";\n } else {\n chat = \"mlx-community/Qwen3.5-2B-4bit\";\n reason = \"High memory available - using Qwen3.5-2B for better quality\";\n }\n\n return {\n chat,\n tts: \"kokoro-82m\",\n stt: \"whisper-tiny.en\",\n embedding: \"all-MiniLM-L6-v2\",\n reason,\n deviceMemory,\n isMobile,\n };\n}\n\n// ============================================\n// Session Phase Tracking (Reload Detection)\n// ============================================\n\ntype DownloadPhase = \"idle\" | \"downloading\" | \"caching\" | \"initializing\" | \"ready\" | \"error\";\n\nexport const SESSION_STORAGE_KEY = \"gerbil_session_phase\";\n\nexport type SessionState = {\n phase: DownloadPhase;\n modelId: string | null;\n sessionId: string;\n timestamp: number;\n bytesDownloaded?: number;\n totalBytes?: number;\n};\n\n/**\n * Generate a unique session ID for tracking across reloads.\n */\nfunction generateSessionId(): string {\n return `${Date.now()}-${Math.random().toString(36).slice(2, 9)}`;\n}\n\n/**\n * Get or create the current session ID.\n */\nfunction getSessionId(): string {\n if (typeof localStorage === \"undefined\") return generateSessionId();\n\n let sessionId = sessionStorage.getItem(\"gerbil_session_id\");\n if (!sessionId) {\n sessionId = generateSessionId();\n sessionStorage.setItem(\"gerbil_session_id\", sessionId);\n }\n return sessionId;\n}\n\n/**\n * Set the current download/initialization phase.\n * Used to detect if a reload happened during a critical operation.\n */\nexport function setDownloadPhase(\n phase: DownloadPhase,\n modelId?: string,\n progress?: { bytesDownloaded: number; totalBytes: number },\n): void {\n if (typeof localStorage === \"undefined\") return;\n\n const state: SessionState = {\n phase,\n modelId: modelId || null,\n sessionId: getSessionId(),\n timestamp: Date.now(),\n bytesDownloaded: progress?.bytesDownloaded,\n totalBytes: progress?.totalBytes,\n };\n\n localStorage.setItem(SESSION_STORAGE_KEY, JSON.stringify(state));\n}\n\n/**\n * Get the last known download phase from storage.\n */\nexport function getDownloadPhase(): SessionState | null {\n if (typeof localStorage === \"undefined\") return null;\n\n try {\n const raw = localStorage.getItem(SESSION_STORAGE_KEY);\n if (!raw) return null;\n return JSON.parse(raw) as SessionState;\n } catch {\n return null;\n }\n}\n\n/**\n * Detect if the page reloaded during a model download/initialization.\n * This typically indicates an iOS memory crash.\n *\n * @returns Detection result with recommended action\n */\nexport function detectMemoryCrash(): {\n crashed: boolean;\n phase?: DownloadPhase;\n modelId?: string;\n timeSinceCrash?: number;\n recommendation?: string;\n} {\n const lastState = getDownloadPhase();\n const currentSessionId = getSessionId();\n\n if (!lastState) {\n return { crashed: false };\n }\n\n // If session ID changed and we were in a critical phase, it's likely a crash/reload\n const criticalPhases: DownloadPhase[] = [\"downloading\", \"caching\", \"initializing\"];\n const wasInCriticalPhase = criticalPhases.includes(lastState.phase);\n const sessionChanged = lastState.sessionId !== currentSessionId;\n const timeSinceCrash = Date.now() - lastState.timestamp;\n\n // Only count as crash if it happened recently (within 5 minutes) and session changed\n const recentCrash = timeSinceCrash < 5 * 60 * 1000;\n\n if (wasInCriticalPhase && sessionChanged && recentCrash) {\n // Clear the state to prevent repeated detection\n localStorage.removeItem(SESSION_STORAGE_KEY);\n\n return {\n crashed: true,\n phase: lastState.phase,\n modelId: lastState.modelId || undefined,\n timeSinceCrash,\n recommendation:\n lastState.modelId && /2b|gemma|vision/i.test(lastState.modelId)\n ? \"The model was too large for your device. Try Qwen3.5-0.8B instead.\"\n : \"Your device ran out of memory. Try a smaller model or use a desktop browser.\",\n };\n }\n\n return { crashed: false };\n}\n\n/**\n * Clear session phase (call when model loads successfully).\n */\nexport function clearDownloadPhase(): void {\n if (typeof localStorage === \"undefined\") return;\n localStorage.removeItem(SESSION_STORAGE_KEY);\n}\n\n// ============================================\n// WebKit Submit-Granularity (group size) Probe\n// ============================================\n//\n// On WebKit/iOS WebGPU, decode speed is bound by GPU round-trips: the executor\n// groups `webkitGroupSize` dispatches per command buffer, then submits + drains\n// (queue.onSubmittedWorkDone) per group. Larger groups amortize the drains and\n// can be ~5x faster on iPad. BUT the safe ceiling is device-dependent in three\n// classes:\n// 1. Newer WebKit (iPad 26.5): high group is correct + fast.\n// 2. Older WebKit: high group yields zero/garbage logits (wrong output).\n// 3. iPhone (iOS 18.7): high group HARD-CRASHES the GPU process (page dies).\n//\n// The crash class is the hard one: a bad group kills the page before any code\n// can record the result. So we use a localStorage BREADCRUMB that OUTLIVES the\n// page kill: we persist the candidate we're about to try BEFORE running any\n// GPU-heavy work. If the page survives, a later promotion clears `trying` and\n// records it as known-good. If the page crashed, `trying` is still set on the\n// next load, so we KNOW that rung crashed and cap below it.\n//\n// The probe escalates UP from the safe floor (never starts optimistic — a\n// first-visit crash is a terrible UX) and persists per-device in localStorage.\n\nexport const WEBKIT_GROUP_PROBE_KEY = \"gerbil-webkit-group-v1\";\n\n/**\n * Candidate group-size ladder. We escalate UP one rung per page load. 128 is\n * treated as effectively \"batch-all\" for this model — kept simple on purpose.\n */\nexport const WEBKIT_GROUP_LADDER = [1, 8, 32, 64, 128] as const;\n\nexport type WebkitGroupProbe = {\n /** Largest group size proven crash-free AND correct on this device. Starts at 1. */\n knownGood: number;\n /** Candidate being attempted this page-load (null when not probing). */\n trying: number | null;\n /** True once we hit a crash/incorrect ceiling and should stop escalating. */\n capped: boolean;\n};\n\nconst DEFAULT_PROBE: WebkitGroupProbe = { knownGood: 1, trying: null, capped: false };\n\n/** Read the persisted WebKit group probe record (guarded; safe on node). */\nexport function readGroupProbe(): WebkitGroupProbe {\n if (typeof localStorage === \"undefined\") return { ...DEFAULT_PROBE };\n try {\n const raw = localStorage.getItem(WEBKIT_GROUP_PROBE_KEY);\n if (!raw) return { ...DEFAULT_PROBE };\n const parsed = JSON.parse(raw) as Partial<WebkitGroupProbe>;\n return {\n knownGood:\n typeof parsed.knownGood === \"number\" && parsed.knownGood >= 1 ? parsed.knownGood : 1,\n trying: typeof parsed.trying === \"number\" ? parsed.trying : null,\n capped: parsed.capped === true,\n };\n } catch {\n return { ...DEFAULT_PROBE };\n }\n}\n\n/** Persist the WebKit group probe record (guarded; no-op on node). */\nexport function writeGroupProbe(rec: WebkitGroupProbe): void {\n if (typeof localStorage === \"undefined\") return;\n try {\n localStorage.setItem(WEBKIT_GROUP_PROBE_KEY, JSON.stringify(rec));\n } catch {\n // Best-effort; private mode / quota can throw.\n }\n}\n\n/**\n * The validated batching target. Originally 128 from an iPad sweep on a much\n * slower engine build (peak 26.9 tok/s at 128, 256 within 2.6%); the 2026-07\n * kernel campaign made per-dispatch GPU time far smaller, which moves the\n * amortization optimum UP. An on-device iPhone sweep (bench harness, engine\n * 1.6.1) measured Qwen3.5-0.8B sampled decode: g32=19, g128≈33, g256=43,\n * g1024=45, g4096=44 — a +36% win at 1024 vs the old 128 target — while\n * LFM2.5 is flat from g32 upward (no cost). The crash breadcrumb still caps\n * any device that can't sustain it.\n */\nconst NONPHONE_TARGET_GROUP = 1024;\n\n/**\n * Resolve the WebKit group size to use this session, recording `trying` as a\n * side effect so a crash this load is detectable on the next load.\n *\n * Algorithm (only meaningful on WebKit; inert otherwise):\n * 1. Read the record (default {knownGood:1, trying:null, capped:false}).\n * 2. If `trying !== null` on entry → the previous load set it but never cleared\n * it → that load CRASHED at `trying`. Cap there, keep `knownGood`, clear\n * `trying`. Use `knownGood` this session.\n * 3. Else if !capped and there is a rung above `knownGood` → set `trying = next`,\n * persist BEFORE any GPU work, and use it (we're escalating).\n * 4. Else → use `knownGood`.\n *\n * @returns the group size to use this session.\n */\nexport function resolveWebkitGroupSize(args: {\n override?: number;\n isWebKit: boolean;\n /**\n * Memory-constrained devices (phones) are the \"crash class\": batching crashes\n * the GPU process, and discovering that costs one user-visible crash before the\n * breadcrumb caps it. When `conservative` is set we never auto-escalate — the\n * device stays at its proven floor (group=1 on first run) and never risks that\n * calibration crash. `?group=N` still lets such a device opt in explicitly.\n */\n conservative?: boolean;\n}): number {\n // Explicit ?group=N override wins and skips the probe entirely.\n if (args.override && args.override > 0) return args.override;\n // Non-WebKit (desktop / Dawn / node) never groups — floor of 1, no bookkeeping.\n if (!args.isWebKit) return 1;\n\n const rec = readGroupProbe();\n\n // Step 2: a stale `trying` means last load crashed at that rung.\n if (rec.trying !== null) {\n const crashedAt = rec.trying;\n const next: WebkitGroupProbe = {\n knownGood: rec.knownGood,\n trying: null,\n capped: true,\n };\n writeGroupProbe(next);\n console.log(\n `[engine] webkit group probe: previous load crashed at group=${crashedAt} → capping at knownGood=${next.knownGood}`,\n );\n return next.knownGood;\n }\n\n // Step 3: non-phone WebKit (iPad / Mac Safari) jumps straight to the validated\n // sweet spot (group=128) instead of climbing rung-by-rung — these devices\n // tolerate batching (iPad ran every rung to 256 coherently), so there's no\n // reason to crawl. The breadcrumb (Step 2) caps it down if a particular device\n // can't sustain it. Phones (conservative) NEVER escalate — they stay at the\n // proven floor (group=1) to avoid the one calibration crash batching costs on\n // the crash class.\n if (!rec.capped && !args.conservative && rec.knownGood < NONPHONE_TARGET_GROUP) {\n const next: WebkitGroupProbe = {\n knownGood: rec.knownGood,\n trying: NONPHONE_TARGET_GROUP,\n capped: false,\n };\n writeGroupProbe(next); // PERSIST BEFORE any GPU-heavy work runs\n console.log(\n `[engine] webkit group probe: trying target group=${NONPHONE_TARGET_GROUP} (knownGood=${rec.knownGood})`,\n );\n return NONPHONE_TARGET_GROUP;\n }\n\n // Step 4: nothing to escalate (capped or at top rung) — use the proven floor.\n console.log(\n `[engine] webkit group probe: knownGood=${rec.knownGood} trying=null capped=${rec.capped} → using ${rec.knownGood}`,\n );\n return rec.knownGood;\n}\n\n/**\n * Promote (or cap) the WebKit group probe after the first successful forward.\n *\n * Call this once per page-load, after the model has loaded AND a first forward\n * completed without the page dying. The breadcrumb already handles the crash\n * class (the page death leaves `trying` set for the next load); this handles the\n * wrong-output class and records success.\n *\n * @param correct true if the first forward produced non-corrupt output.\n * - correct → promote: knownGood = trying, trying = null.\n * - incorrect → cap: keep knownGood at the prior rung, trying = null, capped.\n */\nexport function promoteGroupProbe(correct: boolean): void {\n if (typeof localStorage === \"undefined\") return;\n const rec = readGroupProbe();\n // Nothing was being attempted this load — nothing to promote.\n if (rec.trying === null) return;\n\n if (correct) {\n writeGroupProbe({ knownGood: rec.trying, trying: null, capped: rec.capped });\n console.log(`[engine] webkit group probe: PROMOTED group=${rec.trying} to known-good`);\n } else {\n // Wrong-output class: this rung is incorrect (but did not crash). Keep the\n // prior knownGood and stop escalating.\n writeGroupProbe({ knownGood: rec.knownGood, trying: null, capped: true });\n console.log(\n `[engine] webkit group probe: group=${rec.trying} produced INCORRECT output → capping at knownGood=${rec.knownGood}`,\n );\n }\n}\n","/**\n * WebGPUEngine -- gerbil's native WebGPU inference engine.\n *\n * Public API:\n * const engine = await WebGPUEngine.create({ repo: \"Qwen/Qwen3.5-0.8B\" });\n * const result = await engine.generate(\"What is 2+2?\");\n * engine.destroy();\n */\n\nimport {\n dequantizeGemma4VisionProjection,\n ensureGemma4VisionEmbedderNorms,\n generateGemma4VisionGraph,\n patchGemma4VisionClips,\n resolveGemma4VisionInfo,\n} from \"./architectures/gemma4_vision.js\";\nimport type { KvMode } from \"./architectures/index.js\";\nimport { generateQwen3_5VisionGraph } from \"./architectures/qwen3_5_vision.js\";\nimport type { GPUContext, GPUDiagnosticResult } from \"./device.js\";\nimport { clearPipelineCache, initGPU, verifyGPU } from \"./device.js\";\nimport { Executor } from \"./executor.js\";\nimport type { ModelArchConfig, ModelCapabilities, ModelGraph } from \"./ir.js\";\nimport { type KaniDType, KaniTTS } from \"./kani-tts.js\";\nimport { buildLoRADeltas, fetchAdapter, type LoRADelta } from \"./lora.js\";\nimport { createKeyMapperForArch, type LoadModelOptions, loadModel } from \"./model-loader.js\";\n\nexport { createDefaultHFKeyMapper } from \"./ir.js\";\n// LoRA adapter (\"flavor\") loading — public engine capability. High-level users go\n// through Gerbil.loadAdapter; these are the primitives (also used by tests + the\n// serving side to parse/merge adapters directly).\nexport {\n type AdapterConfig,\n type AdapterSource,\n applyLoRAToStore,\n buildLoRADeltas,\n fetchAdapter,\n type LoRADelta,\n splitFusedQGateDelta,\n} from \"./lora.js\";\n\nimport { cleanSuggestion } from \"./autocomplete-clean.js\";\nimport {\n RequestScheduler,\n type SchedulerHost,\n type ServeOptions,\n type ServeResult,\n} from \"./batch/scheduler.js\";\nimport { Swarm, type SwarmOptions } from \"./batch/swarm.js\";\nimport { type GepardDType, GepardTTS } from \"./gepard-tts.js\";\nimport { loadOuteSpeaker, type OuteDType, type OuteSpeaker, OuteTTS } from \"./outetts.js\";\nimport { type ParlerSpeakOptions, ParlerTTS } from \"./parler-tts.js\";\nimport { type SamplingParams, sampleToken } from \"./sampler.js\";\nimport type { ChatMessage, Tokenizer } from \"./tokenizer.js\";\nimport type { VisionExecutor } from \"./vision-executor.js\";\nimport { VisionExecutor as VisionExecutorImpl } from \"./vision-executor.js\";\nimport {\n buildGemma4VisionPositionTensors,\n buildMRoPECosSin,\n buildMRoPEPositionIds,\n buildVisionPositionTensors,\n type ImageProcessorConfig,\n preprocessImage,\n preprocessImageGemma4,\n QWEN3_5_IMAGE_PROCESSOR,\n} from \"./vision-preprocess.js\";\nimport { remapPrunedToken } from \"./vocab-prune.js\";\n\n// Per-capability default models live in a standalone module so the React hooks\n// can resolve defaults without statically importing this (heavy) engine module.\nexport {\n DEFAULT_MODELS,\n isTTSRepo,\n OUTETTS_ASSETS,\n OUTETTS_PRESET_VOICES,\n resolveDefaultRepo,\n} from \"./defaults.js\";\n\nimport { promoteGroupProbe, resolveWebkitGroupSize } from \"../browser/device-guards.js\";\nimport {\n DEFAULT_MODELS,\n isTTSRepo,\n OUTETTS_ASSETS,\n OUTETTS_PRESET_VOICES,\n resolveDefaultRepo,\n} from \"./defaults.js\";\n\nexport interface WebGPUEngineOptions extends Omit<LoadModelOptions, \"repo\"> {\n /**\n * HuggingFace repo ID (e.g. \"mlx-community/Qwen3.5-0.8B-4bit\") or full URL.\n * Optional — when omitted, a sensible default is chosen for the requested\n * capability (text, vision, or embeddings). See {@link DEFAULT_MODELS}.\n */\n repo?: string;\n /** Max sequence length (default: from model config, capped at 4096). */\n maxSeqLen?: number;\n /** Override KV mode: \"f32\", \"native-f16\", or \"packed-f16\". Auto-detected if omitted. */\n kvMode?: KvMode;\n /**\n * Build the vision encoder (Qwen3.5 ViT) alongside the text model so\n * `encodeImage()` can turn image patches into merged image-embedding tokens.\n * Only valid for vision-capable checkpoints (Qwen3.5). Downloads the ~192MB\n * vision tower. Default: false.\n */\n enableVision?: boolean;\n /** Max patches the vision encoder can process in one call (default 4096). */\n maxVisionPatches?: number;\n}\n\nexport interface EncodeImageResult {\n /** Merged image-embedding tokens, row-major [rows * dim]. */\n embeds: Float32Array;\n /** Number of merged tokens (numPatches / spatial_merge_size^2). */\n rows: number;\n /** Embedding dimension (out_hidden_size, 1024 for Qwen3.5). */\n dim: number;\n}\n\nexport interface EmbedOptions {\n /**\n * Instruction prefix for query embeddings (Qwen3-Embedding convention:\n * \"Instruct: {task}\\nQuery:{text}\"). Omit for document embeddings.\n */\n instruction?: string;\n /**\n * EmbeddingGemma task prefix. The model is asymmetric: queries and documents\n * use different prefixes (`task: search result | query: ` vs `title: none |\n * text: `). Pass \"query\" for search queries and \"document\" for the corpus\n * being searched. Defaults to \"query\" for EmbeddingGemma when omitted. Ignored\n * by non-Gemma embedding models (use `instruction` for Qwen3-Embedding).\n */\n taskType?: \"query\" | \"document\";\n /**\n * Override the raw task prefix prepended to the text (EmbeddingGemma). When\n * set, takes precedence over `taskType`. Use for non-retrieval tasks, e.g.\n * \"task: clustering | query: \" or \"task: classification | query: \".\n */\n taskPrompt?: string;\n /** Max tokens to encode (longer inputs are truncated). Default: model context, capped at maxSeqLen. */\n maxTokens?: number;\n}\n\n/** EmbeddingGemma task prefixes (from config_sentence_transformers.json prompts). */\nconst EMBEDDING_GEMMA_PROMPTS = {\n query: \"task: search result | query: \",\n document: \"title: none | text: \",\n} as const;\n\nexport interface GenerateOptions {\n /** Max tokens to generate (default: 512). */\n maxTokens?: number;\n /** Stop generation on these strings. */\n stopSequences?: string[];\n /** Sampling parameters. */\n sampling?: SamplingParams;\n /** System prompt to prepend. */\n systemPrompt?: string;\n /** Callback for each generated token (for streaming). */\n onToken?: (token: string, meta?: { tokenIndex: number; tps: number; elapsedMs: number }) => void;\n}\n\nexport interface GenerateResult {\n /** Generated text. */\n text: string;\n /** Number of tokens generated. */\n tokensGenerated: number;\n /** Tokens per second. */\n tokensPerSecond: number;\n /** Total generation time in ms. */\n totalTime: number;\n /** Why generation stopped. */\n finishReason: \"eos\" | \"max_tokens\" | \"stop_sequence\";\n /**\n * Decode-only wall time in ms (excludes prefill). Set by the batched path\n * (generateBatch) so aggregate decode throughput is measurable directly.\n */\n decodeTime?: number;\n /**\n * Raw generated token ids, in order. Used by parity harnesses (e.g. the\n * paged-KV token-exactness gate) to compare runs without decode ambiguity.\n */\n tokenIds?: number[];\n /** Thinking content if model produced it (future). */\n thinking?: string;\n}\n\n/**\n * A minimal JSON-schema-ish shape used by {@link WebGPUEngine.generateObject} to\n * validate generated output without pulling in a schema library. Only `required`\n * and `properties` are inspected (presence of required keys). Pass a predicate\n * function instead for arbitrary validation.\n */\nexport interface ObjectSchema {\n /** Keys that must be present on the parsed object. */\n required?: string[];\n /** Property descriptors (only the key set is used for validation). */\n properties?: Record<string, unknown>;\n /** Allow extra schema fields (type, etc.) without TS complaints. */\n [key: string]: unknown;\n}\n\n/** Validator for {@link WebGPUEngine.generateObject}: a schema object or predicate. */\nexport type ObjectValidator<T = unknown> = ObjectSchema | ((o: T) => boolean);\n\nexport interface GenerateObjectOptions extends GenerateOptions {\n /**\n * Validation target. Either a predicate `(o) => boolean` or a minimal\n * JSON-schema-ish object with `required`/`properties` (required keys must\n * exist). Omit to only require syntactically valid JSON.\n */\n schema?: ObjectValidator;\n /**\n * Max RETRIES after the first attempt (so up to `maxRetries + 1` generations).\n * Default: 4.\n */\n maxRetries?: number;\n}\n\nexport interface GenerateObjectResult<T = unknown> {\n /** The parsed + validated object (or array). */\n object: T;\n /** The raw model text the object was extracted from. */\n text: string;\n /** How many generation attempts it took (1 = first try). */\n attempts: number;\n}\n\nexport interface IntegrityCheckEntry {\n label: string;\n length: number;\n sum: number;\n first4: number[];\n argmax: number;\n maxVal: number;\n match?: \"PASS\" | \"FAIL\";\n refSum?: number;\n refArgmax?: number;\n error?: string;\n note?: string;\n}\n\nexport interface IntegrityCheckResult {\n checks: IntegrityCheckEntry[];\n allPass: boolean;\n}\n\n/**\n * Extract the first complete JSON object or array from a model's text output.\n *\n * Tolerant of prose, markdown, and ```json code fences: it scans for the first\n * `{` or `[`, then walks forward tracking string/escape state and brace/bracket\n * depth to find the matching close, returning the balanced substring. Returns\n * `undefined` when no JSON-looking span is present. Used by\n * {@link WebGPUEngine.generateObject}.\n */\nfunction extractJson(text: string): string | undefined {\n // Strip code-fence markers; the brace scan below ignores surrounding prose.\n const cleaned = text.replace(/```(?:json)?/gi, \"\");\n const start = cleaned.search(/[{[]/);\n if (start === -1) return undefined;\n const open = cleaned[start];\n const close = open === \"{\" ? \"}\" : \"]\";\n let depth = 0;\n let inString = false;\n let escaped = false;\n for (let i = start; i < cleaned.length; i++) {\n const ch = cleaned[i];\n if (inString) {\n if (escaped) {\n escaped = false;\n } else if (ch === \"\\\\\") {\n escaped = true;\n } else if (ch === '\"') {\n inString = false;\n }\n continue;\n }\n if (ch === '\"') {\n inString = true;\n } else if (ch === open) {\n depth++;\n } else if (ch === close) {\n depth--;\n if (depth === 0) return cleaned.slice(start, i + 1);\n }\n }\n return undefined;\n}\n\n/**\n * The main WebGPU inference engine.\n *\n * Usage:\n * const engine = await WebGPUEngine.create({ repo: \"Qwen/Qwen3.5-0.8B\" });\n * const result = await engine.generate(\"Hello!\");\n * console.log(result.text);\n * engine.destroy();\n */\n\n/** System prompt that locks the model into \"continue the text\" autocomplete mode. */\nconst AUTOCOMPLETE_SYSTEM = [\n \"You are an inline autocomplete engine.\",\n \"Continue the user's text with a brief, natural continuation of the SAME sentence or thought.\",\n \"Output ONLY the continuation text — no preamble, no quotes, no explanations, no assistant voice.\",\n \"Do not answer questions; just continue the writing.\",\n 'Example — input: \"The quick brown fox\" → continuation: \" jumps over the lazy dog.\"',\n].join(\" \");\n\n/** A tool the agent loop can call. Framework-agnostic; pass `defineTool` output or a plain object. */\nexport interface AgentTool {\n name: string;\n description: string;\n /** Optional JSON-schema-ish parameter description shown to the model. */\n parameters?: unknown;\n execute: (args: any) => Promise<string> | string;\n}\n\n/** One step of an agentic tool-calling run, for trace UIs. */\nexport type AgentStep =\n | { kind: \"tool_call\"; tool: string; args: unknown }\n | { kind: \"tool_result\"; tool: string; result: string }\n | { kind: \"answer\"; text: string };\n\nfunction formatAgentToolsPrompt(tools: AgentTool[]): string {\n const defs = tools\n .map(\n (t) =>\n `## ${t.name}\\nDescription: ${t.description}\\nParameters: ${JSON.stringify(\n t.parameters ?? { type: \"object\", properties: {} },\n )}`,\n )\n .join(\"\\n\\n\");\n return `You are a helpful assistant with access to tools.\n\n# Tools\n\n${defs}\n\n## How to call a tool\n\nReply with ONLY:\n<tool_call>\n{\"name\": \"tool_name\", \"arguments\": {\"param\": \"value\"}}\n</tool_call>\n\nWhen you have the final answer, reply normally with no tool_call.`;\n}\n\nfunction parseAgentToolCall(text: string): { name: string; args: unknown } | null {\n const tagged = text.match(/<tool_call>\\s*([\\s\\S]*?)\\s*<\\/tool_call>/);\n const json = tagged ? tagged[1] : (text.match(/\\{\\s*\"name\"\\s*:[\\s\\S]*\\}/)?.[0] ?? null);\n if (!json) {\n return null;\n }\n try {\n const parsed = JSON.parse(json) as {\n name?: string;\n arguments?: unknown;\n args?: unknown;\n };\n if (typeof parsed.name === \"string\") {\n return { name: parsed.name, args: parsed.arguments ?? parsed.args ?? {} };\n }\n } catch {\n // not a valid tool call\n }\n return null;\n}\n\nexport class WebGPUEngine {\n // ── Base text-model resources ──\n // These are null on a TTS-only engine (created via `create({ repo: <tts> })`),\n // which skips GPU init + the single-graph base load and lazily builds the\n // dedicated native TTS engine on the first speak(). The private getters below\n // throw a clear error if a base-model op is attempted on such an engine.\n private _ctx: GPUContext | null;\n private _executor: Executor | null;\n private _tokenizer: Tokenizer | null;\n private get ctx(): GPUContext {\n if (!this._ctx) throw new Error(WebGPUEngine.TTS_LITE_ERROR);\n return this._ctx;\n }\n private get executor(): Executor {\n if (!this._executor) throw new Error(WebGPUEngine.TTS_LITE_ERROR);\n return this._executor;\n }\n private get tokenizer(): Tokenizer {\n if (!this._tokenizer) throw new Error(WebGPUEngine.TTS_LITE_ERROR);\n return this._tokenizer;\n }\n private static readonly TTS_LITE_ERROR =\n \"This engine was created for a TTS checkpoint; base-model ops (generate/embed/describeImage) are unavailable. Use speak() / encodeSpeaker().\";\n private _destroyed = false;\n private _isEmbedding: boolean;\n /** HF architecture string (e.g. \"Gemma3TextModel\", \"Qwen3ForCausalLM\"). */\n private _architecture: string;\n /** Vision encoder (built only when enableVision and the model is vision-capable). */\n private visionExecutor: VisionExecutor | null;\n /** Raw vision_config (for host preprocessing of grids). */\n private visionConfig: Record<string, unknown> | null;\n /** Raw pos_embed.weight table for bilinear interpolation. */\n private visionPosEmbedTable: Float32Array | null;\n /** True when the LM graph was built with the multimodal (M-RoPE + splice) path. */\n private _multimodalGraph: boolean;\n /** Raw config.json (for M-RoPE params: mrope_section, rope_theta, partial factor). */\n private rawConfig: Record<string, unknown> | null;\n /** Effective max sequence length (cos/sin table coverage). */\n private maxSeqLen: number;\n /** Original create() options (used to lazily spin up the Kani-TTS engine for speak()). */\n private _createOptions: WebGPUEngineOptions;\n /** Lazily-created Kani-TTS engine (codec-LM + NanoCodec) backing speak(). */\n private _kaniTTS: KaniTTS | null = null;\n /** Lazily-created OuteTTS engine (Qwen3-0.6B codec-LM + DAC.speech) backing speak(). */\n private _outeTTS: OuteTTS | null = null;\n /** The preset voice the lazily-built OuteTTS engine was created with. */\n private _outeVoice: string | null = null;\n /** Source of the runtime LoRA adapter currently applied on the static base, if any. */\n private _currentAdapter: string | null = null;\n /** Named adapters registered for per-lane batched decode (GERBIL_BATCH_LORA). */\n private _batchAdapters = new Map<string, { id: number; deltas: LoRADelta[] }>();\n /** Lazily-created Parler-TTS engine (Flan-T5 encoder + decoder LM + dac_44khz). */\n private _parlerTTS: ParlerTTS | null = null;\n /** Lazily-created Gepard-1.0 engine (Qwen3.5 multihead codec-LM + NanoCodec 21.5 fps). */\n private _gepardTTS: GepardTTS | null = null;\n /** Lazily-created continuous-batching scheduler (GERBIL_BATCH, Phase 5). */\n private _scheduler: RequestScheduler | null = null;\n\n /**\n * WebKit group-size probe state. When true, a candidate group size is being\n * tried this page-load and must be promoted (or capped) after the FIRST\n * successful forward produces non-corrupt logits. Goes false once handled so\n * promotion runs at most once per session. Always false on Dawn/node.\n */\n private _groupProbePending = false;\n\n /**\n * Tail of the per-engine generation queue. The shared {@link Executor} owns a\n * single set of readback/staging buffers (logits + argmax) and one KV cache, so\n * two overlapping generate()/embed()/describeImage() calls on the SAME engine\n * instance would call `mapAsync` on the logits/argmax readback while a prior map\n * is still pending (\"Buffer already has an outstanding map pending\") and corrupt\n * each other's KV state. The browser SDK shares one engine per model across\n * components (see SHARED_ENGINES in browser/use-engine.ts), so this overlap is\n * real — e.g. a playground's chat handle and its example-generator on the same\n * instance. We serialize whole generations through this promise chain: a second\n * caller awaits the first. Per-engine and only engaged on genuine overlap, so it\n * adds no per-token overhead to the decode hot path.\n */\n private _genQueueTail: Promise<void> = Promise.resolve();\n\n /** Model capabilities (text, vision, moe). */\n readonly capabilities: ModelCapabilities;\n /** Model architecture config (null on a TTS-only lite engine). */\n private readonly _config: ModelArchConfig | null;\n /** Model architecture config. Throws on a TTS-only lite engine. */\n get config(): ModelArchConfig {\n if (!this._config) throw new Error(WebGPUEngine.TTS_LITE_ERROR);\n return this._config;\n }\n\n private constructor(\n ctx: GPUContext | null,\n executor: Executor | null,\n tokenizer: Tokenizer | null,\n graph: ModelGraph | null,\n opts: {\n multimodalGraph: boolean;\n rawConfig: Record<string, unknown>;\n maxSeqLen: number;\n createOptions: WebGPUEngineOptions;\n /** True if a WebKit group-size candidate is being probed this session. */\n groupProbePending?: boolean;\n },\n vision?: {\n executor: VisionExecutor;\n config: Record<string, unknown>;\n posEmbedTable: Float32Array;\n } | null,\n ) {\n this._ctx = ctx;\n this._executor = executor;\n this._tokenizer = tokenizer;\n // A TTS-only engine has no base text graph; capabilities/config/architecture\n // are placeholders (speak() routes purely off the repo). Everything else\n // reads through the private getters, which throw if a base op is attempted.\n this.capabilities = graph?.capabilities ?? { text: true, vision: false, moe: false };\n this._config = graph?.config ?? null;\n this._isEmbedding = graph?.outputs.includes(\"embedding\") ?? false;\n this._architecture = graph?.architecture ?? \"\";\n this.visionExecutor = vision?.executor ?? null;\n this.visionConfig = vision?.config ?? null;\n this.visionPosEmbedTable = vision?.posEmbedTable ?? null;\n this._multimodalGraph = opts.multimodalGraph;\n this.rawConfig = opts.rawConfig;\n this.maxSeqLen = opts.maxSeqLen;\n this._createOptions = opts.createOptions;\n this._groupProbePending = opts.groupProbePending ?? false;\n }\n\n /** True if this engine has a vision encoder built (use encodeImage()). */\n get hasVision(): boolean {\n return this.visionExecutor !== null;\n }\n\n /** Per-opType decode GPU-time breakdown (only populated under GERBIL_PROFILE). */\n getDecodeProfile(): Array<{ opType: string; ns: number; count: number }> {\n return this.executor.getProfile();\n }\n\n /** Clear accumulated decode profiler data (e.g. to drop warm-up tokens). */\n resetDecodeProfile(): void {\n this.executor.resetProfile();\n }\n\n /** Profile ONE real decode step (the pipelined-greedy kernels). Token-independent\n * timing — pass any valid id. Only meaningful under GERBIL_PROFILE. */\n async profileDecodeStep(tokenId: number): Promise<void> {\n await this.executor.profileDecodeStep(tokenId);\n }\n\n /** Decode dispatch count + the device's storage-buffer limit (which gates the\n * INT4 projection fusions). Lets the iPad runner report whether fusions applied\n * on-device or silently fell back (8 < 9 ⇒ more dispatches ⇒ more mobile drains). */\n getDecodeStats(): { dispatches: number; maxStorageBuffers: number } {\n return {\n dispatches: this.executor.decodeDispatchCount,\n maxStorageBuffers: this.executor.maxStorageBuffers,\n };\n }\n\n // ── Runtime LoRA adapters (\"flavors\") ─────────────────────────────────\n //\n // Apply — or hot-swap — a LoRA adapter on the ALREADY-LOADED base at runtime,\n // as low-rank correction kernels layered on the static (INT4 or float) base.\n // The base weights are never re-quantized or re-uploaded: a tuned model = the\n // resident base + a few-MB adapter. Different adapters swap on the same warm\n // engine (the A/B factor buffers are rebuilt; the base is untouched), and\n // `loadAdapter(null)` removes the correction entirely.\n\n /**\n * Load, swap, or remove a runtime LoRA adapter on the loaded base.\n *\n * @param source Adapter spec (`hf:owner/repo`, a URL, or `file:./dir` holding\n * `adapter_config.json` + `adapter_model.safetensors`), or `null` to drop it.\n */\n async loadAdapter(source: string | null): Promise<void> {\n if (source === null) {\n this.executor.clearRuntimeLoRA();\n this._currentAdapter = null;\n return;\n }\n const adapter = await fetchAdapter(source, {\n hfToken: this._createOptions.hfToken,\n revision: this._createOptions.revision,\n });\n if (!adapter) {\n throw new Error(`No adapter found at ${source}.`);\n }\n const keyMapper = createKeyMapperForArch(this._architecture);\n const deltas = buildLoRADeltas(adapter, keyMapper);\n const { applied, skipped } = this.executor.applyRuntimeLoRA(deltas);\n if (applied === 0) {\n throw new Error(\n `Adapter ${source} resolved to 0 applicable runtime targets on ${this._architecture} (skipped ${skipped}).`,\n );\n }\n console.log(\n `[engine] runtime adapter ${source}: applied ${applied} target(s)${skipped ? `, skipped ${skipped}` : \"\"}.`,\n );\n this._currentAdapter = source;\n }\n\n /** The runtime LoRA adapter currently applied on the base, or null. */\n getAdapter(): string | null {\n return this._currentAdapter;\n }\n\n /**\n * Register a named LoRA adapter for per-lane batched decode (SGMV phase 1,\n * `GERBIL_BATCH=N` + `GERBIL_BATCH_LORA=1`). The adapter's factors are\n * fetched and packed into the executor's shared factor buffers ONCE; any\n * number of batch lanes can then run it concurrently by passing its name in\n * `generateBatch`'s per-lane `adapters` option. Registering the same name\n * twice is a no-op.\n */\n async registerAdapter(name: string, source: string): Promise<void> {\n this.checkDestroyed();\n if (!this.executor.batchLoraEnabled) {\n throw new Error(\n \"registerAdapter requires GERBIL_BATCH=N (N >= 2) and GERBIL_BATCH_LORA=1 on the Dawn path\",\n );\n }\n if (this._batchAdapters.has(name)) return;\n const adapter = await fetchAdapter(source, {\n hfToken: this._createOptions.hfToken,\n revision: this._createOptions.revision,\n });\n if (!adapter) {\n throw new Error(`No adapter found at ${source}.`);\n }\n const keyMapper = createKeyMapperForArch(this._architecture);\n const deltas = buildLoRADeltas(adapter, keyMapper);\n const id = this.executor.registerBatchAdapter(deltas);\n this._batchAdapters.set(name, { id, deltas });\n console.log(`[engine] batch adapter \"${name}\" (${source}) registered as id ${id}.`);\n }\n\n /** Names of the adapters registered for per-lane batched decode. */\n getRegisteredAdapters(): string[] {\n return [...this._batchAdapters.keys()];\n }\n\n /**\n * Write a coarse crash-phase breadcrumb that survives a GPU-process kill / page\n * reload. The iPad harness reads `localStorage[\"gerbil-crash-phase\"]` after a\n * crash; without these, a describe-time crash only shows the last load phase\n * (\"engine:ready\"). The describe path tags vit-encode / splice / text-decode so\n * the next run shows WHERE it died, not just \"crashed after load\".\n */\n private setPhase(phase: string): void {\n try {\n if (typeof localStorage !== \"undefined\") {\n localStorage.setItem(\"gerbil-crash-phase\", phase);\n }\n } catch {\n // localStorage can throw in private mode / cross-origin; telemetry is best-effort.\n }\n }\n\n /** True if this engine was loaded as an embedding model (use embed(), not generate()). */\n get isEmbedding(): boolean {\n return this._isEmbedding;\n }\n\n /**\n * WebKit group-size probe promotion hook. Runs at most once per session, after\n * the FIRST forward completes without the page dying. If the page had crashed\n * at this group size, this code never runs and the localStorage breadcrumb\n * (left by the resolver) caps the device on the next load — that is what makes\n * the probe survive the crash class. Here we additionally handle the\n * wrong-output class by inspecting the first forward's logits for corruption\n * (NaN / Inf / all-zero / all-same), reusing the same signals as integrityCheck().\n */\n private maybePromoteGroupProbe(logits: Float32Array): void {\n if (!this._groupProbePending) return;\n this._groupProbePending = false; // promote at most once per session\n\n // Sample a prefix (full-vocab scans are wasteful; corruption shows up early).\n const n = Math.min(logits.length, 256);\n let allZero = true;\n let allSame = true;\n let finite = true;\n const first = logits[0];\n for (let i = 0; i < n; i++) {\n const v = logits[i];\n if (!Number.isFinite(v)) {\n finite = false;\n break;\n }\n if (v !== 0) allZero = false;\n if (v !== first) allSame = false;\n }\n const correct = finite && !allZero && !allSame;\n promoteGroupProbe(correct);\n }\n\n /**\n * Create and initialize a WebGPUEngine.\n *\n * Downloads the model from HuggingFace, compiles shaders, uploads weights.\n */\n static async create(options: WebGPUEngineOptions = {}): Promise<WebGPUEngine> {\n // Fill in the default model for the requested capability when no repo is\n // given, so callers can `create()` / `create({ embedding: true })` and it\n // just works, while any explicit `repo` is still honored everywhere below.\n options = { ...options, repo: resolveDefaultRepo(options) };\n\n // ── TTS checkpoints: defer to the dedicated native engine ──\n // Kani (conv-backbone codec-LM), OuteTTS (Qwen3 codec-LM), and Parler\n // (encoder-decoder) are NOT loadable as a single text graph — feeding them\n // through the base loader errors at load (e.g. Kani's \"No GPU buffer for\n // tensor layers.0.conv.in_proj.weight\", Parler's \"not loadable via the\n // single-graph generate() path\"). Return a lightweight TTS-only engine that\n // stores these options and builds the correct native TTS engine\n // (_kaniTTS / _outeTTS / _parlerTTS) lazily on the first speak(). This is the\n // low-level path used by the browser `useTTS` hook.\n if (isTTSRepo(options.repo)) {\n return WebGPUEngine._buildTTSLite(options);\n }\n\n // Initialize WebGPU\n const ctx = await initGPU();\n\n // A failed build — most commonly an iOS OOM mid weight-upload — would\n // otherwise leak the just-allocated GPUDevice and its ~400MB of buffers for\n // the page's lifetime, and a retry would stack another ~400MB on top → a\n // death spiral that crashes the tab (and reads as \"crashes even after a\n // clean cache / reboot\"). Tear the device down on ANY failure.\n try {\n return await WebGPUEngine._buildFromContext(ctx, options);\n } catch (err) {\n try {\n ctx.device.destroy();\n } catch {\n /* device may already be lost on a hard OOM */\n }\n throw err;\n }\n }\n\n /**\n * Build a lightweight TTS-only engine: no GPU device is initialized and no base\n * text graph is loaded. It stores the create() options; the first `speak()`\n * (or `encodeSpeaker()`) lazily builds the dedicated native TTS engine —\n * {@link KaniTTS}, {@link OuteTTS}, or {@link ParlerTTS} — which brings its own\n * GPU device and weights. Base-model ops throw {@link WebGPUEngine.TTS_LITE_ERROR}.\n */\n private static _buildTTSLite(options: WebGPUEngineOptions): WebGPUEngine {\n return new WebGPUEngine(\n null,\n null,\n null,\n null,\n {\n multimodalGraph: false,\n rawConfig: {},\n // Sequence bound handed to the native TTS engine on first speak(); TTS\n // clips are short, so a modest default is ample (callers can override).\n maxSeqLen: options.maxSeqLen ?? 2048,\n createOptions: options,\n },\n null,\n );\n }\n\n private static async _buildFromContext(\n ctx: Awaited<ReturnType<typeof initGPU>>,\n options: WebGPUEngineOptions,\n ): Promise<WebGPUEngine> {\n // ── Detect environment ──\n const isBrowser = typeof navigator !== \"undefined\" && typeof location !== \"undefined\";\n const isSafari =\n isBrowser && /Safari/.test(navigator.userAgent) && !/Chrome/.test(navigator.userAgent);\n\n // ── URL parameter overrides (browser only) ──\n const params = isBrowser ? new URLSearchParams(location.search) : null;\n const forceKvF32 = params?.has(\"kvf32\");\n const maxSeqOverride = params?.get(\"maxseq\");\n const groupOverride = params?.get(\"group\");\n\n // ── Determine KV mode ──\n // Priority: explicit option > URL param > auto-detect\n let kvMode: KvMode;\n if (options.kvMode) {\n kvMode = options.kvMode;\n } else if (forceKvF32) {\n kvMode = \"f32\";\n } else if (isSafari && ctx.hasF16) {\n // Safari/WebKit miscompiles native f16 types — use packed u32 + unpack2x16float\n kvMode = \"packed-f16\";\n } else if (ctx.hasF16) {\n kvMode = \"native-f16\";\n } else {\n kvMode = \"f32\";\n }\n\n const kvDtype = kvMode === \"f32\" ? \"f32\" : \"f16\";\n\n console.log(\n `[engine] kvMode: ${kvMode}, kvDtype: ${kvDtype}, f16 supported: ${ctx.hasF16}, safari: ${isSafari}`,\n );\n\n // Crash-phase tracking for mobile debugging (survives tab crash)\n const setPhase = (phase: string) => {\n try {\n if (typeof localStorage !== \"undefined\") localStorage.setItem(\"gerbil-crash-phase\", phase);\n } catch {}\n };\n\n // Load model (config, tokenizer, weights). When vision is enabled, build the\n // multimodal LM graph variant (M-RoPE + vision-embedding splice); text-only\n // generation through it is numerically identical to the plain graph.\n setPhase(\"engine:loading-model\");\n // Mobile WebKit has a ~few-second GPU watchdog and a tight (~1.5-2GB) jetsam\n // budget. The ViT Attention op is a single O(N²) dispatch over N patches, so a\n // large N both over-reserves memory and risks a watchdog kill. The host caps\n // the longest image side (≈448px → a few hundred patches), so reserve far\n // fewer patches on WebKit. Desktop/Dawn keeps the roomy 4096 ceiling.\n const maxVisionPatches = options.maxVisionPatches ?? (ctx.isWebKitWebGPU ? 1024 : 4096);\n const multimodal = options.enableVision\n ? { maxVisionTokens: Math.ceil(maxVisionPatches / 4) }\n : undefined;\n const { graph, tokenizer, weights, rawConfig, pleSource } = await loadModel({\n ...options,\n repo: resolveDefaultRepo(options), // resolves to a string (already filled above)\n kvDtype,\n multimodal,\n });\n setPhase(`engine:model-loaded:${weights.size}-weights`);\n\n // ── Vision tower (opt-in) ──\n // Build BEFORE the text executor's uploadWeights() consumes/deletes the\n // weight entries. The vision tower needs its own f32 copy of visual.* and the\n // raw pos_embed table for host bilinear interpolation.\n let visionBundle: {\n executor: VisionExecutor;\n config: Record<string, unknown>;\n posEmbedTable: Float32Array;\n } | null = null;\n // Gate on the checkpoint actually shipping a vision tower (vision_config +\n // tower weights), not the text graph's capability flag (which describes\n // the text graph only). Two families are supported:\n // • Qwen3.5 ViT — \"visual.*\" weights, \"visual.pos_embed.weight\" table\n // • Gemma 4 ViT — \"vision_tower.*\" weights, axial pos-embed table\n // \"vision_tower.patch_embedder.position_embedding_table\"\n const hasVisionConfig = rawConfig.vision_config != null;\n const isGemma4Vision =\n ((rawConfig.vision_config as Record<string, unknown> | undefined)?.model_type as string) ===\n \"gemma4_vision\" || [...weights.keys()].some((k) => k.startsWith(\"vision_tower.\"));\n const visPosKey = isGemma4Vision\n ? \"vision_tower.patch_embedder.position_embedding_table\"\n : \"visual.pos_embed.weight\";\n const towerPrefix = isGemma4Vision ? \"vision_tower.\" : \"visual.\";\n const hasVisualWeights = weights.keys().some((k) => k.startsWith(towerPrefix));\n const wantVision = Boolean(options.enableVision && hasVisionConfig);\n if (wantVision && hasVisualWeights) {\n const visGraph = isGemma4Vision\n ? generateGemma4VisionGraph(rawConfig)\n : generateQwen3_5VisionGraph(rawConfig);\n const maxPatches = maxVisionPatches;\n // Drain the vision-tower tensors (+ projector / pos-embed) out of the\n // WeightSource into a heap Map so the existing (synchronous, Map-based)\n // vision-prep helpers and VisionExecutor.uploadWeights keep working\n // unchanged. The tower is ~201 MB BF16 and only materialized when vision is\n // explicitly enabled — bounded, and disjoint from the text weights the text\n // executor streams below.\n const visWeights = new Map<string, { data: ArrayBufferView; shape: number[] }>();\n for (const k of weights.keys()) {\n if (k.startsWith(towerPrefix) || k.startsWith(\"embed_vision.\") || k === visPosKey) {\n const w = await weights.get(k);\n if (w) visWeights.set(k, w);\n }\n }\n // Patch Gemma 4 ClippableLinear clip scalars into the graph + drop them,\n // and dequantize the MLX-int4 projector (no-op for BF16 checkpoints).\n if (isGemma4Vision) {\n patchGemma4VisionClips(visGraph, visWeights);\n const gi = resolveGemma4VisionInfo(rawConfig);\n const qc = (rawConfig.quantization_config ?? rawConfig.quantization) as\n | Record<string, unknown>\n | undefined;\n const projGroupSize = (qc?.group_size as number) ?? 64;\n dequantizeGemma4VisionProjection(visWeights, projGroupSize, gi.textHidden, gi.hiddenSize);\n // Synthesize the multimodal-embedder norm gains (post-projection norm is\n // no-scale → ones; soft_embedding_norm falls back to ones if a lean export\n // omits it). The post-projection RMSNorm rescales the image soft tokens to\n // the text-embedding magnitude so the LM actually attends to the image.\n ensureGemma4VisionEmbedderNorms(visWeights, gi.hiddenSize, gi.textHidden);\n }\n const visExec = new VisionExecutorImpl(ctx, visGraph, maxPatches);\n // Snapshot the pos-embed table before uploadWeights consumes it.\n const posW = visWeights.get(visPosKey);\n const posTable =\n posW && posW.data instanceof Float32Array\n ? new Float32Array(posW.data) // copy — weights map entry will be uploaded+freed\n : posW\n ? new Float32Array(\n posW.data.buffer,\n posW.data.byteOffset,\n posW.data.byteLength / 4,\n ).slice()\n : null;\n await visExec.uploadWeights(visWeights); // reads (does not delete) tower constants\n visExec.initBindGroups();\n if (posTable) {\n visionBundle = {\n executor: visExec,\n config: (rawConfig.vision_config as Record<string, unknown>) ?? rawConfig,\n posEmbedTable: posTable,\n };\n }\n }\n\n // ── Determine max sequence length ──\n let maxSeqLen: number;\n if (maxSeqOverride) {\n maxSeqLen = Math.min(Number.parseInt(maxSeqOverride, 10), graph.config.context_length);\n } else if (forceKvF32 && isSafari) {\n // f32 KV on Safari = 2x memory; cap at 1024 to avoid OOM\n maxSeqLen = Math.min(options.maxSeqLen ?? 1024, graph.config.context_length, 1024);\n } else if (ctx.isWebKitWebGPU) {\n // iOS/Safari: jetsam kills the web content process around 1.5-2GB.\n // Default conservatively; honor explicit requests up to 2048.\n maxSeqLen = Math.min(options.maxSeqLen ?? 512, graph.config.context_length, 2048);\n } else {\n maxSeqLen = Math.min(\n options.maxSeqLen ?? graph.config.context_length,\n graph.config.context_length,\n 4096,\n );\n }\n\n console.log(`[engine] maxSeqLen: ${maxSeqLen}, architecture: ${graph.architecture}`);\n\n // Log device limits for debugging Safari issues\n if (ctx.isWebKitWebGPU) {\n console.log(\n `[engine] device limits: maxBufferSize=${ctx.limits.maxBufferSize}, ` +\n `maxStorageBufferBindingSize=${ctx.limits.maxStorageBufferBindingSize}, ` +\n `maxComputeWorkgroupStorageSize=${ctx.limits.maxComputeWorkgroupStorageSize}`,\n );\n }\n\n // Create executor and upload weights inside error scopes — Safari reports\n // failed allocations and invalid bind groups asynchronously, and without\n // scopes the affected dispatches silently no-op.\n setPhase(\"engine:allocating-buffers\");\n ctx.device.pushErrorScope(\"out-of-memory\");\n ctx.device.pushErrorScope(\"validation\");\n // ── WebKit submit-granularity (group size) selection ──\n // On WebKit, the executor groups `webkitGroupSize` dispatches per command\n // buffer (one submit + GPU drain per group); larger groups amortize the\n // round-trip and can be ~5x faster on iPad. The safe ceiling is\n // device-dependent (some devices crash or produce garbage at high group),\n // so we run a crash-surviving, self-calibrating probe that escalates UP from\n // group=1 and persists the result per-device in localStorage. An explicit\n // ?group=N overrides everything and skips the probe.\n // - groupOverride present → use it verbatim.\n // - WebKit, no override → resolver picks the rung + records the breadcrumb.\n // - Dawn / node → undefined (executor floors at 1; probe inert).\n const groupOverrideNum = groupOverride ? Number.parseInt(groupOverride, 10) : undefined;\n let webkitGroupSize: number | undefined;\n // True only when we escalated to a new candidate this load and must promote\n // (or cap) it after the first successful forward.\n let probingGroup = false;\n if (groupOverrideNum) {\n webkitGroupSize = groupOverrideNum;\n console.log(\n `[engine] webkitGroupSize override: ${webkitGroupSize} dispatches/command buffer`,\n );\n } else if (ctx.isWebKitWebGPU) {\n // The resolver picks the rung and, when escalating, writes `trying` to the\n // localStorage breadcrumb BEFORE we touch the GPU. We then attempt a\n // promotion after the first forward; promoteGroupProbe() is itself a no-op\n // when `trying === null` (capped / at the floor), so it is always safe to\n // flag this as pending — no need to re-derive whether we actually escalated.\n //\n // Phones are NO LONGER treated as a crash class. We thought iPhone batching\n // crashed the GPU process — but that was memory pressure from the old broken\n // cache (404 MB redownloaded into RAM every load + orphaned/corrupt entries\n // filling the quota). With the IndexedDB cache that pressure is gone, and an\n // iPhone (iOS 18.7) ran Qwen3.5-0.8B at group=4096 / 38.4 tok/s, coherent.\n // So phones escalate like tablets; the crash-surviving breadcrumb still caps\n // any genuinely memory-tight device down after a single bad load.\n webkitGroupSize = resolveWebkitGroupSize({ isWebKit: true });\n probingGroup = true;\n }\n const executor = new Executor(ctx, graph, { maxSeqLen, kvMode, webkitGroupSize });\n // Gemma 4: register the CPU-resident PLE table (streamed per-step, never\n // uploaded to a GPU buffer) before uploadWeights consumes the rest.\n if (pleSource) {\n executor.setPleSource(pleSource);\n }\n setPhase(\"engine:uploading-weights\");\n await executor.uploadWeights(weights);\n // Free the browser transform-staging cache now that every weight is GPU-\n // resident. (The PLE table lives in a separate cache and is NOT evicted —\n // it is lazily streamed on first forward.)\n await weights.dispose?.();\n setPhase(\"engine:compiling-shaders\");\n executor.initBindGroups();\n const validationError = await ctx.device.popErrorScope();\n const oomError = await ctx.device.popErrorScope();\n if (oomError || validationError) {\n const detail = [\n oomError ? `out-of-memory: ${oomError.message}` : null,\n validationError ? `validation: ${validationError.message}` : null,\n ]\n .filter(Boolean)\n .join(\"; \");\n setPhase(`engine:gpu-error:${detail.slice(0, 120)}`);\n throw new Error(\n `GPU setup failed (${detail}). The model likely exceeds this device's memory budget — try a smaller maxSeqLen or a q4-quantized model.`,\n );\n }\n setPhase(\"engine:ready\");\n\n return new WebGPUEngine(\n ctx,\n executor,\n tokenizer,\n graph,\n {\n multimodalGraph: Boolean(multimodal),\n rawConfig,\n maxSeqLen,\n createOptions: options,\n groupProbePending: probingGroup,\n },\n visionBundle,\n );\n }\n\n /**\n * Encode an image (already preprocessed into patches) into merged\n * image-embedding tokens of dim `out_hidden_size` (1024 for Qwen3.5).\n *\n * This is the VISION ENCODER ONLY — it returns the image tokens; it does not\n * splice them into a text sequence or apply M-RoPE (that is the LM-side\n * integration phase). Requires `enableVision: true` at create() on a\n * vision-capable checkpoint.\n *\n * @param patches Flattened patches, row-major [numPatches, patch_dim].\n * patch_dim = in_channels * temporal_patch_size * patch_size^2 (1536 for Qwen3.5).\n * Patches must already be ordered in spatial_merge_size×spatial_merge_size\n * groups (as the HF image processor emits them).\n * @param gridTHW The (temporal, height, width) patch-grid dims for the image.\n * numPatches must equal t*h*w.\n */\n async encodeImage(\n patches: Float32Array,\n gridTHW: [number, number, number],\n onStage?: (stage: string, info?: { layer?: number; total?: number }) => void,\n ): Promise<EncodeImageResult> {\n this.checkDestroyed();\n if (!this.visionExecutor || !this.visionConfig || !this.visionPosEmbedTable) {\n throw new Error(\n \"encodeImage() requires a vision encoder. Load with { enableVision: true } \" +\n \"on a vision-capable checkpoint (e.g. Qwen/Qwen3.5-0.8B).\",\n );\n }\n const vcfg = this.visionConfig;\n\n // ── Gemma 4 ViT path ──\n if (this.visionExecutor.gemma4) {\n const info = resolveGemma4VisionInfo({ vision_config: vcfg });\n const gridH = gridTHW[1];\n const gridW = gridTHW[2];\n // The pos-embed table is [2, posSize, hidden]; posSize = total/(2*hidden).\n const posSize = Math.floor(this.visionPosEmbedTable.length / (2 * info.hiddenSize));\n const host = buildGemma4VisionPositionTensors(\n gridH,\n gridW,\n this.visionPosEmbedTable,\n posSize,\n {\n hiddenSize: info.hiddenSize,\n numHeads: info.numHeads,\n headDim: info.headDim,\n ropeTheta: info.ropeTheta,\n poolingKernelSize: info.poolingKernelSize,\n },\n );\n return this.visionExecutor.encodeGemma4(\n {\n patches,\n posEmbeds: host.posEmbeds,\n cos: host.cos,\n sin: host.sin,\n poolMatrix: host.poolMatrix,\n numPatches: host.numPatches,\n numPooled: host.numPooled,\n },\n onStage,\n );\n }\n\n // ── Qwen3.5 ViT path ──\n const hiddenSize = vcfg.hidden_size as number;\n const numHeads = vcfg.num_heads as number;\n const host = buildVisionPositionTensors(gridTHW, this.visionPosEmbedTable, {\n hiddenSize,\n numHeads,\n numPositionEmbeddings: vcfg.num_position_embeddings as number,\n spatialMergeSize: vcfg.spatial_merge_size as number,\n ropeTheta: 10_000.0,\n });\n const numPatches = gridTHW[0] * gridTHW[1] * gridTHW[2];\n return this.visionExecutor.encode(\n {\n patches,\n posEmbeds: host.posEmbeds,\n cos: host.cos,\n sin: host.sin,\n numPatches,\n },\n onStage,\n );\n }\n\n // ── Multimodal M-RoPE helpers ────────────────────────────────────────────\n\n /** Resolve M-RoPE params from rawConfig: rope_dim, theta, mrope_section. */\n private mropeParams(): {\n ropeDim: number;\n theta: number;\n section: [number, number, number];\n imageTokenId: number;\n mergeSize: number;\n } {\n const cfg = this.rawConfig ?? {};\n const textCfg = (cfg.text_config as Record<string, unknown>) ?? cfg;\n const rope = (textCfg.rope_parameters as Record<string, unknown>) ?? {};\n const headDim = this.config.head_dim;\n const partial = (rope.partial_rotary_factor as number) ?? 0.25;\n const ropeDim = Math.floor(headDim * partial);\n const theta = (rope.rope_theta as number) ?? this.config.rope_base ?? 10_000;\n const section = ((rope.mrope_section as number[]) ?? [11, 11, 10]) as [number, number, number];\n const visCfg = (cfg.vision_config as Record<string, unknown>) ?? {};\n return {\n ropeDim,\n theta,\n section,\n imageTokenId: (cfg.image_token_id as number) ?? 248_056,\n mergeSize: (visCfg.spatial_merge_size as number) ?? 2,\n };\n }\n\n /**\n * Write the M-RoPE cos/sin (token order) + image row-map for a prefill of\n * `positionIds3` ([3, seq]). `rowMap[i]` = vision-buffer row for image tokens,\n * -1 for text. Returns the logical position of the last token (for decode).\n */\n private writeMRoPEPrefill(positionIds3: Int32Array, seq: number, rowMap: Int32Array): number {\n const { ropeDim, theta, section } = this.mropeParams();\n const { cos, sin } = buildMRoPECosSin(positionIds3, seq, ropeDim, theta, section);\n this.executor.writeInput(\"mrope_cos\", cos);\n this.executor.writeInput(\"mrope_sin\", sin);\n this.executor.writeInput(\"vision_row_map\", rowMap);\n // last logical position = max over the 3 components of the final token.\n const last = seq - 1;\n return Math.max(positionIds3[last], positionIds3[seq + last], positionIds3[2 * seq + last]);\n }\n\n /**\n * Write a single decode-step M-RoPE cos/sin row at table slot `seqPos` for a\n * text token at logical position `logicalPos`, plus a -1 row-map entry.\n */\n private writeMRoPEDecodeStep(seqPos: number, logicalPos: number): void {\n const { ropeDim, theta, section } = this.mropeParams();\n // Text token: all 3 position components equal → 1D RoPE for this row.\n const pid = new Int32Array(3);\n pid[0] = logicalPos;\n pid[1] = logicalPos;\n pid[2] = logicalPos;\n const { cos, sin } = buildMRoPECosSin(pid, 1, ropeDim, theta, section);\n const rowBytes = ropeDim * 4;\n this.executor.writeInputAt(\"mrope_cos\", cos, seqPos * rowBytes);\n this.executor.writeInputAt(\"mrope_sin\", sin, seqPos * rowBytes);\n }\n\n /** Write linear-position M-RoPE inputs for a pure-text forward (no image). */\n private writeMRoPELinearText(seq: number): void {\n const { ropeDim, theta, section } = this.mropeParams();\n // Positions 0..seq-1, all three components equal (1D RoPE).\n const pid = new Int32Array(3 * seq);\n for (let i = 0; i < seq; i++) {\n pid[i] = i;\n pid[seq + i] = i;\n pid[2 * seq + i] = i;\n }\n const { cos, sin } = buildMRoPECosSin(pid, seq, ropeDim, theta, section);\n this.executor.writeInput(\"mrope_cos\", cos);\n this.executor.writeInput(\"mrope_sin\", sin);\n const rowMap = new Int32Array(seq).fill(-1);\n this.executor.writeInput(\"vision_row_map\", rowMap);\n }\n\n /**\n * Generate text from a prompt.\n *\n * Serialized per engine: the shared executor's readback/staging buffers and KV\n * cache cannot be shared by two overlapping generations, so a concurrent call on\n * the same instance awaits this one (see {@link _genQueueTail}).\n */\n async generate(\n prompt: string | ChatMessage[],\n options: GenerateOptions = {},\n ): Promise<GenerateResult> {\n this.checkDestroyed();\n const release = await this._acquireGenLock();\n try {\n return await this._generateLocked(prompt, options);\n } finally {\n release();\n }\n }\n\n /**\n * Batched lockstep generation (GERBIL_BATCH=N — Phase 2 of the\n * continuous-batching campaign, Dawn only).\n *\n * Prefills each prompt sequentially into its batch slot (KV into the slot's\n * block-table row, SSM/conv state adopted into the slot's state-pool rows),\n * then decodes all N sequences in lockstep: one batched dispatch stream per\n * step produces one token per row. Greedy-only in Phase 2 (per-row GPU\n * argmax); rows that hit EOS/stop keep decoding in lockstep with their\n * output discarded until every row has finished — rows never interact, so\n * per-row streams are token-exact vs single-sequence generation.\n *\n * Requires exactly `executor.batchSize` prompts (fixed lockstep batch; the\n * Phase 3 scheduler will lift this).\n */\n async generateBatch(\n prompts: Array<string | ChatMessage[]>,\n options: GenerateOptions & {\n maxTokensPerRow?: number[];\n /**\n * Per-lane adapter names (SGMV phase 1 — requires GERBIL_BATCH_LORA=1\n * and prior {@link registerAdapter} calls). `adapters[i]` selects the\n * adapter lane i decodes with; null/undefined = bare base. Lanes with\n * different adapters (or none) decode concurrently over the shared base.\n */\n adapters?: Array<string | null | undefined>;\n } = {},\n ): Promise<GenerateResult[]> {\n this.checkDestroyed();\n const B = this.executor.batchSize;\n if (B <= 0) {\n throw new Error(\"generateBatch requires GERBIL_BATCH=N (N >= 2) on the Dawn path\");\n }\n if (prompts.length !== B) {\n throw new Error(\n `generateBatch: got ${prompts.length} prompts for a fixed batch of ${B} ` +\n `(set GERBIL_BATCH=${prompts.length})`,\n );\n }\n if (this._multimodalGraph || this.executor.hasPleSource() || this.executor.hasRuntimeAdapter) {\n throw new Error(\"generateBatch: multimodal, PLE, and runtime-LoRA models are Phase 2+ work\");\n }\n const { maxTokens = 512, stopSequences = [], sampling = {}, systemPrompt } = options;\n if ((sampling.temperature ?? 0.7) >= 1e-6) {\n throw new Error(\"generateBatch: Phase 2 is greedy-only — pass sampling: { temperature: 0 }\");\n }\n\n // ── Per-lane adapters (GERBIL_BATCH_LORA) ──\n const laneAdapterNames = options.adapters;\n if (laneAdapterNames && laneAdapterNames.length !== B) {\n throw new Error(\n `generateBatch: got ${laneAdapterNames.length} lane adapters for a batch of ${B}`,\n );\n }\n const wantLora = laneAdapterNames?.some((a) => a != null) ?? false;\n if (wantLora && !this.executor.batchLoraEnabled) {\n throw new Error(\"generateBatch: per-lane adapters require GERBIL_BATCH_LORA=1\");\n }\n const laneAdapters: Array<{ id: number; deltas: LoRADelta[] } | null> = new Array(B).fill(null);\n if (laneAdapterNames) {\n for (let i = 0; i < B; i++) {\n const name = laneAdapterNames[i];\n if (name == null) continue;\n const reg = this._batchAdapters.get(name);\n if (!reg) {\n throw new Error(\n `generateBatch: adapter \"${name}\" not registered (call registerAdapter first)`,\n );\n }\n laneAdapters[i] = reg;\n }\n }\n\n const release = await this._acquireGenLock();\n try {\n const startTime = performance.now();\n this.executor.resetBatch();\n\n const eosId = this.tokenizer.config.eosTokenId;\n const eotId = this.resolveEndOfTurnId();\n const keepPlan = this.config.vocabKeepPlan;\n const remapTok = keepPlan\n ? (i: number): number => remapPrunedToken(i, keepPlan)\n : (i: number): number => i;\n\n const rows = prompts.map((_p, i) => ({\n generatedIds: [] as number[],\n text: \"\",\n finished: false,\n finishReason: \"max_tokens\" as GenerateResult[\"finishReason\"],\n // Per-row token budget (serving benches assign each request its own).\n limit: options.maxTokensPerRow?.[i] ?? maxTokens,\n }));\n\n // ── Sequential per-slot prefill (batched prefill is Phase 3) ──\n const firstTokens = new Uint32Array(B);\n for (let i = 0; i < B; i++) {\n const p = prompts[i];\n const messages: ChatMessage[] =\n typeof p === \"string\"\n ? [\n ...(systemPrompt ? [{ role: \"system\" as const, content: systemPrompt }] : []),\n { role: \"user\" as const, content: p },\n ]\n : systemPrompt\n ? [{ role: \"system\" as const, content: systemPrompt }, ...p]\n : p;\n const inputIds = this.tokenizer.encodeChat(messages, { addGenerationPrompt: true });\n // Lane adapter: prefill runs on the single-sequence path, so apply the\n // lane's adapter as the proven runtime overlay for exactly this\n // prompt's prefill (KV/SSM state and the first sampled token then\n // match a solo run with that adapter loaded), then drop it.\n const laneReg = laneAdapters[i];\n if (laneReg) this.executor.applyRuntimeLoRA(laneReg.deltas);\n try {\n this.executor.beginBatchSlot(i);\n const { logits } = await this.executor.forward(new Uint32Array(inputIds));\n this.executor.finishBatchSlot(i);\n firstTokens[i] = remapTok(sampleToken(logits, { temperature: 0 }));\n } finally {\n if (laneReg) this.executor.clearRuntimeLoRA();\n }\n }\n\n // Per-lane adapter selection for the batched decode steps: the shared\n // base GEMMs are untouched; lanes with an adapter get gathered low-rank\n // corrections, bare-base lanes cost nothing extra.\n if (this.executor.batchLoraEnabled) {\n this.executor.setBatchLaneAdapters(laneAdapters.map((a) => (a ? a.id : -1)));\n }\n\n const consume = (row: (typeof rows)[number], tok: number): void => {\n if (row.finished) return;\n row.generatedIds.push(tok);\n if ((eosId !== null && tok === eosId) || (eotId !== null && tok === eotId)) {\n row.finished = true;\n row.finishReason = \"eos\";\n return;\n }\n row.text += this.tokenizer.decode([tok], true);\n if (stopSequences.some((s) => row.text.includes(s))) {\n for (const s of stopSequences) {\n const idx = row.text.indexOf(s);\n if (idx !== -1) row.text = row.text.slice(0, idx);\n }\n row.finished = true;\n row.finishReason = \"stop_sequence\";\n return;\n }\n if (row.generatedIds.length >= row.limit) row.finished = true;\n };\n\n const decodeStart = performance.now();\n for (let i = 0; i < B; i++) consume(rows[i], firstTokens[i]);\n\n // ── Lockstep batched decode, pipelined depth-2 like the single path ──\n const depth = Executor.PIPELINE_DEPTH;\n const lens = this.executor.batchSlotLengths;\n let capacity = Number.POSITIVE_INFINITY;\n for (let i = 0; i < B; i++) {\n capacity = Math.min(capacity, this.maxSeqLen - lens[i] - 1);\n }\n const maxRowLimit = rows.reduce((a, r) => Math.max(a, r.limit), 0);\n const stepsNeeded = Math.max(0, Math.min(maxRowLimit - 1, capacity));\n let submitted = 0;\n let consumedSteps = 0;\n while (consumedSteps < stepsNeeded && !rows.every((r) => r.finished)) {\n while (submitted < stepsNeeded && submitted < consumedSteps + depth) {\n this.executor.submitBatchDecodeStep(\n submitted === 0 ? firstTokens : null,\n submitted % depth,\n );\n submitted++;\n }\n const toks = await this.executor.readBatchTokens(consumedSteps % depth);\n consumedSteps++;\n for (let i = 0; i < B; i++) consume(rows[i], toks[i]);\n }\n\n const decodeTime = performance.now() - decodeStart;\n const totalTime = performance.now() - startTime;\n return rows.map((r) => ({\n text: r.text,\n tokensGenerated: r.generatedIds.length,\n tokensPerSecond: r.generatedIds.length / (totalTime / 1000),\n totalTime,\n decodeTime,\n finishReason: r.finishReason,\n tokenIds: [...r.generatedIds],\n }));\n } finally {\n release();\n }\n }\n\n /**\n * Continuous-batching scheduler (GERBIL_BATCH=N — Phase 5 of the batching\n * campaign, Dawn only). Returns the engine's request scheduler (created on\n * first call): submit many requests with independent prompts/limits and the\n * scheduler multiplexes them over the batch lanes with dynamic admission,\n * immediate lane retirement, and chunked prefill. Greedy-only; per-request\n * output is token-exact vs single-sequence generate().\n */\n createScheduler(): RequestScheduler {\n this.checkDestroyed();\n if (this._scheduler) return this._scheduler;\n if (this.executor.batchSize <= 0) {\n throw new Error(\"createScheduler requires GERBIL_BATCH=N (N >= 2) on the Dawn path\");\n }\n if (this._multimodalGraph || this.executor.hasPleSource() || this.executor.hasRuntimeAdapter) {\n throw new Error(\"createScheduler: multimodal, PLE, and runtime-LoRA models are unsupported\");\n }\n const keepPlan = this.config.vocabKeepPlan;\n const host: SchedulerHost = {\n executor: this.executor,\n encodeChat: (messages) => this.tokenizer.encodeChat(messages, { addGenerationPrompt: true }),\n decodeToken: (id) => this.tokenizer.decode([id], true),\n eosTokenId: this.tokenizer.config.eosTokenId,\n eotTokenId: this.resolveEndOfTurnId(),\n remapToken: keepPlan ? (i) => remapPrunedToken(i, keepPlan) : (i) => i,\n resolveAdapter: (name) => {\n const reg = this._batchAdapters.get(name);\n if (!reg) {\n throw new Error(\n `scheduler: adapter \"${name}\" not registered (call registerAdapter first)`,\n );\n }\n return reg;\n },\n acquireLock: () => this._acquireGenLock(),\n };\n this._scheduler = new RequestScheduler(host);\n return this._scheduler;\n }\n\n /**\n * Create a swarm — the MoTA mode-B primitive (docs/research/slm-swarms.md):\n * named members (LoRA adapters on this engine's shared base, or null for the\n * bare base), an optional plan that fans an input out into per-member\n * sub-tasks, and an optional reduce that joins the results. `swarm.run()`\n * decodes every sub-task CONCURRENTLY through the continuous-batching\n * scheduler with per-request adapters — one batched pass, so the fan-out\n * costs roughly the slowest member, not the sum.\n *\n * Every non-null member source is registered via {@link registerAdapter}\n * (downloads in parallel; factors packed into shared GPU buffers once).\n * Requires `GERBIL_BATCH=N` (N >= 2) + `GERBIL_BATCH_LORA=1` on the Dawn\n * path; greedy-only like the scheduler underneath.\n */\n async createSwarm<R = Record<string, ServeResult>>(options: SwarmOptions<R>): Promise<Swarm<R>> {\n this.checkDestroyed();\n if (!this.executor.batchLoraEnabled) {\n throw new Error(\n \"createSwarm requires GERBIL_BATCH=N (N >= 2) and GERBIL_BATCH_LORA=1 on the Dawn path\",\n );\n }\n const scheduler = this.createScheduler();\n await Promise.all(\n Object.entries(options.members).map(([name, source]) =>\n source == null ? Promise.resolve() : this.registerAdapter(name, source),\n ),\n );\n return new Swarm(scheduler, options);\n }\n\n /**\n * Resolve the end-of-turn stop token id, or null if the model has none.\n *\n * Chat models like Gemma 4 end an assistant turn with a dedicated end-of-turn\n * token (`<turn|>`, id 106) rather than the generic `<eos>`. Every text-decode\n * loop must treat it as a stop token or the model runs on past its answer and\n * repeats until it hits `maxTokens`. Resolved from the tokenizer's added tokens\n * so it is null for models without a turn delimiter (Qwen, LFM2, …), leaving\n * their decode behaviour unchanged.\n */\n private resolveEndOfTurnId(): number | null {\n return this.tokenizer.tokenToId(\"<turn|>\") ?? this.tokenizer.tokenToId(\"<end_of_turn>\");\n }\n\n private async _generateLocked(\n prompt: string | ChatMessage[],\n options: GenerateOptions = {},\n ): Promise<GenerateResult> {\n this.checkDestroyed();\n\n const { maxTokens = 512, stopSequences = [], sampling = {}, systemPrompt, onToken } = options;\n\n // Reset executor for new generation\n this.executor.reset();\n\n // Tokenize\n let inputIds: number[];\n if (typeof prompt === \"string\") {\n // Wrap in chat format\n const messages: ChatMessage[] = [];\n if (systemPrompt) {\n messages.push({ role: \"system\", content: systemPrompt });\n }\n messages.push({ role: \"user\", content: prompt });\n inputIds = this.tokenizer.encodeChat(messages, { addGenerationPrompt: true });\n } else {\n // Already chat messages\n const messages = systemPrompt\n ? [{ role: \"system\" as const, content: systemPrompt }, ...prompt]\n : prompt;\n inputIds = this.tokenizer.encodeChat(messages, { addGenerationPrompt: true });\n }\n\n const startTime = performance.now();\n const isGreedy = (sampling.temperature ?? 0.7) < 1e-6;\n\n // Multimodal graph, text-only prompt. Two flavors:\n // - Qwen3.5 (M-RoPE): feed linear-position cos/sin (reduces to 1D RoPE) + an\n // all-text row map; decode steps write one cos/sin row each.\n // - Gemma 4 (standard 1D RoPE, self-computed): no host cos/sin. Just clear the\n // vision row-map to all -1 so EmbedSplice passes the text embeds through.\n const hasMRoPE = this._multimodalGraph && this.executor.hasBuffer(\"mrope_cos\");\n if (this._multimodalGraph) {\n if (hasMRoPE) {\n this.writeMRoPELinearText(inputIds.length);\n } else if (this.executor.hasBuffer(\"vision_row_map\")) {\n this.executor.writeInput(\"vision_row_map\", new Int32Array(inputIds.length).fill(-1));\n }\n }\n\n // Prefill: process all input tokens at once\n let { logits } = await this.executor.forward(new Uint32Array(inputIds));\n\n // WebKit group-size probe: the first forward survived (page didn't die), so\n // promote the candidate group size if its output is non-corrupt, else cap.\n // No-op on Dawn/node and after the first call. Done before decode so a wrong\n // group is recorded even if the user stops the generation early.\n this.maybePromoteGroupProbe(logits);\n\n // Decode loop\n const generatedIds: number[] = [];\n let finishReason: GenerateResult[\"finishReason\"] = \"max_tokens\";\n let generatedText = \"\";\n\n const eosId = this.tokenizer.config.eosTokenId;\n const eotId = this.resolveEndOfTurnId();\n // Decode-only timing (excludes prefill) for live tok/s in the onToken meta.\n const decodeStart = performance.now();\n\n // Emit one token; returns true when generation should stop.\n const consumeToken = (nextToken: number): boolean => {\n generatedIds.push(nextToken);\n\n // Check EOS / end-of-turn (Gemma ends turns on <turn|>, not <eos>)\n if ((eosId !== null && nextToken === eosId) || (eotId !== null && nextToken === eotId)) {\n finishReason = \"eos\";\n return true;\n }\n\n // Decode token and check stop sequences\n const tokenText = this.tokenizer.decode([nextToken], true);\n generatedText += tokenText;\n if (onToken) {\n const elapsedMs = performance.now() - decodeStart;\n const tokenIndex = generatedIds.length;\n onToken(tokenText, {\n tokenIndex,\n elapsedMs,\n tps: elapsedMs > 0 ? (tokenIndex / elapsedMs) * 1000 : 0,\n });\n }\n\n if (stopSequences.some((s) => generatedText.includes(s))) {\n // Trim the stop sequence from the end\n for (const s of stopSequences) {\n const idx = generatedText.indexOf(s);\n if (idx !== -1) {\n generatedText = generatedText.slice(0, idx);\n }\n }\n finishReason = \"stop_sequence\";\n return true;\n }\n return false;\n };\n\n // M-RoPE decode positions are logical (text continues after the image at the\n // post-image cursor), so each step needs a fresh cos/sin row — incompatible\n // with the GPU-chained pipelined path. mmDecode tracks the logical position.\n // Gemma 4's multimodal graph uses self-computed sequential RoPE (no host cos/sin),\n // so it is NOT an mmDecode case and can use the fast pipelined path.\n const mmDecode = hasMRoPE;\n let mmLogicalPos = inputIds.length; // text-only: logical == token index\n\n // Gemma 4 streams a CPU-resident Per-Layer-Embedding table: each decode step\n // must gather+upload the PLE rows for the ACTUAL next token id on the CPU\n // (streamPleRows, inside forward()) before the forward runs. The GPU-chained\n // pipelined path and forwardArgmax both pick the next token ON THE GPU and\n // never call back into the CPU, so they leave `ple_embed_out` stale — the\n // model produces one good token then collapses into repetition. Force such\n // models onto the per-step forward() + CPU-argmax loop (proven exact), which\n // streams PLE for every token. Costs the pipelined-decode speedup, but PLE\n // already requires per-step CPU work so there is no faster correct path.\n const streamsPle = this.executor.hasPleSource();\n\n // Vocab-pruned head (Lever B): the head emits logits in the PRUNED index space.\n // The argmax shader remaps its winning index back to the real token id on the\n // GPU (ARGMAX Params prefix_len/tail_start), so forwardArgmax AND the GPU-chained\n // pipelined path both yield real token ids — pruning works on every decode path,\n // including the fast Dawn pipeline. Only host-side sampleToken (which runs over\n // the pruned logits array) needs the CPU remap below.\n const keepPlan = this.config.vocabKeepPlan;\n const remapTok = keepPlan\n ? (i: number): number => remapPrunedToken(i, keepPlan)\n : (i: number): number => i;\n\n if (isGreedy && !this.executor.needsMultiEncoder && !mmDecode && !streamsPle) {\n // ── Pipelined greedy decode (Dawn) ──\n // Overlay-safe: submitGreedyDecodeStep encodes activeDecodeEntries, so a\n // runtime LoRA overlay (selectively-unfused base + spliced low-rank\n // dispatches) runs inside the same pass and its correction lands before\n // the argmax reads logits — identical entries to the forwardArgmax path.\n // The argmax result is chained into input_ids on the GPU, so up to\n // PIPELINE_DEPTH decode steps stay in flight while tokens are read\n // back one step behind. Removes per-token CPU prep and map latency\n // from the critical path.\n const firstToken = remapTok(sampleToken(logits, sampling, [...inputIds, ...generatedIds]));\n if (!consumeToken(firstToken)) {\n const stepsNeeded = Math.min(maxTokens - 1, this.executor.decodeCapacityRemaining());\n const windowK = this.executor.decodeWindowK;\n if (windowK > 0) {\n // ── K-step decode windows (GERBIL_DECODE_WINDOW, Dawn only) ──\n // Each window records K full decode steps + argmax into ONE command\n // buffer / ONE submit, with GPU-side token chaining between steps\n // and a single 4·K-byte readback at window end. EOS is detected at\n // window granularity, so up to K-1 tokens past EOS are computed and\n // discarded here. Scaffold: windows run sequentially (no depth-2\n // window pipelining yet). See\n // docs/design/dispatch-collapse-campaign.md §3 Lever 1.\n let produced = 0;\n let stopped = false;\n while (!stopped && produced < stepsNeeded) {\n const steps = Math.min(windowK, stepsNeeded - produced);\n this.executor.submitGreedyDecodeWindow(produced === 0 ? firstToken : null, steps, 0);\n const tokens = await this.executor.readDecodeWindow(0, steps);\n produced += steps;\n for (const tok of tokens) {\n if (consumeToken(tok)) {\n stopped = true;\n break;\n }\n }\n }\n } else {\n const depth = Executor.PIPELINE_DEPTH;\n let submitted = 0;\n let consumed = 0;\n while (consumed < stepsNeeded) {\n while (submitted < stepsNeeded && submitted < consumed + depth) {\n this.executor.submitGreedyDecodeStep(\n submitted === 0 ? firstToken : null,\n submitted % depth,\n );\n submitted++;\n }\n const tok = await this.executor.readDecodeToken(consumed % depth);\n consumed++;\n if (consumeToken(tok)) break;\n }\n }\n }\n } else {\n // PLE-streaming models (Gemma 4) must run the CPU forward() path every step\n // (forwardArgmax bypasses the per-token PLE gather). Sample greedily on the\n // CPU from the forward() logits instead of the GPU argmax shader.\n const useCpuForward = !isGreedy || streamsPle;\n for (let step = 0; step < maxTokens; step++) {\n let nextToken: number;\n if (step === 0 || useCpuForward) {\n nextToken = remapTok(sampleToken(logits, sampling, [...inputIds, ...generatedIds]));\n } else {\n // Greedy multimodal/desktop fallback: write this step's M-RoPE row\n // (logical position) before the GPU forward reads it.\n if (mmDecode) this.writeMRoPEDecodeStep(this.executor.currentSeqPos, mmLogicalPos);\n // The argmax shader already remapped the pruned index → real token id.\n nextToken = await this.executor.forwardArgmax(\n new Uint32Array([generatedIds[generatedIds.length - 1]]),\n );\n mmLogicalPos++;\n }\n\n if (consumeToken(nextToken)) break;\n\n if (useCpuForward) {\n if (mmDecode) this.writeMRoPEDecodeStep(this.executor.currentSeqPos, mmLogicalPos);\n const result = await this.executor.forward(new Uint32Array([nextToken]));\n logits = result.logits;\n mmLogicalPos++;\n }\n }\n }\n\n const totalTime = performance.now() - startTime;\n const tokensGenerated = generatedIds.length;\n const tokensPerSecond = tokensGenerated / (totalTime / 1000);\n\n return {\n text: generatedText,\n tokensGenerated,\n tokensPerSecond,\n totalTime,\n finishReason,\n tokenIds: [...generatedIds],\n };\n }\n\n /**\n * Inline autocomplete: continue `prefix` with a brief, single-line continuation.\n * Wraps `generate` with low-latency defaults (16 tokens, temp 0.3, a repetition\n * penalty of 1.25, stop at the first newline) + a continuation system prompt,\n * then cleans the output: strip after newline, dequote, drop an echoed prefix,\n * drop a leading overlap with the typed tail, drop a leading word-run that\n * restates an earlier typed phrase, truncate an internal phrase loop, cap the\n * length, and add a smart leading space.\n *\n * The repetition penalty plus the overlap/restatement/loop cleanup keep small\n * quantized models (e.g. Qwen3.5-0.8B) from echoing the typed text or looping\n * on a phrase. Both are on by default; `repetitionPenalty` and `maxChars` are\n * overridable.\n *\n * ```ts\n * const suggestion = await engine.autocomplete(\"The quick brown fox\");\n * // \" jumps over the lazy dog.\"\n * ```\n */\n async autocomplete(\n prefix: string,\n opts: {\n maxTokens?: number;\n temperature?: number;\n /** Repetition penalty applied during sampling (default 1.25; 1.0 disables). */\n repetitionPenalty?: number;\n stop?: string[];\n singleLine?: boolean;\n /** Character cap for the cleaned continuation (default 140). */\n maxChars?: number;\n } = {},\n ): Promise<string> {\n const out = await this.generate(prefix, {\n systemPrompt: AUTOCOMPLETE_SYSTEM,\n maxTokens: opts.maxTokens ?? 16,\n sampling: {\n temperature: opts.temperature ?? 0.3,\n repetitionPenalty: opts.repetitionPenalty ?? 1.25,\n },\n stopSequences: opts.stop ?? [\"\\n\"],\n });\n return cleanSuggestion(out.text, prefix, {\n singleLine: opts.singleLine ?? true,\n maxChars: opts.maxChars,\n });\n }\n\n /**\n * Rewrite `text` in a target tone (e.g. \"professional\", \"friendly\", \"concise\",\n * \"playful\", \"pirate\") or with free-form `instructions`. Returns only the\n * rewritten text.\n *\n * ```ts\n * await engine.rewrite(\"hey can u send the file\", { tone: \"professional\" });\n * ```\n */\n async rewrite(\n text: string,\n opts: {\n tone?: string;\n instructions?: string;\n maxTokens?: number;\n temperature?: number;\n } = {},\n ): Promise<string> {\n const system =\n opts.instructions ??\n `Rewrite the user's text in a ${opts.tone ?? \"professional\"} tone. ` +\n \"Output ONLY the rewritten text — no preamble, no quotes, no commentary.\";\n const out = await this.generate(text, {\n systemPrompt: system,\n maxTokens: opts.maxTokens ?? 256,\n sampling: { temperature: opts.temperature ?? 0.7 },\n });\n return out.text.trim();\n }\n\n /**\n * Agentic tool-calling loop: generate, parse a `<tool_call>`, run the matching\n * tool's `execute`, feed the result back, and repeat up to `maxSteps` until the\n * model answers without calling a tool. Returns the final text + a step trace.\n *\n * ```ts\n * const { text, steps } = await engine.generateWithTools(\"Weather in Paris?\", {\n * tools: [weatherTool],\n * });\n * ```\n */\n async generateWithTools(\n prompt: string | ChatMessage[],\n opts: {\n tools: AgentTool[];\n maxSteps?: number;\n onStep?: (step: AgentStep) => void;\n maxTokens?: number;\n sampling?: { temperature?: number; topK?: number; topP?: number };\n },\n ): Promise<{ text: string; steps: AgentStep[] }> {\n const { tools, maxSteps = 5, onStep, maxTokens, sampling } = opts;\n const systemPrompt = formatAgentToolsPrompt(tools);\n const messages: ChatMessage[] =\n typeof prompt === \"string\" ? [{ role: \"user\", content: prompt }] : [...prompt];\n const steps: AgentStep[] = [];\n let finalText = \"\";\n\n for (let i = 0; i < maxSteps; i++) {\n const result = await this.generate(messages, { systemPrompt, maxTokens, sampling });\n const call = parseAgentToolCall(result.text);\n if (!call) {\n finalText = result.text;\n const answer: AgentStep = { kind: \"answer\", text: result.text };\n steps.push(answer);\n onStep?.(answer);\n break;\n }\n\n const callStep: AgentStep = { kind: \"tool_call\", tool: call.name, args: call.args };\n steps.push(callStep);\n onStep?.(callStep);\n\n const tool = tools.find((t) => t.name === call.name);\n let resultText: string;\n if (tool) {\n try {\n resultText = String(await tool.execute(call.args));\n } catch (e) {\n resultText = `Error executing ${call.name}: ${e}`;\n }\n } else {\n resultText = `Error: unknown tool \"${call.name}\"`;\n }\n\n const resultStep: AgentStep = { kind: \"tool_result\", tool: call.name, result: resultText };\n steps.push(resultStep);\n onStep?.(resultStep);\n\n messages.push({ role: \"assistant\", content: result.text });\n messages.push({ role: \"user\", content: `Tool ${call.name} returned:\\n${resultText}` });\n finalText = resultText;\n }\n\n return { text: finalText, steps };\n }\n\n /**\n * Generate a STRUCTURED object: generate text, extract the first JSON\n * object/array, parse it, validate it, and RETRY until it is valid (on-device\n * tokens are free, so re-rolling a malformed JSON is cheap).\n *\n * Extraction is tolerant: prose, markdown, and ```json code fences are\n * stripped, then the outermost balanced `{...}` or `[...]` is matched and\n * `JSON.parse`d. Validation is one of:\n * - a predicate `(o) => boolean` (return false to reject),\n * - a minimal JSON-schema-ish object with `required` (those keys must exist),\n * - nothing (only valid JSON is required).\n *\n * On each retry the prompt is nudged with a terse \"return ONLY valid JSON…\"\n * instruction (including the required-key shape when known). Throws a clear\n * error if it never validates within `maxRetries + 1` attempts.\n *\n * ```ts\n * const { object } = await engine.generateObject(\n * 'Extract {name, age} from: \"I am Sarah, 28\"',\n * { schema: { required: [\"name\", \"age\"] } },\n * );\n * // object === { name: \"Sarah\", age: 28 }\n * ```\n *\n * @typeParam T Expected object type (not enforced at runtime — validate via schema).\n */\n async generateObject<T = unknown>(\n prompt: string,\n options: GenerateObjectOptions = {},\n ): Promise<GenerateObjectResult<T>> {\n this.checkDestroyed();\n const { schema, maxRetries = 4, ...generateOpts } = options;\n\n const validate = (value: unknown): boolean => {\n if (typeof schema === \"function\") {\n return (schema as (o: unknown) => boolean)(value);\n }\n if (schema && typeof schema === \"object\" && Array.isArray(schema.required)) {\n if (value === null || typeof value !== \"object\") return false;\n const obj = value as Record<string, unknown>;\n return schema.required.every((key) => key in obj);\n }\n // No schema → any valid JSON value is acceptable.\n return true;\n };\n\n // Build the retry nudge once: include the required-key shape when known so\n // the model gets a concrete target to match.\n const shape =\n schema && typeof schema === \"object\" && Array.isArray(schema.required)\n ? `{ ${schema.required.join(\", \")} }`\n : \"the requested shape\";\n const nudge = `\\n\\nReturn ONLY valid JSON matching ${shape}. No prose, no markdown, no code fences.`;\n\n const attemptsMax = Math.max(0, maxRetries) + 1;\n let lastText = \"\";\n let lastError = \"\";\n for (let attempt = 1; attempt <= attemptsMax; attempt++) {\n const promptForAttempt = attempt === 1 ? prompt : prompt + nudge;\n const result = await this.generate(promptForAttempt, generateOpts);\n lastText = result.text;\n const parsed = extractJson(result.text);\n if (parsed === undefined) {\n lastError = \"no JSON object/array found in output\";\n continue;\n }\n let value: unknown;\n try {\n value = JSON.parse(parsed);\n } catch (e) {\n lastError = `JSON.parse failed: ${e instanceof Error ? e.message : String(e)}`;\n continue;\n }\n if (!validate(value)) {\n lastError = \"parsed JSON failed schema validation\";\n continue;\n }\n return { object: value as T, text: result.text, attempts: attempt };\n }\n\n throw new Error(\n `generateObject failed after ${attemptsMax} attempt(s): ${lastError}. ` +\n `Last output: ${JSON.stringify(lastText.slice(0, 200))}`,\n );\n }\n\n /**\n * Text-to-speech: text → 22 kHz PCM via KaniTTS (LFM2-350M codec-LM + NVIDIA\n * NeMo NanoCodec). Returns `{ pcm: Float32Array, sampleRate: 22050 }`.\n *\n * Runs the full pipeline: the codec-LM backbone autoregressively emits NanoCodec\n * audio tokens (4 per frame), then the bit-exact NanoCodec decoder (FSQ + causal\n * HiFi-GAN) turns the codes into PCM. The heavy lifting lives in {@link KaniTTS}\n * (src/gpu/kani-tts.ts); this lazily constructs that engine on first use\n * (downloading the NanoCodec codec checkpoint alongside the backbone).\n *\n * The default checkpoint is the Apache-2.0 `nineninesix/kani-tts-450m-0.2-ft`\n * (plain `Lfm2ForCausalLM` backbone); the earlier `KaniTTS2ForCausalLM`\n * checkpoints (multi-accent) also work. The codec-LM backbone defaults to INT4\n * (`dtype: \"q4\"`) — pass `dtype: \"f32\"` for full precision.\n */\n async speak(\n text: string,\n options: {\n languageTag?: string;\n /** Kani accent tag, OR an OuteTTS preset voice name (e.g. \"en-female-1-neutral\"). */\n voice?: string;\n temperature?: number;\n topP?: number;\n topK?: number;\n repetitionPenalty?: number;\n maxFrames?: number;\n /** Backbone precision for the lazily-built TTS engine (default \"q4\"). */\n dtype?: KaniDType | OuteDType;\n /** Override the OuteTTS folded DAC codec weights URL/path (else the mirror). */\n codecWeightsPath?: string;\n /**\n * OuteTTS voice cloning: a pre-encoded speaker reference (transcript + per-word\n * DAC c1/c2 codes + prosody features, the preset-JSON shape). When set, this voice\n * is used in-context for this call instead of the preset. Build it from a raw\n * reference clip via `OuteTTS.encodeSpeaker({ audio, sampleRate, transcript })`\n * (DAC.speech encode + prosody), or pass a preset/pre-encoded speaker JSON.\n */\n cloneSpeaker?: OuteSpeaker;\n /**\n * Parler-TTS describe-your-voice hook: a natural-language voice description\n * (\"a warm female voice, slightly fast, clean studio recording\"). Only used by\n * the Parler checkpoint (DEFAULT_MODELS.ttsParler). When omitted, a neutral\n * default description is used.\n */\n describeVoice?: string;\n /**\n * Stop-head sigmoid threshold (Gepard only, default 0.5). Higher = later stop.\n */\n stopThreshold?: number;\n /**\n * Streaming audio callback (Gepard only). Gepard is frame-synchronous, so\n * audio is decoded and delivered chunk-by-chunk WHILE generation runs — the\n * callback fires with each ~1.5 s PCM chunk (the final one has isFinal:true).\n */\n onChunk?: (chunk: {\n pcm: Float32Array;\n sampleRate: number;\n frameIndex: number;\n isFinal: boolean;\n }) => void;\n } = {},\n ): Promise<{ pcm: Float32Array; sampleRate: number; frames: number; audioSeconds: number }> {\n this.checkDestroyed();\n const repo = this._createOptions.repo ?? \"\";\n\n // ── Parler-TTS (selectable describe-your-voice engine): Flan-T5 + decoder + dac_44khz. ──\n if (/parler/i.test(repo) || /parler/i.test(this._architecture)) {\n return this.speakParler(text, options);\n }\n\n // ── OuteTTS (selectable many-voices engine): Qwen3-0.6B codec-LM + DAC.speech. ──\n if (/outetts/i.test(repo) || /oute/i.test(this._architecture)) {\n return this.speakOute(text, options);\n }\n\n // ── Gepard-1.0 (selectable streaming engine): Qwen3.5 multihead codec-LM + NanoCodec. ──\n if (/gepard/i.test(repo) || /gepard/i.test(this._architecture)) {\n return this.speakGepard(text, options);\n }\n\n // ── Kani-TTS (default). ──\n // TTS capability is gated on the loaded repo being a Kani-TTS checkpoint (the\n // architecture string alone no longer identifies it — the Apache default is a\n // plain Lfm2ForCausalLM). Both KaniTTS2 and the plain-LFM2 family route here;\n // KaniTTS.create() auto-detects the per-checkpoint position/RoPE scheme.\n const isTTS =\n this._architecture === \"KaniTTS2ForCausalLM\" ||\n /kani-tts/i.test(repo) ||\n /\\btts\\b/i.test(repo);\n if (!isTTS) {\n throw new Error(\n `speak() requires a Kani-TTS or OuteTTS checkpoint (e.g. \"${DEFAULT_MODELS.tts}\" ` +\n `or \"${DEFAULT_MODELS.ttsOute}\"), loaded engine is \"${this._architecture}\" (repo \"${repo}\").`,\n );\n }\n // Lazily build the dual-graph Kani engine (codec-LM + NanoCodec). It loads its\n // own weights (the backbone repo + the separate NanoCodec checkpoint), so it is\n // independent of this engine's text executor.\n if (!this._kaniTTS) {\n this._kaniTTS = await KaniTTS.create({\n repo: this._createOptions.repo,\n revision: this._createOptions.revision,\n hfToken: this._createOptions.hfToken,\n cacheDir: this._createOptions.cacheDir,\n maxSeqLen: this.maxSeqLen,\n dtype: options.dtype as KaniDType | undefined,\n });\n }\n return this._kaniTTS.speak(text, {\n languageTag: options.voice ?? options.languageTag,\n temperature: options.temperature,\n topP: options.topP,\n topK: options.topK,\n repetitionPenalty: options.repetitionPenalty,\n maxFrames: options.maxFrames,\n });\n }\n\n /**\n * Parler-TTS speak path: lazily build the Parler engine (Flan-T5 description encoder\n * + cross-attending decoder LM + dac_44khz) and synthesize `text` in the voice given\n * by `describeVoice`. Single-checkpoint (all weights, incl. the DAC, in one file).\n */\n private async speakParler(\n text: string,\n options: { describeVoice?: string; temperature?: number; topK?: number; maxFrames?: number },\n ): Promise<{ pcm: Float32Array; sampleRate: number; frames: number; audioSeconds: number }> {\n if (!this._parlerTTS) {\n this._parlerTTS = await ParlerTTS.create({\n repo: this._createOptions.repo,\n revision: this._createOptions.revision,\n hfToken: this._createOptions.hfToken,\n cacheDir: this._createOptions.cacheDir,\n maxSeqLen: this.maxSeqLen,\n });\n }\n const speakOpts: ParlerSpeakOptions = {\n describeVoice: options.describeVoice,\n temperature: options.temperature,\n topK: options.topK,\n maxFrames: options.maxFrames,\n };\n return this._parlerTTS.speak(text, speakOpts);\n }\n\n /** A random natural-language voice description for Parler-TTS (host template bank). */\n randomVoiceDescription(): string {\n return ParlerTTS.randomVoiceDescription();\n }\n\n /**\n * Gepard-1.0 speak path: lazily build the Gepard engine (stock Qwen3.5\n * full-attention codec-LM + 32 host-side FSQ classifier heads + NanoCodec\n * 21.5 fps decoder) and synthesize `text`. Frame-synchronous: when `onChunk`\n * is set, audio streams out during generation. Single default voice for now\n * (voice cloning via the ref-compressor is a documented follow-up).\n */\n private async speakGepard(\n text: string,\n options: {\n temperature?: number;\n topK?: number;\n repetitionPenalty?: number;\n maxFrames?: number;\n stopThreshold?: number;\n dtype?: KaniDType | OuteDType | GepardDType;\n onChunk?: (chunk: {\n pcm: Float32Array;\n sampleRate: number;\n frameIndex: number;\n isFinal: boolean;\n }) => void;\n },\n ): Promise<{ pcm: Float32Array; sampleRate: number; frames: number; audioSeconds: number }> {\n if (!this._gepardTTS) {\n this._gepardTTS = await GepardTTS.create({\n repo: this._createOptions.repo,\n revision: this._createOptions.revision,\n hfToken: this._createOptions.hfToken,\n cacheDir: this._createOptions.cacheDir,\n maxSeqLen: this.maxSeqLen,\n dtype: options.dtype as GepardDType | undefined,\n });\n }\n return this._gepardTTS.speak(text, {\n temperature: options.temperature,\n topK: options.topK,\n repetitionPenalty: options.repetitionPenalty,\n maxFrames: options.maxFrames,\n stopThreshold: options.stopThreshold,\n onChunk: options.onChunk,\n });\n }\n\n /**\n * OuteTTS speak path: lazily build the OuteTTS engine (loading the chosen preset\n * voice's speaker JSON + the folded DAC codec weights from the mirror), rebuilding\n * if the requested voice changed. Mirrors the Kani public shape (temperature/topP/topK).\n */\n private async speakOute(\n text: string,\n options: {\n voice?: string;\n temperature?: number;\n topP?: number;\n topK?: number;\n repetitionPenalty?: number;\n dtype?: KaniDType | OuteDType;\n codecWeightsPath?: string;\n cloneSpeaker?: OuteSpeaker;\n },\n ): Promise<{ pcm: Float32Array; sampleRate: number; frames: number; audioSeconds: number }> {\n await this.ensureOute(options);\n return this._outeTTS!.speak(text, {\n temperature: options.temperature,\n topP: options.topP,\n topK: options.topK,\n repetitionPenalty: options.repetitionPenalty,\n // Per-call cloned voice override (else the preset the engine was built with).\n speaker: options.cloneSpeaker,\n });\n }\n\n /**\n * Lazily build (or reuse) the OuteTTS engine for the requested preset voice,\n * rebuilding if the voice changed. Loads the preset speaker JSON + folded DAC\n * codec weights from the mirror (or a locally-cached `{cacheDir}/{voice}.json`).\n * Shared by {@link speakOute} and {@link encodeSpeaker}.\n */\n private async ensureOute(options: {\n voice?: string;\n dtype?: KaniDType | OuteDType;\n codecWeightsPath?: string;\n }): Promise<void> {\n const voice = options.voice ?? OUTETTS_ASSETS.defaultVoice;\n if (this._outeTTS && this._outeVoice !== voice) {\n this._outeTTS.destroy();\n this._outeTTS = null;\n }\n if (this._outeTTS) {\n return;\n }\n // Prefer a locally-cached speaker JSON ({cacheDir}/{voice}.json), else the mirror.\n const cacheDir = this._createOptions.cacheDir;\n let speakerRef = voice;\n if (cacheDir) {\n const local = `${cacheDir.replace(/\\/$/, \"\")}/${voice}.json`;\n const fs = await import(\"node:fs\").catch(() => null);\n if (fs?.existsSync(local)) {\n speakerRef = local;\n }\n }\n const speaker = await loadOuteSpeaker(speakerRef, OUTETTS_ASSETS.speakersBaseURL);\n this._outeTTS = await OuteTTS.create({\n repo: this._createOptions.repo,\n revision: this._createOptions.revision,\n hfToken: this._createOptions.hfToken,\n cacheDir: this._createOptions.cacheDir,\n maxSeqLen: this.maxSeqLen,\n dtype: (options.dtype as OuteDType | undefined) ?? \"q4\",\n codecWeightsPath: options.codecWeightsPath ?? OUTETTS_ASSETS.codecWeightsURL,\n speaker,\n });\n this._outeVoice = voice;\n }\n\n /**\n * OuteTTS voice cloning: encode a raw reference clip (mono PCM + its transcript)\n * into a reusable speaker (DAC.speech encode → per-word c1/c2 codes + prosody).\n * Pass the result to `speak(text, { cloneSpeaker })` to synthesize new text in that\n * voice. Requires an OuteTTS checkpoint (the folded codec carries the encoder).\n */\n async encodeSpeaker(ref: {\n audio: Float32Array;\n sampleRate: number;\n transcript: string;\n }): Promise<OuteSpeaker> {\n this.checkDestroyed();\n const repo = this._createOptions.repo ?? \"\";\n if (!(/outetts/i.test(repo) || /oute/i.test(this._architecture))) {\n throw new Error(\n `encodeSpeaker() requires an OuteTTS checkpoint (e.g. \"${DEFAULT_MODELS.ttsOute}\"), ` +\n `loaded engine is \"${this._architecture}\" (repo \"${repo}\").`,\n );\n }\n await this.ensureOute({});\n return this._outeTTS!.encodeSpeaker(ref);\n }\n\n /** Accent/voice tags the lazily-built TTS engine supports ([] = single voice). */\n ttsVoices(): string[] {\n if (/outetts/i.test(this._createOptions.repo ?? \"\") || /oute/i.test(this._architecture)) {\n return [...OUTETTS_PRESET_VOICES];\n }\n return this._kaniTTS?.availableVoices() ?? [];\n }\n\n /**\n * Describe an image: image-in → text-out. Runs the vision encoder, splices the\n * merged image tokens into a text prompt, applies multimodal M-RoPE, and\n * generates a description. Requires `enableVision: true` at create().\n *\n * Image input forms:\n * - `{ pixels, width, height }` — decoded RGB (HWC, 0..255), host-preprocessed\n * (smart-resize/normalize/patchify) to match the HF image processor.\n * - `{ patches, gridTHW }` — already-built [N,1536] patch tensor + grid (e.g.\n * HF-exact pixel_values from a reference; skips host preprocessing).\n */\n async describeImage(\n image:\n | { pixels: Float32Array | Uint8ClampedArray | Uint8Array; width: number; height: number }\n | { patches: Float32Array; gridTHW: [number, number, number] },\n prompt = \"Describe this image.\",\n options: GenerateOptions & { imageProcessor?: ImageProcessorConfig } = {},\n ): Promise<GenerateResult> {\n this.checkDestroyed();\n const release = await this._acquireGenLock();\n try {\n return await this._describeImageLocked(image, prompt, options);\n } finally {\n release();\n }\n }\n\n private async _describeImageLocked(\n image:\n | { pixels: Float32Array | Uint8ClampedArray | Uint8Array; width: number; height: number }\n | { patches: Float32Array; gridTHW: [number, number, number] },\n prompt = \"Describe this image.\",\n options: GenerateOptions & { imageProcessor?: ImageProcessorConfig } = {},\n ): Promise<GenerateResult> {\n this.checkDestroyed();\n if (!this.visionExecutor) {\n throw new Error(\n \"describeImage() requires a vision encoder. Load with { enableVision: true } \" +\n \"on a vision-capable checkpoint (Qwen3.5 or Gemma 4).\",\n );\n }\n\n // ── Gemma 4 family path ──\n // ViT encoder + projector are native + validated (cosine 1.0 vs reference).\n // Gemma 4 uses STANDARD sequential 1D RoPE (positions 0..N-1 across text+image),\n // computed inside each layer from the KV write-position — so, unlike Qwen3.5's\n // M-RoPE path, there are no host cos/sin inputs. We splice the merged vision\n // tokens into the `image_token_id` rows (EmbedSplice in the multimodal graph)\n // and run a plain self-RoPE prefill + greedy/sampled decode.\n if (this.visionExecutor.gemma4) {\n if (!this._multimodalGraph) {\n throw new Error(\n \"Gemma 4 describeImage() requires the multimodal text graph. Load with \" +\n \"{ enableVision: true } so generateGemma4Graph builds the vision_embeds + \" +\n \"EmbedSplice variant.\",\n );\n }\n let g4patches: Float32Array;\n let g4gridHW: [number, number];\n if (\"patches\" in image) {\n g4patches = image.patches;\n g4gridHW = [image.gridTHW[1], image.gridTHW[2]];\n } else {\n const pre = preprocessImageGemma4(image.pixels, image.width, image.height);\n g4patches = pre.patches;\n g4gridHW = pre.gridHW;\n }\n const gThw: [number, number, number] = [1, g4gridHW[0], g4gridHW[1]];\n const numPatches = gThw[0] * gThw[1] * gThw[2];\n this.setPhase(`describe:vit-encode:N=${numPatches}`);\n const vision = await this.encodeImage(g4patches, gThw, (stage, info) => {\n const suffix = info?.layer != null ? `:L${info.layer}` : \"\";\n this.setPhase(`describe:${stage}${suffix}`);\n });\n\n // Build the Gemma 4 multimodal token sequence. The HF Gemma processor expands\n // the `<|image|>` chat placeholder into: boi(`<|image>`) + image_token×N +\n // eoi(`<image|>`), bracketed by the \"\\n\\n\" the image template adds, all inside\n // the user turn. We mirror that exactly so token positions match HF.\n const cfg = this.rawConfig ?? {};\n const imageTokenId = (cfg.image_token_id as number) ?? 258_880;\n const boiId = this.tokenizer.tokenToId(\"<|image>\") ?? (cfg.boi_token_id as number) ?? 255_999;\n const eoiId = this.tokenizer.tokenToId(\"<image|>\") ?? (cfg.eoi_token_id as number) ?? 258_882;\n const bos = this.tokenizer.config.bosToken\n ? (this.tokenizer.tokenToId(this.tokenizer.config.bosToken) ?? [])\n : [];\n const bosIds = Array.isArray(bos) ? bos : [bos];\n // User-turn prefix/suffix around the image+prompt, matching applyGemmaTurnTemplate\n // (`<|turn>user\\n … <turn|>\\n<|turn>model\\n`). The image block is \"\\n\\n\" + boi +\n // soft tokens + eoi + \"\\n\\n\", then the text prompt.\n const turnUserOpen = this.tokenizer.encode(\"<|turn>user\\n\");\n const imgLead = this.tokenizer.encode(\"\\n\\n\");\n const imgTrail = this.tokenizer.encode(\"\\n\\n\");\n const promptIds = this.tokenizer.encode(prompt);\n const turnClose = this.tokenizer.encode(\"<turn|>\\n<|turn>model\\n\");\n const imageRun: number[] = new Array(vision.rows).fill(imageTokenId);\n const inputIds: number[] = [\n ...bosIds,\n ...turnUserOpen,\n ...imgLead,\n boiId,\n ...imageRun,\n eoiId,\n ...imgTrail,\n ...promptIds,\n ...turnClose,\n ];\n\n return this.runMultimodalGemma4(vision.embeds, inputIds, imageTokenId, options);\n }\n\n if (!this._multimodalGraph) {\n throw new Error(\n \"describeImage() requires a multimodal engine. Load with { enableVision: true } \" +\n \"on a vision-capable checkpoint (e.g. Qwen/Qwen3.5-0.8B).\",\n );\n }\n\n // 1. Image → patches → merged vision tokens [N, 1024].\n const procCfg = options.imageProcessor ?? QWEN3_5_IMAGE_PROCESSOR;\n let patches: Float32Array;\n let gridTHW: [number, number, number];\n if (\"patches\" in image) {\n patches = image.patches;\n gridTHW = image.gridTHW;\n } else {\n const pre = preprocessImage(image.pixels, image.width, image.height, procCfg);\n patches = pre.patches;\n gridTHW = pre.gridTHW;\n }\n // Phase breadcrumbs survive a GPU-process kill so the harness can attribute a\n // describe-time crash to vit-encode vs splice vs text-decode.\n const numPatches = gridTHW[0] * gridTHW[1] * gridTHW[2];\n this.setPhase(`describe:vit-encode:N=${numPatches}`);\n const vision = await this.encodeImage(patches, gridTHW, (stage, info) => {\n const suffix = info?.layer != null ? `:L${info.layer}` : \"\";\n this.setPhase(`describe:${stage}${suffix}`);\n });\n\n // 2. Build the multimodal token sequence. Match the HF chat template:\n // <|im_start|>user\\n<vision_start><image_pad × N><vision_end>{prompt}\n // <|im_end|>\\n<|im_start|>assistant\\n<think>\\n\\n</think>\\n\\n\n const visStart = this.tokenizer.tokenToId(\"<|vision_start|>\") ?? 248_053;\n const visEnd = this.tokenizer.tokenToId(\"<|vision_end|>\") ?? 248_054;\n const { imageTokenId } = this.mropeParams();\n const numImageTokens = vision.rows;\n const pre = this.tokenizer.encode(\"<|im_start|>user\\n\");\n const post = this.tokenizer.encode(\n `${prompt}<|im_end|>\\n<|im_start|>assistant\\n<think>\\n\\n</think>\\n\\n`,\n );\n const imageRun: number[] = new Array(numImageTokens).fill(imageTokenId);\n const inputIds: number[] = [...pre, visStart, ...imageRun, visEnd, ...post];\n\n return this.runMultimodal(vision.embeds, gridTHW, inputIds, options);\n }\n\n /**\n * Prepare the multimodal prefill: upload vision embeds, build the image row-map\n * and 3D M-RoPE cos/sin, reset state, and write all host inputs. Returns the\n * input ids and the post-image logical cursor for decode. Does NOT run forward.\n */\n private prepareMultimodalPrefill(\n visionEmbeds: Float32Array,\n gridTHW: [number, number, number],\n inputIds: number[],\n ): { lastLogicalPos: number } {\n const { imageTokenId, mergeSize } = this.mropeParams();\n const seq = inputIds.length;\n if (seq > this.maxSeqLen) {\n throw new Error(\n `describeImage: prompt+image is ${seq} tokens > maxSeqLen ${this.maxSeqLen}. ` +\n \"Increase maxSeqLen or use a smaller image.\",\n );\n }\n this.executor.reset();\n this.executor.writeInput(\"vision_embeds\", visionEmbeds);\n\n const rowMap = new Int32Array(seq).fill(-1);\n let v = 0;\n for (let i = 0; i < seq; i++) {\n if (inputIds[i] === imageTokenId) rowMap[i] = v++;\n }\n const positionIds3 = buildMRoPEPositionIds(inputIds, [gridTHW], imageTokenId, mergeSize);\n const lastLogicalPos = this.writeMRoPEPrefill(positionIds3, seq, rowMap);\n return { lastLogicalPos };\n }\n\n /**\n * Gemma 4 multimodal prefill + decode. Unlike Qwen3.5 (M-RoPE), Gemma 4 uses\n * STANDARD sequential 1D RoPE computed inside each layer from the KV write\n * position, so there are no host cos/sin inputs and decode positions are simply\n * the running seqPos — identical to plain text generation. We only upload the\n * merged vision embeds + an image-token row-map (EmbedSplice scatters them into\n * the image_token rows) before the forward pass.\n */\n private async runMultimodalGemma4(\n visionEmbeds: Float32Array,\n inputIds: number[],\n imageTokenId: number,\n options: GenerateOptions,\n ): Promise<GenerateResult> {\n const seq = inputIds.length;\n if (seq > this.maxSeqLen) {\n throw new Error(\n `describeImage: prompt+image is ${seq} tokens > maxSeqLen ${this.maxSeqLen}. ` +\n \"Increase maxSeqLen or use a smaller image.\",\n );\n }\n this.setPhase(`describe:splice:seq=${seq}`);\n this.executor.reset();\n this.executor.writeInput(\"vision_embeds\", visionEmbeds);\n // row_map[i] = vision-buffer row for the i-th image token, -1 for text rows.\n const rowMap = new Int32Array(seq).fill(-1);\n let v = 0;\n for (let i = 0; i < seq; i++) {\n if (inputIds[i] === imageTokenId) rowMap[i] = v++;\n }\n this.executor.writeInput(\"vision_row_map\", rowMap);\n\n this.setPhase(\"describe:text-decode\");\n const { maxTokens = 512, stopSequences = [], sampling = {}, onToken } = options;\n const startTime = performance.now();\n const isGreedy = (sampling.temperature ?? 0.7) < 1e-6;\n\n let { logits } = await this.executor.forward(new Uint32Array(inputIds));\n\n const generatedIds: number[] = [];\n let finishReason: GenerateResult[\"finishReason\"] = \"max_tokens\";\n let generatedText = \"\";\n const eosId = this.tokenizer.config.eosTokenId;\n // Gemma model turns end with the end-of-turn token `<turn|>` (id 106), NOT the\n // generic `<eos>` — treat it as a stop so chat decode doesn't run on into\n // repetition past the answer.\n const eotId = this.resolveEndOfTurnId();\n\n const consumeToken = (nextToken: number): boolean => {\n generatedIds.push(nextToken);\n if ((eosId !== null && nextToken === eosId) || (eotId !== null && nextToken === eotId)) {\n finishReason = \"eos\";\n return true;\n }\n const tokenText = this.tokenizer.decode([nextToken], true);\n generatedText += tokenText;\n onToken?.(tokenText);\n if (stopSequences.some((s) => generatedText.includes(s))) {\n for (const s of stopSequences) {\n const idx = generatedText.indexOf(s);\n if (idx !== -1) generatedText = generatedText.slice(0, idx);\n }\n finishReason = \"stop_sequence\";\n return true;\n }\n return false;\n };\n\n for (let step = 0; step < maxTokens; step++) {\n let nextToken: number;\n if (step === 0) {\n nextToken = sampleToken(logits, sampling, [...inputIds, ...generatedIds]);\n } else if (isGreedy) {\n nextToken = await this.executor.forwardArgmax(\n new Uint32Array([generatedIds[generatedIds.length - 1]]),\n );\n } else {\n nextToken = sampleToken(logits, sampling, [...inputIds, ...generatedIds]);\n }\n\n if (consumeToken(nextToken)) break;\n\n if (!isGreedy) {\n const result = await this.executor.forward(new Uint32Array([nextToken]));\n logits = result.logits;\n }\n }\n\n const totalTime = performance.now() - startTime;\n const tokensGenerated = generatedIds.length;\n return {\n text: generatedText,\n tokensGenerated,\n tokensPerSecond: tokensGenerated / (totalTime / 1000),\n totalTime,\n finishReason,\n tokenIds: [...generatedIds],\n };\n }\n\n /** Prepare + prefill + decode for a fully-specified multimodal token sequence. */\n private async runMultimodal(\n visionEmbeds: Float32Array,\n gridTHW: [number, number, number],\n inputIds: number[],\n options: GenerateOptions,\n ): Promise<GenerateResult> {\n this.setPhase(`describe:splice:seq=${inputIds.length}`);\n const { lastLogicalPos } = this.prepareMultimodalPrefill(visionEmbeds, gridTHW, inputIds);\n this.setPhase(\"describe:text-decode\");\n return this.generateFromPrepared(inputIds, lastLogicalPos + 1, options);\n }\n\n /**\n * Debug: run ONLY the multimodal prefill for an explicit token sequence and\n * return the spliced input embeddings [seq, hidden] + first-token logits. Lets\n * tests compare the fused text+vision stream and M-RoPE numerically vs HF\n * without the decode loop overwriting intermediate buffers.\n */\n async debugMultimodalPrefill(\n patches: Float32Array,\n gridTHW: [number, number, number],\n inputIds: number[],\n ): Promise<{ splicedEmbeds: Float32Array; logits: Float32Array; seq: number }> {\n this.checkDestroyed();\n if (!this._multimodalGraph || !this.visionExecutor) {\n throw new Error(\"debugMultimodalPrefill requires a multimodal engine (enableVision: true).\");\n }\n const vision = await this.encodeImage(patches, gridTHW);\n this.prepareMultimodalPrefill(vision.embeds, gridTHW, inputIds);\n const { logits } = await this.executor.forward(new Uint32Array(inputIds));\n const splicedEmbeds = await this.executor.debugReadBuffer(\n \"embed_spliced\",\n inputIds.length * this.config.hidden_size,\n );\n return { splicedEmbeds, logits, seq: inputIds.length };\n }\n\n /**\n * Internal: run prefill (assumes M-RoPE/splice inputs already written) + decode,\n * with decode logical positions starting at `decodeStartPos`. Used by\n * describeImage so the post-image cursor is honored.\n */\n private async generateFromPrepared(\n inputIds: number[],\n decodeStartPos: number,\n options: GenerateOptions,\n ): Promise<GenerateResult> {\n const { maxTokens = 512, stopSequences = [], sampling = {}, onToken } = options;\n const startTime = performance.now();\n const isGreedy = (sampling.temperature ?? 0.7) < 1e-6;\n\n let { logits } = await this.executor.forward(new Uint32Array(inputIds));\n\n const generatedIds: number[] = [];\n let finishReason: GenerateResult[\"finishReason\"] = \"max_tokens\";\n let generatedText = \"\";\n const eosId = this.tokenizer.config.eosTokenId;\n const eotId = this.resolveEndOfTurnId();\n let mmLogicalPos = decodeStartPos;\n\n const consumeToken = (nextToken: number): boolean => {\n generatedIds.push(nextToken);\n if ((eosId !== null && nextToken === eosId) || (eotId !== null && nextToken === eotId)) {\n finishReason = \"eos\";\n return true;\n }\n const tokenText = this.tokenizer.decode([nextToken], true);\n generatedText += tokenText;\n onToken?.(tokenText);\n if (stopSequences.some((s) => generatedText.includes(s))) {\n for (const s of stopSequences) {\n const idx = generatedText.indexOf(s);\n if (idx !== -1) generatedText = generatedText.slice(0, idx);\n }\n finishReason = \"stop_sequence\";\n return true;\n }\n return false;\n };\n\n for (let step = 0; step < maxTokens; step++) {\n let nextToken: number;\n if (step === 0) {\n nextToken = sampleToken(logits, sampling, [...inputIds, ...generatedIds]);\n } else if (isGreedy) {\n this.writeMRoPEDecodeStep(this.executor.currentSeqPos, mmLogicalPos);\n nextToken = await this.executor.forwardArgmax(\n new Uint32Array([generatedIds[generatedIds.length - 1]]),\n );\n mmLogicalPos++;\n } else {\n nextToken = sampleToken(logits, sampling, [...inputIds, ...generatedIds]);\n }\n\n if (consumeToken(nextToken)) break;\n\n if (!isGreedy) {\n this.writeMRoPEDecodeStep(this.executor.currentSeqPos, mmLogicalPos);\n const result = await this.executor.forward(new Uint32Array([nextToken]));\n logits = result.logits;\n mmLogicalPos++;\n }\n }\n\n const totalTime = performance.now() - startTime;\n const tokensGenerated = generatedIds.length;\n return {\n text: generatedText,\n tokensGenerated,\n tokensPerSecond: tokensGenerated / (totalTime / 1000),\n totalTime,\n finishReason,\n tokenIds: [...generatedIds],\n };\n }\n\n /**\n * Embed text into an L2-normalized vector. The pooling strategy depends on the\n * model: Qwen3-Embedding uses last-token (EOS-position) pooling, while\n * EmbeddingGemma (Gemma3 encoder) uses mean pooling over all tokens followed by\n * a 2-layer Dense head. Requires an embedding model (loaded with\n * { embedding: true }).\n *\n * The returned Float32Array has unit L2 norm, so cosine similarity reduces to a\n * dot product. Length is the model's embedding dim (768 for EmbeddingGemma;\n * config.hidden_size for Qwen3-Embedding).\n *\n * EmbeddingGemma is asymmetric — pass `{ taskType: \"query\" }` for search\n * queries and `{ taskType: \"document\" }` for the corpus, or a raw\n * `{ taskPrompt }` for other tasks (clustering/classification/STS).\n */\n async embed(text: string, options: EmbedOptions = {}): Promise<Float32Array> {\n this.checkDestroyed();\n const release = await this._acquireGenLock();\n try {\n return await this._embedLocked(text, options);\n } finally {\n release();\n }\n }\n\n private async _embedLocked(text: string, options: EmbedOptions = {}): Promise<Float32Array> {\n this.checkDestroyed();\n if (!this._isEmbedding) {\n throw new Error(\n \"embed() requires an embedding model. Load with { embedding: true } \" +\n \"(e.g. repo: 'Qwen/Qwen3-Embedding-0.6B' or \" +\n \"'mlx-community/embeddinggemma-300m-4bit').\",\n );\n }\n\n // Reset non-autoregressive state before each embed call.\n this.executor.reset();\n\n const { instruction, taskType, taskPrompt, maxTokens } = options;\n const isGemmaEncoder =\n this._architecture === \"Gemma3TextModel\" || this._architecture === \"Gemma3Model\";\n\n if (isGemmaEncoder) {\n // EmbeddingGemma: apply the task prefix, mean-pool over all tokens (no EOS\n // pooling token appended — every token participates in the mean).\n const prefix =\n taskPrompt ?? EMBEDDING_GEMMA_PROMPTS[taskType ?? \"query\"] ?? EMBEDDING_GEMMA_PROMPTS.query;\n const input = `${prefix}${text}`;\n\n // The Gemma tokenizer prepends <bos> per its config (add_bos_token: true).\n let ids = this.tokenizer.encode(input);\n\n const cap = maxTokens ?? this.config.context_length;\n if (ids.length > cap) {\n ids = ids.slice(0, cap);\n }\n\n return this.executor.embed(new Uint32Array(ids));\n }\n\n // Qwen3-Embedding: optional instruction prefix + last-token (EOS) pooling.\n const input = instruction ? `Instruct: ${instruction}\\nQuery:${text}` : text;\n\n let ids = this.tokenizer.encode(input);\n\n // Last-token pooling reads the final position; Qwen3-Embedding pools the\n // hidden state at a trailing <|endoftext|> (id 151643 — the model config's\n // eos_token_id), NOT the chat <|im_end|> token the tokenizer reports as\n // eos_token. Resolve the literal token and append it if absent.\n const padId = this.tokenizer.tokenToId(\"<|endoftext|>\") ?? this.tokenizer.config.eosTokenId;\n if (padId !== null && ids[ids.length - 1] !== padId) {\n ids.push(padId);\n }\n\n // Truncate to budget, keeping the trailing pooling token as the last token.\n const cap = maxTokens ?? this.config.context_length;\n if (ids.length > cap) {\n const tail = padId !== null && ids[ids.length - 1] === padId ? [padId] : [];\n ids = [...ids.slice(0, cap - tail.length), ...tail];\n }\n\n return this.executor.embed(new Uint32Array(ids));\n }\n\n /**\n * Generate text as an async iterator (streaming).\n *\n * Uses the onToken callback from generate() to push tokens into a queue\n * that the async generator yields from. The generator returns the full\n * GenerateResult when generation completes.\n *\n * Usage:\n * const gen = engine.stream(\"Hello!\");\n * for await (const token of gen) {\n * process.stdout.write(token);\n * }\n * const result = gen.next(); // { done: true, value: GenerateResult }\n */\n async *stream(\n prompt: string | ChatMessage[],\n options: GenerateOptions = {},\n ): AsyncGenerator<string, GenerateResult, undefined> {\n this.checkDestroyed();\n\n // Token queue: onToken callback pushes here, generator yields from here.\n const tokenQueue: string[] = [];\n let resolve: (() => void) | null = null;\n let done = false;\n\n // Notify the generator that a new token is available\n const pushToken = (token: string): void => {\n tokenQueue.push(token);\n if (resolve) {\n const r = resolve;\n resolve = null;\n r();\n }\n };\n\n // Wait until at least one token is available or generation is done\n const waitForToken = (): Promise<void> => {\n if (tokenQueue.length > 0 || done) {\n return Promise.resolve();\n }\n return new Promise<void>((r) => {\n resolve = r;\n });\n };\n\n // Start generation in the background with our onToken callback\n const genPromise = this.generate(prompt, {\n ...options,\n onToken: (token) => {\n options.onToken?.(token); // Forward to user's callback too\n pushToken(token);\n },\n }).then((result) => {\n done = true;\n // Wake up the generator if it's waiting\n if (resolve) {\n const r = resolve;\n resolve = null;\n r();\n }\n return result;\n });\n\n // Yield tokens as they arrive\n let yielded = 0;\n while (true) {\n await waitForToken();\n\n // Yield all queued tokens\n while (yielded < tokenQueue.length) {\n yield tokenQueue[yielded++];\n }\n\n // If generation is done and we've yielded everything, return the result\n if (done && yielded >= tokenQueue.length) {\n break;\n }\n }\n\n return await genPromise;\n }\n\n /**\n * Debug: read back a named GPU buffer (weight or activation).\n * Call after forward() to inspect intermediate values.\n */\n async debugReadBuffer(tensorName: string, maxElements?: number): Promise<Float32Array> {\n return this.executor.debugReadBuffer(tensorName, maxElements);\n }\n\n /**\n * Run GPU diagnostics (buffer integrity, compute, shared memory).\n * Useful for isolating Safari/WebKit-specific WebGPU issues.\n */\n async diagnose(): Promise<GPUDiagnosticResult> {\n return verifyGPU(this.ctx);\n }\n\n /**\n * Run GPU diagnostics without loading a model.\n * Quick way to check if WebGPU is working correctly on this device.\n */\n static async quickDiagnose(): Promise<GPUDiagnosticResult> {\n const ctx = await initGPU();\n const result = await verifyGPU(ctx);\n clearPipelineCache(ctx.device);\n ctx.device.destroy();\n return result;\n }\n\n /**\n * Run a raw forward pass (no tokenization/chat template).\n * Returns logits for the last token.\n */\n async rawForward(inputIds: Uint32Array): Promise<{ logits: Float32Array }> {\n return this.executor.forward(inputIds);\n }\n\n /**\n * Reset executor state (SSM, positions, etc.)\n */\n resetState(): void {\n this.executor.reset();\n }\n\n /**\n * Encode text to token IDs (useful for debugging / token counting).\n */\n encode(text: string): number[] {\n return this.tokenizer.encode(text);\n }\n\n /**\n * Decode token IDs to text.\n */\n decode(ids: number[], skipSpecialTokens?: boolean): string {\n return this.tokenizer.decode(ids, skipSpecialTokens);\n }\n\n /**\n * Integrity check: reads back key weight tensors and runs a single forward pass,\n * returning checksums for comparison against a known-good reference (Dawn/Node.js).\n *\n * Use this to isolate Safari/iPad corruption:\n * - If weights mismatch → fetch/download pipeline is corrupt\n * - If weights match but logits mismatch → kernel computation bug on Metal\n *\n * Resets executor state before and after (safe to call anytime).\n */\n async integrityCheck(): Promise<IntegrityCheckResult> {\n this.checkDestroyed();\n const checks: IntegrityCheckEntry[] = [];\n const log = (label: string, data: Float32Array | Uint32Array) => {\n const f = data instanceof Float32Array ? data : new Float32Array(data.buffer);\n let sum = 0;\n let maxVal = -Infinity;\n let argmax = 0;\n for (let i = 0; i < f.length; i++) {\n sum += f[i];\n if (f[i] > maxVal) {\n maxVal = f[i];\n argmax = i;\n }\n }\n const entry: IntegrityCheckEntry = {\n label,\n length: f.length,\n sum: Math.round(sum * 1e6) / 1e6,\n first4: [\n Math.round(f[0] * 1e6) / 1e6,\n Math.round(f[1] * 1e6) / 1e6,\n Math.round(f[2] * 1e6) / 1e6,\n Math.round(f[3] * 1e6) / 1e6,\n ],\n argmax,\n maxVal: Math.round(maxVal * 1e4) / 1e4,\n };\n checks.push(entry);\n return entry;\n };\n\n // 0. Report Metal detection and adapter info\n checks.push({\n label: `webkit_detection: isWebKitWebGPU=${this.ctx.isWebKitWebGPU} needsMultiEncoder=${this.executor.needsMultiEncoder}`,\n length: 0,\n sum: 0,\n first4: [0, 0, 0, 0],\n argmax: 0,\n maxVal: 0,\n note: this.ctx.adapterDescription,\n });\n\n // 1. Read back weight tensors (no forward pass needed)\n const weightNames = [\"norm.weight\", \"layers.0.input_layernorm.weight\"];\n\n for (const name of weightNames) {\n try {\n const data = await this.debugReadBuffer(name);\n log(name, data);\n } catch {\n checks.push({\n label: name,\n length: 0,\n sum: NaN,\n first4: [NaN, NaN, NaN, NaN],\n argmax: -1,\n maxVal: NaN,\n error: \"buffer not found\",\n });\n }\n }\n\n // 2. Try to read INT4 packed weights (gate_proj AND embed_tokens)\n for (const qName of [\n \"layers.0.mlp.gate_proj.weight.q\",\n \"embed_tokens.weight.q\",\n \"embed_tokens.weight.scales\",\n \"embed_tokens.weight.zeros\",\n ]) {\n try {\n const q = await this.debugReadBuffer(qName, 16);\n log(`${qName} (reinterpret)`, q);\n } catch {\n checks.push({\n label: qName,\n length: 0,\n sum: NaN,\n first4: [NaN, NaN, NaN, NaN],\n argmax: -1,\n maxVal: NaN,\n error: \"not found\",\n });\n }\n }\n\n // 3a. Single-dispatch diagnostic: run ONLY EmbeddingInt4 with production bind group\n this.executor.reset();\n try {\n const result = await this.executor.debugFirstDispatch(new Uint32Array([1]));\n const entry = log(`single_dispatch(${result.opType})`, result.output);\n entry.note = `dispatch=${result.dispatchSize.join(\",\")} node=${result.nodeId}`;\n } catch (e: any) {\n checks.push({\n label: \"single_dispatch\",\n length: 0,\n sum: NaN,\n first4: [NaN, NaN, NaN, NaN],\n argmax: -1,\n maxVal: NaN,\n error: e.message,\n });\n }\n\n // 3a2. Run entry[1] (RMSNorm) in isolation — embed_out still has data from debugFirstDispatch.\n // If RMSNorm produces non-zero output, the bind group is correct and it's a barrier issue.\n // If zeros, the bind group is pointing to the wrong buffer.\n try {\n const result = await this.executor.debugDispatchEntry(1, 1);\n const entry = log(`isolated_entry1(${result.opType})`, result.output);\n entry.note = `node=${result.nodeId}`;\n } catch (e: any) {\n checks.push({\n label: \"isolated_entry1\",\n length: 0,\n sum: NaN,\n first4: [NaN, NaN, NaN, NaN],\n argmax: -1,\n maxVal: NaN,\n error: e.message,\n });\n }\n\n // 3a3. Run entry[2] (MatVecInt4) in isolation — layer0_norm1_out has data from isolated_entry1.\n // If non-zero: MatVecInt4 kernel works on this GPU.\n // If zeros: the kernel itself is broken on this GPU (not a barrier issue).\n try {\n const result = await this.executor.debugDispatchEntry(2, 1);\n const entry = log(`isolated_entry2(${result.opType})`, result.output);\n entry.note = `node=${result.nodeId}`;\n } catch (e: any) {\n checks.push({\n label: \"isolated_entry2\",\n length: 0,\n sum: NaN,\n first4: [NaN, NaN, NaN, NaN],\n argmax: -1,\n maxVal: NaN,\n error: e.message,\n });\n }\n\n // 3b. Show JS-computed params for first 5 entries (no GPU dispatch needed)\n this.executor.reset();\n const jsParams = this.executor.debugComputeParams(1, 5);\n for (const p of jsParams) {\n checks.push({\n label: `jsParams[${p.idx}] ${p.opType} dispatch=[${p.dispatchSize}] u32=[${p.paramsU32}]`,\n length: p.paramsU32.length,\n sum: p.paramsU32.reduce((a, b) => a + b, 0),\n first4: p.paramsU32.slice(0, 4).map(Number),\n argmax: 0,\n maxVal: 0,\n });\n }\n\n // 3c. Full forward pass with token 1 — compare logits\n this.executor.reset();\n try {\n const { logits } = await this.executor.forward(new Uint32Array([1]));\n log(\"logits(token=1)\", logits);\n\n // Also read embed_out (embedding layer output)\n try {\n const embed = await this.debugReadBuffer(\"embed_out\", 16);\n log(\"embed_out\", embed);\n } catch {\n // embed_out may not exist in all architectures\n }\n\n // 3c. Pipeline probe: read activations at ~8 points to find where data drops to zero\n try {\n const probes = await this.executor.debugPipelineProbe(1);\n for (const p of probes) {\n const paramsStr = p.uniformParams ? ` params=[${p.uniformParams.join(\",\")}]` : \"\";\n const entry: IntegrityCheckEntry = {\n label: `probe[${p.idx}] ${p.opType} → ${p.tensor}${paramsStr}`,\n length: 16,\n sum: p.sum,\n first4: p.first4,\n argmax: 0,\n maxVal: Math.max(...p.first4.map(Math.abs)),\n };\n // Flag if sum is exactly 0 (likely dead activation)\n if (p.sum === 0 && p.first4.every((v) => v === 0)) {\n entry.match = \"FAIL\";\n entry.note = \"all zeros — activation dead\";\n }\n checks.push(entry);\n }\n } catch (e: any) {\n checks.push({\n label: \"pipeline_probe\",\n length: 0,\n sum: NaN,\n first4: [NaN, NaN, NaN, NaN],\n argmax: -1,\n maxVal: NaN,\n error: e.message,\n });\n }\n } catch (e: any) {\n checks.push({\n label: \"logits(token=1)\",\n length: 0,\n sum: NaN,\n first4: [NaN, NaN, NaN, NaN],\n argmax: -1,\n maxVal: NaN,\n error: e.message,\n });\n }\n\n // Reset state so the engine is clean for actual use\n this.executor.reset();\n\n // Dawn reference values for Qwen3.5-0.8B Q4 (updated per current build).\n // Weight checksums are stable across builds; logits may drift with code changes.\n // Key diagnostic: if weights match but logits differ → kernel bug on Metal.\n // If weights don't match → data transfer/download corruption on Safari.\n const reference: Record<string, { sum: number; first4: number[] }> = {\n \"norm.weight\": {\n sum: 4412.571289,\n first4: [0.222656, 3.75, 3.640625, 4.0625],\n },\n \"layers.0.input_layernorm.weight\": {\n sum: 1267.312683,\n first4: [2.0, 1.294922, 1.535156, 1.746094],\n },\n embed_out: {\n sum: -0.067839,\n first4: [0.010059, 0.0264, 0.001888, -0.030794],\n },\n };\n\n // Compare weights against reference and flag obvious corruption\n for (const check of checks) {\n const ref = reference[check.label];\n if (ref) {\n const sumDelta = Math.abs(check.sum - ref.sum);\n const sumMatch = sumDelta < Math.max(Math.abs(ref.sum) * 0.001, 1);\n const first4Match = check.first4.every((v, i) => Math.abs(v - ref.first4[i]) < 0.01);\n check.match = sumMatch && first4Match ? \"PASS\" : \"FAIL\";\n check.refSum = ref.sum;\n } else if (check.label === \"logits(token=1)\") {\n // For logits: check for corruption signals (NaN, Inf, all-same, argmax in range)\n const hasNaN = check.first4.some((v) => Number.isNaN(v));\n const hasInf = check.first4.some((v) => !Number.isFinite(v));\n const allSame = check.first4.every((v) => v === check.first4[0]);\n const argmaxValid = check.argmax >= 0 && check.argmax < check.length;\n check.match = !hasNaN && !hasInf && !allSame && argmaxValid ? \"PASS\" : \"FAIL\";\n }\n }\n\n // Console output\n console.log(\"\\n=== INTEGRITY CHECK ===\");\n for (const c of checks) {\n const status = c.error ? \"ERR\" : (c.match ?? \"---\");\n console.log(\n `[${status}] ${c.label}: sum=${c.sum}, first4=[${c.first4.join(\", \")}], ` +\n `argmax=${c.argmax}, len=${c.length}` +\n (c.refSum !== undefined ? ` (ref sum=${c.refSum})` : \"\") +\n (c.error ? ` ERROR: ${c.error}` : \"\") +\n (c.note ? ` | ${c.note}` : \"\"),\n );\n }\n console.log(\"=== END INTEGRITY CHECK ===\\n\");\n\n const allPass = checks.every((c) => c.match === \"PASS\" || c.match === undefined);\n return { checks, allPass };\n }\n\n /**\n * Destroy the engine and free all GPU resources.\n */\n destroy(): void {\n if (this._destroyed) return;\n this._destroyed = true;\n // A TTS-only lite engine has no base executor/device (both null); only its\n // lazily-built native TTS engines need tearing down.\n this._executor?.destroy();\n this._kaniTTS?.destroy();\n this._outeTTS?.destroy();\n this._parlerTTS?.destroy();\n this._gepardTTS?.destroy();\n this.visionExecutor?.destroy();\n if (this._ctx) {\n clearPipelineCache(this._ctx.device);\n this._ctx.device.destroy();\n }\n }\n\n private checkDestroyed(): void {\n if (this._destroyed) {\n throw new Error(\"WebGPUEngine has been destroyed\");\n }\n }\n\n /**\n * Acquire the per-engine generation lock (see {@link _genQueueTail}). Returns a\n * release fn that MUST be called in a `finally` so the chain never wedges. This\n * is a plain promise-chain mutex: each caller links onto the current tail and\n * only proceeds once the previous holder releases.\n *\n * Non-reentrant: only the top-level generation entry points that directly drive\n * the shared executor readback — generate(), embed(), describeImage() — acquire\n * it. Helpers that delegate to generate() (autocomplete, rewrite,\n * generateWithTools, generateObject, stream) inherit serialization through that\n * single call and must NOT acquire it themselves, or they would self-deadlock.\n */\n private async _acquireGenLock(): Promise<() => void> {\n let release!: () => void;\n const next = new Promise<void>((resolve) => {\n release = resolve;\n });\n const prev = this._genQueueTail;\n this._genQueueTail = next;\n await prev;\n return release;\n }\n}\n\nexport {\n dequantizeGemma4VisionProjection,\n dequantizeMLXProjection,\n type Gemma4VisionGraphInfo,\n generateGemma4VisionGraph,\n patchGemma4VisionClips,\n resolveGemma4VisionInfo,\n} from \"./architectures/gemma4_vision.js\";\n// Gepard-1.0 native streaming TTS (stock Qwen3.5 full-attention body + 32 parallel\n// FSQ classifier heads emitting a whole frame per forward + NanoCodec 21.5 fps\n// decoder). End-to-end: GepardTTS.create() then engine.speak(text, { model:\n// DEFAULT_MODELS.ttsGepard }) → 22 kHz PCM, streamed chunk-by-chunk via onChunk.\nexport {\n buildGepardTextLayout,\n type GepardConfig,\n generateGepardBackboneGraph,\n gepardChannelLevels,\n gepardCodesToLatent,\n parseGepardConfig,\n} from \"./architectures/gepard_tts.js\";\nexport type { GraphDType, KVDType, KvMode } from \"./architectures/index.js\";\n// Kani-TTS-2 native TTS (LFM2-350M codec-LM + NVIDIA NeMo NanoCodec). End-to-end:\n// KaniTTS.create() then engine.speak(text) → 22 kHz PCM. The NanoCodec decoder is\n// validated bit-exact; the codec-LM AR driver (frame positions + learnable RoPE)\n// lives in kani-tts.ts.\nexport {\n audioTokensToCodes,\n generateKaniTtsGraph,\n generateNanoCodecDecoderGraph,\n parseKaniConfig,\n} from \"./architectures/kani_tts.js\";\n// Moonshine native STT (encoder-decoder). End-to-end: MoonshineSTT.create() then\n// engine.transcribe(pcm16k). CrossAttention + conv-frontend kernels validated;\n// dual-graph executor wired (encoder once → frozen K/V → AR decode w/ cross-attn).\nexport {\n generateMoonshineDecoderGraph,\n generateMoonshineEncoderGraph,\n MOONSHINE_REMAINING_WORK,\n moonshineEncoderFrames,\n parseMoonshineConfig,\n} from \"./architectures/moonshine.js\";\n// OuteTTS-1.0-0.6B native TTS (plain Qwen3-0.6B codec-LM + descript DAC.speech\n// decoder, 24 kHz / 2-codebook). FOUNDATION: OuteTTS.create({ codecWeightsPath })\n// then .speak(text) → 24 kHz PCM. The DAC decoder (RVQDequant + Conv/Snake stack)\n// is validated bit-exact vs the torch reference (scripts/engine/test-outetts-codec.mjs);\n// the AR backbone loop lives in outetts.ts. Cloning / int4 / engine.speak surface\n// are the next phase.\nexport {\n audioTokensToDacCodes,\n dacOutputLength,\n generateDacSpeechDecoderGraph,\n generateOuteTtsBackboneGraph,\n parseOuteTtsConfig,\n} from \"./architectures/outetts.js\";\nexport { generateQwen3_5VisionGraph } from \"./architectures/qwen3_5_vision.js\";\nexport {\n RequestScheduler,\n type SchedulerStats,\n type ServeOptions,\n type ServeResult,\n} from \"./batch/scheduler.js\";\nexport {\n Swarm,\n type SwarmMemberResult,\n type SwarmOptions,\n type SwarmTask,\n type SwarmTaskOptions,\n} from \"./batch/swarm.js\";\nexport type { GPUDiagnosticResult } from \"./device.js\";\nexport { initGPU } from \"./device.js\";\nexport { Executor } from \"./executor.js\";\nexport {\n type GepardAudioChunk,\n type GepardDType,\n type GepardSpeakOptions,\n type GepardSpeakResult,\n GepardTTS,\n type GepardTTSOptions,\n} from \"./gepard-tts.js\";\nexport type { ModelArchConfig, ModelCapabilities } from \"./ir.js\";\nexport {\n type KaniDType,\n KaniTTS,\n type KaniTTSOptions,\n type SpeakOptions,\n type SpeakResult,\n} from \"./kani-tts.js\";\nexport {\n type LoadedKaniTTS,\n type LoadedMoonshine,\n loadKaniTTS,\n loadModel,\n loadMoonshine,\n quantizeKaniBackbone,\n} from \"./model-loader.js\";\nexport { MoonshineEncoderExecutor } from \"./moonshine-executor.js\";\nexport {\n MoonshineSTT,\n type MoonshineSTTOptions,\n type TranscribeOptions,\n type TranscribeResult,\n} from \"./moonshine-stt.js\";\nexport {\n buildOutePromptString,\n loadOuteSpeaker,\n type OuteDType,\n type OuteSpeaker,\n type OuteSpeakerWord,\n type OuteSpeakOptions,\n type OuteSpeakResult,\n OuteTTS,\n type OuteTTSOptions,\n} from \"./outetts.js\";\nexport {\n type ParlerSpeakOptions,\n type ParlerSpeakResult,\n ParlerTTS,\n type ParlerTTSOptions,\n} from \"./parler-tts.js\";\nexport type { SamplingParams } from \"./sampler.js\";\n// Re-export useful types\nexport type { ChatMessage } from \"./tokenizer.js\";\nexport { Tokenizer } from \"./tokenizer.js\";\nexport type { VisionInputs } from \"./vision-executor.js\";\nexport { VisionExecutor } from \"./vision-executor.js\";\nexport type {\n Gemma4VisionGridConfig,\n Gemma4VisionPositionTensors,\n ImageProcessorConfig,\n PreprocessedImage,\n VisionGridConfig,\n VisionPositionTensors,\n} from \"./vision-preprocess.js\";\nexport {\n buildGemma4PoolMatrix,\n buildGemma4PosEmbeds,\n buildGemma4RotaryCosSin,\n buildGemma4VisionPositionTensors,\n buildMRoPECosSin,\n buildMRoPEPositionIds,\n buildPosEmbeds,\n buildPositionIds,\n buildRotaryCosSin,\n buildVisionPositionTensors,\n GEMMA4_IMAGE_PROCESSOR,\n mropeFreqDims,\n preprocessImage,\n preprocessImageGemma4,\n QWEN3_5_IMAGE_PROCESSOR,\n smartResize,\n} from \"./vision-preprocess.js\";\n"],"mappings":"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"}
|