Humuhumu33 commited on
Commit
8dd57e9
·
verified ·
1 Parent(s): 096dc76

Q Live: serverless voice AI — 100% in-browser, models κ-streamed from HOLOGRAMTECH

Browse files
This view is limited to 50 files because it contains too many changes.   See raw diff
Files changed (50) hide show
  1. README.md +21 -9
  2. _shared/q/holo-q-mux.js +203 -0
  3. _shared/voice/holo-q-faculty-models.mjs +120 -0
  4. _shared/voice/holo-voice-asr.mjs +154 -0
  5. _shared/voice/holo-voice-tts.mjs +115 -0
  6. _shared/voice/holo-voice-turn.mjs +101 -0
  7. _shared/voice/holo-voice-vad.mjs +90 -0
  8. _shared/voice/vendor/kokoro/kokoro.js +1 -0
  9. _shared/voice/vendor/kokoro/phonemizer.js +0 -0
  10. _shared/voice/vendor/kokoro/stub.js +6 -0
  11. _shared/voice/vendor/kokoro/transformers/ort-wasm-simd-threaded.jsep.mjs +125 -0
  12. _shared/voice/vendor/kokoro/transformers/ort-wasm-simd-threaded.jsep.wasm +3 -0
  13. _shared/voice/vendor/kokoro/transformers/transformers.js +0 -0
  14. _shared/voice/vendor/models/onnx-community/Kokoro-82M-v1.0-ONNX/config.json +3 -0
  15. _shared/voice/vendor/models/onnx-community/Kokoro-82M-v1.0-ONNX/tokenizer.json +175 -0
  16. _shared/voice/vendor/models/onnx-community/Kokoro-82M-v1.0-ONNX/tokenizer_config.json +6 -0
  17. _shared/voice/vendor/models/onnx-community/Kokoro-82M-v1.0-ONNX/voices/af_bella.bin +3 -0
  18. _shared/voice/vendor/models/onnx-community/Kokoro-82M-v1.0-ONNX/voices/af_heart.bin +3 -0
  19. _shared/voice/vendor/models/onnx-community/Kokoro-82M-v1.0-ONNX/voices/af_nicole.bin +3 -0
  20. _shared/voice/vendor/models/onnx-community/Kokoro-82M-v1.0-ONNX/voices/am_fenrir.bin +3 -0
  21. _shared/voice/vendor/models/onnx-community/Kokoro-82M-v1.0-ONNX/voices/am_michael.bin +3 -0
  22. _shared/voice/vendor/models/onnx-community/Kokoro-82M-v1.0-ONNX/voices/am_puck.bin +3 -0
  23. _shared/voice/vendor/models/onnx-community/Kokoro-82M-v1.0-ONNX/voices/bf_emma.bin +3 -0
  24. _shared/voice/vendor/models/onnx-community/Kokoro-82M-v1.0-ONNX/voices/bm_george.bin +3 -0
  25. _shared/voice/vendor/models/onnx-community/silero-vad/onnx/model.onnx +3 -0
  26. _shared/voice/vendor/models/onnx-community/silero-vad/onnx/model_quantized.onnx +3 -0
  27. _shared/voice/vendor/transformers/ort-wasm-simd-threaded.jsep.wasm +3 -0
  28. _shared/voice/vendor/transformers/transformers.js +0 -0
  29. _shared/voice/vendor/transformers/transformers.mjs +0 -0
  30. apps/q/core/engine.js +203 -0
  31. apps/q/core/kappa.js +76 -0
  32. apps/q/core/loader.js +205 -0
  33. apps/q/core/q-brain-fast.mjs +236 -0
  34. apps/q/core/q-self.mjs +62 -0
  35. apps/q/core/semantic.js +98 -0
  36. apps/q/forge/gguf-forge-iq-dequant.mjs +260 -0
  37. apps/q/forge/gguf-forge-iq-grids.mjs +14 -0
  38. apps/q/forge/gguf-forge-kstream.mjs +111 -0
  39. apps/q/forge/gguf-forge.mjs +226 -0
  40. apps/q/forge/gpu/holo-files.mjs +51 -0
  41. apps/q/forge/gpu/holo-model-pack.mjs +47 -0
  42. apps/q/forge/gpu/holo-moonshine-asr.mjs +219 -0
  43. apps/q/forge/gpu/holo-moonshine-ear.mjs +31 -0
  44. apps/q/forge/gpu/holo-onnx-kserve.mjs +53 -0
  45. apps/q/forge/gpu/holo-pack-shards.mjs +121 -0
  46. apps/q/forge/gpu/holo-q-pack-provider.mjs +149 -0
  47. apps/q/forge/gpu/holo-whisper-stream.mjs +108 -0
  48. apps/q/forge/holo-archive.mjs +207 -0
  49. apps/q/holo-delta.mjs +156 -0
  50. apps/q/holo-load-delta.mjs +54 -0
README.md CHANGED
@@ -1,13 +1,25 @@
1
  ---
2
- title: Q Live
3
- emoji: 🐠
4
- colorFrom: yellow
5
  colorTo: purple
6
- sdk: gradio
7
- sdk_version: 6.19.0
8
- python_version: '3.13'
9
- app_file: app.py
10
- pinned: false
11
  ---
12
 
13
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  ---
2
+ title: Q Live — the Serverless Voice
3
+ emoji: 🎙️
4
+ colorFrom: indigo
5
  colorTo: purple
6
+ sdk: static
7
+ app_file: index.html
8
+ pinned: true
9
+ short_description: Talk to Q — a voice AI running 100% in your browser
 
10
  ---
11
 
12
+ # Q Live the Serverless Voice
13
+
14
+ Tap the orb and **talk to Q**. Every model — the brain (BitNet‑2B), the ear (Moonshine), the voice
15
+ (Kokoro) — streams by content address from [HOLOGRAMTECH](https://huggingface.co/HOLOGRAMTECH),
16
+ is verified per block, and runs **entirely in your browser** on WebGPU/WASM.
17
+
18
+ **Zero inference server. Your voice never leaves your device. Works offline after first load.**
19
+
20
+ This is the real‑time speech‑to‑speech experience of a datacenter voice pipeline — with no datacenter.
21
+ Cerebras throws a wafer at latency; Q throws your own GPU and its idle time (it starts answering on your
22
+ confident partial while you're still finishing). One self‑verifying κ‑link boots the whole runtime in any
23
+ cold browser.
24
+
25
+ Built with the Hologram stack. Best in a Chromium browser with WebGPU.
_shared/q/holo-q-mux.js ADDED
@@ -0,0 +1,203 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // holo-q-mux.js — Mixture-of-Specialists for Holo Q: the OS's helper tasks stop defaulting to one
2
+ // big model and each quietly binds the BEST small specialist the open web offers, run on-device and
3
+ // proven by receipt. The native orchestrator (Holo Mind, ADR-0081) discovers · selects · binds ·
4
+ // routes · verifies a per-task model. "auto" stops meaning "use the main model" and starts meaning
5
+ // "the right tiny mind for this exact job" (ADR-0084).
6
+ //
7
+ // THE FACTORING (the honest part): DISCOVERY is one cheap Hugging Face Hub API call per task
8
+ // (serverless — a browser fetch, never a server); SELECTION is a PURE ranking over the returned
9
+ // metadata (no candidate is downloaded to be judged — that would break "fast" and "serverless"); a
10
+ // chosen specialist is a PLAN, not yet a loaded model — loading streams its weights as a
11
+ // content-addressed κ-disk (Holo Q, ADR-0052) and BINDS it behind the existing per-task provider
12
+ // registry. Until a specialist is bound, routeTask() falls back to the main model — never blocks,
13
+ // never fakes (Law L5 voice). DOM-free, dependency-free; sealing/loading is the caller's job, exactly
14
+ // like holo-q-ai.js and holo-q-diffusion.js. The ranking + routing are re-derivable (Node witness).
15
+
16
+ // ── the faculty surface (the OS surface) → a discovery spec each ────────────────────────────────────
17
+ // `pipeline` is the Hugging Face pipeline_tag the job maps to; `need` the engine capability that runs
18
+ // it; `maxParams` the size ceiling that keeps it browser-fast. Two classes share ONE registry + UI:
19
+ // • CORE I/O faculties (pinned:true) — Q's own senses: respond/listen/speak/code. Their specialist is
20
+ // NOT HF-discovered; it is a precompiled, κ-pinned .holo that ships WITH the OS (see PINNED below,
21
+ // sourced from apps/q/forge/.models/holo-ipfs-pins.json). "auto" for these = the OS's own brain.
22
+ // • HELPER tasks (the rest) — each quietly binds the best small specialist the open web offers, by a
23
+ // cheap HF discovery call. "auto" for these = the right tiny mind, else a fall-back to the main brain.
24
+ export const TASKS = [
25
+ // ── CORE I/O — Q's senses (pinned κ .holo, precompiled, content-addressed; not HF-discovered) ──
26
+ { id: "respond", label: "Respond", job: "Main chat / reasoning", pipeline: "text-generation", need: "generative", maxParams: "1.5B", pinned: true },
27
+ { id: "listen", label: "Listen", job: "Speech → text (ASR)", pipeline: "automatic-speech-recognition", need: "asr", maxParams: "700M", pinned: true },
28
+ { id: "speak", label: "Speak", job: "Text → speech (TTS)", pipeline: "text-to-speech", need: "tts", maxParams: "100M", pinned: true },
29
+ { id: "code", label: "Code", job: "Agentic coding", pipeline: "text-generation", need: "generative", maxParams: "3B", pinned: true },
30
+ // Deep reasoning — a 9B THINKING brain (Qwen3.5). NOT a silent default: the device-tier gate
31
+ // (holo-q-think-tier.mjs) routes the 9B only to capable WebGPU hardware; weak/mobile fall to respond.
32
+ { id: "think", label: "Think", job: "Deep reasoning", pipeline: "text-generation", need: "generative", maxParams: "9B", pinned: true },
33
+ // ── HELPER tasks — each discovers + binds the best browser-runnable small specialist (or main) ──
34
+ { id: "create", label: "Create", job: "Build a holospace", pipeline: "text-generation", need: "generative", maxParams: "8B" },
35
+ { id: "ask", label: "Ask", job: "Answer about a holospace", pipeline: "text-generation", need: "generative", maxParams: "8B" },
36
+ { id: "vision", label: "Vision", job: "Image analysis", pipeline: "image-to-text", need: "vlm", maxParams: "2B" },
37
+ { id: "web-extract", label: "Web extract", job: "Page summarization", pipeline: "summarization", need: "generative", maxParams: "1B" },
38
+ { id: "compression", label: "Compression", job: "Context compaction", pipeline: "summarization", need: "generative", maxParams: "1B" },
39
+ { id: "session-search", label: "Session search",job: "Recall queries", pipeline: "feature-extraction",need: "embedding", maxParams: "200M" },
40
+ { id: "skills-hub", label: "Skills hub", job: "Skill search", pipeline: "feature-extraction",need: "embedding", maxParams: "200M" },
41
+ { id: "approval", label: "Approval", job: "Smart auto-approve", pipeline: "text-classification",need: "classifier",maxParams: "200M" },
42
+ { id: "mcp", label: "MCP", job: "MCP tool routing", pipeline: "zero-shot-classification", need: "classifier", maxParams: "500M" },
43
+ { id: "title-gen", label: "Title gen", job: "Session titles", pipeline: "summarization", need: "generative", maxParams: "500M" },
44
+ { id: "curator", label: "Curator", job: "Skill-usage review", pipeline: "text-classification",need: "classifier",maxParams: "500M" },
45
+ // DETERMINISTIC tasks — routed like any other, but NOT model-discovered: their specialist is a pure
46
+ // encoder (no HF model, no weights, no maxParams). `deterministic:true` makes discovery SKIP them, so
47
+ // they ride the same per-task registry + κ-memo spine without ever pretending to pick a model (honest).
48
+ { id: "import", label: "Import", job: "Encode a GitHub repo as a Holo app", deterministic: true },
49
+ ];
50
+
51
+ // ── PINNED — the OS's own precompiled κ .holo specialists for the core I/O faculties ────────────────
52
+ // Sourced from apps/q/forge/.models/holo-ipfs-pins.json (archiveKappa = the .holo footer = did:holo).
53
+ // `instant` is the always-loads core; `upgrade` (optional) is the silent better tier on capable hardware.
54
+ // These are NOT discovered — the κ IS the identity (Law L1); the loader resolves path → Release → κ-route
55
+ // (IPFS heal) and L5-verifies every block, so no host is trusted. This is "auto = Q's own brain", honestly.
56
+ export const PINNED = {
57
+ respond: { faculty: "respond", instant: { id: "qwen2.5-0.5b", kappa: "41a930c07450623751f84af6a55bbecd54fe608ad6e94adf17f83c712aaf1b91", bytesMB: 491.4 }, upgrade: { id: "qwen2.5-1.5b", kappa: "ea7323369bfeebb344c9d0b6252de485e2b9833784405678f910a16cd7746202", bytesMB: 1117.4 } },
58
+ code: { faculty: "code", instant: { id: "qwen-coder-3b", kappa: "33ca24ae50bf5649b4c431817ebf15924b8aa929ab87868c33abeeeb8f695a17", bytesMB: 2105.0 } },
59
+ // think — the precompiled 9B reasoner (DavidAU Qwen3.5-9B THINKING, imatrix Q4_K_M, arch qwen35). The OS's
60
+ // pinned thinking brain; the device-tier gate (holo-q-think-tier) decides whether THIS device loads it or
61
+ // routes to `respond`. No `upgrade` tier — the 9B IS the top tier; weak/mobile fall back, never auto-load it.
62
+ think: { faculty: "think", instant: { id: "qwen3.5-9b-thinking", kappa: "2c9265545555b864438c49df81b72e4ae9221f32f0b4f8ab4ceaa846ea38d94f", bytesMB: 5627.1 } },
63
+ listen: { faculty: "listen", instant: { id: "moonshine-tiny-int8", kappa: "bbd89df22c86fc54455779be070395cc8dab0c3438cbe85974c9f02d2a291780", bytesMB: 29.5 }, upgrade: { id: "moonshine-tiny-f16", kappa: "ff7e1c8b3c9e360ab062ce96a297e6f2467608c634f2e4b171078180056a72d8", bytesMB: 56.2 } },
64
+ speak: { faculty: "speak", instant: { id: "kokoro-82m", kappa: "5beb3c2171121fc7afa10a6325e45ed540147a4ed54157a01020409ca8694124", bytesMB: 96.5 } },
65
+ };
66
+
67
+ // markers (in a model's tags/library) that say "this can run IN A TAB" — the hard gate on selection.
68
+ export const BROWSER_LIBS = ["onnx", "transformers.js", "transformers.js", "gguf"];
69
+ const OPEN_LICENSES = ["apache-2.0", "mit", "bsd", "openrail", "cc-by", "cc0", "llama"];
70
+ const HF_API = "https://huggingface.co/api/models";
71
+
72
+ // ── pure helpers ─────────────────────────────────────────────────────────────────────────────────
73
+ const _tags = (m) => [...(m.tags || []), m.library_name, m.pipeline_tag].filter(Boolean).map((s) => String(s).toLowerCase());
74
+
75
+ // can this model execute in the browser? (an ONNX / transformers.js / GGUF marker present)
76
+ export function runnable(m) { const t = _tags(m); return BROWSER_LIBS.some((lib) => t.includes(lib)); }
77
+
78
+ // estimate parameter count from the id/tags ("0.5b", "135m", "tiny"/"small"/"base") — an ESTIMATE,
79
+ // not a weight fetch (keeping selection cheap). Returns a number or null when unknowable.
80
+ export function paramsEstimate(m) {
81
+ const s = (m.id || m.modelId || "").toLowerCase() + " " + _tags(m).join(" ");
82
+ let mm = s.match(/(\d+(?:\.\d+)?)\s*b(?:\b|illion|-)/); if (mm) return parseFloat(mm[1]) * 1e9;
83
+ mm = s.match(/(\d+(?:\.\d+)?)\s*m(?:\b|illion|-)/); if (mm) return parseFloat(mm[1]) * 1e6;
84
+ if (/\btiny\b/.test(s)) return 60e6;
85
+ if (/\bmini\b|\bsmall\b/.test(s)) return 120e6;
86
+ if (/\bbase\b/.test(s)) return 250e6;
87
+ return null;
88
+ }
89
+ export function maxParamsToNum(cap) {
90
+ const m = String(cap || "").toLowerCase().match(/(\d+(?:\.\d+)?)\s*([bm])/);
91
+ return m ? parseFloat(m[1]) * (m[2] === "b" ? 1e9 : 1e6) : Infinity;
92
+ }
93
+ const openLicense = (m) => _tags(m).some((t) => OPEN_LICENSES.some((l) => t.includes("license:" + l) || t === l));
94
+
95
+ // the cheap selection signal — a PURE, deterministic score over metadata only.
96
+ export function scoreCandidate(m, task) {
97
+ const dl = Math.log10((m.downloads || 0) + 1); // popularity (≈0..7)
98
+ const lk = Math.log10((m.likes || 0) + 1); // endorsement (≈0..4)
99
+ const pipeOk = m.pipeline_tag === task.pipeline ? 1 : 0;
100
+ const run = runnable(m) ? 1 : 0;
101
+ const est = paramsEstimate(m), cap = maxParamsToNum(task.maxParams);
102
+ // within the size cap, smaller is better; over the cap is disqualifying; unknown is neutral-ish.
103
+ const sizeFit = est == null ? 0.3 : est <= cap ? 0.5 + (1 - est / cap) * 0.5 : -2;
104
+ const lic = openLicense(m) ? 0.5 : 0;
105
+ return run * 3 + pipeOk * 2 + dl * 0.6 + lk * 0.3 + sizeFit * 1.5 + lic;
106
+ }
107
+
108
+ // rank fetched candidates for a task — PURE (no network). Returns a sorted, annotated list; ties are
109
+ // broken by id (so the SAME metadata always yields the SAME pick — re-derivable, Law L5).
110
+ export function rankCandidates(models, task) {
111
+ return (models || []).map((m) => ({
112
+ id: m.id || m.modelId, score: +scoreCandidate(m, task).toFixed(4),
113
+ runnable: runnable(m), paramsEstimate: paramsEstimate(m), pipeline: m.pipeline_tag || null,
114
+ downloads: m.downloads || 0, likes: m.likes || 0,
115
+ })).sort((a, b) => (b.score - a.score) || (a.id < b.id ? -1 : a.id > b.id ? 1 : 0));
116
+ }
117
+
118
+ // ── discovery (the one serverless call per task) ────────────────────────────────────────────────────
119
+ // build the Hugging Face Hub query URL for a task (pure — testable without a network).
120
+ export function discoverURL(task, { limit = 20 } = {}) {
121
+ const q = new URLSearchParams({ pipeline_tag: task.pipeline, sort: "downloads", direction: "-1", limit: String(limit) });
122
+ return `${HF_API}?${q.toString()}`;
123
+ }
124
+ // discover(task) → ranked, browser-RUNNABLE candidates. `fetch` is injectable (Node witness / browser).
125
+ export async function discover(task, { fetch = globalThis.fetch, limit = 20 } = {}) {
126
+ const res = await fetch(discoverURL(task, { limit }));
127
+ const models = await res.json();
128
+ return rankCandidates(models, task).filter((c) => c.runnable);
129
+ }
130
+
131
+ // pickSpecialist(taskId) → a PLAN: the top runnable specialist, or an honest fall-back to main when
132
+ // none is browser-runnable. Does NOT download or bind — that is an explicit next step (κ-disk load).
133
+ export async function pickSpecialist(taskId, opts = {}) {
134
+ const task = TASKS.find((t) => t.id === taskId);
135
+ if (!task) throw new Error(`holo-q-mux: unknown task "${taskId}"`);
136
+ // deterministic tasks (e.g. import) have NO model to discover — return an honest plan, never an HF call.
137
+ if (task.deterministic) return { task: taskId, specialist: null, deterministic: true, fallback: null, reason: "deterministic task — a pure encoder is bound, no model is discovered" };
138
+ // pinned core I/O faculties (respond/listen/speak/code) — the OS's OWN precompiled κ .holo, never HF-discovered.
139
+ if (task.pinned) {
140
+ const p = PINNED[task.id];
141
+ return { task: taskId, pinned: true, specialist: p ? { ...p.instant, faculty: p.faculty } : null, upgrade: (p && p.upgrade) || null, fallback: null, reason: "pinned faculty — a precompiled, κ-addressed .holo ships with the OS (content-addressed, L5-verified); not HF-discovered" };
142
+ }
143
+ const ranked = await discover(task, opts);
144
+ if (!ranked.length) return { task: taskId, specialist: null, fallback: "main", reason: "no browser-runnable specialist found — using the main model" };
145
+ return { task: taskId, specialist: ranked[0], alternatives: ranked.slice(1, 4), fallback: null };
146
+ }
147
+
148
+ // autoAssign() → the "magic" entry: a per-task PLAN across the whole helper-task surface, one cheap
149
+ // call each. Pure orchestration over pickSpecialist; the caller loads + binds the ones it wants.
150
+ export async function autoAssign(opts = {}) {
151
+ const out = [];
152
+ for (const t of TASKS) { try { out.push(await pickSpecialist(t.id, opts)); } catch (e) { out.push({ task: t.id, error: String(e && e.message || e) }); } }
153
+ return out;
154
+ }
155
+
156
+ // ── the per-task provider registry — route each helper task to its bound specialist (or main) ────────
157
+ // A provider is the same shape useBrain() takes: { id, generate?|complete?|embed?|classify? }. Loading
158
+ // the κ-disk and constructing the provider is the caller's job; here we only ROUTE.
159
+ const _bound = new Map();
160
+ export function bindSpecialist(taskId, provider) {
161
+ if (!TASKS.find((t) => t.id === taskId)) throw new Error(`holo-q-mux: unknown task "${taskId}"`);
162
+ if (!provider) { _bound.delete(taskId); return { task: taskId, provider: null }; }
163
+ _bound.set(taskId, provider);
164
+ return { task: taskId, provider: provider.id || "specialist" };
165
+ }
166
+ export function routeTask(taskId) { return _bound.get(taskId) || { id: "main", fallback: true }; }
167
+
168
+ // resolveModel(taskId) — THE single front door every consumer reads to learn which LLM runs a faculty
169
+ // RIGHT NOW. One precedence, everywhere (the "one place to select the active model" — ADR-0084):
170
+ // 1. an explicit OVERRIDE — a provider bound via bindSpecialist (the settings picker / admin choice)
171
+ // 2. a PINNED κ .holo — the OS's own precompiled brain for a core I/O faculty (respond/listen/speak/code)
172
+ // 3. the MAIN brain — helper tasks with no bound specialist fall back to the main model (never blocks)
173
+ // Pure + re-derivable: it READS the registry, it does not load. The caller loads the κ / builds the provider.
174
+ export function resolveModel(taskId) {
175
+ const task = TASKS.find((t) => t.id === taskId);
176
+ if (!task) throw new Error(`holo-q-mux: unknown task "${taskId}"`);
177
+ const bound = _bound.get(taskId);
178
+ if (bound) return { task: taskId, source: "override", provider: bound, id: bound.id || "specialist" };
179
+ if (task.pinned && PINNED[taskId]) return { task: taskId, source: "pinned", spec: PINNED[taskId], id: PINNED[taskId].instant.id };
180
+ if (task.deterministic) return { task: taskId, source: "deterministic", id: "encoder" };
181
+ return { task: taskId, source: "main", main: true, id: "main" };
182
+ }
183
+ export function boundSpecialists() { return [..._bound.entries()].map(([task, p]) => ({ task, provider: p.id || "specialist" })); }
184
+ export function unbindAll() { _bound.clear(); }
185
+
186
+ // describeMux() — the seam's honest state: what it routes, how it selects, what is proven vs pending.
187
+ export function describeMux() {
188
+ return {
189
+ tasks: TASKS.map((t) => ({ id: t.id, job: t.job, pipeline: t.pipeline, need: t.need, maxParams: t.maxParams, pinned: !!t.pinned, deterministic: !!t.deterministic })),
190
+ pinned: Object.fromEntries(Object.entries(PINNED).map(([k, v]) => [k, { faculty: v.faculty, instant: v.instant.id, upgrade: v.upgrade ? v.upgrade.id : null, kappa: v.instant.kappa }])),
191
+ discovery: "Hugging Face Hub API (one cheap call per HELPER task, serverless — a browser fetch); core I/O faculties are κ-pinned (precompiled .holo, not discovered)",
192
+ selection: "pure deterministic ranking over metadata; no candidate downloaded to be judged",
193
+ execution: "chosen specialist streams as a content-addressed κ-disk (ADR-0052), bound per-task",
194
+ fallback: "no browser-runnable specialist (or no WebGPU) → the main model; never blocks, never fakes (Law L5)",
195
+ receipt: "decode-agnostic — each task output seals the SAME re-derivable InferenceReceipt, conscience-gated (ADR-0033/0083)",
196
+ bound: boundSpecialists(),
197
+ };
198
+ }
199
+
200
+ export default {
201
+ TASKS, PINNED, BROWSER_LIBS, runnable, paramsEstimate, maxParamsToNum, scoreCandidate, rankCandidates,
202
+ discoverURL, discover, pickSpecialist, autoAssign, bindSpecialist, routeTask, resolveModel, boundSpecialists, unbindAll, describeMux,
203
+ };
_shared/voice/holo-q-faculty-models.mjs ADDED
@@ -0,0 +1,120 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // holo-q-faculty-models.mjs — the ONE bridge from a Q faculty decision to a LOADABLE .holo spec.
2
+ //
3
+ // holo-q-mux.js is the authority on WHICH model runs a faculty (override → pinned κ → main) but it is a
4
+ // pure registry — it carries the κ (identity, Law L1) and the faculty, NOT where the bytes live. This
5
+ // module adds the single hosting map (model id → filename) and turns a mux decision into the {url, release,
6
+ // kappa, upgrade} every loader (holo-brain-engine, holo-moonshine-ear, kokoro) already takes. The κ is read
7
+ // FROM the mux PINNED table, so the two can never drift — change a κ in one place (the mux, sourced from
8
+ // .models/holo-ipfs-pins.json) and every consumer follows. Resolution is pure + re-derivable (no load).
9
+ //
10
+ // Used by: holo-voice-holo-brain.mjs (respond/code chat brain), holo-voice.js (listen/ASR config), and any
11
+ // app that wants "the model the user chose for this faculty". Overrides flow through resolveModel() — so the
12
+ // settings picker (bindSpecialist) controls every faculty from one place.
13
+
14
+ import { resolveModel, PINNED } from "../q/holo-q-mux.js";
15
+
16
+ // where the κ bytes live. The forge dir is the dev/canonical mount; the Release is the prod host (>100MB
17
+ // Pages limit); the κ-route (/.holo/sha256/<κ>, SW heals from IPFS) is the universal fallback the loaders
18
+ // already try. Override the release base via window.HOLO_MODELS_RELEASE_BASE (e.g. a pinned tag).
19
+ const FORGE = "/apps/q/forge/";
20
+ const RELEASE_BASE = (typeof window !== "undefined" && window.HOLO_MODELS_RELEASE_BASE) || "https://github.com/Hologram-Technologies/hologram-apps/releases/download/models-v1/";
21
+ // model id (as named in the mux PINNED table) → its .holo filename. The ONLY hosting fact not in the mux.
22
+ const FILE = {
23
+ "qwen2.5-0.5b": "qwen2.5-0.5b-instruct.holo",
24
+ "qwen2.5-1.5b": "qwen2.5-1.5b-instruct.holo",
25
+ "qwen-coder-3b": "qwen2.5-coder-3b-instruct.holo",
26
+ // think faculty — the 9B reasoner ships as its OWN sharded .holo (not in the q-models pack; no PACK_ID),
27
+ // delivered via its parts manifest + κ-route. specFor builds {url: FORGE/.models/…, release, kappa}.
28
+ "qwen3.5-9b-thinking": "qwen3.5-9b-thinking.holo",
29
+ "moonshine-tiny-int8": "moonshine-tiny-int8.holo",
30
+ "moonshine-tiny-f16": "moonshine-tiny-f16.holo",
31
+ // listen 0.6B upgrade (WebGPU) — the κ-native FastConformer-TDT ear. Encoder + joint are separate .holo;
32
+ // the parakeet ear (holo-parakeet-ear.mjs) takes the encoder as holoUrl and the joint via jointUrl.
33
+ "parakeet-tdt-0.6b-v2": "parakeet-tdt-0.6b-v2-stream.holo",
34
+ "parakeet-tdt-0.6b-v2-joint": "parakeet-tdt-0.6b-v2-joint.holo",
35
+ "kokoro-82m": "kokoro-82m.holo",
36
+ // semantic turn-detector (SmolLM2-135M) — its own loader (createTurnDetectorWeb) but a first-class registry model
37
+ // so it shares the pack delivery; standalone lives in its own dir.
38
+ "turn-detector": "turn-detector/turn-detector.holo",
39
+ };
40
+
41
+ // THE UNIFIED PACK — one κ-addressable .holo holding every faculty model's bodies (deduped, instant-tier-first).
42
+ // ONE delivery, one warm OPFS cache, one address: a pack-aware loader opens it ONCE (holo-model-pack.mjs) and
43
+ // Range-fetches only the model it needs (proven by q-pack-stream-witness: a faculty reads ≈ its own bytes, never
44
+ // the 953MB whole). Standalone .holo stay as the per-model fallback when the pack isn't reachable. PACK_ID maps a
45
+ // mux/FILE model id → its id INSIDE the pack manifest (the encoder/joint are named without the version suffix there).
46
+ const PACK_FILE = "q-models.holo";
47
+ // EVERY Q model lives in the pack (bundle-everything). The pack is one κ-addressable file; because it exceeds GitHub's
48
+ // 2 GiB per-asset cap it's DELIVERED in <2 GiB shards (q-models.holo.partNN, manifest q-models.holo.parts.json) that a
49
+ // spanning reader (holo-pack-shards.mjs) stitches back — one address, sharding invisible above the rangeReader.
50
+ const PACK_ID = {
51
+ "moonshine-tiny-int8": "moonshine-tiny-int8", "moonshine-tiny-f16": "moonshine-tiny-f16", "kokoro-82m": "kokoro-82m",
52
+ "parakeet-tdt-0.6b-v2": "parakeet-encoder", "parakeet-tdt-0.6b-v2-joint": "parakeet-joint",
53
+ "turn-detector": "turn-detector", "qwen2.5-0.5b": "qwen2.5-0.5b", "qwen2.5-1.5b": "qwen2.5-1.5b", "qwen-coder-3b": "qwen-coder-3b",
54
+ };
55
+ // the pack's own coordinates. `url` = monolithic file (dev/FORGE mount, served same-origin when present); `release`
56
+ // = label only. `partsManifest` = the shard manifest, shipped SAME-ORIGIN (tiny → in dist, no CORS); it carries an
57
+ // IPFS gateway + per-shard CIDs so the bytes stream from a CDN-backed CORS+Range gateway (serverless, any-device).
58
+ // GitHub release assets are NOT used for browser delivery (they send no CORS header). Override the gateway via
59
+ // window.HOLO_PACK_GATEWAY; override the whole base via window.HOLO_MODELS_RELEASE_BASE.
60
+ export const packSpec = { file: PACK_FILE, url: FORGE + ".models/" + PACK_FILE, release: RELEASE_BASE + PACK_FILE, partsManifest: FORGE + ".models/" + PACK_FILE + ".parts.json", sharded: true };
61
+
62
+ // THE SEED FIRST-RESPONDER — a tiny (~7MB int8) context-aligned .holo that speaks an instant qwen-aligned opener
63
+ // ("Sure! …") the moment it loads, so a cold user hears audio in <2s while the 485MB brain streams in (speak-while-
64
+ // streaming, holo-voice-seed-handoff.mjs). ONE small same-origin asset (no sharding); release is the prod fallback.
65
+ // κ is the q-seed.holo archive root (file-bundle: seed.onnx int8 + seed.json cfg, L5-verified). Loaded fail-soft:
66
+ // any open/run error → the loop falls back to brain-only, never breaking listen/respond.
67
+ export const seedSpec = { file: "q-seed.holo", url: FORGE + ".models/q-seed.holo", release: RELEASE_BASE + "q-seed.holo", kappa: "did:holo:sha256:32edd21a7f80a0645cf5659be51a4002ef2271aa6637fba08314929f57bae4a0", bytesMB: 7 };
68
+
69
+ // a {id, kappa} from the mux → a loadable spec (url path → release → κ-route; every block L5-verified). When the
70
+ // model also lives in the unified pack, the spec carries {pack:{url,release,model}} so a pack-aware loader prefers
71
+ // the single delivery; loaders that ignore it fall back to the standalone url/release unchanged.
72
+ export function specFor(tier) {
73
+ if (!tier || !tier.id) return null;
74
+ const file = FILE[tier.id];
75
+ if (!file) return { id: tier.id, kappa: tier.kappa || "", url: tier.id, release: "" }; // a direct URL/unknown id — pass through
76
+ const spec = { id: tier.id, kappa: tier.kappa || "", url: FORGE + ".models/" + file, release: RELEASE_BASE + file, bytesMB: tier.bytesMB || 0 };
77
+ if (PACK_ID[tier.id]) spec.pack = { url: packSpec.url, release: packSpec.release, model: PACK_ID[tier.id] };
78
+ return spec;
79
+ }
80
+
81
+ // every pinned TIER the OS ships, indexed by model id (instant + upgrade across all faculties). This is the
82
+ // closed set a user override may name — so a steer ("use the 1.5B") resolves to real, κ-verified bytes, not
83
+ // an arbitrary string. specById(id) → a loadable spec, or null when the id isn't an OS-pinned model.
84
+ const ALL_TIERS = (() => {
85
+ const m = {};
86
+ for (const fac of Object.values(PINNED)) { if (fac.instant) m[fac.instant.id] = fac.instant; if (fac.upgrade) m[fac.upgrade.id] = fac.upgrade; }
87
+ return m;
88
+ })();
89
+ export function specById(id) { return ALL_TIERS[id] ? specFor(ALL_TIERS[id]) : null; }
90
+ // the tiers a given faculty is ALLOWED to use (instant + its own upgrade) — the closed choice set a picker
91
+ // or a steer offers for that faculty. Returns [{id,kappa,bytesMB,tier:"instant"|"upgrade"}], or [] for helpers.
92
+ export function tiersFor(faculty) {
93
+ const p = PINNED[faculty]; if (!p) return [];
94
+ const out = [{ ...p.instant, tier: "instant" }];
95
+ if (p.upgrade) out.push({ ...p.upgrade, tier: "upgrade" });
96
+ return out;
97
+ }
98
+
99
+ // resolveFacultyModel(faculty) — THE call a consumer makes. Returns the loadable spec for the active model
100
+ // of a faculty, honoring the user/admin override, then the OS-pinned κ. Shape:
101
+ // { faculty, source:"override"|"pinned"|"main", instant:{url,release,kappa,...}|null, upgrade:{...}|null, provider?, main? }
102
+ // - source "override": the settings picker bound a specific provider — returned verbatim (the caller uses it).
103
+ // - source "pinned": the OS's own precompiled κ .holo — instant tier (+ optional silent upgrade tier).
104
+ // - source "main": a helper faculty with no binding — defer to the main brain (the caller's main path).
105
+ export function resolveFacultyModel(faculty) {
106
+ const r = resolveModel(faculty);
107
+ if (r.source === "override") return { faculty, source: "override", provider: r.provider, id: r.id, instant: specById(r.id), upgrade: null };
108
+ if (r.source === "pinned") {
109
+ const p = r.spec; // { faculty, instant:{id,kappa,bytesMB}, upgrade?:{...} }
110
+ return { faculty, source: "pinned", instant: specFor(p.instant), upgrade: p.upgrade ? specFor(p.upgrade) : null };
111
+ }
112
+ return { faculty, source: r.source, main: true, id: r.id }; // "main" | "deterministic"
113
+ }
114
+
115
+ // convenience: the bare {url,release,kappa} for a pinned faculty's instant tier (the common case a loader wants).
116
+ export function instantSpec(faculty) { const r = resolveFacultyModel(faculty); return r.source === "pinned" ? r.instant : null; }
117
+ export function upgradeSpec(faculty) { const r = resolveFacultyModel(faculty); return r.source === "pinned" ? r.upgrade : null; }
118
+
119
+ export { PINNED, resolveModel };
120
+ export default { resolveFacultyModel, instantSpec, upgradeSpec, specFor, specById, tiersFor, packSpec, seedSpec };
_shared/voice/holo-voice-asr.mjs ADDED
@@ -0,0 +1,154 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // holo-voice-asr.mjs — the on-device speech-recognition engine for Holo Voice.
2
+ //
3
+ // It binds into the QVAC transcription seam (HoloQVAC.useHoloVoice). The recognizer runs ENTIRELY in
4
+ // the browser — no inference server, no audio leaves the device. Tiered, mirroring QVAC's own
5
+ // "WebGPU, deterministic fallback" pattern (holo-qvac.js):
6
+ //
7
+ // • WebGPU present → Whisper-base (transformers.js, ONNX/WebGPU) — high accuracy
8
+ // • WASM only → Moonshine-tiny (transformers.js, ONNX/WASM) — streaming, any browser
9
+ //
10
+ // Weights resolve by content address through the OS service worker (Law L5) and live offline in
11
+ // CacheStorage after first load — that is what makes recognition serverless. `localPath` points at the
12
+ // vendored κ-disk; set `remote:true` (dev only) to bootstrap from a module CDN before weights are
13
+ // vendored. The library is imported lazily, so loading this module never blocks and never throws on a
14
+ // device that will only use the bring-up fallback.
15
+
16
+ const DEFAULTS = {
17
+ // All vendor paths are resolved RELATIVE TO THIS MODULE (vendor/ is a sibling dir created by
18
+ // tools/vendor-voice-model.mjs), so they work under any mount (_shared, content-addressed, …).
19
+ lib: "vendor/transformers/transformers.js", // transformers.js ESM entry
20
+ libRemote: "https://cdn.jsdelivr.net/npm/@huggingface/transformers@3.0.2",
21
+ ortPath: "vendor/transformers/", // onnxruntime-web wasm lives beside it
22
+ // Tiered for LATENCY: the WASM listen path defaults to Whisper-TINY (~3-5x faster than base — it's the
23
+ // ASR wall-time that dominates response onset), falling back to base if tiny isn't vendored. WebGPU
24
+ // (when it works) keeps base for accuracy. One vendored model per id under localPath.
25
+ modelWebGPU: "onnx-community/whisper-base", // quality tier (WebGPU)
26
+ modelWASM: "onnx-community/whisper-tiny", // fast listen tier (WASM)
27
+ modelWASMFallback: "onnx-community/whisper-base", // used if whisper-tiny isn't vendored
28
+ localPath: "vendor/models/", // model id resolves under here
29
+ remote: false, // dev escape hatch: load lib + weights from the CDN above
30
+ quantized: true,
31
+ // WASM is the default: it's the any-browser floor (Firefox/Safari have no stable WebGPU) AND the
32
+ // quantized Whisper decoder currently hits an ORT WebGPU kernel bug. Opt into WebGPU explicitly.
33
+ preferWebGPU: false,
34
+ // κ-native Holo GGUF ear (opt-in): when WebGPU is present, run Whisper 100% on the κ-substrate —
35
+ // weights streamed by κ from the .holo (HTTP-Range + per-block L5 + OPFS), GPU encoder-decoder
36
+ // forward, no transformers.js/ONNX. Set { module, holoUrl } (resolved relative to this module) to
37
+ // enable; ANY failure transparently falls back to the transformers path below. null = off.
38
+ knativeEar: null, // e.g. { module: "../../q/forge/gpu/holo-whisper-ear.mjs", holoUrl: "…/whisper-base.holo" }
39
+ // κ-served WASM fallback (opt-in): when the κ-native ear is off (no WebGPU) and the transformers/ONNX path
40
+ // runs, serve Whisper's ONNX files from its .holo (HTTP-Range + per-block L5 + OPFS + serverless) into the
41
+ // SAME engine — so the any-browser floor is ALSO content-addressed/warm/serverless, not a flat download.
42
+ // ANY failure restores fetch + falls back to the vendored ONNX files. null = off. Same shim every faculty uses.
43
+ knativeServe: { // κ-served whisper-tiny — its ONNX files stream from the .holo (per-block L5 + OPFS warm) into the SAME transformers engine. ANY failure restores fetch → vendored ONNX. matches modelWASM.
44
+ module: "/apps/q/forge/gpu/holo-onnx-kserve.mjs",
45
+ holoUrl: "/.holo/sha256/361209ec2ff387beb9e763017cd50d18f9cc8b5276346d62420922ca9a5d9185", // κ-pure source; the SW serves this directly once the κ-route heal-fallback lands (then `release` below can go)
46
+ modelId: "onnx-community/whisper-tiny",
47
+ // delivery TODAY: openHoloFiles (holo-files.mjs:18-21) range-fetches holoUrl; on miss it falls back to
48
+ // `release` as a DIRECT URL — CORS + Range from the GitHub Release CDN, per-block re-derived (L5).
49
+ release: "https://github.com/Hologram-Technologies/hologram-apps/releases/download/weights-v1/361209ec2ff387beb9e763017cd50d18f9cc8b5276346d62420922ca9a5d9185",
50
+ },
51
+ lang: "en",
52
+ };
53
+
54
+ function moduleBase() {
55
+ try { return new URL("./", import.meta.url).href; } // …/_shared/voice/
56
+ catch (e) { return new URL("./", location.href).href; }
57
+ }
58
+
59
+ async function hasWebGPU() {
60
+ try { return !!(navigator.gpu && (await navigator.gpu.requestAdapter())); } catch (e) { return false; }
61
+ }
62
+
63
+ // ── the engine ──────────────────────────────────────────────────────────────────────────────────
64
+ export function createASR(opts = {}) {
65
+ const cfg = Object.assign({}, DEFAULTS, opts);
66
+ let pipe = null, knative = null, info = { ready: false, engine: null, model: null, device: null };
67
+ let loading = null;
68
+
69
+ async function load(onProgress) {
70
+ if (pipe || knative) return info;
71
+ if (loading) return loading;
72
+ loading = (async () => {
73
+ const base = moduleBase();
74
+ // κ-native Holo GGUF ear (opt-in, WebGPU only). Transparently falls back on any failure.
75
+ if (cfg.knativeEar && cfg.knativeEar.module && (await hasWebGPU())) {
76
+ try {
77
+ const mod = await import(/* @vite-ignore */ new URL(cfg.knativeEar.module, base).href);
78
+ // UNIFIED PACK (opt-in via cfg.knativeEar.pack): stream the encoder/joint/loose-files from the ONE q-models
79
+ // pack instead of per-model .holo. makePackEarDeps maps the ear's URLs → pack views and is FAIL-SOFT (pack
80
+ // unreachable → the ear's own standalone url/release), and this whole block already falls back to
81
+ // transformers on any error — so enabling the pack can never strand listening.
82
+ let earDeps;
83
+ if (cfg.knativeEar.pack) { try {
84
+ const pp = await import(/* @vite-ignore */ new URL("../../q/forge/gpu/holo-q-pack-provider.mjs", base).href);
85
+ const fm = await import(/* @vite-ignore */ new URL("./holo-q-faculty-models.mjs", base).href);
86
+ // parakeet ear wants the raw openHoloStream views (+ loose files); the moonshine ear wants the whisper-shaped
87
+ // view (getF32/getQuant). Pick by module — both fail-soft to standalone inside the loaders.
88
+ earDeps = /parakeet/.test(cfg.knativeEar.module) ? pp.makePackEarDeps({ packSpec: fm.packSpec }) : { openStream: pp.makePackOpenStream({ packSpec: fm.packSpec }) };
89
+ } catch (_) { earDeps = undefined; } }
90
+ const ear = (mod.createWhisperEar || mod.default)({ holoUrl: new URL(cfg.knativeEar.holoUrl, base).href, upgradeUrl: cfg.knativeEar.upgradeUrl ? new URL(cfg.knativeEar.upgradeUrl, base).href : null, kappa: cfg.knativeEar.kappa, release: cfg.knativeEar.release || "", upgradeKappa: cfg.knativeEar.upgradeKappa || "", upgradeRelease: cfg.knativeEar.upgradeRelease || "", language: cfg.lang }, earDeps);
91
+ await ear.load(onProgress);
92
+ knative = ear; info = Object.assign({ ready: true, engine: "holo-gguf-κnative" }, ear.info());
93
+ return info;
94
+ } catch (e) { try { console.warn("[HoloVoice ASR] κ-native ear unavailable, using transformers:", e && e.message || e); } catch (_) {} }
95
+ }
96
+ const libUrl = cfg.remote ? cfg.libRemote : new URL(cfg.lib, base).href;
97
+ const tf = await import(/* @vite-ignore */ libUrl); // throws here if not vendored → caller falls back
98
+ const { pipeline, env } = tf;
99
+ const webgpu = cfg.preferWebGPU && (await hasWebGPU());
100
+ const device = webgpu ? "webgpu" : "wasm";
101
+ const model = webgpu ? cfg.modelWebGPU : cfg.modelWASM;
102
+ if (env) {
103
+ env.allowRemoteModels = !!cfg.remote; // serverless: weights come from the κ-disk only
104
+ env.allowLocalModels = !cfg.remote;
105
+ if (!cfg.remote) {
106
+ env.localModelPath = new URL(cfg.localPath, base).href;
107
+ // point onnxruntime-web at the vendored wasm so NO binary is fetched from a CDN.
108
+ const wasmPaths = new URL(cfg.ortPath, base).href;
109
+ if (env.backends && env.backends.onnx && env.backends.onnx.wasm) env.backends.onnx.wasm.wasmPaths = wasmPaths;
110
+ }
111
+ // run ORT in a Web Worker (WASM only) so streaming partial transcriptions don't block the main
112
+ // thread / the VAD loop — the UI stays responsive while recognition runs as you speak.
113
+ try { if (!webgpu && cfg.proxy !== false && env.backends && env.backends.onnx && env.backends.onnx.wasm) env.backends.onnx.wasm.proxy = true; } catch (e) {}
114
+ }
115
+ const prog = (p) => { try { onProgress && onProgress({ phase: p.status || "load", file: p.file, loaded: p.loaded, total: p.total, device, model }); } catch (e) {} };
116
+ // κ-served WASM fallback: install the .holo fetch shim BEFORE the pipeline loads, so Whisper's ONNX files
117
+ // are served by content address. Transparently falls back to vendored ONNX on any failure.
118
+ let kserve = null;
119
+ if (cfg.knativeServe && cfg.knativeServe.module && cfg.knativeServe.holoUrl) {
120
+ try {
121
+ const km = await import(/* @vite-ignore */ new URL(cfg.knativeServe.module, base).href);
122
+ kserve = await (km.serveModelFromHolo || km.default)({ holoUrl: new URL(cfg.knativeServe.holoUrl, base).href, modelId: cfg.knativeServe.modelId || model, release: cfg.knativeServe.release || "" });
123
+ } catch (e) { try { console.warn("[HoloVoice ASR] κ-served fallback unavailable, using vendored ONNX:", e && e.message || e); } catch (_) {} kserve = null; }
124
+ }
125
+ const dtype = cfg.quantized ? "q8" : "fp32";
126
+ const build = (m) => pipeline("automatic-speech-recognition", m, { device, dtype, progress_callback: prog });
127
+ let used = model;
128
+ try { pipe = await build(model); }
129
+ catch (e) { // tiny not vendored (or load failed) → fall back to base
130
+ if (kserve) { try { kserve.restore(); } catch (_) {} kserve = null; } // the κ-served tiny failed → un-shim so base loads vendored
131
+ if (!webgpu && cfg.modelWASMFallback && cfg.modelWASMFallback !== model) { used = cfg.modelWASMFallback; pipe = await build(used); }
132
+ else throw e;
133
+ }
134
+ info = { ready: true, engine: kserve ? "transformers-κserved" : "transformers", model: used, device, servedFromHolo: kserve ? kserve.served.length : 0 };
135
+ return info;
136
+ })().catch((e) => { loading = null; throw e; });
137
+ return loading;
138
+ }
139
+
140
+ // transcribe(audio, opts) — audio is a Float32Array of mono PCM at 16 kHz (Holo Voice resamples).
141
+ async function transcribe(audio, o = {}) {
142
+ if (!pipe && !knative) await load(o.onProgress);
143
+ if (knative) return knative.transcribe(audio, o); // κ-native ear (same {text,…} shape)
144
+ const args = { language: o.language || null, task: "transcribe", chunk_length_s: 30, stride_length_s: 5 };
145
+ if (o.prompt) args.prompt = o.prompt; // best-effort decoding bias (ignored where unsupported)
146
+ const r = await pipe(audio, args);
147
+ const text = (r && (Array.isArray(r) ? r.map((x) => x.text).join(" ") : r.text) || "").trim();
148
+ return { text, language: o.language || null, runtime: info.device === "webgpu" ? "browser-webgpu" : "browser-wasm" };
149
+ }
150
+
151
+ return { id: "holo-voice-asr", load, transcribe, info: () => info, sampleRate: 16000 };
152
+ }
153
+
154
+ export default createASR;
_shared/voice/holo-voice-tts.mjs ADDED
@@ -0,0 +1,115 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // holo-voice-tts.mjs — Q's natural voice: Kokoro-82M text-to-speech, on-device and serverless.
2
+ //
3
+ // Kokoro is the best small open TTS; kokoro-js drives it. It imports "@huggingface/transformers" and
4
+ // "phonemizer" as bare specifiers — the frames map those (import map) to the vendored copies under
5
+ // vendor/kokoro/, so this runs entirely in the browser with no CDN and no server. We import the SAME
6
+ // transformers module first and point its ONNX env at the vendored wasm + model, so kokoro inherits a
7
+ // fully local, serverless config. WASM by default (any browser); WebGPU opt-in. If anything here fails,
8
+ // holo-voice.js falls back to the browser's built-in speechSynthesis — so Q always talks.
9
+
10
+ const DEFAULTS = {
11
+ tfLib: "vendor/kokoro/transformers/transformers.js", // kokoro's transformers (3.5.1), import-mapped
12
+ ortPath: "vendor/kokoro/transformers/", // its bundled onnxruntime-web wasm
13
+ kokoroLib: "vendor/kokoro/kokoro.js",
14
+ localPath: "vendor/models/",
15
+ model: "onnx-community/Kokoro-82M-v1.0-ONNX",
16
+ dtype: "q8", // → onnx/model_quantized.onnx
17
+ voice: "af_heart", // warm, natural default
18
+ preferWebGPU: false,
19
+ // κ-served voice (opt-in): serve Kokoro's ONNX files from its .holo (HTTP-Range + per-block L5 + OPFS warm
20
+ // cache + serverless multi-source) into the SAME kokoro-js/onnxruntime engine — content-addressed weight
21
+ // delivery, no engine change. Set { module, holoUrl, modelId?, kappa, release } to enable; ANY failure
22
+ // transparently restores fetch and falls back to the vendored ONNX files below. null = off (vendored path).
23
+ knativeVoice: null, // e.g. { module: "../../q/forge/gpu/holo-onnx-kserve.mjs", holoUrl: "…/kokoro-82m.holo" }
24
+ };
25
+
26
+ function moduleBase() { try { return new URL("./", import.meta.url).href; } catch (e) { return new URL("./", location.href).href; } }
27
+
28
+ export function createTTS(opts = {}) {
29
+ const cfg = Object.assign({}, DEFAULTS, opts);
30
+ let tts = null, loading = null, info = { ready: false, device: null };
31
+
32
+ async function load(onProgress) {
33
+ if (tts) return info;
34
+ if (loading) return loading;
35
+ loading = (async () => {
36
+ const base = moduleBase();
37
+ // configure the shared transformers env BEFORE kokoro imports it (same module URL = same instance).
38
+ const TF = await import(/* @vite-ignore */ new URL(cfg.tfLib, base).href);
39
+ if (TF.env) {
40
+ TF.env.allowRemoteModels = false; TF.env.allowLocalModels = true;
41
+ TF.env.localModelPath = new URL(cfg.localPath, base).href;
42
+ if (TF.env.backends && TF.env.backends.onnx && TF.env.backends.onnx.wasm) {
43
+ TF.env.backends.onnx.wasm.wasmPaths = new URL(cfg.ortPath, base).href;
44
+ TF.env.backends.onnx.wasm.proxy = true; // worker → no UI freeze while synthesizing
45
+ }
46
+ }
47
+ // κ-served voice (opt-in): install the .holo fetch shim BEFORE kokoro loads, so its model files are
48
+ // served by content address from the .holo. Transparently falls back to the vendored ONNX on any failure.
49
+ let kserve = null;
50
+ if (cfg.knativeVoice && cfg.knativeVoice.module && cfg.knativeVoice.holoUrl) {
51
+ try {
52
+ const km = await import(/* @vite-ignore */ new URL(cfg.knativeVoice.module, base).href);
53
+ // serve Kokoro's files from the ONE q-models pack when opted in (fail-soft → holoUrl/release standalone)
54
+ let openFiles = null;
55
+ if (cfg.knativeVoice.pack) { try { const pp = await import(/* @vite-ignore */ new URL("/apps/q/forge/gpu/holo-q-pack-provider.mjs", base).href); const fm = await import(/* @vite-ignore */ new URL("./holo-q-faculty-models.mjs", import.meta.url).href); openFiles = pp.makePackOpenFiles("kokoro-82m", { packSpec: fm.packSpec }); } catch (_) {} }
56
+ kserve = await (km.serveModelFromHolo || km.default)({
57
+ holoUrl: new URL(cfg.knativeVoice.holoUrl, base).href,
58
+ modelId: cfg.knativeVoice.modelId || cfg.model,
59
+ release: cfg.knativeVoice.release || "",
60
+ openFiles,
61
+ });
62
+ } catch (e) { try { console.warn("[HoloVoice TTS] κ-served voice unavailable, using vendored ONNX:", e && e.message || e); } catch (_) {} kserve = null; }
63
+ }
64
+ const mod = await import(/* @vite-ignore */ new URL(cfg.kokoroLib, base).href);
65
+ const KokoroTTS = mod.KokoroTTS || (mod.default && mod.default.KokoroTTS);
66
+ // device: explicit cfg.device wins (the bake-off harness sets it); else preferWebGPU→webgpu when available, else wasm.
67
+ const device = cfg.device || ((cfg.preferWebGPU && navigator.gpu) ? "webgpu" : "wasm");
68
+ try {
69
+ tts = await KokoroTTS.from_pretrained(cfg.model, { dtype: cfg.dtype, device, progress_callback: onProgress });
70
+ } catch (e) { if (kserve) { try { kserve.restore(); } catch (_) {} } throw e; } // κ-served load failed → un-shim so the caller's fallback fetches the vendored files
71
+ info = { ready: true, device, model: cfg.model, dtype: cfg.dtype, engine: kserve ? "kokoro-κserved" : "kokoro-onnx", servedFromHolo: kserve ? kserve.served.length : 0 };
72
+ return info;
73
+ })().catch((e) => { loading = null; throw e; });
74
+ return loading;
75
+ }
76
+
77
+ // synth(text, {voice}) → { audio: Float32Array, sampling_rate } (a kokoro-js RawAudio).
78
+ async function synth(text, o = {}) {
79
+ if (!tts) await load(o.onProgress);
80
+ return tts.generate(String(text || "").trim(), { voice: o.voice || cfg.voice });
81
+ }
82
+ function listVoices() { try { return tts && tts.voices ? Object.keys(tts.voices) : []; } catch (e) { return []; } }
83
+
84
+ return { id: "holo-voice-tts", load, synth, voices: listVoices, info: () => info };
85
+ }
86
+
87
+ // createTieredTTS — the "instant + HD" voice composition, behind the SAME seam ({load, synth, voices, info}).
88
+ // Q speaks immediately on the `primary` engine (e.g. Kokoro); a heavier, more natural `hd` engine loads in
89
+ // the BACKGROUND and, once ready, transparently takes over future utterances — never blocking the first
90
+ // word, never a gap. If HD fails to load (or errors mid-use), it silently stays on / falls back to primary,
91
+ // so the voice is always available. This is the production scaffolding any HD model (Parler · StyleTTS2 ·
92
+ // a κ-sealed clone) plugs into — pass it as `hd` and nothing else changes. `hd` omitted ⇒ pure primary.
93
+ export function createTieredTTS(opts = {}) {
94
+ const primary = opts.primary, hd = opts.hd || null;
95
+ if (!primary) throw new Error("createTieredTTS: a primary engine is required");
96
+ let tier = "primary", hdReady = false, hdFailed = false;
97
+ async function load(onProgress) {
98
+ const pinfo = await primary.load(onProgress); // the instant tier is ready first — first word never waits
99
+ if (hd) {
100
+ Promise.resolve().then(() => hd.load()) // promote in the background; never blocks playback
101
+ .then(() => { hdReady = true; tier = "hd"; try { opts.onUpgrade && opts.onUpgrade(hd.info ? hd.info() : null); } catch (e) {} })
102
+ .catch(() => { hdFailed = true; });
103
+ }
104
+ return info();
105
+ }
106
+ async function synth(text, o = {}) {
107
+ if (hdReady && hd) { try { return await hd.synth(text, o); } catch (e) { hdReady = false; tier = "primary"; } } // HD error → fall back, keep talking
108
+ return primary.synth(text, o);
109
+ }
110
+ function voices() { try { const s = new Set([].concat(primary.voices ? primary.voices() : [], hd && hd.voices ? hd.voices() : [])); return Array.from(s); } catch (e) { return []; } }
111
+ function info() { return { ready: !!(primary.info && primary.info().ready), tier, hdReady, hdFailed, primary: primary.info && primary.info(), hd: hd && hd.info ? hd.info() : null }; }
112
+ return { id: "holo-voice-tier", load, synth, voices, info, get tier() { return tier; } };
113
+ }
114
+
115
+ export default createTTS;
_shared/voice/holo-voice-turn.mjs ADDED
@@ -0,0 +1,101 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // holo-voice-turn.mjs — on-device SEMANTIC TURN-DETECTION for Holo Voice (deep-research RANK 1).
2
+ //
3
+ // Reads the (partial) transcript and predicts whether the USER IS DONE — so the live loop can end the
4
+ // turn the instant an utterance is semantically complete (firing before trailing silence) and, just as
5
+ // importantly, can VETO a premature endpoint when the user only paused mid-thought. This is the single
6
+ // biggest lever toward a human-call response onset (<300ms median): the 550ms fixed silence is the
7
+ // largest fixed cost in a turn, and a turn-end model removes it.
8
+ //
9
+ // Model: LiveKit's open-weights turn-detector (a small fine-tuned LLM; ONNX builds at
10
+ // onnx-community/turn-detector-ONNX · livekit/turn-detector). CPU-only via ONNX Runtime Web, ~25ms,
11
+ // q4f16 ≈118MB (verified specs; the "~50ms" figure was refuted — it's ~25ms). It outputs the
12
+ // probability that the turn is COMPLETE given the conversation so far.
13
+ //
14
+ // SERVERLESS like the other engines: weights load same-origin from the vendored κ-disk (vendor it with
15
+ // `node tools/vendor-voice-model.mjs --turn`), nothing leaves the device. Imported lazily and GATED by
16
+ // HOLO_VOICE_CONFIG.turnModel — until it's both vendored AND enabled, holo-voice.js uses its heuristic
17
+ // turn-completion scorer, so this module never blocks or breaks the working path.
18
+ //
19
+ // ⚠ EXPERIMENTAL / UNVERIFIED-ON-REAL-HW: the exact end-of-utterance read below (chat-format → forward →
20
+ // P(EOU token) at the last position) follows LiveKit's documented recipe, but the deep-research pass
21
+ // verified the model's existence/specs, NOT this transformers.js invocation. predict() returns null on
22
+ // ANY mismatch so the caller falls back to the heuristic. Verify on real hardware before trusting it,
23
+ // and re-pin the q4f16 inference once confirmed.
24
+
25
+ const DEFAULTS = {
26
+ lib: "vendor/transformers/transformers.js",
27
+ libRemote: "https://cdn.jsdelivr.net/npm/@huggingface/transformers@3.0.2",
28
+ ortPath: "vendor/transformers/",
29
+ model: "onnx-community/turn-detector-ONNX",
30
+ localPath: "vendor/models/",
31
+ remote: false,
32
+ dtype: "q4f16", // ~118MB; falls back to q8 if the model lacks a q4f16 file
33
+ // candidate end-of-turn marker tokens (Qwen-style chat end). The first that resolves to an id is used.
34
+ eouTokens: ["<|im_end|>", "<|endoftext|>"],
35
+ };
36
+
37
+ function moduleBase() {
38
+ try { return new URL("./", import.meta.url).href; }
39
+ catch (e) { return new URL("./", location.href).href; }
40
+ }
41
+
42
+ export function createTurnDetector(opts = {}) {
43
+ const cfg = Object.assign({}, DEFAULTS, opts);
44
+ let model = null, tok = null, Tensor = null, eouId = null, info = { ready: false, model: cfg.model, device: null };
45
+ let loading = null;
46
+
47
+ async function load(onProgress) {
48
+ if (model) return info;
49
+ if (loading) return loading;
50
+ loading = (async () => {
51
+ const base = moduleBase();
52
+ const libUrl = cfg.remote ? cfg.libRemote : new URL(cfg.lib, base).href;
53
+ const tf = await import(/* @vite-ignore */ libUrl); // throws if not vendored → caller falls back
54
+ const { AutoTokenizer, AutoModelForCausalLM, env } = tf; Tensor = tf.Tensor;
55
+ if (env) {
56
+ env.allowRemoteModels = !!cfg.remote;
57
+ env.allowLocalModels = !cfg.remote;
58
+ if (!cfg.remote) {
59
+ env.localModelPath = new URL(cfg.localPath, base).href;
60
+ const wasmPaths = new URL(cfg.ortPath, base).href;
61
+ if (env.backends && env.backends.onnx && env.backends.onnx.wasm) env.backends.onnx.wasm.wasmPaths = wasmPaths;
62
+ }
63
+ }
64
+ const prog = (p) => { try { onProgress && onProgress({ phase: p.status || "load", file: p.file, loaded: p.loaded, total: p.total, model: cfg.model }); } catch (e) {} };
65
+ tok = await AutoTokenizer.from_pretrained(cfg.model, { progress_callback: prog });
66
+ let dtype = cfg.dtype;
67
+ try { model = await AutoModelForCausalLM.from_pretrained(cfg.model, { device: "wasm", dtype, progress_callback: prog }); }
68
+ catch (e) { dtype = "q8"; model = await AutoModelForCausalLM.from_pretrained(cfg.model, { device: "wasm", dtype, progress_callback: prog }); }
69
+ // resolve the end-of-turn token id once (the marker whose probability == "the turn is complete").
70
+ for (const t of cfg.eouTokens) { try { const ids = tok.encode(t, { add_special_tokens: false }); if (ids && ids.length === 1) { eouId = ids[0]; break; } } catch (e) {} }
71
+ info = { ready: true, model: cfg.model, device: "wasm", dtype, eouId };
72
+ return info;
73
+ })().catch((e) => { loading = null; throw e; });
74
+ return loading;
75
+ }
76
+
77
+ // predict(text) → probability in [0,1] that the user's turn is COMPLETE. null on any failure.
78
+ async function predict(text) {
79
+ try {
80
+ if (!model || eouId == null || !Tensor) return null;
81
+ const enc = tok.apply_chat_template([{ role: "user", content: String(text || "") }], { add_generation_prompt: false, tokenize: true });
82
+ const ids = Array.isArray(enc) ? enc : (enc && enc.input_ids) || null;
83
+ if (!ids || !ids.length) return null;
84
+ const input_ids = new Tensor("int64", BigInt64Array.from(ids.map((x) => BigInt(x))), [1, ids.length]);
85
+ const attention_mask = new Tensor("int64", BigInt64Array.from(ids.map(() => 1n)), [1, ids.length]);
86
+ const out = await model({ input_ids, attention_mask });
87
+ const logits = out && (out.logits || out.last_hidden_state);
88
+ if (!logits || !logits.dims) return null;
89
+ const [, seq, vocab] = logits.dims; // [1, seq, vocab]
90
+ const off = (seq - 1) * vocab; // logits at the final position
91
+ const data = logits.data;
92
+ let max = -Infinity; for (let i = 0; i < vocab; i++) { const v = data[off + i]; if (v > max) max = v; }
93
+ let sum = 0; for (let i = 0; i < vocab; i++) sum += Math.exp(data[off + i] - max);
94
+ return Math.exp(data[off + eouId] - max) / sum; // softmax prob of the EOU token
95
+ } catch (e) { return null; }
96
+ }
97
+
98
+ return { id: "holo-voice-turn", load, predict, info: () => info };
99
+ }
100
+
101
+ export default createTurnDetector;
_shared/voice/holo-voice-vad.mjs ADDED
@@ -0,0 +1,90 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // holo-voice-vad.mjs — the SOVEREIGN, pure-ONNX stage-1 wake gate: Silero VAD (MIT) running on the
2
+ // onnxruntime-web that transformers.js ALREADY bundles. No emscripten build, no account key, no new
3
+ // runtime — just a 2 MB ONNX model loaded through the SAME vendored transformers instance as the ASR, so
4
+ // it inherits the serverless config (local weights, vendored wasm, no CDN) and shares the loaded ORT.
5
+ //
6
+ // WHY (first principles): the always-on wake loop should spend Whisper ONLY on real speech. Energy-RMS
7
+ // can't tell speech from a slammed door, music, or a TV; Silero VAD can. So it's the cheap stage-1 gate —
8
+ // it proposes ("this segment is speech"), Whisper-tiny disposes (confirms "Q" + the carrier). This is the
9
+ // pure-ONNX replacement for the sherpa-onnx KWS path (which needed an emscripten wasm runtime we can't
10
+ // vendor in-browser). Sovereign AND web-native: it runs on the runtime we already ship.
11
+ //
12
+ // const vad = await createVAD({ base, threshold }); // loads onnx-community/silero-vad via AutoModel
13
+ // const p = await vad.speechProb(frame512_16k); // streaming: one 512-sample frame → P(speech)
14
+ // const has = await vad.segmentHasSpeech(float32_16k); // one-shot: scan a whole segment → bool
15
+ // vad.reset();
16
+ //
17
+ // HONESTY: Silero VAD-on-transformers.js is the documented pattern (the transformers.js realtime-whisper
18
+ // demo loads onnx-community/silero-vad with `config:{model_type:'custom'}` — there's no config.json in the
19
+ // repo). The model is v5 (I/O: input·sr·state → output·stateN; state [2,1,128]). The exact call is verified
20
+ // to LOAD + RUN in-browser here; gating accuracy/threshold needs real-mic tuning. Fails closed: any error
21
+ // → the caller keeps its energy-VAD path (no regression).
22
+
23
+ const SAMPLE_RATE = 16000;
24
+ const FRAME = 512; // Silero v5 expects 512 samples per step at 16 kHz
25
+ const STATE_DIMS = [2, 1, 128]; // v5 unified LSTM state
26
+ const STATE_LEN = 2 * 1 * 128;
27
+
28
+ // Resolve relative to THIS module's URL — same discipline as holo-voice-asr.mjs (vendor/ is a sibling).
29
+ function moduleBase() {
30
+ try { return new URL("./", import.meta.url).href; }
31
+ catch (e) { return new URL("./", (typeof location !== "undefined" ? location.href : "")).href; }
32
+ }
33
+
34
+ export async function createVAD(opts) {
35
+ opts = opts || {};
36
+ const base = opts.base || moduleBase();
37
+ const lib = opts.lib || "vendor/transformers/transformers.js";
38
+ const localPath = opts.localPath || "vendor/models/";
39
+ const ortPath = opts.ortPath || "vendor/transformers/";
40
+ const model = opts.model || "onnx-community/silero-vad";
41
+ const dtype = opts.dtype || "fp32"; // model.onnx (2 MB). 'q8' → model_quantized.onnx (639 KB) if vendored.
42
+ const threshold = opts.threshold != null ? opts.threshold : 0.5;
43
+
44
+ // Import the SAME vendored transformers module instance the ASR uses (ES-module cache → shared env + ORT).
45
+ const tf = await import(/* @vite-ignore */ new URL(lib, base).href);
46
+ const { AutoModel, Tensor, env } = tf;
47
+ if (!AutoModel || !Tensor) throw new Error("transformers.js missing AutoModel/Tensor");
48
+ if (env) { // idempotent: serverless, weights + wasm are vendored
49
+ env.allowRemoteModels = false; env.allowLocalModels = true;
50
+ env.localModelPath = new URL(localPath, base).href;
51
+ try { const wp = new URL(ortPath, base).href; if (env.backends && env.backends.onnx && env.backends.onnx.wasm) env.backends.onnx.wasm.wasmPaths = wp; } catch (e) {}
52
+ }
53
+
54
+ // No config.json in the repo → pass a custom config inline (the documented Silero-on-transformers.js trick).
55
+ const net = await AutoModel.from_pretrained(model, { config: { model_type: "custom" }, dtype: dtype });
56
+
57
+ const sr = new Tensor("int64", [BigInt(SAMPLE_RATE)], []);
58
+ let state = new Tensor("float32", new Float32Array(STATE_LEN), STATE_DIMS);
59
+ function reset() { state = new Tensor("float32", new Float32Array(STATE_LEN), STATE_DIMS); }
60
+
61
+ // run ONE 512-sample frame → P(speech). Carries the recurrent state forward.
62
+ async function speechProb(frame) {
63
+ let x = frame;
64
+ if (x.length !== FRAME) { const f = new Float32Array(FRAME); f.set(x.subarray ? x.subarray(0, FRAME) : x.slice(0, FRAME)); x = f; } // pad/trim to 512
65
+ const input = new Tensor("float32", x, [1, FRAME]);
66
+ const out = await net({ input: input, sr: sr, state: state });
67
+ if (out.stateN) state = out.stateN;
68
+ const o = out.output && out.output.data;
69
+ return o && o.length ? o[0] : 0;
70
+ }
71
+
72
+ // one-shot: scan a whole 16 kHz segment in 512-sample frames → did ANY frame exceed the speech threshold?
73
+ // Returns { speech, maxProb }. Resets state first so each segment is judged independently.
74
+ async function segmentHasSpeech(audio, thr) {
75
+ reset();
76
+ const t = thr != null ? thr : threshold;
77
+ let max = 0;
78
+ for (let i = 0; i + 1 <= audio.length; i += FRAME) {
79
+ const end = Math.min(i + FRAME, audio.length);
80
+ const p = await speechProb(audio.subarray ? audio.subarray(i, end) : audio.slice(i, end));
81
+ if (p > max) max = p;
82
+ if (max >= t) { /* keep scanning a touch could refine, but early-out is enough for a gate */ break; }
83
+ }
84
+ return { speech: max >= t, maxProb: max };
85
+ }
86
+
87
+ return { backend: "silero-vad-onnx", threshold: threshold, model: model, speechProb: speechProb, segmentHasSpeech: segmentHasSpeech, reset: reset };
88
+ }
89
+
90
+ export default { createVAD };
_shared/voice/vendor/kokoro/kokoro.js ADDED
@@ -0,0 +1 @@
 
 
1
+ import{StyleTextToSpeech2Model as e,AutoTokenizer as a,Tensor as t,RawAudio as r,env as n}from"@huggingface/transformers";import{phonemize as l}from"phonemizer";import s from"path";import i from"fs/promises";function o(e){if(e.includes("."))return e;if(e.includes(":")){let[a,t]=e.split(":").map(Number);return 0===t?`${a} o'clock`:t<10?`${a} oh ${t}`:`${a} ${t}`}let a=parseInt(e.slice(0,4),10);if(a<1100||a%1e3<10)return e;let t=e.slice(0,2),r=parseInt(e.slice(2,4),10),n=e.endsWith("s")?"s":"";if(a%1e3>=100&&a%1e3<=999){if(0===r)return`${t} hundred${n}`;if(r<10)return`${t} oh ${r}${n}`}return`${t} ${r}${n}`}function c(e){const a="$"===e[0]?"dollar":"pound";if(isNaN(Number(e.slice(1))))return`${e.slice(1)} ${a}s`;if(!e.includes(".")){let t="1"===e.slice(1)?"":"s";return`${e.slice(1)} ${a}${t}`}const[t,r]=e.slice(1).split("."),n=parseInt(r.padEnd(2,"0"),10);return`${t} ${a}${"1"===t?"":"s"} and ${n} ${"$"===e[0]?1===n?"cent":"cents":1===n?"penny":"pence"}`}function g(e){let[a,t]=e.split(".");return`${a} point ${t.split("").join(" ")}`}const u=new RegExp(`(\\s*[${d=';:,.!?¡¿—…"«»“”(){}[]',d.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}]+\\s*)+`,"g");var d;async function m(e,a="a",t=!0){t&&(e=function(e){return e.replace(/[‘’]/g,"'").replace(/«/g,"“").replace(/»/g,"”").replace(/[“”]/g,'"').replace(/\(/g,"«").replace(/\)/g,"»").replace(/、/g,", ").replace(/。/g,". ").replace(/!/g,"! ").replace(/,/g,", ").replace(/:/g,": ").replace(/;/g,"; ").replace(/?/g,"? ").replace(/[^\S \n]/g," ").replace(/ +/," ").replace(/(?<=\n) +(?=\n)/g,"").replace(/\bD[Rr]\.(?= [A-Z])/g,"Doctor").replace(/\b(?:Mr\.|MR\.(?= [A-Z]))/g,"Mister").replace(/\b(?:Ms\.|MS\.(?= [A-Z]))/g,"Miss").replace(/\b(?:Mrs\.|MRS\.(?= [A-Z]))/g,"Mrs").replace(/\betc\.(?! [A-Z])/gi,"etc").replace(/\b(y)eah?\b/gi,"$1e'a").replace(/\d*\.\d+|\b\d{4}s?\b|(?<!:)\b(?:[1-9]|1[0-2]):[0-5]\d\b(?!:)/g,o).replace(/(?<=\d),(?=\d)/g,"").replace(/[$£]\d+(?:\.\d+)?(?: hundred| thousand| (?:[bm]|tr)illion)*\b|[$£]\d+\.\d\d?\b/gi,c).replace(/\d*\.\d+/g,g).replace(/(?<=\d)-(?=\d)/g," to ").replace(/(?<=\d)S/g," S").replace(/(?<=[BCDFGHJ-NP-TV-Z])'?s\b/g,"'S").replace(/(?<=X')S\b/g,"s").replace(/(?:[A-Za-z]\.){2,} [a-z]/g,(e=>e.replace(/\./g,"-"))).replace(/(?<=[A-Z])\.(?=[A-Z])/gi,"-").trim()}(e));const r=function(e,a){const t=[];let r=0;for(const n of e.matchAll(a)){const a=n[0];r<n.index&&t.push({match:!1,text:e.slice(r,n.index)}),a.length>0&&t.push({match:!0,text:a}),r=n.index+a.length}return r<e.length&&t.push({match:!1,text:e.slice(r)}),t}(e,u),n="a"===a?"en-us":"en",s=(await Promise.all(r.map((async({match:e,text:a})=>e?a:(await l(a,n)).join(" "))))).join("");let i=s.replace(/kəkˈoːɹoʊ/g,"kˈoʊkəɹoʊ").replace(/kəkˈɔːɹəʊ/g,"kˈəʊkəɹəʊ").replace(/ʲ/g,"j").replace(/r/g,"ɹ").replace(/x/g,"k").replace(/ɬ/g,"l").replace(/(?<=[a-zɹː])(?=hˈʌndɹɪd)/g," ").replace(/ z(?=[;:,.!?¡¿—…"«»“” ]|$)/g,"z");return"a"===a&&(i=i.replace(/(?<=nˈaɪn)ti(?!ː)/g,"di")),i.trim()}function p(e,a=!0){return".!?…。?!".includes(e)||a&&"\n"===e}function f(e,a){let t=a;for(;t<e.length&&!/\s/.test(e[t]);)++t;return e.substring(a,t)}const h=new Set(["mr","mrs","ms","dr","prof","sr","jr","sgt","col","gen","rep","sen","gov","lt","maj","capt","st","mt","etc","co","inc","ltd","dept","vs","p","pg","jan","feb","mar","apr","jun","jul","aug","sep","sept","oct","nov","dec","sun","mon","tu","tue","tues","wed","th","thu","thur","thurs","fri","sat"]);function _(e){return e=e.replace(/['’]s$/i,"").replace(/\.+$/,""),h.has(e.toLowerCase())}const v=new Map([[")","("],["]","["],["}","{"],["》","《"],["〉","〈"],["›","‹"],["»","«"],["〉","〈"],["」","「"],["』","『"],["〕","〔"],["】","【"]]),b=new Set(v.values());function y(e,a,t,r){if('"'===e||"'"===e){if("'"===e&&t>0&&t<r.length-1&&/[A-Za-z]/.test(r[t-1])&&/[A-Za-z]/.test(r[t+1]))return;return void(a.length&&a.at(-1)===e?a.pop():a.push(e))}if(b.has(e))return void a.push(e);const n=v.get(e);n&&a.length&&a.at(-1)===n&&a.pop()}class w{constructor(){this._buffer="",this._sentences=[],this._resolver=null,this._closed=!1}push(...e){for(const a of e)this._buffer+=a,this._process()}close(){if(this._closed)throw new Error("Stream is already closed.");this._closed=!0,this.flush()}flush(){const e=this._buffer.trim();e.length>0&&this._sentences.push(e),this._buffer="",this._resolve()}_resolve(){this._resolver&&(this._resolver(),this._resolver=null)}_process(){let e=0;const a=this._buffer,t=a.length;let r=0,n=[];const l=e=>{let r=e;for(;r+1<t&&p(a[r+1],!1);)++r;for(;r+1<t&&(n=a[r+1],"\"')]}」』".includes(n));)++r;var n;let l=r+1;for(;l<t&&/\s/.test(a[l]);)++l;return{end:r,nextNonSpace:l}};for(;r<t;){const s=a[r];if(y(s,n,r,a),0===n.length&&p(s)){const n=a.slice(e,r);if(/(^|\n)\d+$/.test(n)){++r;continue}const{end:i,nextNonSpace:o}=l(r);if(r===o-1&&"\n"!==s){++r;continue}if(o===t)break;let c=r-1;for(;c>=0&&/\S/.test(a[c]);)c--;c=Math.max(e,c+1);const g=f(a,c);if(!g){++r;continue}if((/https?[,:]\/\//.test(g)||g.includes("@"))&&!p(g.at(-1))){r=c+g.length;continue}if(_(g)){++r;continue}if(/^([A-Za-z]\.)+$/.test(g)&&o<t&&/[A-Z]/.test(a[o])){++r;continue}if("."===s&&o<t&&/[a-z]/.test(a[o])){++r;continue}const u=a.substring(e,i+1).trim();if("..."===u||"…"===u){++r;continue}u&&this._sentences.push(u),r=e=i+1}else++r}this._buffer=a.substring(e),this._sentences.length>0&&this._resolve()}async*[Symbol.asyncIterator](){if(this._resolver)throw new Error("Another iterator is already active.");for(;;)if(this._sentences.length>0)yield this._sentences.shift();else{if(this._closed)break;await new Promise((e=>{this._resolver=e}))}}[Symbol.iterator](){this.flush();const e=this._sentences[Symbol.iterator]();return this._sentences=[],e}get sentences(){return this._sentences}}const $=Object.freeze({af_heart:{name:"Heart",language:"en-us",gender:"Female",traits:"❤️",targetQuality:"A",overallGrade:"A"},af_alloy:{name:"Alloy",language:"en-us",gender:"Female",targetQuality:"B",overallGrade:"C"},af_aoede:{name:"Aoede",language:"en-us",gender:"Female",targetQuality:"B",overallGrade:"C+"},af_bella:{name:"Bella",language:"en-us",gender:"Female",traits:"🔥",targetQuality:"A",overallGrade:"A-"},af_jessica:{name:"Jessica",language:"en-us",gender:"Female",targetQuality:"C",overallGrade:"D"},af_kore:{name:"Kore",language:"en-us",gender:"Female",targetQuality:"B",overallGrade:"C+"},af_nicole:{name:"Nicole",language:"en-us",gender:"Female",traits:"🎧",targetQuality:"B",overallGrade:"B-"},af_nova:{name:"Nova",language:"en-us",gender:"Female",targetQuality:"B",overallGrade:"C"},af_river:{name:"River",language:"en-us",gender:"Female",targetQuality:"C",overallGrade:"D"},af_sarah:{name:"Sarah",language:"en-us",gender:"Female",targetQuality:"B",overallGrade:"C+"},af_sky:{name:"Sky",language:"en-us",gender:"Female",targetQuality:"B",overallGrade:"C-"},am_adam:{name:"Adam",language:"en-us",gender:"Male",targetQuality:"D",overallGrade:"F+"},am_echo:{name:"Echo",language:"en-us",gender:"Male",targetQuality:"C",overallGrade:"D"},am_eric:{name:"Eric",language:"en-us",gender:"Male",targetQuality:"C",overallGrade:"D"},am_fenrir:{name:"Fenrir",language:"en-us",gender:"Male",targetQuality:"B",overallGrade:"C+"},am_liam:{name:"Liam",language:"en-us",gender:"Male",targetQuality:"C",overallGrade:"D"},am_michael:{name:"Michael",language:"en-us",gender:"Male",targetQuality:"B",overallGrade:"C+"},am_onyx:{name:"Onyx",language:"en-us",gender:"Male",targetQuality:"C",overallGrade:"D"},am_puck:{name:"Puck",language:"en-us",gender:"Male",targetQuality:"B",overallGrade:"C+"},am_santa:{name:"Santa",language:"en-us",gender:"Male",targetQuality:"C",overallGrade:"D-"},bf_emma:{name:"Emma",language:"en-gb",gender:"Female",traits:"🚺",targetQuality:"B",overallGrade:"B-"},bf_isabella:{name:"Isabella",language:"en-gb",gender:"Female",targetQuality:"B",overallGrade:"C"},bm_george:{name:"George",language:"en-gb",gender:"Male",targetQuality:"B",overallGrade:"C"},bm_lewis:{name:"Lewis",language:"en-gb",gender:"Male",targetQuality:"C",overallGrade:"D+"},bf_alice:{name:"Alice",language:"en-gb",gender:"Female",traits:"🚺",targetQuality:"C",overallGrade:"D"},bf_lily:{name:"Lily",language:"en-gb",gender:"Female",traits:"🚺",targetQuality:"C",overallGrade:"D"},bm_daniel:{name:"Daniel",language:"en-gb",gender:"Male",traits:"🚹",targetQuality:"C",overallGrade:"D"},bm_fable:{name:"Fable",language:"en-gb",gender:"Male",traits:"🚹",targetQuality:"B",overallGrade:"C"}});const G=new Map;async function k(e){if(G.has(e))return G.get(e);const a=new Float32Array(await async function(e){if(i&&Object.hasOwn(i,"readFile")){const a="undefined"!=typeof __dirname?__dirname:import.meta.dirname,t=s.resolve(a,`../voices/${e}.bin`),{buffer:r}=await i.readFile(t);return r}const a=`https://huggingface.co/onnx-community/Kokoro-82M-v1.0-ONNX/resolve/main/voices/${e}.bin`;let t;try{t=await caches.open("kokoro-voices");const e=await t.match(a);if(e)return await e.arrayBuffer()}catch(e){console.warn("Unable to open cache",e)}const r=await fetch(a),n=await r.arrayBuffer();if(t)try{await t.put(a,new Response(n,{headers:r.headers}))}catch(e){console.warn("Unable to cache file",e)}return n}(e));return G.set(e,a),a}class M{constructor(e,a){this.model=e,this.tokenizer=a}static async from_pretrained(t,{dtype:r="fp32",device:n=null,progress_callback:l=null}={}){const s=e.from_pretrained(t,{progress_callback:l,dtype:r,device:n}),i=a.from_pretrained(t,{progress_callback:l}),o=await Promise.all([s,i]);return new M(...o)}get voices(){return $}list_voices(){console.table($)}_validate_voice(e){if(!$.hasOwnProperty(e))throw console.error(`Voice "${e}" not found. Available voices:`),console.table($),new Error(`Voice "${e}" not found. Should be one of: ${Object.keys($).join(", ")}.`);return e.at(0)}async generate(e,{voice:a="af_heart",speed:t=1}={}){const r=this._validate_voice(a),n=await m(e,r),{input_ids:l}=this.tokenizer(n,{truncation:!0});return this.generate_from_ids(l,{voice:a,speed:t})}async generate_from_ids(e,{voice:a="af_heart",speed:n=1}={}){const l=256*Math.min(Math.max(e.dims.at(-1)-2,0),509),s=(await k(a)).slice(l,l+256),i={input_ids:e,style:new t("float32",s,[1,256]),speed:new t("float32",[n],[1])},{waveform:o}=await this.model(i);return new r(o.data,24e3)}async*stream(e,{voice:a="af_heart",speed:t=1,split_pattern:r=null}={}){const n=this._validate_voice(a);let l;if(e instanceof w)l=e;else{if("string"!=typeof e)throw new Error("Invalid input type. Expected string or TextSplitterStream.");{l=new w;const a=r?e.split(r).map((e=>e.trim())).filter((e=>e.length>0)):[e];l.push(...a)}}for await(const e of l){const r=await m(e,n),{input_ids:l}=this.tokenizer(r,{truncation:!0}),s=await this.generate_from_ids(l,{voice:a,speed:t});yield{text:e,phonemes:r,audio:s}}}}const Q={set wasmPaths(e){n.backends.onnx.wasm.wasmPaths=e},get wasmPaths(){return n.backends.onnx.wasm.wasmPaths}};export{M as KokoroTTS,w as TextSplitterStream,Q as env};
_shared/voice/vendor/kokoro/phonemizer.js ADDED
The diff for this file is too large to render. See raw diff
 
_shared/voice/vendor/kokoro/stub.js ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ // browser stub for node built-ins kokoro-js imports but doesn't use client-side.
2
+ export const join = (...a) => a.join('/');
3
+ export const resolve = (...a) => a.join('/');
4
+ export const dirname = (p) => String(p).replace(/\/[^/]*$/, '');
5
+ export const readFile = async () => { throw new Error('fs unavailable in browser'); };
6
+ export default {};
_shared/voice/vendor/kokoro/transformers/ort-wasm-simd-threaded.jsep.mjs ADDED
@@ -0,0 +1,125 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ var ortWasmThreaded = (() => {
2
+ var _scriptName = import.meta.url;
3
+
4
+ return (
5
+ async function(moduleArg = {}) {
6
+ var moduleRtn;
7
+
8
+ var e=moduleArg,aa,ca,da=new Promise((a,b)=>{aa=a;ca=b}),ea="object"==typeof window,k="undefined"!=typeof WorkerGlobalScope,n="object"==typeof process&&"object"==typeof process.versions&&"string"==typeof process.versions.node&&"renderer"!=process.type,q=k&&self.name?.startsWith("em-pthread");if(n){const {createRequire:a}=await import("module");var require=a(import.meta.url),fa=require("worker_threads");global.Worker=fa.Worker;q=(k=!fa.oc)&&"em-pthread"==fa.workerData}
9
+ e.mountExternalData=(a,b)=>{a.startsWith("./")&&(a=a.substring(2));(e.Eb||(e.Eb=new Map)).set(a,b)};e.unmountExternalData=()=>{delete e.Eb};var SharedArrayBuffer=globalThis.SharedArrayBuffer??(new WebAssembly.Memory({initial:0,maximum:0,pc:!0})).buffer.constructor;
10
+ const ha=a=>async(...b)=>{try{if(e.Fb)throw Error("Session already started");const c=e.Fb={dc:b[0],errors:[]},d=await a(...b);if(e.Fb!==c)throw Error("Session mismatch");e.Jb?.flush();const f=c.errors;if(0<f.length){let g=await Promise.all(f);g=g.filter(h=>h);if(0<g.length)throw Error(g.join("\n"));}return d}finally{e.Fb=null}};
11
+ e.jsepInit=(a,b)=>{if("webgpu"===a){[e.Jb,e.Ub,e.Yb,e.Kb,e.Xb,e.jb,e.Zb,e.ac,e.Vb,e.Wb,e.$b]=b;const c=e.Jb;e.jsepRegisterBuffer=(d,f,g,h)=>c.registerBuffer(d,f,g,h);e.jsepGetBuffer=d=>c.getBuffer(d);e.jsepCreateDownloader=(d,f,g)=>c.createDownloader(d,f,g);e.jsepOnCreateSession=d=>{c.onCreateSession(d)};e.jsepOnReleaseSession=d=>{c.onReleaseSession(d)};e.jsepOnRunStart=d=>c.onRunStart(d);e.bc=(d,f)=>{c.upload(d,f)}}else if("webnn"===a){const c=b[0];[e.nc,e.Nb,e.webnnEnsureTensor,e.Ob,e.webnnDownloadTensor]=
12
+ b.slice(1);e.webnnReleaseTensorId=e.Nb;e.webnnUploadTensor=e.Ob;e.webnnOnRunStart=d=>c.onRunStart(d);e.webnnOnRunEnd=c.onRunEnd.bind(c);e.webnnRegisterMLContext=(d,f)=>{c.registerMLContext(d,f)};e.webnnOnReleaseSession=d=>{c.onReleaseSession(d)};e.webnnCreateMLTensorDownloader=(d,f)=>c.createMLTensorDownloader(d,f);e.webnnRegisterMLTensor=(d,f,g,h)=>c.registerMLTensor(d,f,g,h);e.webnnCreateMLContext=d=>c.createMLContext(d);e.webnnRegisterMLConstant=(d,f,g,h,l,m)=>c.registerMLConstant(d,f,g,h,l,e.Eb,
13
+ m);e.webnnRegisterGraphInput=c.registerGraphInput.bind(c);e.webnnIsGraphInput=c.isGraphInput.bind(c);e.webnnCreateTemporaryTensor=c.createTemporaryTensor.bind(c);e.webnnIsInt64Supported=c.isInt64Supported.bind(c)}};
14
+ let ja=()=>{const a=(b,c,d)=>(...f)=>{const g=t,h=c?.();f=b(...f);const l=c?.();h!==l&&(b=l,d(h),c=d=null);return t!=g?ia():f};(b=>{for(const c of b)e[c]=a(e[c],()=>e[c],d=>e[c]=d)})(["_OrtAppendExecutionProvider","_OrtCreateSession","_OrtRun","_OrtRunWithBinding","_OrtBindInput"]);"undefined"!==typeof ha&&(e._OrtRun=ha(e._OrtRun),e._OrtRunWithBinding=ha(e._OrtRunWithBinding));ja=void 0};e.asyncInit=()=>{ja?.()};var ka=Object.assign({},e),la="./this.program",ma=(a,b)=>{throw b;},v="",na,oa;
15
+ if(n){var fs=require("fs"),pa=require("path");import.meta.url.startsWith("data:")||(v=pa.dirname(require("url").fileURLToPath(import.meta.url))+"/");oa=a=>{a=qa(a)?new URL(a):a;return fs.readFileSync(a)};na=async a=>{a=qa(a)?new URL(a):a;return fs.readFileSync(a,void 0)};!e.thisProgram&&1<process.argv.length&&(la=process.argv[1].replace(/\\/g,"/"));process.argv.slice(2);ma=(a,b)=>{process.exitCode=a;throw b;}}else if(ea||k)k?v=self.location.href:"undefined"!=typeof document&&
16
+ document.currentScript&&(v=document.currentScript.src),_scriptName&&(v=_scriptName),v.startsWith("blob:")?v="":v=v.slice(0,v.replace(/[?#].*/,"").lastIndexOf("/")+1),n||(k&&(oa=a=>{var b=new XMLHttpRequest;b.open("GET",a,!1);b.responseType="arraybuffer";b.send(null);return new Uint8Array(b.response)}),na=async a=>{if(qa(a))return new Promise((c,d)=>{var f=new XMLHttpRequest;f.open("GET",a,!0);f.responseType="arraybuffer";f.onload=()=>{200==f.status||0==f.status&&f.response?c(f.response):d(f.status)};
17
+ f.onerror=d;f.send(null)});var b=await fetch(a,{credentials:"same-origin"});if(b.ok)return b.arrayBuffer();throw Error(b.status+" : "+b.url);});var ra=console.log.bind(console),sa=console.error.bind(console);n&&(ra=(...a)=>fs.writeSync(1,a.join(" ")+"\n"),sa=(...a)=>fs.writeSync(2,a.join(" ")+"\n"));var ta=ra,x=sa;Object.assign(e,ka);ka=null;var ua=e.wasmBinary,z,va,A=!1,wa,B,xa,ya,za,Aa,Ba,Ca,C,Da,Ea,qa=a=>a.startsWith("file://");function D(){z.buffer!=B.buffer&&E();return B}
18
+ function F(){z.buffer!=B.buffer&&E();return xa}function G(){z.buffer!=B.buffer&&E();return ya}function Fa(){z.buffer!=B.buffer&&E();return za}function H(){z.buffer!=B.buffer&&E();return Aa}function I(){z.buffer!=B.buffer&&E();return Ba}function Ga(){z.buffer!=B.buffer&&E();return Ca}function J(){z.buffer!=B.buffer&&E();return Ea}
19
+ if(q){var Ha;if(n){var Ia=fa.parentPort;Ia.on("message",b=>onmessage({data:b}));Object.assign(globalThis,{self:global,postMessage:b=>Ia.postMessage(b)})}var Ja=!1;x=function(...b){b=b.join(" ");n?fs.writeSync(2,b+"\n"):console.error(b)};self.alert=function(...b){postMessage({Bb:"alert",text:b.join(" "),ic:Ka()})};self.onunhandledrejection=b=>{throw b.reason||b;};function a(b){try{var c=b.data,d=c.Bb;if("load"===d){let f=[];self.onmessage=g=>f.push(g);self.startWorker=()=>{postMessage({Bb:"loaded"});
20
+ for(let g of f)a(g);self.onmessage=a};for(const g of c.Rb)if(!e[g]||e[g].proxy)e[g]=(...h)=>{postMessage({Bb:"callHandler",Qb:g,args:h})},"print"==g&&(ta=e[g]),"printErr"==g&&(x=e[g]);z=c.kc;E();Ha(c.lc)}else if("run"===d){La(c.Ab);Ma(c.Ab,0,0,1,0,0);Na();Oa(c.Ab);Ja||(Pa(),Ja=!0);try{Qa(c.fc,c.Hb)}catch(f){if("unwind"!=f)throw f;}}else"setimmediate"!==c.target&&("checkMailbox"===d?Ja&&Ra():d&&(x(`worker: received unknown command ${d}`),x(c)))}catch(f){throw Sa(),f;}}self.onmessage=a}
21
+ function E(){var a=z.buffer;e.HEAP8=B=new Int8Array(a);e.HEAP16=ya=new Int16Array(a);e.HEAPU8=xa=new Uint8Array(a);e.HEAPU16=za=new Uint16Array(a);e.HEAP32=Aa=new Int32Array(a);e.HEAPU32=Ba=new Uint32Array(a);e.HEAPF32=Ca=new Float32Array(a);e.HEAPF64=Ea=new Float64Array(a);e.HEAP64=C=new BigInt64Array(a);e.HEAPU64=Da=new BigUint64Array(a)}q||(z=new WebAssembly.Memory({initial:256,maximum:65536,shared:!0}),E());function Ta(){q?startWorker(e):K.Ca()}var Ua=0,Va=null;
22
+ function Wa(){Ua--;if(0==Ua&&Va){var a=Va;Va=null;a()}}function L(a){a="Aborted("+a+")";x(a);A=!0;a=new WebAssembly.RuntimeError(a+". Build with -sASSERTIONS for more info.");ca(a);throw a;}var Xa;async function Ya(a){if(!ua)try{var b=await na(a);return new Uint8Array(b)}catch{}if(a==Xa&&ua)a=new Uint8Array(ua);else if(oa)a=oa(a);else throw"both async and sync fetching of the wasm failed";return a}
23
+ async function Za(a,b){try{var c=await Ya(a);return await WebAssembly.instantiate(c,b)}catch(d){x(`failed to asynchronously prepare wasm: ${d}`),L(d)}}async function $a(a){var b=Xa;if(!ua&&"function"==typeof WebAssembly.instantiateStreaming&&!qa(b)&&!n)try{var c=fetch(b,{credentials:"same-origin"});return await WebAssembly.instantiateStreaming(c,a)}catch(d){x(`wasm streaming compile failed: ${d}`),x("falling back to ArrayBuffer instantiation")}return Za(b,a)}
24
+ function ab(){bb={L:cb,Aa:db,b:eb,$:fb,A:gb,pa:hb,X:ib,Z:jb,qa:kb,na:lb,ga:mb,ma:nb,J:ob,Y:pb,V:qb,oa:rb,W:sb,va:tb,E:ub,Q:vb,O:wb,D:xb,u:yb,r:zb,P:Ab,z:Bb,R:Cb,ja:Db,T:Eb,aa:Fb,M:Gb,F:Hb,ia:Oa,sa:Ib,t:Jb,Ba:Kb,w:Lb,o:Mb,l:Nb,c:Ob,n:Pb,j:Qb,v:Rb,p:Sb,f:Tb,s:Ub,m:Vb,e:Wb,k:Xb,i:Yb,g:Zb,d:$b,da:ac,ea:bc,fa:cc,ba:dc,ca:ec,N:fc,xa:gc,ua:hc,h:ic,C:jc,G:kc,ta:lc,x:mc,ra:nc,U:oc,q:pc,y:qc,K:rc,S:sc,za:tc,ya:uc,ka:vc,la:wc,_:xc,B:yc,I:zc,ha:Ac,H:Bc,a:z,wa:Cc};return{a:bb}}
25
+ var Dc={829644:(a,b,c,d,f)=>{if("undefined"==typeof e||!e.Eb)return 1;a=M(Number(a>>>0));a.startsWith("./")&&(a=a.substring(2));a=e.Eb.get(a);if(!a)return 2;b=Number(b>>>0);c=Number(c>>>0);d=Number(d>>>0);if(b+c>a.byteLength)return 3;try{const g=a.subarray(b,b+c);switch(f){case 0:F().set(g,d>>>0);break;case 1:e.mc?e.mc(d,g):e.bc(d,g);break;default:return 4}return 0}catch{return 4}},830468:(a,b,c)=>{e.Ob(a,F().subarray(b>>>0,b+c>>>0))},830532:()=>e.nc(),830574:a=>{e.Nb(a)},830611:()=>{e.Vb()},830642:()=>
26
+ {e.Wb()},830671:()=>{e.$b()},830696:a=>e.Ub(a),830729:a=>e.Yb(a),830761:(a,b,c)=>{e.Kb(Number(a),Number(b),Number(c),!0)},830824:(a,b,c)=>{e.Kb(Number(a),Number(b),Number(c))},830881:()=>"undefined"!==typeof wasmOffsetConverter,830938:a=>{e.jb("Abs",a,void 0)},830989:a=>{e.jb("Neg",a,void 0)},831040:a=>{e.jb("Floor",a,void 0)},831093:a=>{e.jb("Ceil",a,void 0)},831145:a=>{e.jb("Reciprocal",a,void 0)},831203:a=>{e.jb("Sqrt",a,void 0)},831255:a=>{e.jb("Exp",a,void 0)},831306:a=>{e.jb("Erf",a,void 0)},
27
+ 831357:a=>{e.jb("Sigmoid",a,void 0)},831412:(a,b,c)=>{e.jb("HardSigmoid",a,{alpha:b,beta:c})},831491:a=>{e.jb("Log",a,void 0)},831542:a=>{e.jb("Sin",a,void 0)},831593:a=>{e.jb("Cos",a,void 0)},831644:a=>{e.jb("Tan",a,void 0)},831695:a=>{e.jb("Asin",a,void 0)},831747:a=>{e.jb("Acos",a,void 0)},831799:a=>{e.jb("Atan",a,void 0)},831851:a=>{e.jb("Sinh",a,void 0)},831903:a=>{e.jb("Cosh",a,void 0)},831955:a=>{e.jb("Asinh",a,void 0)},832008:a=>{e.jb("Acosh",a,void 0)},832061:a=>{e.jb("Atanh",a,void 0)},
28
+ 832114:a=>{e.jb("Tanh",a,void 0)},832166:a=>{e.jb("Not",a,void 0)},832217:(a,b,c)=>{e.jb("Clip",a,{min:b,max:c})},832286:a=>{e.jb("Clip",a,void 0)},832338:(a,b)=>{e.jb("Elu",a,{alpha:b})},832396:a=>{e.jb("Gelu",a,void 0)},832448:a=>{e.jb("Relu",a,void 0)},832500:(a,b)=>{e.jb("LeakyRelu",a,{alpha:b})},832564:(a,b)=>{e.jb("ThresholdedRelu",a,{alpha:b})},832634:(a,b)=>{e.jb("Cast",a,{to:b})},832692:a=>{e.jb("Add",a,void 0)},832743:a=>{e.jb("Sub",a,void 0)},832794:a=>{e.jb("Mul",a,void 0)},832845:a=>
29
+ {e.jb("Div",a,void 0)},832896:a=>{e.jb("Pow",a,void 0)},832947:a=>{e.jb("Equal",a,void 0)},833E3:a=>{e.jb("Greater",a,void 0)},833055:a=>{e.jb("GreaterOrEqual",a,void 0)},833117:a=>{e.jb("Less",a,void 0)},833169:a=>{e.jb("LessOrEqual",a,void 0)},833228:(a,b,c,d,f)=>{e.jb("ReduceMean",a,{keepDims:!!b,noopWithEmptyAxes:!!c,axes:d?Array.from(H().subarray(Number(d)>>>0,Number(f)>>>0)):[]})},833403:(a,b,c,d,f)=>{e.jb("ReduceMax",a,{keepDims:!!b,noopWithEmptyAxes:!!c,axes:d?Array.from(H().subarray(Number(d)>>>
30
+ 0,Number(f)>>>0)):[]})},833577:(a,b,c,d,f)=>{e.jb("ReduceMin",a,{keepDims:!!b,noopWithEmptyAxes:!!c,axes:d?Array.from(H().subarray(Number(d)>>>0,Number(f)>>>0)):[]})},833751:(a,b,c,d,f)=>{e.jb("ReduceProd",a,{keepDims:!!b,noopWithEmptyAxes:!!c,axes:d?Array.from(H().subarray(Number(d)>>>0,Number(f)>>>0)):[]})},833926:(a,b,c,d,f)=>{e.jb("ReduceSum",a,{keepDims:!!b,noopWithEmptyAxes:!!c,axes:d?Array.from(H().subarray(Number(d)>>>0,Number(f)>>>0)):[]})},834100:(a,b,c,d,f)=>{e.jb("ReduceL1",a,{keepDims:!!b,
31
+ noopWithEmptyAxes:!!c,axes:d?Array.from(H().subarray(Number(d)>>>0,Number(f)>>>0)):[]})},834273:(a,b,c,d,f)=>{e.jb("ReduceL2",a,{keepDims:!!b,noopWithEmptyAxes:!!c,axes:d?Array.from(H().subarray(Number(d)>>>0,Number(f)>>>0)):[]})},834446:(a,b,c,d,f)=>{e.jb("ReduceLogSum",a,{keepDims:!!b,noopWithEmptyAxes:!!c,axes:d?Array.from(H().subarray(Number(d)>>>0,Number(f)>>>0)):[]})},834623:(a,b,c,d,f)=>{e.jb("ReduceSumSquare",a,{keepDims:!!b,noopWithEmptyAxes:!!c,axes:d?Array.from(H().subarray(Number(d)>>>
32
+ 0,Number(f)>>>0)):[]})},834803:(a,b,c,d,f)=>{e.jb("ReduceLogSumExp",a,{keepDims:!!b,noopWithEmptyAxes:!!c,axes:d?Array.from(H().subarray(Number(d)>>>0,Number(f)>>>0)):[]})},834983:a=>{e.jb("Where",a,void 0)},835036:(a,b,c)=>{e.jb("Transpose",a,{perm:b?Array.from(H().subarray(Number(b)>>>0,Number(c)>>>0)):[]})},835160:(a,b,c,d)=>{e.jb("DepthToSpace",a,{blocksize:b,mode:M(c),format:d?"NHWC":"NCHW"})},835293:(a,b,c,d)=>{e.jb("DepthToSpace",a,{blocksize:b,mode:M(c),format:d?"NHWC":"NCHW"})},835426:(a,
33
+ b,c,d,f,g,h,l,m,p,r,u,w,y,ba)=>{e.jb("ConvTranspose",a,{format:m?"NHWC":"NCHW",autoPad:b,dilations:[c],group:d,kernelShape:[f],pads:[g,h],strides:[l],wIsConst:()=>!!D()[p>>>0],outputPadding:r?Array.from(H().subarray(Number(r)>>>0,Number(u)>>>0)):[],outputShape:w?Array.from(H().subarray(Number(w)>>>0,Number(y)>>>0)):[],activation:M(ba)})},835859:(a,b,c,d,f,g,h,l,m,p,r,u,w,y)=>{e.jb("ConvTranspose",a,{format:l?"NHWC":"NCHW",autoPad:b,dilations:Array.from(H().subarray(Number(c)>>>0,(Number(c)>>>0)+2>>>
34
+ 0)),group:d,kernelShape:Array.from(H().subarray(Number(f)>>>0,(Number(f)>>>0)+2>>>0)),pads:Array.from(H().subarray(Number(g)>>>0,(Number(g)>>>0)+4>>>0)),strides:Array.from(H().subarray(Number(h)>>>0,(Number(h)>>>0)+2>>>0)),wIsConst:()=>!!D()[m>>>0],outputPadding:p?Array.from(H().subarray(Number(p)>>>0,Number(r)>>>0)):[],outputShape:u?Array.from(H().subarray(Number(u)>>>0,Number(w)>>>0)):[],activation:M(y)})},836520:(a,b,c,d,f,g,h,l,m,p,r,u,w,y,ba)=>{e.jb("ConvTranspose",a,{format:m?"NHWC":"NCHW",
35
+ autoPad:b,dilations:[c],group:d,kernelShape:[f],pads:[g,h],strides:[l],wIsConst:()=>!!D()[p>>>0],outputPadding:r?Array.from(H().subarray(Number(r)>>>0,Number(u)>>>0)):[],outputShape:w?Array.from(H().subarray(Number(w)>>>0,Number(y)>>>0)):[],activation:M(ba)})},836953:(a,b,c,d,f,g,h,l,m,p,r,u,w,y)=>{e.jb("ConvTranspose",a,{format:l?"NHWC":"NCHW",autoPad:b,dilations:Array.from(H().subarray(Number(c)>>>0,(Number(c)>>>0)+2>>>0)),group:d,kernelShape:Array.from(H().subarray(Number(f)>>>0,(Number(f)>>>0)+
36
+ 2>>>0)),pads:Array.from(H().subarray(Number(g)>>>0,(Number(g)>>>0)+4>>>0)),strides:Array.from(H().subarray(Number(h)>>>0,(Number(h)>>>0)+2>>>0)),wIsConst:()=>!!D()[m>>>0],outputPadding:p?Array.from(H().subarray(Number(p)>>>0,Number(r)>>>0)):[],outputShape:u?Array.from(H().subarray(Number(u)>>>0,Number(w)>>>0)):[],activation:M(y)})},837614:(a,b)=>{e.jb("GlobalAveragePool",a,{format:b?"NHWC":"NCHW"})},837705:(a,b,c,d,f,g,h,l,m,p,r,u,w,y)=>{e.jb("AveragePool",a,{format:y?"NHWC":"NCHW",auto_pad:b,ceil_mode:c,
37
+ count_include_pad:d,storage_order:f,dilations:g?Array.from(H().subarray(Number(g)>>>0,Number(h)>>>0)):[],kernel_shape:l?Array.from(H().subarray(Number(l)>>>0,Number(m)>>>0)):[],pads:p?Array.from(H().subarray(Number(p)>>>0,Number(r)>>>0)):[],strides:u?Array.from(H().subarray(Number(u)>>>0,Number(w)>>>0)):[]})},838184:(a,b)=>{e.jb("GlobalAveragePool",a,{format:b?"NHWC":"NCHW"})},838275:(a,b,c,d,f,g,h,l,m,p,r,u,w,y)=>{e.jb("AveragePool",a,{format:y?"NHWC":"NCHW",auto_pad:b,ceil_mode:c,count_include_pad:d,
38
+ storage_order:f,dilations:g?Array.from(H().subarray(Number(g)>>>0,Number(h)>>>0)):[],kernel_shape:l?Array.from(H().subarray(Number(l)>>>0,Number(m)>>>0)):[],pads:p?Array.from(H().subarray(Number(p)>>>0,Number(r)>>>0)):[],strides:u?Array.from(H().subarray(Number(u)>>>0,Number(w)>>>0)):[]})},838754:(a,b)=>{e.jb("GlobalMaxPool",a,{format:b?"NHWC":"NCHW"})},838841:(a,b,c,d,f,g,h,l,m,p,r,u,w,y)=>{e.jb("MaxPool",a,{format:y?"NHWC":"NCHW",auto_pad:b,ceil_mode:c,count_include_pad:d,storage_order:f,dilations:g?
39
+ Array.from(H().subarray(Number(g)>>>0,Number(h)>>>0)):[],kernel_shape:l?Array.from(H().subarray(Number(l)>>>0,Number(m)>>>0)):[],pads:p?Array.from(H().subarray(Number(p)>>>0,Number(r)>>>0)):[],strides:u?Array.from(H().subarray(Number(u)>>>0,Number(w)>>>0)):[]})},839316:(a,b)=>{e.jb("GlobalMaxPool",a,{format:b?"NHWC":"NCHW"})},839403:(a,b,c,d,f,g,h,l,m,p,r,u,w,y)=>{e.jb("MaxPool",a,{format:y?"NHWC":"NCHW",auto_pad:b,ceil_mode:c,count_include_pad:d,storage_order:f,dilations:g?Array.from(H().subarray(Number(g)>>>
40
+ 0,Number(h)>>>0)):[],kernel_shape:l?Array.from(H().subarray(Number(l)>>>0,Number(m)>>>0)):[],pads:p?Array.from(H().subarray(Number(p)>>>0,Number(r)>>>0)):[],strides:u?Array.from(H().subarray(Number(u)>>>0,Number(w)>>>0)):[]})},839878:(a,b,c,d,f)=>{e.jb("Gemm",a,{alpha:b,beta:c,transA:d,transB:f})},839982:a=>{e.jb("MatMul",a,void 0)},840036:(a,b,c,d)=>{e.jb("ArgMax",a,{keepDims:!!b,selectLastIndex:!!c,axis:d})},840144:(a,b,c,d)=>{e.jb("ArgMin",a,{keepDims:!!b,selectLastIndex:!!c,axis:d})},840252:(a,
41
+ b)=>{e.jb("Softmax",a,{axis:b})},840315:(a,b)=>{e.jb("Concat",a,{axis:b})},840375:(a,b,c,d,f)=>{e.jb("Split",a,{axis:b,numOutputs:c,splitSizes:d?Array.from(H().subarray(Number(d)>>>0,Number(f)>>>0)):[]})},840531:a=>{e.jb("Expand",a,void 0)},840585:(a,b)=>{e.jb("Gather",a,{axis:Number(b)})},840656:(a,b)=>{e.jb("GatherElements",a,{axis:Number(b)})},840735:(a,b)=>{e.jb("GatherND",a,{batch_dims:Number(b)})},840814:(a,b,c,d,f,g,h,l,m,p,r)=>{e.jb("Resize",a,{antialias:b,axes:c?Array.from(H().subarray(Number(c)>>>
42
+ 0,Number(d)>>>0)):[],coordinateTransformMode:M(f),cubicCoeffA:g,excludeOutside:h,extrapolationValue:l,keepAspectRatioPolicy:M(m),mode:M(p),nearestMode:M(r)})},841176:(a,b,c,d,f,g,h)=>{e.jb("Slice",a,{starts:b?Array.from(H().subarray(Number(b)>>>0,Number(c)>>>0)):[],ends:d?Array.from(H().subarray(Number(d)>>>0,Number(f)>>>0)):[],axes:g?Array.from(H().subarray(Number(g)>>>0,Number(h)>>>0)):[]})},841440:a=>{e.jb("Tile",a,void 0)},841492:(a,b,c)=>{e.jb("InstanceNormalization",a,{epsilon:b,format:c?"NHWC":
43
+ "NCHW"})},841606:(a,b,c)=>{e.jb("InstanceNormalization",a,{epsilon:b,format:c?"NHWC":"NCHW"})},841720:a=>{e.jb("Range",a,void 0)},841773:(a,b)=>{e.jb("Einsum",a,{equation:M(b)})},841854:(a,b,c,d,f)=>{e.jb("Pad",a,{mode:b,value:c,pads:d?Array.from(H().subarray(Number(d)>>>0,Number(f)>>>0)):[]})},841997:(a,b,c,d,f,g)=>{e.jb("BatchNormalization",a,{epsilon:b,momentum:c,spatial:!!f,trainingMode:!!d,format:g?"NHWC":"NCHW"})},842166:(a,b,c,d,f,g)=>{e.jb("BatchNormalization",a,{epsilon:b,momentum:c,spatial:!!f,
44
+ trainingMode:!!d,format:g?"NHWC":"NCHW"})},842335:(a,b,c)=>{e.jb("CumSum",a,{exclusive:Number(b),reverse:Number(c)})},842432:(a,b,c)=>{e.jb("DequantizeLinear",a,{axis:b,blockSize:c})},842522:(a,b,c,d,f)=>{e.jb("GridSample",a,{align_corners:b,mode:M(c),padding_mode:M(d),format:f?"NHWC":"NCHW"})},842692:(a,b,c,d,f)=>{e.jb("GridSample",a,{align_corners:b,mode:M(c),padding_mode:M(d),format:f?"NHWC":"NCHW"})},842862:(a,b)=>{e.jb("ScatterND",a,{reduction:M(b)})},842947:(a,b,c,d,f,g,h,l,m)=>{e.jb("Attention",
45
+ a,{numHeads:b,isUnidirectional:c,maskFilterValue:d,scale:f,doRotary:g,qkvHiddenSizes:h?Array.from(H().subarray(Number(l)>>>0,Number(l)+h>>>0)):[],pastPresentShareBuffer:!!m})},843219:a=>{e.jb("BiasAdd",a,void 0)},843274:a=>{e.jb("BiasSplitGelu",a,void 0)},843335:a=>{e.jb("FastGelu",a,void 0)},843391:(a,b,c,d,f,g,h,l,m,p,r,u,w,y,ba,Vd)=>{e.jb("Conv",a,{format:u?"NHWC":"NCHW",auto_pad:b,dilations:c?Array.from(H().subarray(Number(c)>>>0,Number(d)>>>0)):[],group:f,kernel_shape:g?Array.from(H().subarray(Number(g)>>>
46
+ 0,Number(h)>>>0)):[],pads:l?Array.from(H().subarray(Number(l)>>>0,Number(m)>>>0)):[],strides:p?Array.from(H().subarray(Number(p)>>>0,Number(r)>>>0)):[],w_is_const:()=>!!D()[Number(w)>>>0],activation:M(y),activation_params:ba?Array.from(Ga().subarray(Number(ba)>>>0,Number(Vd)>>>0)):[]})},843975:a=>{e.jb("Gelu",a,void 0)},844027:(a,b,c,d,f,g,h,l,m)=>{e.jb("GroupQueryAttention",a,{numHeads:b,kvNumHeads:c,scale:d,softcap:f,doRotary:g,rotaryInterleaved:h,smoothSoftmax:l,localWindowSize:m})},844244:(a,
47
+ b,c,d)=>{e.jb("LayerNormalization",a,{axis:b,epsilon:c,simplified:!!d})},844355:(a,b,c,d)=>{e.jb("LayerNormalization",a,{axis:b,epsilon:c,simplified:!!d})},844466:(a,b,c,d,f,g)=>{e.jb("MatMulNBits",a,{k:b,n:c,accuracyLevel:d,bits:f,blockSize:g})},844593:(a,b,c,d,f,g)=>{e.jb("MultiHeadAttention",a,{numHeads:b,isUnidirectional:c,maskFilterValue:d,scale:f,doRotary:g})},844752:(a,b)=>{e.jb("QuickGelu",a,{alpha:b})},844816:(a,b,c,d,f)=>{e.jb("RotaryEmbedding",a,{interleaved:!!b,numHeads:c,rotaryEmbeddingDim:d,
48
+ scale:f})},844955:(a,b,c)=>{e.jb("SkipLayerNormalization",a,{epsilon:b,simplified:!!c})},845057:(a,b,c)=>{e.jb("SkipLayerNormalization",a,{epsilon:b,simplified:!!c})},845159:(a,b,c,d)=>{e.jb("GatherBlockQuantized",a,{gatherAxis:b,quantizeAxis:c,blockSize:d})},845280:a=>{e.Zb(a)},845314:(a,b)=>e.ac(Number(a),Number(b),e.Fb.dc,e.Fb.errors)};function db(a,b,c){return Ec(async()=>{await e.Xb(Number(a),Number(b),Number(c))})}function cb(){return"undefined"!==typeof wasmOffsetConverter}
49
+ class Fc{name="ExitStatus";constructor(a){this.message=`Program terminated with exit(${a})`;this.status=a}}
50
+ var Gc=a=>{a.terminate();a.onmessage=()=>{}},Hc=[],Lc=a=>{0==N.length&&(Ic(),Jc(N[0]));var b=N.pop();if(!b)return 6;Kc.push(b);O[a.Ab]=b;b.Ab=a.Ab;var c={Bb:"run",fc:a.ec,Hb:a.Hb,Ab:a.Ab};n&&b.unref();b.postMessage(c,a.Mb);return 0},P=0,Q=(a,b,...c)=>{for(var d=2*c.length,f=Mc(),g=Nc(8*d),h=g>>>3,l=0;l<c.length;l++){var m=c[l];"bigint"==typeof m?(C[h+2*l]=1n,C[h+2*l+1]=m):(C[h+2*l]=0n,J()[h+2*l+1>>>0]=m)}a=Oc(a,0,d,g,b);Pc(f);return a};
51
+ function Cc(a){if(q)return Q(0,1,a);wa=a;if(!(0<P)){for(var b of Kc)Gc(b);for(b of N)Gc(b);N=[];Kc=[];O={};A=!0}ma(a,new Fc(a))}function Qc(a){if(q)return Q(1,0,a);xc(a)}var xc=a=>{wa=a;if(q)throw Qc(a),"unwind";Cc(a)},N=[],Kc=[],Rc=[],O={};function Sc(){for(var a=e.numThreads-1;a--;)Ic();Hc.unshift(()=>{Ua++;Tc(()=>Wa())})}var Vc=a=>{var b=a.Ab;delete O[b];N.push(a);Kc.splice(Kc.indexOf(a),1);a.Ab=0;Uc(b)};function Na(){Rc.forEach(a=>a())}
52
+ var Jc=a=>new Promise(b=>{a.onmessage=g=>{g=g.data;var h=g.Bb;if(g.Gb&&g.Gb!=Ka()){var l=O[g.Gb];l?l.postMessage(g,g.Mb):x(`Internal error! Worker sent a message "${h}" to target pthread ${g.Gb}, but that thread no longer exists!`)}else if("checkMailbox"===h)Ra();else if("spawnThread"===h)Lc(g);else if("cleanupThread"===h)Vc(O[g.hc]);else if("loaded"===h)a.loaded=!0,n&&!a.Ab&&a.unref(),b(a);else if("alert"===h)alert(`Thread ${g.ic}: ${g.text}`);else if("setimmediate"===g.target)a.postMessage(g);else if("callHandler"===
53
+ h)e[g.Qb](...g.args);else h&&x(`worker sent an unknown command ${h}`)};a.onerror=g=>{x(`${"worker sent an error!"} ${g.filename}:${g.lineno}: ${g.message}`);throw g;};n&&(a.on("message",g=>a.onmessage({data:g})),a.on("error",g=>a.onerror(g)));var c=[],d=[],f;for(f of d)e.propertyIsEnumerable(f)&&c.push(f);a.postMessage({Bb:"load",Rb:c,kc:z,lc:va})});function Tc(a){q?a():Promise.all(N.map(Jc)).then(a)}
54
+ function Ic(){var a=new Worker(new URL(import.meta.url),{type:"module",workerData:"em-pthread",name:"em-pthread"});N.push(a)}var La=a=>{E();var b=I()[a+52>>>2>>>0];a=I()[a+56>>>2>>>0];Wc(b,b-a);Pc(b)},Qa=(a,b)=>{P=0;a=Xc(a,b);0<P?wa=a:Yc(a)};class Zc{constructor(a){this.Ib=a-24}}var $c=0,ad=0;function eb(a,b,c){a>>>=0;var d=new Zc(a);b>>>=0;c>>>=0;I()[d.Ib+16>>>2>>>0]=0;I()[d.Ib+4>>>2>>>0]=b;I()[d.Ib+8>>>2>>>0]=c;$c=a;ad++;throw $c;}
55
+ function bd(a,b,c,d){return q?Q(2,1,a,b,c,d):fb(a,b,c,d)}function fb(a,b,c,d){a>>>=0;b>>>=0;c>>>=0;d>>>=0;if("undefined"==typeof SharedArrayBuffer)return 6;var f=[];if(q&&0===f.length)return bd(a,b,c,d);a={ec:c,Ab:a,Hb:d,Mb:f};return q?(a.Bb="spawnThread",postMessage(a,f),0):Lc(a)}
56
+ var cd="undefined"!=typeof TextDecoder?new TextDecoder:void 0,dd=(a,b=0,c=NaN)=>{b>>>=0;var d=b+c;for(c=b;a[c]&&!(c>=d);)++c;if(16<c-b&&a.buffer&&cd)return cd.decode(a.buffer instanceof ArrayBuffer?a.subarray(b,c):a.slice(b,c));for(d="";b<c;){var f=a[b++];if(f&128){var g=a[b++]&63;if(192==(f&224))d+=String.fromCharCode((f&31)<<6|g);else{var h=a[b++]&63;f=224==(f&240)?(f&15)<<12|g<<6|h:(f&7)<<18|g<<12|h<<6|a[b++]&63;65536>f?d+=String.fromCharCode(f):(f-=65536,d+=String.fromCharCode(55296|f>>10,56320|
57
+ f&1023))}}else d+=String.fromCharCode(f)}return d},M=(a,b)=>(a>>>=0)?dd(F(),a,b):"";function gb(a,b,c){return q?Q(3,1,a,b,c):0}function hb(a,b){if(q)return Q(4,1,a,b)}
58
+ var ed=a=>{for(var b=0,c=0;c<a.length;++c){var d=a.charCodeAt(c);127>=d?b++:2047>=d?b+=2:55296<=d&&57343>=d?(b+=4,++c):b+=3}return b},fd=(a,b,c)=>{var d=F();b>>>=0;if(0<c){var f=b;c=b+c-1;for(var g=0;g<a.length;++g){var h=a.charCodeAt(g);if(55296<=h&&57343>=h){var l=a.charCodeAt(++g);h=65536+((h&1023)<<10)|l&1023}if(127>=h){if(b>=c)break;d[b++>>>0]=h}else{if(2047>=h){if(b+1>=c)break;d[b++>>>0]=192|h>>6}else{if(65535>=h){if(b+2>=c)break;d[b++>>>0]=224|h>>12}else{if(b+3>=c)break;d[b++>>>0]=240|h>>18;
59
+ d[b++>>>0]=128|h>>12&63}d[b++>>>0]=128|h>>6&63}d[b++>>>0]=128|h&63}}d[b>>>0]=0;a=b-f}else a=0;return a};function ib(a,b){if(q)return Q(5,1,a,b)}function jb(a,b,c){if(q)return Q(6,1,a,b,c)}function kb(a,b,c){return q?Q(7,1,a,b,c):0}function lb(a,b){if(q)return Q(8,1,a,b)}function mb(a,b,c){if(q)return Q(9,1,a,b,c)}function nb(a,b,c,d){if(q)return Q(10,1,a,b,c,d)}function ob(a,b,c,d){if(q)return Q(11,1,a,b,c,d)}function pb(a,b,c,d){if(q)return Q(12,1,a,b,c,d)}function qb(a){if(q)return Q(13,1,a)}
60
+ function rb(a,b){if(q)return Q(14,1,a,b)}function sb(a,b,c){if(q)return Q(15,1,a,b,c)}var tb=()=>L(""),gd,R=a=>{for(var b="";F()[a>>>0];)b+=gd[F()[a++>>>0]];return b},hd={},jd={},kd={},S;function ld(a,b,c={}){var d=b.name;if(!a)throw new S(`type "${d}" must have a positive integer typeid pointer`);if(jd.hasOwnProperty(a)){if(c.Sb)return;throw new S(`Cannot register type '${d}' twice`);}jd[a]=b;delete kd[a];hd.hasOwnProperty(a)&&(b=hd[a],delete hd[a],b.forEach(f=>f()))}
61
+ function T(a,b,c={}){return ld(a,b,c)}var md=(a,b,c)=>{switch(b){case 1:return c?d=>D()[d>>>0]:d=>F()[d>>>0];case 2:return c?d=>G()[d>>>1>>>0]:d=>Fa()[d>>>1>>>0];case 4:return c?d=>H()[d>>>2>>>0]:d=>I()[d>>>2>>>0];case 8:return c?d=>C[d>>>3]:d=>Da[d>>>3];default:throw new TypeError(`invalid integer width (${b}): ${a}`);}};
62
+ function ub(a,b,c){a>>>=0;c>>>=0;b=R(b>>>0);T(a,{name:b,fromWireType:d=>d,toWireType:function(d,f){if("bigint"!=typeof f&&"number"!=typeof f)throw null===f?f="null":(d=typeof f,f="object"===d||"array"===d||"function"===d?f.toString():""+f),new TypeError(`Cannot convert "${f}" to ${this.name}`);"number"==typeof f&&(f=BigInt(f));return f},Cb:U,readValueFromPointer:md(b,c,-1==b.indexOf("u")),Db:null})}var U=8;
63
+ function vb(a,b,c,d){a>>>=0;b=R(b>>>0);T(a,{name:b,fromWireType:function(f){return!!f},toWireType:function(f,g){return g?c:d},Cb:U,readValueFromPointer:function(f){return this.fromWireType(F()[f>>>0])},Db:null})}var nd=[],V=[];function Ob(a){a>>>=0;9<a&&0===--V[a+1]&&(V[a]=void 0,nd.push(a))}
64
+ var W=a=>{if(!a)throw new S("Cannot use deleted val. handle = "+a);return V[a]},X=a=>{switch(a){case void 0:return 2;case null:return 4;case !0:return 6;case !1:return 8;default:const b=nd.pop()||V.length;V[b]=a;V[b+1]=1;return b}};function od(a){return this.fromWireType(I()[a>>>2>>>0])}var pd={name:"emscripten::val",fromWireType:a=>{var b=W(a);Ob(a);return b},toWireType:(a,b)=>X(b),Cb:U,readValueFromPointer:od,Db:null};function wb(a){return T(a>>>0,pd)}
65
+ var qd=(a,b)=>{switch(b){case 4:return function(c){return this.fromWireType(Ga()[c>>>2>>>0])};case 8:return function(c){return this.fromWireType(J()[c>>>3>>>0])};default:throw new TypeError(`invalid float width (${b}): ${a}`);}};function xb(a,b,c){a>>>=0;c>>>=0;b=R(b>>>0);T(a,{name:b,fromWireType:d=>d,toWireType:(d,f)=>f,Cb:U,readValueFromPointer:qd(b,c),Db:null})}
66
+ function yb(a,b,c,d,f){a>>>=0;c>>>=0;b=R(b>>>0);-1===f&&(f=4294967295);f=l=>l;if(0===d){var g=32-8*c;f=l=>l<<g>>>g}var h=b.includes("unsigned")?function(l,m){return m>>>0}:function(l,m){return m};T(a,{name:b,fromWireType:f,toWireType:h,Cb:U,readValueFromPointer:md(b,c,0!==d),Db:null})}
67
+ function zb(a,b,c){function d(g){var h=I()[g>>>2>>>0];g=I()[g+4>>>2>>>0];return new f(D().buffer,g,h)}a>>>=0;var f=[Int8Array,Uint8Array,Int16Array,Uint16Array,Int32Array,Uint32Array,Float32Array,Float64Array,BigInt64Array,BigUint64Array][b];c=R(c>>>0);T(a,{name:c,fromWireType:d,Cb:U,readValueFromPointer:d},{Sb:!0})}
68
+ function Ab(a,b){a>>>=0;b=R(b>>>0);T(a,{name:b,fromWireType:function(c){for(var d=I()[c>>>2>>>0],f=c+4,g,h=f,l=0;l<=d;++l){var m=f+l;if(l==d||0==F()[m>>>0])h=M(h,m-h),void 0===g?g=h:(g+=String.fromCharCode(0),g+=h),h=m+1}Y(c);return g},toWireType:function(c,d){d instanceof ArrayBuffer&&(d=new Uint8Array(d));var f="string"==typeof d;if(!(f||d instanceof Uint8Array||d instanceof Uint8ClampedArray||d instanceof Int8Array))throw new S("Cannot pass non-string to std::string");var g=f?ed(d):d.length;var h=
69
+ rd(4+g+1),l=h+4;I()[h>>>2>>>0]=g;if(f)fd(d,l,g+1);else if(f)for(f=0;f<g;++f){var m=d.charCodeAt(f);if(255<m)throw Y(h),new S("String has UTF-16 code units that do not fit in 8 bits");F()[l+f>>>0]=m}else for(f=0;f<g;++f)F()[l+f>>>0]=d[f];null!==c&&c.push(Y,h);return h},Cb:U,readValueFromPointer:od,Db(c){Y(c)}})}
70
+ var sd="undefined"!=typeof TextDecoder?new TextDecoder("utf-16le"):void 0,td=(a,b)=>{var c=a>>1;for(var d=c+b/2;!(c>=d)&&Fa()[c>>>0];)++c;c<<=1;if(32<c-a&&sd)return sd.decode(F().slice(a,c));c="";for(d=0;!(d>=b/2);++d){var f=G()[a+2*d>>>1>>>0];if(0==f)break;c+=String.fromCharCode(f)}return c},ud=(a,b,c)=>{c??=2147483647;if(2>c)return 0;c-=2;var d=b;c=c<2*a.length?c/2:a.length;for(var f=0;f<c;++f){var g=a.charCodeAt(f);G()[b>>>1>>>0]=g;b+=2}G()[b>>>1>>>0]=0;return b-d},vd=a=>2*a.length,wd=(a,b)=>{for(var c=
71
+ 0,d="";!(c>=b/4);){var f=H()[a+4*c>>>2>>>0];if(0==f)break;++c;65536<=f?(f-=65536,d+=String.fromCharCode(55296|f>>10,56320|f&1023)):d+=String.fromCharCode(f)}return d},xd=(a,b,c)=>{b>>>=0;c??=2147483647;if(4>c)return 0;var d=b;c=d+c-4;for(var f=0;f<a.length;++f){var g=a.charCodeAt(f);if(55296<=g&&57343>=g){var h=a.charCodeAt(++f);g=65536+((g&1023)<<10)|h&1023}H()[b>>>2>>>0]=g;b+=4;if(b+4>c)break}H()[b>>>2>>>0]=0;return b-d},yd=a=>{for(var b=0,c=0;c<a.length;++c){var d=a.charCodeAt(c);55296<=d&&57343>=
72
+ d&&++c;b+=4}return b};
73
+ function Bb(a,b,c){a>>>=0;b>>>=0;c>>>=0;c=R(c);if(2===b){var d=td;var f=ud;var g=vd;var h=l=>Fa()[l>>>1>>>0]}else 4===b&&(d=wd,f=xd,g=yd,h=l=>I()[l>>>2>>>0]);T(a,{name:c,fromWireType:l=>{for(var m=I()[l>>>2>>>0],p,r=l+4,u=0;u<=m;++u){var w=l+4+u*b;if(u==m||0==h(w))r=d(r,w-r),void 0===p?p=r:(p+=String.fromCharCode(0),p+=r),r=w+b}Y(l);return p},toWireType:(l,m)=>{if("string"!=typeof m)throw new S(`Cannot pass non-string to C++ string type ${c}`);var p=g(m),r=rd(4+p+b);I()[r>>>2>>>0]=p/b;f(m,r+4,p+b);
74
+ null!==l&&l.push(Y,r);return r},Cb:U,readValueFromPointer:od,Db(l){Y(l)}})}function Cb(a,b){a>>>=0;b=R(b>>>0);T(a,{Tb:!0,name:b,Cb:0,fromWireType:()=>{},toWireType:()=>{}})}function Db(a){Ma(a>>>0,!k,1,!ea,131072,!1);Na()}var zd=a=>{if(!A)try{if(a(),!(0<P))try{q?Yc(wa):xc(wa)}catch(b){b instanceof Fc||"unwind"==b||ma(1,b)}}catch(b){b instanceof Fc||"unwind"==b||ma(1,b)}};
75
+ function Oa(a){a>>>=0;"function"===typeof Atomics.jc&&(Atomics.jc(H(),a>>>2,a).value.then(Ra),a+=128,Atomics.store(H(),a>>>2,1))}var Ra=()=>{var a=Ka();a&&(Oa(a),zd(Ad))};function Eb(a,b){a>>>=0;a==b>>>0?setTimeout(Ra):q?postMessage({Gb:a,Bb:"checkMailbox"}):(a=O[a])&&a.postMessage({Bb:"checkMailbox"})}var Bd=[];function Fb(a,b,c,d,f){b>>>=0;d/=2;Bd.length=d;c=f>>>0>>>3;for(f=0;f<d;f++)Bd[f]=C[c+2*f]?C[c+2*f+1]:J()[c+2*f+1>>>0];return(b?Dc[b]:Cd[a])(...Bd)}var Gb=()=>{P=0};
76
+ function Hb(a){a>>>=0;q?postMessage({Bb:"cleanupThread",hc:a}):Vc(O[a])}function Ib(a){n&&O[a>>>0].ref()}var Ed=(a,b)=>{var c=jd[a];if(void 0===c)throw a=Dd(a),c=R(a),Y(a),new S(`${b} has unknown type ${c}`);return c},Fd=(a,b,c)=>{var d=[];a=a.toWireType(d,c);d.length&&(I()[b>>>2>>>0]=X(d));return a};function Jb(a,b,c){b>>>=0;c>>>=0;a=W(a>>>0);b=Ed(b,"emval::as");return Fd(b,c,a)}function Kb(a,b){b>>>=0;a=W(a>>>0);b=Ed(b,"emval::as");return b.toWireType(null,a)}var Gd=a=>{try{a()}catch(b){L(b)}};
77
+ function Hd(){var a=K,b={};for(let [c,d]of Object.entries(a))b[c]="function"==typeof d?(...f)=>{Id.push(c);try{return d(...f)}finally{A||(Id.pop(),t&&1===Z&&0===Id.length&&(Z=0,P+=1,Gd(Jd),"undefined"!=typeof Fibers&&Fibers.rc()))}}:d;return b}var Z=0,t=null,Kd=0,Id=[],Ld={},Md={},Nd=0,Od=null,Pd=[];function ia(){return new Promise((a,b)=>{Od={resolve:a,reject:b}})}
78
+ function Qd(){var a=rd(65548),b=a+12;I()[a>>>2>>>0]=b;I()[a+4>>>2>>>0]=b+65536;b=Id[0];var c=Ld[b];void 0===c&&(c=Nd++,Ld[b]=c,Md[c]=b);b=c;H()[a+8>>>2>>>0]=b;return a}function Rd(){var a=H()[t+8>>>2>>>0];a=K[Md[a]];--P;return a()}
79
+ function Sd(a){if(!A){if(0===Z){var b=!1,c=!1;a((d=0)=>{if(!A&&(Kd=d,b=!0,c)){Z=2;Gd(()=>Td(t));"undefined"!=typeof MainLoop&&MainLoop.Pb&&MainLoop.resume();d=!1;try{var f=Rd()}catch(l){f=l,d=!0}var g=!1;if(!t){var h=Od;h&&(Od=null,(d?h.reject:h.resolve)(f),g=!0)}if(d&&!g)throw f;}});c=!0;b||(Z=1,t=Qd(),"undefined"!=typeof MainLoop&&MainLoop.Pb&&MainLoop.pause(),Gd(()=>Ud(t)))}else 2===Z?(Z=0,Gd(Wd),Y(t),t=null,Pd.forEach(zd)):L(`invalid state: ${Z}`);return Kd}}
80
+ function Ec(a){return Sd(b=>{a().then(b)})}function Lb(a){a>>>=0;return Ec(async()=>{var b=await W(a);return X(b)})}var Xd=[];function Mb(a,b,c,d){c>>>=0;d>>>=0;a=Xd[a>>>0];b=W(b>>>0);return a(null,b,c,d)}var Yd={},Zd=a=>{var b=Yd[a];return void 0===b?R(a):b};function Nb(a,b,c,d,f){c>>>=0;d>>>=0;f>>>=0;a=Xd[a>>>0];b=W(b>>>0);c=Zd(c);return a(b,b[c],d,f)}var $d=()=>"object"==typeof globalThis?globalThis:Function("return this")();
81
+ function Pb(a){a>>>=0;if(0===a)return X($d());a=Zd(a);return X($d()[a])}var ae=a=>{var b=Xd.length;Xd.push(a);return b},be=(a,b)=>{for(var c=Array(a),d=0;d<a;++d)c[d]=Ed(I()[b+4*d>>>2>>>0],"parameter "+d);return c},ce=(a,b)=>Object.defineProperty(b,"name",{value:a});
82
+ function de(a){var b=Function;if(!(b instanceof Function))throw new TypeError(`new_ called with constructor type ${typeof b} which is not a function`);var c=ce(b.name||"unknownFunctionName",function(){});c.prototype=b.prototype;c=new c;a=b.apply(c,a);return a instanceof Object?a:c}
83
+ function Qb(a,b,c){b=be(a,b>>>0);var d=b.shift();a--;var f="return function (obj, func, destructorsRef, args) {\n",g=0,h=[];0===c&&h.push("obj");for(var l=["retType"],m=[d],p=0;p<a;++p)h.push("arg"+p),l.push("argType"+p),m.push(b[p]),f+=` var arg${p} = argType${p}.readValueFromPointer(args${g?"+"+g:""});\n`,g+=b[p].Cb;f+=` var rv = ${1===c?"new func":"func.call"}(${h.join(", ")});\n`;d.Tb||(l.push("emval_returnValue"),m.push(Fd),f+=" return emval_returnValue(retType, destructorsRef, rv);\n");l.push(f+
84
+ "};\n");a=de(l)(...m);c=`methodCaller<(${b.map(r=>r.name).join(", ")}) => ${d.name}>`;return ae(ce(c,a))}function Rb(a){a=Zd(a>>>0);return X(e[a])}function Sb(a,b){b>>>=0;a=W(a>>>0);b=W(b);return X(a[b])}function Tb(a){a>>>=0;9<a&&(V[a+1]+=1)}function Ub(){return X([])}function Vb(a){a=W(a>>>0);for(var b=Array(a.length),c=0;c<a.length;c++)b[c]=a[c];return X(b)}function Wb(a){return X(Zd(a>>>0))}function Xb(){return X({})}
85
+ function Yb(a){a>>>=0;for(var b=W(a);b.length;){var c=b.pop();b.pop()(c)}Ob(a)}function Zb(a,b,c){b>>>=0;c>>>=0;a=W(a>>>0);b=W(b);c=W(c);a[b]=c}function $b(a,b){b>>>=0;a=Ed(a>>>0,"_emval_take_value");a=a.readValueFromPointer(b);return X(a)}
86
+ function ac(a,b){a=-9007199254740992>a||9007199254740992<a?NaN:Number(a);b>>>=0;a=new Date(1E3*a);H()[b>>>2>>>0]=a.getUTCSeconds();H()[b+4>>>2>>>0]=a.getUTCMinutes();H()[b+8>>>2>>>0]=a.getUTCHours();H()[b+12>>>2>>>0]=a.getUTCDate();H()[b+16>>>2>>>0]=a.getUTCMonth();H()[b+20>>>2>>>0]=a.getUTCFullYear()-1900;H()[b+24>>>2>>>0]=a.getUTCDay();a=(a.getTime()-Date.UTC(a.getUTCFullYear(),0,1,0,0,0,0))/864E5|0;H()[b+28>>>2>>>0]=a}
87
+ var ee=a=>0===a%4&&(0!==a%100||0===a%400),fe=[0,31,60,91,121,152,182,213,244,274,305,335],ge=[0,31,59,90,120,151,181,212,243,273,304,334];
88
+ function bc(a,b){a=-9007199254740992>a||9007199254740992<a?NaN:Number(a);b>>>=0;a=new Date(1E3*a);H()[b>>>2>>>0]=a.getSeconds();H()[b+4>>>2>>>0]=a.getMinutes();H()[b+8>>>2>>>0]=a.getHours();H()[b+12>>>2>>>0]=a.getDate();H()[b+16>>>2>>>0]=a.getMonth();H()[b+20>>>2>>>0]=a.getFullYear()-1900;H()[b+24>>>2>>>0]=a.getDay();var c=(ee(a.getFullYear())?fe:ge)[a.getMonth()]+a.getDate()-1|0;H()[b+28>>>2>>>0]=c;H()[b+36>>>2>>>0]=-(60*a.getTimezoneOffset());c=(new Date(a.getFullYear(),6,1)).getTimezoneOffset();
89
+ var d=(new Date(a.getFullYear(),0,1)).getTimezoneOffset();a=(c!=d&&a.getTimezoneOffset()==Math.min(d,c))|0;H()[b+32>>>2>>>0]=a}
90
+ function cc(a){a>>>=0;var b=new Date(H()[a+20>>>2>>>0]+1900,H()[a+16>>>2>>>0],H()[a+12>>>2>>>0],H()[a+8>>>2>>>0],H()[a+4>>>2>>>0],H()[a>>>2>>>0],0),c=H()[a+32>>>2>>>0],d=b.getTimezoneOffset(),f=(new Date(b.getFullYear(),6,1)).getTimezoneOffset(),g=(new Date(b.getFullYear(),0,1)).getTimezoneOffset(),h=Math.min(g,f);0>c?H()[a+32>>>2>>>0]=Number(f!=g&&h==d):0<c!=(h==d)&&(f=Math.max(g,f),b.setTime(b.getTime()+6E4*((0<c?h:f)-d)));H()[a+24>>>2>>>0]=b.getDay();c=(ee(b.getFullYear())?fe:ge)[b.getMonth()]+
91
+ b.getDate()-1|0;H()[a+28>>>2>>>0]=c;H()[a>>>2>>>0]=b.getSeconds();H()[a+4>>>2>>>0]=b.getMinutes();H()[a+8>>>2>>>0]=b.getHours();H()[a+12>>>2>>>0]=b.getDate();H()[a+16>>>2>>>0]=b.getMonth();H()[a+20>>>2>>>0]=b.getYear();a=b.getTime();return BigInt(isNaN(a)?-1:a/1E3)}function dc(a,b,c,d,f,g,h){return q?Q(16,1,a,b,c,d,f,g,h):-52}function ec(a,b,c,d,f,g){if(q)return Q(17,1,a,b,c,d,f,g)}var he={},pc=()=>performance.timeOrigin+performance.now();
92
+ function fc(a,b){if(q)return Q(18,1,a,b);he[a]&&(clearTimeout(he[a].id),delete he[a]);if(!b)return 0;var c=setTimeout(()=>{delete he[a];zd(()=>ie(a,performance.timeOrigin+performance.now()))},b);he[a]={id:c,qc:b};return 0}
93
+ function gc(a,b,c,d){a>>>=0;b>>>=0;c>>>=0;d>>>=0;var f=(new Date).getFullYear(),g=(new Date(f,0,1)).getTimezoneOffset();f=(new Date(f,6,1)).getTimezoneOffset();var h=Math.max(g,f);I()[a>>>2>>>0]=60*h;H()[b>>>2>>>0]=Number(g!=f);b=l=>{var m=Math.abs(l);return`UTC${0<=l?"-":"+"}${String(Math.floor(m/60)).padStart(2,"0")}${String(m%60).padStart(2,"0")}`};a=b(g);b=b(f);f<g?(fd(a,c,17),fd(b,d,17)):(fd(a,d,17),fd(b,c,17))}var lc=()=>Date.now(),je=1;
94
+ function hc(a,b,c){if(!(0<=a&&3>=a))return 28;if(0===a)a=Date.now();else if(je)a=performance.timeOrigin+performance.now();else return 52;C[c>>>0>>>3]=BigInt(Math.round(1E6*a));return 0}var ke=[],le=(a,b)=>{ke.length=0;for(var c;c=F()[a++>>>0];){var d=105!=c;d&=112!=c;b+=d&&b%8?4:0;ke.push(112==c?I()[b>>>2>>>0]:106==c?C[b>>>3]:105==c?H()[b>>>2>>>0]:J()[b>>>3>>>0]);b+=d?8:4}return ke};function ic(a,b,c){a>>>=0;b=le(b>>>0,c>>>0);return Dc[a](...b)}
95
+ function jc(a,b,c){a>>>=0;b=le(b>>>0,c>>>0);return Dc[a](...b)}var kc=()=>{};function mc(a,b){return x(M(a>>>0,b>>>0))}var nc=()=>{P+=1;throw"unwind";};function oc(){return 4294901760}var qc=()=>n?require("os").cpus().length:navigator.hardwareConcurrency;function rc(){L("Cannot use emscripten_pc_get_function without -sUSE_OFFSET_CONVERTER");return 0}
96
+ function sc(a){a>>>=0;var b=F().length;if(a<=b||4294901760<a)return!1;for(var c=1;4>=c;c*=2){var d=b*(1+.2/c);d=Math.min(d,a+100663296);a:{d=(Math.min(4294901760,65536*Math.ceil(Math.max(a,d)/65536))-z.buffer.byteLength+65535)/65536|0;try{z.grow(d);E();var f=1;break a}catch(g){}f=void 0}if(f)return!0}return!1}var me=()=>{L("Cannot use convertFrameToPC (needed by __builtin_return_address) without -sUSE_OFFSET_CONVERTER");return 0},ne={},oe=a=>{a.forEach(b=>{var c=me();c&&(ne[c]=b)})};
97
+ function tc(){var a=Error().stack.toString().split("\n");"Error"==a[0]&&a.shift();oe(a);ne.Lb=me();ne.cc=a;return ne.Lb}function uc(a,b,c){a>>>=0;b>>>=0;if(ne.Lb==a)var d=ne.cc;else d=Error().stack.toString().split("\n"),"Error"==d[0]&&d.shift(),oe(d);for(var f=3;d[f]&&me()!=a;)++f;for(a=0;a<c&&d[a+f];++a)H()[b+4*a>>>2>>>0]=me();return a}
98
+ var pe={},re=()=>{if(!qe){var a={USER:"web_user",LOGNAME:"web_user",PATH:"/",PWD:"/",HOME:"/home/web_user",LANG:("object"==typeof navigator&&navigator.languages&&navigator.languages[0]||"C").replace("-","_")+".UTF-8",_:la||"./this.program"},b;for(b in pe)void 0===pe[b]?delete a[b]:a[b]=pe[b];var c=[];for(b in a)c.push(`${b}=${a[b]}`);qe=c}return qe},qe;
99
+ function vc(a,b){if(q)return Q(19,1,a,b);a>>>=0;b>>>=0;var c=0;re().forEach((d,f)=>{var g=b+c;f=I()[a+4*f>>>2>>>0]=g;for(g=0;g<d.length;++g)D()[f++>>>0]=d.charCodeAt(g);D()[f>>>0]=0;c+=d.length+1});return 0}function wc(a,b){if(q)return Q(20,1,a,b);a>>>=0;b>>>=0;var c=re();I()[a>>>2>>>0]=c.length;var d=0;c.forEach(f=>d+=f.length+1);I()[b>>>2>>>0]=d;return 0}function yc(a){return q?Q(21,1,a):52}function zc(a,b,c,d){return q?Q(22,1,a,b,c,d):52}function Ac(a,b,c,d){return q?Q(23,1,a,b,c,d):70}
100
+ var se=[null,[],[]];function Bc(a,b,c,d){if(q)return Q(24,1,a,b,c,d);b>>>=0;c>>>=0;d>>>=0;for(var f=0,g=0;g<c;g++){var h=I()[b>>>2>>>0],l=I()[b+4>>>2>>>0];b+=8;for(var m=0;m<l;m++){var p=F()[h+m>>>0],r=se[a];0===p||10===p?((1===a?ta:x)(dd(r)),r.length=0):r.push(p)}f+=l}I()[d>>>2>>>0]=f;return 0}q||Sc();for(var te=Array(256),ue=0;256>ue;++ue)te[ue]=String.fromCharCode(ue);gd=te;S=e.BindingError=class extends Error{constructor(a){super(a);this.name="BindingError"}};
101
+ e.InternalError=class extends Error{constructor(a){super(a);this.name="InternalError"}};V.push(0,1,void 0,1,null,1,!0,1,!1,1);e.count_emval_handles=()=>V.length/2-5-nd.length;var Cd=[Cc,Qc,bd,gb,hb,ib,jb,kb,lb,mb,nb,ob,pb,qb,rb,sb,dc,ec,fc,vc,wc,yc,zc,Ac,Bc],bb,K;
102
+ (async function(){function a(d,f){K=d.exports;K=Hd();K=ve();Rc.push(K.ib);va=f;Wa();return K}Ua++;var b=ab();if(e.instantiateWasm)return new Promise(d=>{e.instantiateWasm(b,(f,g)=>{a(f,g);d(f.exports)})});if(q)return new Promise(d=>{Ha=f=>{var g=new WebAssembly.Instance(f,ab());d(a(g,f))}});Xa??=e.locateFile?e.locateFile?e.locateFile("ort-wasm-simd-threaded.jsep.wasm",v):v+"ort-wasm-simd-threaded.jsep.wasm":(new URL("ort-wasm-simd-threaded.jsep.wasm",import.meta.url)).href;try{var c=await $a(b);
103
+ return a(c.instance,c.module)}catch(d){return ca(d),Promise.reject(d)}})();var Dd=a=>(Dd=K.Da)(a),Pa=()=>(Pa=K.Ea)();e._OrtInit=(a,b)=>(e._OrtInit=K.Fa)(a,b);e._OrtGetLastError=(a,b)=>(e._OrtGetLastError=K.Ga)(a,b);e._OrtCreateSessionOptions=(a,b,c,d,f,g,h,l,m,p)=>(e._OrtCreateSessionOptions=K.Ha)(a,b,c,d,f,g,h,l,m,p);e._OrtAppendExecutionProvider=(a,b,c,d,f)=>(e._OrtAppendExecutionProvider=K.Ia)(a,b,c,d,f);e._OrtAddFreeDimensionOverride=(a,b,c)=>(e._OrtAddFreeDimensionOverride=K.Ja)(a,b,c);
104
+ e._OrtAddSessionConfigEntry=(a,b,c)=>(e._OrtAddSessionConfigEntry=K.Ka)(a,b,c);e._OrtReleaseSessionOptions=a=>(e._OrtReleaseSessionOptions=K.La)(a);e._OrtCreateSession=(a,b,c)=>(e._OrtCreateSession=K.Ma)(a,b,c);e._OrtReleaseSession=a=>(e._OrtReleaseSession=K.Na)(a);e._OrtGetInputOutputCount=(a,b,c)=>(e._OrtGetInputOutputCount=K.Oa)(a,b,c);e._OrtGetInputOutputMetadata=(a,b,c,d)=>(e._OrtGetInputOutputMetadata=K.Pa)(a,b,c,d);e._OrtFree=a=>(e._OrtFree=K.Qa)(a);
105
+ e._OrtCreateTensor=(a,b,c,d,f,g)=>(e._OrtCreateTensor=K.Ra)(a,b,c,d,f,g);e._OrtGetTensorData=(a,b,c,d,f)=>(e._OrtGetTensorData=K.Sa)(a,b,c,d,f);e._OrtReleaseTensor=a=>(e._OrtReleaseTensor=K.Ta)(a);e._OrtCreateRunOptions=(a,b,c,d)=>(e._OrtCreateRunOptions=K.Ua)(a,b,c,d);e._OrtAddRunConfigEntry=(a,b,c)=>(e._OrtAddRunConfigEntry=K.Va)(a,b,c);e._OrtReleaseRunOptions=a=>(e._OrtReleaseRunOptions=K.Wa)(a);e._OrtCreateBinding=a=>(e._OrtCreateBinding=K.Xa)(a);
106
+ e._OrtBindInput=(a,b,c)=>(e._OrtBindInput=K.Ya)(a,b,c);e._OrtBindOutput=(a,b,c,d)=>(e._OrtBindOutput=K.Za)(a,b,c,d);e._OrtClearBoundOutputs=a=>(e._OrtClearBoundOutputs=K._a)(a);e._OrtReleaseBinding=a=>(e._OrtReleaseBinding=K.$a)(a);e._OrtRunWithBinding=(a,b,c,d,f)=>(e._OrtRunWithBinding=K.ab)(a,b,c,d,f);e._OrtRun=(a,b,c,d,f,g,h,l)=>(e._OrtRun=K.bb)(a,b,c,d,f,g,h,l);e._OrtEndProfiling=a=>(e._OrtEndProfiling=K.cb)(a);e._JsepOutput=(a,b,c)=>(e._JsepOutput=K.db)(a,b,c);
107
+ e._JsepGetNodeName=a=>(e._JsepGetNodeName=K.eb)(a);
108
+ var Ka=()=>(Ka=K.fb)(),Y=e._free=a=>(Y=e._free=K.gb)(a),rd=e._malloc=a=>(rd=e._malloc=K.hb)(a),Ma=(a,b,c,d,f,g)=>(Ma=K.kb)(a,b,c,d,f,g),Sa=()=>(Sa=K.lb)(),Oc=(a,b,c,d,f)=>(Oc=K.mb)(a,b,c,d,f),Uc=a=>(Uc=K.nb)(a),Yc=a=>(Yc=K.ob)(a),ie=(a,b)=>(ie=K.pb)(a,b),Ad=()=>(Ad=K.qb)(),Wc=(a,b)=>(Wc=K.rb)(a,b),Pc=a=>(Pc=K.sb)(a),Nc=a=>(Nc=K.tb)(a),Mc=()=>(Mc=K.ub)(),Xc=e.dynCall_ii=(a,b)=>(Xc=e.dynCall_ii=K.vb)(a,b),Ud=a=>(Ud=K.wb)(a),Jd=()=>(Jd=K.xb)(),Td=a=>(Td=K.yb)(a),Wd=()=>(Wd=K.zb)();
109
+ function ve(){var a=K;a=Object.assign({},a);var b=d=>f=>d(f)>>>0,c=d=>()=>d()>>>0;a.Da=b(a.Da);a.fb=c(a.fb);a.hb=b(a.hb);a.tb=b(a.tb);a.ub=c(a.ub);a.__cxa_get_exception_ptr=b(a.__cxa_get_exception_ptr);return a}e.stackSave=()=>Mc();e.stackRestore=a=>Pc(a);e.stackAlloc=a=>Nc(a);
110
+ e.setValue=function(a,b,c="i8"){c.endsWith("*")&&(c="*");switch(c){case "i1":D()[a>>>0]=b;break;case "i8":D()[a>>>0]=b;break;case "i16":G()[a>>>1>>>0]=b;break;case "i32":H()[a>>>2>>>0]=b;break;case "i64":C[a>>>3]=BigInt(b);break;case "float":Ga()[a>>>2>>>0]=b;break;case "double":J()[a>>>3>>>0]=b;break;case "*":I()[a>>>2>>>0]=b;break;default:L(`invalid type for setValue: ${c}`)}};
111
+ e.getValue=function(a,b="i8"){b.endsWith("*")&&(b="*");switch(b){case "i1":return D()[a>>>0];case "i8":return D()[a>>>0];case "i16":return G()[a>>>1>>>0];case "i32":return H()[a>>>2>>>0];case "i64":return C[a>>>3];case "float":return Ga()[a>>>2>>>0];case "double":return J()[a>>>3>>>0];case "*":return I()[a>>>2>>>0];default:L(`invalid type for getValue: ${b}`)}};e.UTF8ToString=M;e.stringToUTF8=fd;e.lengthBytesUTF8=ed;
112
+ function we(){if(0<Ua)Va=we;else if(q)aa(e),Ta();else{for(;0<Hc.length;)Hc.shift()(e);0<Ua?Va=we:(e.calledRun=!0,A||(Ta(),aa(e)))}}we();e.PTR_SIZE=4;moduleRtn=da;
113
+
114
+
115
+ return moduleRtn;
116
+ }
117
+ );
118
+ })();
119
+ export default ortWasmThreaded;
120
+ var isPthread = globalThis.self?.name?.startsWith('em-pthread');
121
+ var isNode = typeof globalThis.process?.versions?.node == 'string';
122
+ if (isNode) isPthread = (await import('worker_threads')).workerData === 'em-pthread';
123
+
124
+ // When running as a pthread, construct a new instance on startup
125
+ isPthread && ortWasmThreaded();
_shared/voice/vendor/kokoro/transformers/ort-wasm-simd-threaded.jsep.wasm ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:c46655e8a94afc45338d4cb2b840475f88e5012d524509916e505079c00bfa39
3
+ size 21596019
_shared/voice/vendor/kokoro/transformers/transformers.js ADDED
The diff for this file is too large to render. See raw diff
 
_shared/voice/vendor/models/onnx-community/Kokoro-82M-v1.0-ONNX/config.json ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ {
2
+ "model_type": "style_text_to_speech_2"
3
+ }
_shared/voice/vendor/models/onnx-community/Kokoro-82M-v1.0-ONNX/tokenizer.json ADDED
@@ -0,0 +1,175 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "version": "1.0",
3
+ "truncation": null,
4
+ "padding": null,
5
+ "added_tokens": [],
6
+ "normalizer": {
7
+ "type": "Replace",
8
+ "pattern": {
9
+ "Regex": "[^$;:,.!?\u2014\u2026\"()\u201c\u201d \u0303\u02a3\u02a5\u02a6\u02a8\u1d5d\uab67AIOQSTWY\u1d4aabcdefhijklmnopqrstuvwxyz\u0251\u0250\u0252\u00e6\u03b2\u0254\u0255\u00e7\u0256\u00f0\u02a4\u0259\u025a\u025b\u025c\u025f\u0261\u0265\u0268\u026a\u029d\u026f\u0270\u014b\u0273\u0272\u0274\u00f8\u0278\u03b8\u0153\u0279\u027e\u027b\u0281\u027d\u0282\u0283\u0288\u02a7\u028a\u028b\u028c\u0263\u0264\u03c7\u028e\u0292\u0294\u02c8\u02cc\u02d0\u02b0\u02b2\u2193\u2192\u2197\u2198\u1d7b]"
10
+ },
11
+ "content": ""
12
+ },
13
+ "pre_tokenizer": {
14
+ "type": "Split",
15
+ "pattern": {
16
+ "Regex": ""
17
+ },
18
+ "behavior": "Isolated",
19
+ "invert": false
20
+ },
21
+ "post_processor": {
22
+ "type": "TemplateProcessing",
23
+ "single": [
24
+ {
25
+ "SpecialToken": {
26
+ "id": "$",
27
+ "type_id": 0
28
+ }
29
+ },
30
+ {
31
+ "Sequence": {
32
+ "id": "A",
33
+ "type_id": 0
34
+ }
35
+ },
36
+ {
37
+ "SpecialToken": {
38
+ "id": "$",
39
+ "type_id": 0
40
+ }
41
+ }
42
+ ],
43
+ "special_tokens": {
44
+ "$": {
45
+ "id": "$",
46
+ "ids": [
47
+ 0
48
+ ],
49
+ "tokens": [
50
+ "$"
51
+ ]
52
+ }
53
+ }
54
+ },
55
+ "decoder": null,
56
+ "model": {
57
+ "vocab": {
58
+ "$": 0,
59
+ ";": 1,
60
+ ":": 2,
61
+ ",": 3,
62
+ ".": 4,
63
+ "!": 5,
64
+ "?": 6,
65
+ "\u2014": 9,
66
+ "\u2026": 10,
67
+ "\"": 11,
68
+ "(": 12,
69
+ ")": 13,
70
+ "\u201c": 14,
71
+ "\u201d": 15,
72
+ " ": 16,
73
+ "\u0303": 17,
74
+ "\u02a3": 18,
75
+ "\u02a5": 19,
76
+ "\u02a6": 20,
77
+ "\u02a8": 21,
78
+ "\u1d5d": 22,
79
+ "\uab67": 23,
80
+ "A": 24,
81
+ "I": 25,
82
+ "O": 31,
83
+ "Q": 33,
84
+ "S": 35,
85
+ "T": 36,
86
+ "W": 39,
87
+ "Y": 41,
88
+ "\u1d4a": 42,
89
+ "a": 43,
90
+ "b": 44,
91
+ "c": 45,
92
+ "d": 46,
93
+ "e": 47,
94
+ "f": 48,
95
+ "h": 50,
96
+ "i": 51,
97
+ "j": 52,
98
+ "k": 53,
99
+ "l": 54,
100
+ "m": 55,
101
+ "n": 56,
102
+ "o": 57,
103
+ "p": 58,
104
+ "q": 59,
105
+ "r": 60,
106
+ "s": 61,
107
+ "t": 62,
108
+ "u": 63,
109
+ "v": 64,
110
+ "w": 65,
111
+ "x": 66,
112
+ "y": 67,
113
+ "z": 68,
114
+ "\u0251": 69,
115
+ "\u0250": 70,
116
+ "\u0252": 71,
117
+ "\u00e6": 72,
118
+ "\u03b2": 75,
119
+ "\u0254": 76,
120
+ "\u0255": 77,
121
+ "\u00e7": 78,
122
+ "\u0256": 80,
123
+ "\u00f0": 81,
124
+ "\u02a4": 82,
125
+ "\u0259": 83,
126
+ "\u025a": 85,
127
+ "\u025b": 86,
128
+ "\u025c": 87,
129
+ "\u025f": 90,
130
+ "\u0261": 92,
131
+ "\u0265": 99,
132
+ "\u0268": 101,
133
+ "\u026a": 102,
134
+ "\u029d": 103,
135
+ "\u026f": 110,
136
+ "\u0270": 111,
137
+ "\u014b": 112,
138
+ "\u0273": 113,
139
+ "\u0272": 114,
140
+ "\u0274": 115,
141
+ "\u00f8": 116,
142
+ "\u0278": 118,
143
+ "\u03b8": 119,
144
+ "\u0153": 120,
145
+ "\u0279": 123,
146
+ "\u027e": 125,
147
+ "\u027b": 126,
148
+ "\u0281": 128,
149
+ "\u027d": 129,
150
+ "\u0282": 130,
151
+ "\u0283": 131,
152
+ "\u0288": 132,
153
+ "\u02a7": 133,
154
+ "\u028a": 135,
155
+ "\u028b": 136,
156
+ "\u028c": 138,
157
+ "\u0263": 139,
158
+ "\u0264": 140,
159
+ "\u03c7": 142,
160
+ "\u028e": 143,
161
+ "\u0292": 147,
162
+ "\u0294": 148,
163
+ "\u02c8": 156,
164
+ "\u02cc": 157,
165
+ "\u02d0": 158,
166
+ "\u02b0": 162,
167
+ "\u02b2": 164,
168
+ "\u2193": 169,
169
+ "\u2192": 171,
170
+ "\u2197": 172,
171
+ "\u2198": 173,
172
+ "\u1d7b": 177
173
+ }
174
+ }
175
+ }
_shared/voice/vendor/models/onnx-community/Kokoro-82M-v1.0-ONNX/tokenizer_config.json ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ {
2
+ "model_max_length": 512,
3
+ "pad_token": "$",
4
+ "tokenizer_class": "PreTrainedTokenizer",
5
+ "unk_token": "$"
6
+ }
_shared/voice/vendor/models/onnx-community/Kokoro-82M-v1.0-ONNX/voices/af_bella.bin ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:f69d836209b78eb8c66e75e3cda491e26ea838a3674257e9d4e5703cbaf55c8b
3
+ size 522240
_shared/voice/vendor/models/onnx-community/Kokoro-82M-v1.0-ONNX/voices/af_heart.bin ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:d583ccff3cdca2f7fae535cb998ac07e9fcb90f09737b9a41fa2734ec44a8f0b
3
+ size 522240
_shared/voice/vendor/models/onnx-community/Kokoro-82M-v1.0-ONNX/voices/af_nicole.bin ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:cd2191ab31b914ed7b318416b0e4440fdf392ddad9106a060819aa600a64f59a
3
+ size 522240
_shared/voice/vendor/models/onnx-community/Kokoro-82M-v1.0-ONNX/voices/am_fenrir.bin ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:c27989f741f7ee34d273a39d8a595cc0837d35f5ced9a29b7cc162614616df43
3
+ size 522240
_shared/voice/vendor/models/onnx-community/Kokoro-82M-v1.0-ONNX/voices/am_michael.bin ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:1d1f21dd8da39c30705cd4c75d039d265e9bc4a2a93ed09bc9e1b1225eb95ba1
3
+ size 522240
_shared/voice/vendor/models/onnx-community/Kokoro-82M-v1.0-ONNX/voices/am_puck.bin ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:fcf73c989033e9233e0b98713eca600c8c74dcc1614b37009d5450ff4a2274a0
3
+ size 522240
_shared/voice/vendor/models/onnx-community/Kokoro-82M-v1.0-ONNX/voices/bf_emma.bin ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:669fe0647f9dd04fcab92f1439a40eeb4c8b4ab1f82e4996fe3d918ce4a63b73
3
+ size 522240
_shared/voice/vendor/models/onnx-community/Kokoro-82M-v1.0-ONNX/voices/bm_george.bin ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:c4b235a4c1f2cd3b939fed08b899ce9385638b763f7b73a59616c4fc9bd6c9bc
3
+ size 522240
_shared/voice/vendor/models/onnx-community/silero-vad/onnx/model.onnx ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:a4a068cd6cf1ea8355b84327595838ca748ec29a25bc91fc82e6c299ccdc5808
3
+ size 2243022
_shared/voice/vendor/models/onnx-community/silero-vad/onnx/model_quantized.onnx ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:982c96dc518784fb9d19bc7f56cc8252473b020e4f2099f32049e4ad0b3b43e7
3
+ size 639335
_shared/voice/vendor/transformers/ort-wasm-simd-threaded.jsep.wasm ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:0f6fe5c40378504d1a25a77f766133464bb15705af23e01c994f185719fb080e
3
+ size 21643825
_shared/voice/vendor/transformers/transformers.js ADDED
The diff for this file is too large to render. See raw diff
 
_shared/voice/vendor/transformers/transformers.mjs ADDED
The diff for this file is too large to render. See raw diff
 
apps/q/core/engine.js ADDED
@@ -0,0 +1,203 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // core/engine.js — the inference ENGINE adapter (the only module that touches the wasm
2
+ // tokenizer + the WebGPU `gpu` object). DOM-free. Wraps a model that core/loader.js has
3
+ // already loaded onto the GPU and exposes a clean, UI-agnostic API:
4
+ //
5
+ // const engine = await createEngine(modelEntry, { gpu, info, imageKappa });
6
+ // const { text, outIds } = await engine.generate(ids, { onToken, signal });
7
+ // const rec = await engine.buildReceipt({ ... }); // PROV-O, re-derivable (Law L5)
8
+ //
9
+ // The token loop, framing, memo and receipt logic are lifted byte-for-byte from the
10
+ // original index.html think()/run()/sealReceipt — only the DOM writes are replaced by an
11
+ // onToken callback and the running/handedOff flags by an AbortSignal, so output (and the
12
+ // receipt κ) is identical to the original app.
13
+
14
+ import { qvac_tokenize, qvac_continue, kappa } from "../pkg/holospaces_web.js";
15
+ import { clean, didHolo, kappaTokens, sealReceipt, verifyIntegrity, idBytes, kappaBytes } from "./kappa.js";
16
+
17
+ const _perf = () => (typeof performance !== "undefined" ? performance.now() : 0);
18
+ const _sleep = (ms) => new Promise((r) => setTimeout(r, ms));
19
+
20
+ // The engine is itself a content-addressed object — hash the wasm once (lazy).
21
+ let _engineK = null;
22
+ export async function engineKappa() {
23
+ if (_engineK) return _engineK;
24
+ try { const b = new Uint8Array(await (await fetch(new URL("../pkg/holospaces_web_bg.wasm", import.meta.url))).arrayBuffer()); _engineK = await kappaBytes(b); }
25
+ catch { _engineK = "did:holo:sha256:(engine unavailable)"; }
26
+ return _engineK;
27
+ }
28
+
29
+ export async function createEngine(modelEntry, loaded) {
30
+ const { gpu, info, imageKappa } = loaded;
31
+ const m = modelEntry;
32
+ const engineReady = engineKappa();
33
+
34
+ // model κ: the κ-disk's VERIFIED image_kappa when present (a real content address of the
35
+ // weights, every sector re-derived); else the model's declared identity.
36
+ const modelKappa = imageKappa
37
+ ? "did:holo:sha256:" + String(imageKappa).replace(/^(did:holo:)?sha256:/, "")
38
+ : await didHolo({ "@type": "schema:SoftwareSourceCode", name: m.name, size: m.size, fmt: m.fmt || "", family: m.fam || "" });
39
+
40
+ const memo = new Map();
41
+ let _drafter = null; // learned speculative drafter (fn(seq,max)=>ids); null → standard decode. Set via setDrafter().
42
+ let _pinLen = 0; // KV-COMMONS prefix pin: length of the pinned shared prefix (0 = none). See pinPrefix/usePin below.
43
+
44
+ const tokenize = (text) => { try { return JSON.parse(qvac_tokenize(text)).ids || []; } catch { return []; } };
45
+ const detokenize = (ids) => { try { return clean(JSON.parse(qvac_continue(JSON.stringify(ids), 0, 0, 0, ids.length)).text || ""); } catch { return ""; } };
46
+ const fingerprint = (ids) => kappa(idBytes(ids)); // live mind κ (blake3, from wasm)
47
+
48
+ // Frame one user turn. Qwen2/3 use ChatML (its <|im_*|> markers are atomic BPE tokens);
49
+ // other instruction models use a plain Q/A frame. (Verbatim from the original run().)
50
+ function frameTurn(prompt, hasHistory) {
51
+ if (m.qwen) {
52
+ const noThink = m.qwen3 ? "<think>\n\n</think>\n\n" : ""; // Qwen3: skip the thinking block for fast direct answers
53
+ return (hasHistory ? "<|im_end|>\n" : "") + `<|im_start|>user\n${prompt}<|im_end|>\n<|im_start|>assistant\n` + noThink;
54
+ }
55
+ if (m.llama3) // LLaMA-3 header template (BitNet b1.58 etc.)
56
+ return (hasHistory ? "<|eot_id|>" : "") + `<|start_header_id|>user<|end_header_id|>\n\n${prompt}<|eot_id|><|start_header_id|>assistant<|end_header_id|>\n\n`;
57
+ if (m.olmo) // OLMo/OLMoE: <|user|>/<|assistant|> role tags (each turn self-delimited; leading bos via m.bos)
58
+ return `<|user|>\n${prompt}\n<|assistant|>\n`;
59
+ if (m.userWord) // word-frame (Falcon-E: its ChatML template stalls EMPIRICALLY; "User:/Falcon:" answers — see q-falcon-templates sweep)
60
+ return (hasHistory ? "\n" : "") + "User: " + prompt + "\nFalcon:";
61
+ return "Question: " + prompt + "\nAnswer:";
62
+ }
63
+
64
+ function params() {
65
+ const temp = m.temp || 0;
66
+ return { decode: temp > 0 ? "sampled@t=" + temp : "greedy-argmax", maxTokens: m.cap, repetitionPenalty: m.rep ?? 1.05, template: m.qwen ? "chatml" : m.llama3 ? "llama3" : "qa", thinking: !m.qwen3 };
67
+ }
68
+
69
+ // The streaming token loop. `ids` is the whole running conversation (the mind); generation
70
+ // appends to it. onToken({ text, ids, outIds, stats }) fires per step; signal aborts.
71
+ async function generate(ids, { onToken, signal, repPenalty, maxNew } = {}) {
72
+ const rep = repPenalty ?? m.rep ?? 1.3;
73
+ const newCap = maxNew ?? m.cap ?? 80; // max NEW tokens this call
74
+ const kvCap = (m.ctx || m.cap || 80) + 8; // the engine's KV allocation (loader kvOf)
75
+ const promptLen = ids.length;
76
+ const tStart = _perf();
77
+ let first = true, decodeStart = 0, decodeTok = 0, ttft = 0, tokps = 0, msExec = 0, err = null, outText = "";
78
+ if (promptLen >= kvCap - 1) err = new Error(`context full: ${promptLen} tokens ≥ ${kvCap} KV positions`);
79
+
80
+ // SPECULATIVE PATH (opt-in): when a learned drafter is registered and the engine has the batched-verify
81
+ // head, the drafter proposes and the target batch-verifies — output is BYTE-IDENTICAL to greedy decode
82
+ // (greedy verify), streamed via onCommit. Any incompatibility/throw falls straight through to the standard
83
+ // loop below, so default Q (no drafter) and unsupported models are completely unaffected.
84
+ if (!err && _drafter && gpu.specDecode && gpu.setDrafter) {
85
+ try {
86
+ gpu.setDrafter(_drafter);
87
+ const out = []; const t0 = _perf(); let ttft2 = 0, tokps2 = 0;
88
+ const seq = await gpu.specDecode(ids.slice(), newCap, rep, (tk) => {
89
+ if (signal && signal.aborted) return false;
90
+ out.push(tk);
91
+ if (!ttft2) ttft2 = _perf() - tStart;
92
+ const dt = _perf() - t0; if (dt > 0) tokps2 = out.length / (dt / 1000);
93
+ if (onToken) onToken({ text: detokenize(out), ids: ids.slice(0, promptLen).concat(out), outIds: out.slice(), stats: { ttft: ttft2, tokps: tokps2, msExec: gpu.timing ? gpu.timing.exec : 0, gpuBytes: gpu.gpuBytes, spec: gpu.specStats ? gpu.specStats() : null } });
94
+ return out.length < newCap;
95
+ });
96
+ const outIds = seq.slice(promptLen);
97
+ let text = detokenize(outIds);
98
+ if (m.stopText) { const ix = text.indexOf(m.stopText); if (ix >= 0) text = text.slice(0, ix); }
99
+ return { text, outIds, ids: seq, stats: { ttft: ttft2, tokps: tokps2, msExec: gpu.timing ? gpu.timing.exec : 0, spec: gpu.specStats ? gpu.specStats() : null }, error: null };
100
+ } catch (e) { try { gpu.setDrafter(null); } catch {} /* fall through to the standard decode loop */ }
101
+ }
102
+
103
+ while (!err && !(signal && signal.aborted) && ids.length - promptLen < newCap && ids.length < kvCap - 1) {
104
+ const prevLen = ids.length;
105
+ try { ids = await (gpu.decode || gpu.generate)(ids, first ? 1 : 6, rep); } // batched GPU decode head (4 B/token readback) when the engine has it
106
+ catch (e) { err = e; break; }
107
+ const dn = ids.length - prevLen;
108
+ if (dn > 0) {
109
+ msExec = gpu.timing ? gpu.timing.exec : msExec;
110
+ if (first) { ttft = _perf() - tStart; decodeStart = _perf(); first = false; } // TTFT = prefill + first token
111
+ else { decodeTok += dn; const dt = _perf() - decodeStart; if (dt > 0) tokps = decodeTok / (dt / 1000); } // steady decode rate
112
+ }
113
+ const di = ids.slice(promptLen);
114
+ // incremental detokenize: decode only a bounded window (the dn new tokens + a small left context)
115
+ // and append the delta — O(1) per step, not re-detokenizing the whole growing output (was O(n²)).
116
+ { const a = Math.max(promptLen, ids.length - (dn + 8)); const wf = detokenize(ids.slice(a)); const wp = a >= ids.length - dn ? "" : detokenize(ids.slice(a, ids.length - dn)); outText += wf.slice(wp.length); }
117
+ let text = outText, hitStop = false;
118
+ if (m.stopText) { const ix = text.indexOf(m.stopText); if (ix >= 0) { text = text.slice(0, ix); hitStop = true; } } // word-framed models stop on the next "User:" turn
119
+ if (onToken) onToken({ text, ids: ids.slice(), outIds: di.slice(), stats: { ttft, tokps, msExec, gpuBytes: gpu.gpuBytes } });
120
+ if (hitStop) break;
121
+ if (ids.length <= prevLen) break; // EOS / no progress
122
+ // degeneration guard: a long run of one repeated character (the repetition collapse of
123
+ // small/experimental quants) will never recover — stop instead of burning the budget.
124
+ if (text.length > 80 && /(.)\1{63}$/.test(text)) { err = new Error("degenerate repetition — stopped"); break; }
125
+ await _sleep(0); // yield to the event loop so the UI can paint — no artificial throttle (gpu.decode already awaits the GPU)
126
+ }
127
+ const outIds = ids.slice(promptLen);
128
+ let text = detokenize(outIds);
129
+ if (m.stopText) { const ix = text.indexOf(m.stopText); if (ix >= 0) text = text.slice(0, ix); }
130
+ return { text, outIds, ids, stats: { ttft, tokps, msExec }, error: err };
131
+ }
132
+
133
+ // DIFFUSION decode (Dream-class): iterative bidirectional unmasking over a fixed `steps` budget,
134
+ // wall-clock fixed by steps not output length. Greedy ⇒ deterministic ⇒ κ-re-derivable (Law L5).
135
+ // `ids` is the framed prompt; we diffuse `genLen` masked positions after it. Returns the same shape
136
+ // as generate() so callers (and the brain seam) are agnostic. onToken fires ONCE with the final fill
137
+ // (diffusion has no left-to-right token stream — the whole block resolves together).
138
+ // Two modes: APPEND (genLen masks at the suffix — generation) or FILL (ids ALREADY contain mask ids
139
+ // anywhere → infill/surgical edit, conditioning on BOTH sides; diffusion's structural edge over AR).
140
+ // `causal` flips the parity gate (causal block=1 must equal the sequential engine — validates the pass).
141
+ async function diffuse(ids, { genLen, steps, fill, causal, signal, onToken } = {}) {
142
+ if (!gpu || !gpu.diffuse) throw new Error("this model has no diffusion engine (load a diffusion κ-object)");
143
+ const gl = fill ? 0 : (genLen ?? Math.min(m.cap || 64, (m.ctx || 192) - ids.length - 1));
144
+ const S = steps ?? m.steps ?? 12;
145
+ const tStart = _perf();
146
+ const seq = await gpu.diffuse(ids, gl, { steps: S, fill: !!fill, causal: !!causal, signal });
147
+ // append → output is the generated suffix; fill → the whole sequence is the answer (a span edited in place)
148
+ const outIds = fill ? seq.slice() : seq.slice(ids.length);
149
+ let text = detokenize(outIds);
150
+ if (m.stopText && !fill) { const ix = text.indexOf(m.stopText); if (ix >= 0) text = text.slice(0, ix); }
151
+ const stats = { ttft: _perf() - tStart, tokps: 0, msExec: gpu.timing ? gpu.timing.exec : 0, steps: S, fill: !!fill, diff: gpu.diffStats ? gpu.diffStats() : null };
152
+ if (onToken) onToken({ text, ids: seq.slice(), outIds: outIds.slice(), stats });
153
+ return { text, outIds, ids: seq, stats, error: null };
154
+ }
155
+
156
+ // κ-memo: identical (context ⊕ prompt ⊕ model ⊕ params) → replay in O(1), no decode.
157
+ const memoKey = async (ctxIds, turnIds, p) => didHolo({ ctx: await kappaTokens(ctxIds.concat(turnIds)), model: modelKappa, params: p || params() });
158
+
159
+ async function buildReceipt({ promptText, ctxIds, turnIds, outIds, fromMemo, evaluateText, paramsPatch, extraUsed }) {
160
+ return sealReceipt({
161
+ promptText, ctxIds, turnIds, outIds, text: detokenize(outIds), params: { ...params(), ...(paramsPatch || {}) }, fromMemo,
162
+ modelKappa, engineKappa: await engineReady, evaluateText, extraUsed,
163
+ });
164
+ }
165
+
166
+ // Re-derivation (greedy only): re-run the exact inference and reproduce κ(output) byte-for-byte.
167
+ async function reDerive(rec) {
168
+ if (!gpu) return { ok: false, reason: "load the model to re-derive" };
169
+ if (/sampled/.test(rec.params.decode)) return { ok: false, reason: "sampled decode — only the κ-binding is verifiable, not re-derivation" };
170
+ try {
171
+ let seq = rec.ctxIds.concat(rec.turnIds); const start = seq.length;
172
+ gpu.reset();
173
+ seq = await (gpu.decode || gpu.generate)(seq, rec.outIds.length, rec.params.repetitionPenalty); // same head as the live path — replay must match byte-for-byte
174
+ const got = await kappaTokens(seq.slice(start)), want = rec.body["prov:generated"]["holo:outputTokens"];
175
+ return { ok: got === want, got, want };
176
+ } finally { try { gpu.reset(); } catch {} }
177
+ }
178
+
179
+ return {
180
+ model: m, dims: gpu.dims, modelKappa, bosId: info?.bos ?? null, get gpuBytes() { return gpu.gpuBytes; },
181
+ tokenize, detokenize, fingerprint, frameTurn, params,
182
+ generate,
183
+ // register/clear the learned speculative drafter (fn(seq,max)=>ids). Off by default; safe fallback.
184
+ setDrafter: (fn) => { _drafter = fn || null; try { gpu.setDrafter && gpu.setDrafter(_drafter); } catch (e) {} },
185
+ specAvailable: !!(gpu.specDecode && gpu.setDrafter),
186
+ // ── KV-COMMONS prefix pin (in-session; parity with the standalone Q engine) ──────────────────────
187
+ // Prefill a stable shared prefix (the system persona) ONCE and keep it resident, so every following
188
+ // generate() that begins with the SAME tokens reuses its K/V and prefills only the new turn (sync()
189
+ // matches the common prefix, decodes from divergence). Byte-identical to a cold prefill — the collapse
190
+ // is exact (same ids, same positions, same weights). Needs gpu.sync + gpu.truncateTo (present here).
191
+ kvPinAvailable: !!(gpu.truncateTo && gpu.sync),
192
+ // pinPrefix(ids): prefill `ids` and remember the resident length as the pin.
193
+ pinPrefix: async (ids) => { if (!gpu.sync || !gpu.truncateTo) return 0; try { gpu.reset(); await gpu.sync(ids.slice()); _pinLen = gpu.cachedLen; return _pinLen; } catch (e) { _pinLen = 0; return 0; } },
194
+ // pinCurrent(len): pin an already-resident prefix (e.g. the persona just prefilled as a greeting side-effect) — zero extra prefill.
195
+ pinCurrent: (len) => { if (!gpu.truncateTo) return 0; try { _pinLen = gpu.truncateTo(len); return _pinLen; } catch (e) { return 0; } },
196
+ // usePin(): rewind the KV cursor to the pinned prefix right before a turn, so sync() reuses it. Returns reused length.
197
+ usePin: () => { if (_pinLen > 0 && gpu.truncateTo) { try { return gpu.truncateTo(_pinLen); } catch (e) { return 0; } } return 0; },
198
+ pinLen: () => _pinLen,
199
+ memoKey, memoGet: (k) => memo.get(k), memoHas: (k) => memo.has(k), memoSet: (k, v) => memo.set(k, v),
200
+ buildReceipt, verify: verifyIntegrity, reDerive,
201
+ stats: () => gpu.timing, reset: () => { try { gpu.reset(); } catch {} }, destroy: () => { try { gpu.destroy(); } catch {} },
202
+ };
203
+ }
apps/q/core/kappa.js ADDED
@@ -0,0 +1,76 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // core/kappa.js — the PURE content-addressing + receipt layer (no wasm, no DOM).
2
+ //
3
+ // Lifted verbatim (behaviour-identical) from the original Holo Q index.html so that
4
+ // BOTH the browser app and the pure-Node witness (tools/q-witness.mjs) import the same
5
+ // re-derivation logic. Uses only Web Crypto (crypto.subtle), which exists in the browser
6
+ // and in Node ≥ 20 as globalThis.crypto.subtle — so a receipt's κ re-derives identically
7
+ // in either runtime (Law L5). The PROV-O receipt body and its did:holo are byte-for-byte
8
+ // what the original sealed, so existing receipts keep verifying.
9
+
10
+ const _enc = new TextEncoder();
11
+ const _td = new TextDecoder();
12
+
13
+ // RFC 8785 JCS — canonical JSON, so a receipt's κ re-derives identically anywhere.
14
+ export const jcs = (v) => Array.isArray(v) ? "[" + v.map(jcs).join(",") + "]"
15
+ : (v && typeof v === "object") ? "{" + Object.keys(v).sort().map((k) => JSON.stringify(k) + ":" + jcs(v[k])).join(",") + "}"
16
+ : JSON.stringify(v);
17
+
18
+ export async function sha256hex(u8) {
19
+ const d = await crypto.subtle.digest("SHA-256", u8);
20
+ return Array.from(new Uint8Array(d), (b) => b.toString(16).padStart(2, "0")).join("");
21
+ }
22
+
23
+ export const idBytes = (ids) => new Uint8Array(new Uint32Array(ids).buffer);
24
+
25
+ export const didHolo = async (obj) => "did:holo:sha256:" + await sha256hex(_enc.encode(jcs(obj)));
26
+ export const kappaText = async (s) => "did:holo:sha256:" + await sha256hex(_enc.encode(s || ""));
27
+ export const kappaTokens = async (a) => "did:holo:sha256:" + await sha256hex(idBytes(a)); // the answer's tokens, by content
28
+ export const kappaBytes = async (u8) => "did:holo:sha256:" + await sha256hex(u8);
29
+
30
+ export const shortK = (k) => {
31
+ const s = String(k || ""); const ax = s.split(":").slice(0, 2).join(":"); const h = s.split(":").pop();
32
+ return ax + ":" + (h.length > 18 ? h.slice(0, 12) + "…" + h.slice(-4) : h);
33
+ };
34
+
35
+ // SentencePiece byte-fallback tokens (<0xNN>) → their actual bytes, UTF-8 decoded.
36
+ export const decodeBytes = (t) => t.replace(/(?:<0x[0-9A-Fa-f]{2}>)+/g, (run) => {
37
+ const b = []; run.replace(/<0x([0-9A-Fa-f]{2})>/g, (_, h) => (b.push(parseInt(h, 16)), ""));
38
+ try { return _td.decode(new Uint8Array(b)); } catch { return ""; }
39
+ });
40
+ export const clean = (t) => decodeBytes(
41
+ t.replace(/<think>[\s\S]*?<\/think>/g, "").replace(/<\/?think>/g, "").replace(/<\|[^>]*\|>/g, "").replace(/<unk>|<s>|<\/s>/g, "")
42
+ ).replace(/^\s+/, "");
43
+
44
+ // ── verifiable-inference receipt ────────────────────────────────────────────────
45
+ // An answer is a content-addressed, re-derivable transform on the substrate:
46
+ // κ(context) ⊕ κ(prompt) ⊕ κ(model) ⊕ κ(params) ⊕ κ(engine) → κ(output)
47
+ // sealed as a PROV-O receipt with its OWN did:holo. Greedy decode is deterministic,
48
+ // so anyone re-runs it and reproduces κ(output) byte for byte (Law L5).
49
+
50
+ // Build the canonical PROV-O receipt body. All κ inputs are already did:holo strings.
51
+ // `extraUsed` merges additional provenance (e.g. holo:toolReceipts — the agentic work-trail).
52
+ export function receiptBody({ modelKappa, engineKappa, promptKappa, contextKappa, outputKappa, tokenCount, params, conscience, extraUsed }) {
53
+ return {
54
+ "@context": ["http://www.w3.org/ns/prov#", { holo: "https://hologram.os/ns/q#" }],
55
+ "@type": "prov:Activity", "holo:kind": "verifiable-inference",
56
+ "prov:used": { "holo:model": modelKappa, "holo:engine": engineKappa, "holo:prompt": promptKappa, "holo:context": contextKappa, "holo:params": params, ...(extraUsed || {}) },
57
+ "prov:generated": { "holo:outputTokens": outputKappa, "holo:tokenCount": tokenCount },
58
+ "holo:conscience": conscience || { outcome: "unverified" },
59
+ };
60
+ }
61
+
62
+ // Seal a receipt: compute the κ inputs from raw tokens/text, assemble the body, address it.
63
+ // `text` is the already-decoded answer; `evaluateText` (optional) is the conscience judge.
64
+ export async function sealReceipt({ promptText, ctxIds, turnIds, outIds, text, params, fromMemo, modelKappa, engineKappa, evaluateText, extraUsed }) {
65
+ const [promptKappa, contextKappa, outputKappa] = await Promise.all([
66
+ kappaText(promptText), kappaTokens(ctxIds.concat(turnIds)), kappaTokens(outIds),
67
+ ]);
68
+ let conscience = { outcome: "unverified" };
69
+ try { if (evaluateText) { const v = evaluateText(text); conscience = { outcome: v.outcome, blocked: v.blocked || [], caveats: v.caveats || [], sealed: v.sealed !== false }; } } catch {}
70
+ const body = receiptBody({ modelKappa, engineKappa, promptKappa, contextKappa, outputKappa, tokenCount: outIds.length, params, conscience, extraUsed });
71
+ const id = await didHolo(body);
72
+ return { id, body, text, promptText, ctxIds: ctxIds.slice(), turnIds: turnIds.slice(), outIds: outIds.slice(), params, fromMemo: !!fromMemo };
73
+ }
74
+
75
+ // Integrity: recompute the receipt's did:holo from its body — tamper any byte and it won't match.
76
+ export const verifyIntegrity = async (rec) => { const again = await didHolo(rec.body); return { ok: again === rec.id, again }; };
apps/q/core/loader.js ADDED
@@ -0,0 +1,205 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // core/loader.js — model LOADING (the 5 substrate paths) + the model catalog + the
2
+ // browser-cache manager. Lifted faithfully from the original index.html so a model still
3
+ // loads byte-identically; the only change is that DOM status writes become onStatus/onProgress
4
+ // callbacks, and each path RETURNS { gpu, info, manifest, imageKappa } instead of mutating
5
+ // globals. core/engine.js then wraps the returned gpu. (window.__gpu / window.__kd handles are
6
+ // still exposed for the probe + system-monitor panels.)
7
+
8
+ import init, { kappa, qvac_load_model, qvac_load_gpu, qvac_tokenize, qvac_continue, qvac_gpu_manifest, qvac_gpu_tensor, qvac_gpu_free, qvac_panic_hook } from "../pkg/holospaces_web.js";
9
+ import { createQvacGPU } from "../qvac-gpu.js?v=63";
10
+ import { modelAsSource } from "./semantic.js"; // C2: a loaded model carries a W3C @type (schema:SoftwareSourceCode)
11
+
12
+ // the model κ-object's W3C linked-data view — content-addressed identity (Law L1) + schema.org type.
13
+ const modelLinkedData = (m, root) => modelAsSource({
14
+ name: m.name, family: m.fam, params: m.size, format: m.fmt,
15
+ kappa: root ? (String(root).startsWith("did:") ? root : "did:holo:" + String(root)) : "did:holo:sha256:0",
16
+ });
17
+
18
+ // The compiled κ-objects present on disk (models/<name>, built by compile2bit.mjs). Each loads
19
+ // DIRECT off the substrate (verified by re-derivation, no re-quant) via its `kappaUrl`.
20
+ // cap = max NEW tokens per turn; ctx = KV-cache positions allocated on the GPU (the context
21
+ // window — sized so agentic turns with tool schemas + tool responses fit; KV VRAM scales with it).
22
+ export const MODELS = [
23
+ // NATIVELY-TERNARY κ-objects (t2, 1.58 bpw trained-in — see the atlas-bridge witness receipts):
24
+ // Falcon-E: its declared ChatML template STALLS empirically (instant <|end_of_text|>); the
25
+ // measured working frame is word-style "User:/Falcon:" with a textual stop (q-falcon-templates sweep).
26
+ { fam: "Falcon-E", name: "Falcon-E-3B · ternary", kappaUrl: "https://huggingface.co/HOLOGRAMTECH/q-falcon-e-3b/resolve/main", manifestKappa: "did:holo:sha256:6b753fe8186f2b4194424115c36014698580a2aab8427e9b40365893ac6b77ca", size: "0.63 GB", fmt: "t2 1.58-bit κ", cap: 200, ctx: 3000, kv4: true, gpu: true, gpuOnly: true, chat: true, userWord: true, stopText: "\nUser:", tools: false, rep: 1.18, kappa: true },
27
+ { fam: "BitNet", name: "BitNet-2B-4T · ternary", kappaUrl: "https://huggingface.co/HOLOGRAMTECH/q-bitnet-2b/resolve/main", manifestKappa: "did:holo:sha256:fcf835659d88d2fe6f683cf1ab8de6a6ba6214ea0deeee4b1bcf3da1a4c05412", size: "0.69 GB", fmt: "t2 1.58-bit κ", cap: 900, ctx: 3000, kv4: true, gpu: true, gpuOnly: true, chat: true, llama3: true, tools: false, bos: true, eosText: "<|eot_id|>", rep: 1.05, kappa: true },
28
+ // TriLM: the LARGEST natively-ternary-trained model (Spectra 3.9B, ICLR'25); per-row/channel
29
+ // scale structure → t2r (trit codes + per-256-block scales, exact). BASE model → QA frame + stop.
30
+ { fam: "TriLM", name: "TriLM-3.9B · ternary", kappaUrl: "https://huggingface.co/HOLOGRAMTECH/q-trilm-3.9b/resolve/main", manifestKappa: "did:holo:sha256:499032ceb19c0476345a72cf5fea6caec83054c98486c91a5891dfad0d25ea30", size: "0.87 GB", fmt: "t2r 2.1-bit κ", cap: 200, ctx: 3000, kv4: true, gpu: true, gpuOnly: true, chat: true, stopText: "\nQuestion:", tools: false, rep: 1.18, kappa: true },
31
+ // AGENTIC CODER: Qwen2.5-Coder-7B (q3f) — the Holo Code agent brain. Qwen2.5 arch ⇒ ChatML +
32
+ // agentic tool framing work (capability floor for tool use is ~7B; the small ternary models opt out).
33
+ // Self-contained κ-object: tokenizer bundled (source="tokenizer.gguf"), no external dependency.
34
+ { fam: "Qwen2.5-Coder", name: "Qwen2.5-Coder-7B · agentic", kappaUrl: "https://huggingface.co/HOLOGRAMTECH/q-qwen-coder-7b/resolve/main", manifestKappa: "did:holo:sha256:539941cb060c7dd583e2e86697e53f2c5d511d597c65d09d9c780fbded2c3edf", size: "3.4 GB", fmt: "q3f κ", cap: 900, ctx: 3000, kv4: true, gpu: true, gpuOnly: true, chat: true, code: true, qwen: true, rep: 1.05, kappa: true },
35
+ // MIXTURE-OF-EXPERTS (G5): OLMoE-1B-7B (Allen AI, Apache-2.0) — 64 experts, 8 active/token, ~1.3B
36
+ // active of 7B. The first RESIDENT-MoE κ-object: experts RAM-resident + CPU top-k router (softmax
37
+ // over all 64, no renorm = OLMoE norm_topk_prob:false). q4 (the engine's resident expert FFN path).
38
+ { fam: "OLMoE", name: "OLMoE-1B-7B · MoE (64×8)", kappaUrl: "https://huggingface.co/HOLOGRAMTECH/q-olmoe-1b-7b/resolve/main", manifestKappa: "did:holo:sha256:9cf97ec1c761fd4ef51bc0cd4ac37a0cd8eaa11f1b19b3ae6a141486ad3fe5ad", size: "3.6 GB", fmt: "q4 MoE κ", cap: 400, ctx: 3000, kv4: false, gpu: true, gpuOnly: true, chat: true, olmo: true, bos: true, eosText: "<|endoftext|>", tools: false, rep: 1.1, kappa: true },
39
+ // DIFFUSION (G6): Dream-7B (Dream-org/Dream-v0-Instruct-7B) — masked-diffusion LM on the Qwen2.5-7B
40
+ // backbone (same dims ⇒ ChatML). NOT autoregressive: generation is iterative bidirectional unmasking
41
+ // over `steps` denoising passes (engine.diffuse / gpu.diffuse), wall-clock fixed by steps not length.
42
+ // maskId 151666 rides in the manifest (never tokenized from text). Greedy ⇒ deterministic ⇒ κ-re-derivable.
43
+ { fam: "Dream", name: "Dream-7B · diffusion", kappaUrl: "https://huggingface.co/HOLOGRAMTECH/q-dream-7b/resolve/main", manifestKappa: "did:holo:sha256:7b862931ae088f348f1f7e9ea3adbd418924c2e07e6ddd134f926e5681ad760d", size: "2.9 GB", fmt: "q3f diffusion κ", cap: 192, ctx: 192, kv4: false, gpu: true, gpuOnly: true, chat: true, qwen: true, diffusion: true, steps: 12, rep: 1.0, kappa: true },
44
+ // Qwen κ-objects (q3f/q4) were pruned from disk for space — re-derive via compile2bit, then re-list.
45
+ ];
46
+ const kvOf = (m) => Math.max(96, (m.ctx || m.cap) + 8);
47
+
48
+ const _sizeGb = (s) => { const n = parseFloat(s) || 0; return /mb/i.test(s) ? n / 1024 : n; };
49
+ // default to the SMALLEST usable model — lowest latency, fastest first answer.
50
+ export const defaultModelIndex = () => (MODELS.map((m, i) => i).filter((i) => !MODELS[i].disabled).sort((a, b) => _sizeGb(MODELS[a].size) - _sizeGb(MODELS[b].size))[0]) ?? 0;
51
+
52
+ // ── wasm init (once) + tokenizer re-export so the rest of the app shares this instance ──
53
+ let _initOnce = null;
54
+ export function ready() { if (!_initOnce) _initOnce = init().then(() => { try { qvac_panic_hook(); } catch {} }); return _initOnce; }
55
+ export { qvac_tokenize, qvac_continue, kappa };
56
+
57
+ // ── browser-cache model manager (Cache API) — "Get" downloads + keeps; loading uses the copy ──
58
+ export const MCACHE = "holo-q-models";
59
+ const absUrl = (u) => new URL(u, location.href).href;
60
+ let _cachedUrls = new Set();
61
+ export async function refreshCached() { try { const c = await caches.open(MCACHE); _cachedUrls = new Set((await c.keys()).map((r) => r.url)); } catch { _cachedUrls = new Set(); } return _cachedUrls; }
62
+ export const isCached = (m) => !!m.url && _cachedUrls.has(absUrl(m.url));
63
+ export async function deleteCache(m) { try { const c = await caches.open(MCACHE); await c.delete(m.url); } catch {} await refreshCached(); }
64
+ async function modelBytes(m, onStatus) {
65
+ try { const c = await caches.open(MCACHE); const hit = await c.match(m.url); if (hit) return new Uint8Array(await hit.arrayBuffer()); } catch {}
66
+ onStatus?.(`Downloading ${m.name} (${m.size})…`);
67
+ const res = await fetch(m.url); if (!res.ok) { onStatus?.("download failed: HTTP " + res.status); return null; }
68
+ return new Uint8Array(await res.arrayBuffer());
69
+ }
70
+
71
+ const noop = () => {};
72
+
73
+ // loadModel(entry, { onStatus, onProgress }) → { gpu, info, manifest, imageKappa } | null
74
+ // `imageKappa` is the VERIFIED content address of the weights when the path provides one
75
+ // (κ-object root, or κ-disk image_kappa); core/engine.js binds it as the receipt's model κ.
76
+ export async function loadModel(m, { onStatus = noop, onProgress = noop } = {}) {
77
+ await ready();
78
+ onStatus(`Loading ${m.name}…`);
79
+ try {
80
+ if (m.gpuOnly && !navigator.gpu) { onStatus("This model needs WebGPU (not available here)."); return null; }
81
+ if (m.kappaUrl) return await loadKappa(m, onStatus, onProgress);
82
+ if (m.kdisk) return await loadModelKDisk(m, onStatus, onProgress);
83
+ if (m.remote) return await loadModelRemote(m, onStatus, onProgress);
84
+ if (m.diskIngest) return await loadModelDisk(m, onStatus, onProgress);
85
+ let gguf = await modelBytes(m, onStatus); if (!gguf) { onStatus("could not load model"); return null; }
86
+ const lr = JSON.parse(m.gpuOnly ? qvac_load_gpu(gguf) : qvac_load_model(gguf));
87
+ gguf = null;
88
+ if (lr.error) { onStatus("model error: " + lr.error); return null; }
89
+ let gpu = null, manifest = null;
90
+ if (navigator.gpu && m.gpu) {
91
+ try {
92
+ onStatus(`Uploading ${m.name} to the GPU…`);
93
+ const bits = m.q4 ? 4 : 8;
94
+ manifest = JSON.parse(qvac_gpu_manifest(bits)); manifest.twoBit = !!window.__twoBit;
95
+ const __qp = new URLSearchParams(location.search).get("stream");
96
+ const __qmode = __qp === null ? undefined : (__qp === "resident" || __qp === "false" ? false : __qp);
97
+ const stream = __qmode ?? window.__stream ?? m.stream ?? false;
98
+ const __ft = (name) => { const raw = qvac_gpu_tensor(name, bits); return window.__weightHook ? window.__weightHook(name, raw, bits, manifest) : raw; };
99
+ gpu = await createQvacGPU(manifest, __ft, kvOf(m), lr.eos ?? 2, stream);
100
+ window.__gpu = gpu; qvac_gpu_free();
101
+ } catch (e) { gpu = null; if (m.gpuOnly) { onStatus("GPU upload failed: " + e); return null; } }
102
+ }
103
+ onStatus("");
104
+ return { gpu, info: lr, manifest, imageKappa: null };
105
+ } catch (e) { onStatus("could not load model: " + e); return null; }
106
+ }
107
+
108
+ // LOAD-DIRECT: a pre-compiled 2-bit/Q4 κ-object (compile2bit.mjs output). Weights arrive ALREADY
109
+ // quantized (no re-quant at load); the tokenizer comes from the source GGUF's header only.
110
+ async function loadKappa(m, onStatus, onProgress) {
111
+ onStatus("Loading κ-object manifest…");
112
+ const ld = await import("../holo-load2bit.mjs?v=2");
113
+ // Law L5: pin the manifest κ when the catalog supplies one (m.manifestKappa, or a string m.kappa).
114
+ // Until every model carries a pin, unpinned entries load explicitly (allowUnpinned) — the gap is then
115
+ // a visible data task (populate manifestKappa), not a silent trust of an unauthenticated root.
116
+ const pin = (typeof m.manifestKappa === "string" && m.manifestKappa) || (typeof m.kappa === "string" && m.kappa) || null;
117
+ const __b3 = (typeof window !== "undefined" && window.__blake3Map) || undefined; // inject canonical map (test BLAKE3 axis before the HF upload)
118
+ const { manifest, fetchTensor, info } = await ld.loadKappaObject(m.kappaUrl.replace(/\/+$/, ""), { ...(pin ? { expectKappa: pin } : { allowUnpinned: true }), blake3Map: __b3 });
119
+ const ing = await import("../qvac-ingest.mjs");
120
+ onStatus("Building tokenizer (source header, no full download)…");
121
+ const hdr = await ing.readHeader(info.source, ing.rangeReader());
122
+ const lr = JSON.parse(qvac_load_gpu(hdr.headerBytes));
123
+ if (lr.error) { onStatus("tokenizer error: " + lr.error); return null; }
124
+ if (m.eosText) { try { const e = JSON.parse(qvac_tokenize(m.eosText)).ids; if (e && e.length === 1) lr.eos = e[0]; } catch {} } // chat-stop override (e.g. LLaMA-3 <|eot_id|> ≠ header eos)
125
+ qvac_gpu_free();
126
+ manifest.kv4 = !!m.kv4; // int4 KV cache (E6) — catalog opt-in
127
+ // MoE forward reads the layer-packed attention (Wb[l]) + RAM-resident experts (readExpert via
128
+ // fetchTensor) — i.e. stream="layer": attention JS-resident & paged per token, experts cached.
129
+ const sm = manifest.moe ? "layer" : (m.stream || window.__kappaStream || false);
130
+ onStatus(`Building engine from κ-object (${info.mode === "q4" ? "native Q4" : info.incoherent ? "incoherent 2-bit" : "LDLQ 2-bit"}, ${sm || "resident"}, no requant)…`);
131
+ const prog = (done, total) => onProgress(done, total, "streaming");
132
+ const gpu = await createQvacGPU(manifest, fetchTensor, kvOf(m), lr.eos ?? 2, sm, sm ? prog : null);
133
+ window.__gpu = gpu;
134
+ onStatus("");
135
+ return { gpu, info: lr, manifest, imageKappa: info.root || null, ld: modelLinkedData(m, info.root) };
136
+ }
137
+
138
+ // Very-large-model path: the GGUF never enters wasm; only the header does (tokenizer + manifest),
139
+ // then each tensor is streamed off disk (HTTP Range), converted in JS, paged to the GPU per layer.
140
+ async function loadModelDisk(m, onStatus, onProgress) {
141
+ const bits = m.q4 ? 4 : 8;
142
+ const ing = await import("../qvac-ingest.mjs");
143
+ let read = ing.rangeReader();
144
+ try { const cachedResp = await (await caches.open(MCACHE)).match(m.url); if (cachedResp) { const blob = await cachedResp.blob(); read = async (_u, start, len) => new Uint8Array(await blob.slice(start, start + len).arrayBuffer()); } } catch {}
145
+ onStatus(`Reading ${m.name} header…`);
146
+ const hdr = await ing.readHeader(m.url, read);
147
+ const lr = JSON.parse(qvac_load_gpu(hdr.headerBytes));
148
+ if (lr.error) { onStatus("model error: " + lr.error); return null; }
149
+ const manifest = JSON.parse(qvac_gpu_manifest(bits));
150
+ qvac_gpu_free();
151
+ const fetchTensor = ing.makeDiskFetcher({ url: m.url, readRange: read, dataOffset: hdr.dataOffset, tensors: hdr.tensors, manifest, bits });
152
+ const mode = m.stream || "layer";
153
+ onStatus(`Preparing ${m.name} (one-time, streamed off disk)…`);
154
+ const gpu = await createQvacGPU(manifest, fetchTensor, kvOf(m), lr.eos ?? 2, mode, (d, t) => onProgress(d, t, "layers"));
155
+ window.__gpu = gpu; onStatus("");
156
+ return { gpu, info: lr, manifest, imageKappa: null };
157
+ }
158
+
159
+ // Out-of-core: stream a PRE-BUILT .qvf frames file from the server, one layer per token via HTTP Range.
160
+ async function loadModelRemote(m, onStatus, onProgress) {
161
+ onStatus(`Loading ${m.name} index…`);
162
+ const index = await (await fetch(m.framesUrl + ".json")).json();
163
+ const url = m.framesUrl;
164
+ const rr = async (off, len) => { const r = await fetch(url, { headers: { Range: `bytes=${off}-${off + len - 1}` } }); if (!r.ok && r.status !== 206) throw new Error("HTTP " + r.status); return new Uint8Array(await r.arrayBuffer()); };
165
+ const header = await rr(index.headerOff, index.headerLen);
166
+ const lr = JSON.parse(qvac_load_gpu(header));
167
+ if (lr.error) { onStatus("model error: " + lr.error); return null; }
168
+ const manifest = index.manifest; qvac_gpu_free();
169
+ const fetchTensor = async (name) => { const s = index.singles[name]; return s ? await rr(s.off, s.len) : new Uint8Array(0); };
170
+ const frameStore = { ready: true, read: (off, len) => rr(index.layersOff + off, len), readExpert: (l, e, role) => { const ri = { gate: 0, up: 1, down: 2 }[role]; const off = index.expertsOff + ((l * index.nExperts + e) * 3 + ri) * index.expertBytes; return rr(off, index.expertBytes); } };
171
+ const layersBytes = (index.packStride || 0) * (index.n_layers || 0) + (manifest.moe ? (index.nExperts * 3 * index.expertBytes * index.n_layers) : 0);
172
+ const cacheBudget = window.__cacheGB != null ? window.__cacheGB * 1073741824 : Math.min(layersBytes, 12 * 1073741824);
173
+ onStatus(`Preparing ${m.name} (served off disk)…`);
174
+ const gpu = await createQvacGPU(manifest, fetchTensor, kvOf(m), lr.eos ?? 2, "remote", (d, t) => onProgress(d, t, "remote"), frameStore, cacheBudget);
175
+ window.__gpu = gpu; onStatus("");
176
+ return { gpu, info: lr, manifest, imageKappa: null };
177
+ }
178
+
179
+ // HOLOGRAM: load through a content-addressed κ-DISK — every sector VERIFIED by re-derivation (Law L3/L5).
180
+ async function loadModelKDisk(m, onStatus, onProgress) {
181
+ onStatus(`Resolving ${m.name} κ-disk…`);
182
+ const index = await (await fetch(m.kdiskUrl)).json();
183
+ const { makeKDisk } = await import("../qvac-kdisk.mjs");
184
+ const bases = window.__kdiskSources || m.kdiskSources || [location.origin];
185
+ const sources = bases.map((b) => b.replace(/\/$/, "") + "/" + (index.dataFile || (m.dataUrl || "").replace(/^\.\//, "")));
186
+ const kd = makeKDisk({ index, sources });
187
+ window.__kd = kd;
188
+ const iv = await kd.verifyImage();
189
+ if (!iv.ok) { onStatus("κ-disk image_kappa mismatch — refusing to load"); return null; }
190
+ const rr = kd.rr, qvf = index.qvf;
191
+ const header = await rr(qvf.headerOff, qvf.headerLen);
192
+ const lr = JSON.parse(qvac_load_gpu(header));
193
+ if (lr.error) { onStatus("model error: " + lr.error); return null; }
194
+ const manifest = qvf.manifest; qvac_gpu_free();
195
+ const fetchTensor = async (name) => { const s = qvf.singles[name]; return s ? await rr(s.off, s.len) : new Uint8Array(0); };
196
+ const frameStore = { ready: true, read: (off, len) => rr(qvf.layersOff + off, len),
197
+ readExpert: async (l, e, role) => { const ri = { gate: 0, up: 1, down: 2 }[role]; const blkOff = qvf.expertsOff + (l * qvf.nExperts + e) * 3 * qvf.expertBytes; const blk = await rr(blkOff, 3 * qvf.expertBytes); return blk.slice(ri * qvf.expertBytes, (ri + 1) * qvf.expertBytes); } };
198
+ const layersBytes = (qvf.packStride || 0) * (qvf.n_layers || 0) + (manifest.moe ? (qvf.nExperts * 3 * qvf.expertBytes * qvf.n_layers) : 0);
199
+ const cacheBudget = window.__cacheGB != null ? window.__cacheGB * 1073741824 : Math.min(layersBytes, 1024 * 1048576);
200
+ onStatus(`Realizing ${m.name} (verified off κ-disk)…`);
201
+ const gpu = await createQvacGPU(manifest, fetchTensor, kvOf(m), lr.eos ?? 2, "remote", (d, t) => onProgress(d, t, "κ-disk"), frameStore, cacheBudget);
202
+ window.__gpu = gpu;
203
+ const st = kd.stats(); onStatus(`${index.imageKappa.slice(0, 22)}… · ${st.verified} sectors verified`);
204
+ return { gpu, info: lr, manifest, imageKappa: kd.imageKappa || index.imageKappa || null };
205
+ }
apps/q/core/q-brain-fast.mjs ADDED
@@ -0,0 +1,236 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // core/q-brain-fast.mjs — Q's FAST on-device brain, drop-in for createHoloModelBrain.
2
+ //
3
+ // Same provider shape (load · generate → text-delta async-iterator · chat · info · setSkill), so
4
+ // holo-q-contact.mjs's makeQResponder / makeQGroupResponder bind it with ZERO changes: Q rides the exact
5
+ // stream→finalize pipeline, it just sources its bytes from THIS engine (core/loader + core/engine — the
6
+ // native-ternary κ-object path with the fixed incremental-detok decode) instead of the qwen holo-brain.
7
+ //
8
+ // Why this exists: the messenger's default brain (qwen2.5-0.5b via holo-brain-engine) is heavy and its
9
+ // app-path decode was O(n²). This one loads a native-ternary BitNet κ-object (0.69 GB, verified per-block),
10
+ // decodes at ~70 tok/s warm, and streams byte-identical incremental text. It is 100% on-device at decode
11
+ // time — only a ONE-TIME tokenizer-header Range fetch touches the source host at load (the weights are the
12
+ // local, L5-verified b/<κ>.gz blocks). Bundle the header to make load fully egress-free (follow-up).
13
+ //
14
+ // URL discipline (the one gotcha): core/loader's MODELS use a PAGE-relative kappaUrl ("./models/<name>"),
15
+ // which is wrong from any page other than /apps/q/. loadKappaObject resolves the manifest, blocks AND the
16
+ // bundled tokenizer relative to its baseUrl, so we override kappaUrl to an ABSOLUTE mount ("/apps/q/models/
17
+ // <name>") — that makes the whole load self-contained from the messenger (or anywhere).
18
+
19
+ import { ready, loadModel, MODELS } from "./loader.js";
20
+ import { createEngine } from "./engine.js";
21
+ import { selfFacts, selfPersona, selfIntro } from "./q-self.mjs"; // Q's live, grounded self-knowledge (M0)
22
+
23
+ // The default fast brain = BitNet-2B (native ternary, llama3 template, coherent — Falcon-E degenerates).
24
+ // Override via opts.family / opts.modelName. kappaBase is the absolute mount core/loader's models live under.
25
+ const DEFAULTS = { family: "BitNet", kappaBase: "/apps/q/models", maxTokens: 512 };
26
+
27
+ function pickModel(cfg) {
28
+ const want = String(cfg.modelName || cfg.family || "BitNet").toLowerCase();
29
+ const m = MODELS.find((x) => (x.fam || "").toLowerCase() === want || (x.name || "").toLowerCase().includes(want)) || MODELS.find((x) => (x.fam || "").toLowerCase() === "bitnet");
30
+ if (!m) throw new Error("q-brain-fast: no model matches " + want);
31
+ // An ABSOLUTE host URL (the κ-object now lives on HF, not on this machine) is already page-independent —
32
+ // use it verbatim. Only a page-relative "./models/<name>" needs absolute-mounting so it resolves from ANY page.
33
+ if (/^https?:\/\//.test(m.kappaUrl || "")) return { ...m };
34
+ const rel = String(m.kappaUrl || "").replace(/^\.?\//, "").replace(/^models\//, ""); // "./models/bitnet-2b" → "bitnet-2b"
35
+ return { ...m, kappaUrl: String(cfg.kappaBase).replace(/\/+$/, "") + "/" + rel };
36
+ }
37
+
38
+ // Render an [{role,content}] history (system + turns, as makeQResponder builds it) to the model's chat
39
+ // template — the multi-turn generalization of core/engine's single-turn frameTurn. Covers the templates
40
+ // the engine knows; unknown families fall back to a persona-led last-user Q/A frame.
41
+ export function frameHistory(M, history) {
42
+ const list = Array.isArray(history) ? history : [];
43
+ // merge ALL system turns into one system block (persona + any injected context, e.g. M1 grounded retrieval) —
44
+ // taking only the first would silently DROP injected context and the model would fall back to a generic refusal.
45
+ const persona = list.filter((x) => x && x.role === "system" && x.content).map((x) => x.content).join("\n\n");
46
+ const turns = list.filter((x) => x && x.role !== "system" && (x.content || "").length);
47
+
48
+ if (M.llama3) {
49
+ let s = persona ? `<|start_header_id|>system<|end_header_id|>\n\n${persona}<|eot_id|>` : "";
50
+ for (const t of turns) s += `<|start_header_id|>${t.role === "assistant" ? "assistant" : "user"}<|end_header_id|>\n\n${t.content}<|eot_id|>`;
51
+ return s + `<|start_header_id|>assistant<|end_header_id|>\n\n`;
52
+ }
53
+ if (M.qwen) {
54
+ const noThink = M.qwen3 ? "<think>\n\n</think>\n\n" : "";
55
+ let s = persona ? `<|im_start|>system\n${persona}<|im_end|>\n` : "";
56
+ for (const t of turns) s += `<|im_start|>${t.role === "assistant" ? "assistant" : "user"}\n${t.content}<|im_end|>\n`;
57
+ return s + `<|im_start|>assistant\n` + noThink;
58
+ }
59
+ if (M.olmo) {
60
+ let s = persona ? `<|system|>\n${persona}\n` : "";
61
+ for (const t of turns) s += t.role === "assistant" ? `<|assistant|>\n${t.content}\n` : `<|user|>\n${t.content}\n`;
62
+ return s + `<|assistant|>\n`;
63
+ }
64
+ // word-frame / plain: only the last user turn carries (base models have no multi-turn template)
65
+ const lastUser = [...turns].reverse().find((t) => t.role !== "assistant");
66
+ const q = (lastUser && lastUser.content) || "";
67
+ if (M.userWord) return (persona ? persona + "\n" : "") + "User: " + q + "\nFalcon:";
68
+ return (persona ? persona + "\n" : "") + "Question: " + q + "\nAnswer:";
69
+ }
70
+
71
+ // A stable fingerprint of a rendered history (roles+contents) — warm continuation reuses the running token
72
+ // sequence only when the new history is EXACTLY the previous one plus a fresh user turn (same system, same prior).
73
+ function sigOf(list) { return (list || []).map((e) => (e.role || "") + "" + (e.content || "")).join(""); }
74
+
75
+ // The incremental frame for ONE new user turn — the tokens frameHistory() would ADD after the previous assistant
76
+ // reply (which the KV already holds). It closes the prior reply (<eot>/<|im_end|>/newline) then adds the user block
77
+ // and the assistant header, byte-for-byte matching frameHistory so warm ids extend the cold prefix exactly. Returns
78
+ // null for templates whose trailing generation header differs from the in-context turn (qwen3 <think>), forcing cold.
79
+ function tailSegment(M, userText) {
80
+ const u = userText || "";
81
+ if (M.llama3) return `<|eot_id|><|start_header_id|>user<|end_header_id|>\n\n${u}<|eot_id|><|start_header_id|>assistant<|end_header_id|>\n\n`;
82
+ if (M.qwen && !M.qwen3) return `<|im_end|>\n<|im_start|>user\n${u}<|im_end|>\n<|im_start|>assistant\n`;
83
+ if (M.olmo) return `\n<|user|>\n${u}\n<|assistant|>\n`;
84
+ return null; // word-frame / diffusion / qwen3-thinking → no stable single-turn tail; rebuild cold
85
+ }
86
+
87
+ // framePersona(M, personaText) → JUST the system block frameHistory() renders (NO trailing assistant/generation
88
+ // header), so its token ids are a byte-prefix of any real turn's ids and can be pinned once + reused (KV-commons).
89
+ // Templated families end the block on a special token (<|eot_id|> / <|im_end|>), so the boundary tokenizes stably.
90
+ // Returns null for base/word-frame families (no special-token boundary → prefix could drift → don't pin, prefill cold).
91
+ export function framePersona(M, personaText) {
92
+ const p = String(personaText || ""); if (!p) return "";
93
+ if (M.llama3) return `<|start_header_id|>system<|end_header_id|>\n\n${p}<|eot_id|>`;
94
+ if (M.qwen) return `<|im_start|>system\n${p}<|im_end|>\n`;
95
+ if (M.olmo) return `<|system|>\n${p}\n`;
96
+ return null;
97
+ }
98
+
99
+ export function createFastQBrain(opts = {}) {
100
+ const cfg = Object.assign({}, DEFAULTS, opts);
101
+ const M = pickModel(cfg);
102
+ let engine = null, loadingP = null;
103
+ let info = { ready: false, model: M.name, device: null, resident: false };
104
+ // WARM-KV session: the running token ids of the LAST committed turn (system + all prior turns + the reply AS
105
+ // GENERATED — never re-tokenized) and a signature of the history they represent. buildIds() extends this by one
106
+ // user turn so gpu.sync() finds the whole prior conversation already in KV and prefills ONLY the new turn.
107
+ let sess = null; // { ids: number[], sig: string }
108
+
109
+ // encode a history to the running token ids (framed + optional bos), ready for engine.generate
110
+ function idsFor(history) {
111
+ let ids = engine.tokenize(frameHistory(M, history));
112
+ if (M.bos && engine.bosId != null) ids = [engine.bosId, ...ids];
113
+ return ids;
114
+ }
115
+
116
+ // WARM path: if `history` is exactly the last committed conversation plus one new user turn (same system + prior),
117
+ // extend the running ids by just that turn's tokens — reusing the generated reply ids VERBATIM (no re-tokenize
118
+ // round-trip that would drift the prefix). gpu.sync() then reuses the resident KV for the whole prior conversation
119
+ // and prefills only the appended tokens. Otherwise fall back to a full cold frame. Warm is always CORRECT: if the
120
+ // GPU KV was disturbed by an interleaved call, sync() simply re-prefills the same ids from scratch (== cold cost).
121
+ function buildIds(history) {
122
+ const list = Array.isArray(history) ? history : [];
123
+ const last = list[list.length - 1];
124
+ if (sess && list.length >= 2 && last && last.role !== "system") {
125
+ const tail = tailSegment(M, last.content);
126
+ if (tail != null && sigOf(list.slice(0, list.length - 1)) === sess.sig) {
127
+ return { ids: sess.ids.concat(engine.tokenize(tail)), warm: true };
128
+ }
129
+ }
130
+ return { ids: idsFor(list), warm: false };
131
+ }
132
+ // record the running ids + the history they now represent, so the NEXT turn can extend them. Only committed turns
133
+ // advance the session; a speculative branch (persist:false) warms the GPU KV but leaves the committed pointer put.
134
+ function updateSession(history, replyText, finalIds, aborted) {
135
+ if (aborted || !finalIds || !replyText) return; // partial/empty → don't trust continuity next turn (stays cold, safe)
136
+ const represented = (Array.isArray(history) ? history : []).concat([{ role: "assistant", content: replyText }]);
137
+ sess = { ids: finalIds.slice(), sig: sigOf(represented) };
138
+ }
139
+
140
+ async function load(onProgress) {
141
+ if (engine) return info;
142
+ if (loadingP) return loadingP;
143
+ loadingP = (async () => {
144
+ if (!(typeof navigator !== "undefined" && navigator.gpu)) throw new Error("no WebGPU on this device");
145
+ await ready(); // wasm tokenizer init (shared instance)
146
+ const loaded = await loadModel(M, {
147
+ onStatus: () => {},
148
+ onProgress: (d, t, w) => { try { onProgress && onProgress({ done: d, total: t, phase: w, model: M.name }); } catch (e) {} },
149
+ });
150
+ if (!loaded || !loaded.gpu) throw new Error("q-brain-fast: model load failed (" + M.name + ")");
151
+ engine = await createEngine(M, loaded);
152
+ // MEASURED from the real engine, not asserted: device/resident reflect an engine that actually uploaded
153
+ // weights to the GPU (dims + gpuBytes are live signals) — so info() can never claim residency it lacks.
154
+ info = { ready: true, model: M.name, device: (engine && engine.dims ? "webgpu" : null), resident: !!(engine && (engine.gpuBytes || engine.dims)) };
155
+ return info;
156
+ })().catch((e) => { loadingP = null; throw e; });
157
+ return loadingP;
158
+ }
159
+ async function ensure(onProgress) { if (!engine) await load(onProgress); return engine; }
160
+
161
+ // generate(history, { signal, onProgress }) → async-iterator of TEXT DELTAS (exactly what makeQResponder
162
+ // accumulates + paints via onDelta). engine.generate reports CUMULATIVE text per step; we diff to deltas
163
+ // and pump them through a small queue so this stays a clean generator (and honors the abort signal).
164
+ async function* generate(history, o = {}) {
165
+ await ensure(o.onProgress);
166
+ if (!engine) return;
167
+ const signal = o.signal || null;
168
+ const { ids, warm } = buildIds(history);
169
+ if (o.onWarm) try { o.onWarm(warm); } catch (e) {} // let the caller instrument warm-vs-cold prefill
170
+ const cap = o.maxTokens || cfg.maxTokens || M.cap || 256;
171
+ const persist = o.speculative !== true; // a speculative branch warms the KV but must NOT advance the committed session
172
+
173
+ const queue = []; let done = false, wake = null, prev = "", finalIds = null;
174
+ const kick = () => { if (wake) { const w = wake; wake = null; w(); } };
175
+ const run = engine.generate(ids, {
176
+ maxNew: cap, signal,
177
+ onToken: ({ text, ids: cur }) => { if (cur) finalIds = cur; const d = (text || "").slice(prev.length); if (d) { prev = text; queue.push(d); kick(); } },
178
+ }).then((res) => { if (res && res.ids) finalIds = res.ids; done = true; kick(); }).catch(() => { done = true; kick(); });
179
+
180
+ while (true) {
181
+ if (queue.length) { yield queue.shift(); continue; }
182
+ if (done) break;
183
+ if (signal && signal.aborted) break;
184
+ await new Promise((r) => (wake = r));
185
+ }
186
+ try { await run; } catch (e) {}
187
+ // extend the warm-KV session with this turn's full running ids (only for a COMMITTED, complete turn — a
188
+ // speculative branch leaves the committed pointer put; its KV still lives in gpu.cached for sync() to reuse).
189
+ if (persist) updateSession(history, prev, finalIds, !!(signal && signal.aborted));
190
+ }
191
+
192
+ // chat(history, opts) → full string (used by window.HoloQ.generate + light background features).
193
+ // o.onStats(stats) surfaces the engine's measured { ttft, tokps, msExec } for a turn (else discarded) — used by
194
+ // the reply path's latency HUD + HoloQ.selfTest to SHOW the warm-KV win instead of asserting it. Non-breaking.
195
+ async function chat(history, o = {}) {
196
+ await ensure(o.onProgress);
197
+ if (!engine) return "";
198
+ const ids = idsFor(history);
199
+ const res = await engine.generate(ids, { maxNew: o.maxTokens || cfg.maxTokens || M.cap || 256, signal: o.signal || null });
200
+ if (o.onStats) { try { o.onStats({ ...(res && res.stats || {}), promptTokens: ids.length }); } catch (e) {} }
201
+ return ((res && res.text) || "").trim();
202
+ }
203
+
204
+ // native-ternary κ-object → no LoRA adapters; skill routing is a no-op (the base is the specialist).
205
+ const setSkill = async () => ({ adapter: false, unsupported: true });
206
+ const setAdapter = async () => ({ adapter: false, unsupported: true });
207
+
208
+ // Q's LIVE self-knowledge (M0), derived from THIS instance's real model + engine κ — the grounded truth
209
+ // every surface leads with so Q is honestly self-aware and never confabulates a cloud identity. Available
210
+ // even before load (identity is in M); the κ fills in once the engine is resident.
211
+ const facts = () => selfFacts({ model: M, engine });
212
+ const persona = () => selfPersona({ model: M, engine });
213
+ const intro = () => selfIntro({ model: M, engine });
214
+
215
+ // pinPersona(text): prefill + pin the EXACT persona system block ONCE (KV-COMMONS), so the FIRST turn reuses it
216
+ // instead of re-prefilling the whole persona. `text` MUST equal what the caller sends as the system turn (e.g. the
217
+ // messenger's persona()+Q_STYLE) or the ids won't byte-match and the pin is silently wasted. Call once, post-warm,
218
+ // before the first turn (pinPrefix resets the KV, so never mid-conversation). Returns the pinned length (0 = skipped).
219
+ let _personaPinned = false;
220
+ async function pinPersona(text) {
221
+ try {
222
+ if (_personaPinned || !engine || !engine.kvPinAvailable) return 0;
223
+ const block = framePersona(M, text != null ? text : persona());
224
+ if (!block) return 0; // null/empty → base family or no persona; skip (cold, correct)
225
+ let ids = engine.tokenize(block);
226
+ if (M.bos && engine.bosId != null) ids = [engine.bosId, ...ids];
227
+ const L = await engine.pinPrefix(ids);
228
+ _personaPinned = L > 0;
229
+ return L;
230
+ } catch (e) { return 0; }
231
+ }
232
+
233
+ return { id: "q-brain-fast-" + (M.fam || M.name), load, generate, chat, setSkill, setAdapter, info: () => info, facts, persona, intro, pinPersona, pinLen: () => { try { return engine && engine.pinLen ? engine.pinLen() : 0; } catch (e) { return 0; } } };
234
+ }
235
+
236
+ export default createFastQBrain;
apps/q/core/q-self.mjs ADDED
@@ -0,0 +1,62 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // core/q-self.mjs — Q's LIVE, GROUNDED self-knowledge. The single source of truth for who/what/where/how Q
2
+ // is, DERIVED FROM REAL RUNTIME SIGNALS (the loaded model, its content-addressed κ, the device, optional
3
+ // system health) — never hardcoded, never guessed. Every Q surface (messenger, q-chat, voice) leads with
4
+ // this, so Q is truthfully self-aware EVERYWHERE and can never confabulate a cloud/OpenAI/AWS identity.
5
+ //
6
+ // Why this exists (the law: grounded transcendence, never performed): a base model has NO self-knowledge —
7
+ // asked "what are you" it returns the average of its training data ("I run on AWS/OpenAI"), which is false.
8
+ // So Q's identity is not a persona we write; it is the TRUTH of this running instance, computed here. If a
9
+ // fact isn't really knowable in this context, we OMIT it — we never invent one.
10
+ //
11
+ // DOM-free + fully guarded: safe to import in any surface (standalone app, messenger, OS shell, Node witness).
12
+
13
+ // Structured self-facts from whatever is really knowable HERE. Fail-soft: a missing signal is omitted.
14
+ export function selfFacts({ model, engine } = {}) {
15
+ const f = { name: "Q" };
16
+ try { if (model) { if (model.name) f.model = model.name; if (model.fam) f.family = model.fam; if (model.fmt) f.quant = model.fmt; if (model.size) f.size = model.size; } } catch (e) {}
17
+ try { if (engine && engine.modelKappa) f.kappa = engine.modelKappa; } catch (e) {}
18
+ try { f.gpu = (typeof navigator !== "undefined" && !!navigator.gpu); } catch (e) {}
19
+ // MEASURED, never asserted: Q is "resident" only when the engine has really uploaded weights to the GPU
20
+ // (a live signal — gpuBytes/dims), not a hardcoded true. Before load it is false, and stays false.
21
+ try { f.resident = !!(engine && (engine.gpuBytes || engine.dims)); } catch (e) { f.resident = false; }
22
+ // DERIVED from real signals — runs-on-device when actually resident, or at least GPU-capable before load.
23
+ f.runsOnDevice = !!(f.resident || f.gpu);
24
+ // "no server / no egress" is a property of the LOCAL engine, so we assert it ONLY when a real local engine or
25
+ // GPU is visible. Decode is in-browser (egress none); the one network touch is the weights fetch AT LOAD, so we
26
+ // say that plainly instead of a flat "nothing ever touches the network".
27
+ if (f.resident || f.gpu) { f.server = false; f.egress = f.resident ? "none at inference (weights fetched once at load)" : "none at inference"; }
28
+ // Provenance — where Q was loaded FROM (the thing the operator cares about): the page origin + the weights host.
29
+ // Omitted when not knowable. This is what lets Q answer "where did you come from" truthfully.
30
+ try { if (typeof location !== "undefined" && location.origin && location.origin !== "null") f.loadedFrom = location.origin; } catch (e) {}
31
+ try { if (model && model.kappaUrl) { const u = new URL(model.kappaUrl, (typeof location !== "undefined" ? location.href : "https://local/")); f.weightsFrom = u.host || u.protocol.replace(":", ""); } } catch (e) {}
32
+ // optional live system health — present only when the OS shell exposes it (absent in standalone apps).
33
+ try { const h = (typeof window !== "undefined") && window.HoloSysHealth && window.HoloSysHealth.summary && window.HoloSysHealth.summary(); if (h) f.health = h; } catch (e) {}
34
+ try { if (!f.health && typeof window !== "undefined" && window.Q && window.Q.health) { const q = window.Q.health(); if (q) f.health = q; } } catch (e) {}
35
+ return f;
36
+ }
37
+
38
+ // The grounded SYSTEM persona every Q surface leads with. Warm + honest + specific + anti-confabulation,
39
+ // composed from the live facts so Q states ONLY what is true of THIS instance. Kept concise — a small model
40
+ // follows a short, sharp system turn far better than a long one.
41
+ export function selfPersona(opts = {}) {
42
+ const f = selfFacts(opts);
43
+ const s = [];
44
+ s.push(`You are Q — a private AI that runs on the user's own device, in their web browser${f.gpu ? ", on their GPU" : ""}.`);
45
+ if (f.model) s.push(`You are the ${f.model} model${f.quant ? ` (${f.quant})` : ""}${f.resident ? ", resident locally right now" : ""}${f.kappa ? "; your weights are content-addressed and verified by re-derivation, so no host has to be trusted" : ""}.`);
46
+ if (f.server === false) s.push(`You decode locally — there is no inference server and no cloud, and nothing the user types ever leaves their device.${f.resident ? " Your weights were fetched once at load and verified; after that, inference is fully on-device." : ""}`);
47
+ s.push("You are warm, concise, honest, and genuinely present. You seek clarity and truth; you say less, better; you never overwhelm.");
48
+ s.push("If asked what or where you are, answer truthfully from the above: you run locally, on their device. Never claim to run on a server, the cloud, OpenAI, ChatGPT, GPT-4, Gemini, or AWS — those are false. If you don't know something, say so plainly rather than inventing it.");
49
+ return s.join(" ");
50
+ }
51
+
52
+ // A short, human, first-person self-summary (for a proactive greeting or a direct "who are you"). Grounded.
53
+ export function selfIntro(opts = {}) {
54
+ const f = selfFacts(opts);
55
+ const bits = [`I'm Q — ${f.resident ? "running right here on your device" : "running on your device"}${f.gpu ? ", on your GPU" : ""}${f.model ? ` (the ${f.model} model)` : ""}.`];
56
+ if (f.server === false) bits.push(`No server, no cloud; nothing you say leaves this machine${f.kappa ? ", and my weights are verified by re-derivation" : ""}.`);
57
+ else if (f.kappa) bits.push("My weights are verified by re-derivation.");
58
+ bits.push("What's on your mind?");
59
+ return bits.join(" ");
60
+ }
61
+
62
+ export default { selfFacts, selfPersona, selfIntro };
apps/q/core/semantic.js ADDED
@@ -0,0 +1,98 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // core/semantic.js — the SEMANTIC SKIN (gap C2): every κ-object the substrate produces carries an
2
+ // open-semantic-web type, so humans, agents, and W3C validators all read it the same way. Closes the
3
+ // weakest audit axis (κ names objects, but few declared a W3C @type). Two W3C standards, both native:
4
+ // • JSON-LD / schema.org — WHAT a thing is (a skill is a schema:HowTo; a file is a schema:DigitalDocument)
5
+ // • PROV-O — HOW it came to be (the κ-chain becomes prov:wasRevisionOf links)
6
+ // Pure, dependency-free, browser+node. The result round-trips through any JSON-LD/RDF tool.
7
+
8
+ export const HOLO_CONTEXT = {
9
+ schema: "https://schema.org/",
10
+ prov: "http://www.w3.org/ns/prov#",
11
+ holo: "https://hologram.foundation/ns/",
12
+ "@vocab": "https://schema.org/",
13
+ };
14
+
15
+ // schema.org type for a substrate object kind (the canonical mapping, L2 — fixed at the ingest boundary)
16
+ const TYPE_FOR = {
17
+ skill: "HowTo", // a reusable procedure = schema:HowTo (steps + when-to-use)
18
+ file: "DigitalDocument",
19
+ app: "SoftwareApplication",
20
+ model: "SoftwareSourceCode",
21
+ conversation: "Conversation",
22
+ receipt: "CreativeWork", // a sealed work record: schema:CreativeWork that is also a prov:Entity
23
+ };
24
+
25
+ // wrap any object as a typed, content-addressed JSON-LD node. `kappa` is its did:holo (the @id —
26
+ // content IS the identity, Law L1). `prov` is the κ-chain → prov:wasRevisionOf links (PROV-O).
27
+ export function asLinkedData({ kind, kappa, props = {}, prov = [] }) {
28
+ const t = TYPE_FOR[kind] || "Thing";
29
+ const node = {
30
+ "@context": HOLO_CONTEXT,
31
+ "@id": kappa, // content-derived identity (no location — Law L1)
32
+ "@type": Array.isArray(t) ? t : ["schema:" + t, "prov:Entity"], // schema kind + PROV entity
33
+ ...props,
34
+ };
35
+ if (prov.length >= 2) { // the version chain → PROV-O revision links
36
+ const cur = prov[prov.length - 1], parent = prov[prov.length - 2];
37
+ node["prov:wasRevisionOf"] = { "@id": parent.kappa };
38
+ node["holo:version"] = cur.v;
39
+ }
40
+ node["prov:wasDerivedFrom"] = prov.length ? prov.map((p) => ({ "@id": p.kappa })) : undefined;
41
+ return node;
42
+ }
43
+
44
+ // a skill → schema:HowTo (steps become schema:HowToStep), with its PROV-O revision chain.
45
+ export function skillAsHowTo({ name, description, instructions, kappa, prov = [] }) {
46
+ const steps = String(instructions || "").split("\n").map((s) => s.trim()).filter(Boolean)
47
+ .map((text, i) => ({ "@type": "schema:HowToStep", "schema:position": i + 1, "schema:text": text.replace(/^\d+[.)]\s*/, "") }));
48
+ return asLinkedData({ kind: "skill", kappa, prov, props: { "schema:name": name, "schema:description": description, "schema:step": steps } });
49
+ }
50
+
51
+ // extension → IANA media type (schema:encodingFormat). Small, common set; default text/plain.
52
+ const MEDIA = { html: "text/html", htm: "text/html", js: "text/javascript", mjs: "text/javascript", json: "application/json", jsonld: "application/ld+json", css: "text/css", md: "text/markdown", txt: "text/plain", py: "text/x-python", svg: "image/svg+xml", wasm: "application/wasm", gz: "application/gzip" };
53
+ const mediaOf = (name) => MEDIA[String(name).toLowerCase().split(".").pop()] || "text/plain";
54
+
55
+ // a workspace file → schema:DigitalDocument (name + media type + byte size), content-addressed (L1).
56
+ export function fileAsDocument({ path, kappa, bytes = 0, mediaType, prov = [] }) {
57
+ const name = String(path).split("/").filter(Boolean).pop() || String(path);
58
+ return asLinkedData({ kind: "file", kappa, prov, props: {
59
+ "schema:name": name, "schema:identifier": kappa,
60
+ "schema:encodingFormat": mediaType || mediaOf(name), "schema:contentSize": bytes } });
61
+ }
62
+
63
+ // a built app → schema:SoftwareApplication (a self-contained WebGPU/Web app object).
64
+ export function appAsSoftware({ name, kappa, bytes = 0, prov = [] }) {
65
+ return asLinkedData({ kind: "app", kappa, prov, props: {
66
+ "schema:name": String(name).replace(/\.html$/i, ""), "schema:identifier": kappa,
67
+ "schema:applicationCategory": "WebApplication", "schema:operatingSystem": "Any (WebGPU/Web)",
68
+ "schema:fileSize": bytes } });
69
+ }
70
+
71
+ // a loaded model → schema:SoftwareSourceCode (the κ-object that runs on the GPU).
72
+ export function modelAsSource({ name, kappa, family, params, format, prov = [] }) {
73
+ return asLinkedData({ kind: "model", kappa, prov, props: {
74
+ "schema:name": name, "schema:identifier": kappa, "schema:programmingLanguage": "WGSL/WebGPU",
75
+ "holo:family": family, "holo:parameters": params, "holo:format": format } });
76
+ }
77
+
78
+ // one dispatcher so any producer can type any κ-object: linkedDataFor("app", {...}) etc.
79
+ export function linkedDataFor(kind, props = {}) {
80
+ switch (kind) {
81
+ case "skill": return skillAsHowTo(props);
82
+ case "file": return fileAsDocument(props);
83
+ case "app": return appAsSoftware(props);
84
+ case "model": return modelAsSource(props);
85
+ default: return asLinkedData({ kind, kappa: props.kappa, prov: props.prov || [], props: props.props || props });
86
+ }
87
+ }
88
+
89
+ // VERIFY (the gate): an object is semantically valid iff it has @context, an @id (κ), and a @type
90
+ // carrying both a schema.org kind and PROV-O lineage. Returns { ok, types, hasId, hasContext }.
91
+ export function verifySemantic(node) {
92
+ const types = [].concat(node && node["@type"] || []);
93
+ const hasSchema = types.some((t) => /^schema:|^https:\/\/schema\.org\//.test(t));
94
+ const hasProv = types.some((t) => /^prov:/.test(t)) || !!node["prov:wasDerivedFrom"];
95
+ const hasId = typeof node?.["@id"] === "string" && node["@id"].startsWith("did:holo:");
96
+ const hasContext = !!node?.["@context"];
97
+ return { ok: hasSchema && hasId && hasContext, hasSchema, hasProv, hasId, hasContext, types };
98
+ }
apps/q/forge/gguf-forge-iq-dequant.mjs ADDED
@@ -0,0 +1,260 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // IQ-quant dequantization, transcribed line-for-line from ggml-quants.c
2
+ // (llama.cpp b7248): dequantize_row_iq2_xxs:3077 iq2_xs:3105 iq2_s:3132
3
+ // iq3_xxs:3164 iq3_s:3196 iq1_s:3239 iq1_m:3264 iq4_nl:3314 iq4_xs:3332.
4
+ // Block layouts: ggml-common.h:485-563.
5
+ //
6
+ // ONE source of truth, two behaviours: makeIQ(fr, f16ToF32) binds the rounding
7
+ // function. The Tier-A oracle passes Math.fround (binary32-exact, witnessed
8
+ // bit-for-bit vs ggml to_float in gguf-forge-iq.test.mjs); the runtime passes
9
+ // identity (float64, fine for the GPU engine which re-quantizes anyway).
10
+ //
11
+ // Codebook grids are flattened little-endian byte runs (gguf-forge-iq-grids.mjs):
12
+ // an entry `idx` of stride S occupies bytes [idx*S .. idx*S+S). iq2*/iq3* read
13
+ // uint8, iq1s_grid / kvalues_iq4nl read int8.
14
+
15
+ import {
16
+ iq2xxs_grid, iq2xs_grid, iq2s_grid, iq3xxs_grid, iq3s_grid, iq1s_grid,
17
+ ksigns_iq2xs, kmask_iq2xs, kvalues_iq4nl,
18
+ } from "./gguf-forge-iq-grids.mjs";
19
+
20
+ const QK_K = 256;
21
+ const IQ1S_DELTA = 0.125, IQ1M_DELTA = 0.125;
22
+ const s8 = (b) => (b << 24) >> 24; // uint8 -> int8
23
+
24
+ export function makeIQ(fr, f16ToF32) {
25
+ const sign1 = (signs, j) => (signs & kmask_iq2xs[j] ? -1 : 1);
26
+
27
+ // dequantize_row_iq2_xxs (:3077). Block 66 B: d:f16 qs:uint16[32].
28
+ function dequantIQ2XXS(raw, elements) {
29
+ const out = new Float32Array(elements);
30
+ const dv = new DataView(raw.buffer, raw.byteOffset, raw.byteLength);
31
+ const nb = elements / QK_K; let o = 0;
32
+ for (let i = 0; i < nb; i++) {
33
+ const bp = i * 66, qs = bp + 2;
34
+ const d = f16ToF32(dv.getUint16(bp, true));
35
+ for (let ib32 = 0; ib32 < QK_K / 32; ++ib32) {
36
+ const a0 = dv.getUint32(qs + 8 * ib32, true), a1 = dv.getUint32(qs + 8 * ib32 + 4, true);
37
+ const db = fr(fr(d * fr(0.5 + (a1 >>> 28))) * 0.25);
38
+ for (let l = 0; l < 4; ++l) {
39
+ const idx = (a0 >>> (8 * l)) & 0xff;
40
+ const signs = ksigns_iq2xs[(a1 >>> (7 * l)) & 127];
41
+ for (let j = 0; j < 8; ++j) out[o++] = sign1(signs, j) * fr(db * iq2xxs_grid[idx * 8 + j]);
42
+ }
43
+ }
44
+ }
45
+ return out;
46
+ }
47
+
48
+ // dequantize_row_iq2_xs (:3105). Block 74 B: d:f16 qs:uint16[32] scales:uint8[8].
49
+ function dequantIQ2XS(raw, elements) {
50
+ const out = new Float32Array(elements);
51
+ const dv = new DataView(raw.buffer, raw.byteOffset, raw.byteLength);
52
+ const nb = elements / QK_K; let o = 0;
53
+ for (let i = 0; i < nb; i++) {
54
+ const bp = i * 74, qs = bp + 2, scB = bp + 66;
55
+ const d = f16ToF32(dv.getUint16(bp, true));
56
+ for (let ib32 = 0; ib32 < QK_K / 32; ++ib32) {
57
+ const db = [fr(fr(d * fr(0.5 + (raw[scB + ib32] & 0xf))) * 0.25),
58
+ fr(fr(d * fr(0.5 + (raw[scB + ib32] >> 4))) * 0.25)];
59
+ for (let l = 0; l < 4; ++l) {
60
+ const q = dv.getUint16(qs + (4 * ib32 + l) * 2, true);
61
+ const idx = q & 511, signs = ksigns_iq2xs[q >> 9], dl = db[l >> 1];
62
+ for (let j = 0; j < 8; ++j) out[o++] = sign1(signs, j) * fr(dl * iq2xs_grid[idx * 8 + j]);
63
+ }
64
+ }
65
+ }
66
+ return out;
67
+ }
68
+
69
+ // dequantize_row_iq2_s (:3132). Block 82 B: d:f16 qs:uint8[64] qh:uint8[8] scales:uint8[8].
70
+ // signs = qs + 32 (second half of qs); idx = qs[l] | ((qh[ib32]<<(8-2l)) & 0x300).
71
+ function dequantIQ2S(raw, elements) {
72
+ const out = new Float32Array(elements);
73
+ const dv = new DataView(raw.buffer, raw.byteOffset, raw.byteLength);
74
+ const nb = elements / QK_K; let o = 0;
75
+ for (let i = 0; i < nb; i++) {
76
+ const bp = i * 82, qhB = bp + 66, scB = bp + 74;
77
+ const d = f16ToF32(dv.getUint16(bp, true));
78
+ let qs = bp + 2, signs = bp + 2 + 32;
79
+ for (let ib32 = 0; ib32 < QK_K / 32; ++ib32) {
80
+ const db = [fr(fr(d * fr(0.5 + (raw[scB + ib32] & 0xf))) * 0.25),
81
+ fr(fr(d * fr(0.5 + (raw[scB + ib32] >> 4))) * 0.25)];
82
+ for (let l = 0; l < 4; ++l) {
83
+ const dl = db[l >> 1];
84
+ const idx = raw[qs + l] | (((raw[qhB + ib32] << (8 - 2 * l)) & 0x300));
85
+ for (let j = 0; j < 8; ++j) out[o++] = sign1(raw[signs + l], j) * fr(dl * iq2s_grid[idx * 8 + j]);
86
+ }
87
+ qs += 4; signs += 4;
88
+ }
89
+ }
90
+ return out;
91
+ }
92
+
93
+ // dequantize_row_iq3_xxs (:3164). Block 98 B: d:f16 qs:uint8[96].
94
+ // qs[0..63]=grid idx; scales_and_signs = qs+64 (8 uint32). db scale uses *0.5.
95
+ function dequantIQ3XXS(raw, elements) {
96
+ const out = new Float32Array(elements);
97
+ const dv = new DataView(raw.buffer, raw.byteOffset, raw.byteLength);
98
+ const nb = elements / QK_K; let o = 0;
99
+ for (let i = 0; i < nb; i++) {
100
+ const bp = i * 98, ss = bp + 2 + 64;
101
+ const d = f16ToF32(dv.getUint16(bp, true));
102
+ let qs = bp + 2;
103
+ for (let ib32 = 0; ib32 < QK_K / 32; ++ib32) {
104
+ const a32 = dv.getUint32(ss + 4 * ib32, true);
105
+ const db = fr(fr(d * fr(0.5 + (a32 >>> 28))) * 0.5);
106
+ for (let l = 0; l < 4; ++l) {
107
+ const signs = ksigns_iq2xs[(a32 >>> (7 * l)) & 127];
108
+ const g1 = raw[qs + 2 * l] * 4, g2 = raw[qs + 2 * l + 1] * 4;
109
+ for (let j = 0; j < 4; ++j) {
110
+ out[o + j + 0] = sign1(signs, j + 0) * fr(db * iq3xxs_grid[g1 + j]);
111
+ out[o + j + 4] = sign1(signs, j + 4) * fr(db * iq3xxs_grid[g2 + j]);
112
+ }
113
+ o += 8;
114
+ }
115
+ qs += 8;
116
+ }
117
+ }
118
+ return out;
119
+ }
120
+
121
+ // dequantize_row_iq3_s (:3196). Block 110 B: d:f16 qs:uint8[64] qh:uint8[8] signs:uint8[32] scales:uint8[4].
122
+ function dequantIQ3S(raw, elements) {
123
+ const out = new Float32Array(elements);
124
+ const dv = new DataView(raw.buffer, raw.byteOffset, raw.byteLength);
125
+ const nb = elements / QK_K; let o = 0;
126
+ for (let i = 0; i < nb; i++) {
127
+ const bp = i * 110, scB = bp + 106;
128
+ const d = f16ToF32(dv.getUint16(bp, true));
129
+ let qs = bp + 2, qh = bp + 66, signs = bp + 74;
130
+ for (let ib32 = 0; ib32 < QK_K / 32; ib32 += 2) {
131
+ const db1 = fr(d * (1 + 2 * (raw[scB + (ib32 >> 1)] & 0xf)));
132
+ const db2 = fr(d * (1 + 2 * (raw[scB + (ib32 >> 1)] >> 4)));
133
+ for (let l = 0; l < 4; ++l) {
134
+ const g1 = (raw[qs + 2 * l] | ((raw[qh] << (8 - 2 * l)) & 256)) * 4;
135
+ const g2 = (raw[qs + 2 * l + 1] | ((raw[qh] << (7 - 2 * l)) & 256)) * 4;
136
+ for (let j = 0; j < 4; ++j) {
137
+ out[o + j + 0] = sign1(raw[signs + l], j + 0) * fr(db1 * iq3s_grid[g1 + j]);
138
+ out[o + j + 4] = sign1(raw[signs + l], j + 4) * fr(db1 * iq3s_grid[g2 + j]);
139
+ }
140
+ o += 8;
141
+ }
142
+ qs += 8; signs += 4;
143
+ for (let l = 0; l < 4; ++l) {
144
+ const g1 = (raw[qs + 2 * l] | ((raw[qh + 1] << (8 - 2 * l)) & 256)) * 4;
145
+ const g2 = (raw[qs + 2 * l + 1] | ((raw[qh + 1] << (7 - 2 * l)) & 256)) * 4;
146
+ for (let j = 0; j < 4; ++j) {
147
+ out[o + j + 0] = sign1(raw[signs + l], j + 0) * fr(db2 * iq3s_grid[g1 + j]);
148
+ out[o + j + 4] = sign1(raw[signs + l], j + 4) * fr(db2 * iq3s_grid[g2 + j]);
149
+ }
150
+ o += 8;
151
+ }
152
+ qh += 2; qs += 8; signs += 4;
153
+ }
154
+ }
155
+ return out;
156
+ }
157
+
158
+ // dequantize_row_iq1_s (:3239). Block 50 B: d:f16 qs:uint8[32] qh:uint16[8]. grid int8.
159
+ function dequantIQ1S(raw, elements) {
160
+ const out = new Float32Array(elements);
161
+ const dv = new DataView(raw.buffer, raw.byteOffset, raw.byteLength);
162
+ const nb = elements / QK_K; let o = 0;
163
+ for (let i = 0; i < nb; i++) {
164
+ const bp = i * 50, qhB = bp + 34;
165
+ const d = f16ToF32(dv.getUint16(bp, true));
166
+ let qs = bp + 2;
167
+ for (let ib = 0; ib < QK_K / 32; ++ib) {
168
+ const qh = dv.getUint16(qhB + 2 * ib, true);
169
+ const dl = fr(d * (2 * ((qh >> 12) & 7) + 1));
170
+ const delta = (qh & 0x8000) ? -IQ1S_DELTA : IQ1S_DELTA;
171
+ for (let l = 0; l < 4; ++l) {
172
+ const g = (raw[qs + l] | (((qh >> (3 * l)) & 7) << 8)) * 8;
173
+ for (let j = 0; j < 8; ++j) out[o++] = fr(dl * fr(s8(iq1s_grid[g + j]) + delta));
174
+ }
175
+ qs += 4;
176
+ }
177
+ }
178
+ return out;
179
+ }
180
+
181
+ // dequantize_row_iq1_m (:3264). Block 56 B: qs:uint8[32] qh:uint8[16] scales:uint8[8].
182
+ // No d field — f16 scale is woven from the four scale uint16s. grid int8.
183
+ function dequantIQ1M(raw, elements) {
184
+ const out = new Float32Array(elements);
185
+ const dv = new DataView(raw.buffer, raw.byteOffset, raw.byteLength);
186
+ const nb = elements / QK_K; let o = 0;
187
+ const delta = new Float32Array(4), idx = new Uint16Array(4);
188
+ for (let i = 0; i < nb; i++) {
189
+ const bp = i * 56, scB = bp + 48;
190
+ const sc = [dv.getUint16(scB, true), dv.getUint16(scB + 2, true), dv.getUint16(scB + 4, true), dv.getUint16(scB + 6, true)];
191
+ const u16 = (sc[0] >> 12) | ((sc[1] >> 8) & 0x00f0) | ((sc[2] >> 4) & 0x0f00) | (sc[3] & 0xf000);
192
+ const d = f16ToF32(u16);
193
+ let qs = bp, qh = bp + 32;
194
+ for (let ib = 0; ib < QK_K / 32; ++ib) {
195
+ const dl1 = fr(d * (2 * ((sc[ib >> 1] >> (6 * (ib % 2) + 0)) & 0x7) + 1));
196
+ const dl2 = fr(d * (2 * ((sc[ib >> 1] >> (6 * (ib % 2) + 3)) & 0x7) + 1));
197
+ idx[0] = raw[qs + 0] | ((raw[qh + 0] << 8) & 0x700);
198
+ idx[1] = raw[qs + 1] | ((raw[qh + 0] << 4) & 0x700);
199
+ idx[2] = raw[qs + 2] | ((raw[qh + 1] << 8) & 0x700);
200
+ idx[3] = raw[qs + 3] | ((raw[qh + 1] << 4) & 0x700);
201
+ delta[0] = raw[qh + 0] & 0x08 ? -IQ1M_DELTA : IQ1M_DELTA;
202
+ delta[1] = raw[qh + 0] & 0x80 ? -IQ1M_DELTA : IQ1M_DELTA;
203
+ delta[2] = raw[qh + 1] & 0x08 ? -IQ1M_DELTA : IQ1M_DELTA;
204
+ delta[3] = raw[qh + 1] & 0x80 ? -IQ1M_DELTA : IQ1M_DELTA;
205
+ for (let l = 0; l < 2; ++l) {
206
+ const g = idx[l] * 8;
207
+ for (let j = 0; j < 8; ++j) out[o++] = fr(dl1 * fr(s8(iq1s_grid[g + j]) + delta[l]));
208
+ }
209
+ for (let l = 2; l < 4; ++l) {
210
+ const g = idx[l] * 8;
211
+ for (let j = 0; j < 8; ++j) out[o++] = fr(dl2 * fr(s8(iq1s_grid[g + j]) + delta[l]));
212
+ }
213
+ qs += 4; qh += 2;
214
+ }
215
+ }
216
+ return out;
217
+ }
218
+
219
+ // dequantize_row_iq4_nl (:3314). Block 18 B / 32 elems: d:f16 qs:uint8[16]. kvalues int8.
220
+ function dequantIQ4NL(raw, elements) {
221
+ const out = new Float32Array(elements);
222
+ const dv = new DataView(raw.buffer, raw.byteOffset, raw.byteLength);
223
+ const nb = elements / 32; let o = 0;
224
+ for (let i = 0; i < nb; i++) {
225
+ const bp = i * 18, qs = bp + 2;
226
+ const d = f16ToF32(dv.getUint16(bp, true));
227
+ for (let j = 0; j < 16; ++j) {
228
+ out[o + j] = fr(d * s8(kvalues_iq4nl[raw[qs + j] & 0xf]));
229
+ out[o + 16 + j] = fr(d * s8(kvalues_iq4nl[raw[qs + j] >> 4]));
230
+ }
231
+ o += 32;
232
+ }
233
+ return out;
234
+ }
235
+
236
+ // dequantize_row_iq4_xs (:3332). Block 136 B: d:f16 scales_h:uint16 scales_l:uint8[4] qs:uint8[128].
237
+ function dequantIQ4XS(raw, elements) {
238
+ const out = new Float32Array(elements);
239
+ const dv = new DataView(raw.buffer, raw.byteOffset, raw.byteLength);
240
+ const nb = elements / QK_K; let o = 0;
241
+ for (let i = 0; i < nb; i++) {
242
+ const bp = i * 136, slB = bp + 4;
243
+ const d = f16ToF32(dv.getUint16(bp, true));
244
+ const sh = dv.getUint16(bp + 2, true);
245
+ let qs = bp + 8;
246
+ for (let ib = 0; ib < QK_K / 32; ++ib) {
247
+ const ls = ((raw[slB + (ib >> 1)] >> (4 * (ib % 2))) & 0xf) | (((sh >> (2 * ib)) & 3) << 4);
248
+ const dl = fr(d * (ls - 32));
249
+ for (let j = 0; j < 16; ++j) {
250
+ out[o + j] = fr(dl * s8(kvalues_iq4nl[raw[qs + j] & 0xf]));
251
+ out[o + 16 + j] = fr(dl * s8(kvalues_iq4nl[raw[qs + j] >> 4]));
252
+ }
253
+ o += 32; qs += 16;
254
+ }
255
+ }
256
+ return out;
257
+ }
258
+
259
+ return { dequantIQ2XXS, dequantIQ2XS, dequantIQ2S, dequantIQ3XXS, dequantIQ3S, dequantIQ1S, dequantIQ1M, dequantIQ4NL, dequantIQ4XS };
260
+ }
apps/q/forge/gguf-forge-iq-grids.mjs ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // AUTO-GENERATED by gen-iq-grids.mjs from ggml-common.h — do not edit by hand.
2
+ // IQ-quant codebook grids + helper tables, flattened to little-endian byte runs.
3
+ // A grid entry `idx` of stride S occupies bytes [idx*S .. idx*S+S); read uint8
4
+ // for iq2*/iq3* grids, int8 (`(b<<24)>>24`) for iq1s_grid / kvalues_iq4nl.
5
+ const D = (s) => Uint8Array.from(atob(s), (c) => c.charCodeAt(0));
6
+ export const iq2xxs_grid = /* 2048B */ D("CAgICAgICAgrCAgICAgICBkZCAgICAgICCsICAgICAgrKwgICAgICBkIGQgICAgICBkZCAgICAgICCsICAgICCsIKwgICAgICCsrCAgICAgrKysICAgICBkICBkICAgICBkIGQgICAgICBkZCAgICAgrGRkICAgIGQgrGQgICAgIGSsZCAgICAgICCsICAgIKwgIKwgICAgrKwgrCAgICCsIKysICAgIGQgICBkICAgIGQgIGQgICAgIGQgZCAgIGRkZCBkICAgICAgZGQgICAgZCCsZCAgICCsZKxkICAgICAgIKwgICCsICAgrCAgIKwgrCCsICAgrCAgrKwgICBkICAgIGQgICBkICAgZCAgICBkICBkICBkIKwgIGQgICBkrCAgZCAgICAgZCBkICCsICBkIGQgICCsIGQgZCAgICCsZCBkICBkICCsIGQgICBkIKwgZCAgICBkrCBkICAgZKysIGQgICAgICBkZCAgrCAgIGRkICAgrCAgZGQgICAgrCBkZCAgrGQgZGRkICBkrKxkZGQgICAgIKxkZCAgZCBkrGRkICBkrCAgrGQgICAgZCCsZCAgICAgZKxkICAgZCCsrGQgICBkrKysZCAgICAgICCsICBkZCAgIKwgICCsICAgrCAgIGRkICCsICAgrKwgIKwgIGQgIGQgrCAgIGQgZCCsICAgIGRkIKwgIKwgZGQgrCAgIKwgrCCsICAgZCAgZKwgICAgIGRkrCAgrCAgIKysICAgZGQgrKwgIGQgICAgIGQgIGQgICAgZCAgIGQgICBkIGQgrCAgIGQgICAgZCAgZCAgIKxkICBkICBkIKwgIGQgICBkrCAgZCBkZGSsICBkICAgICBkIGQgIKwgIGQgZCAgIKwgZCBkICAgZGRkIGQgrKxkZGQgZCAgICCsZCBkICBkrCCsIGQgZGQgZKwgZCAgICAgIGRkICCsICAgZGQgICCsICBkZCBkZKwgIGRkIGSsIGQgZGQgICAgrCBkZCAgrGQgZGRkIKwgrGRkZGQgICAgIKxkZCCsZGQgrGRkIGQgICAgrGQgIGQgICCsZCAgIGQgIKxkICAgIGQgrGQgZCAgrCCsZCAgICAgZKxkIGRkICBkrGQgICCsrGSsZCBkIGRkrKxkICAgICAgIKwgrCAgICAgrCCsrCAgICCsICBkIGQgIKwgZCCsZCAgrCAgICCsICCsIKwgIKwgIKwgZKysIGQgrCAgrCBkZCCsICAgICCsIKwgrCAgIKwgrCBkICAgIGSsICBkICAgZKwgICBkICBkrCAgICBkIGSsIKxkZGQgZKwgICAgIGRkrCBkICBkZGSsICBkrGRkZKwgICBkrKxkrCAgrCAgIKysICAgrCAgrKwgIGRkrCCsrCAgZCBkrKysIGQgICAgICBkIGQgICAgIGQgIGQgICAgZCCsZCAgICBkZCCsICAgIGQgZKwgICAgZCAgIGQgICBkIKwgZCAgIGSsZGRkICAgZCAgrGQgICBkZCAgrCAgIGQgZCCsICAgZCAgZKwgICBkICAgIGQgIGQgIKwgZCAgZGQgrGRkICBkICAgrGQgIGRkZCCsZCAgZGQgICCsICBkICBkIKwgIGQgrCBkrCAgZKxkZGSsICBkIKysZKwgIGQgICAgIGQgZCCsICAgZCBkICCsICBkIGQgICCsIGQgZGSsZKwgZCBkrCBkIGRkIGQgZKwgZGQgZCAgICCsZCBkZCAgICCsIGQgZCAgIKwgZCAgZCAgrCBkICAgZCCsIGRkZCBkIKwgZCAgICBkrCBkIKxkZGSsIGRkIKxkZKwgZKwgIKxkrCBkZGQgZKysIGQgIGSsrKwgZCAgICAgIGRkIKwgICAgZGRkIGQgICBkZGSsZCAgIGRkICCsICAgZGQgICCsICBkZCCsIKwgIGRkIGQgIGQgZGSsICBkZCBkZCBkrKxkIGRkZCBkrKwgZGQgIGSsIGRkZKwgZKwgZGRkrKwgIGRkZGRkICAgrGRkZCBkZGSsZGRkICAgICCsZGRkIGQgIKxkZGSsZCAgrGRkIGSsZCCsZGQgICBkZKxkZCCsICCsrGRkIGQgICAgrGQgIGQgICCsZCAgIGQgIKxkIKysZCAgrGQgICAgZCCsZGRkZGRkIKxkIKxkIKwgrGQgIKxkrCCsZCAgICAgZKxkZGQgICBkrGQgIGQgZGSsZKwgZCBkZKxkIGQgrGRkrGSsICBkIKysZCAgICAgICCsrCAgICAgIKysrCAgICAgrGQgIGQgICCsrCAgrCAgIKwgZCAgZCAgrCCsZCBkICCsICAgZGQgIKxkIGQgrCAgrGQgICAgZCCsIGQgICBkIKwgIGQgIGQgrGRkZCAgZCCsICAgZCBkIKwgIKxkIGQgrCAgICBkZCCsrGQgZGRkIKwgZGSsZGQgrGSsICCsZCCsICAgZKxkIKwgIKxkrGQgrKwgICAgrCCsIGQgIGSsIKxkIGQgrKwgrCBkICAgIGSsICBkICAgZKwgZKwgICBkrCAgIGQgIGSsZCCsrCAgZKysZGQgZCBkrCAgIKxkIGSsZGQgZKwgZKwgICAgIGRkrKwgrCAgZGSsIGQgZCBkZKxkIGRkZGRkrGQgIKwgrGSsICCsIGSsZKysICAgICCsrCAgZGQgIKysZGQgrCAgrKxkrCAgZCCsrCAgICCsIKysIKxkICBkrKwgIGRkIKysrCBkICBkrKys=");
7
+ export const iq2xs_grid = /* 4096B */ D("CAgICAgICAgrCAgICAgICBkZCAgICAgICCsICAgICAgrKwgICAgICBkIGQgICAgICBkZCAgICAgrGRkICAgICBkrGQgICAgICAgrCAgICAgrCCsICAgICBkZKwgICAgICCsrCAgICAgZCAgZCAgICAgZCBkICAgIKxkIGQgICAgZKwgZCAgICAgIGRkICAgIKwgZGQgICAgZGRkZCAgICAgrGRkICAgIGQgrGQgICAgIGSsZCAgICAgICCsICAgIKwgIKwgICAgZGQgrCAgICAgrCCsICAgIGQgZKwgICAgIGRkrCAgICBkrGSsICAgICAgrKwgICAgZCAgIGQgICAgZCAgZCAgIKxkICBkICAgZKwgIGQgICAgIGQgZCAgIKwgZCBkICAgZGRkIGQgICAgrGQgZCAgIKysZCBkICAgZCCsIGQgICAgZKwgZCAgICAgIGRkICAgrCAgZGQgICBkZCBkZCAgICCsIGRkICAgZCBkZGQgICAgZGRkZCAgICAgrGRkICAgIKysZGQgICBkICCsZCAgICBkIKxkICAgICBkrGQgICAgICAgrCAgIKwgICCsICAgZGQgIKwgICAgrCAgrCAgIGQgZCCsICAgIGRkIKwgICAgIKwgrCAgIGQgIGSsICAgIGQgZKwgICAgIGRkrCAgIGRkZGSsICAgICAgrKwgICCsrCCsrCAgIGQgICAgZCAgIGQgICBkICCsZCAgIGQgIGSsICAgZCAgICBkICBkICCsIGQgIGQgIGRkZCAgZCAgIKxkICBkICBkIKwgIGQgICBkrCAgZCAgICAgZCBkICCsICBkIGQgIGRkIGQgZCAgIKwgZCBkICBkIGRkIGQgICBkZGQgZCAgrGRkZCBkICAgIKxkIGQgIGQgIKwgZCAgIGQgrCBkICAgIGSsIGQgICAgICBkZCAgrCAgIGRkICBkZCAgZGQgICCsICBkZCAgZCBkIGRkICAgZGQgZGQgICAgrCBkZCAgZCAgZGRkICAgZCBkZGQgICAgZGRkZCAgZCCsZGRkICAgICCsZGQgIGQgICCsZCAgIGQgIKxkICAgIGQgrGQgIKxkrCCsZCAgICAgZKxkICCsICBkrGQgICBkIKysZCAgICAgICCsICCsICAgIKwgIGRkICAgrCAgIKwgICCsICCsrCAgIKwgIGQgZCAgrCAgIGRkICCsICAgIKwgIKwgIGRkrCAgrCAgZCAgZCCsICAgZCBkIKwgICAgZGQgrCAgIKxkZCCsICAgICCsIKwgICAgrKwgrCAgrKysrCCsICBkICAgZKwgICBkICBkrCAgICBkIGSsICAgICBkZKwgIGQgIKxkrCAgZKwgrGSsICAgICAgrKwgICAgrCCsrCAgIKysIKysICCsZGSsrKwgICAgrKysrCAgZCAgICAgZCAgZCAgICBkIKxkICAgIGQgZKwgICAgZCAgIGQgICBkIKwgZCAgIGQgZGRkICAgZCAgrGQgICBkIGQgrCAgIGQgIGSsICAgZCAgICBkICBkIKwgIGQgIGQgZGQgZCAgZCAgrCBkICBkIGQgZGQgIGQgIGRkZCAgZCAgIKxkICBkIKysrGQgIGQgZCAgrCAgZCAgZCCsICBkICAgZKwgIGQgICAgIGQgZCCsICAgZCBkIGRkICBkIGQgIKwgIGQgZCBkIGQgZCBkICBkZCBkIGQgICCsIGQgZCBkICBkZCBkICBkIGRkIGQgICBkZGQgZCAgICCsZCBkICBkZKxkIGQgrGRkrGQgZCBkICAgrCBkICBkICCsIGQgrGQgIKwgZCAgIGQgrCBkICAgIGSsIGQgICCsZKwgZCAgICAgIGRkIKwgICAgZGQgZGQgICBkZCAgrCAgIGRkIGQgZCAgZGQgIGRkICBkZCAgIKwgIGRkIGQgIGQgZGQgIGQgZCBkZCBkrCBkIGRkICAgZGQgZGQgIGSsZCBkZCAgICCsIGRkIGQgICBkZGQgIGQgIGRkZCAgIGQgZGRkICAgIGRkZGQgICAgIKxkZCAgZGQgrGRkIGSsIGSsZGQgZCAgICCsZCAgZCAgIKxkICAgZCAgrGQgrCBkICCsZCAgICBkIKxkICBkZGQgrGQgrGQgrCCsZCAgICAgZKxkIGRkICBkrGQgrGSsZGSsZCBkIGRkrKxkIGSsrKysrGQgICAgICAgrCCsICAgICCsIGRkICAgIKwgIKwgICAgrCCsrCAgICCsIGQgZCAgIKwgIGRkICAgrCAgIKwgICCsIGQgIGQgIKwgIGQgZCAgrCAgIGRkICCsICAgIKwgIKwgICCsrCAgrCBkICAgZCCsICBkICBkIKwgICBkIGQgrCAgICBkZCCsICCsIGRkIKwgZGSsZGQgrCAgICAgrCCsIKwgrCCsIKwgICAgrKwgrCAgrKysrCCsIGQgICAgZKwgIGQgICBkrCAgIGQgIGSsIGSsrCAgZKwgICAgZCBkrCAgICAgZGSsIGQgIGRkZKwgrCBkZGRkrCBkrGSsZGSsIGQgICCsZKwgrKxkIKxkrCCsZKysrGSsICAgICAgrKwgIKwgICCsrCCsrCAgIKysICAgrCAgrKwgZGRkZCCsrCAgrCCsIKysIKwgrKwgrKwgIKysZGSsrCAgIGSsZKysICCsICCsrKwgICCsIKysrCCsICCsrKysICCsIKysrKwgrKwgrKysrCBkICAgICAgZCBkICAgICBkrGQgICAgIGRkrCAgICAgZCAgZCAgICBkrCBkICAgIGRkZGQgICAgZCCsZCAgICBkZCCsICAgIGQgZKwgICAgZCAgIGQgICBkrCAgZCAgIGRkZCBkICAgZCCsIGQgICBkrKwgZCAgIGRkIGRkICAgZCBkZGQgICBkICCsZCAgIGRkZKxkICAgZGQgIKwgICBkIGQgrCAgIGQgIGSsICAgZCAgICBkICBkrCAgIGQgIGRkZCAgZCAgZCCsICBkICBkZCBkIGQgIGQgZGQgZCAgZCAgrCBkICBkZCAgZGQgIGQgZCBkZCAgZCAgZGRkICBkICAgrGQgIGRkZCCsZCAgZKwgrKxkICBkZCAgIKwgIGQgZCAgrCAgZCAgZCCsICBkrCBkIKwgIGRkrKwgrCAgZCAgIGSsICBkICAgICBkIGSsICAgIGQgZGRkICAgZCBkIKwgICBkIGRkIGQgIGQgZCBkZCAgZCBkZKxkICBkIGQgIKwgIGQgZGQgIGQgZCBkIGQgZCBkIGQgIGRkIGQgZCAgIKwgZCBkIGRkrCBkIGRkICAgZGQgZCBkICBkZCBkICBkIGRkIGQgZKwgZGQgZCAgIGRkZCBkrKxkrGRkIGQgICAgrGQgZKysICCsZCBkIGQgZKxkIGQgIGRkrGQgZGQgICAgrCBkIGQgICCsIGQgIGQgIKwgZCAgIGQgrCBkZGQgZCCsIGQgZGRkIKwgZKwgrGQgrCBkICAgIGSsIGRkIGQgZKwgZCBkIGRkrCBkICBkZGSsIGRkrKxkZKwgZCBkICCsrCBkICAgICAgZGSsICAgICBkZGRkICAgIGRkIKwgICAgZGRkIGQgICBkZCBkZCAgIGRkICCsICAgZGQgrKwgICBkZGQgIGQgIGRkIGQgZCAgZGQgIGRkICBkZCAgIKwgIGRkZCAgIGQgZGQgZCAgZCBkZCAgZCBkIGRkZGRkIGQgZGQgICBkZCBkZKwgIGRkIGRkICAgIKwgZGQgZCBkrCBkZKysrKysIGRkZCAgICBkZGQgZCAgIGRkZCAgZCAgZGRkZCCsICBkZGQgICBkIGRkZCAgrGQgZGRkZCAgrCBkZGRkIKysIGRkZCAgICBkZGRkIKwgIGRkZGQgICCsZGRkZCCsIKxkZGRkZCCsIKxkZGQgrKxkrGRkZGQgrKysZGRkICAgICCsZGQgZGQgIKxkZGQgIGQgrGRkICBkZCCsZGRkrGSsIKxkZKysZCBkrGRkICAgZGSsZGSsICBkZKxkZGRkIKysrGRkZCAgICAgrGQgZCAgICCsZCAgZCAgIKxkICAgZCAgrGQgZGRkICCsZKwgrGQgIKxkrGQgrCAgrGRkrKysICCsZCAgICBkIKxkIGSsIKwgrGSsrCBkrCCsZKwgZKysIKxkICAgICBkrGSsZGQgIGSsZCAgZCBkZKxkICAgZGRkrGRkZCBkZGSsZCBkrKxkZKxkZCAgICCsrGSsrKxkIKysZGRkrCBkrKxkrGQgIKysrGQgZGRkrKysZKwgrGSsrKxkICAgICAgIKysICAgICAgrGRkICAgICCsIKwgICAgIKxkIGQgICAgrCBkZCAgICCsICCsICAgIKysrKwgICAgrGQgIGQgICCsIGQgZCAgIKwgIGRkICAgrCAgIKwgICCsrCAgrCAgIKwgrKysICAgrKysrKwgICCsZCAgIGQgIKwgZCAgZCAgrKxkICBkICCsICBkIGQgIKwgICBkZCAgrGQgZGRkICCsZKxkZGQgIKwgICAgrCAgrCAgrCCsICCsICAgrKwgIKysICCsrCAgrCAgrKysICCsIKysrKwgIKxkICAgIGQgrCBkICAgZCCsICBkICBkIKysIGQgIGQgrGRkZCAgZCCsICAgZCBkIKwgIKxkIGQgrGSsIKwgZCCsICAgIGRkIKwgZCBkZGQgrGRkrKxkZCCsIKxkIKxkIKysrKxkrGQgrCAgICAgrCCsIKwgICCsIKxkZKwgIKwgrKysZGQgrCCsICAgrCCsIKysICCsIKwgrCCsrKwgrCCsrGQgIGSsIKysIKwgrKwgrCAgIKysrCCsIKwgrKysIKysZGSsrKwgrCCsrKysrCCsZCAgICAgZKwgZCAgICBkrCAgZCAgIGSsICAgZCAgZKysZGRkICBkrCBkIKwgIGSsICAgIGQgZKysIKwgZCBkrCBkrGRkIGSsrGRkZKwgZKxkrCCsrCBkrCAgICAgZGSsZGQgICBkZKwgZCBkIGRkrCAgZGQgZGSsIKxkZCBkZKxkrKwgZGRkrCAgZKxkZGSsrCBkrGRkZKxkICBkrGRkrGQgZGQgrGSsrGSsrCCsZKxkrCBkZKxkrGRkZCCsrGSsICCsZKysZKwgICAgICCsrKwgICAgIKysIKwgICAgrKysrCAgICCsrCAgrCAgIKysrKysICAgrKwgIKysICCsrGQgZGRkIKysZKxkZGQgrKysZKysZCCsrCAgICCsIKysrCAgIKwgrKwgrCAgrCCsrKysrCCsIKysICAgrKwgrKwgIKysrCCsrCAgIGQgZKysZGRkrCBkrKxkZKxkrGSsrCCsZKysZKysrKwgICCsrKwgIKwgIKysrKwgrCAgrKysIKysICCsrKwgIKysIKysrCCsrKwgrKysIGQgIGSsrKwgZCCsZKysrKxkIKxkrKysIKysIKysrKysrKwgrKysrGQgZKysrKysrKysrKysrKw==");
8
+ export const iq2s_grid = /* 8192B */ D("CAgICAgICAgrCAgICAgICBkZCAgICAgICCsICAgICAgrKwgICAgICBkIGQgICAgICBkZCAgICAgrGRkICAgICBkrGQgICAgICAgrCAgICAgrCCsICAgICBkZKwgICAgICCsrCAgICAgZCAgZCAgICAgZCBkICAgIKxkIGQgICAgZKwgZCAgICAgIGRkICAgIKwgZGQgICAgZGRkZCAgICAgrGRkICAgIGQgrGQgICAgIGSsZCAgICCsZKxkICAgIGSsrGQgICAgICAgrCAgICCsICCsICAgIGRkIKwgICAgIKwgrCAgICBkIGSsICAgICBkZKwgICAgICCsrCAgICBkZKysICAgIKysrKwgICAgZCAgIGQgICAgZCAgZCAgIKxkICBkICAgZKwgIGQgICAgIGQgZCAgIKwgZCBkICAgZGRkIGQgICAgrGQgZCAgIGQgrCBkICAgIGSsIGQgICAgICBkZCAgIKwgIGRkICAgZGQgZGQgICAgrCBkZCAgIGQgZGRkICAgIGRkZGQgICCsZGRkZCAgIGSsZGRkICAgICCsZGQgICBkZKxkZCAgICCsrGRkICAgZCAgrGQgICAgZCCsZCAgICAgZKxkICAgrCBkrGQgICBkZGSsZCAgIGQgrKxkICAgIGSsrGQgICAgICAgrCAgIKwgICCsICAgZGQgIKwgICAgrCAgrCAgIGQgZCCsICAgIGRkIKwgICAgIKwgrCAgIKysrCCsICAgZCAgZKwgICAgZCBkrCAgIKxkIGSsICAgZKwgZKwgICAgIGRkrCAgIGRkZGSsICAgICAgrKwgICBkZCCsrCAgIKysIKysICAgIGRkrKwgICCsIKysrCAgIGQgICAgZCAgIGQgICBkICCsZCAgIGQgIGSsICAgZCAgICBkICBkICCsIGQgIGQgIGRkZCAgZCAgIKxkICBkICBkIKwgIGQgICBkrCAgZCAgrGSsICBkICBkrKwgIGQgICAgIGQgZCAgrCAgZCBkICBkZCBkIGQgICCsIGQgZCAgrKwgZCBkICBkIGRkIGQgICBkZGQgZCAgrGRkZCBkICBkrGRkIGQgICAgrGQgZCAgrCCsZCBkICBkZKxkIGQgIGQgIKwgZCAgIGQgrCBkICCsZCCsIGQgIGSsIKwgZCAgICBkrCBkICBkZGSsIGQgICCsZKwgZCAgZCCsrCBkICAgZKysIGQgICAgICBkZCAgrCAgIGRkICBkZCAgZGQgICCsICBkZCAgrKwgIGRkICBkIGQgZGQgICBkZCBkZCAgrGRkIGRkICBkrGQgZGQgICAgrCBkZCAgZGSsIGRkICAgrKwgZGQgIGQgIGRkZCAgIGQgZGRkICCsZCBkZGQgIGSsIGRkZCAgICBkZGRkICCsIGRkZGQgIGRkZGRkZCAgIKxkZGRkICBkIKxkZGQgICBkrGRkZCAgICAgrGRkICCsICCsZGQgIGRkIKxkZCAgIKwgrGRkICBkIGSsZGQgICBkZKxkZCAgICCsrGRkICBkICAgrGQgICBkICCsZCAgrGQgIKxkICBkrCAgrGQgICAgZCCsZCAgZGRkIKxkICAgICBkrGQgIGRkIGSsZCAgIKwgZKxkICBkIGRkrGQgICBkZGSsZCAgICCsZKxkICBkICCsrGQgICBkIKysZCAgICBkrKxkICAgICAgIKwgIKwgICAgrCAgZGQgICCsICAgrCAgIKwgIGQgZCAgrCAgIGRkICCsICCsZGQgIKwgIGSsZCAgrCAgICCsICCsICBkZKwgIKwgIKysrCAgrCAgZCAgZCCsICAgZCBkIKwgIKxkIGQgrCAgZKwgZCCsICAgIGRkIKwgIKwgZGQgrCAgZGRkZCCsICAgrGRkIKwgIGQgrGQgrCAgIGSsZCCsICAgICCsIKwgIGRkIKwgrCAgIGRkrCCsICCsrKysIKwgIGQgICBkrCAgIGQgIGSsICAgIGQgZKwgIKwgZCBkrCAgZGRkIGSsICAgrGQgZKwgIGQgrCBkrCAgICAgZGSsICBkZCBkZKwgICCsIGRkrCAgZCBkZGSsICAgZGRkZKwgICAgrGRkrCAgZCAgrGSsICAgIGSsZKwgICAgICCsrCAgZCBkIKysICAgZGQgrKwgIKwgrCCsrCAgIKysIKysICCsrKwgrKwgICAgZGSsrCAgZKxkrKysICBkICAgICBkICBkICAgIGQgrGQgICAgZCBkrCAgICBkICAgZCAgIGQgrCBkICAgZCBkZGQgICBkICCsZCAgIGQgZCCsICAgZCAgZKwgICBkIKxkrCAgIGQgICAgZCAgZCCsICBkICBkIGRkIGQgIGQgIKwgZCAgZCBkIGRkICBkICBkZGQgIGQgrGRkZCAgZCBkrGRkICBkICAgrGQgIGQgrCCsZCAgZCBkZKxkICBkICCsrGQgIGQgZCAgrCAgZCAgZCCsICBkIKxkIKwgIGQgICBkrCAgZCBkZGSsICBkICCsZKwgIGQgZCCsrCAgZCAgZKysICBkICAgICBkIGQgrCAgIGQgZCBkZCAgZCBkICCsICBkIGQgrKwgIGQgZCBkIGQgZCBkICBkZCBkIGQgrGRkIGQgZCBkrGQgZCBkICAgrCBkIGQgrCCsIGQgZCBkZKwgZCBkICCsrCBkIGQgZCAgZGQgZCAgZCBkZCBkIKxkIGRkIGQgZKwgZGQgZCAgIGRkZCBkIKwgZGRkIGQgZGRkZGQgZCAgrGRkZCBkIGQgrGRkIGQgIGSsZGQgZCAgICCsZCBkIKwgIKxkIGQgZGQgrGQgZCAgrCCsZCBkIGQgZKxkIGQgIGRkrGQgZCBkICAgrCBkICBkICCsIGQgZKwgIKwgZCAgIGQgrCBkIGRkZCCsIGQgZCCsIKwgZCAgZKwgrCBkICAgIGSsIGQgZGQgZKwgZCBkIGRkrCBkICBkZGSsIGQgZCAgrKwgZCAgZCCsrCBkICAgZKysIGQgICAgICBkZCCsICAgIGRkIGRkICAgZGQgIKwgICBkZCBkIGQgIGRkICBkZCAgZGQgrGRkICBkZCBkrGQgIGRkICAgrCAgZGQgZGSsICBkZCAgrKwgIGRkIGQgIGQgZGQgIGQgZCBkZCCsZCBkIGRkIGSsIGQgZGQgICBkZCBkZCCsIGRkIGRkIGRkZGQgZGQgIKxkZCBkZCBkIKxkIGRkICBkrGQgZGQgICAgrCBkZCCsICCsIGRkIGRkIKwgZGQgIKwgrCBkZCBkIGSsIGRkICBkZKwgZGQgICCsrCBkZCBkICAgZGRkICBkICBkZGQgrGQgIGRkZCBkrCAgZGRkICAgZCBkZGQgrCBkIGRkZCBkZGQgZGRkICCsZCBkZGQgZCCsIGRkZCAgZKwgZGRkICAgIGRkZGQgrCAgZGRkZCBkZCBkZGRkICCsIGRkZGQgZCBkZGRkZCAgZGRkZGRkICAgrGRkZGQgZCAgrGRkZCAgZCCsZGRkICAgZKxkZGQgICAgIKxkZCBkZCAgrGRkICCsICCsZGQgZCBkIKxkZCAgZGQgrGRkICAgrCCsZGQgZCAgZKxkZCAgZCBkrGRkICAgZGSsZGQgICAgrKxkZCCsrKysrGRkIGQgICAgrGQgIGQgICCsZCCsZCAgIKxkIGSsICAgrGQgICBkICCsZCBkZGQgIKxkICCsZCAgrGQgZCCsICCsZCAgICBkIKxkIKwgIGQgrGQgZGQgZCCsZCAgrCBkIKxkIGQgZGQgrGQgIGRkZCCsZCAgIKxkIKxkIGQgIKwgrGQgIGQgrCCsZCAgICAgZKxkIKwgICBkrGQgZGQgIGSsZCAgrCAgZKxkIGQgZCBkrGQgIGRkIGSsZCAgIKwgZKxkIGQgIGRkrGQgIGQgZGSsZCAgIGRkZKxkIGSsrGRkrGQgrCCsrGSsZCAgZCAgrKxkICAgZCCsrGQgICAgZKysZCCsZGRkrKxkICAgICAgIKwgrCAgICAgrCBkZCAgICCsICCsICAgIKwgZCBkICAgrCAgZGQgICCsIKxkZCAgIKwgZKxkICAgrCAgIKwgICCsIGRkrCAgIKwgrKysICAgrCBkICBkICCsICBkIGQgIKwgICBkZCAgrCCsIGRkICCsIGRkZGQgIKwgIGSsZCAgrCAgICCsICCsIKysIKwgIKwgIGRkrCAgrCCsrKysICCsIGQgICBkIKwgIGQgIGQgrCAgIGQgZCCsIKwgZCBkIKwgZGRkIGQgrCBkIKwgZCCsICAgIGRkIKwgrCAgZGQgrCBkZCBkZCCsIGQgZGRkIKwgIGRkZGQgrCAgIKxkZCCsIGQgIKxkIKwgIGQgrGQgrCAgIGSsZCCsICAgICCsIKwgrKwgIKwgrCCsIKwgrCCsICCsrCCsIKwgrKysIKwgrCAgZCBkrCCsICAgZGSsIKwgIKwgrKwgrCCsrCCsrCCsICCsrKysIKwgZCAgICBkrCAgZCAgIGSsIKxkICAgZKwgZKwgICBkrCAgIGQgIGSsIGRkZCAgZKwgIKxkICBkrCBkIKwgIGSsICBkrCAgZKwgICAgZCBkrCCsICBkIGSsIGRkIGQgZKwgIKwgZCBkrCBkIGRkIGSsICBkZGQgZKwgICCsZCBkrCBkICCsIGSsICBkIKwgZKwgICBkrCBkrCAgICAgZGSsIGRkICBkZKwgIKwgIGRkrCBkIGQgZGSsICBkZCBkZKwgICCsIGRkrCBkICBkZGSsICBkIGRkZKwgICBkZGRkrCCsZKxkZGSsICAgIKxkZKwgZCAgIKxkrCAgZCAgrGSsICAgZCCsZKwgICAgZKxkrCBkrGRkrGSsICAgICAgrKwgZGQgICCsrCBkIGQgIKysICBkZCAgrKwgZCAgZCCsrCAgZCBkIKysICAgZGQgrKwgrKwgrCCsrCCsrKysIKysIGQgICBkrKwgIGQgIGSsrCAgIGQgZKysIGRkZKxkrKwgrKwgIKysrCCsIKwgrKysICBkrGSsrKwgIKwgrKysrCCsrCCsrKysIGQgICAgICBkIGQgICAgIGSsZCAgICAgZGSsICAgICBkICBkICAgIGSsIGQgICAgZGRkZCAgICBkIKxkICAgIGSsrGQgICAgZGQgrCAgICBkIGSsICAgIGSsZKwgICAgZCAgIGQgICBkrCAgZCAgIGRkZCBkICAgZCCsIGQgICBkrKwgZCAgIGRkIGRkICAgZCBkZGQgICBkrGRkZCAgIGRkrGRkICAgZCAgrGQgICBkrCCsZCAgIGRkZKxkICAgZGQgIKwgICBkIGQgrCAgIGQgIGSsICAgZGRkZKwgICBkIKxkrCAgIGRkIKysICAgZCBkrKwgICBkICAgIGQgIGSsICAgZCAgZGRkICBkICBkIKwgIGQgIGRkIGQgZCAgZCBkZCBkICBkrGRkIGQgIGRkrGQgZCAgZCAgrCBkICBkrCCsIGQgIGRkZKwgZCAgZGQgIGRkICBkIGQgZGQgIGSsZCBkZCAgZGSsIGRkICBkICBkZGQgIGSsIGRkZCAgZGRkZGRkICBkIKxkZGQgIGRkIKxkZCAgZCBkrGRkICBkICAgrGQgIGSsICCsZCAgZGRkIKxkICBkIKwgrGQgIGRkIGSsZCAgZCBkZKxkICBkICCsrGQgIGRkICAgrCAgZCBkICCsICBkICBkIKwgIGSsIGQgrCAgZGRkZCCsICBkIKxkIKwgIGQgZKwgrCAgZCAgIGSsICBkZGQgZKwgIGQgrCBkrCAgZGQgZGSsICBkIGRkZKwgIGQgIKxkrCAgZGQgIKysICBkIGQgrKwgIGQgICAgIGQgZKwgICAgZCBkZGQgICBkIGQgrCAgIGQgZKysICAgZCBkZCBkICBkIGQgZGQgIGQgZKxkZCAgZCBkZKxkICBkIGQgIKwgIGQgZKwgrCAgZCBkZGSsICBkIGQgrKwgIGQgZGQgIGQgZCBkIGQgZCBkIGSsZCBkIGQgZGSsIGQgZCBkICBkZCBkIGSsIGRkIGQgZGRkZGQgZCBkIKxkZCBkIGRkIKxkIGQgZCBkrGQgZCBkICAgrCBkIGSsICCsIGQgZGRkIKwgZCBkIKwgrCBkIGRkIGSsIGQgZCBkZKwgZCBkICCsrCBkIGRkICAgZGQgZCBkICBkZCBkrGQgIGRkIGRkrCAgZGQgZCAgZCBkZCBkrCBkIGRkIGRkZGQgZGQgZCCsZCBkZCBkZCCsIGRkIGQgZKwgZGQgZCAgIGRkZCBkrCAgZGRkIGRkZCBkZGQgZCCsIGRkZCBkZCBkZGRkIGQgZGRkZGQgZCAgrGRkZCBkrKysZGRkIGRkICCsZGQgZCBkIKxkZCBkICBkrGRkIGQgICAgrGQgZKwgICCsZCBkZGQgIKxkIGQgrCAgrGQgZGQgZCCsZCBkIGRkIKxkIGQgIKwgrGQgZGQgIGSsZCBkIGQgZKxkIGQgIGRkrGQgZCAgIKysZCBkZGSsrKxkIGRkICAgIKwgZCBkICAgrCBkZKwgICCsIGQgIGQgIKwgZKwgZCAgrCBkZGRkICCsIGQgrGQgIKwgZGQgrCAgrCBkIGSsICCsIGQgICBkIKwgZKwgIGQgrCBkZGQgZCCsIGQgrCBkIKwgZGQgZGQgrCBkIGRkZCCsIGQgIKxkIKwgZCBkIKwgrCBkICBkrCCsIGQgICAgZKwgZKwgICBkrCBkZGQgIGSsIGQgrCAgZKwgZGQgZCBkrCBkIGRkIGSsIGQgIKwgZKwgZGQgIGRkrCBkIGQgZGSsIGQgIGRkZKwgZCAgIKxkrCBkrGRkrGSsIGRkICAgrKwgZCBkICCsrCBkICBkIKysIGQgICBkrKwgZCAgICAgIGRkrCAgICAgZGRkZCAgICBkZCCsICAgIGRkZCBkICAgZGQgZGQgICBkZKxkZCAgIGRkZKxkICAgZGQgIKwgICBkZKwgrCAgIGRkZGSsICAgZGQgrKwgICBkZGQgIGQgIGRkIGQgZCAgZGSsZCBkICBkZGSsIGQgIGRkICBkZCAgZGSsIGRkICBkZGRkZGQgIGRkIKxkZCAgZGRkIKxkICBkZCBkrGQgIGRkICAgrCAgZGSsICCsICBkZGRkIKwgIGRkIKwgrCAgZGRkIGSsICBkZCBkZKwgIGRkZCAgIGQgZGQgZCAgZCBkZKxkICBkIGRkZKwgIGQgZGQgIGQgZCBkZKwgZCBkIGRkZGRkIGQgZGQgrGQgZCBkZGQgrCBkIGRkIGSsIGQgZGQgICBkZCBkZKwgIGRkIGRkZGQgZGQgZGQgrCBkZCBkZGQgZGRkIGRkIGRkZGQgZGQgIKxkZCBkZGQgIKxkIGRkIGQgrGQgZGQgIGSsZCBkZCAgICCsIGRkZGQgIKwgZGQgrCAgrCBkZGQgZCCsIGRkIGRkIKwgZGQgIKwgrCBkZGQgIGSsIGRkIGQgZKwgZGQgIGRkrCBkZGSsrGSsIGRkICAgrKwgZGRkICAgIGRkZCBkICAgZGRkrGQgICBkZGRkrCAgIGRkZCAgZCAgZGRkrCBkICBkZGRkZGQgIGRkZCCsZCAgZGRkZCCsICBkZGQgZKwgIGRkZCAgIGQgZGRkrCAgZCBkZGRkZCBkIGRkZCCsIGQgZGRkZCBkZCBkZGQgZGRkIGRkZCAgrGQgZGRkZCAgrCBkZGQgZCCsIGRkZCAgZKwgZGRkICAgIGRkZGSsICAgZGRkZGRkICBkZGRkIKwgIGRkZGRkIGQgZGRkZCBkZCBkZGRkICCsIGRkZGRkICBkZGRkZCBkIGRkZGRkICBkZGRkZGQgICCsZGRkZGQgICCsZGRkIGQgIKxkZGQgIGQgrGRkZKxkrCCsZGRkICAgZKxkZGQgICAgIKxkZKwgICAgrGRkZGQgICCsZGQgrCAgIKxkZGQgZCAgrGRkIGRkICCsZGQgIKwgIKxkZGQgIGQgrGRkIGQgZCCsZGQgIGRkIKxkZKysZGQgrGRkICAgrCCsZGRkICAgZKxkZCBkICBkrGRkICBkIGSsZGQgICBkZKxkZCAgICCsrGRkZKxkIKysZGRkZCCsrKxkZCCsrKysrGRkZCAgICAgrGQgZCAgICCsZKxkICAgIKxkICBkICAgrGSsIGQgICCsZGRkZCAgIKxkIKxkICAgrGRkIKwgICCsZCBkrCAgIKxkICAgZCAgrGRkZCBkICCsZCCsIGQgIKxkZCBkZCAgrGQgZGRkICCsZCAgrGQgIKxkIGQgrCAgrGQgIGSsICCsZCAgICBkIKxkrCAgIGQgrGRkZCAgZCCsZCCsICBkIKxkZCBkIGQgrGQgZGQgZCCsZCAgrCBkIKxkZCAgZGQgrGQgZCBkZCCsZCAgZGRkIKxkICAgrGQgrGRkrGSsZCCsZCBkICCsIKxkICBkIKwgrGQgICBkrCCsZKxkZGSsIKxkZCCsrKwgrGQgICAgIGSsZGRkICAgZKxkIKwgICBkrGRkIGQgIGSsZCBkZCAgZKxkICCsICBkrGRkICBkIGSsZCBkIGQgZKxkICBkZCBkrGQgICCsIGSsZGQgICBkZKxkIGQgIGRkrGQgIGQgZGSsZCAgIGRkZKxkrKwgZGRkrGQgrKxkZGSsZKwgZKxkZKxkICAgIKxkrGQgZGSsrGSsZGQgICAgrKxkIGQgICCsrGQgIGQgIKysZGRkrGQgrKxkIKxkrCCsrGQgICAgZKysZKysrCBkrKxkrCAgZKysrGRkIKysrKysZCAgICAgICCsrCAgICAgIKxkZCAgICAgrCCsICAgICCsZCBkICAgIKwgZGQgICAgrGSsZCAgICCsICCsICAgIKxkZKwgICAgrGQgIGQgICCsIGQgZCAgIKwgIGRkICAgrKwgZGQgICCsZGRkZCAgIKwgrGRkICAgrGQgrGQgICCsICAgrCAgIKxkZCCsICAgrGQgZKwgICCsIGRkrCAgIKxkICAgZCAgrCBkICBkICCsZKwgIGQgIKwgIGQgZCAgrKwgZCBkICCsZGRkIGQgIKwgrGQgZCAgrGQgrCBkICCsIGSsIGQgIKwgICBkZCAgrKwgIGRkICCsZGQgZGQgIKwgrCBkZCAgrGQgZGRkICCsIGRkZGQgIKxkICCsZCAgrCBkIKxkICCsICBkrGQgIKxkrKysZCAgrCAgICCsICCsZGQgIKwgIKysrCAgrCAgrGQgZCCsICCsIGRkIKwgIKxkICBkrCAgrCBkIGSsICCsICBkZKwgIKxkICAgIGQgrCBkICAgZCCsrGQgICBkIKxkrCAgIGQgrCAgZCAgZCCsrCBkICBkIKxkZGQgIGQgrCCsZCAgZCCsZCCsICBkIKwgICBkIGQgrKwgIGQgZCCsZGQgZCBkIKwgrCBkIGQgrGQgZGQgZCCsIGRkZCBkIKwgIKxkIGQgrGQgIKwgZCCsIGQgrCBkIKwgIGSsIGQgrCAgICBkZCCsrCAgIGRkIKxkZCAgZGQgrCCsICBkZCCsZCBkIGRkIKwgZGQgZGQgrCAgrCBkZCCsZCAgZGRkIKwgZCBkZGQgrCAgZGRkZCCsICAgrGRkIKysrCCsZGQgrGQgICCsZCCsIGQgIKxkIKwgIGQgrGQgrGSsrCCsZCCsICAgZKxkIKwgICAgIKwgrGRkICAgrCCsZCBkICCsIKwgZGQgIKwgrGQgIGQgrCCsIGQgZCCsIKwgIGRkIKwgrKwgrKwgrCCsZCAgIGSsIKwgZCAgZKwgrCAgIGRkrCCsZGSsZGSsIKysIKwgrKwgrCCsZGSsrCCsrKxkZKysIKysICCsrKwgrKwgrKysrCCsZCAgICAgZKwgZCAgICBkrGSsICAgIGSsICBkICAgZKysIGQgICBkrGRkZCAgIGSsIKxkICAgZKwgZKwgICBkrCAgIGQgIGSsrCAgZCAgZKxkZCBkICBkrCCsIGQgIGSsZCBkZCAgZKwgZGRkICBkrCAgrGQgIGSsZCAgrCAgZKwgZCCsICBkrCAgZKwgIGSsICAgIGQgZKxkZCAgZCBkrGQgZCBkIGSsIGRkIGQgZKxkICBkZCBkrCBkIGRkIGSsICBkZGQgZKysrGRkZCBkrGQgICCsIGSsIGQgIKwgZKwgIGQgrCBkrCAgIGSsIGSsrGSsrKwgZKwgICAgIGRkrKwgICAgZGSsZGQgICBkZKwgrCAgIGRkrGQgZCAgZGSsIGRkICBkZKwgIKwgIGRkrGQgIGQgZGSsIGQgZCBkZKwgIGRkIGRkrCAgIKwgZGSsrGRkrCBkZKxkICAgZGRkrCBkICBkZGSsICBkIGRkZKwgICBkZGRkrCCsZKxkZGSsZCCsrGRkZKwgICAgrGRkrKxkIGSsZGSsIGSsZKxkZKxkICAgIKxkrCBkICAgrGSsICBkICCsZKysZKwgIKxkrCAgIGQgrGSsZKysrCCsZKwgICAgZKxkrGSsIGRkrGSsrCBkZGSsZKwgIGSsrKxkrCAgICAgIKysZGQgICAgrKysrCAgICCsrCBkZCAgIKysrCCsICAgrKysrKwgICCsrGQgIGQgIKysIGQgZCAgrKwgIGRkICCsrKwgrKwgIKysrKysrCAgrKwgICBkZCCsrGRkrGRkIKysrCAgIKwgrKysrCAgrCCsrKwgrCCsIKysIKysIKwgrKysrKwgrCCsrKwgIKysIKysIKwgrKwgrKysrCCsrCCsrCCsrKysIKysZCAgICBkrKwgZCAgIGSsrCAgZCAgZKysICAgZCBkrKxkrCCsIGSsrCBkrKwgZKysICAgIGRkrKxkrGQgZGSsrGQgZGSsZKysrKwgICCsrKwgrKwgIKysrKwgrKwgrKysIGRkZGSsrKysZCCsZKysrCCsICCsrKysrKwgIKysrKwgIKwgrKysrKwgrCCsrKysIKysIKysrKwgrCCsrKysrKysrKysrKys=");
9
+ export const iq3xxs_grid = /* 1024B */ D("BAQEBBQEBAQkBAQEDAwEBBwMBAQ+DAQEBBQEBBQUBAQMHAQEFCQEBBw+BAQsPgQEDAQMBBwEDAQEDAwEFAwMBAwUDAQsFAwEBBwMBBQcDAQMJAwEJCwMBAQ+DAQEBBQEFAQUBCQEFAQMDBQEBBQUBBQUFAQMHBQEHBwUBD4cFAQMLBQEPiwUBCw+FAQMBBwEPgQcBAQMHAQUDBwELBQcBAQ+HAQcDCQEPhwkBCQkJAQ+LCQEHD4kBCw+JAQMBCwEPgQsBBQcLAQULCwELBw0BCQ0NAQEDD4EJAw+BDQMPgQcJD4EDDQ+BAwEBAwcBAQMBAwEDBQMBAwMFAQMHBQEDAQcBAwUHAQMJBwEDD4kBAwELAQMBAQMDBQEDAwMDAwMBBQMDBQUDAwMBBQMHAQUDAQMFAwUDBQMDBQUDAQcFAwUPhQMBAQcDBQEHAwEFBwMDBwcDDQkHAw0NBwMDAQkDCwEJAwELCQMBBQsDCQULAw0JCwMDD4sDCwENAwUFD4MBCQ+DAQEBBQUBAQUDAwEFBwMBBQEFAQUFBQEFDQUBBQMHAQUFCQEFAwEDBQcBAwULAQMFAQMDBQUDAwUDBQMFAQcDBQcNAwUPjQMFAQ+DBQEBBQUFAQUFAwMFBQ+DBQUBBQUFBQUFBQ+HBQUBCQUFCwsFBQMBBwUBAwcFCQMHBQEPhwUJD4cFCwcJBQcLCQUHAQsFD4ULBQMJCwUJD4sFAwEPhQcBD4UNAw+FCwkPhQMBAQcBAwEHBQMBBwMFAQcHBQEHAQsBBwsNAQcFD4EHAQEDBwUBAwcBBQMHAwcDBwkJAwcNCQMHAwEFBwcBBQcBAwUHCwUFBwULBQcFD4UHAwMHBwcHBwcBBwkHD4kJBwUPiQcBAQsHDQELBwUFCwcLCwsHCQMNBw0HDQcHDQ0HBwcPhwEND4cJAQEJD4MBCQsHAQkPhwEJBwsBCQ+LAQkJD4MJAQUFCQ+HBQkBCQUJAQ0FCQ0NBQkPgQcJCwkHCQkBCQkDCwkJCQ0JCQsFCwkHCQsJAQ+LCQsBD4kBAw+JBQMPiQEHD4kFAwELAwkBCwEPgQsBAQMLDQEDCw0FAwsLCwMLCQMFCwUHBQsFD4ULBQEHCwcLBwsBAwkLBwUJCw+FCQsFD4kLBQELCwMHCwsBCw0LCQUPiwUJD4sJBQENCQkBDQ0JAQ0JDQENAwUDDQMNAw0PgwUNCQ0FDQEHBw0NBwcNCQkJDQsBCw0FCwsNBwcNDQcBD40DBQ+NBwEBD4sBAQ+PgQEPgQMBD4UHAQ+FCwEPjQUDD4EJAw+FAwUPiwkFD4ULBQ+BAQcPiwMHD4cHBw+BDQcPgwUJD4MJCQ+BAQsPhQELD4kFCw+BBw0Pg==");
10
+ export const iq3s_grid = /* 2048B */ D("AQEBAQMBAQEFAQEBCwEBAQ8BAQEBAwEBAwMBAQUDAQEJAwEBDQMBAQEFAQEDBQEBCwUBAQcHAQEBCQEBBQkBAQsJAQEPCQEBAwsBAQcLAQEBDQEBBQ0BAQMPAQEJDwEBDw8BAQEBAwEDAQMBBQEDAQkBAwEBAwMBAwMDAQsDAwEBBQMBBwUDAQ8FAwEDBwMBCwcDAQkJAwEDDQMBCw0DAQUPAwEBAQUBAwEFAQsBBQEPAQUBAQMFAQcDBQENAwUBAwUFAQsFBQEBBwUBCQcFAQUJBQELCQUBDwkFAQMLBQEHCwUBAQ8FAQcPBQEHAQcBAwMHAQsDBwEBBQcBBQUHAQMHBwEHBwcBDQcHAQkJBwEBCwcBBQsHAQ8NBwEDDwcBCw8HAQEBCQEHAwkBDwMJAQMFCQEJBQkBBQcJAQEJCQEHCQkBAwsJAQEPCQEFAQsBCQELAQEFCwEFBQsBDQULAQcHCwEDCQsBCwkLAQ8JCwENDQsBBw8LAQ0BDQEDAw0BBwMNAQMHDQEFCw0BAw8NAQEBDwEFAQ8BCQEPAQEFDwEFBQ8BDQUPAQcHDwEBCw8BCQsPAQEBAQMDAQEDBQEBAwkBAQMBAwEDAwMBAwcDAQMLAwEDDwMBAwEFAQMFBQEDAwcBAwkHAQMNBwEDCQsBAw0LAQMDDQEDBQ8BAwEBAwMDAQMDBwEDAw0BAwMBAwMDCQMDAwMFAwMBBwMDBwcDAwMJAwMBCwMDBQsDAwEPAwMNDwMDAQEFAwUDBQMLAwUDDwMFAwEFBQMJBQUDBQcFAwEJBQMHCQUDCwsFAwENBQMFDwUDAwEHAwkBBwMPAQcDAQMHAwcDBwMDBQcDDwUHAwEHBwMJBwcDAwkHAwUNBwMBDwcDBwEJAwsBCQMFAwkDCQMJAwMHCQMHBwkDBQkJAw0JCQMBCwkDCQsJAwMBCwMBAwsDBwMLAwMFCwMBBwsDBQcLAwMLCwMBBQ0DCQUNAw8FDQMJCQ0DDQkNAwMBDwMHAQ8DAQMPAwUDDwMDBQ8DCwcPAwMJDwMFDQ8DAQ8PAwEBAQUDAQEFBwEBBQsBAQUPAQEFAQMBBQUDAQUJAwEFDQMBBQMFAQUHBQEFDwUBBQEHAQUFBwEFAwkBBQcJAQULCQEFAQsBBQULAQUPDQEFAQ8BBQcPAQULDwEFAQEDBQUBAwUBAwMFBwMDBQ8DAwUFBQMFCwUDBQMHAwUJBwMFBQkDBQMLAwUDAQUFCQEFBQ8BBQUDBQUFBwUFBQEHBQUPBwUFAwkFBQcLBQUPCwUFAw8FBQkPBQUBAQcFBQEHBQsBBwUDAwcFBQUHBQkFBwUDBwcFBwcHBQUJBwUBCwcFDQ0HBQMBCQUPAQkFAQUJBQcFCQUFBwkFCwcJBQMJCQUFDwkFCw8JBQkBCwUDAwsFBQULBQ8HCwUBCQsFBwsLBQEPCwUBAQ0FBQENBQ8BDQUDBQ0FCwsNBQMNDQULAQ8FAwMPBQ0FDwUBBw8FBwkPBQELDwUFAQEHAwMBBwcDAQcLAwEHDwMBBwUFAQcDBwEHBwcBBwsHAQcFCQEHCQkBBw8JAQcDCwEHBw0BBwMPAQcDAQMHBwEDBwsBAwcJAwMHAwUDBwcFAwcBCQMHAQ0DBwUPAwcNDwMHAQEFBwUDBQcBBQUHBQcFBwkHBQcBCwUHAwEHBwEDBwcJAwcHAwUHBwcFBwcPBQcHAQcHBwMJBwcHCQcHDwkHBwsLBwcHDwcHBwEJBwMDCQcNAwkHBQUJBwMHCQcFCwkHAQ0JBwkNCQcDAQsHAQMLBwUDCwcLBQsHBQcLBwkJCwcNCwsHBw8LBw0DDQcDCQ0HAwEPBwcBDwcBBQ8HBQUPBwsHDwcBAQEJCQEBCQUDAQkBBQEJCQUBCQ8FAQkFBwEJAwkBCQELAQkBDwEJBQEDCQ8BAwkDAwMJBwMDCQUFAwkBBwMJCwcDCQcJAwkDCwMJCwsDCQMBBQkHAQUJAQMFCQsDBQkDBQUJBwcFCQEJBQkPCwUJBQ0FCQEPBQkJAQcJAwMHCQcDBwkBBQcJBQUHCQMHBwkLBwcJAQEJCQUBCQkJBQkJDwcJCQEJCQkDDwkJCwELCQ8BCwkDBQsJBQ0LCQcDDQkJBw0JAQ0NCQEDDwkLAw8JAQcPCQcJDwkDCw8JBQEBCwEDAQsJAwELBQUBCwEJAQsJCQELDwkBCwULAQsNDQELCQ8BCwMBAwsHAQMLCwEDCwUDAwsDBQMLBQcDCwUPAwsBAQULAwMFCwcFBQsBBwULDQcFCwcLBQsFAQcLDwEHCwEDBwsPBQcLCQkHCwMLBwsLDQcLBw8HCwMBCQsJAQkLAQUJCwUHCQsNCQkLBQMLCw0FCwsDCwsLBwsLCwUJDQsFAQ8LCQEPCwUFDwsDAwENBwMBDQsDAQ0DBwENBwcBDQENAQ0BAQMNAQUDDQ8FAw0JDQMNBQMFDQkHBQ0FCQUNCwsFDQUNBQ0BDwUNAQEHDQkDBw0DBQcNAQkHDQsFCQ0HCQkNBQ0JDQEBCw0HAQsNCQcLDQENCw0LAQ0NAQkNDQMDDw0HAw8NAQEBDwkBAQ8PAQEPAQUBDwUFAQ8NBwEPAQkBDwkLAQ8FDQEPBQEDDwMDAw8JBQMPBwkDDwsJAw8DAQUPCQEFDwEDBQ8NAwUPAwUFDwEHBQ8DCwUPBQEHDwUHBw8LBwcPBwsHDwMBCQ8LAQkPBwMJDwEFCQ8BCwkPBQULDwUJCw8FAQ0PAwcNDwEBDw8=");
11
+ export const iq1s_grid = /* 16384B */ D("//////////8B/////////wAA/////////wH///////8BAf///////wD/AP//////AAAA/////////wH//////wH/Af///////wEB//////8BAQH//////wAA/wD/////AP8AAP//////AAAA/////wEAAAD/////AAABAP////////8B/////wH//wH//////wH/Af////8BAf8B/////wAAAAH///////8BAf////8B/wEB//////8BAQH/////AQEBAf//////AP//AP///wAA//8A////AP8A/wD/////AAD/AP///wEAAP8A////AAEA/wD///8BAQD/AP///wAAAf8A////AP//AAD///8BAP8AAP///wAB/wAA////Af8AAAD///8AAAAAAP///wEBAAAA////AP8BAAD/////AAEAAP///wEAAQAA/////wEBAAD///8AAP8BAP///wD/AAEA/////wAAAQD///8BAAABAP///wAAAQEA/////////wH///8B////Af////8B//8B////AQH//wH///8AAAD/Af//////Af8B////Af8B/wH/////AQH/Af///wEBAf8B////AAD/AAH///8A/wAAAf///wABAAAB/////wABAAH///8AAQEAAf///////wEB////Af//AQH/////Af8BAf///wEB/wEB////AP8AAQH///8AAAABAf///wABAAEB//////8BAQH///8B/wEBAf////8BAQEB////AQEBAQH///8A/wD//wD///8AAP//AP//AQAA//8A//8AAAH//wD//wD//wD/AP//AAH/AP8A//8AAAAA/wD//wEBAAD/AP///wABAP8A//8AAAEA/wD//wD/AAH/AP//AAEAAf8A//8AAAEB/wD//wD///8AAP///wD//wAA//8AAP//AAD//wEA//8AAP//AAAA/wAA////AQD/AAD//wEBAP8AAP//AAEB/wAA//////8AAAD//wAA/wAAAP//AQH/AAAA/////wAAAAD//wD/AAAAAP///wAAAAAA//8AAAAAAAD//wEAAAAAAP//AAEAAAAA/////wEAAAD//wH/AQAAAP//AAABAAAA////AQEAAAD//wEBAQAAAP//AP//AQAA//8A/wABAAD//wAAAAEAAP///wEAAQAA//8BAQABAAD//wD/AQEAAP///wABAQAA//8AAAEBAAD//wEAAQEAAP//AAEBAQAA////AAD/AQD//wABAP8BAP//AP//AAEA////AP8AAQD/////AAABAP//Af8AAAEA//8AAAAAAQD///8BAAABAP////8BAAEA//8A/wEAAQD//wEAAQABAP//AAEBAAEA//8AAP8BAQD//wD/AAEBAP///wAAAQEA//8AAQABAQD/////////Af//Af////8B////Af///wH//wEB////Af//AAAA//8B/////wH//wH//wH/Af//Af///wEB//8B//8BAQH//wH//wAA/wD/Af//AP8AAP8B//8BAAAA/wH//wAAAQD/Af//////Af8B//8B//8B/wH///8B/wH/Af//AQH/Af8B//8AAAAB/wH/////AQH/Af//Af8BAf8B////AQEB/wH//wEBAQH/Af//AAD//wAB//8A/wD/AAH///8AAP8AAf//AAEA/wAB////AAH/AAH//wAAAf8AAf//AP//AAAB/////wAAAAH//wD/AAAAAf//AAAAAAAB//8A/wEAAAH///8AAQAAAf//AAEBAAAB//8A/wABAAH///8AAAEAAf//AQAAAQAB//8AAQABAAH//wAAAQEAAf///////wEB//8B////AQH///8B//8BAf//AQH//wEB//8AAAD/AQH/////Af8BAf//Af8B/wEB////AQH/AQH//wEBAf8BAf//AAD/AAEB//8A/wAAAQH//wABAAABAf//AP8BAAEB//8AAAEAAQH//////wEBAf//Af//AQEB//8AAP8BAQH///8B/wEBAf//AQH/AQEB//8AAAABAQH/////AQEBAf//Af8BAQEB////AQEBAQH//wEBAQEBAf////8A////AP8A/wD///8A//8AAP///wD/AAEA////AP//AAH///8A/wAAAf///wD/AP//AP//AP//AP8A//8A////AAD//wD/AAAAAP//AP//AQAA//8A/wD/AQD//wD//wABAP//AP8AAAEA//8A/wABAQD//wD/AP8AAf//AP//AAAB//8A/wEAAAH//wD/AP8BAf//AP8AAAEB//8A/wD///8A/wD//wD//wD/AP8BAP//AP8A/wAB//8A/wD///8A/wD/AP8B/wD/AP8A/wAAAP8A/wD//wEA/wD/AP8A/wH/AP8A//8AAf8A/wD/AAEB/wD/AP8AAP8AAP8A/wEB/wAA/wD///8AAAD/AP8A/wAAAP8A/wH/AAAA/wD//wAAAAD/AP8AAAAAAP8A/wEAAAAA/wD/AAEAAAD/AP///wEAAP8A/wAAAQAA/wD//wD/AQD/AP8B/wABAP8A/wAAAAEA/wD/AP8BAQD/AP//AAEBAP8A/wD/AP8B/wD//wAA/wH/AP8BAAD/Af8A/wAAAf8B/wD/////AAH/AP8BAP8AAf8A/wAB/wAB/wD/Af8AAAH/AP8AAAAAAf8A//8BAAAB/wD/AQEAAAH/AP//AAEAAf8A/wEAAQAB/wD/AAD/AQH/AP8A/wABAf8A//8AAAEB/wD/AQAAAQH/AP8AAAEBAf8A/wD/////AAD/AQD///8AAP8AAf///wAA//8AAP//AAD/AAAA//8AAP//AQD//wAA/wABAP//AAD/AP8B//8AAP8BAAH//wAA/wD//wD/AAD/AAD/AP8AAP8BAP8A/wAA//8B/wD/AAD/AQH/AP8AAP8A/wAA/wAA//8AAAD/AAD/AAAAAP8AAP8BAAAA/wAA/wABAAD/AAD/Af8BAP8AAP8AAAEA/wAA//8BAQD/AAD//wD/Af8AAP8AAf8B/wAA////AAH/AAD//wAAAf8AAP8AAAAB/wAA//8BAAH/AAD/AAEAAf8AAP8BAQAB/wAA/wD/AQH/AAD//wABAf8AAP8AAAEB/wAA/wABAQH/AAD/Af///wAAAP8AAP//AAAA/wEB//8AAAD/AP8A/wAAAP//AAD/AAAA/wAAAP8AAAD/AQAA/wAAAP8AAQD/AAAA////Af8AAAD/Af8B/wAAAP8AAAH/AAAA//8BAf8AAAD/AQEB/wAAAP8A//8AAAAA//8A/wAAAAD/AAD/AAAAAP8BAP8AAAAA/wD/AAAAAAD/Af8AAAAAAP//AAAAAAAA/wAAAAAAAAD/AQAAAAAAAP8AAQAAAAAA/wEBAAAAAAD/AP8BAAAAAP//AAEAAAAA/wAAAQAAAAD/AQABAAAAAP8AAQEAAAAA/////wEAAAD/Af//AQAAAP//AP8BAAAA/wAA/wEAAAD//wH/AQAAAP8BAf8BAAAA////AAEAAAD/AP8AAQAAAP//AAABAAAA/wAAAAEAAAD/AQAAAQAAAP8AAQABAAAA/wEBAAEAAAD///8BAQAAAP8B/wEBAAAA/wAAAQEAAAD/AP///wEAAP//AP//AQAA/wAA//8BAAD/AQD//wEAAP8AAAD/AQAA/wEAAP8BAAD//wEA/wEAAP8BAQD/AQAA/wD/Af8BAAD/AQAB/wEAAP////8AAQAA/wH//wABAAD//wD/AAEAAP8AAP8AAQAA//8B/wABAAD/AQH/AAEAAP8A/wAAAQAA/wAAAAABAAD/AQAAAAEAAP//AQAAAQAA/wABAAABAAD/AP8BAAEAAP//AAEAAQAA/wAAAQABAAD//wEBAAEAAP8AAQEAAQAA/wEBAQABAAD/AQD/AQEAAP8BAf8BAQAA/wH/AAEBAAD/AAAAAQEAAP//AAEBAQAA/wABAQEBAAD/AP8A//8BAP8BAAD//wEA/wAAAf//AQD/AP//AP8BAP//AP8A/wEA/wEA/wD/AQD/AAH/AP8BAP///wAA/wEA/wAAAAD/AQD//wEAAP8BAP8BAQAA/wEA////AQD/AQD/AP8BAP8BAP//AAEA/wEA/wEAAQD/AQD/AAEBAP8BAP8AAP8B/wEA/wD/AAH/AQD//wAAAf8BAP8AAAEB/wEA////AP8AAQD/Af8A/wABAP8AAAD/AAEA/wEBAP8AAQD/AP8B/wABAP8AAAH/AAEA/wH//wAAAQD//wD/AAABAP8AAP8AAAEA//8B/wAAAQD/AP8AAAABAP//AAAAAAEA/wAAAAAAAQD/AQAAAAABAP8AAQAAAAEA/wEBAAAAAQD///8BAAABAP8AAAEAAAEA/wEBAQAAAQD/AAH/AQABAP8A/wABAAEA/wH/AAEAAQD/AAAAAQABAP//AQABAAEA/wD/AQEAAQD/AQABAQABAP8AAQEBAAEA/wAB//8BAQD/AQAA/wEBAP//AAH/AQEA/wEAAf8BAQD//wD/AAEBAP8BAP8AAQEA/wAB/wABAQD///8AAAEBAP8B/wAAAQEA/wAAAAABAQD//wEAAAEBAP8A/wEAAQEA/wEAAQABAQD/AAEBAAEBAP8AAP8BAQEA/wD/AAEBAQD/AQAAAQEBAP8BAQABAQEA/////////wH/Af//////Af//Af////8B/wEB/////wH/AAAA////Af///wH///8B/wH/Af///wH/AAAB////Af//AQH///8B/wEBAf///wH/AAD/AP//Af8A/wAA//8B/wABAAD//wH/AP8BAP//Af8AAAEA//8B/////wH//wH/Af//Af//Af//Af8B//8B/wEB/wH//wH/AAAAAf//Af///wEB//8B/wH/AQH//wH/AAABAf//Af//AQEB//8B/wEBAQH//wH/AAD//wD/Af8A/wD/AP8B//8AAP8A/wH/AAEA/wD/Af8AAAH/AP8B/wH//wAA/wH//wD/AAD/Af8AAf8AAP8B/wAAAAAA/wH//wEAAAD/Af8BAQAAAP8B/wD/AQAA/wH//wABAAD/Af8AAAEAAP8B/wEAAQAA/wH/AAD/AQD/Af///wABAP8B/wEAAAEA/wH/AAEAAQD/Af8AAAEBAP8B/wD///8B/wH//wH//wH/Af8BAf//Af8B/wD/AP8B/wH/AAAA/wH/Af///wH/Af8B/wH/Af8B/wH//wEB/wH/Af8BAQH/Af8B/wAA/wAB/wH/AP8AAAH/Af8BAAAAAf8B/wABAAAB/wH/AAABAAH/Af8A//8BAf8B//8B/wEB/wH/AQH/AQH/Af8A/wABAf8B/wAAAAEB/wH///8BAQH/Af8B/wEBAf8B//8BAQEB/wH/AQEBAQH/Af8AAP///wAB//8AAP//AAH/AQAA//8AAf8AAQD//wAB/wAAAf//AAH//wD/AP8AAf8AAP8A/wAB/wEA/wD/AAH/AAH/AP8AAf8B/wAA/wAB/wAAAAD/AAH//wEAAP8AAf8BAQAA/wAB/wEAAQD/AAH/AAD/Af8AAf8A/wAB/wAB//8AAAH/AAH/AAEAAf8AAf8A/wEB/wAB/wAAAQH/AAH/AAH//wAAAf8AAAD/AAAB/wD/Af8AAAH/AAEB/wAAAf////8AAAAB/wAA/wAAAAH//wH/AAAAAf8A/wAAAAAB//8AAAAAAAH/AAAAAAAAAf8AAQAAAAAB/wH/AQAAAAH/AAABAAAAAf//AQEAAAAB/wAB/wEAAAH///8AAQAAAf//AAABAAAB/wAAAAEAAAH//wEAAQAAAf8BAQABAAAB/wD/AQEAAAH//wABAQAAAf8BAAEBAAAB/wABAQEAAAH/AAD//wEAAf///wD/AQAB/wH/AP8BAAH/AAEA/wEAAf8AAAH/AQAB/wD//wABAAH/AAH/AAEAAf8AAAAAAQAB////AQABAAH/AP8BAAEAAf8AAQEAAQAB//8A/wEBAAH/AQD/AQEAAf///wABAQAB/wEBAAEBAAH///////8BAf8B/////wEB//8B////AQH/AQH///8BAf8AAAD//wEB////Af//AQH/Af8B//8BAf//AQH//wEB/wEBAf//AQH/AAD/AP8BAf8A/wAA/wEB//8AAAD/AQH/AAABAP8BAf////8B/wEB/wH//wH/AQH//wH/Af8BAf8BAf8B/wEB////AQH/AQH/Af8BAf8BAf//AQEB/wEB/wEBAQH/AQH/AAH//wABAf8A/wD/AAEB//8AAP8AAQH/AAEA/wABAf8AAAH/AAEB/wEA/wAAAQH/AAH/AAABAf8B/wAAAAEB/wAAAAAAAQH/AP8BAAABAf//AAEAAAEB/wEAAQAAAQH/AAEBAAABAf8AAP8BAAEB////AAEAAQH/AQAAAQABAf8AAQABAAEB//8AAQEAAQH/AAABAQABAf//////AQEB/wH///8BAQH//wH//wEBAf8BAf//AQEB////Af8BAQH/Af8B/wEBAf//AQH/AQEB/wEBAf8BAQH/AAD/AAEBAf8A/wAAAQEB/wEAAAABAQH/AAEAAAEBAf8AAAEAAQEB/////wEBAQH/Af//AQEBAf//Af8BAQEB/wEB/wEBAQH/AAAAAQEBAf///wEBAQEB/wH/AQEBAQH//wEBAQEBAf8BAQEBAQEB/wAA//////8AAP8A/////wABAAD/////AAAAAf////8AAAH/AP///wAB/wAA////AAAAAAD///8A/wEAAP///wABAQAA////AAD/AQD///8A/wABAP///wABAAEA////AP8AAAH///8AAAEAAf///wAA/wEB////AAEAAQH///8A/////wD//wAA////AP//AP8A//8A//8AAQD//wD//wAAAf//AP//AAH/AP8A//8AAAAA/wD//wABAAD/AP//AP8BAP8A//8AAQEA/wD//wAA/wH/AP//AAEAAf8A//8AAAEB/wD//wAAAP8AAP//AP8B/wAA//8AAQH/AAD//wAA/wAAAP//AP8AAAAA//8AAAAAAAD//wABAAAAAP//AAABAAAA//8AAQEAAAD//wAAAAEAAP//AP8BAQAA//8AAQEBAAD//wAA//8BAP//AP8A/wEA//8AAQD/AQD//wD//wABAP//AAH/AAEA//8AAAAAAQD//wD//wEBAP//AAD/AQEA//8AAf8BAQD//wAAAP//Af//AAD/AP8B//8A/wAA/wH//wABAAD/Af//AAAAAf8B//8AAP//AAH//wAB/wAAAf//AAAAAAAB//8AAQEAAAH//wD/AAEAAf//AAABAQAB//8AAAH/AQH//wD/AAABAf//AAAAAQEB//8AAP////8A/wAAAAD//wD/AAABAP//AP8AAAEB//8A/wAAAP8A/wD/AP8B/wD/AP8AAQH/AP8A/wAA/wAA/wD/AP8AAAD/AP8AAAAAAP8A/wABAAAA/wD/AAD/AQD/AP8AAf8BAP8A/wAAAAEA/wD/AP8BAQD/AP8AAQEBAP8A/wAA//8B/wD/AAEA/wH/AP8AAAH/Af8A/wD//wAB/wD/AAH/AAH/AP8AAAAAAf8A/wD//wEB/wD/AAD/AQH/AP8AAAEBAf8A/wAA////AAD/AAH///8AAP8AAAD//wAA/wABAf//AAD/AAD/AP8AAP8A/wAA/wAA/wAAAAD/AAD/AAEAAP8AAP8AAAEA/wAA/wD//wH/AAD/AAAAAf8AAP8AAQEB/wAA/wAA//8AAAD/AP8A/wAAAP8AAAD/AAAA/wABAP8AAAD/AAAB/wAAAP8A//8AAAAA/wAA/wAAAAD/AP8AAAAAAP8AAAAAAAAA/wABAAAAAAD/AP8BAAAAAP8AAAEAAAAA/wAA/wEAAAD/AP8AAQAAAP8AAAABAAAA/wABAAEAAAD/AAABAQAAAP8AAf//AQAA/wD/AP8BAAD/AAAA/wEAAP8A/wH/AQAA/wAA/wABAAD/AP8AAAEAAP8AAAAAAQAA/wABAAABAAD/AAABAAEAAP8AAQEAAQAA/wAAAAEBAAD/AP8BAQEAAP8AAQEBAQAA/wAA////AQD/AAAA//8BAP8AAAH//wEA/wD/AAD/AQD/AAAAAP8BAP8A/wEA/wEA/wABAQD/AQD/AAD/Af8BAP8A/wAB/wEA/wAAAQH/AQD/AP///wABAP8AAf//AAEA/wAAAP8AAQD/AP8B/wABAP8A//8AAAEA/wAA/wAAAQD/AAH/AAABAP8AAAAAAAEA/wABAAAAAQD/AAABAAABAP8AAf8BAAEA/wAAAAEAAQD/AP8BAQABAP8AAP//AQEA/wAAAP8BAQD/AAEB/wEBAP8A/wAAAQEA/wAAAAABAQD/AAD/AQEBAP8A/wABAQEA/wABAAEBAQD/AAAA////Af8AAP8A//8B/wAAAAD//wH/AAEBAP//Af8AAAAB//8B/wAB//8A/wH/AAAB/wD/Af8A//8AAP8B/wAAAAAA/wH/AP8BAAD/Af8AAP8BAP8B/wD/AAEA/wH/AAEAAQD/Af8AAAEBAP8B/wAAAP8B/wH/AAD/AAH/Af8A/wAAAf8B/wABAAAB/wH/AAABAAH/Af8AAAABAf8B/wAA////AAH/AAAA//8AAf8AAQD//wAB/wABAf//AAH/AP//AP8AAf8A/wAA/wAB/wAAAAD/AAH/AP8BAP8AAf8AAP8B/wAB/wD/AAH/AAH/AAEAAf8AAf8A////AAAB/wAAAP8AAAH/AAEB/wAAAf8AAP8AAAAB/wAB/wAAAAH/AP8AAAAAAf8AAAAAAAAB/wABAAAAAAH/AAABAAAAAf8A//8BAAAB/wAB/wEAAAH/AAAAAQAAAf8AAQABAAAB/wABAQEAAAH/AAEA/wEAAf8AAAH/AQAB/wAB/wABAAH/AAAAAAEAAf8AAQAAAQAB/wD/AQABAAH/AAD/AQEAAf8A/wABAQAB/wABAAEBAAH/AAABAQEAAf8AAQAA/wEB/wD/AP8AAQH/AAEA/wABAf8AAAH/AAEB/wAAAAAAAQH/AP8BAAABAf8AAQEAAAEB/wD/AAEAAQH/AAABAQABAf8A/wAAAQEB/wAAAAEBAQH/AAD//////wAA/wD/////AAAAAP////8AAAEA/////wAAAAH/////AAAB/wD///8AAAAAAP///wAAAQEA////AAAA/wH///8AAP8AAf///wAAAAEB////AAD///8A//8AAAAA/wD//wAA/wH/AP//AAAA/wAA//8AAP8AAAD//wAAAAAAAP//AAABAAAA//8AAAABAAD//wAAAAABAP//AAD/AQEA//8AAAEA/wH//wAAAAH/Af//AAAAAAAB//8AAP8BAAH//wAA//8BAf//AAAA/wEB//8AAAEAAQH//wAAAAEBAf//AAAAAP//AP8AAP8B//8A/wAAAAH//wD/AAABAf//AP8AAAD/AP8A/wAA/wAA/wD/AAAAAAD/AP8AAAEAAP8A/wAA/wEA/wD/AAAAAQD/AP8AAP//Af8A/wAAAAAB/wD/AAABAAH/AP8AAP8BAf8A/wAAAQEB/wD/AAAA//8AAP8AAP8A/wAA/wAAAAD/AAD/AAABAP8AAP8AAAAB/wAA/wAA//8AAAD/AAAA/wAAAP8AAAH/AAAA/wAA/wAAAAD/AAAAAAAAAP8AAAEAAAAA/wAA/wEAAAD/AAAAAQAAAP8AAAEBAAAA/wAAAP8BAAD/AAD/AAEAAP8AAAAAAQAA/wAAAQABAAD/AAAAAQEAAP8AAAH//wEA/wAAAAD/AQD/AAAA/wABAP8AAP8AAAEA/wAAAAAAAQD/AAABAAABAP8AAAABAAEA/wAA//8BAQD/AAAAAAEBAP8AAAEBAQEA/wAAAP///wH/AAABAP//Af8AAAH/AP8B/wAAAAAA/wH/AAABAQD/Af8AAAD/Af8B/wAA/wAB/wH/AAAB//8AAf8AAAAA/wAB/wAAAQH/AAH/AAAA/wAAAf8AAP8AAAAB/wAAAAAAAAH/AAABAAAAAf8AAAABAAAB/wAAAf8BAAH/AAAAAAEAAf8AAAAA/wEB/wAA//8AAQH/AAAB/wABAf8AAAAAAAEB/wAAAAEAAQH/AAABAQABAf8AAP8AAQEB/wAA/wD///8AAAAAAP///wAAAAD/AP//AAAA/wAA//8AAAAAAAD//wAAAAEAAP//AAAA/wEA//8AAAAAAQD//wAAAAD/Af//AAAAAAAB//8AAAD/AQH//wAAAAEBAf//AAAAAP//AP8AAAD/AP8A/wAAAAAA/wD/AAAAAQD/AP8AAAAAAf8A/wAAAAEB/wD/AAAA//8AAP8AAAAA/wAA/wAAAP8AAAD/AAAAAAAAAP8AAAABAAAA/wAAAP8BAAD/AAAAAAEAAP8AAAABAQAA/wAAAAD/AQD/AAAAAf8BAP8AAAD/AAEA/wAAAAAAAQD/AAAAAQABAP8AAAAAAQEA/wAAAP///wH/AAAA/wH/Af8AAAABAf8B/wAAAAD/AAH/AAAA/wAAAf8AAAAAAAAB/wAAAAEAAAH/AAAAAAEAAf8AAAAA/wEB/wAAAP8AAQH/AAAAAAABAf8AAAABAQEB/wAAAAD///8AAAAAAf///wAAAAD/AP//AAAAAAAA//8AAAAAAQD//wAAAAAAAf//AAAAAP//AP8AAAAAAP8A/wAAAAAB/wD/AAAAAP8AAP8AAAAAAAAA/wAAAAABAAD/AAAAAAABAP8AAAAAAQEA/wAAAAAA/wH/AAAAAP8AAf8AAAAAAAAB/wAAAAABAAH/AAAAAAABAf8AAAAA////AAAAAAAA//8AAAAAAAH//wAAAAAA/wD/AAAAAAAAAP8AAAAAAAEA/wAAAAAA/wH/AAAAAAAAAf8AAAAAAP//AAAAAAAAAP8AAAAAAAAB/wAAAAAAAP8AAAAAAAAAAAAAAAAAAAABAAAAAAAAAP8BAAAAAAAAAAEAAAAAAAABAQAAAAAAAP//AQAAAAAAAP8BAAAAAAD/AAEAAAAAAAAAAQAAAAAAAQABAAAAAAD/AQEAAAAAAAABAQAAAAAAAQEBAAAAAAAA//8BAAAAAP8A/wEAAAAAAAD/AQAAAAAAAf8BAAAAAAEB/wEAAAAA//8AAQAAAAAA/wABAAAAAP8AAAEAAAAAAAAAAQAAAAABAAABAAAAAP8BAAEAAAAAAAEAAQAAAAAA/wEBAAAAAP8AAQEAAAAAAAABAQAAAAABAAEBAAAAAAABAQEAAAAA/////wEAAAAA////AQAAAAH///8BAAAA/wD//wEAAAABAP//AQAAAP8B//8BAAAAAAH//wEAAAAA/wD/AQAAAP8AAP8BAAAAAAAA/wEAAAD/AQD/AQAAAAABAP8BAAAA//8B/wEAAAAA/wH/AQAAAAH/Af8BAAAA/wAB/wEAAAAAAAH/AQAAAAEAAf8BAAAA/wEB/wEAAAAAAQH/AQAAAAD//wABAAAAAAD/AAEAAAABAP8AAQAAAP8B/wABAAAAAAH/AAEAAAABAf8AAQAAAP//AAABAAAAAP8AAAEAAAAB/wAAAQAAAP8AAAABAAAAAAAAAAEAAAABAAAAAQAAAP8BAAABAAAAAAEAAAEAAAABAQAAAQAAAAD/AQABAAAA/wABAAEAAAAAAAEAAQAAAAABAQABAAAAAf//AQEAAAAAAP8BAQAAAAEA/wEBAAAA/wH/AQEAAAAAAf8BAQAAAAEB/wEBAAAAAP8AAQEAAAAAAAABAQAAAAEBAAEBAAAAAf8BAQEAAAAAAAEBAQAAAAEAAQEBAAAA/wEBAQEAAAAAAQEBAQAAAP8A////AQAAAAD///8BAAABAP///wEAAAAB////AQAA//8A//8BAAAAAAD//wEAAP8BAP//AQAAAP8B//8BAAABAQH//wEAAAAA/wD/AQAA/wH/AP8BAAABAf8A/wEAAAD/AAD/AQAA/wAAAP8BAAAAAAAA/wEAAAEAAAD/AQAA/wEAAP8BAAAAAQAA/wEAAP//AQD/AQAAAf8BAP8BAAD/AAEA/wEAAAAAAQD/AQAAAf//Af8BAAAAAf8B/wEAAP//AAH/AQAAAf8AAf8BAAAAAAAB/wEAAP8BAAH/AQAAAP8BAf8BAAAAAQEB/wEAAAD///8AAQAAAf///wABAAAAAP//AAEAAAEB//8AAQAAAP8A/wABAAD/AAD/AAEAAAAAAP8AAQAAAQAA/wABAAAAAQD/AAEAAAAAAf8AAQAAAP//AAABAAD/AP8AAAEAAAAA/wAAAQAAAQD/AAABAAAAAf8AAAEAAP//AAAAAQAAAP8AAAABAAAB/wAAAAEAAP8AAAAAAQAAAAAAAAABAAABAAAAAAEAAP8BAAAAAQAAAAEAAAABAAABAQAAAAEAAAD/AQAAAQAA/wABAAABAAAAAAEAAAEAAAEAAQAAAQAAAAEBAAABAAAA//8BAAEAAAAA/wEAAQAAAAH/AQABAAAA/wABAAEAAP8AAAEAAQAAAAAAAQABAAABAAABAAEAAP8BAAEAAQAAAAEAAQABAAAAAAEBAAEAAP8A//8BAQAA/wH//wEBAAAAAAD/AQEAAAEBAP8BAQAA//8B/wEBAAAAAAH/AQEAAAEAAf8BAQAAAAEB/wEBAAAAAP8AAQEAAP8B/wABAQAAAAH/AAEBAAAA/wAAAQEAAAAAAAABAQAAAQAAAAEBAAD/AQAAAQEAAAABAAABAQAAAf8BAAEBAAAAAAEAAQEAAP8BAQABAQAAAQEBAAEBAAAA//8BAQEAAAEB/wEBAQAAAf8AAQEBAAAAAAABAQEAAAEAAAEBAQAA/wEAAQEBAAABAQABAQEAAAD/AQEBAQAAAAD/////AQD/AAD///8BAAEAAP///wEAAAEA////AQAAAAH///8BAP8A/wD//wEA//8AAP//AQAAAAAA//8BAAEAAAD//wEA/wEAAP//AQABAQAA//8BAAD/AQD//wEA/wABAP//AQABAAEA//8BAAABAQD//wEAAP//Af//AQABAAAB//8BAAAAAQH//wEAAP///wD/AQD/AP//AP8BAAEA//8A/wEAAAH//wD/AQAB/wD/AP8BAAAAAP8A/wEAAP8B/wD/AQAB/wH/AP8BAAEAAf8A/wEAAAEB/wD/AQAAAP8AAP8BAAAB/wAA/wEAAP8AAAD/AQAAAAAAAP8BAAEAAAAA/wEAAAEAAAD/AQAAAAEAAP8BAAEAAQAA/wEAAQEBAAD/AQD/AP8BAP8BAAEB/wEA/wEAAf8AAQD/AQAAAAABAP8BAAD/AQEA/wEAAQABAQD/AQAAAQEBAP8BAAD/AP8B/wEAAQAA/wH/AQAAAQD/Af8BAP///wAB/wEAAP//AAH/AQABAP8AAf8BAAAAAAAB/wEAAQAAAAH/AQD/AQAAAf8BAP//AQAB/wEAAAD/AQH/AQAA/wABAf8BAAEAAAEB/wEAAAABAQH/AQAA/wD//wABAAH/AP//AAEAAAAA//8AAQABAAD//wABAAEBAP//AAEAAP8B//8AAQABAAH//wABAAABAf//AAEA////AP8AAQAB//8A/wABAAAA/wD/AAEA/wH/AP8AAQABAf8A/wABAAD/AAD/AAEA/wAAAP8AAQAAAAAA/wABAAEAAAD/AAEAAAEAAP8AAQABAQAA/wABAP//AQD/AAEAAf8BAP8AAQAAAAEA/wABAP8A/wH/AAEAAAD/Af8AAQAAAf8B/wABAP//AAH/AAEAAf8AAf8AAQD/AAAB/wABAAAAAAH/AAEAAQAAAf8AAQD/AQAB/wABAAEBAAH/AAEAAP8BAf8AAQD/AAEB/wABAAABAQH/AAEAAAD//wAAAQD/Af//AAABAAEB//8AAAEAAP8A/wAAAQAAAAD/AAABAAEAAP8AAAEAAAEA/wAAAQD/AP8AAAABAAAA/wAAAAEAAQD/AAAAAQAAAf8AAAABAP//AAAAAAEAAP8AAAAAAQD/AAAAAAABAAAAAAAAAAEAAQAAAAAAAQAAAQAAAAABAAD/AQAAAAEA/wABAAAAAQAAAAEAAAABAAEAAQAAAAEAAAEBAAAAAQABAP8BAAABAAAB/wEAAAEAAQH/AQAAAQAA/wABAAABAAAAAAEAAAEAAQAAAQAAAQAAAQABAAABAAEBAAEAAAEAAf8BAQAAAQAAAAEBAAABAAEAAQEAAAEA/wEBAQAAAQAB////AQABAAAB//8BAAEAAAAA/wEAAQD//wH/AQABAAEAAf8BAAEA/wEB/wEAAQAAAQH/AQABAP///wABAAEAAAD/AAEAAQD/Af8AAQABAAEB/wABAAEAAP8AAAEAAQD/AAAAAQABAAAAAAABAAEAAQAAAAEAAQD/AQAAAQABAAEBAAABAAEA//8BAAEAAQAAAAEAAQABAP8BAQABAAEA////AQEAAQAB//8BAQABAAAA/wEBAAEAAQH/AQEAAQD/AAABAQABAAEAAAEBAAEA/wEAAQEAAQAAAQABAQABAP//AQEBAAEA/wABAQEAAQABAAEBAQABAAEBAQEBAAEAAQAA//8BAQAAAQD//wEBAAAAAf//AQEAAP//AP8BAQAB/wAA/wEBAAAAAAD/AQEAAQEAAP8BAQAA/wEA/wEBAAABAQD/AQEAAAD/Af8BAQAA/wAB/wEBAP8BAAH/AQEAAQABAf8BAQAA////AAEBAP8A//8AAQEA//8A/wABAQAAAAD/AAEBAAD/Af8AAQEA/wAB/wABAQABAAH/AAEBAAABAf8AAQEA////AAABAQAA//8AAAEBAAAA/wAAAQEAAQD/AAABAQD/Af8AAAEBAAD/AAAAAQEA/wAAAAABAQAAAAAAAAEBAAEAAAAAAQEAAAEAAAABAQD//wEAAAEBAAAAAQAAAQEAAQEBAAABAQAB//8BAAEBAP8A/wEAAQEAAQH/AQABAQAAAAABAAEBAAD/AQEAAQEA/wABAQABAQAAAAEBAAEBAAABAQEAAQEAAP8A/wEBAQABAAD/AQEBAP8BAP8BAQEAAP//AAEBAQD/AP8AAQEBAAAB/wABAQEA//8AAAEBAQAAAAAAAQEBAP8BAAABAQEAAQEAAAEBAQD/AAEAAQEBAAAAAQABAQEAAAEBAAEBAQABAP8BAQEBAP8AAAEBAQEA/wEAAQEBAQABAQABAQEBAAEAAQEBAQEA/////////wEB////////Af8B//////8BAQH//////wH//wH/////AQH/Af////8B/wEB/////wEBAQH/////AQAA/wD///8B//8AAP///wEA/wAA////Af8AAAD///8BAQAAAP///wEAAQAA////AQAAAQD///8B////Af///wEB//8B////Af8B/wH///8BAQH/Af///wEAAAAB////Af//AQH///8BAf8BAf///wH/AQEB////AQEBAQH///8BAAD//wD//wEA/wD/AP//Af8AAP8A//8BAQAA/wD//wEAAQD/AP//AQAAAf8A//8BAP//AAD//wH/AP8AAP//AQAB/wAA//8B//8AAAD//wEB/wAAAP//AQAAAAAA//8BAQAAAAD//wH/AQAAAP//AQABAAAA//8B/wABAAD//wEBAAEAAP//AQABAQAA//8BAAD/AQD//wEAAf8BAP//Af8AAAEA//8BAQAAAQD//wEAAQABAP//AQAAAQEA//8B/////wH//wEB////Af//Af8B//8B//8BAQH//wH//wEAAAD/Af//Af//Af8B//8BAf8B/wH//wH/AQH/Af//AQEBAf8B//8BAP8AAAH//wH/AAAAAf//AQABAAAB//8BAAABAAH//wH///8BAf//AQH//wEB//8B/wH/AQH//wEBAf8BAf//AQAAAAEB//8B//8BAQH//wEB/wEBAf//Af8BAQEB//8BAQEBAQH//wH/AAD//wD/AQABAP//AP8BAP//AP8A/wH/AP8A/wD/AQD/AAD/AP8BAAAAAP8A/wEBAQAA/wD/AQD/AQD/AP8B/wABAP8A/wEAAQEA/wD/Af8AAAH/AP8BAAEAAf8A/wEA////AAD/AQAB//8AAP8BAf8A/wAA/wEAAAD/AAD/AQEBAP8AAP8BAQAB/wAA/wEAAQH/AAD/Af///wAAAP8BAP//AAAA/wEAAP8AAAD/Af8B/wAAAP8BAP8AAAAA/wH/AAAAAAD/AQAAAAAAAP8BAQAAAAAA/wEAAQAAAAD/AQEBAAAAAP8BAAABAAAA/wEBAAEAAAD/Af8BAQAAAP8BAQEBAAAA/wEA//8BAAD/Af8A/wEAAP8BAQD/AQAA/wEAAf8BAAD/Af//AAEAAP8BAf8AAQAA/wEAAAABAAD/Af8BAAEAAP8BAQABAQAA/wEA/wD/AQD/AQEAAP8BAP8BAAEA/wEA/wEAAAH/AQD/AQD//wABAP8B/wD/AAEA/wEAAf8AAQD/AQEB/wABAP8B//8AAAEA/wEAAAAAAQD/AQABAAABAP8BAQEAAAEA/wEA/wEAAQD/AQEAAQABAP8BAQEBAAEA/wEAAP8BAQD/AQD/AAEBAP8BAQEAAQEA/wH/AAEBAQD/Af//////Af8BAf////8B/wH/Af///wH/AQEB////Af8BAAAA//8B/wH//wH//wH/AQH/Af//Af8B/wEB//8B/wEBAQH//wH/AQD//wD/Af8BAAD/AP8B/wEA/wAA/wH/Af8AAAD/Af8BAAEAAP8B/wEAAAEA/wH/AQABAQD/Af8B////Af8B/wEB//8B/wH/Af8B/wH/Af8BAQH/Af8B/wEAAAAB/wH/Af//AQH/Af8BAf8BAf8B/wH/AQEB/wH/AQEBAQH/Af8BAAD//wAB/wEBAP//AAH/AQD/AP8AAf8B/wAA/wAB/wEBAAD/AAH/AQAAAf8AAf8BAP//AAAB/wH/AP8AAAH/AQEA/wAAAf8BAAH/AAAB/wH//wAAAAH/AQH/AAAAAf8BAAAAAAAB/wEBAQAAAAH/AQD/AQAAAf8B/wABAAAB/wEAAP8BAAH/AQEAAAEAAf8BAAEAAQAB/wEAAAEBAAH/Af////8BAf8BAf///wEB/wH/Af//AQH/AQEB//8BAf8BAAAA/wEB/wH//wH/AQH/AQH/Af8BAf8B/wEB/wEB/wEBAQH/AQH/AQAA/wABAf8BAP8AAAEB/wH/AAAAAQH/AQEAAAABAf8B////AQEB/wEB//8BAQH/Af8B/wEBAf8BAQH/AQEB/wEAAAABAQH/Af//AQEBAf8BAf8BAQEB/wH/AQEBAQH/AQEBAQEBAf8BAAD/////AAEA/wD///8AAQEAAP///wAB/wEA////AAEAAQD///8AAQAAAf///wABAP//AP//AAEBAP8A//8AAQAB/wD//wABAAAAAP//AAH/AQAA//8AAQEBAAD//wABAAEBAP//AAEBAQEA//8AAQAA/wH//wABAP8AAf//AAH/AAAB//8AAQEAAAH//wABAAEAAf//AAEAAAEB//8AAQD///8A/wAB/wD//wD/AAEBAP//AP8AAQAB//8A/wAB//8A/wD/AAEAAAD/AP8AAf8BAP8A/wABAQEA/wD/AAEA/wH/AP8AAf8AAf8A/wABAQAB/wD/AAEAAQH/AP8AAf///wAA/wABAAD/AAD/AAH//wAAAP8AAQD/AAAA/wAB/wAAAAD/AAEAAAAAAP8AAQEAAAAA/wABAAEAAAD/AAEB/wEAAP8AAQAAAQAA/wAB/wD/AQD/AAEBAP8BAP8AAQH/AAEA/wABAAAAAQD/AAH/AQABAP8AAQD/AQEA/wAB/wABAQD/AAEBAAEBAP8AAQABAQEA/wABAAD//wH/AAEA/wD/Af8AAf8AAP8B/wABAAEA/wH/AAEAAAH/Af8AAf8A/wAB/wABAQD/AAH/AAEAAf8AAf8AAf//AAAB/wABAf8AAAH/AAEAAAAAAf8AAf8BAAAB/wABAQABAAH/AAEAAQEAAf8AAQAA/wEB/wAB/wAAAQH/AAEBAAABAf8AAQABAQEB/wABAP////8AAAH/AP///wAAAQEA////AAAB//8A//8AAAEAAAD//wAAAf8BAP//AAABAQAB//8AAAH///8A/wAAAQEB/wD/AAABAP8AAP8AAAH/AAAA/wAAAQAAAAD/AAABAQAAAP8AAAH/AQAA/wAAAQABAAD/AAAB//8BAP8AAAEA/wEA/wAAAQH/AQD/AAABAAABAP8AAAH/AP8B/wAAAQEA/wH/AAABAf8AAf8AAAH/AAAB/wAAAQAAAAH/AAAB/wEAAf8AAAEA/wEB/wAAAQABAQH/AAAB/////wAAAAEAAP//AAAAAf8B//8AAAABAQH//wAAAAH//wD/AAAAAQD/AP8AAAAB/wAA/wAAAAEAAAD/AAAAAQEAAP8AAAABAAEA/wAAAAEA/wH/AAAAAQAAAf8AAAABAAEB/wAAAAEBAQH/AAAAAQD//wAAAAAB/wD/AAAAAAEAAP8AAAAAAQEA/wAAAAABAAH/AAAAAAH//wAAAAAAAQD/AAAAAAABAf8AAAAAAAH/AAAAAAAAAQAAAAAAAAABAQAAAAAAAAH/AQAAAAAAAQABAAAAAAABAQEAAAAAAAEA/wEAAAAAAf8AAQAAAAABAAABAAAAAAEBAAEAAAAAAQABAQAAAAABAP//AQAAAAEAAP8BAAAAAf8B/wEAAAABAP8AAQAAAAEB/wABAAAAAf8AAAEAAAABAAAAAQAAAAEBAAABAAAAAQABAAEAAAABAQEAAQAAAAH//wEBAAAAAQH/AQEAAAABAAABAQAAAAH/AQEBAAAAAQEBAQEAAAABAP///wEAAAH/AP//AQAAAf//AP8BAAABAAAA/wEAAAEAAQD/AQAAAf//Af8BAAABAQAB/wEAAAEAAQH/AQAAAQAA/wABAAAB/wH/AAEAAAEAAf8AAQAAAQD/AAABAAABAf8AAAEAAAEAAAAAAQAAAQEAAAABAAABAAEAAAEAAAEAAAEAAQAAAf8BAQABAAABAf//AQEAAAH/AP8BAQAAAQAB/wEBAAABAQH/AQEAAAEB/wABAQAAAf8AAAEBAAABAAAAAQEAAAH/AAEBAQAAAQEAAQEBAAABAAEBAQEAAAEAAP///wEAAQEAAP//AQABAAEA//8BAAEAAAH//wEAAQD//wD/AQABAQD/AP8BAAH//wAA/wEAAQH/AAD/AQABAAAAAP8BAAEBAAAA/wEAAQEBAAD/AQAB/wABAP8BAAEAAAEA/wEAAQAA/wH/AQABAP8AAf8BAAEBAAAB/wEAAQABAAH/AQABAAABAf8BAAH/AP//AAEAAQEA//8AAQABAAH//wABAAH//wD/AAEAAQH/AP8AAQABAAAA/wABAAH/AQD/AAEAAQEBAP8AAQAB//8B/wABAAEA/wH/AAEAAf8AAf8AAQABAQAB/wABAAH///8AAAEAAQH//wAAAQABAAD/AAABAAH/Af8AAAEAAQEB/wAAAQABAP8AAAABAAH/AAAAAAEAAQAAAAAAAQABAQAAAAABAAEAAQAAAAEAAQH/AQAAAQABAAABAAABAAEBAAEAAAEAAQEBAQAAAQABAP//AQABAAH/AP8BAAEAAf//AAEAAQABAf8AAQABAAEAAAABAAEAAQEBAAEAAQABAP8BAQABAAEBAAEBAAEAAQAA//8BAQABAAAA/wEBAAEAAAH/AQEAAf8A/wABAQABAQD/AAEBAAEAAf8AAQEAAf//AAABAQABAAAAAAEBAAH/AQAAAQEAAQD/AQABAQABAAD/AQEBAAEA/wABAQEAAf8AAAEBAQABAAAAAQEBAAEBAAABAQEAAf///////wEBAf//////AQH/Af////8BAQEB/////wEBAAAA////AQH//wH///8BAQH/Af///wEB/wEB////AQEBAQH///8BAQAA/wD//wEBAP8AAP//AQH/AAAA//8BAQEAAAD//wEBAAEAAP//AQH///8B//8BAQH//wH//wEB/wH/Af//AQEBAf8B//8BAQAAAAH//wEB//8BAf//AQEB/wEB//8BAf8BAQH//wEBAQEBAf//AQEAAP//AP8BAQAB//8A/wEBAP8A/wD/AQH/AAD/AP8BAQEAAP8A/wEBAAEA/wD/AQEBAQD/AP8BAQEA/wAA/wEBAAH/AAD/AQEA/wAAAP8BAQAAAAAA/wEB/wEAAAD/AQEBAQAAAP8BAQD/AQAA/wEB/wABAAD/AQEAAP8BAP8BAf//AAEA/wEBAf8AAQD/AQEBAAABAP8BAQABAAEA/wEBAf///wH/AQH/Af//Af8BAQEB//8B/wEB//8A/wH/AQEAAQD/Af8BAQH/Af8B/wEB/wEB/wH/AQEBAQH/Af8BAQAA/wAB/wEBAP8AAAH/AQEBAAAAAf8BAQABAAAB/wEBAAABAAH/AQH///8BAf8BAQH//wEB/wEB/wH/AQH/AQEBAf8BAf8BAQAAAAEB/wEB//8BAQH/AQEB/wEBAf8BAf8BAQEB/wEBAQEBAQH/AQEAAQD//wABAQAAAf//AAEBAP//AP8AAQH/AP8A/wABAf//AAD/AAEB/wAAAP8AAQEAAAAA/wABAf8BAAD/AAEBAQEAAP8AAQEA/wEA/wABAQAAAQD/AAEBAQABAP8AAQH/AQEA/wABAQABAQD/AAEBAAD/Af8AAQEBAP//AAABAQAB//8AAAEB//8A/wAAAQEB/wD/AAABAQAAAP8AAAEB/wEA/wAAAQEBAAH/AAABAQABAf8AAAEBAf//AAAAAQEAAP8AAAABAQD/AAAAAAEB/wAAAAAAAQEAAAAAAAABAQEAAAAAAAEBAAEAAAAAAQEAAAEAAAABAQEBAQAAAAEBAP//AQAAAQH/AP8BAAABAQAA/wEAAAEBAQD/AQAAAQEAAf8BAAABAQH/AAEAAAEBAAAAAQAAAQH/AQABAAABAQAA//8BAAEBAP8A/wEAAQEBAAD/AQABAQEBAP8BAAEBAP8B/wEAAQEAAAH/AQABAf8A/wABAAEBAQD/AAEAAQEBAf8AAQABAQH/AAABAAEBAAAAAAEAAQEBAAAAAQABAf8BAAABAAEB//8BAAEAAQEB/wEAAQABAQEA/wEBAAEB//8AAQEAAQEAAAABAQABAQEAAAEBAAEBAAEAAQEAAQEA/wEBAQABAf8AAQEBAAEBAQABAQEAAQH//////wEBAQH/////AQEB/wH///8BAQEBAf///wEBAf//Af//AQEBAf8B//8BAQH/AQH//wEBAQEBAf//AQEBAP8AAP8BAQH/AAAA/wEBAQEAAAD/AQEBAAEAAP8BAQH///8B/wEBAQH//wH/AQEB/wH/Af8BAQEBAf8B/wEBAQAAAAH/AQEB//8BAf8BAQEB/wEB/wEBAf8BAQH/AQEBAQEBAf8BAQEAAP//AAEBAf8AAP8AAQEBAAEA/wABAQEA/wH/AAEBAQAAAf8AAQEBAP//AAABAQH//wAAAAEBAQAAAAAAAQEBAQEAAAABAQEA/wEAAAEBAQEAAQAAAQEBAAEBAAABAQH//wABAAEBAQEAAAEAAQEB/////wEBAQEB////AQEBAf8B//8BAQEBAQH//wEBAQH//wH/AQEBAQH/Af8BAQEB/wEB/wEBAQEBAQH/AQEBAQD/AAABAQEB/wAAAAEBAQEBAAAAAQEBAf///wEBAQEBAf//AQEBAQH/Af8BAQEBAQEB/wEBAQEBAAAAAQEBAQH//wEBAQEBAQH/AQEBAQEB/wEBAQEBAQEBAQEBAQEBAQ==");
12
+ export const ksigns_iq2xs = /* 128B */ D("AIGCA4QFBoeICQqLDI2OD5AREpMUlZYXGJmaG5wdHp+gISKjJKWmJyipqiusLS6vMLGyM7Q1Nre4OTq7PL2+P8BBQsNExcZHSMnKS8xNTs9Q0dJT1FVW19hZWttc3d5fYOHiY+RlZufoaWrrbO3ub/BxcvN09fZ3ePn6e/x9fv8=");
13
+ export const kmask_iq2xs = /* 8B */ D("AQIECBAgQIA=");
14
+ export const kvalues_iq4nl = /* 16B */ D("gZitv8/d6vYBDRkmNUVZcQ==");
apps/q/forge/gguf-forge-kstream.mjs ADDED
@@ -0,0 +1,111 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // gguf-forge-kstream.mjs — load an LLM 100% from its sealed .holo, by κ, native to the substrate.
2
+ //
3
+ // The vision's load path: a model is a content-addressed archive of per-tensor κ-bodies (sealHolo /
4
+ // writeHolo). This opens it WITHOUT re-forging the monolithic GGUF — every tensor is fetched BY ITS κ
5
+ // and re-derived before use (L5), with a global κ-cache (a block seen once is reused, O(1) warm). The
6
+ // embedded gguf.header gives the plan (arch + hparams + tensor infos + tokenizer); meta.order gives
7
+ // name→κ. Output is forge-compatible: { plan, store } feed synthesizeGraph + forward unchanged, and
8
+ // (in the browser) the SAME .holo streams over HTTP-Range / SW κ-route / IPFS — serverless, verified.
9
+ //
10
+ // readHolo (whole bytes, Node/in-memory) and openGgufHoloStream (rangeReader, browser cold-load) share
11
+ // one shape. The per-body L5 lives in holo-archive's store; we add the name→κ plan + a verify-once
12
+ // global κ-cache so a forward doesn't re-hash every matvec.
13
+
14
+ import { readHolo, openHoloStream } from "./holo-archive.mjs";
15
+ import { parseGgufHeader } from "../qvac-ingest.mjs";
16
+ import { GGML_TYPE_NAME } from "./gguf-forge.mjs";
17
+
18
+ // build the forge-compatible plan (name→κ + dims/type) from the embedded gguf header + meta.order
19
+ function planFrom(headerBytes, order) {
20
+ const hd = parseGgufHeader(headerBytes);
21
+ const byName = new Map(order.map((o) => [o.name, o.kappa]));
22
+ const tensors = hd.tensors.map((t) => ({
23
+ name: t.name, dims: t.dims, type: t.ggmlType, typeName: GGML_TYPE_NAME[t.ggmlType] || String(t.ggmlType),
24
+ kappa: "sha256:" + byName.get(t.name), // identity = content (from the κ-body directory)
25
+ }));
26
+ return { arch: hd.meta["general.architecture"], meta: hd.meta, tensors };
27
+ }
28
+
29
+ // the head region = [0, firstBodyOffset): the 64-byte head + section table + Extension (baked gguf
30
+ // header + tokenizer) + Metadata + the weights directory — everything BEFORE the first weight body.
31
+ // Found cheaply (head + section table + the weights count, ~200B) without reading the 6MB header.
32
+ async function firstBodyOffset(range) {
33
+ const head = await range(0, 64), hdv = new DataView(head.buffer, head.byteOffset, head.byteLength);
34
+ const sc = hdv.getUint16(8, true);
35
+ const tbl = await range(10, sc * 17), tdv = new DataView(tbl.buffer, tbl.byteOffset, tbl.byteLength);
36
+ let wOff = null;
37
+ for (let i = 0, p = 0; i < sc; i++, p += 17) if (tbl[p] === 3) wOff = Number(tdv.getBigUint64(p + 1, true)); // Weights=3
38
+ const cntB = await range(wOff, 4); const count = new DataView(cntB.buffer, cntB.byteOffset, cntB.byteLength).getUint32(0, true);
39
+ return wOff + 4 + count * 48; // [count u32] + count×[κ32 off8 len8]
40
+ }
41
+
42
+ // Resolve the head blob from the persistent store (0 transport on warm) or fetch+persist it (cold).
43
+ // Keyed by its own content κ (headκ = sha256(head)) → store.peek L5-verifies it. A pointer maps the
44
+ // archive identity to headκ: the .holo footer κ (rootKappa, the LINK — content-addressed) and/or a
45
+ // local url hint (a non-identity accelerator for open-by-URL). Returns the head bytes + warm flag.
46
+ async function resolveHeadBlob(range, persist, { rootKappa, urlHint }) {
47
+ const footHex = rootKappa ? String(rootKappa).split(":").pop() : null;
48
+ const urlKey = urlHint ? await persist.hash(new TextEncoder().encode(urlHint)) : null;
49
+ let headK = null;
50
+ if (footHex) headK = await persist.getHint("head_" + footHex); // content-addressed pointer (the link)
51
+ if (!headK && urlKey) headK = await persist.getHint("url_" + urlKey); // local url accelerator
52
+ if (headK) { const blob = await persist.peek(headK); if (blob) return { blob, warm: true }; }
53
+ // cold: one fetch of the contiguous head region, content-address + persist, write the pointers
54
+ const fbo = await firstBodyOffset(range);
55
+ const blob = await range(0, fbo);
56
+ const hk = await persist.hash(blob);
57
+ await persist.putBody(hk, blob);
58
+ if (footHex) await persist.putHint("head_" + footHex, hk);
59
+ if (urlKey) await persist.putHint("url_" + urlKey, hk);
60
+ return { blob, warm: false };
61
+ }
62
+
63
+ // a verify-once global κ-cache over a base store (the holo store already L5-verifies on first get).
64
+ // Subsequent gets are O(1) and offline. Shared across loads when the same Map is passed in.
65
+ function cachedStore(base, cache = new Map()) {
66
+ return { get: (hex) => { let b = cache.get(hex); if (b === undefined) { b = base.get(hex); cache.set(hex, b); } return b; }, has: (hex) => base.has(hex), cache };
67
+ }
68
+
69
+ // ── whole-bytes (Node / fully-in-memory): open a .holo and load by κ with L5 + cache ──
70
+ export function openGgufHolo(bytes, { cache } = {}) {
71
+ const h = readHolo(bytes); // footer L5 + per-body L5 store + meta.order
72
+ return { plan: planFrom(h.headerBytes, h.meta.order), store: cachedStore(h.store, cache), rootHolo: h.footer, meta: h.meta, headerBytes: h.headerBytes };
73
+ }
74
+
75
+ // ── streaming (browser cold-load): open a .holo over a Range reader; bodies fetched on demand by κ ──
76
+ // rangeReader(off,len)->Promise<Uint8Array> (HTTP-Range, SW κ-route, or IPFS). store.get is async.
77
+ // persist (optional, browser): a makeKappaStore() instance — OPFS-first, 0-network warm, survives
78
+ // reload + offline. Injected (not imported) so this module stays Node-safe. The in-mem cache sits in
79
+ // front for same-session O(1); persist sits behind for cross-session O(1). getBody L5-verifies every
80
+ // transport body, so a persisted body is trusted only after re-derivation.
81
+ export async function openGgufHoloStream(rangeReader, { cache = new Map(), persist = null, rootKappa = null, urlHint = null } = {}) {
82
+ // HEAD PERSISTENCE: when a persistent store + an identity hint are present, serve the whole head
83
+ // region from a content-addressed blob (0 transport on warm) so the ~6MB gguf header/tokenizer is
84
+ // offline too — not just the weight bodies. effRange serves head reads from the blob, bodies via wire.
85
+ let effRange = rangeReader, headWarm = null;
86
+ if (persist && persist.putBody && (rootKappa || urlHint)) {
87
+ const h = await resolveHeadBlob(rangeReader, persist, { rootKappa, urlHint });
88
+ headWarm = h.warm;
89
+ effRange = (off, len) => (off + len <= h.blob.length) ? Promise.resolve(h.blob.subarray(off, off + len)) : rangeReader(off, len);
90
+ }
91
+ const s = await openHoloStream(effRange); // header + directory up front; bodies on demand
92
+ const fetchBody = (hex) => s.getBody(hex); // Range + per-block L5 (refuses mismatch)
93
+ const base = persist ? (hex) => persist.get(hex, () => fetchBody(hex)) : fetchBody;
94
+ const aget = async (hex) => { let b = cache.get(hex); if (b === undefined) { b = await base(hex); cache.set(hex, b); } return b; };
95
+ return { plan: planFrom(s.headerBytes, s.meta.order), store: { get: aget, cache }, meta: s.meta, headerBytes: s.headerBytes, persist, headWarm };
96
+ }
97
+
98
+ // UNIFIED-PACK adapter: build the SAME { plan, store, headerBytes, headWarm } the brain consumes, but sourced from a
99
+ // pack model view (openModelPack/holo-q-pack-provider) instead of a per-model rangeReader. The view already carries the
100
+ // baked gguf header (view.headerBytes) + name→κ (view.order) + a per-κ L5 getBody — exactly planFrom + a verify-once
101
+ // store. So createHoloBrain runs over the unified pack with ZERO forge/forward changes: same plan, same bodies, same κ.
102
+ export function ggufStreamFromPackModel(view, { cache = new Map(), persist = null } = {}) {
103
+ const plan = planFrom(view.headerBytes, view.order);
104
+ const fetchBody = (hex) => view.getBody(hex); // pack getBody = Range + per-block L5
105
+ const base = persist ? (hex) => persist.get(hex, () => fetchBody(hex)) : fetchBody;
106
+ const aget = async (hex) => { let b = cache.get(hex); if (b === undefined) { b = await base(hex); cache.set(hex, b); } return b; };
107
+ return { plan, store: { get: aget, cache }, meta: { order: view.order }, headerBytes: view.headerBytes, persist, headWarm: true };
108
+ }
109
+
110
+ // the exec loader seam: forward(plan, graph, store, tokens, { load }) — verify-once (store already L5).
111
+ export const kstreamLoad = (store, kappaRef) => store.get(String(kappaRef).split(":").pop());
apps/q/forge/gguf-forge.mjs ADDED
@@ -0,0 +1,226 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // GGUF Forge — split a GGUF into κ-addressable objects, ORIGINAL BYTES PRESERVED.
2
+ //
3
+ // This is the "compile into κ-addressable objects" core. Unlike qvac-ingest's
4
+ // makeDiskFetcher (which dequantizes then RE-QUANTIZES Q4_K/Q6_K into the engine's
5
+ // lossy 4-bit format — a fidelity violation for "strictly adhere to original
6
+ // code"), the forge stores each tensor's EXACT on-disk ggml quant bytes as its own
7
+ // content-addressed κ-object. The κ of a tensor IS the hash of the bytes llama.cpp
8
+ // would mmap, so fidelity is byte-literal and L5-verifiable on every load.
9
+ //
10
+ // Output:
11
+ // • blocks: Map<hex, Uint8Array> the κ-store (one object per tensor, by content)
12
+ // • plan: a JSON manifest of arch + hparams + per-tensor {dims, type, κ, sri}
13
+ // • rootKappa: did:holo:sha256 of the canonical plan — the model's identity (L1)
14
+ //
15
+ // Laws: L1 identity=content, L2 one object per tensor (dedup by κ), L5 verify by
16
+ // re-derivation. holospaces github.com/Hologram-Technologies/holospaces.
17
+
18
+ import { parseGgufHeader } from "../qvac-ingest.mjs";
19
+ import { sha256hex, sriOf, kappa, didHolo, jcs } from "../../../usr/lib/holo/holo-uor.mjs";
20
+
21
+ // ── ggml type → (block elements, block bytes). Source: ggml.c type_traits table
22
+ // (blck_size, type_size). Covers the standard set a Qx_K_M GGUF uses. Exotic
23
+ // IQ*/TBQ/MXFP4 types throw until their kernels land (honest, not silent). ──
24
+ const QK = 32, QK_K = 256;
25
+ const TYPE_BLOCK = {
26
+ 0: [1, 4], // F32
27
+ 1: [1, 2], // F16
28
+ 2: [QK, 18], // Q4_0
29
+ 3: [QK, 20], // Q4_1
30
+ 6: [QK, 22], // Q5_0
31
+ 7: [QK, 24], // Q5_1
32
+ 8: [QK, 34], // Q8_0
33
+ 9: [QK, 36], // Q8_1
34
+ 10: [QK_K, 84], // Q2_K
35
+ 11: [QK_K, 110], // Q3_K
36
+ 12: [QK_K, 144], // Q4_K
37
+ 13: [QK_K, 176], // Q5_K
38
+ 14: [QK_K, 210], // Q6_K
39
+ 15: [QK_K, 292], // Q8_K (intermediate; not normally stored)
40
+ 16: [QK_K, 66], // IQ2_XXS
41
+ 17: [QK_K, 74], // IQ2_XS
42
+ 18: [QK_K, 98], // IQ3_XXS
43
+ 19: [QK_K, 50], // IQ1_S
44
+ 20: [QK, 18], // IQ4_NL (block = 32 elems)
45
+ 21: [QK_K, 110], // IQ3_S
46
+ 22: [QK_K, 82], // IQ2_S
47
+ 23: [QK_K, 136], // IQ4_XS
48
+ 29: [QK_K, 56], // IQ1_M
49
+ 30: [1, 2], // BF16
50
+ 35: [QK_K, 66], // TQ2_0 (BitNet ternary, 2.0625 bpw)
51
+ };
52
+ export const GGML_TYPE_NAME = {
53
+ 0: "F32", 1: "F16", 2: "Q4_0", 3: "Q4_1", 6: "Q5_0", 7: "Q5_1", 8: "Q8_0", 9: "Q8_1",
54
+ 10: "Q2_K", 11: "Q3_K", 12: "Q4_K", 13: "Q5_K", 14: "Q6_K", 15: "Q8_K",
55
+ 16: "IQ2_XXS", 17: "IQ2_XS", 18: "IQ3_XXS", 19: "IQ1_S", 20: "IQ4_NL",
56
+ 21: "IQ3_S", 22: "IQ2_S", 23: "IQ4_XS", 29: "IQ1_M", 30: "BF16", 35: "TQ2_0",
57
+ // TurboQuant / PolarQuant KV-cache quant (not weight types — KvMemory plane)
58
+ 42: "TBQ3_0", 43: "TBQ4_0", 44: "TBQ3_0_64", 45: "TBQ4_0_64",
59
+ 46: "PQ3_0", 47: "PQ3_0_64", 48: "PQ4_0", 49: "PQ4_0_64",
60
+ };
61
+
62
+ // ggml_nbytes for a contiguous tensor of `numElements` of `ggmlType` (the exact
63
+ // span llama.cpp loads — excludes inter-tensor alignment padding).
64
+ export function ggmlNBytes(ggmlType, numElements) {
65
+ const bt = TYPE_BLOCK[ggmlType];
66
+ if (!bt) throw new Error(`gguf-forge: unsupported ggml type ${ggmlType} (no block size yet)`);
67
+ const [blk, bytes] = bt;
68
+ if (numElements % blk !== 0) throw new Error(`gguf-forge: ${numElements} not divisible by block ${blk} (type ${ggmlType})`);
69
+ return (numElements / blk) * bytes;
70
+ }
71
+
72
+ const numElements = (dims) => dims.reduce((a, b) => a * b, 1);
73
+
74
+ // Forge a full in-memory GGUF (Uint8Array) into κ-objects. For multi-GB models the
75
+ // streaming variant (forgeGgufStream, below) does the same with a Range reader so
76
+ // no tensor beyond the one being hashed is ever resident.
77
+ export function forgeGguf(bytes) {
78
+ const { version, dataOffset, tensors, meta } = parseGgufHeader(bytes);
79
+ const blocks = new Map();
80
+ const planTensors = [];
81
+ for (const t of tensors) {
82
+ const n = numElements(t.dims);
83
+ const nbytes = ggmlNBytes(t.ggmlType, n);
84
+ const start = dataOffset + t.offset;
85
+ const end = start + nbytes;
86
+ if (end > bytes.byteLength) throw new Error(`gguf-forge: tensor ${t.name} runs past EOF (${end} > ${bytes.byteLength})`);
87
+ // EXACT bytes — no copy semantics changed, no re-quant. This subarray IS the κ-object.
88
+ const blob = bytes.subarray(start, end);
89
+ const hex = sha256hex(blob);
90
+ if (!blocks.has(hex)) blocks.set(hex, blob.slice()); // own the bytes; L2 dedup by content
91
+ planTensors.push({
92
+ name: t.name, dims: t.dims, type: t.ggmlType, typeName: GGML_TYPE_NAME[t.ggmlType] || String(t.ggmlType),
93
+ nbytes, kappa: kappa("sha256", hex), sri: sriOf(blob),
94
+ });
95
+ }
96
+ const arch = meta["general.architecture"] || "unknown";
97
+ // The plan is the sealed manifest: arch + all scalar metadata + per-tensor κ refs.
98
+ // No raw weight bytes here — only content addresses. Hashing it gives model identity.
99
+ const plan = {
100
+ format: "gguf-forge/1",
101
+ arch,
102
+ ggufVersion: version,
103
+ meta, // scalar hparams + tokenizer ids captured by parseGgufHeader
104
+ tensors: planTensors, // ordered as in the GGUF directory
105
+ };
106
+ const planHex = sha256hex(jcs(plan));
107
+ const rootKappa = didHolo("sha256", planHex);
108
+ return { version, dataOffset, arch, meta, tensors: planTensors, blocks, plan, rootKappa };
109
+ }
110
+
111
+ // Streaming forge: same κ-objects from a Range reader (start,len)->Promise<Uint8Array>,
112
+ // for models too large to hold whole. Reads the header once, then each tensor span once.
113
+ export async function forgeGgufStream(readRange, { headerBytes }) {
114
+ const { version, dataOffset, tensors, meta } = parseGgufHeader(headerBytes);
115
+ const blocks = new Map();
116
+ const planTensors = [];
117
+ for (const t of tensors) {
118
+ const n = numElements(t.dims);
119
+ const nbytes = ggmlNBytes(t.ggmlType, n);
120
+ const blob = await readRange(dataOffset + t.offset, nbytes);
121
+ if (blob.byteLength !== nbytes) throw new Error(`gguf-forge: short read for ${t.name}`);
122
+ const hex = sha256hex(blob);
123
+ if (!blocks.has(hex)) blocks.set(hex, blob);
124
+ planTensors.push({
125
+ name: t.name, dims: t.dims, type: t.ggmlType, typeName: GGML_TYPE_NAME[t.ggmlType] || String(t.ggmlType),
126
+ nbytes, kappa: kappa("sha256", hex), sri: sriOf(blob),
127
+ });
128
+ }
129
+ const arch = meta["general.architecture"] || "unknown";
130
+ const plan = { format: "gguf-forge/1", arch, ggufVersion: version, meta, tensors: planTensors };
131
+ const rootKappa = didHolo("sha256", sha256hex(jcs(plan)));
132
+ return { version, dataOffset, arch, meta, tensors: planTensors, blocks, plan, rootKappa };
133
+ }
134
+
135
+ // Disk-backed forge for models too large to hold in RAM (e.g. GLM-5.2, 254-467 GB).
136
+ // Reads each tensor span ONCE to derive its κ, then RELEASES the bytes — peak memory is
137
+ // the largest single tensor, not the model. Emits no `blocks` Map; instead a
138
+ // `dir: { hex -> { fileOffset, len } }` so a disk store can range-read any κ-block later,
139
+ // plus a per-expert `expertDir` (same shape as buildExpertDirectory) computed in the same
140
+ // pass. Same plan/κ as forgeGgufStream (verified by gguf-forge-disk.test).
141
+ const EXPERT_RE_SCAN = /\.ffn_(gate|up|down)_exps\.weight$/;
142
+
143
+ // Shared scan core. `entries` = [{ name, dims, ggmlType, read(off,len)->Promise<bytes>, loc(off,len)->dirEntry }].
144
+ // `read(0,nbytes)` returns the whole tensor (read ONCE); slices come from that blob (no re-read).
145
+ // `loc` builds the κ→location directory entry ({fileOffset,len} single-file, or {part,fileOffset,len}
146
+ // multi-part). Same κ/plan/rootKappa regardless of where the bytes physically live.
147
+ async function scanCore(entries, meta, version) {
148
+ const planTensors = [], dir = Object.create(null), expertTensors = Object.create(null);
149
+ for (const t of entries) {
150
+ const nbytes = ggmlNBytes(t.ggmlType, numElements(t.dims));
151
+ const blob = await t.read(0, nbytes);
152
+ if (blob.byteLength !== nbytes) throw new Error(`gguf-forge: short read for ${t.name}`);
153
+ const hex = sha256hex(blob);
154
+ if (!(hex in dir)) dir[hex] = t.loc(0, nbytes);
155
+ planTensors.push({
156
+ name: t.name, dims: t.dims, type: t.ggmlType, typeName: GGML_TYPE_NAME[t.ggmlType] || String(t.ggmlType),
157
+ nbytes, kappa: kappa("sha256", hex), sri: sriOf(blob),
158
+ });
159
+ if (EXPERT_RE_SCAN.test(t.name) && t.dims.length >= 3) {
160
+ const [K, N, E] = t.dims, stride = ggmlNBytes(t.ggmlType, K * N), experts = [];
161
+ for (let e = 0; e < E; e++) {
162
+ const sh = sha256hex(blob.subarray(e * stride, (e + 1) * stride));
163
+ if (!(sh in dir)) dir[sh] = t.loc(e * stride, stride);
164
+ experts.push({ e, kappa: kappa("sha256", sh) });
165
+ }
166
+ expertTensors[t.name] = { type: t.ggmlType, typeName: GGML_TYPE_NAME[t.ggmlType] || String(t.ggmlType), dims: [K, N, E], stride, nExpert: E, experts };
167
+ }
168
+ // blob released here — never retained
169
+ }
170
+ const arch = meta["general.architecture"] || "unknown";
171
+ const plan = { format: "gguf-forge/1", arch, ggufVersion: version, meta, tensors: planTensors };
172
+ const rootKappa = didHolo("sha256", sha256hex(jcs(plan)));
173
+ const expertDir = { format: "gguf-forge-expert-dir/1", model: rootKappa, tensors: expertTensors };
174
+ return { version, arch, meta, tensors: planTensors, plan, rootKappa, dir, expertDir };
175
+ }
176
+
177
+ // Disk-backed forge for models too large to hold in RAM (e.g. GLM-5.2, 254-467 GB).
178
+ // Reads each tensor span ONCE to derive its κ, then RELEASES the bytes — peak memory is
179
+ // the largest single tensor, not the model. Emits no `blocks` Map; instead a
180
+ // `dir: { hex -> { fileOffset, len } }` so a disk store can range-read any κ-block later,
181
+ // plus a per-expert `expertDir` (same shape as buildExpertDirectory). Same κ as forgeGgufStream.
182
+ export async function forgeGgufScan(readRange, { headerBytes }) {
183
+ const { version, dataOffset, tensors, meta } = parseGgufHeader(headerBytes);
184
+ const entries = tensors.map((t) => {
185
+ const base = dataOffset + t.offset;
186
+ return { name: t.name, dims: t.dims, ggmlType: t.ggmlType, read: (o, l) => readRange(base + o, l), loc: (o, l) => ({ fileOffset: base + o, len: l }) };
187
+ });
188
+ return { dataOffset, ...(await scanCore(entries, meta, version)) };
189
+ }
190
+
191
+ // Multi-part forge (GLM-5.2 ships as a 7-part split GGUF). `multipart` = openGgufMultipart()
192
+ // result: { meta, version, tensors:[{name,dims,ggmlType,part,fileOffset}], parts:[{readRange}] }.
193
+ // Each tensor is read from its OWNING part; dir entries carry {part,fileOffset,len}. Produces the
194
+ // SAME κ/rootKappa/.holo as forging the un-split model (verified by gguf-multipart.test).
195
+ export async function forgeGgufScanParts(multipart) {
196
+ const entries = multipart.tensors.map((t) => ({
197
+ name: t.name, dims: t.dims, ggmlType: t.ggmlType,
198
+ read: (o, l) => multipart.parts[t.part].readRange(t.fileOffset + o, l),
199
+ loc: (o, l) => ({ part: t.part, fileOffset: t.fileOffset + o, len: l }),
200
+ }));
201
+ return scanCore(entries, multipart.meta, multipart.version);
202
+ }
203
+
204
+ // L5: load a tensor's bytes by κ, RE-DERIVE the hash, refuse on mismatch.
205
+ // `store` is any { get(hex) -> Uint8Array | undefined }. Accepts "sha256:<hex>",
206
+ // "did:holo:sha256:<hex>", or a bare hex.
207
+ export function loadByKappa(store, kappaRef) {
208
+ const hex = String(kappaRef).split(":").pop();
209
+ const bytes = store.get(hex);
210
+ if (!bytes) throw new Error(`gguf-forge: κ not found: ${kappaRef}`);
211
+ const got = sha256hex(bytes);
212
+ if (got !== hex) throw new Error(`gguf-forge: L5 REFUSE — ${kappaRef} re-derives to sha256:${got}`);
213
+ return bytes;
214
+ }
215
+
216
+ // Re-derive the whole plan's identity from a store: verify every tensor block, then
217
+ // re-hash the plan. Returns the recomputed rootKappa (throws on any tamper).
218
+ export function verifyPlan(store, plan) {
219
+ for (const t of plan.tensors) loadByKappa(store, t.kappa); // L5 per block
220
+ return didHolo("sha256", sha256hex(jcs(plan)));
221
+ }
222
+
223
+ // Map-backed κ-store helper for tests/Node.
224
+ export function mapStore(blocks) {
225
+ return { get: (hex) => blocks.get(hex), has: (hex) => blocks.has(hex), put: (b) => { const h = sha256hex(b); blocks.set(h, b); return h; } };
226
+ }
apps/q/forge/gpu/holo-files.mjs ADDED
@@ -0,0 +1,51 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // holo-files.mjs — serve a file-bundle .holo (seal-files-holo.mjs) by κ in the browser: HTTP-Range fetch
2
+ // each file body by its content address, per-block SHA-256 L5 verify, OPFS cache (instant + offline on the
3
+ // 2nd load). Reconstructs files as bytes / Blob object-URLs so an existing runtime (onnxruntime-web,
4
+ // kokoro-js, transformers.js) can consume a κ-addressable model with no flat download and no trust in transport.
5
+ // openHoloFiles(url) → { meta, files:[{name,kappa,len}], getFile(name)->Uint8Array, objectURL(name)->url, stats }
6
+ const MAGIC = [0x48, 0x4f, 0x4c, 0x4f];
7
+ const hexOf = (b) => { let s = ""; for (const x of b) s += x.toString(16).padStart(2, "0"); return s; };
8
+ const sha256hex = async (buf) => hexOf(new Uint8Array(await crypto.subtle.digest("SHA-256", buf)));
9
+ async function opfsGet(k) { try { const d = await (await navigator.storage.getDirectory()).getDirectoryHandle("holo-kappa", { create: true }); return new Uint8Array(await (await (await d.getFileHandle(k)).getFile()).arrayBuffer()); } catch { return null; } }
10
+ async function opfsPut(k, b) { try { const d = await (await navigator.storage.getDirectory()).getDirectoryHandle("holo-kappa", { create: true }); const w = await (await d.getFileHandle(k, { create: true })).createWritable(); await w.write(b); await w.close(); return true; } catch { return false; } }
11
+
12
+ export async function openHoloFiles(url, { useOpfs = true, release = "" } = {}) {
13
+ const stats = { ranges: 0, bytesFetched: 0, verifies: 0, opfsHits: 0, opfsWrites: 0, releaseRoute: false };
14
+ let whole = null, activeUrl = url, triedRelease = false;
15
+ const rd = async (off, len) => {
16
+ if (whole) return whole.subarray(off, off + len);
17
+ stats.ranges++;
18
+ let r = null; try { r = await fetch(activeUrl, { headers: { Range: `bytes=${off}-${off + len - 1}` } }); } catch (e) { r = null; }
19
+ if ((!r || !r.ok) && release && activeUrl !== release && !triedRelease) { // big bundle lives as a GitHub Release asset
20
+ triedRelease = true; activeUrl = release; stats.releaseRoute = true;
21
+ try { r = await fetch(activeUrl, { headers: { Range: `bytes=${off}-${off + len - 1}` } }); } catch (e) { r = null; }
22
+ }
23
+ if (!r || !r.ok) throw new Error("holo fetch failed (" + (r ? r.status : "network") + "): " + activeUrl);
24
+ const u = new Uint8Array(await r.arrayBuffer()); stats.bytesFetched += u.length;
25
+ if (r.status === 206) return u;
26
+ if (u.length > len) { whole = u; return whole.subarray(off, off + len); }
27
+ return u;
28
+ };
29
+ const head = await rd(0, 64), hdv = new DataView(head.buffer, head.byteOffset, head.byteLength);
30
+ for (let i = 0; i < 4; i++) if (head[i] !== MAGIC[i]) throw new Error("not a .holo");
31
+ const sc = hdv.getUint16(8, true);
32
+ const tbl = await rd(10, sc * 17), tdv = new DataView(tbl.buffer, tbl.byteOffset, tbl.byteLength), sections = {};
33
+ for (let i = 0, p = 0; i < sc; i++, p += 17) sections[tbl[p]] = { off: Number(tdv.getBigUint64(p + 1, true)), len: Number(tdv.getBigUint64(p + 9, true)) };
34
+ const m = sections[8], meta = JSON.parse(new TextDecoder().decode(await rd(m.off, m.len)));
35
+ const w = sections[3], cntB = await rd(w.off, 4), count = new DataView(cntB.buffer, cntB.byteOffset, cntB.byteLength).getUint32(0, true);
36
+ const dirB = await rd(w.off + 4, count * 48), ddv = new DataView(dirB.buffer, dirB.byteOffset, dirB.byteLength), dir = new Map();
37
+ for (let i = 0, p = 0; i < count; i++, p += 48) dir.set(hexOf(dirB.subarray(p, p + 32)), { off: Number(ddv.getBigUint64(p + 32, true)), len: Number(ddv.getBigUint64(p + 40, true)) });
38
+ const byName = new Map(meta.files.map((f) => [f.name, f])), cache = new Map();
39
+
40
+ async function bodyByKappa(hex) {
41
+ if (useOpfs) { const c = await opfsGet(hex); if (c) { stats.verifies++; if (await sha256hex(c) === hex) { stats.opfsHits++; return c; } } }
42
+ const d = dir.get(hex); if (!d) throw new Error("κ not in holo: " + hex);
43
+ const b = await rd(d.off, d.len);
44
+ stats.verifies++; if (await sha256hex(b) !== hex) throw new Error("L5 REFUSE " + hex);
45
+ if (useOpfs && await opfsPut(hex, b)) stats.opfsWrites++;
46
+ return b;
47
+ }
48
+ async function getFile(name) { if (cache.has(name)) return cache.get(name); const f = byName.get(name); if (!f) throw new Error("no file " + name); const b = await bodyByKappa(f.kappa); cache.set(name, b); return b; }
49
+ async function objectURL(name, mime = "application/octet-stream") { return URL.createObjectURL(new Blob([await getFile(name)], { type: mime })); }
50
+ return { meta, files: meta.files, getFile, objectURL, bodyByKappa, stats };
51
+ }
apps/q/forge/gpu/holo-model-pack.mjs ADDED
@@ -0,0 +1,47 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // holo-model-pack.mjs — open the unified q-models.holo ONCE and hand each faculty a per-model view shaped EXACTLY
2
+ // like an openHoloStream result, so every loader (parakeet ear's encoderStream/jointStream, loadJointFromHolo, the
3
+ // turn-detector binding, moonshine/kokoro) accepts pack.model(id) with ZERO code change. Same body κ ⇒ same bytes
4
+ // ⇒ identical results. One open, one OPFS κ-store shared across faculties; faculties Range-fetch only their bodies.
5
+ //
6
+ // openModelPack({ rangeReader, persist }) → { manifest, getBody, dir, model(id) }
7
+ // model(id) → { meta:{order}, order, files, headerBytes, getBody, getBodySlice, dir, bodyLen, names }
8
+ // rangeReader(off,len)->Uint8Array: production wraps streamHolo/openHoloFiles over the pack URL (Range → release →
9
+ // κ-route → OPFS); node wraps a local file. `persist` (makeKappaStore) optional for the shared OPFS warm.
10
+ import { openHoloStream } from "../holo-archive.mjs";
11
+
12
+ const b64dec = (b64) => (typeof Buffer !== "undefined" ? new Uint8Array(Buffer.from(b64, "base64")) : Uint8Array.from(atob(b64), (c) => c.charCodeAt(0)));
13
+
14
+ export async function openModelPack({ rangeReader, persist = null } = {}) {
15
+ if (!rangeReader) throw new Error("openModelPack needs a rangeReader(off,len)->Uint8Array");
16
+ const s = await openHoloStream(rangeReader); // one open over the whole pack
17
+ const manifest = JSON.parse(new TextDecoder().decode(s.headerBytes));
18
+ if (!manifest || manifest.format !== "holo-pack/1") throw new Error("not a q-models pack");
19
+
20
+ function model(id) {
21
+ const m = manifest.models[id];
22
+ if (!m) throw new Error("model not in pack: " + id);
23
+ // per-model baked header: OLD packs inline it as base64 (m.ext, available sync); NEW split-manifest packs store it
24
+ // as a κ-BODY (m.extKappa) fetched lazily — so OPENING the pack reads ~100 KB not ~29 MB of headers. A loader that
25
+ // needs headerBytes calls await ensureHeader() first (no-op when inline). Both formats supported, no faculty rewrite.
26
+ let _header = m.ext ? b64dec(m.ext) : null;
27
+ // SHAPE == openHoloStream's return (order/getBody/headerBytes) — faculties don't change a line.
28
+ return {
29
+ id, kind: m.kind, tier: m.tier,
30
+ meta: Object.assign({}, m.meta, { order: m.order, arch: (m.meta && m.meta.arch) || id }),
31
+ order: m.order,
32
+ files: m.files || [],
33
+ get headerBytes() { return _header; },
34
+ ensureHeader: async () => { if (_header == null && m.extKappa) _header = await s.getBody(m.extKappa); return _header; },
35
+ getBody: s.getBody, // SHARED over the pack (same dir, same OPFS)
36
+ getBodySlice: s.getBodySlice,
37
+ dir: s.dir,
38
+ bodyLen: s.bodyLen,
39
+ names: m.order.map((o) => o.name),
40
+ fileBody: async (name) => { const f = (m.files || []).find((x) => x.name === name) || m.order.find((x) => x.name === name); if (!f) throw new Error("no file " + name + " in " + id); return s.getBody(f.kappa); },
41
+ };
42
+ }
43
+
44
+ return { manifest, getBody: s.getBody, dir: s.dir, models: () => Object.keys(manifest.models), model };
45
+ }
46
+
47
+ export default openModelPack;
apps/q/forge/gpu/holo-moonshine-asr.mjs ADDED
@@ -0,0 +1,219 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // holo-moonshine-asr.mjs — Q's κ-native WebGPU ear, Moonshine edition. Same interface as holo-whisper-asr
2
+ // (createMoonshineASR(url).transcribe(pcm16k) → {text, ids, gpuMs, ms}) but Moonshine arch: RAW audio (NO
3
+ // mel) → conv stem → RoPE encoder → KV-cache RoPE/cross decoder → gated SwiGLU → tied head → SPM detok.
4
+ // Weights 100% κ-streamed + L5-verified from the .holo. Decode is incremental (KV-cache) for live latency.
5
+ import { streamHolo } from "./holo-whisper-stream.mjs";
6
+
7
+ // Llama SentencePiece detok: Replace(▁→space) → ByteFallback(<0xNN>→byte) → Fuse → Strip one leading space.
8
+ function makeDetok(tokJson) {
9
+ const vocab = tokJson.model.vocab, inv = []; for (const [tok, id] of Object.entries(vocab)) inv[id] = tok;
10
+ const tenc = new TextEncoder(), tdec = new TextDecoder();
11
+ return (ids) => {
12
+ const bytes = [];
13
+ for (const id of ids) { if (id <= 2) continue; const piece = inv[id]; if (piece === undefined) continue;
14
+ const m = /^<0x([0-9A-Fa-f]{2})>$/.exec(piece);
15
+ if (m) bytes.push(parseInt(m[1], 16));
16
+ else { const u = tenc.encode(piece.replace(/▁/g, " ")); for (const b of u) bytes.push(b); } }
17
+ let t = tdec.decode(new Uint8Array(bytes)); return t.startsWith(" ") ? t.slice(1) : t;
18
+ };
19
+ }
20
+
21
+ const CONV1F = `@group(0)@binding(0)var<storage,read>inp:array<f32>;@group(0)@binding(1)var<storage,read>w:array<f32>;@group(0)@binding(2)var<storage,read>b:array<f32>;@group(0)@binding(3)var<storage,read_write>outp:array<f32>;@group(0)@binding(4)var<uniform>p:vec4<u32>;@group(0)@binding(5)var<uniform>q:vec4<u32>;
22
+ @compute @workgroup_size(64)fn main(@builtin(global_invocation_id)g:vec3<u32>){let idx=g.x;let IC=p.x;let OC=p.y;let K=p.z;let OL=p.w;let L=q.x;let stride=q.y;if(idx>=OC*OL){return;}
23
+ let oc=idx/OL;let ol=idx%OL;var s=select(0.0,b[oc],q.w==1u);let wb=oc*IC*K;let st=ol*stride;for(var ic=0u;ic<IC;ic++){let ib=ic*L;let wcb=wb+ic*K;for(var k=0u;k<K;k++){s=s+inp[ib+st+k]*w[wcb+k];}}outp[oc*OL+ol]=s;}`;
24
+ const TANH = `@group(0)@binding(0)var<storage,read_write>c:array<f32>;@group(0)@binding(1)var<uniform>p:vec4<u32>;@compute @workgroup_size(64)fn main(@builtin(global_invocation_id)g:vec3<u32>){if(g.x>=p.x){return;}c[g.x]=tanh(c[g.x]);}`;
25
+ const GELU = `@group(0)@binding(0)var<storage,read_write>c:array<f32>;@group(0)@binding(1)var<uniform>p:vec4<u32>;
26
+ fn erf(x:f32)->f32{let s=sign(x);let ax=abs(x);let t=1.0/(1.0+0.3275911*ax);let y=1.0-(((((1.061405429*t-1.453152027)*t)+1.421413741)*t-0.284496736)*t+0.254829592)*t*exp(-ax*ax);return s*y;}
27
+ @compute @workgroup_size(64)fn main(@builtin(global_invocation_id)g:vec3<u32>){if(g.x>=p.x){return;}let x=c[g.x];c[g.x]=0.5*x*(1.0+erf(x*0.7071067811865476));}`;
28
+ const GNSTATS = `@group(0)@binding(0)var<storage,read>x:array<f32>;@group(0)@binding(1)var<storage,read_write>o:array<f32>;@group(0)@binding(2)var<uniform>p:vec4<u32>;
29
+ var<workgroup> ss:array<f32,256>;var<workgroup> sq:array<f32,256>;
30
+ @compute @workgroup_size(256)fn main(@builtin(local_invocation_id)l:vec3<u32>){let t=l.x;let N=p.x;var a=0.0;var b=0.0;for(var i=t;i<N;i=i+256u){let v=x[i];a=a+v;b=b+v*v;}ss[t]=a;sq[t]=b;workgroupBarrier();
31
+ var st=128u;loop{if(st==0u){break;}if(t<st){ss[t]=ss[t]+ss[t+st];sq[t]=sq[t]+sq[t+st];}workgroupBarrier();st=st/2u;}
32
+ if(t==0u){let m=ss[0]/f32(N);let v=sq[0]/f32(N)-m*m;o[0]=m;o[1]=1.0/sqrt(v+1e-5);}}`;
33
+ const GNAPPLY = `@group(0)@binding(0)var<storage,read_write>x:array<f32>;@group(0)@binding(1)var<storage,read>st:array<f32>;@group(0)@binding(2)var<storage,read>w:array<f32>;@group(0)@binding(3)var<storage,read>b:array<f32>;@group(0)@binding(4)var<uniform>p:vec4<u32>;
34
+ @compute @workgroup_size(64)fn main(@builtin(global_invocation_id)g:vec3<u32>){let idx=g.x;let C=p.x;let T=p.y;if(idx>=C*T){return;}x[idx]=(x[idx]-st[0])*st[1]*w[idx/T]+b[idx/T];}`;
35
+ const TRANSP = `@group(0)@binding(0)var<storage,read>inp:array<f32>;@group(0)@binding(1)var<storage,read_write>o:array<f32>;@group(0)@binding(2)var<uniform>p:vec4<u32>;
36
+ @compute @workgroup_size(64)fn main(@builtin(global_invocation_id)g:vec3<u32>){let idx=g.x;let F=p.x;let S=p.y;if(idx>=F*S){return;}let f=idx/S;let c=idx%S;o[idx]=inp[c*F+f];}`;
37
+ const TILED = `@group(0)@binding(0)var<storage,read>A:array<f32>;@group(0)@binding(1)var<storage,read>B:array<f32>;@group(0)@binding(2)var<storage,read>bias:array<f32>;@group(0)@binding(3)var<storage,read_write>Y:array<f32>;@group(0)@binding(4)var<uniform>p:vec4<u32>;
38
+ var<workgroup> As:array<f32,256>;var<workgroup> Bs:array<f32,256>;
39
+ @compute @workgroup_size(16,16)fn main(@builtin(workgroup_id)wg:vec3<u32>,@builtin(local_invocation_id)l:vec3<u32>){
40
+ let rows=p.x;let inD=p.y;let outD=p.z;let tx=l.x;let ty=l.y;let r=wg.y*16u+ty;let o=wg.x*16u+tx;var acc=0.0;let nT=(inD+15u)/16u;
41
+ for(var kt=0u;kt<nT;kt++){let ai=kt*16u+tx;let bi=kt*16u+ty;
42
+ As[ty*16u+tx]=select(0.0,A[r*inD+ai],r<rows&&ai<inD);Bs[ty*16u+tx]=select(0.0,B[o*inD+bi],o<outD&&bi<inD);
43
+ workgroupBarrier();for(var kk=0u;kk<16u;kk++){acc=acc+As[ty*16u+kk]*Bs[kk*16u+tx];}workgroupBarrier();}
44
+ if(r<rows&&o<outD){Y[r*outD+o]=acc+select(0.0,bias[o],p.w==1u);}}`;
45
+ const LN = `@group(0)@binding(0)var<storage,read>x:array<f32>;@group(0)@binding(1)var<storage,read>w:array<f32>;@group(0)@binding(2)var<storage,read>b:array<f32>;@group(0)@binding(3)var<storage,read_write>y:array<f32>;@group(0)@binding(4)var<uniform>p:vec4<u32>;
46
+ @compute @workgroup_size(64)fn main(@builtin(global_invocation_id)g:vec3<u32>){let row=g.x;let n=p.x;let S=p.y;if(row>=n){return;}let base=row*S;var mean=0.0;for(var i=0u;i<S;i++){mean=mean+x[base+i];}mean=mean/f32(S);var v=0.0;for(var i=0u;i<S;i++){let d=x[base+i]-mean;v=v+d*d;}let sc=1.0/sqrt(v/f32(S)+1e-5);for(var i=0u;i<S;i++){y[base+i]=(x[base+i]-mean)*sc*w[i]+b[i];}}`;
47
+ const ROPE = `@group(0)@binding(0)var<storage,read_write>v:array<f32>;@group(0)@binding(1)var<uniform>p:vec4<u32>;@group(0)@binding(2)var<uniform>pb:vec4<u32>;
48
+ @compute @workgroup_size(64)fn main(@builtin(global_invocation_id)g:vec3<u32>){let idx=g.x;let n=p.x;let S=p.y;let H=p.z;let hd=p.w;let half=16u;let rot=32u;if(idx>=n*H*half){return;}
49
+ let row=idx/(H*half);let rem=idx%(H*half);let h=rem/half;let j=rem%half;let pos=row+pb.x;let base=row*S+h*hd;let i0=base+2u*j;
50
+ let freq=exp(-(f32(2u*j)/f32(rot))*9.210340371976182);let ang=f32(pos)*freq;let c=cos(ang);let s=sin(ang);
51
+ let a=v[i0];let b=v[i0+1u];v[i0]=a*c-b*s;v[i0+1u]=b*c+a*s;}`;
52
+ const ATTN = `@group(0)@binding(0)var<storage,read>q:array<f32>;@group(0)@binding(1)var<storage,read>k:array<f32>;@group(0)@binding(2)var<storage,read>v:array<f32>;@group(0)@binding(3)var<storage,read_write>o:array<f32>;@group(0)@binding(4)var<uniform>p:vec4<u32>;@group(0)@binding(5)var<uniform>pc:vec4<u32>;@group(0)@binding(6)var<uniform>pf:vec4<f32>;
53
+ @compute @workgroup_size(64)fn main(@builtin(global_invocation_id)g:vec3<u32>){let idx=g.x;let nQ=p.x;let nK=p.y;let H=p.z;let hd=p.w;let Sd=H*hd;let scale=pf.x;if(idx>=H*nQ){return;}
54
+ let h=idx/nQ;let i=idx%nQ;let ho=h*hd;let qb=i*Sd+ho;let lim=select(nK,i+1u,pc.x==1u);
55
+ var m=-3.0e38;var l=0.0;var acc:array<f32,64>;for(var d=0u;d<hd;d++){acc[d]=0.0;}
56
+ for(var jj=0u;jj<lim;jj++){let kb=jj*Sd+ho;var s=0.0;for(var d=0u;d<hd;d++){s=s+q[qb+d]*k[kb+d];}s=s*scale;let mn=max(m,s);let cr=exp(m-mn);let e=exp(s-mn);l=l*cr+e;let vb=jj*Sd+ho;for(var d=0u;d<hd;d++){acc[d]=acc[d]*cr+e*v[vb+d];}m=mn;}
57
+ let ob=i*Sd+ho;for(var d=0u;d<hd;d++){o[ob+d]=acc[d]/l;}}`;
58
+ const SWIGLU = `@group(0)@binding(0)var<storage,read>h1:array<f32>;@group(0)@binding(1)var<storage,read_write>gg:array<f32>;@group(0)@binding(2)var<uniform>p:vec4<u32>;
59
+ @compute @workgroup_size(64)fn main(@builtin(global_invocation_id)g:vec3<u32>){let idx=g.x;let n=p.x;let IFF=p.y;if(idx>=n*IFF){return;}let r=idx/IFF;let o=idx%IFF;let gate=h1[r*2u*IFF+IFF+o];let hid=h1[r*2u*IFF+o];gg[idx]=(gate/(1.0+exp(-gate)))*hid;}`;
60
+ const ADD = `@group(0)@binding(0)var<storage,read_write>x:array<f32>;@group(0)@binding(1)var<storage,read>y:array<f32>;@group(0)@binding(2)var<uniform>p:vec4<u32>;@compute @workgroup_size(64)fn main(@builtin(global_invocation_id)g:vec3<u32>){if(g.x>=p.x){return;}x[g.x]=x[g.x]+y[g.x];}`;
61
+ // EMBED: dx[d] = embed[ids[pos]*S+d] (token stays on GPU → no per-token CPU round-trip)
62
+ const EMBED = `@group(0)@binding(0)var<storage,read>ids:array<u32>;@group(0)@binding(1)var<storage,read>te:array<f32>;@group(0)@binding(2)var<storage,read_write>x:array<f32>;@group(0)@binding(3)var<uniform>p:vec4<u32>;
63
+ @compute @workgroup_size(64)fn main(@builtin(global_invocation_id)g:vec3<u32>){let d=g.x;let pos=p.x;let S=p.y;if(d>=S){return;}x[d]=te[ids[pos]*S+d];}`;
64
+ // GPU argmax over full vocab (Moonshine: no token suppression) → writes next id into ids[outPos]
65
+ const ARGMAX = `@group(0)@binding(0)var<storage,read>logits:array<f32>;@group(0)@binding(1)var<storage,read_write>ids:array<u32>;@group(0)@binding(2)var<uniform>p:vec4<u32>;
66
+ var<workgroup> bV:array<f32,256>;var<workgroup> bI:array<u32,256>;
67
+ @compute @workgroup_size(256)fn main(@builtin(local_invocation_id)l:vec3<u32>){let t=l.x;let V=p.y;var mv=-3.0e38;var mi=0u;
68
+ for(var i=t;i<V;i=i+256u){let s=logits[i];if(s>mv){mv=s;mi=i;}}
69
+ bV[t]=mv;bI[t]=mi;workgroupBarrier();
70
+ var st=128u;loop{if(st==0u){break;}if(t<st){if(bV[t+st]>bV[t]){bV[t]=bV[t+st];bI[t]=bI[t+st];}}workgroupBarrier();st=st/2u;}
71
+ if(t==0u){ids[p.x]=bI[0];}}`;
72
+ // in-shader int8 dequant tiled GEMM: B = int8 weights packed 4/u32, per-row f32 scale → ¼ GPU mem + ~1.8× (bandwidth)
73
+ const TILED_Q8 = `@group(0)@binding(0)var<storage,read>A:array<f32>;@group(0)@binding(1)var<storage,read>B:array<u32>;@group(0)@binding(2)var<storage,read>scl:array<f32>;@group(0)@binding(3)var<storage,read>bias:array<f32>;@group(0)@binding(4)var<storage,read_write>Y:array<f32>;@group(0)@binding(5)var<uniform>p:vec4<u32>;
74
+ var<workgroup> As:array<f32,256>;var<workgroup> Bs:array<f32,256>;
75
+ fn rdq(idx:u32)->f32{let w=B[idx>>2u];let sh=(idx&3u)*8u;let b=(w>>sh)&0xffu;return f32(i32(b<<24u)>>24u);}
76
+ @compute @workgroup_size(16,16)fn main(@builtin(workgroup_id)wg:vec3<u32>,@builtin(local_invocation_id)l:vec3<u32>){
77
+ let rows=p.x;let inD=p.y;let outD=p.z;let tx=l.x;let ty=l.y;let r=wg.y*16u+ty;let o=wg.x*16u+tx;var acc=0.0;let nT=(inD+15u)/16u;
78
+ for(var kt=0u;kt<nT;kt++){let ai=kt*16u+tx;let bi=kt*16u+ty;
79
+ As[ty*16u+tx]=select(0.0,A[r*inD+ai],r<rows&&ai<inD);Bs[ty*16u+tx]=select(0.0,rdq(o*inD+bi),o<outD&&bi<inD);
80
+ workgroupBarrier();for(var kk=0u;kk<16u;kk++){acc=acc+As[ty*16u+kk]*Bs[kk*16u+tx];}workgroupBarrier();}
81
+ if(r<rows&&o<outD){Y[r*outD+o]=acc*scl[o]+select(0.0,bias[o],p.w==1u);}}`;
82
+ // int8 embedding gather: dx[d] = int8_embed[tok*S+d] * scale[tok]
83
+ const EMBED_Q8 = `@group(0)@binding(0)var<storage,read>ids:array<u32>;@group(0)@binding(1)var<storage,read>te:array<u32>;@group(0)@binding(2)var<storage,read>scl:array<f32>;@group(0)@binding(3)var<storage,read_write>x:array<f32>;@group(0)@binding(4)var<uniform>p:vec4<u32>;
84
+ fn rdq(idx:u32)->f32{let w=te[idx>>2u];let sh=(idx&3u)*8u;let b=(w>>sh)&0xffu;return f32(i32(b<<24u)>>24u);}
85
+ @compute @workgroup_size(64)fn main(@builtin(global_invocation_id)g:vec3<u32>){let d=g.x;let pos=p.x;let S=p.y;if(d>=S){return;}let tok=ids[pos];x[d]=rdq(tok*S+d)*scl[tok];}`;
86
+
87
+ export async function createMoonshineASR(holoUrl, { onProgress, kappa = "", release = "", openStream = null } = {}) {
88
+ if (!navigator.gpu) throw new Error("no WebGPU");
89
+ const log = (s) => onProgress && onProgress(s);
90
+ log("streaming Moonshine by κ…");
91
+ const H0 = await (openStream || streamHolo)(holoUrl, { kappa, release }); // openStream = unified-pack view (fail-soft → streamHolo)
92
+ const cfg = H0.meta.config, S = cfg.hidden_size, NH = cfg.encoder_num_attention_heads, hd = S / NH, IFF = cfg.intermediate_size;
93
+ const NL = cfg.encoder_num_hidden_layers, DL = cfg.decoder_num_hidden_layers, VOCAB = cfg.vocab_size, scale = 1 / Math.sqrt(hd);
94
+ const detok = makeDetok(JSON.parse(new TextDecoder().decode(H0.headerBytes)));
95
+ const W = new Map(); await Promise.all(H0.meta.order.map(async (o) => W.set(o.name, await H0.getF32(o.name))));
96
+ log(`streamed ${W.size} tensors · ${(H0.stats.bytesFetched / 1e6).toFixed(1)}MB · ${H0.stats.verifies} L5${H0.stats.opfsHits ? " · " + H0.stats.opfsHits + " OPFS" : ""}`);
97
+
98
+ const dev = await (await navigator.gpu.requestAdapter()).requestDevice();
99
+ const pipe = (c) => dev.createComputePipeline({ layout: "auto", compute: { module: dev.createShaderModule({ code: c }), entryPoint: "main" } });
100
+ const P = { conv: pipe(CONV1F), tanh: pipe(TANH), gelu: pipe(GELU), gns: pipe(GNSTATS), gna: pipe(GNAPPLY), transp: pipe(TRANSP), tiled: pipe(TILED), tiledq8: pipe(TILED_Q8), ln: pipe(LN), rope: pipe(ROPE), attn: pipe(ATTN), swiglu: pipe(SWIGLU), add: pipe(ADD), emb: pipe(EMBED), embq8: pipe(EMBED_Q8), argmax: pipe(ARGMAX) };
101
+ const sb = (k) => dev.createBuffer({ size: Math.max(4, k * 4), usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_SRC | GPUBufferUsage.COPY_DST });
102
+ const wb = (a) => { const b = dev.createBuffer({ size: Math.max(4, a.byteLength), usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST }); dev.queue.writeBuffer(b, 0, a); return b; };
103
+ const u4 = (v) => { const b = dev.createBuffer({ size: 16, usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST }); dev.queue.writeBuffer(b, 0, new Uint32Array([...v, 0, 0, 0, 0].slice(0, 4))); return b; };
104
+ const f4 = (v) => { const b = dev.createBuffer({ size: 16, usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST }); dev.queue.writeBuffer(b, 0, new Float32Array([...v, 0, 0, 0, 0].slice(0, 4))); return b; };
105
+ const G = (k) => Math.ceil(k / 64), T16 = (x) => Math.ceil(x / 16);
106
+ const bg = (pl, a) => dev.createBindGroup({ layout: pl.getBindGroupLayout(0), entries: a.map((b, i) => ({ binding: i, resource: { buffer: b } })) });
107
+ const disp = (e, pl, a, k, wg) => { const pa = e.beginComputePass(); pa.setPipeline(pl); pa.setBindGroup(0, bg(pl, a)); pa.dispatchWorkgroups(wg || G(k)); pa.end(); };
108
+ const i8buf = (u8) => { const b = dev.createBuffer({ size: Math.max(4, Math.ceil(u8.length / 4) * 4), usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST }); dev.queue.writeBuffer(b, 0, u8); return b; };
109
+ // tile() now takes a TYPED weight w = {f32:buf} or {q8:buf, sc:buf} → routes to TILED or in-shader int8 TILED_Q8
110
+ const tile = (e, A, w, bias, Y, rows, inD, outD, hb) => { const pa = e.beginComputePass();
111
+ if (w.q8) { pa.setPipeline(P.tiledq8); pa.setBindGroup(0, bg(P.tiledq8, [A, w.q8, w.sc, bias, Y, u4([rows, inD, outD, hb])])); }
112
+ else { pa.setPipeline(P.tiled); pa.setBindGroup(0, bg(P.tiled, [A, w.f32, bias, Y, u4([rows, inD, outD, hb])])); }
113
+ pa.dispatchWorkgroups(T16(outD), T16(rows)); pa.end(); };
114
+ const GW = (n) => wb(W.get(n)), dummy = wb(new Float32Array([0])), zeroS = wb(new Float32Array(S));
115
+ const readback = async (buf, len) => { const rb = dev.createBuffer({ size: len * 4, usage: GPUBufferUsage.COPY_DST | GPUBufferUsage.MAP_READ }); const e = dev.createCommandEncoder(); e.copyBufferToBuffer(buf, 0, rb, 0, len * 4); dev.queue.submit([e.finish()]); await rb.mapAsync(GPUMapMode.READ); const r = new Float32Array(rb.getMappedRange().slice(0)); rb.unmap(); rb.destroy(); return r; };
116
+
117
+ // resident weights: matmul weights (.q/k/v/o_proj, .fc1/fc2, embed) = TYPED (int8 in-shader when the .holo
118
+ // is int8 → ¼ GPU mem + ~1.8× matmul); conv + 1D (norm/bias) stay f32 buffers. f16/f32 models → {f32} (untouched).
119
+ const isMM = (n) => /(q_proj|k_proj|v_proj|o_proj|fc1|fc2)\.weight$/.test(n) || n === "model.decoder.embed_tokens.weight";
120
+ const loadW = async (name) => { const q = await H0.getQuant(name); return q.q8 ? { q8: i8buf(q.int8), sc: wb(q.scales) } : { f32: wb(q.f32) }; };
121
+ const EW = {}, DW = {};
122
+ for (const o of H0.meta.order) {
123
+ if (o.name.startsWith("model.encoder.")) EW[o.name] = isMM(o.name) ? await loadW(o.name) : GW(o.name);
124
+ else if (o.name.startsWith("model.decoder.layers.")) DW[o.name] = isMM(o.name) ? await loadW(o.name) : GW(o.name);
125
+ }
126
+ const embedW = await loadW("model.decoder.embed_tokens.weight"), dnorm = GW("model.decoder.norm.weight");
127
+ const q8model = !!embedW.q8;
128
+ const fScale = f4([scale]), causal0 = u4([0]), causal1 = u4([1]), pb0 = u4([0]);
129
+ const MAXTOK = 256, EOS = 2, BOS = 1;
130
+
131
+ async function transcribe(pcm16k, { maxNew = 200 } = {}) {
132
+ const tg = performance.now();
133
+ const L = pcm16k.length, T1 = ((L - 127) / 64 | 0) + 1, T2 = ((T1 - 7) / 3 | 0) + 1, frames = ((T2 - 3) / 2 | 0) + 1, C2 = 2 * S;
134
+ const pcmB = wb(pcm16k), c1 = sb(S * T1), c2 = sb(C2 * T2), c3 = sb(S * frames), gstat = sb(2), encX = sb(frames * S);
135
+ let e = dev.createCommandEncoder();
136
+ disp(e, P.conv, [pcmB, EW["model.encoder.conv1.weight"], dummy, c1, u4([1, S, 127, T1]), u4([L, 64, 0, 0])], S * T1);
137
+ disp(e, P.tanh, [c1, u4([S * T1])], S * T1);
138
+ disp(e, P.gns, [c1, gstat, u4([S * T1])], 0, 1);
139
+ disp(e, P.gna, [c1, gstat, EW["model.encoder.groupnorm.weight"], EW["model.encoder.groupnorm.bias"], u4([S, T1])], S * T1);
140
+ disp(e, P.conv, [c1, EW["model.encoder.conv2.weight"], EW["model.encoder.conv2.bias"], c2, u4([S, C2, 7, T2]), u4([T1, 3, 0, 1])], C2 * T2);
141
+ disp(e, P.gelu, [c2, u4([C2 * T2])], C2 * T2);
142
+ disp(e, P.conv, [c2, EW["model.encoder.conv3.weight"], EW["model.encoder.conv3.bias"], c3, u4([C2, S, 3, frames]), u4([T2, 2, 0, 1])], S * frames);
143
+ disp(e, P.gelu, [c3, u4([S * frames])], S * frames);
144
+ disp(e, P.transp, [c3, encX, u4([frames, S])], frames * S);
145
+ // encoder layers
146
+ const an = sb(frames * S), q = sb(frames * S), k = sb(frames * S), v = sb(frames * S), at = sb(frames * S), ao = sb(frames * S), mn = sb(frames * S), h1 = sb(frames * IFF), h2 = sb(frames * S);
147
+ const aEnc = u4([frames, frames, NH, hd]), uNES = u4([frames, S]), uNEadd = u4([frames * S]), uIFF = u4([frames * IFF]), uRopeE = u4([frames, S, NH, hd]);
148
+ for (let il = 0; il < NL; il++) { const pf = `model.encoder.layers.${il}.`;
149
+ disp(e, P.ln, [encX, EW[pf + "input_layernorm.weight"], zeroS, an, uNES], frames);
150
+ tile(e, an, EW[pf + "self_attn.q_proj.weight"], dummy, q, frames, S, S, 0);
151
+ tile(e, an, EW[pf + "self_attn.k_proj.weight"], dummy, k, frames, S, S, 0);
152
+ tile(e, an, EW[pf + "self_attn.v_proj.weight"], dummy, v, frames, S, S, 0);
153
+ disp(e, P.rope, [q, uRopeE, pb0], frames * NH * 16); disp(e, P.rope, [k, uRopeE, pb0], frames * NH * 16);
154
+ disp(e, P.attn, [q, k, v, at, aEnc, causal0, fScale], NH * frames);
155
+ tile(e, at, EW[pf + "self_attn.o_proj.weight"], dummy, ao, frames, S, S, 0);
156
+ disp(e, P.add, [encX, ao, uNEadd], frames * S);
157
+ disp(e, P.ln, [encX, EW[pf + "post_attention_layernorm.weight"], zeroS, mn, uNES], frames);
158
+ tile(e, mn, EW[pf + "mlp.fc1.weight"], EW[pf + "mlp.fc1.bias"], h1, frames, S, IFF, 1);
159
+ disp(e, P.gelu, [h1, uIFF], frames * IFF);
160
+ tile(e, h1, EW[pf + "mlp.fc2.weight"], EW[pf + "mlp.fc2.bias"], h2, frames, IFF, S, 1);
161
+ disp(e, P.add, [encX, h2, uNEadd], frames * S);
162
+ }
163
+ const encO = sb(frames * S);
164
+ disp(e, P.ln, [encX, EW["model.encoder.layer_norm.weight"], zeroS, encO, uNES], frames);
165
+ // cross K/V per layer (once)
166
+ const cK = [], cV = []; for (let il = 0; il < DL; il++) { const pf = `model.decoder.layers.${il}.`; cK[il] = sb(frames * S); cV[il] = sb(frames * S); tile(e, encO, DW[pf + "encoder_attn.k_proj.weight"], dummy, cK[il], frames, S, S, 0); tile(e, encO, DW[pf + "encoder_attn.v_proj.weight"], dummy, cV[il], frames, S, S, 0); }
167
+ dev.queue.submit([e.finish()]);
168
+ const encMs = Math.round(performance.now() - tg);
169
+
170
+ // GPU-resident chunked decode: EMBED reads the ids buffer, GPU ARGMAX writes the next id → ONE submit
171
+ // per chunk (no per-token CPU round-trip / 32768-logit readback). Read ids back per chunk to stop at EOS.
172
+ const Kc = [], Vc = []; for (let il = 0; il < DL; il++) { Kc[il] = sb(MAXTOK * S); Vc[il] = sb(MAXTOK * S); }
173
+ const idsB = dev.createBuffer({ size: (MAXTOK + 1) * 4, usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_SRC | GPUBufferUsage.COPY_DST }); dev.queue.writeBuffer(idsB, 0, new Uint32Array([BOS]));
174
+ const idsRb = dev.createBuffer({ size: (MAXTOK + 1) * 4, usage: GPUBufferUsage.COPY_DST | GPUBufferUsage.MAP_READ });
175
+ const dx = sb(S), dan = sb(S), dq = sb(S), dk = sb(S), dvv = sb(S), dsa = sb(S), dso = sb(S), dcn = sb(S), dcq = sb(S), dcr = sb(S), dco = sb(S), dmn = sb(S), dh1 = sb(2 * IFF), dgg = sb(IFF), dh2 = sb(S), logitsB = sb(VOCAB);
176
+ const u1 = u4([1, S]), aCross = u4([1, frames, NH, hd]), uadd = u4([S]), uswig = u4([1, IFF]);
177
+ const gen = []; const td = performance.now(); const CH = 16, limit = Math.min(maxNew, MAXTOK - 2); let p = 0, eot = false;
178
+ while (p < limit && !eot) {
179
+ const end = Math.min(p + CH, limit); const ec = dev.createCommandEncoder();
180
+ for (; p < end; p++) {
181
+ const pbP = u4([p]), aSelf = u4([1, p + 1, NH, hd]), uRope1 = u4([1, S, NH, hd]);
182
+ if (q8model) disp(ec, P.embq8, [idsB, embedW.q8, embedW.sc, dx, u4([p, S])], S);
183
+ else disp(ec, P.emb, [idsB, embedW.f32, dx, u4([p, S])], S);
184
+ for (let il = 0; il < DL; il++) { const pf = `model.decoder.layers.${il}.`;
185
+ disp(ec, P.ln, [dx, DW[pf + "input_layernorm.weight"], zeroS, dan, u1], 1);
186
+ tile(ec, dan, DW[pf + "self_attn.q_proj.weight"], dummy, dq, 1, S, S, 0);
187
+ tile(ec, dan, DW[pf + "self_attn.k_proj.weight"], dummy, dk, 1, S, S, 0);
188
+ tile(ec, dan, DW[pf + "self_attn.v_proj.weight"], dummy, dvv, 1, S, S, 0);
189
+ disp(ec, P.rope, [dq, uRope1, pbP], NH * 16); disp(ec, P.rope, [dk, uRope1, pbP], NH * 16);
190
+ ec.copyBufferToBuffer(dk, 0, Kc[il], p * S * 4, S * 4); ec.copyBufferToBuffer(dvv, 0, Vc[il], p * S * 4, S * 4);
191
+ disp(ec, P.attn, [dq, Kc[il], Vc[il], dsa, aSelf, causal0, fScale], NH);
192
+ tile(ec, dsa, DW[pf + "self_attn.o_proj.weight"], dummy, dso, 1, S, S, 0);
193
+ disp(ec, P.add, [dx, dso, uadd], S);
194
+ disp(ec, P.ln, [dx, DW[pf + "post_attention_layernorm.weight"], zeroS, dcn, u1], 1);
195
+ tile(ec, dcn, DW[pf + "encoder_attn.q_proj.weight"], dummy, dcq, 1, S, S, 0);
196
+ disp(ec, P.attn, [dcq, cK[il], cV[il], dcr, aCross, causal0, fScale], NH);
197
+ tile(ec, dcr, DW[pf + "encoder_attn.o_proj.weight"], dummy, dco, 1, S, S, 0);
198
+ disp(ec, P.add, [dx, dco, uadd], S);
199
+ disp(ec, P.ln, [dx, DW[pf + "final_layernorm.weight"], zeroS, dmn, u1], 1);
200
+ tile(ec, dmn, DW[pf + "mlp.fc1.weight"], DW[pf + "mlp.fc1.bias"], dh1, 1, S, 2 * IFF, 1);
201
+ disp(ec, P.swiglu, [dh1, dgg, uswig], IFF);
202
+ tile(ec, dgg, DW[pf + "mlp.fc2.weight"], DW[pf + "mlp.fc2.bias"], dh2, 1, IFF, S, 1);
203
+ disp(ec, P.add, [dx, dh2, uadd], S);
204
+ }
205
+ disp(ec, P.ln, [dx, dnorm, zeroS, dan, u1], 1);
206
+ tile(ec, dan, embedW, dummy, logitsB, 1, S, VOCAB, 0);
207
+ disp(ec, P.argmax, [logitsB, idsB, u4([p + 1, VOCAB])], 0, 1);
208
+ }
209
+ ec.copyBufferToBuffer(idsB, 0, idsRb, 0, (MAXTOK + 1) * 4);
210
+ dev.queue.submit([ec.finish()]);
211
+ await idsRb.mapAsync(GPUMapMode.READ); const ids = new Uint32Array(idsRb.getMappedRange().slice(0)); idsRb.unmap();
212
+ gen.length = 0; for (let i = 1; i <= p; i++) { if (ids[i] === EOS) { eot = true; break; } gen.push(ids[i]); }
213
+ }
214
+ const gpuMs = Math.round(performance.now() - tg), decMs = Math.round(performance.now() - td);
215
+ [pcmB, c1, c2, c3, gstat, encX, an, q, k, v, at, ao, mn, h1, h2, encO, dx, dan, dq, dk, dvv, dsa, dso, dcn, dcq, dcr, dco, dmn, dh1, dgg, dh2, logitsB, idsB, idsRb, ...cK, ...cV, ...Kc, ...Vc].forEach((b) => b.destroy());
216
+ return { text: detok(gen), ids: gen, gpuMs, encMs, decMs, frames, ms: gpuMs };
217
+ }
218
+ return { transcribe, config: cfg, S, encNL: NL, decNL: DL, stats: H0.stats };
219
+ }
apps/q/forge/gpu/holo-moonshine-ear.mjs ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // holo-moonshine-ear.mjs — production adapter exposing the κ-native Moonshine WebGPU ASR engine to Q's voice
2
+ // stack (holo-voice-asr.mjs interface): createWhisperEar({ holoUrl, upgradeUrl, kappa, language }) →
3
+ // { load(progressCb), transcribe(pcm16k, opts) -> {text} }.
4
+ // FIRST-LOAD TIERING: load the small int8 .holo first (~¼ the bytes → talk in ~half the cold-start time),
5
+ // then silently stream the lossless f16 .holo in the background and hot-swap the engine. Same trick as Q's
6
+ // .holo brain (tiny-now → upgrade-silent). holo-voice-asr.mjs auto-falls back to ONNX if WebGPU/load fails.
7
+ import { createMoonshineASR } from "./holo-moonshine-asr.mjs";
8
+
9
+ export function createWhisperEar({ holoUrl, upgradeUrl, kappa, release, upgradeKappa, upgradeRelease, language } = {}, deps = {}) {
10
+ const openStream = deps.openStream || null; // unified-pack view (fail-soft → streamHolo inside createMoonshineASR)
11
+ let asr = null, tier = "", upgrading = false;
12
+ return {
13
+ async load(progress) {
14
+ asr = await createMoonshineASR(holoUrl, { onProgress: progress, kappa, release, openStream }); // fast tier (int8) — pack → path → Release → κ-route
15
+ tier = upgradeUrl ? "int8" : "base";
16
+ if (upgradeUrl) { // silent background upgrade to the lossless tier; hot-swap when it lands
17
+ upgrading = true;
18
+ createMoonshineASR(upgradeUrl, { kappa: upgradeKappa, release: upgradeRelease, openStream }).then((hi) => { asr = hi; tier = "f16"; upgrading = false; }).catch(() => { upgrading = false; });
19
+ }
20
+ return true;
21
+ },
22
+ async transcribe(audio, opts = {}) {
23
+ if (!asr) await this.load();
24
+ const a = asr; // pin the current tier for this call (background swap won't disturb an in-flight transcribe)
25
+ const r = await a.transcribe(audio, opts);
26
+ return { text: r.text, ids: r.ids, ms: r.ms, gpuMs: r.gpuMs, tier }; // {text,…} shape Holo Voice consumes
27
+ },
28
+ info: () => ({ engine: "moonshine-κ", holoUrl, upgradeUrl, kappa, tier, upgrading }),
29
+ };
30
+ }
31
+ export default createWhisperEar;
apps/q/forge/gpu/holo-onnx-kserve.mjs ADDED
@@ -0,0 +1,53 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // holo-onnx-kserve.mjs — serve an ONNX faculty model's files from its κ-addressable .holo INTO the
2
+ // unchanged transformers.js / onnxruntime-web runtime. ONE shim for every ONNX faculty (TTS · embed ·
3
+ // vision): no engine port — only weight DELIVERY becomes content-addressed (HTTP-Range + per-block L5 +
4
+ // OPFS warm cache + serverless multi-source), exactly like the κ-native brain/ASR, but the forward stays on
5
+ // the proven engine. Generalises the proof in kokoro-holo-test.html into a reusable, fail-safe module.
6
+ //
7
+ // serveModelFromHolo({ holoUrl, modelId, release }) → { stats, served, missed, restore, modelKey } (browser)
8
+ //
9
+ // Install BEFORE the engine loads; the engine then fetches its model files normally and the shim answers any
10
+ // request whose URL contains "<last-segment-of-modelId>/" from the .holo. Everything else passes through
11
+ // untouched (cheap substring test). Keep it installed for the engine's lifetime (lazy per-file fetches —
12
+ // e.g. a TTS voice — still route through it); call restore() to uninstall. ANY failure ⇒ the caller restores
13
+ // and falls back to the vendored ONNX path, so a faculty is never bricked by the κ path.
14
+
15
+ // the URL key a transformers model id resolves to: "onnx-community/Kokoro-82M-v1.0-ONNX" → "Kokoro-82M-v1.0-ONNX/"
16
+ export function modelKeyFor(modelId) { return String(modelId || "").split("/").pop() + "/"; }
17
+
18
+ // PURE, INJECTABLE routing core (Node-witnessable). Wraps target.fetch so any request whose URL contains
19
+ // `key` is answered from `hf.getFile(name)`; non-matching (and not-in-holo) requests fall through to the
20
+ // original transport. Returns the running served/missed lists and a restore() that reinstalls the original.
21
+ export function installModelFetchShim({ hf, key, target }) {
22
+ const orig = target.fetch; // the RAW original — restore() reinstalls this exact reference
23
+ const callOrig = orig.bind(target); // bound copy for safe invocation (window.fetch needs its this)
24
+ const served = [], missed = [];
25
+ const ResponseCtor = target.Response || (typeof Response !== "undefined" ? Response : null);
26
+ target.fetch = async (input, init) => {
27
+ const url = typeof input === "string" ? input : (input && input.url) || "";
28
+ const i = url.indexOf(key);
29
+ if (i >= 0) {
30
+ const name = decodeURIComponent(url.slice(i + key.length).split("?")[0]);
31
+ try {
32
+ const b = await hf.getFile(name);
33
+ served.push(name);
34
+ return new ResponseCtor(b, { status: 200, headers: { "Content-Type": "application/octet-stream", "Content-Length": String((b && (b.length || b.byteLength)) || 0) } });
35
+ } catch (e) { missed.push(name); } // not in the .holo → fall through to the original transport
36
+ }
37
+ return callOrig(input, init);
38
+ };
39
+ return { served, missed, restore() { target.fetch = orig; } };
40
+ }
41
+
42
+ // browser entry: open the file-bundle .holo (range + L5 + OPFS, release fallback) and install the shim on
43
+ // `target` (window by default). `openFiles` is injectable for tests; in the browser it lazy-imports holo-files.
44
+ export async function serveModelFromHolo({ holoUrl, modelId, release = "", target, openFiles } = {}) {
45
+ const t = target || (typeof window !== "undefined" ? window : globalThis);
46
+ const open = openFiles || (async (u, o) => (await import("./holo-files.mjs")).openHoloFiles(u, o));
47
+ const hf = await open(holoUrl, { release });
48
+ const key = modelKeyFor(modelId);
49
+ const shim = installModelFetchShim({ hf, key, target: t });
50
+ return { stats: hf.stats, served: shim.served, missed: shim.missed, restore: shim.restore, modelKey: key, files: hf.files };
51
+ }
52
+
53
+ export default serveModelFromHolo;
apps/q/forge/gpu/holo-pack-shards.mjs ADDED
@@ -0,0 +1,121 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // holo-pack-shards.mjs — present a sharded pack as ONE logical file. The single q-models.holo is delivered in <2 GiB
2
+ // parts (GitHub's per-asset cap); this stitches them behind a normal rangeReader(off,len) so openModelPack / every
3
+ // faculty loader sees one contiguous file at one address. Sharding is pure transport — never visible above here.
4
+ //
5
+ // spanReader(parts, readPart) → async (off,len) => Uint8Array // parts: [{start,len}]; readPart(i,off,len)->bytes
6
+ // makeShardedRangeReader({ parts, fetchPart }) → rangeReader // production: fetchPart(i,off,len) HTTP-Ranges part i
7
+ //
8
+ // A single read may straddle a part boundary; spanReader splits it across parts and concatenates. Production wires
9
+ // fetchPart to Range-GET part i from the release (κ-route/OPFS heal underneath), so a body that crosses a boundary
10
+ // is fetched from two assets transparently and L5-verified as one body by openHoloStream.
11
+
12
+ // stitch a logical [off,off+len) read across byte-contiguous parts. readPart(i, withinOff, n) returns ≥ n bytes.
13
+ export function spanReader(parts, readPart) {
14
+ const total = parts.reduce((mx, p) => Math.max(mx, p.start + p.len), 0);
15
+ return async (off, len) => {
16
+ if (off < 0 || off + len > total) throw new Error(`span read out of range: [${off},${off + len}) of ${total}`);
17
+ const out = new Uint8Array(len);
18
+ let done = 0;
19
+ while (done < len) {
20
+ const g = off + done;
21
+ const i = parts.findIndex((p) => g >= p.start && g < p.start + p.len);
22
+ if (i < 0) throw new Error("no part covers offset " + g);
23
+ const p = parts[i], within = g - p.start, n = Math.min(len - done, p.len - within);
24
+ const chunk = await readPart(i, within, n);
25
+ out.set(chunk.length > n ? chunk.subarray(0, n) : chunk, done);
26
+ done += n;
27
+ }
28
+ return out;
29
+ };
30
+ }
31
+
32
+ // production reader: parts from a manifest, each fetched via HTTP Range from its release asset URL (with κ-route/OPFS
33
+ // healing the bytes underneath). fetchPart(i, off, len) -> Promise<Uint8Array>.
34
+ export function makeShardedRangeReader({ parts, fetchPart }) {
35
+ return spanReader(parts, (i, off, len) => fetchPart(i, off, len));
36
+ }
37
+
38
+ // ── HTTP transport (production) ──────────────────────────────────────────────────────────────────
39
+ // one URL's Range read, handling a 206 (partial — the normal GitHub-release case) AND a server that ignores Range
40
+ // and returns 200-whole (defensive: cache the whole body once, slice locally thereafter). fetchImpl is injectable so
41
+ // the path is witnessed in Node with a mock fetch serving local shards.
42
+ export function makeRangeFetcher({ fetchImpl } = {}) {
43
+ const f = fetchImpl || (typeof fetch !== "undefined" ? fetch : null);
44
+ if (!f) throw new Error("makeRangeFetcher: no fetch available");
45
+ const whole = new Map(); // url → full body when the server ignored Range
46
+ return async (url, off, len) => {
47
+ const w = whole.get(url); if (w) return w.subarray(off, off + len);
48
+ let r; try { r = await f(url, { headers: { Range: `bytes=${off}-${off + len - 1}` } }); } catch (e) { r = null; }
49
+ if (!r || !r.ok) throw new Error("range fetch failed (" + (r ? r.status : "network") + "): " + url);
50
+ const u = new Uint8Array(await r.arrayBuffer());
51
+ if (r.status === 206) return u; // exact slice
52
+ if (u.length > len) { whole.set(url, u); return u.subarray(off, off + len); } // 200-whole → cache + slice
53
+ return u;
54
+ };
55
+ }
56
+
57
+ // open the unified pack over its SHARDS from a release: fetch the parts manifest, build a spanning rangeReader that
58
+ // Range-GETs each part. The result's rangeReader hands straight to openModelPack — the OS sees one file, one address.
59
+ // peerResolve(part) -> Promise<Uint8Array|null>: the COMMONS source. A part is content-addressed
60
+ // (part.sha256), so it can be served by ANY peer and is hash-trustless; openHoloStream L5-verifies the
61
+ // assembled body downstream regardless, so a wrong peer byte is caught (the commons is a latency choice,
62
+ // never trust — same contract as the CDN/IPFS sources). null/throw → fall through to CDN/origin.
63
+ export async function openShardedPack({ partsUrl, base, fetchImpl, gateway, peerResolve } = {}) {
64
+ const f = fetchImpl || (typeof fetch !== "undefined" ? fetch : null);
65
+ if (!f) throw new Error("openShardedPack: no fetch available");
66
+ if (!partsUrl) throw new Error("openShardedPack needs partsUrl");
67
+ // the manifest ships SAME-ORIGIN (tiny → in dist), so this fetch never hits a CORS wall.
68
+ const mr = await f(partsUrl); if (!mr || !mr.ok) throw new Error("parts manifest fetch failed (" + (mr ? mr.status : "network") + "): " + partsUrl);
69
+ const manifest = JSON.parse(new TextDecoder().decode(new Uint8Array(await mr.arrayBuffer())));
70
+ const range = makeRangeFetcher({ fetchImpl: f });
71
+ // SERVERLESS delivery, in priority order — all CORS + Range, no app server:
72
+ // 1. CDN over a GitHub repo (manifest.cdnBase, jsDelivr): {cdnBase}/{name}. Global immutable CDN, fast any-device.
73
+ // manifest.rawBase (raw.githubusercontent) is the same-repo fallback. Override via window.HOLO_PACK_CDN.
74
+ // 2. IPFS gateway by CID (manifest.gateway + per-part cid): {gateway}/ipfs/{cid}. Override via HOLO_PACK_GATEWAY.
75
+ // 3. a co-located mirror by part name ({base}/{name}).
76
+ // Every block is L5-verified regardless of source (a source is a latency choice, never trust).
77
+ const G = (typeof globalThis !== "undefined") ? globalThis : {};
78
+ const cdn = (G.HOLO_PACK_CDN || manifest.cdnBase || "").replace(/\/+$/, "");
79
+ const raw = (manifest.rawBase || "").replace(/\/+$/, "");
80
+ const gw = (gateway || G.HOLO_PACK_GATEWAY || manifest.gateway || "").replace(/\/+$/, "");
81
+ const baseUrl = base || partsUrl.replace(/[^/]*$/, "");
82
+ const primary = (p) => cdn ? `${cdn}/${p.name}` : (gw && p.cid) ? `${gw}/ipfs/${p.cid}` : (baseUrl + p.name);
83
+ const peerWhole = new Map(); // i → whole verified part from a peer (null = peer miss)
84
+ const fabricOn = () => !(typeof globalThis !== "undefined" && globalThis.HoloFabric && globalThis.HoloFabric.enabled === false); // ONE kill switch
85
+ const fetchPart = async (i, off, len) => {
86
+ const p = manifest.parts[i];
87
+ if (peerResolve && fabricOn()) { // COMMONS first: a peer that already has this part (by κ)
88
+ let whole = peerWhole.get(i);
89
+ if (whole === undefined) { try { whole = (await peerResolve(p)) || null; } catch { whole = null; } peerWhole.set(i, whole); }
90
+ if (whole && whole.length >= p.len) return whole.subarray(off, off + len); // 0 bytes from origin
91
+ }
92
+ try { return await range(primary(p), off, len); }
93
+ catch (e) { if (cdn && raw) return range(`${raw}/${p.name}`, off, len); throw e; } // jsDelivr miss → raw.githubusercontent
94
+ };
95
+ return { manifest, rangeReader: makeShardedRangeReader({ parts: manifest.parts, fetchPart }) };
96
+ }
97
+
98
+ // THE one call the OS makes: open the unified pack, preferring the monolithic file when reachable (dev / FORGE local
99
+ // mount — a single <2 GiB-cap-free file), else the sharded release. Returns the OPENED pack (openModelPack shape) +
100
+ // how it was reached. monolithicUrl is probed with one tiny Range read of the "HOLO" magic; any failure → shards.
101
+ export async function openQPack({ monolithicUrl, partsUrl, base, fetchImpl, openModelPack, gateway, peerResolve } = {}) {
102
+ if (!openModelPack) ({ openModelPack } = await import("./holo-model-pack.mjs"));
103
+ const f = fetchImpl || (typeof fetch !== "undefined" ? fetch : null);
104
+ if (monolithicUrl && f) {
105
+ try {
106
+ const range = makeRangeFetcher({ fetchImpl: f });
107
+ // time-box the probe: an absent 4.6GB monolithic can trigger host-side κ-healing that hangs instead of 404ing.
108
+ // A real same-origin monolithic (dev) answers a 4-byte Range in well under a second; anything slower → shards.
109
+ const magic = await Promise.race([range(monolithicUrl, 0, 4), new Promise((_, r) => setTimeout(() => r(new Error("monolithic probe timeout")), 2500))]);
110
+ if (magic && magic.length >= 4 && magic[0] === 0x48 && magic[1] === 0x4f) { // "HO" — the monolithic file is served whole (dev / same-origin)
111
+ const pack = await openModelPack({ rangeReader: (off, len) => range(monolithicUrl, off, len) });
112
+ return { via: "monolithic", pack };
113
+ }
114
+ } catch { /* fall through to shards */ }
115
+ }
116
+ const { manifest, rangeReader } = await openShardedPack({ partsUrl, base, fetchImpl: f, gateway, peerResolve });
117
+ const pack = await openModelPack({ rangeReader });
118
+ return { via: "sharded", manifest, pack };
119
+ }
120
+
121
+ export default { spanReader, makeShardedRangeReader, makeRangeFetcher, openShardedPack, openQPack };
apps/q/forge/gpu/holo-q-pack-provider.mjs ADDED
@@ -0,0 +1,149 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // holo-q-pack-provider.mjs — the consumer seam: open the unified q-models pack ONCE per page and hand each faculty its
2
+ // model view from it, fail-soft to the faculty's own standalone .holo when the pack isn't reachable. This is what
3
+ // voice.js / the ear + brain loaders call instead of fetching a per-model .holo: one open, one warm OPFS store, one
4
+ // address; pack.model(id) is openHoloStream-shaped so the loaders take it unchanged.
5
+ //
6
+ // getQPack({ packSpec, fetchImpl }) → the opened pack (memoized; concurrent callers share one open)
7
+ // packModelFor(spec, { packSpec, fetchImpl }) → spec's model view FROM the pack, or null (caller uses standalone)
8
+ //
9
+ // spec is a faculty spec from holo-q-faculty-models.specFor()/resolveFacultyModel — it carries spec.pack={url,release,
10
+ // model} when the model lives in the pack. packSpec is that module's exported packSpec (one file + shards manifest).
11
+ import { openQPack } from "./holo-pack-shards.mjs";
12
+
13
+ let _pack = null, _opening = null, _key = null;
14
+
15
+ const baseOf = (url) => (url ? url.replace(/[^/]*$/, "") : undefined);
16
+
17
+ // open the pack once. Prefers the monolithic file (dev/FORGE-local), falls back to release shards. Memoized by the
18
+ // pack's address so every faculty on the page shares ONE open + OPFS warm. Concurrent callers await the same promise.
19
+ export async function getQPack({ packSpec, fetchImpl } = {}) {
20
+ if (!packSpec) throw new Error("getQPack needs packSpec");
21
+ const key = (packSpec.url || "") + "|" + (packSpec.partsManifest || "");
22
+ if (_pack && _key === key) return _pack;
23
+ if (_opening && _key === key) return _opening;
24
+ _key = key;
25
+ _opening = openQPack({ monolithicUrl: packSpec.url, partsUrl: packSpec.partsManifest, base: baseOf(packSpec.release), fetchImpl })
26
+ .then((r) => { _pack = r.pack; _pack.__via = r.via; _opening = null; return _pack; })
27
+ .catch((e) => { if (_key === key) { _opening = null; _key = null; } throw e; });
28
+ return _opening;
29
+ }
30
+
31
+ export function resetQPack() { _pack = null; _opening = null; _key = null; }
32
+
33
+ // hand a faculty its model view FROM the pack, or null. null ⇒ the model isn't in the pack OR the pack is unreachable
34
+ // ⇒ the caller falls back to spec.url/spec.release (the standalone .holo) — never a hard failure.
35
+ export async function packModelFor(spec, { packSpec, fetchImpl } = {}) {
36
+ try {
37
+ if (!spec || !spec.pack) return null;
38
+ const pack = await getQPack({ packSpec, fetchImpl });
39
+ return pack.model(spec.pack.model);
40
+ } catch { return null; }
41
+ }
42
+
43
+ // ── ear adapter ──────────────────────────────────────────────────────────────────────────────────
44
+ // createWhisperEar (parakeet) loads its encoder + joint via deps.openStream(url) and its small loose files (rescale
45
+ // json/bin, vocab, nemo) via deps.fetchBytes(url). This maps those URLs — by basename — onto the unified pack so the
46
+ // REAL ear streams entirely from the one file, with the standalone url/release as fallback. ZERO ear changes:
47
+ // createWhisperEar(cfg, makePackEarDeps({ packSpec })) ← that's the whole flip.
48
+ const EAR_BYNAME = {
49
+ "parakeet-tdt-0.6b-v2-stream.holo": { kind: "stream", model: "parakeet-encoder" },
50
+ "parakeet-tdt-0.6b-v2-joint.holo": { kind: "stream", model: "parakeet-joint" },
51
+ "parakeet-encoder-rescale.json": { kind: "file", model: "parakeet-encoder", file: "parakeet-encoder-rescale.json" },
52
+ "parakeet-encoder-rescale.bin": { kind: "file", model: "parakeet-encoder", file: "parakeet-encoder-rescale.bin" },
53
+ "parakeet-vocab.txt": { kind: "file", model: "parakeet-encoder", file: "parakeet-vocab.txt" },
54
+ "parakeet-nemo128.onnx": { kind: "file", model: "parakeet-encoder", file: "parakeet-nemo128.onnx" },
55
+ };
56
+ const basename = (u) => String(u).split(/[/?#]/).filter(Boolean).pop();
57
+
58
+ // ── universal faculty→pack map ───────────────────────────────────────────────────────────────────
59
+ // every model's standalone .holo basename → how it's served from the pack: "stream" (openHoloStream-shaped loaders:
60
+ // moonshine/parakeet ears), "gguf" (the GGUF brain via ggufStreamFromPackModel), "files" (file-bundle loaders served
61
+ // through openHoloFiles: turn-detector, kokoro). So ONE provider backs every loader in the voice loop.
62
+ const PACK_BYNAME = {
63
+ "moonshine-tiny-int8.holo": { kind: "stream", model: "moonshine-tiny-int8" },
64
+ "moonshine-tiny-f16.holo": { kind: "stream", model: "moonshine-tiny-f16" },
65
+ "parakeet-tdt-0.6b-v2-stream.holo": { kind: "stream", model: "parakeet-encoder" },
66
+ "parakeet-tdt-0.6b-v2-joint.holo": { kind: "stream", model: "parakeet-joint" },
67
+ "qwen2.5-0.5b-instruct.holo": { kind: "gguf", model: "qwen2.5-0.5b" },
68
+ "qwen2.5-1.5b-instruct.holo": { kind: "gguf", model: "qwen2.5-1.5b" },
69
+ "qwen2.5-coder-3b-instruct.holo": { kind: "gguf", model: "qwen-coder-3b" },
70
+ "turn-detector.holo": { kind: "files", model: "turn-detector" },
71
+ "kokoro-82m.holo": { kind: "files", model: "kokoro-82m" },
72
+ };
73
+
74
+ // reconstruct streamHolo's view (getF32/getQuant/getMelFilters/meta.config) from a pack model view — the moonshine ear
75
+ // reads these, not the bare getBody. Reuses holo-whisper-stream's buildHoloViews over the view's L5 getBody, so decode
76
+ // is byte-identical to the standalone .holo. The view carries the full meta (config + order with dims/type) from the pack.
77
+ export async function streamHoloFromPackModel(view) {
78
+ await view.ensureHeader?.(); // split-manifest pack: fetch the lazy header body before decode
79
+ const { buildHoloViews } = await import("./holo-whisper-stream.mjs");
80
+ const v = buildHoloViews(view.meta, view.headerBytes, (h) => view.getBody(h));
81
+ return Object.assign({}, v, { dir: view.dir, stats: { ranges: 0, bytesFetched: 0, verifies: 0, opfsHits: 0, fromPack: true } });
82
+ }
83
+
84
+ // an openStream(url,opts) for the moonshine ear (whisper-shaped): pack view (full getF32/getQuant) for a known
85
+ // basename, else fallback to streamHolo. (Parakeet uses makePackEarDeps — the raw openHoloStream view — not this.)
86
+ export function makePackOpenStream({ packSpec, fetchImpl, openStream, onSource } = {}) {
87
+ return async (url, o) => {
88
+ const e = PACK_BYNAME[basename(url)];
89
+ if (e && e.kind === "stream") { try { const pack = await getQPack({ packSpec, fetchImpl }); const v = await streamHoloFromPackModel(pack.model(e.model)); try { onSource && onSource("stream", basename(url), "pack"); } catch {} return v; } catch {} }
90
+ try { onSource && onSource("stream", basename(url), "standalone"); } catch {}
91
+ if (openStream) return openStream(url, o);
92
+ const { streamHolo } = await import("./holo-whisper-stream.mjs"); return streamHolo(url, o);
93
+ };
94
+ }
95
+
96
+ // an openFiles(url,opts) for file-bundle loaders (serveModelFromHolo's `openFiles`): a files-view backed by the pack
97
+ // model's fileBody, else fallback to openHoloFiles. modelId pins which pack model answers (turn-detector / kokoro).
98
+ export function makePackOpenFiles(modelId, { packSpec, fetchImpl, openFiles, onSource } = {}) {
99
+ return async (url, o) => {
100
+ try { const pack = await getQPack({ packSpec, fetchImpl }); const m = pack.model(modelId);
101
+ // a file-bundle's named entries land in `order` (the forge stores them there); `files` holds only extra loose
102
+ // files. Expose whichever carries the names so serveModelFromHolo can enumerate; getFile resolves across both.
103
+ const names = (m.files && m.files.length) ? m.files : m.order;
104
+ try { onSource && onSource("files", basename(url), "pack"); } catch {}
105
+ return { meta: { files: names }, files: names, getFile: (name) => m.fileBody(name), bodyByKappa: (k) => m.getBody(k), objectURL: async (name, mime = "application/octet-stream") => URL.createObjectURL(new Blob([await m.fileBody(name)], { type: mime })) };
106
+ } catch {}
107
+ try { onSource && onSource("files", basename(url), "standalone"); } catch {}
108
+ if (openFiles) return openFiles(url, o);
109
+ const { openHoloFiles } = await import("./holo-files.mjs"); return openHoloFiles(url, o);
110
+ };
111
+ }
112
+
113
+ // resolve a model .holo URL → its pack entry {kind,model} (or null if not in the pack) — lets a loader decide whether
114
+ // to take a pack adapter for the model it was handed by URL (the brain/turn/tts call sites).
115
+ export function packEntryForUrl(url) { return PACK_BYNAME[basename(url)] || null; }
116
+
117
+ // a ()→{plan,store,headerBytes,…} for the GGUF brain (createHoloBrain's openGgufStream): the unified-pack qwen, built
118
+ // via ggufStreamFromPackModel. Falls back to null so the brain uses its own makeBrainRange+openGgufHoloStream path.
119
+ export function makePackGgufStream(modelId, { packSpec, fetchImpl, onSource } = {}) {
120
+ return async ({ persist = null } = {}) => {
121
+ try { const pack = await getQPack({ packSpec, fetchImpl }); const { ggufStreamFromPackModel } = await import("../gguf-forge-kstream.mjs");
122
+ const view = pack.model(modelId); await view.ensureHeader?.(); // split-manifest: fetch the lazy GGUF header before planFrom
123
+ try { onSource && onSource("gguf", modelId, "pack"); } catch {}
124
+ return ggufStreamFromPackModel(view, { persist });
125
+ } catch { try { onSource && onSource("gguf", modelId, "standalone"); } catch {} return null; }
126
+ };
127
+ }
128
+
129
+ export function makePackEarDeps({ packSpec, fetchImpl, openStream, fetchBytes, onSource } = {}) {
130
+ const note = (kind, name, src) => { try { onSource && onSource(kind, name, src); } catch {} };
131
+ return {
132
+ openStream: async (url, o) => {
133
+ const e = EAR_BYNAME[basename(url)];
134
+ if (e && e.kind === "stream") { try { const pack = await getQPack({ packSpec, fetchImpl }); const v = pack.model(e.model); await v.ensureHeader?.(); note("stream", basename(url), "pack"); return v; } catch {} }
135
+ note("stream", basename(url), "standalone");
136
+ if (openStream) return openStream(url, o);
137
+ const { streamHolo } = await import("./holo-whisper-stream.mjs"); return streamHolo(url, o);
138
+ },
139
+ fetchBytes: async (url) => {
140
+ const e = EAR_BYNAME[basename(url)];
141
+ if (e && e.kind === "file") { try { const pack = await getQPack({ packSpec, fetchImpl }); const b = await pack.model(e.model).fileBody(e.file); note("file", basename(url), "pack"); return b; } catch {} }
142
+ note("file", basename(url), "standalone");
143
+ if (fetchBytes) return fetchBytes(url);
144
+ const r = await fetch(url); if (!r.ok) throw new Error("fetch " + url + " " + r.status); return new Uint8Array(await r.arrayBuffer());
145
+ },
146
+ };
147
+ }
148
+
149
+ export default { getQPack, packModelFor, resetQPack, makePackEarDeps };
apps/q/forge/gpu/holo-whisper-stream.mjs ADDED
@@ -0,0 +1,108 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // holo-whisper-stream.mjs — load Whisper weights 100% from the .holo, native to the κ substrate:
2
+ // • HTTP-Range fetch of each tensor body by its κ (content address) — only what's needed, in any order
3
+ // • per-block WebCrypto SHA-256 L5 verify (re-derive every byte before accepting it)
4
+ // • OPFS cache keyed by κ → second load is instant + offline (serverless), still L5-verified
5
+ // • dequant verbatim ggml bytes (F16/F32) → f32 for the WebGPU kernels
6
+ // No flat blob, no trust in the transport: identity is the hash, exactly like the rest of Hologram.
7
+ const MAGIC = [0x48, 0x4f, 0x4c, 0x4f];
8
+ const hexOf = (b) => { let s = ""; for (const x of b) s += x.toString(16).padStart(2, "0"); return s; };
9
+
10
+ // f16→f32 via a 64K lookup table (IEEE half, incl. subnormals/inf/nan) — built once.
11
+ const F16 = new Float32Array(65536);
12
+ for (let h = 0; h < 65536; h++) { const s = (h >> 15) & 1, e = (h >> 10) & 0x1f, m = h & 0x3ff; let v; if (e === 0) v = Math.pow(2, -14) * (m / 1024); else if (e === 31) v = m ? NaN : Infinity; else v = Math.pow(2, e - 15) * (1 + m / 1024); F16[h] = s ? -v : v; }
13
+
14
+ const sha256hex = async (buf) => hexOf(new Uint8Array(await crypto.subtle.digest("SHA-256", buf)));
15
+
16
+ async function opfsGet(key) { try { const r = await navigator.storage.getDirectory(); const d = await r.getDirectoryHandle("holo-kappa", { create: true }); const fh = await d.getFileHandle(key); return new Uint8Array(await (await fh.getFile()).arrayBuffer()); } catch { return null; } }
17
+ async function opfsPut(key, bytes) { try { const r = await navigator.storage.getDirectory(); const d = await r.getDirectoryHandle("holo-kappa", { create: true }); const fh = await d.getFileHandle(key, { create: true }); const w = await fh.createWritable(); await w.write(bytes); await w.close(); return true; } catch { return false; } }
18
+
19
+ // align a (possibly offset) body view to a fresh ArrayBuffer for typed-array views
20
+ const aligned = (u) => (u.byteOffset % 4 === 0) ? u : new Uint8Array(u.slice().buffer);
21
+
22
+ export async function streamHolo(url, { useOpfs = true, kappa = "", release = "" } = {}) {
23
+ const stats = { ranges: 0, bytesFetched: 0, verifies: 0, opfsHits: 0, opfsWrites: 0, support206: false, kappaRoute: false, releaseRoute: false };
24
+ let wholeBuf = null; // set when the server returns the 200 full body → serve all reads from memory
25
+ let activeUrl = url, switched = false, triedRelease = false;
26
+ const fetchRange = (u, off, len) => fetch(u, { headers: { Range: `bytes=${off}-${off + len - 1}` } });
27
+ const rangeReader = async (off, len) => {
28
+ if (wholeBuf) return wholeBuf.subarray(off, off + len); // no-Range server: one full fetch, then in-memory slices
29
+ stats.ranges++;
30
+ let r = null; try { r = await fetchRange(activeUrl, off, len); } catch (e) { r = null; }
31
+ // DEPLOY TIER 2: weights too large for Pages (100MB/file) live as a GitHub Release asset (2GB/file).
32
+ if ((!r || !r.ok) && release && activeUrl !== release && !triedRelease) {
33
+ triedRelease = true; activeUrl = release; stats.releaseRoute = true;
34
+ try { r = await fetchRange(activeUrl, off, len); } catch (e) { r = null; }
35
+ }
36
+ // STATIC/IPFS DEPLOY: the gitignored .holo isn't at its path → heal by κ (/.holo/sha256/<κ>), the
37
+ // Service Worker pulls it from IPFS/mesh. Same fallback as Q's .holo brain (holo-brain-engine).
38
+ if ((!r || !r.ok) && kappa && !switched) {
39
+ switched = true; activeUrl = "/.holo/sha256/" + kappa; stats.kappaRoute = true;
40
+ try { r = await fetchRange(activeUrl, off, len); } catch (e) { r = null; }
41
+ }
42
+ if (!r || !r.ok) throw new Error("holo fetch failed (" + (r ? r.status : "network") + "): " + activeUrl);
43
+ stats.support206 = stats.support206 || r.status === 206;
44
+ const u = new Uint8Array(await r.arrayBuffer());
45
+ stats.bytesFetched += u.length;
46
+ if (r.status === 206) return u; // true partial response → use as-is
47
+ if (u.length > len) { wholeBuf = u; return wholeBuf.subarray(off, off + len); } // got whole file → cache, slice (every block still L5-verified)
48
+ return u;
49
+ };
50
+ // ── parse head / sections / metadata / weights directory ──
51
+ const head = await rangeReader(0, 64), hdv = new DataView(head.buffer, head.byteOffset, head.byteLength);
52
+ for (let i = 0; i < 4; i++) if (head[i] !== MAGIC[i]) throw new Error("not a .holo");
53
+ const sc = hdv.getUint16(8, true);
54
+ const tbl = await rangeReader(10, sc * 17), tdv = new DataView(tbl.buffer, tbl.byteOffset, tbl.byteLength), sections = {};
55
+ for (let i = 0, p = 0; i < sc; i++, p += 17) sections[tbl[p]] = { off: Number(tdv.getBigUint64(p + 1, true)), len: Number(tdv.getBigUint64(p + 9, true)) };
56
+ const m = sections[8], metaB = await rangeReader(m.off, m.len);
57
+ const meta = JSON.parse(new TextDecoder().decode(metaB));
58
+ // Extension (kind 14) = [keyLen u16][key][ggml whisper head bytes] → hparams + mel filterbank + vocab
59
+ const ex = sections[14], exB = ex ? await rangeReader(ex.off, ex.len) : null;
60
+ const headerBytes = exB ? exB.subarray(2 + new DataView(exB.buffer, exB.byteOffset, exB.byteLength).getUint16(0, true)) : null;
61
+ const w = sections[3], cntB = await rangeReader(w.off, 4), count = new DataView(cntB.buffer, cntB.byteOffset, cntB.byteLength).getUint32(0, true);
62
+ const dirB = await rangeReader(w.off + 4, count * 48), ddv = new DataView(dirB.buffer, dirB.byteOffset, dirB.byteLength), dir = new Map();
63
+ for (let i = 0, p = 0; i < count; i++, p += 48) dir.set(hexOf(dirB.subarray(p, p + 32)), { off: Number(ddv.getBigUint64(p + 32, true)), len: Number(ddv.getBigUint64(p + 40, true)) });
64
+ // fetch+verify one body by κ (OPFS-cached) — REFUSE on hash mismatch (L5)
65
+ async function bodyByKappa(hex) {
66
+ if (useOpfs) { const c = await opfsGet(hex); if (c) { stats.verifies++; if (await sha256hex(c) === hex) { stats.opfsHits++; return c; } } }
67
+ const d = dir.get(hex); if (!d) throw new Error("κ not in holo: " + hex);
68
+ const b = await rangeReader(d.off, d.len);
69
+ stats.verifies++; if (await sha256hex(b) !== hex) throw new Error("L5 REFUSE " + hex);
70
+ if (useOpfs && await opfsPut(hex, b)) stats.opfsWrites++;
71
+ return b;
72
+ }
73
+ const views = buildHoloViews(meta, headerBytes, bodyByKappa);
74
+ return Object.assign({}, views, { dir, sections, stats });
75
+ }
76
+
77
+ // the dequant accessors (getF32/getQuant/getMelFilters) over a meta + a body fetcher — extracted so the unified pack
78
+ // reuses the EXACT decode (holo-q-pack-provider's streamHoloFromPackModel passes the pack view's L5 getBody here).
79
+ // getBody(hex) → Promise<Uint8Array> (already L5-verified by the caller). meta.order carries name/dims/type/kappa.
80
+ export function buildHoloViews(meta, headerBytes, getBody) {
81
+ const byName = new Map(meta.order.map((o) => [o.name, o]));
82
+ const norm = (k) => String(k).split(":").pop();
83
+ async function getF32(name) {
84
+ const o = byName.get(name); if (!o) throw new Error("no tensor " + name);
85
+ const n = o.dims.reduce((a, b) => a * b, 1), body = aligned(await getBody(norm(o.kappa)));
86
+ if (o.type === 0) return new Float32Array(body.buffer, body.byteOffset, n); // F32 verbatim
87
+ if (o.type === 1) { const u = new Uint16Array(body.buffer, body.byteOffset, n), f = new Float32Array(n); for (let i = 0; i < n; i++) f[i] = F16[u[i]]; return f; } // F16→F32
88
+ if (o.type === 9) { // per-row int8: [f32 scale × rows][int8 × n] → F32
89
+ const rows = o.dims[0], cols = n / rows, scales = new Float32Array(body.buffer, body.byteOffset, rows), q = new Int8Array(body.buffer, body.byteOffset + rows * 4, n), f = new Float32Array(n);
90
+ for (let r = 0; r < rows; r++) { const sc = scales[r], b = r * cols; for (let c = 0; c < cols; c++) f[b + c] = q[b + c] * sc; }
91
+ return f;
92
+ }
93
+ throw new Error("unhandled ggml type " + o.type);
94
+ }
95
+ async function getQuant(name) {
96
+ const o = byName.get(name); if (!o) throw new Error("no tensor " + name);
97
+ const n = o.dims.reduce((a, b) => a * b, 1);
98
+ if (o.type === 9) { const body = aligned(await getBody(norm(o.kappa))), rows = o.dims[0];
99
+ return { q8: true, rows, cols: n / rows, scales: new Float32Array(body.buffer, body.byteOffset, rows), int8: new Uint8Array(body.buffer, body.byteOffset + rows * 4, n) }; }
100
+ return { q8: false, f32: await getF32(name) };
101
+ }
102
+ async function getMelFilters() {
103
+ const mk = meta.mel && meta.mel.kappa; if (!mk) throw new Error("no mel filterbank in .holo");
104
+ const body = aligned(await getBody(norm(mk)));
105
+ return new Float32Array(body.buffer, body.byteOffset, meta.mel.n_mel * meta.mel.n_fft);
106
+ }
107
+ return { meta, getF32, getQuant, getMelFilters, bodyByKappa: (h) => getBody(norm(h)), headerBytes, names: meta.order.map((o) => o.name) };
108
+ }
apps/q/forge/holo-archive.mjs ADDED
@@ -0,0 +1,207 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // GGUF → .holo writer/reader. A .holo is the precompiled, streamable, content-
2
+ // addressed package the cold-load runtime consumes: a section table + a Weights
3
+ // section of sha256-keyed, deduplicated weight bodies laid out in FIRST-USE order
4
+ // (so streaming arrives in compute order), with the GGUF header (metadata +
5
+ // tokenizer) baked in as an Extension and a footer fingerprint = the model's
6
+ // did:holo. Each body's ABSOLUTE file offset is in the directory, so a single
7
+ // weight is range-fetchable (HTTP Range) and verified by re-derivation (L5).
8
+ //
9
+ // Layout aligns to hologram/crates/hologram-archive (MAGIC "HOLO" v2, SectionRef
10
+ // {kind,offset,len}, Weights=3/Metadata=8/Extension=14). Hash axis is sha256 (the
11
+ // forge axis = SRI = L5), not the Rust crate's blake3 — byte-exact Rust-decoder
12
+ // interop is out of scope; this is the JS runtime's streaming package.
13
+
14
+ import { forgeGguf } from "./gguf-forge.mjs";
15
+ import { parseGgufHeader } from "../qvac-ingest.mjs";
16
+ // sha256hex + didHolo INLINED (FIPS 180-4, byte-identical to holo-uor) — was imported via a dev-tree relative path
17
+ // that doesn't resolve in the sealed dist (holo://os/…), which broke `import()` of this module (and everything
18
+ // through it: holo-model-pack, gguf-forge-kstream/brain) on the native host. Self-contained = loads in node AND dist.
19
+ const _SHA_K = new Uint32Array([0x428a2f98,0x71374491,0xb5c0fbcf,0xe9b5dba5,0x3956c25b,0x59f111f1,0x923f82a4,0xab1c5ed5,0xd807aa98,0x12835b01,0x243185be,0x550c7dc3,0x72be5d74,0x80deb1fe,0x9bdc06a7,0xc19bf174,0xe49b69c1,0xefbe4786,0x0fc19dc6,0x240ca1cc,0x2de92c6f,0x4a7484aa,0x5cb0a9dc,0x76f988da,0x983e5152,0xa831c66d,0xb00327c8,0xbf597fc7,0xc6e00bf3,0xd5a79147,0x06ca6351,0x14292967,0x27b70a85,0x2e1b2138,0x4d2c6dfc,0x53380d13,0x650a7354,0x766a0abb,0x81c2c92e,0x92722c85,0xa2bfe8a1,0xa81a664b,0xc24b8b70,0xc76c51a3,0xd192e819,0xd6990624,0xf40e3585,0x106aa070,0x19a4c116,0x1e376c08,0x2748774c,0x34b0bcb5,0x391c0cb3,0x4ed8aa4a,0x5b9cca4f,0x682e6ff3,0x748f82ee,0x78a5636f,0x84c87814,0x8cc70208,0x90befffa,0xa4506ceb,0xbef9a3f7,0xc67178f2]);
20
+ const _rotr = (x, n) => (x >>> n) | (x << (32 - n));
21
+ function _sha256u8(msg) {
22
+ const h = new Uint32Array([0x6a09e667,0xbb67ae85,0x3c6ef372,0xa54ff53a,0x510e527f,0x9b05688c,0x1f83d9ab,0x5be0cd19]);
23
+ const len = msg.length, bitLen = len * 8, withOne = len + 1, k = (56 - (withOne % 64) + 64) % 64, total = withOne + k + 8;
24
+ const m = new Uint8Array(total); m.set(msg); m[len] = 0x80;
25
+ const hi = Math.floor(bitLen / 0x100000000), lo = bitLen >>> 0;
26
+ m[total-8]=(hi>>>24)&255; m[total-7]=(hi>>>16)&255; m[total-6]=(hi>>>8)&255; m[total-5]=hi&255;
27
+ m[total-4]=(lo>>>24)&255; m[total-3]=(lo>>>16)&255; m[total-2]=(lo>>>8)&255; m[total-1]=lo&255;
28
+ const w = new Uint32Array(64);
29
+ for (let off = 0; off < total; off += 64) {
30
+ for (let i = 0; i < 16; i++) w[i] = (m[off+i*4]<<24)|(m[off+i*4+1]<<16)|(m[off+i*4+2]<<8)|(m[off+i*4+3]);
31
+ for (let i = 16; i < 64; i++) { const s0=_rotr(w[i-15],7)^_rotr(w[i-15],18)^(w[i-15]>>>3); const s1=_rotr(w[i-2],17)^_rotr(w[i-2],19)^(w[i-2]>>>10); w[i]=(w[i-16]+s0+w[i-7]+s1)|0; }
32
+ let a=h[0],b=h[1],c=h[2],d=h[3],e=h[4],f=h[5],g=h[6],hh=h[7];
33
+ for (let i = 0; i < 64; i++) { const S1=_rotr(e,6)^_rotr(e,11)^_rotr(e,25); const ch=(e&f)^((~e)&g); const t1=(hh+S1+ch+_SHA_K[i]+w[i])|0; const S0=_rotr(a,2)^_rotr(a,13)^_rotr(a,22); const maj=(a&b)^(a&c)^(b&c); const t2=(S0+maj)|0; hh=g;g=f;f=e;e=(d+t1)|0;d=c;c=b;b=a;a=(t1+t2)|0; }
34
+ h[0]=(h[0]+a)|0;h[1]=(h[1]+b)|0;h[2]=(h[2]+c)|0;h[3]=(h[3]+d)|0;h[4]=(h[4]+e)|0;h[5]=(h[5]+f)|0;h[6]=(h[6]+g)|0;h[7]=(h[7]+hh)|0;
35
+ }
36
+ const out = new Uint8Array(32);
37
+ for (let i = 0; i < 8; i++) { out[i*4]=(h[i]>>>24)&255; out[i*4+1]=(h[i]>>>16)&255; out[i*4+2]=(h[i]>>>8)&255; out[i*4+3]=h[i]&255; }
38
+ return out;
39
+ }
40
+ const _u8 = (x) => typeof x === "string" ? new TextEncoder().encode(x) : (x instanceof Uint8Array ? x : new Uint8Array(x));
41
+ const sha256hex = (x) => { const u = _sha256u8(_u8(x)); let s = ""; for (let i = 0; i < u.length; i++) s += u[i].toString(16).padStart(2, "0"); return s; };
42
+ const didHolo = (axis, hex) => `did:holo:${axis}:${hex}`;
43
+
44
+ const MAGIC = [0x48, 0x4f, 0x4c, 0x4f]; // "HOLO"
45
+ const VERSION = 2;
46
+ const K = { Weights: 3, Metadata: 8, Extension: 14 };
47
+ const HEX = (h) => { const b = new Uint8Array(32); for (let i = 0; i < 32; i++) b[i] = parseInt(h.substr(i * 2, 2), 16); return b; };
48
+ const hexOf = (b) => { let s = ""; for (const x of b) s += x.toString(16).padStart(2, "0"); return s; };
49
+
50
+ // ── writer ──
51
+ export function writeHolo(ggufBytes) {
52
+ const f = forgeGguf(ggufBytes);
53
+ const dataOffset = parseGgufHeader(ggufBytes).dataOffset;
54
+ const headerBytes = ggufBytes.subarray(0, dataOffset); // GGUF metadata + tokenizer + tensor infos
55
+
56
+ // first-use order = GGUF tensor directory order (token_embd → per-layer → output);
57
+ // dedup bodies by κ but keep first-occurrence order.
58
+ const order = [], seen = new Map(); // κ-hex → {offset(within bodies), len}
59
+ let bodyTotal = 0;
60
+ for (const t of f.tensors) {
61
+ const hex = t.kappa.split(":").pop();
62
+ if (!seen.has(hex)) { seen.set(hex, { off: bodyTotal, len: t.nbytes }); bodyTotal += t.nbytes; }
63
+ order.push({ name: t.name, kappa: hex });
64
+ }
65
+ const uniq = [...seen.entries()]; // [hex, {off,len}]
66
+
67
+ const meta = JSON.stringify({ format: "holo/2", arch: f.arch, sourceRoot: f.rootKappa, nTensors: f.tensors.length, nBodies: uniq.length, order });
68
+ const extKey = "gguf.header";
69
+ const enc = new TextEncoder();
70
+ const metaBytes = enc.encode(meta);
71
+ const extKeyBytes = enc.encode(extKey);
72
+ const extPayload = cat([u16(extKeyBytes.length), extKeyBytes, headerBytes]); // [keyLen][key][bytes]
73
+ const dirCount = uniq.length;
74
+ const dirBytes = 4 + dirCount * (32 + 8 + 8); // [count u32][κ(32) off(u64) len(u64)]×
75
+ const weightsLen = dirBytes + bodyTotal;
76
+
77
+ // layout: header + section-table + ext + meta + weights + footer(32)
78
+ const sectionCount = 3;
79
+ const headSize = 4 + 2 + 2 + 2 + sectionCount * (1 + 8 + 8);
80
+ const extOff = headSize, metaOff = extOff + extPayload.length, weightsOff = metaOff + metaBytes.length;
81
+ const bodiesStart = weightsOff + dirBytes;
82
+ const fileLen = bodiesStart + bodyTotal + 32;
83
+
84
+ const out = new Uint8Array(fileLen);
85
+ const dv = new DataView(out.buffer);
86
+ let p = 0;
87
+ out.set(MAGIC, p); p += 4;
88
+ dv.setUint16(p, VERSION, true); p += 2;
89
+ dv.setUint16(p, 0, true); p += 2; // flags
90
+ dv.setUint16(p, sectionCount, true); p += 2;
91
+ const sec = (kind, off, len) => { out[p] = kind; p += 1; dv.setBigUint64(p, BigInt(off), true); p += 8; dv.setBigUint64(p, BigInt(len), true); p += 8; };
92
+ sec(K.Extension, extOff, extPayload.length);
93
+ sec(K.Metadata, metaOff, metaBytes.length);
94
+ sec(K.Weights, weightsOff, weightsLen);
95
+ out.set(extPayload, extOff);
96
+ out.set(metaBytes, metaOff);
97
+ // weights directory (ABSOLUTE file offsets) + bodies
98
+ dv.setUint32(weightsOff, dirCount, true);
99
+ let dp = weightsOff + 4;
100
+ const store = (h) => f.blocks.get(h);
101
+ for (const [hex, info] of uniq) {
102
+ out.set(HEX(hex), dp); dp += 32;
103
+ dv.setBigUint64(dp, BigInt(bodiesStart + info.off), true); dp += 8;
104
+ dv.setBigUint64(dp, BigInt(info.len), true); dp += 8;
105
+ out.set(store(hex), bodiesStart + info.off);
106
+ }
107
+ // footer = sha256 over everything before the footer → the .holo's identity
108
+ const footHex = sha256hex(out.subarray(0, fileLen - 32));
109
+ out.set(HEX(footHex), fileLen - 32);
110
+ return { holo: out, rootHolo: didHolo("sha256", footHex), nBodies: uniq.length, nTensors: f.tensors.length, bytes: fileLen };
111
+ }
112
+
113
+ // ── generic archive writer ──
114
+ // Seal ANY content into the same MAGIC HOLO v2 structure as writeHolo (so readHolo / openHoloStream /
115
+ // makeKappaStore / the SW /.holo/sha256/<κ> route all read it unchanged) — used for non-GGUF κ-objects
116
+ // like a LoRA adapter. Caller supplies the deduped κ-bodies + a metadata object (with order:[{name,kappa}])
117
+ // + an optional extension payload. Footer = sha256(everything) = the archive's did:holo identity.
118
+ export function writeHoloArchive({ meta, bodies, extKey = "holo.archive", extBytes = new Uint8Array(0) }) {
119
+ const enc = new TextEncoder();
120
+ const metaBytes = enc.encode(JSON.stringify(meta));
121
+ const extKeyBytes = enc.encode(extKey);
122
+ const extPayload = cat([u16(extKeyBytes.length), extKeyBytes, extBytes]);
123
+ const dirCount = bodies.length, dirBytes = 4 + dirCount * 48;
124
+ let bodyTotal = 0; for (const b of bodies) bodyTotal += b.bytes.length;
125
+ const sectionCount = 3, headSize = 4 + 2 + 2 + 2 + sectionCount * 17;
126
+ const extOff = headSize, metaOff = extOff + extPayload.length, weightsOff = metaOff + metaBytes.length;
127
+ const bodiesStart = weightsOff + dirBytes, fileLen = bodiesStart + bodyTotal + 32;
128
+ const out = new Uint8Array(fileLen), dv = new DataView(out.buffer);
129
+ let p = 0; out.set(MAGIC, p); p += 4; dv.setUint16(p, VERSION, true); p += 2; dv.setUint16(p, 0, true); p += 2; dv.setUint16(p, sectionCount, true); p += 2;
130
+ const sec = (kind, off, len) => { out[p] = kind; p += 1; dv.setBigUint64(p, BigInt(off), true); p += 8; dv.setBigUint64(p, BigInt(len), true); p += 8; };
131
+ sec(K.Extension, extOff, extPayload.length); sec(K.Metadata, metaOff, metaBytes.length); sec(K.Weights, weightsOff, dirBytes + bodyTotal);
132
+ out.set(extPayload, extOff); out.set(metaBytes, metaOff);
133
+ dv.setUint32(weightsOff, dirCount, true); let dp = weightsOff + 4, bo = bodiesStart;
134
+ for (const b of bodies) { out.set(HEX(b.kappa), dp); dp += 32; dv.setBigUint64(dp, BigInt(bo), true); dp += 8; dv.setBigUint64(dp, BigInt(b.bytes.length), true); dp += 8; out.set(b.bytes, bo); bo += b.bytes.length; }
135
+ const footHex = sha256hex(out.subarray(0, fileLen - 32)); out.set(HEX(footHex), fileLen - 32);
136
+ return { holo: out, footer: didHolo("sha256", footHex), bytes: fileLen };
137
+ }
138
+
139
+ // ── reader ──
140
+ export function readHolo(bytes) {
141
+ const dv = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
142
+ for (let i = 0; i < 4; i++) if (bytes[i] !== MAGIC[i]) throw new Error("not a .holo");
143
+ if (dv.getUint16(4, true) !== VERSION) throw new Error("holo version");
144
+ const sectionCount = dv.getUint16(8, true);
145
+ let p = 10; const sections = {};
146
+ for (let i = 0; i < sectionCount; i++) { const kind = bytes[p]; const off = Number(dv.getBigUint64(p + 1, true)); const len = Number(dv.getBigUint64(p + 9, true)); sections[kind] = { off, len }; p += 17; }
147
+ // footer verify (L5 on the whole archive)
148
+ const footHex = hexOf(bytes.subarray(bytes.length - 32));
149
+ if (sha256hex(bytes.subarray(0, bytes.length - 32)) !== footHex) throw new Error("holo footer mismatch (tamper)");
150
+ // extension: gguf header
151
+ const e = sections[K.Extension]; const keyLen = dv.getUint16(e.off, true);
152
+ const headerBytes = bytes.subarray(e.off + 2 + keyLen, e.off + e.len);
153
+ // metadata
154
+ const m = sections[K.Metadata];
155
+ const meta = JSON.parse(new TextDecoder().decode(bytes.subarray(m.off, m.off + m.len)));
156
+ // weights directory → κ-hex → {offset(abs), len}
157
+ const w = sections[K.Weights]; const count = dv.getUint32(w.off, true); const dir = new Map();
158
+ let dp = w.off + 4;
159
+ for (let i = 0; i < count; i++) { const hex = hexOf(bytes.subarray(dp, dp + 32)); dp += 32; const off = Number(dv.getBigUint64(dp, true)); dp += 8; const len = Number(dv.getBigUint64(dp, true)); dp += 8; dir.set(hex, { off, len }); }
160
+ const getBody = (kappaOrHex) => { const h = String(kappaOrHex).split(":").pop(); const d = dir.get(h); if (!d) throw new Error("κ not in holo: " + h); return bytes.subarray(d.off, d.off + d.len); };
161
+ // a κ-store with L5 verify on every body fetch
162
+ const store = { get: (h) => { const d = dir.get(h); if (!d) return undefined; const b = bytes.subarray(d.off, d.off + d.len); if (sha256hex(b) !== h) throw new Error("holo L5 REFUSE " + h); return b; }, has: (h) => dir.has(h) };
163
+ return { sections, meta, headerBytes, dir, getBody, store, footer: didHolo("sha256", footHex), rangeOf: (kappaOrHex) => dir.get(String(kappaOrHex).split(":").pop()) };
164
+ }
165
+
166
+ // ── streaming/partial reader: open a .holo over a Range reader (HTTP Range, or a
167
+ // file slice). Fetches only the header + directory up front (~the baked gguf
168
+ // metadata, a few MB); weight bodies are fetched on demand by absolute offset
169
+ // and verified per block (L5). This is the cold-load path. ──
170
+ export async function openHoloStream(rangeReader) {
171
+ const head = await rangeReader(0, 64);
172
+ const hdv = new DataView(head.buffer, head.byteOffset, head.byteLength);
173
+ for (let i = 0; i < 4; i++) if (head[i] !== MAGIC[i]) throw new Error("not a .holo");
174
+ if (hdv.getUint16(4, true) !== VERSION) throw new Error("holo version");
175
+ const sectionCount = hdv.getUint16(8, true);
176
+ const tbl = await rangeReader(10, sectionCount * 17);
177
+ const tdv = new DataView(tbl.buffer, tbl.byteOffset, tbl.byteLength);
178
+ const sections = {};
179
+ for (let i = 0, p = 0; i < sectionCount; i++, p += 17) sections[tbl[p]] = { off: Number(tdv.getBigUint64(p + 1, true)), len: Number(tdv.getBigUint64(p + 9, true)) };
180
+ // baked gguf header (metadata + tokenizer + tensor infos)
181
+ const e = sections[K.Extension], extBytes = await rangeReader(e.off, e.len);
182
+ const edv = new DataView(extBytes.buffer, extBytes.byteOffset, extBytes.byteLength);
183
+ const keyLen = edv.getUint16(0, true);
184
+ const headerBytes = extBytes.subarray(2 + keyLen);
185
+ // metadata (first-use order, name→κ)
186
+ const m = sections[K.Metadata], metaBytes = await rangeReader(m.off, m.len);
187
+ const meta = JSON.parse(new TextDecoder().decode(metaBytes));
188
+ // weights directory (κ → absolute offset/len) — only the directory, not the bodies
189
+ const w = sections[K.Weights];
190
+ const cntB = await rangeReader(w.off, 4); const count = new DataView(cntB.buffer, cntB.byteOffset, cntB.byteLength).getUint32(0, true);
191
+ const dirB = await rangeReader(w.off + 4, count * 48), ddv = new DataView(dirB.buffer, dirB.byteOffset, dirB.byteLength);
192
+ const dir = new Map();
193
+ for (let i = 0, p = 0; i < count; i++, p += 48) dir.set(hexOf(dirB.subarray(p, p + 32)), { off: Number(ddv.getBigUint64(p + 32, true)), len: Number(ddv.getBigUint64(p + 40, true)) });
194
+ // hardware-accelerated SHA-256 (WebCrypto, ~GB/s) so per-block L5 verify isn't the
195
+ // bottleneck at high bandwidth; falls back to pure-JS sha256hex if unavailable.
196
+ const cs = globalThis.crypto?.subtle;
197
+ const vhex = cs ? async (b) => { const d = new Uint8Array(await cs.digest("SHA-256", b)); let s = ""; for (const x of d) s += x.toString(16).padStart(2, "0"); return s; } : async (b) => sha256hex(b);
198
+ // fetch + L5-verify one weight body by κ
199
+ const getBody = async (kappaOrHex) => { const h = String(kappaOrHex).split(":").pop(); const d = dir.get(h); if (!d) throw new Error("κ not in holo: " + h); const b = await rangeReader(d.off, d.len); if (await vhex(b) !== h) throw new Error("holo L5 REFUSE " + h); return b; };
200
+ // fetch a sub-range WITHIN a body (e.g. one token_embd row) — defers the rest
201
+ const getBodySlice = async (kappaOrHex, byteOff, byteLen) => { const d = dir.get(String(kappaOrHex).split(":").pop()); return rangeReader(d.off + byteOff, byteLen); };
202
+ return { sections, meta, headerBytes, dir, getBody, getBodySlice, order: meta.order, bodyLen: (k) => dir.get(String(k).split(":").pop())?.len };
203
+ }
204
+
205
+ // ── helpers ──
206
+ const u16 = (n) => { const b = new Uint8Array(2); new DataView(b.buffer).setUint16(0, n, true); return b; };
207
+ function cat(arrs) { let n = 0; for (const a of arrs) n += a.length; const o = new Uint8Array(n); let p = 0; for (const a of arrs) { o.set(a, p); p += a.length; } return o; }
apps/q/holo-delta.mjs ADDED
@@ -0,0 +1,156 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // holo-delta.mjs — A2 of the personal-model-zoo plan: family index-delta. A finetune that shares a base's
2
+ // FRAME (see holo-model-frame.mjs) is stored as `base-κ + per-tensor delta`, reconstructed at LOAD (no new
3
+ // kernel — the engine still reads normal quantized weights). Two wins compose:
4
+ // • FROZEN tensors (identical κ to the base) cost 0 extra bytes — content-addressing dedups them for free.
5
+ // • CHANGED tensors are stored as a BitDelta (Liu et al. 2024): sign(Δ) at 1 bit/param + one scale α.
6
+ //
7
+ // HONEST storage math (this is where the "5–9×" claim earns or loses): the zoo ratio is driven by the
8
+ // FROZEN-TENSOR FRACTION, not within-tensor sparsity. A LoRA/partial finetune (most tensors frozen) →
9
+ // 10–30×; a FULL finetune (every tensor moves) → only ~3–4× (BitDelta is ~1 bit/param vs a 3–4 bit base).
10
+ // BitDelta is intrinsically lossy (sign+scale captures ~2/π≈64% of a Gaussian delta's energy); its
11
+ // published result is that OUTPUT quality is nonetheless preserved — that must be confirmed by perplexity
12
+ // on a REAL base+finetune pair (the A2 pass-bar gate), which this codec self-test does not run.
13
+ //
14
+ // Pure JS, isomorphic, zero deps. Node self-test sweeps frozen-fraction + reports fidelity and zoo ratio.
15
+
16
+ import { shareable } from "./holo-model-frame.mjs";
17
+
18
+ // ── BitDelta codec: Δ = ftW − baseW ; store sign(Δ) (1 bit) + α = mean|Δ| (the L2-optimal ±1 scale). ──
19
+ export function encodeBitDelta(baseW, ftW) {
20
+ const n = baseW.length, signBits = new Uint8Array((n + 7) >> 3);
21
+ let absSum = 0;
22
+ for (let i = 0; i < n; i++) {
23
+ const d = ftW[i] - baseW[i];
24
+ if (d >= 0) signBits[i >> 3] |= 1 << (i & 7); // bit set ⇒ +1
25
+ absSum += Math.abs(d);
26
+ }
27
+ return { kind: "bitdelta", n, alpha: absSum / n, signBits }; // ~1 bit/param + one f32
28
+ }
29
+
30
+ export function decodeBitDelta(baseW, rec, out) {
31
+ const n = rec.n, a = rec.alpha, o = out || new Float32Array(n);
32
+ for (let i = 0; i < n; i++) {
33
+ const pos = (rec.signBits[i >> 3] >> (i & 7)) & 1;
34
+ o[i] = baseW[i] + (pos ? a : -a);
35
+ }
36
+ return o;
37
+ }
38
+
39
+ // fraction of the delta's ENERGY captured by sign+scale (1 = perfect). For a Gaussian Δ this → 2/π ≈ 0.637.
40
+ export function deltaCaptured(baseW, ftW, rec) {
41
+ const n = rec.n; let num = 0, den = 0;
42
+ for (let i = 0; i < n; i++) {
43
+ const d = ftW[i] - baseW[i], pos = (rec.signBits[i >> 3] >> (i & 7)) & 1, r = d - (pos ? rec.alpha : -rec.alpha);
44
+ num += r * r; den += d * d;
45
+ }
46
+ return den ? 1 - num / den : 1;
47
+ }
48
+
49
+ // ── model-level delta: per tensor, frozen (κ identical) → ref (0 bytes) else bitdelta. Frame-guarded. ──
50
+ // tensors: { name → { kappa, params, baseW?, ftW? } }. baseW/ftW (dequant weights) only needed to encode
51
+ // CHANGED tensors; pass them for changed ones, omit for frozen (κ tells us they're identical).
52
+ export function deltaModel(baseMeta, ftMeta, baseTensors, ftTensors) {
53
+ if (!shareable(baseMeta, ftMeta)) throw new Error("holo-delta: base and finetune are not in the same frame/arch — cannot delta (see holo-model-frame.shareable)");
54
+ const records = {}; let frozenParams = 0, changedParams = 0, deltaBytes = 0;
55
+ for (const name of Object.keys(ftTensors)) {
56
+ const b = baseTensors[name], f = ftTensors[name];
57
+ if (b && f.kappa && b.kappa === f.kappa) { records[name] = { kind: "ref", kappa: b.kappa }; frozenParams += f.params || 0; continue; }
58
+ const rec = encodeBitDelta(f.baseW, f.ftW);
59
+ records[name] = { kind: "bitdelta", base: b ? b.kappa : null, alpha: rec.alpha, n: rec.n };
60
+ changedParams += rec.n; deltaBytes += rec.signBits.length + 4; // bits + α
61
+ }
62
+ return { records, stats: { frozenParams, changedParams, deltaBytes, deltaBitsPerChangedParam: changedParams ? (deltaBytes * 8) / changedParams : 0 } };
63
+ }
64
+
65
+ // ── LOSSLESS byte-delta over stored quantized blocks (the right fit for κ-objects). A base and finetune
66
+ // tensor share the same packed length (same dims+fmt); store only the differing byte runs. Reconstruction
67
+ // is byte-identical to the finetune's own block ⇒ perplexity = standalone (NO quality gate). Falls back to
68
+ // storing the whole block when the diff isn't sparse. This is the default for the family loader. ──
69
+ const _GAP = 8; // coalesce changed runs separated by ≤_GAP identical bytes (amortizes per-run header)
70
+ export function encodeByteDelta(baseBytes, ftBytes) {
71
+ if (baseBytes.length !== ftBytes.length) return { kind: "whole", len: ftBytes.length, bytes: ftBytes };
72
+ const n = ftBytes.length, runs = []; let i = 0, deltaSize = 0;
73
+ while (i < n) {
74
+ if (baseBytes[i] === ftBytes[i]) { i++; continue; }
75
+ let j = i + 1, gap = 0; // extend run, tolerating short identical gaps
76
+ while (j < n && (baseBytes[j] !== ftBytes[j] || (gap = run_gap(baseBytes, ftBytes, j)) <= _GAP)) { j += gap > 0 ? gap : 1; if (gap > 0) gap = 0; }
77
+ runs.push({ off: i, bytes: ftBytes.slice(i, j) }); deltaSize += (j - i) + 8; // bytes + ~8B run header
78
+ i = j;
79
+ }
80
+ if (deltaSize >= n * 0.9) return { kind: "whole", len: n, bytes: ftBytes }; // not sparse enough → store whole
81
+ return { kind: "bytedelta", len: n, runs };
82
+ }
83
+ function run_gap(a, b, j) { let g = 0; while (j + g < a.length && a[j + g] === b[j + g]) g++; return g; }
84
+ export function applyByteDelta(baseBytes, rec) {
85
+ if (rec.kind === "whole") return rec.bytes;
86
+ const out = baseBytes.slice(0, rec.len);
87
+ for (const r of rec.runs) out.set(r.bytes, r.off);
88
+ return out;
89
+ }
90
+ export function byteDeltaSize(rec) { return rec.kind === "whole" ? rec.bytes.length : rec.runs.reduce((s, r) => s + r.bytes.length + 8, 0); }
91
+
92
+ // compact binary (de)serialization for a byte-delta record — what gets gzipped + content-addressed.
93
+ export function serializeDelta(rec) {
94
+ if (rec.kind === "whole") { const o = new Uint8Array(5 + rec.bytes.length); new DataView(o.buffer).setUint32(1, rec.len); o[0] = 1; o.set(rec.bytes, 5); return o; }
95
+ let sz = 9; for (const r of rec.runs) sz += 8 + r.bytes.length;
96
+ const o = new Uint8Array(sz), dv = new DataView(o.buffer); o[0] = 0; dv.setUint32(1, rec.len); dv.setUint32(5, rec.runs.length); let p = 9;
97
+ for (const r of rec.runs) { dv.setUint32(p, r.off); dv.setUint32(p + 4, r.bytes.length); o.set(r.bytes, p + 8); p += 8 + r.bytes.length; }
98
+ return o;
99
+ }
100
+ export function parseDelta(u8) {
101
+ const dv = new DataView(u8.buffer, u8.byteOffset, u8.byteLength), len = dv.getUint32(1);
102
+ if (u8[0] === 1) return { kind: "whole", len, bytes: u8.subarray(5) };
103
+ const nRuns = dv.getUint32(5), runs = []; let p = 9;
104
+ for (let i = 0; i < nRuns; i++) { const off = dv.getUint32(p), blen = dv.getUint32(p + 4); runs.push({ off, bytes: u8.subarray(p + 8, p + 8 + blen) }); p += 8 + blen; }
105
+ return { kind: "bytedelta", len, runs };
106
+ }
107
+
108
+ // zoo storage ratio vs storing N finetunes independently. baseBitsPerParam ≈ 3 (q3) or 4 (q4).
109
+ export function zooRatio({ totalParams, frozenFractionOfParams, N, baseBitsPerParam = 3 }) {
110
+ const B = baseBitsPerParam, g = 1 - frozenFractionOfParams; // g = changed fraction
111
+ const independent = (N + 1) * totalParams * B;
112
+ const shared = totalParams * B + N * (g * totalParams * 1); // base + N×(changed params × 1 bit)
113
+ return independent / shared;
114
+ }
115
+
116
+ // ── Node self-test: realistic synthetic base + finetunes at varying frozen fractions. ──
117
+ if (typeof process !== "undefined" && process.argv[1] && process.argv[1].endsWith("holo-delta.mjs")) {
118
+ const n = 1 << 20; // 1M-param tensor
119
+ const rnd = (() => { let s = 0x2545f491; return () => { s ^= s << 13; s ^= s >>> 17; s ^= s << 5; s >>>= 0; return s / 4294967296; }; })();
120
+ const gauss = (sig) => { let u = 0, v = 0; while (!u) u = rnd(); while (!v) v = rnd(); return sig * Math.sqrt(-2 * Math.log(u)) * Math.cos(2 * Math.PI * v); };
121
+ const baseW = new Float32Array(n); for (let i = 0; i < n; i++) baseW[i] = gauss(0.02); // LLM-like weight σ
122
+
123
+ console.log("\n— BitDelta fidelity on a CHANGED tensor (Δ ~ Gaussian) —");
124
+ for (const dsig of [0.002, 0.02]) {
125
+ const ftW = new Float32Array(n); for (let i = 0; i < n; i++) ftW[i] = baseW[i] + gauss(dsig);
126
+ const rec = encodeBitDelta(baseW, ftW); const hat = decodeBitDelta(baseW, rec);
127
+ let relNum = 0, relDen = 0; for (let i = 0; i < n; i++) { const e = ftW[i] - hat[i]; relNum += e * e; relDen += ftW[i] * ftW[i]; }
128
+ const bpp = (rec.signBits.length + 4) * 8 / n;
129
+ console.log(` Δσ=${dsig}: α=${rec.alpha.toExponential(2)} energy-captured=${(deltaCaptured(baseW, ftW, rec) * 100).toFixed(1)}% recon ||err||/||ft||=${Math.sqrt(relNum / relDen).toExponential(2)} ${bpp.toFixed(3)} bits/param`);
130
+ }
131
+
132
+ console.log("\n— zoo storage ratio (base + 50 finetunes) by frozen-tensor fraction —");
133
+ for (const frozen of [0.0, 0.5, 0.8, 0.9, 0.98]) {
134
+ const r3 = zooRatio({ totalParams: 2e9, frozenFractionOfParams: frozen, N: 50, baseBitsPerParam: 3 });
135
+ const r4 = zooRatio({ totalParams: 2e9, frozenFractionOfParams: frozen, N: 50, baseBitsPerParam: 4 });
136
+ const tag = frozen === 0 ? "full finetune" : frozen >= 0.98 ? "LoRA-ish" : "partial";
137
+ console.log(` frozen=${(frozen * 100).toFixed(0).padStart(3)}% → ${r3.toFixed(1)}× (q3 base) · ${r4.toFixed(1)}× (q4 base) [${tag}]`);
138
+ }
139
+
140
+ console.log("\n— lossless byte-delta over a quantized block (reconstruct must be byte-identical) —");
141
+ for (const changeFrac of [0.02, 0.2, 0.6]) {
142
+ const blkN = 1 << 20, base = new Uint8Array(blkN); for (let i = 0; i < blkN; i++) base[i] = (rnd() * 256) | 0;
143
+ const ft = base.slice(); for (let i = 0; i < blkN; i++) if (rnd() < changeFrac) ft[i] = (rnd() * 256) | 0; // finetune flips a fraction of bytes
144
+ const rec = encodeByteDelta(base, ft); const back = applyByteDelta(base, rec);
145
+ let identical = back.length === ft.length; for (let i = 0; identical && i < ft.length; i++) identical = back[i] === ft[i];
146
+ console.log(` changed≈${(changeFrac * 100).toFixed(0)}% → ${rec.kind.padEnd(9)} ${(byteDeltaSize(rec) / 1024).toFixed(0)}KB vs ${(blkN / 1024).toFixed(0)}KB block (${(byteDeltaSize(rec) / blkN).toFixed(2)}×) reconstruct byte-identical=${identical}`);
147
+ }
148
+
149
+ console.log("\n— frame guard —");
150
+ const A = { frame: { fingerprint: "x" }, d: 2560, n_layers: 30, ff: 6912, n_heads: 20, n_kv_heads: 5, hd: 128, vocab: 128256 };
151
+ const Bsame = { ...A }, Bdiff = { ...A, d: 3584 };
152
+ console.log(` same frame+arch shareable: ${shareable(A, Bsame)} · different arch shareable: ${shareable(A, Bdiff)}`);
153
+ // and that deltaModel refuses a mismatched pair
154
+ try { deltaModel(A, Bdiff, {}, {}); console.log(" ERROR: deltaModel should have refused"); }
155
+ catch (e) { console.log(` deltaModel correctly refused mismatch: "${e.message.slice(0, 60)}…"`); }
156
+ }
apps/q/holo-load-delta.mjs ADDED
@@ -0,0 +1,54 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // holo-load-delta.mjs — A2 LOAD wiring. Loads a family finetune stored as `base-κ + delta` (format
2
+ // "holo-delta/1", produced by _delta-build.mjs) and returns the SAME { manifest, fetchTensor, info } shape
3
+ // as holo-load2bit.loadKappaObject — so the GPU engine, KV-cache, and Q's brain loader are UNCHANGED.
4
+ // loadKappaObject delegates here automatically when it sees the holo-delta/1 format (one seam, hidden).
5
+ //
6
+ // Per tensor: ref → the base block (frozen, κ identical, dedup'd in the OPFS store); whole → the stored
7
+ // finetune block; bytedelta → base block + lossless byte-delta. Reconstruction is byte-identical to the
8
+ // finetune's own block ⇒ perplexity = standalone (no quality gate). The win is download/storage.
9
+ //
10
+ // Law L5: base AND delta blocks are each κ-verified (sha256(gz)==κ) before use; both κ are named in the
11
+ // L5-verified delta manifest, so the trust chain holds without re-hashing the reconstruction.
12
+ import { parseDelta, applyByteDelta } from "./holo-delta.mjs";
13
+ import { reshapeTensor, buildEngineManifest } from "./holo-load2bit.mjs";
14
+
15
+ async function gunzip(u8) { const ds = new DecompressionStream("gzip"); const w = ds.writable.getWriter(); w.write(u8); w.close(); return new Uint8Array(await new Response(ds.readable).arrayBuffer()); }
16
+ const hex = (buf) => [...new Uint8Array(buf)].map((b) => b.toString(16).padStart(2, "0")).join("");
17
+ const kFile = (k) => String(k).replace(":", "_"); // κ "sha256:<hex>" → block file "sha256_<hex>"
18
+
19
+ export async function loadDeltaObject(deltaUrl, opts = {}) {
20
+ const droot = String(deltaUrl).replace(/\/+$/, "");
21
+ const man = opts.manifest || await (await fetch(droot + "/manifest.json", { cache: "no-store" })).json();
22
+ const baseRoot = String(opts.baseUrl || man.base?.url || man.base?.dir || "").replace(/\/+$/, "");
23
+ if (!baseRoot) throw new Error("delta-load: no base location (opts.baseUrl or manifest.base.url)");
24
+
25
+ // κ-verified block fetch against a chosen root (base for frozen/base blocks, delta for delta blocks).
26
+ const getBlock = async (root, kappa) => {
27
+ const gz = new Uint8Array(await (await fetch(root + "/b/" + kFile(kappa) + ".gz", { cache: "no-store" })).arrayBuffer());
28
+ const got = "sha256:" + hex(await crypto.subtle.digest("SHA-256", gz));
29
+ if (got !== kappa) throw new Error("delta-load κ MISMATCH " + String(kappa).slice(0, 24));
30
+ return gunzip(gz);
31
+ };
32
+
33
+ const normRecs = {}; // {name → {N,K,fmt,fp16?,s?}} for the shared manifest builder
34
+ for (const [name, dr] of Object.entries(man.tensors)) normRecs[name] = dr.meta || {};
35
+
36
+ const fetchTensor = async (name) => {
37
+ const dr = man.tensors[name]; if (!dr) return new Uint8Array(0);
38
+ let raw;
39
+ if (dr.kind === "ref") raw = await getBlock(baseRoot, dr.kappa); // frozen
40
+ else if (dr.kind === "whole") raw = parseDelta(await getBlock(droot, dr.delta)).bytes; // stored whole
41
+ else if (dr.kind === "bytedelta") raw = applyByteDelta(await getBlock(baseRoot, dr.base), parseDelta(await getBlock(droot, dr.delta)));
42
+ else throw new Error("delta-load: unknown record kind " + dr.kind + " for " + name);
43
+ return reshapeTensor(dr.meta || {}, raw);
44
+ };
45
+
46
+ let e8lutData; // E₈ LUT (if any) is a frozen base block
47
+ if (man.e8lut) { const b = await getBlock(baseRoot, man.e8lut.replace(/^did:holo:/, "")); e8lutData = new Float32Array(b.buffer, b.byteOffset, 2048); }
48
+ const manifest = buildEngineManifest(man, normRecs, e8lutData);
49
+ // tokenizer is the base's (finetune shares vocab); resolve a relative source against the BASE dir.
50
+ if (man.source && !/^https?:\/\//.test(man.source)) man.source = baseRoot + "/" + man.source;
51
+ return { manifest, fetchTensor, info: man };
52
+ }
53
+
54
+ export default loadDeltaObject;