From 9607c8558f8580774b1735bf0b1fd808d3b2470d Mon Sep 17 00:00:00 2001 From: Lucas Winther Date: Thu, 29 Oct 2026 21:34:15 +0100 Subject: [PATCH 1/6] Add plan for the Transformers.js 4.3.2 upgrade (workstream 1) Co-Authored-By: Claude Opus 5.5 --- docs/plans/001-1-transformers-upgrade.md | 122 +++++++++++++++++++++++ 1 file changed, 122 insertions(+) create mode 100644 docs/plans/001-1-transformers-upgrade.md diff --git a/docs/plans/001-1-transformers-upgrade.md b/docs/plans/001-1-transformers-upgrade.md new file mode 100644 index 0000000..851c621 --- /dev/null +++ b/docs/plans/001-1-transformers-upgrade.md @@ -0,0 +1,122 @@ +--- +status: in-progress +--- + +# 001-1 — Transformers.js 4.2.0 → 4.3.2 Implementation Plan + +> **For agentic workers:** REQUIRED SUB-SKILL: superpowers:executing-plans (inline, no nested +> subagents — coordination plan rule). Steps use checkbox (`- [ ]`) syntax for tracking. + +**Goal:** run the browser engine on `@huggingface/transformers` 4.3.2 with the D-027/D-028 +sequential-session patch carried over, and re-test the decisions the upgrade may obsolete. + +**Architecture:** dependency bump + `bun patch` regeneration; a small runtime-guard test file pins +the installed version, the patch, and the upstream seek-loop condition D-021 depends on, so a future +bump that silently drops the patch or changes the condition fails the fast suite. Re-tests run as +scratch measurement scripts outside the repo (`/tmp/ws1/`); their numbers go into `D-WS1*` entries. + +**Tech Stack:** Bun 1.3, `@huggingface/transformers` 4.3.2 (onnxruntime-web 1.31.0-dev.20260914, +onnxruntime-node 1.30.0), bun:test. + +**Spec:** `docs/specs/001-transcription-quality-and-speed.md` (Goal 1); coordination rules in +`docs/plans/001-0-coordination.md`. + +## Global Constraints + +- Bun only; no new runtime dependency; transformers stays a devDependency (D-031). +- New decisions are `## D-WS1 — …` appended at the bottom of `docs/Decisions.md`; Accepted + entries are superseded, never rewritten. +- Heavy commands (real-model runs, benchmarks, model downloads, full `bun test`) under + `flock /tmp/whisper-heavy.lock`. Ports 3110–3119. No push, no publishing. +- Measurements are CPU numbers (onnxruntime-node, or onnxruntime-web wasm EP under Bun); say which. +- No WebGPU-only default change ships on WASM numbers; WebGPU items → "needs owner's browser check". + +## Review Focus + +1. **Patch silently lost on reinstall** (lockfile/`patchedDependencies` key mismatch) → the app + loads fine but mobile OOM returns. Pinned by Task 1's patch-applied test. +2. **onnxruntime-web file names changed** (new version may ship different `.mjs/.wasm` names) → + `/ort/` serving and `dist/ort` copy must still contain what ort-web requests. Task 1: build and + check `dist/ort/` contains `ort-wasm-simd-threaded.jsep.{mjs,wasm}` (the WebGPU bundle's files). +3. **Upstream changes the seek-loop condition** → D-021's `max_new_tokens` could become wrong or + unneeded without notice. Pinned by Task 2's source-tripwire test. +4. **onnxruntime-node 1.30 drifts real-model WER** → `tests/live-real-model.test.ts` under the lock + (Task 5). +5. **q8 decoders on WASM at default optimization level** (D-014's failure) — Task 3 measures every + level before any change to the worker's session options. + +--- + +### Task 1: Upgrade to 4.3.2 and carry the patch + +**Files:** +- Create: `tests/transformers-runtime.test.ts` +- Modify: `package.json`, `bun.lock`, `AGENTS.md` (patch path), `docs/WorkBreakdown.md` +- Create: `patches/@huggingface%2Ftransformers@4.3.2.patch`; Delete: the 4.2.0 patch + +**Interfaces:** +- Produces: `tests/transformers-runtime.test.ts` (Task 2 adds a case to it). + +- [ ] **Step 1: Write the failing test** `describe("@huggingface/transformers runtime")`: + - `"installed version is the pinned 4.3.2"` — `node_modules/@huggingface/transformers/package.json` + `.version === "4.3.2"`. + - `"patchedDependencies points at an existing patch for the installed version"` — root + `package.json` `patchedDependencies["@huggingface/transformers@4.3.2"]` is a path that exists. + - `"web bundle's constructSessions carries the sequential-load patch (D-027/D-028)"` — the + `constructSessions` function text sliced from `dist/transformers.web.js` contains + `options?.sequentialSessionLoad` and both `Promise.all(` and `for (const name of Object.keys(names))`. +- [ ] **Step 2: Run** `bun test tests/transformers-runtime.test.ts` → FAIL on version (4.2.0) and key. +- [ ] **Step 3:** `bun add -d @huggingface/transformers@4.3.2` (remove the 4.2.0 + `patchedDependencies` entry first if bun refuses), `bun patch @huggingface/transformers`, re-apply + the 4.2.0 hunk to `constructSessions` in `dist/transformers.web.js` (upstream is unchanged: + still a bare `Promise.all`), `bun patch --commit node_modules/@huggingface/transformers`. + `git rm` the 4.2.0 patch. Re-link the shared `.cache` symlink if the reinstall removed it. +- [ ] **Step 4: Run** the test → PASS; `bun install --frozen-lockfile` clean; typecheck; fast + suite; `bun run build`; `ls dist/ort` shows the files ort-web 1.31 requests. +- [ ] **Step 5:** docs: AGENTS.md patch filename; `D-WS1a` (upgrade, patch carried, why upstream + doesn't obsolete it, ort versions, Parakeet = CTC only); WorkBreakdown tick. Commit + "Upgrade @huggingface/transformers to 4.3.2 and carry the sequential-session patch". + +### Task 2: D-021 re-test (seek loop) + +**Files:** Modify `tests/transformers-runtime.test.ts`, `docs/Decisions.md`, +`src/worker/inference.worker.ts` (comment only: "4.2" → "4.2–4.3", cite D-WS1b). + +- [ ] **Step 1: Test** `"Whisper generate still takes the seek loop when max_new_tokens is unset (D-021)"` + — `src/models/whisper/modeling_whisper.js` contains + `if (generation_config.return_timestamps && !kwargs.max_new_tokens)`. Run → PASS expected + (tripwire; it encodes the revisit condition, verified against the 4.3.2 source). +- [ ] **Step 2: Measure** (`/tmp/ws1/d021.ts`, onnxruntime-node, under the lock): tiny.en q8 on + `en_alien.opus` (ffmpeg-static → 16 kHz f32), pipeline options as the worker + (`chunk_length_s 30, stride_length_s 5, return_timestamps true`), with and without + `max_new_tokens: 440`; record wall-clock, generate-pass count (wrap `model.generate`), window + count, WER vs `en_alien.txt` (`tests/dsp.ts` `wordErrorRate`). +- [ ] **Step 3:** `D-WS1b` with the numbers; keep `max_new_tokens: 440` unless the seek path is now + both faster and not worse on WER. Commit. + +### Task 3: D-014 re-test (WASM graphOptimizationLevel) + +**Files:** `docs/Decisions.md`; `src/worker/inference.worker.ts` only if the outcome is "drop". + +- [ ] **Step 1: Measure** (`/tmp/ws1/d014.ts`): `globalThis[Symbol.for("onnxruntime")] = + await import("onnxruntime-web")` before importing transformers, wasm EP, 1 thread; for + `onnx-community/whisper-tiny` `decoder_model_merged_quantized.onnx` create a session at + `disabled/basic/extended/all`; record success/error. If all load: transcribe `en_aiproblem` with + tiny.en q8 at `basic` vs default (`all`), 3 warm runs each, wall-clock + text identity. +- [ ] **Step 2:** If default fails → keep, `D-WS1c` "still needed on ort-web 1.31.0-dev". If it + loads and is not slower → remove the override (worker comment cites D-WS1c), run a q8 transcribe + again through the harness with the worker's new options. Commit. + +### Task 4: WebGPU-affecting changes (D-022, D-025/D-026) — inspection only + +- [ ] **Step 1:** Read 4.3.0/4.3.1/4.3.2 release notes and diff 4.2.0↔4.3.2 `src/` for + WebGPU/fp16/Firefox/Safari changes; check ort-web 1.31 dist for Gecko/fp16 handling. +- [ ] **Step 2:** `D-WS1d` listing each item as "needs owner's browser check" with what to try + (explicit WebGPU on Firefox for D-026; medium fp16 for D-022; Safari 26 WebGPU). No code change. + Commit. + +### Task 5: Verify and finish + +- [ ] typecheck, fast suite, build green; `flock /tmp/whisper-heavy.lock bun test + tests/live-real-model.test.ts` green; record WER per clip in D-WS1a if changed from the bars. +- [ ] `git status` clean; last commit `git rm docs/plans/001-1-transformers-upgrade.md`. From 753ea0397904fb6ba671644bd11b7553f9b44f88 Mon Sep 17 00:00:00 2001 From: Lucas Winther Date: Thu, 29 Oct 2026 21:44:18 +0100 Subject: [PATCH 2/6] Upgrade @huggingface/transformers to 4.3.2 and carry the sequential-session patch Co-Authored-By: Claude Opus 5.5 --- AGENTS.md | 2 +- bun.lock | 98 +++++++++---------- docs/Decisions.md | 28 ++++++ docs/WorkBreakdown.md | 4 + docs/plans/001-1-transformers-upgrade.md | 10 +- package.json | 4 +- ...> @huggingface%2Ftransformers@4.3.2.patch} | 7 +- tests/transformers-runtime.test.ts | 50 ++++++++++ 8 files changed, 136 insertions(+), 67 deletions(-) rename patches/{@huggingface%2Ftransformers@4.2.0.patch => @huggingface%2Ftransformers@4.3.2.patch} (88%) create mode 100644 tests/transformers-runtime.test.ts diff --git a/AGENTS.md b/AGENTS.md index de0e81b..7f9e600 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -38,7 +38,7 @@ step with the commands above, in the same commit. `src/worker/inference.worker.ts` only — never on the main thread. Server inference = faster-whisper via `server-py/sidecar.py` — never Transformers.js on the server. - **`@huggingface/transformers` is patched and a devDependency on purpose.** It is pinned by - `patches/@huggingface%2Ftransformers@4.2.0.patch` (D-027/D-028) and kept out of runtime deps so the + `patches/@huggingface%2Ftransformers@4.3.2.patch` (D-027/D-028, D-WS1a) and kept out of runtime deps so the Docker image stays small (D-031). Upgrading or moving it means redoing the patch: ask first. - **No cross-origin subresources.** Every response carries COOP/COEP `require-corp` (D-023, `src/index.ts`); a CDN script/style/font will be blocked. Self-host it (onnxruntime is served from `/ort/`). diff --git a/bun.lock b/bun.lock index 5059fc1..5871853 100644 --- a/bun.lock +++ b/bun.lock @@ -12,7 +12,7 @@ }, "devDependencies": { "@fontsource-variable/inter": "^5.3.0", - "@huggingface/transformers": "^4.2.0", + "@huggingface/transformers": "4.3.2", "@types/bun": "latest", "@types/passport": "^1.0.17", "@types/passport-local": "^1.0.38", @@ -27,70 +27,74 @@ "ffmpeg-static", ], "patchedDependencies": { - "@huggingface/transformers@4.2.0": "patches/@huggingface%2Ftransformers@4.2.0.patch", + "@huggingface/transformers@4.3.2": "patches/@huggingface%2Ftransformers@4.3.2.patch", }, "packages": { "@derhuerst/http-basic": ["@derhuerst/http-basic@8.2.4", "", { "dependencies": { "caseless": "^0.12.0", "concat-stream": "^2.0.0", "http-response-object": "^3.0.1", "parse-cache-control": "^1.0.1" } }, "sha512-F9rL9k9Xjf5blCz8HsJRO4diy111cayL2vkY2XE4r4t3n0yPXVYy3KD3nJ1qbrSn9743UWSXH4IwuCa/HWlGFw=="], - "@emnapi/runtime": ["@emnapi/runtime@1.11.2", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-kyOl3X0DuTiT1h2ft8r2fYO8JYtU9a9Xis/zBSiGArNaagCOWx90N1k2wxp18czFDH+OgcWGb5ZP/XMt3dcyPA=="], + "@emnapi/runtime": ["@emnapi/runtime@1.11.3", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-Xz4Tpyki7XyrpbUK1jR1AhdAdaXyhhY4lZ3neLodmhpuWfy2PAQN5B46sAiU4liOXGLkHypn/qU+jvfWSCYYLA=="], "@fontsource-variable/inter": ["@fontsource-variable/inter@5.3.0", "", {}, "sha512-OupL48va4JNofb97w6NYeF9S7W/kHNKM0Er8Dem5nqi4jeOLrVJDoE8tZEpnMJmtkvNbB1EIPPwHcdkF6b1oUA=="], - "@huggingface/jinja": ["@huggingface/jinja@0.5.9", "", {}, "sha512-uWTG+l3VJRsl7EXxYizuL3P+cCPoc3cRqbWWRcQN0FhejRfbdq0RNhCmbY/YDtnTcz9icdLYuLDjsnz4d8JMuw=="], + "@huggingface/jinja": ["@huggingface/jinja@0.5.11", "", {}, "sha512-YzEzwM5oQf4r0vs7ifWQ+yuVR1YkAHrjERQ+a8WRsStHHp4NRBg+NesjiFc+X2AFUpRvvrIeHDS1xFy9jY/IjQ=="], - "@huggingface/tokenizers": ["@huggingface/tokenizers@0.1.3", "", {}, "sha512-8rF/RRT10u+kn7YuUbUg0OF30K8rjTc78aHpxT+qJ1uWSqxT1MHi8+9ltwYfkFYJzT/oS+qw3JVfHtNMGAdqyA=="], + "@huggingface/tokenizers": ["@huggingface/tokenizers@0.2.0", "", {}, "sha512-LidMHe1FpcSYH4vcSjXooda34pC0M8m1gmDOv7SQi6Iv+ib1zX7J3sHBCC9/3FPCkn2k1b55FneVqMRxrr99pg=="], - "@huggingface/transformers": ["@huggingface/transformers@4.2.0", "", { "dependencies": { "@huggingface/jinja": "^0.5.6", "@huggingface/tokenizers": "^0.1.3", "onnxruntime-node": "1.24.3", "onnxruntime-web": "1.26.0-dev.20260416-b7804b056c", "sharp": "^0.34.5" } }, "sha512-8BRCoBMH0XsWaEIamuR0LrJGAfftgHAfb2Vrffy0VKlSAE/MnUJ5/h/zTfEP3fDIft+nk7TqB8xXEyABGitBjQ=="], + "@huggingface/transformers": ["@huggingface/transformers@4.3.2", "", { "dependencies": { "@huggingface/jinja": "^0.5.10", "@huggingface/tokenizers": "^0.2.0", "onnxruntime-node": "1.30.0", "onnxruntime-web": "1.31.0-dev.20260914-8d85527a0", "sharp": "^0.35.4" } }, "sha512-V3+dqf3iWlRYJ9I9GreM3zGQd0lAXnnoPeddmkOQYWAEE4l/+Fi6p7tx/qVUJlKQgLXGim2W76rTOzz+eC0i7g=="], "@img/colour": ["@img/colour@1.1.0", "", {}, "sha512-Td76q7j57o/tLVdgS746cYARfSyxk8iEfRxewL9h4OMzYhbW4TAcppl0mT4eyqXddh6L/jwoM75mo7ixa/pCeQ=="], - "@img/sharp-darwin-arm64": ["@img/sharp-darwin-arm64@0.34.5", "", { "optionalDependencies": { "@img/sharp-libvips-darwin-arm64": "1.2.4" }, "os": "darwin", "cpu": "arm64" }, "sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w=="], + "@img/sharp-darwin-arm64": ["@img/sharp-darwin-arm64@0.35.5", "", { "optionalDependencies": { "@img/sharp-libvips-darwin-arm64": "1.3.4" }, "os": "darwin", "cpu": "arm64" }, "sha512-QRUlFQ0WxvdWyqqG/WtI3iupfD5rBzmCHXSdPsY91sAtVtTo7Q4cb6zOccZ3gqEqkr0f1As1ehLqmEpDsRf+lg=="], - "@img/sharp-darwin-x64": ["@img/sharp-darwin-x64@0.34.5", "", { "optionalDependencies": { "@img/sharp-libvips-darwin-x64": "1.2.4" }, "os": "darwin", "cpu": "x64" }, "sha512-YNEFAF/4KQ/PeW0N+r+aVVsoIY0/qxxikF2SWdp+NRkmMB7y9LBZAVqQ4yhGCm/H3H270OSykqmQMKLBhBJDEw=="], + "@img/sharp-darwin-x64": ["@img/sharp-darwin-x64@0.35.5", "", { "optionalDependencies": { "@img/sharp-libvips-darwin-x64": "1.3.4" }, "os": "darwin", "cpu": "x64" }, "sha512-+BR255RhDlpygUpOc/Jdt1nT6DQ3XG/ERo5wbcdOf5Q320dKtPCKPLR1LJs9VGXRaMa8l1uUa0tkCNOXiAxZUw=="], - "@img/sharp-libvips-darwin-arm64": ["@img/sharp-libvips-darwin-arm64@1.2.4", "", { "os": "darwin", "cpu": "arm64" }, "sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g=="], + "@img/sharp-freebsd-wasm32": ["@img/sharp-freebsd-wasm32@0.35.5", "", { "dependencies": { "@img/sharp-wasm32": "0.35.5" }, "os": "freebsd" }, "sha512-Y/z91nEZ4uIBX5X3nfTovjU9lHNKFYbL2lpHCLVNmXQK03VIZvXBBt0KxbPGp2SdGSF+2mQU4e+hQaWOt86iAw=="], - "@img/sharp-libvips-darwin-x64": ["@img/sharp-libvips-darwin-x64@1.2.4", "", { "os": "darwin", "cpu": "x64" }, "sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg=="], + "@img/sharp-libvips-darwin-arm64": ["@img/sharp-libvips-darwin-arm64@1.3.4", "", { "os": "darwin", "cpu": "arm64" }, "sha512-5R89nBYiRdUlSWJxPhO+GVtaXzXSxKnRu/xqMn3KTA3L9EB9Oy/P+Nn2f2vlhPuUdy/Zusb2DarbyTpGCfEDuw=="], - "@img/sharp-libvips-linux-arm": ["@img/sharp-libvips-linux-arm@1.2.4", "", { "os": "linux", "cpu": "arm" }, "sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A=="], + "@img/sharp-libvips-darwin-x64": ["@img/sharp-libvips-darwin-x64@1.3.4", "", { "os": "darwin", "cpu": "x64" }, "sha512-iR2OKH80yi0U+dUplyh3/xdpFvps6YkCwsXenIJxqxR1v9o+xtKTGbS9H7cps+2Vxjc8B1j96p75NmTGjIhtpQ=="], - "@img/sharp-libvips-linux-arm64": ["@img/sharp-libvips-linux-arm64@1.2.4", "", { "os": "linux", "cpu": "arm64" }, "sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw=="], + "@img/sharp-libvips-linux-arm": ["@img/sharp-libvips-linux-arm@1.3.4", "", { "os": "linux", "cpu": "arm" }, "sha512-LmRtTsOHuvM2+wlO2Db37dx5MiZhB0FvSunciw48YjdOkZz9KAiRbm8ujeMOA1INqmei5NapFxYEK1D1ZSidmw=="], - "@img/sharp-libvips-linux-ppc64": ["@img/sharp-libvips-linux-ppc64@1.2.4", "", { "os": "linux", "cpu": "ppc64" }, "sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA=="], + "@img/sharp-libvips-linux-arm64": ["@img/sharp-libvips-linux-arm64@1.3.4", "", { "os": "linux", "cpu": "arm64" }, "sha512-Y3dgX/6lE2QhQb+Gxy0WZxfg9MEm/JBjamZpS2IklP7xIQoKN4hzAm7KcMVGtaVDt3neE9OKBC7vAfonA/Lr1A=="], - "@img/sharp-libvips-linux-riscv64": ["@img/sharp-libvips-linux-riscv64@1.2.4", "", { "os": "linux", "cpu": "none" }, "sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA=="], + "@img/sharp-libvips-linux-ppc64": ["@img/sharp-libvips-linux-ppc64@1.3.4", "", { "os": "linux", "cpu": "ppc64" }, "sha512-Le6boB8Tai0Nis+gIxIpKx68UDVVIqdR8Tin5Yf1z2LJJQLDJvCDRqRu+jC2qCoD+eIomonmOwB4smBRxfVpYQ=="], - "@img/sharp-libvips-linux-s390x": ["@img/sharp-libvips-linux-s390x@1.2.4", "", { "os": "linux", "cpu": "s390x" }, "sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ=="], + "@img/sharp-libvips-linux-riscv64": ["@img/sharp-libvips-linux-riscv64@1.3.4", "", { "os": "linux", "cpu": "none" }, "sha512-aHkkIEHPRdQEegJN20MLmGtxYD9R2wQr3Cwpddnu5+YKMt6Uzax7S9h5gpZTo8wyrGuZSlfQ63OevL5mTyOC7Q=="], - "@img/sharp-libvips-linux-x64": ["@img/sharp-libvips-linux-x64@1.2.4", "", { "os": "linux", "cpu": "x64" }, "sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw=="], + "@img/sharp-libvips-linux-s390x": ["@img/sharp-libvips-linux-s390x@1.3.4", "", { "os": "linux", "cpu": "s390x" }, "sha512-ra/mB6MikESDUO7Yg+Mi95bFBb9GsObURuhnOv3OqknjGe9sZrG8tCe9q0xSIGrtLgvgw0gKnFWcK4blSgQOuQ=="], - "@img/sharp-libvips-linuxmusl-arm64": ["@img/sharp-libvips-linuxmusl-arm64@1.2.4", "", { "os": "linux", "cpu": "arm64" }, "sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw=="], + "@img/sharp-libvips-linux-x64": ["@img/sharp-libvips-linux-x64@1.3.4", "", { "os": "linux", "cpu": "x64" }, "sha512-GJ//SSXbnwSDes02umB3nDJLFcQzw8a18V8fyhqr6tV515tOEMdImjjxj1AoafMRz56F3PHgftnj1QEKSU1zkw=="], - "@img/sharp-libvips-linuxmusl-x64": ["@img/sharp-libvips-linuxmusl-x64@1.2.4", "", { "os": "linux", "cpu": "x64" }, "sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg=="], + "@img/sharp-libvips-linuxmusl-arm64": ["@img/sharp-libvips-linuxmusl-arm64@1.3.4", "", { "os": "linux", "cpu": "arm64" }, "sha512-hvulFwtjUcagsis6BBxHwGFwWoNZjgYmULGVrZcyfNbjA8hKILbRxGg15/7w5HDyXHXUos/j6baAWqnCyQ2DWA=="], - "@img/sharp-linux-arm": ["@img/sharp-linux-arm@0.34.5", "", { "optionalDependencies": { "@img/sharp-libvips-linux-arm": "1.2.4" }, "os": "linux", "cpu": "arm" }, "sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw=="], + "@img/sharp-libvips-linuxmusl-x64": ["@img/sharp-libvips-linuxmusl-x64@1.3.4", "", { "os": "linux", "cpu": "x64" }, "sha512-6zXKeE/p39I1AmA3cJG35eyBGNqNddLnUXjhwBnsGjFPWqf5VKkDBEqaEkPDoTEtkxwi2vv8Tcr2mDyP4So7Fg=="], - "@img/sharp-linux-arm64": ["@img/sharp-linux-arm64@0.34.5", "", { "optionalDependencies": { "@img/sharp-libvips-linux-arm64": "1.2.4" }, "os": "linux", "cpu": "arm64" }, "sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg=="], + "@img/sharp-linux-arm": ["@img/sharp-linux-arm@0.35.5", "", { "optionalDependencies": { "@img/sharp-libvips-linux-arm": "1.3.4" }, "os": "linux", "cpu": "arm" }, "sha512-LEaXK2WdXVK5ykcw0buWyPMsmLLL2vpHLD6yrNSW+JGEL3BZPA4tpKN6iaMc4AxTTAoaX/sU1rOL51lcIz48ZQ=="], - "@img/sharp-linux-ppc64": ["@img/sharp-linux-ppc64@0.34.5", "", { "optionalDependencies": { "@img/sharp-libvips-linux-ppc64": "1.2.4" }, "os": "linux", "cpu": "ppc64" }, "sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA=="], + "@img/sharp-linux-arm64": ["@img/sharp-linux-arm64@0.35.5", "", { "optionalDependencies": { "@img/sharp-libvips-linux-arm64": "1.3.4" }, "os": "linux", "cpu": "arm64" }, "sha512-LYVx5JTsOM2CBzmxreh+nl64/3H6Xb09iSLknqH47z2T2DFFxDeFLP5y4dJwe6H7uGQlHPyEEtIqyo3DYsRwdQ=="], - "@img/sharp-linux-riscv64": ["@img/sharp-linux-riscv64@0.34.5", "", { "optionalDependencies": { "@img/sharp-libvips-linux-riscv64": "1.2.4" }, "os": "linux", "cpu": "none" }, "sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw=="], + "@img/sharp-linux-ppc64": ["@img/sharp-linux-ppc64@0.35.5", "", { "optionalDependencies": { "@img/sharp-libvips-linux-ppc64": "1.3.4" }, "os": "linux", "cpu": "ppc64" }, "sha512-QVxAAq8evVRI9ia2vqgwrmWucn5Dfv+JdWzj75pD8omHLPSP7f8p20O8jxzjCcuCEQEOtYOZUmX1hkiZ0kdevA=="], - "@img/sharp-linux-s390x": ["@img/sharp-linux-s390x@0.34.5", "", { "optionalDependencies": { "@img/sharp-libvips-linux-s390x": "1.2.4" }, "os": "linux", "cpu": "s390x" }, "sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg=="], + "@img/sharp-linux-riscv64": ["@img/sharp-linux-riscv64@0.35.5", "", { "optionalDependencies": { "@img/sharp-libvips-linux-riscv64": "1.3.4" }, "os": "linux", "cpu": "none" }, "sha512-LtdreXguaavKODPIfzJ4kffx7UNt1omwtK0rch4EBbbSTXPnxWmYSayXdLJw0fJzQ97kHt1gL/yh4tvU+nCyRQ=="], - "@img/sharp-linux-x64": ["@img/sharp-linux-x64@0.34.5", "", { "optionalDependencies": { "@img/sharp-libvips-linux-x64": "1.2.4" }, "os": "linux", "cpu": "x64" }, "sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ=="], + "@img/sharp-linux-s390x": ["@img/sharp-linux-s390x@0.35.5", "", { "optionalDependencies": { "@img/sharp-libvips-linux-s390x": "1.3.4" }, "os": "linux", "cpu": "s390x" }, "sha512-UZasTOFiYzotTsGOCu42BfUzP6Tu6Do/947iRm1RsLKvlllxwGcn4RN27LibGWceix4Y+Pmw3jsnTcCQIgWjqA=="], - "@img/sharp-linuxmusl-arm64": ["@img/sharp-linuxmusl-arm64@0.34.5", "", { "optionalDependencies": { "@img/sharp-libvips-linuxmusl-arm64": "1.2.4" }, "os": "linux", "cpu": "arm64" }, "sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg=="], + "@img/sharp-linux-x64": ["@img/sharp-linux-x64@0.35.5", "", { "optionalDependencies": { "@img/sharp-libvips-linux-x64": "1.3.4" }, "os": "linux", "cpu": "x64" }, "sha512-SxFtLTeJInhAA9Q836kux2vZNeOBQEx658qvbboZScr0wIARym3IcGmW7KpVD5sbVg0Ojy+udFQdayYIZyoNog=="], - "@img/sharp-linuxmusl-x64": ["@img/sharp-linuxmusl-x64@0.34.5", "", { "optionalDependencies": { "@img/sharp-libvips-linuxmusl-x64": "1.2.4" }, "os": "linux", "cpu": "x64" }, "sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q=="], + "@img/sharp-linuxmusl-arm64": ["@img/sharp-linuxmusl-arm64@0.35.5", "", { "optionalDependencies": { "@img/sharp-libvips-linuxmusl-arm64": "1.3.4" }, "os": "linux", "cpu": "arm64" }, "sha512-9HbMclmI1zlNkFRs3z9/eBtDjfD0sGlrX1z6b1qwmiFY5ElDLh4BC0LPBdVp7z1DXFiKlIcznf+ZlsuZzLxQqg=="], - "@img/sharp-wasm32": ["@img/sharp-wasm32@0.34.5", "", { "dependencies": { "@emnapi/runtime": "^1.7.0" }, "cpu": "none" }, "sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw=="], + "@img/sharp-linuxmusl-x64": ["@img/sharp-linuxmusl-x64@0.35.5", "", { "optionalDependencies": { "@img/sharp-libvips-linuxmusl-x64": "1.3.4" }, "os": "linux", "cpu": "x64" }, "sha512-4KOphqB035HrVdqLZfCgMzzERrQkkzOwRhl4OAkRO1YCldbaFjySXMaK534Mo0V+LndnlJk+sbUyLeU0ULyD1A=="], - "@img/sharp-win32-arm64": ["@img/sharp-win32-arm64@0.34.5", "", { "os": "win32", "cpu": "arm64" }, "sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g=="], + "@img/sharp-wasm32": ["@img/sharp-wasm32@0.35.5", "", { "dependencies": { "@emnapi/runtime": "^1.11.3" } }, "sha512-Ptsga1su4tQx+LLF1ECS9U6nz5kmrXKo6XVbtR48Ke3ZRxxgaWBu7IDtEe1quo8hiupwm6WFqxVlXaSf7IINGQ=="], - "@img/sharp-win32-ia32": ["@img/sharp-win32-ia32@0.34.5", "", { "os": "win32", "cpu": "ia32" }, "sha512-FV9m/7NmeCmSHDD5j4+4pNI8Cp3aW+JvLoXcTUo0IqyjSfAZJ8dIUmijx1qaJsIiU+Hosw6xM5KijAWRJCSgNg=="], + "@img/sharp-webcontainers-wasm32": ["@img/sharp-webcontainers-wasm32@0.35.5", "", { "dependencies": { "@img/sharp-wasm32": "0.35.5" }, "cpu": "none" }, "sha512-hfhF/FmoQyTUkA0bIKFOtw536BQSeBMe6BF6QyWlrPxT754+TFLaZ7sKKTfvvM0yJgKgaYTwnFCIZ/GuDw5SUA=="], - "@img/sharp-win32-x64": ["@img/sharp-win32-x64@0.34.5", "", { "os": "win32", "cpu": "x64" }, "sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw=="], + "@img/sharp-win32-arm64": ["@img/sharp-win32-arm64@0.35.5", "", { "os": "win32", "cpu": "arm64" }, "sha512-X4t7g+7ZA5DKblCBEXGjUqqemj4vczING/5viFwAL8h4N3qYeyjwdCvRLHi4EdOUI+2Z7UFlp1VM+p/AuEtm6Q=="], + + "@img/sharp-win32-ia32": ["@img/sharp-win32-ia32@0.35.5", "", { "os": "win32", "cpu": "ia32" }, "sha512-5Zm82LoBc43nhwNybZlG7Y1KO//Zhsn306fQl29ZOuStHLGTo3BWL83q3cznX0poxSAMuYL1On/BHBxkBeKr6A=="], + + "@img/sharp-win32-x64": ["@img/sharp-win32-x64@0.35.5", "", { "os": "win32", "cpu": "x64" }, "sha512-x76eH0vEiHlcMQu8Y8IenntaACtddpT6W0wmXtWrnKcnKI7ME5DdgqhAD6SEWOEl1v2zDvkZDhFA9KnURwpfqg=="], "@protobufjs/aspromise": ["@protobufjs/aspromise@1.1.2", "", {}, "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ=="], @@ -182,12 +186,10 @@ "@typescript/typescript-win32-x64": ["@typescript/typescript-win32-x64@7.0.2", "", { "os": "win32", "cpu": "x64" }, "sha512-0BQ3HkAHHlKLSp1qRvf3SUhGpGsDuhB/jgFw75guyqbxJqEaS0Cw/VFO8i2nHglJUzQCRtMMR/IBAKE3ETMC4g=="], - "adm-zip": ["adm-zip@0.5.18", "", {}, "sha512-ufJnssQGbxzLNS1Ho9bCtX4rQKCCvoVuDLHoJyc3F9dOGDB4BkWs2Ci0kv53lqocAEQ/Cbi+I2XCsNYGqVYqng=="], + "adm-zip": ["adm-zip@0.6.1", "", {}, "sha512-Xwrja8nx9e5o2N1my4DsKCeKpdrnACyr1wtbPxBDgGzKzKyE9kRtBFA8mWldI+RVlD7CBZNWY/wQ2+ydwOR6kQ=="], "agent-base": ["agent-base@6.0.2", "", { "dependencies": { "debug": "4" } }, "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ=="], - "boolean": ["boolean@3.2.0", "", {}, "sha512-d0II/GO9uf9lfUHH2BQsjxzRJZBdsjgsBiW4BvhWk/3qoKwQFjIDVN19PfX8F2D/r9PCMTtLWjYVCFrpeYUzsw=="], - "buffer-from": ["buffer-from@1.1.2", "", {}, "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ=="], "bun-types": ["bun-types@1.3.14", "", { "dependencies": { "@types/node": "*" } }, "sha512-4N0ig0fEomHt5R0KCFWjovxow98rIoRwKolrYdCcknNwMekCXRnWEUvgu5soYV8QXtVsrUD8B95MBOZGPvr6KQ=="], @@ -206,23 +208,19 @@ "detect-libc": ["detect-libc@2.1.2", "", {}, "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ=="], - "detect-node": ["detect-node@2.1.0", "", {}, "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g=="], - "env-paths": ["env-paths@2.2.1", "", {}, "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A=="], "es-define-property": ["es-define-property@1.0.1", "", {}, "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g=="], "es-errors": ["es-errors@1.3.0", "", {}, "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw=="], - "es6-error": ["es6-error@4.1.1", "", {}, "sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg=="], - "escape-string-regexp": ["escape-string-regexp@4.0.0", "", {}, "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA=="], "ffmpeg-static": ["ffmpeg-static@5.3.0", "", { "dependencies": { "@derhuerst/http-basic": "^8.2.0", "env-paths": "^2.2.0", "https-proxy-agent": "^5.0.0", "progress": "^2.0.3" } }, "sha512-H+K6sW6TiIX6VGend0KQwthe+kaceeH/luE8dIZyOP35ik7ahYojDuqlTV1bOrtEwl01sy2HFNGQfi5IDJvotg=="], "flatbuffers": ["flatbuffers@25.9.23", "", {}, "sha512-MI1qs7Lo4Syw0EOzUl0xjs2lsoeqFku44KpngfIduHBYvzm8h2+7K8YMQh1JtVVVrUvhLpNwqVi4DERegUJhPQ=="], - "global-agent": ["global-agent@3.0.0", "", { "dependencies": { "boolean": "^3.0.1", "es6-error": "^4.1.1", "matcher": "^3.0.0", "roarr": "^2.15.3", "semver": "^7.3.2", "serialize-error": "^7.0.1" } }, "sha512-PT6XReJ+D07JvGoxQMkT6qji/jVNfX/h364XHZOWeRzy64sSFr+xJ5OX7LI3b4MPQzdL4H8Y8M0xzPpsVMwA8Q=="], + "global-agent": ["global-agent@4.1.6", "", { "dependencies": { "globalthis": "^1.0.2", "matcher": "^4.0.0", "semver": "^7.3.5", "serialize-error": "^8.1.0" } }, "sha512-V9u791atI/bS7RryfRTK2oixDWo6/RCrIikjwuQ4kADPRZZml1C6LUJXc7y6qRhaAF8geo3bIvE/siAGJCw38A=="], "globalthis": ["globalthis@1.0.4", "", { "dependencies": { "define-properties": "^1.2.1", "gopd": "^1.0.1" } }, "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ=="], @@ -238,21 +236,19 @@ "inherits": ["inherits@2.0.4", "", {}, "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="], - "json-stringify-safe": ["json-stringify-safe@5.0.1", "", {}, "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA=="], - "long": ["long@5.3.2", "", {}, "sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA=="], - "matcher": ["matcher@3.0.0", "", { "dependencies": { "escape-string-regexp": "^4.0.0" } }, "sha512-OkeDaAZ/bQCxeFAozM55PKcKU0yJMPGifLwV4Qgjitu+5MoAfSQN4lsLJeXZ1b8w0x+/Emda6MZgXS1jvsapng=="], + "matcher": ["matcher@4.0.0", "", { "dependencies": { "escape-string-regexp": "^4.0.0" } }, "sha512-S6x5wmcDmsDRRU/c2dkccDwQPXoFczc5+HpQ2lON8pnvHlnvHAHj5WlLVvw6n6vNyHuVugYrFohYxbS+pvFpKQ=="], "ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="], "object-keys": ["object-keys@1.1.1", "", {}, "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA=="], - "onnxruntime-common": ["onnxruntime-common@1.24.3", "", {}, "sha512-GeuPZO6U/LBJXvwdaqHbuUmoXiEdeCjWi/EG7Y1HNnDwJYuk6WUbNXpF6luSUY8yASul3cmUlLGrCCL1ZgVXqA=="], + "onnxruntime-common": ["onnxruntime-common@1.30.0", "", {}, "sha512-7fdVWjAID1dVhH/G8qK3APARunV4VkBFoCQAP7qp4Wkab0mrorvmc+sqiT+mKXOzDqdjN5j+/Z9nb4gzNPWcyA=="], - "onnxruntime-node": ["onnxruntime-node@1.24.3", "", { "dependencies": { "adm-zip": "^0.5.16", "global-agent": "^3.0.0", "onnxruntime-common": "1.24.3" }, "os": [ "linux", "win32", "darwin", ] }, "sha512-JH7+czbc8ALA819vlTgcV+Q214/+VjGeBHDjX81+ZCD0PCVCIFGFNtT0V4sXG/1JXypKPgScQcB3ij/hk3YnTg=="], + "onnxruntime-node": ["onnxruntime-node@1.30.0", "", { "dependencies": { "adm-zip": "^0.6.0", "global-agent": "^4.1.3", "onnxruntime-common": "1.30.0" }, "os": [ "linux", "win32", "darwin", ] }, "sha512-twhs1C2C/BFkz1yc5OY0KIU2GUq6DURO7hD4bx5Q2Qy3nAMJwRXW8xU3NVczE29VA9lolLOYepoD8fjTGOfIqw=="], - "onnxruntime-web": ["onnxruntime-web@1.26.0-dev.20260416-b7804b056c", "", { "dependencies": { "flatbuffers": "^25.1.24", "guid-typescript": "^1.0.9", "long": "^5.2.3", "onnxruntime-common": "1.24.0-dev.20251116-b39e144322", "platform": "^1.3.6", "protobufjs": "^7.2.4" } }, "sha512-MD6Ss4GSpQBo6zqoJzyT9LRbKYs7x/JVN23FT24EcEvlqF4VuzPOeH6X38orZPKHQDbprn7K+SBpu0/mj2CQiw=="], + "onnxruntime-web": ["onnxruntime-web@1.31.0-dev.20260914-8d85527a0", "", { "dependencies": { "flatbuffers": "^25.1.24", "guid-typescript": "^1.0.9", "long": "^5.2.3", "onnxruntime-common": "1.31.0-dev.20260911-2a43ec07e", "platform": "^1.3.6", "protobufjs": "^7.2.4" } }, "sha512-Iy7rtadoBgxS/LLvDr3QW38DB1PNXRnr0GJMcL0TAt7c9qjgVQl83UlGCVyeAnK2InpmW8Uc3PL8XIuqtDeF6g=="], "parse-cache-control": ["parse-cache-control@1.0.1", "", {}, "sha512-60zvsJReQPX5/QP0Kzfd/VrpjScIQ7SHBW6bFCYfEP+fp0Eppr1SHhIO5nd1PjZtvclzSzES9D/p5nFJurwfWg=="], @@ -276,27 +272,21 @@ "readable-stream": ["readable-stream@3.6.2", "", { "dependencies": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", "util-deprecate": "^1.0.1" } }, "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA=="], - "roarr": ["roarr@2.15.4", "", { "dependencies": { "boolean": "^3.0.1", "detect-node": "^2.0.4", "globalthis": "^1.0.1", "json-stringify-safe": "^5.0.1", "semver-compare": "^1.0.0", "sprintf-js": "^1.1.2" } }, "sha512-CHhPh+UNHD2GTXNYhPWLnU8ONHdI+5DI+4EYIAOaiD63rHeYlZvyh8P+in5999TTSFgUYuKUAjzRI4mdh/p+2A=="], - "safe-buffer": ["safe-buffer@5.2.1", "", {}, "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="], "scheduler": ["scheduler@0.27.0", "", {}, "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q=="], "semver": ["semver@7.8.5", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA=="], - "semver-compare": ["semver-compare@1.0.0", "", {}, "sha512-YM3/ITh2MJ5MtzaM429anh+x2jiLVjqILF4m4oyQB18W7Ggea7BfqdH/wGMK7dDiMghv/6WG7znWMwUDzJiXow=="], + "serialize-error": ["serialize-error@8.1.0", "", { "dependencies": { "type-fest": "^0.20.2" } }, "sha512-3NnuWfM6vBYoy5gZFvHiYsVbafvI9vZv/+jlIigFn4oP4zjNPK3LhcY0xSCgeb1a5L8jO71Mit9LlNoi2UfDDQ=="], - "serialize-error": ["serialize-error@7.0.1", "", { "dependencies": { "type-fest": "^0.13.1" } }, "sha512-8I8TjW5KMOKsZQTvoxjuSIa7foAwPWGOts+6o7sgjz41/qMD9VQHEDxi6PBvK2l0MXUmqZyNpUK+T2tQaaElvw=="], - - "sharp": ["sharp@0.34.5", "", { "dependencies": { "@img/colour": "^1.0.0", "detect-libc": "^2.1.2", "semver": "^7.7.3" }, "optionalDependencies": { "@img/sharp-darwin-arm64": "0.34.5", "@img/sharp-darwin-x64": "0.34.5", "@img/sharp-libvips-darwin-arm64": "1.2.4", "@img/sharp-libvips-darwin-x64": "1.2.4", "@img/sharp-libvips-linux-arm": "1.2.4", "@img/sharp-libvips-linux-arm64": "1.2.4", "@img/sharp-libvips-linux-ppc64": "1.2.4", "@img/sharp-libvips-linux-riscv64": "1.2.4", "@img/sharp-libvips-linux-s390x": "1.2.4", "@img/sharp-libvips-linux-x64": "1.2.4", "@img/sharp-libvips-linuxmusl-arm64": "1.2.4", "@img/sharp-libvips-linuxmusl-x64": "1.2.4", "@img/sharp-linux-arm": "0.34.5", "@img/sharp-linux-arm64": "0.34.5", "@img/sharp-linux-ppc64": "0.34.5", "@img/sharp-linux-riscv64": "0.34.5", "@img/sharp-linux-s390x": "0.34.5", "@img/sharp-linux-x64": "0.34.5", "@img/sharp-linuxmusl-arm64": "0.34.5", "@img/sharp-linuxmusl-x64": "0.34.5", "@img/sharp-wasm32": "0.34.5", "@img/sharp-win32-arm64": "0.34.5", "@img/sharp-win32-ia32": "0.34.5", "@img/sharp-win32-x64": "0.34.5" } }, "sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg=="], - - "sprintf-js": ["sprintf-js@1.1.3", "", {}, "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA=="], + "sharp": ["sharp@0.35.5", "", { "dependencies": { "@img/colour": "^1.1.0", "detect-libc": "^2.1.2", "semver": "^7.8.5" }, "optionalDependencies": { "@img/sharp-darwin-arm64": "0.35.5", "@img/sharp-darwin-x64": "0.35.5", "@img/sharp-freebsd-wasm32": "0.35.5", "@img/sharp-libvips-darwin-arm64": "1.3.4", "@img/sharp-libvips-darwin-x64": "1.3.4", "@img/sharp-libvips-linux-arm": "1.3.4", "@img/sharp-libvips-linux-arm64": "1.3.4", "@img/sharp-libvips-linux-ppc64": "1.3.4", "@img/sharp-libvips-linux-riscv64": "1.3.4", "@img/sharp-libvips-linux-s390x": "1.3.4", "@img/sharp-libvips-linux-x64": "1.3.4", "@img/sharp-libvips-linuxmusl-arm64": "1.3.4", "@img/sharp-libvips-linuxmusl-x64": "1.3.4", "@img/sharp-linux-arm": "0.35.5", "@img/sharp-linux-arm64": "0.35.5", "@img/sharp-linux-ppc64": "0.35.5", "@img/sharp-linux-riscv64": "0.35.5", "@img/sharp-linux-s390x": "0.35.5", "@img/sharp-linux-x64": "0.35.5", "@img/sharp-linuxmusl-arm64": "0.35.5", "@img/sharp-linuxmusl-x64": "0.35.5", "@img/sharp-webcontainers-wasm32": "0.35.5", "@img/sharp-win32-arm64": "0.35.5", "@img/sharp-win32-ia32": "0.35.5", "@img/sharp-win32-x64": "0.35.5" }, "peerDependencies": { "@types/node": "*" }, "optionalPeers": ["@types/node"] }, "sha512-Ywn4OnzGukp7CDMrp08RQ50YKmuwG47brZgIVPTvBaaAfQlRlygrRqSrxdCiL9M+LlzLBiJ68IR1QqvzHyjC7g=="], "string_decoder": ["string_decoder@1.3.0", "", { "dependencies": { "safe-buffer": "~5.2.0" } }, "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA=="], "tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="], - "type-fest": ["type-fest@0.13.1", "", {}, "sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg=="], + "type-fest": ["type-fest@0.20.2", "", {}, "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ=="], "typedarray": ["typedarray@0.0.6", "", {}, "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA=="], @@ -310,6 +300,6 @@ "http-response-object/@types/node": ["@types/node@10.17.60", "", {}, "sha512-F0KIgDJfy2nA3zMLmWGKxcH2ZVEtCZXHHdOQs2gSaQ27+lNeEfGxzkIw90aXswATX7AZ33tahPbzy6KAfUreVw=="], - "onnxruntime-web/onnxruntime-common": ["onnxruntime-common@1.24.0-dev.20251116-b39e144322", "", {}, "sha512-BOoomdHYmNRL5r4iQ4bMvsl2t0/hzVQ3OM3PHD0gxeXu1PmggqBv3puZicEUVOA3AtHHYmqZtjMj9FOfGrATTw=="], + "onnxruntime-web/onnxruntime-common": ["onnxruntime-common@1.31.0-dev.20260911-2a43ec07e", "", {}, "sha512-gBuF6U32YErKIAt+yD7DeGBpjRxhJ1uJwako6ygjokSZULDU6Pd+KWComX8Tumk1hYVHRxjPj7mdMnD0ryAPOw=="], } } diff --git a/docs/Decisions.md b/docs/Decisions.md index 5dc8f08..9008a54 100644 --- a/docs/Decisions.md +++ b/docs/Decisions.md @@ -1224,3 +1224,31 @@ whole-file output is equally bad, which is exactly what the absolute bar exists to catch. **Consequence:** full `bun test` ≈ 19 min on CPU (en_alien ≈ 20 min of it on a cold run); the fast suite excludes this file. + +## D-WS1a — Transformers.js 4.2.0 → 4.3.2, sequential-session patch carried over +**Status:** Accepted (2026-10-29, spec 001 Goal 1) +`@huggingface/transformers` is now pinned to exactly `4.3.2` (latest; 4.3.0 +added Safari 26+ WebGPU). It brings onnxruntime-web +`1.31.0-dev.20260914-8d85527a0` (was `1.26.0-dev.20260416`) and +onnxruntime-node `1.30.0` (was `1.24.3`). +**Patch.** Upstream `constructSessions` (`dist/transformers.web.js`) is +still the bare `Promise.all` over sub-model sessions, so D-027/D-028's +`options.sequentialSessionLoad` branch is still needed. Regenerated with +`bun patch` as `patches/@huggingface%2Ftransformers@4.3.2.patch` (the same +hunk, byte-identical apart from line offsets); the 4.2.0 patch is deleted. +The version is pinned exactly (no caret) because the patch is keyed by +version: a caret range would let a fresh lockfile resolve a version the +patch does not apply to. +**Guard.** `tests/transformers-runtime.test.ts` (fast suite) fails if the +installed version, the `patchedDependencies` key, or the patched +`constructSessions` body drift apart — a lost patch would otherwise only +show up as mobile tab crashes. +**Unchanged by the bump:** onnxruntime-web's WebGPU bundle still loads the +`ort-wasm-simd-threaded.asyncify.{mjs,wasm}` pair (same as 1.26), and +`scripts/build.ts` / `/ort/` already copy every `ort-wasm-*` file. +**Parakeet (for spec 001 Goal 7):** 4.3.2 supports only the CTC variant — +`ParakeetForCTC` (`model_type: "parakeet_ctc"`, routed through the ASR +pipeline's wav2vec2/CTC path) plus `ParakeetFeatureExtractor`. There is no +TDT/RNN-T (transducer) decoder or joint-network loop anywhere in the +package, so **Parakeet TDT 0.6B v3 is not supported natively**; per the +spec, that path uses `parakeet.js`. diff --git a/docs/WorkBreakdown.md b/docs/WorkBreakdown.md index 336b0b4..d69541b 100644 --- a/docs/WorkBreakdown.md +++ b/docs/WorkBreakdown.md @@ -339,6 +339,10 @@ cached. `language`/`task` the same way the HTTP route does, and `tests/server-live.test.ts` covers the bridge against a fake sidecar. +## M8 — Transcription quality and speed (spec 001) +- [x] Transformers.js 4.2.0 → 4.3.2, sequential-session patch regenerated + for 4.3.2 and guarded by `tests/transformers-runtime.test.ts` (D-WS1a). + --- ## Deliberately out of scope (for now) diff --git a/docs/plans/001-1-transformers-upgrade.md b/docs/plans/001-1-transformers-upgrade.md index 851c621..978a5fa 100644 --- a/docs/plans/001-1-transformers-upgrade.md +++ b/docs/plans/001-1-transformers-upgrade.md @@ -57,7 +57,7 @@ onnxruntime-node 1.30.0), bun:test. **Interfaces:** - Produces: `tests/transformers-runtime.test.ts` (Task 2 adds a case to it). -- [ ] **Step 1: Write the failing test** `describe("@huggingface/transformers runtime")`: +- [x] **Step 1: Write the failing test** `describe("@huggingface/transformers runtime")`: - `"installed version is the pinned 4.3.2"` — `node_modules/@huggingface/transformers/package.json` `.version === "4.3.2"`. - `"patchedDependencies points at an existing patch for the installed version"` — root @@ -65,15 +65,15 @@ onnxruntime-node 1.30.0), bun:test. - `"web bundle's constructSessions carries the sequential-load patch (D-027/D-028)"` — the `constructSessions` function text sliced from `dist/transformers.web.js` contains `options?.sequentialSessionLoad` and both `Promise.all(` and `for (const name of Object.keys(names))`. -- [ ] **Step 2: Run** `bun test tests/transformers-runtime.test.ts` → FAIL on version (4.2.0) and key. -- [ ] **Step 3:** `bun add -d @huggingface/transformers@4.3.2` (remove the 4.2.0 +- [x] **Step 2: Run** `bun test tests/transformers-runtime.test.ts` → FAIL on version (4.2.0) and key. +- [x] **Step 3:** `bun add -d @huggingface/transformers@4.3.2` (remove the 4.2.0 `patchedDependencies` entry first if bun refuses), `bun patch @huggingface/transformers`, re-apply the 4.2.0 hunk to `constructSessions` in `dist/transformers.web.js` (upstream is unchanged: still a bare `Promise.all`), `bun patch --commit node_modules/@huggingface/transformers`. `git rm` the 4.2.0 patch. Re-link the shared `.cache` symlink if the reinstall removed it. -- [ ] **Step 4: Run** the test → PASS; `bun install --frozen-lockfile` clean; typecheck; fast +- [x] **Step 4: Run** the test → PASS; `bun install --frozen-lockfile` clean; typecheck; fast suite; `bun run build`; `ls dist/ort` shows the files ort-web 1.31 requests. -- [ ] **Step 5:** docs: AGENTS.md patch filename; `D-WS1a` (upgrade, patch carried, why upstream +- [x] **Step 5:** docs: AGENTS.md patch filename; `D-WS1a` (upgrade, patch carried, why upstream doesn't obsolete it, ort versions, Parakeet = CTC only); WorkBreakdown tick. Commit "Upgrade @huggingface/transformers to 4.3.2 and carry the sequential-session patch". diff --git a/package.json b/package.json index 7389e07..70d464e 100644 --- a/package.json +++ b/package.json @@ -18,7 +18,7 @@ }, "devDependencies": { "@fontsource-variable/inter": "^5.3.0", - "@huggingface/transformers": "^4.2.0", + "@huggingface/transformers": "4.3.2", "@types/bun": "latest", "@types/passport": "^1.0.17", "@types/passport-local": "^1.0.38", @@ -31,6 +31,6 @@ "ffmpeg-static" ], "patchedDependencies": { - "@huggingface/transformers@4.2.0": "patches/@huggingface%2Ftransformers@4.2.0.patch" + "@huggingface/transformers@4.3.2": "patches/@huggingface%2Ftransformers@4.3.2.patch" } } diff --git a/patches/@huggingface%2Ftransformers@4.2.0.patch b/patches/@huggingface%2Ftransformers@4.3.2.patch similarity index 88% rename from patches/@huggingface%2Ftransformers@4.2.0.patch rename to patches/@huggingface%2Ftransformers@4.3.2.patch index e26c9ff..7937bef 100644 --- a/patches/@huggingface%2Ftransformers@4.2.0.patch +++ b/patches/@huggingface%2Ftransformers@4.3.2.patch @@ -1,11 +1,8 @@ -diff --git a/node_modules/@huggingface/transformers/.bun-tag-8719566ebeed846f b/.bun-tag-8719566ebeed846f -new file mode 100644 -index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/dist/transformers.web.js b/dist/transformers.web.js -index bb7b32717a42475a5f66411a33d5e5964dfda3e2..03de63967e99f8f3c847858621d72577ef037391 100644 +index a86f15e936b5b03d960037ed3e82a175dd5a0ffb..d74ef622704370b0235a628cfa5746b06fcc620e 100644 --- a/dist/transformers.web.js +++ b/dist/transformers.web.js -@@ -18558,22 +18558,49 @@ async function getSession(pretrained_model_name_or_path, fileName, options, cach +@@ -19840,22 +19840,49 @@ async function getSession(pretrained_model_name_or_path, fileName, options, cach return { buffer_or_path, session_options, session_config }; } async function constructSessions(pretrained_model_name_or_path, names, options, cache_sessions = void 0) { diff --git a/tests/transformers-runtime.test.ts b/tests/transformers-runtime.test.ts new file mode 100644 index 0000000..73babd5 --- /dev/null +++ b/tests/transformers-runtime.test.ts @@ -0,0 +1,50 @@ +import { describe, expect, test } from "bun:test"; +import { existsSync, readFileSync } from "node:fs"; +import { join } from "node:path"; + +/** + * Tripwires for the patched, pinned Transformers.js runtime (D-WS1a). + * `@huggingface/transformers` carries a `bun patch` (D-027/D-028) keyed by + * its exact version; a bump that forgets to regenerate the patch would leave + * the app working but silently bring back the mobile OOM. These checks fail + * the fast suite instead. + */ + +const ROOT = join(import.meta.dir, ".."); +const PKG_DIR = join(ROOT, "node_modules/@huggingface/transformers"); +const PINNED_VERSION = "4.3.2"; + +function read(path: string): string { + return readFileSync(path, "utf8"); +} + +/** Source text of `async function (…) { … }` in a bundled file. */ +function functionSource(source: string, name: string): string { + const start = source.indexOf(`async function ${name}(`); + if (start < 0) throw new Error(`${name} not found`); + const end = source.indexOf("\nfunction ", start + 1); + const endAsync = source.indexOf("\nasync function ", start + 1); + const stops = [end, endAsync].filter((i) => i > 0); + return source.slice(start, stops.length ? Math.min(...stops) : undefined); +} + +describe("@huggingface/transformers runtime", () => { + test("installed version is the pinned 4.3.2", () => { + const installed = JSON.parse(read(join(PKG_DIR, "package.json"))).version; + expect(installed).toBe(PINNED_VERSION); + }); + + test("patchedDependencies points at an existing patch for the installed version", () => { + const rootPkg = JSON.parse(read(join(ROOT, "package.json"))); + const patchPath = rootPkg.patchedDependencies?.[`@huggingface/transformers@${PINNED_VERSION}`]; + expect(typeof patchPath).toBe("string"); + expect(existsSync(join(ROOT, patchPath))).toBe(true); + }); + + test("web bundle's constructSessions carries the sequential-load patch (D-027/D-028)", () => { + const body = functionSource(read(join(PKG_DIR, "dist/transformers.web.js")), "constructSessions"); + expect(body).toContain("options?.sequentialSessionLoad"); + expect(body).toContain("Promise.all("); + expect(body).toContain("for (const name of Object.keys(names))"); + }); +}); From cd9aa48b838c5c6216ccf35a5b99ed7b03130435 Mon Sep 17 00:00:00 2001 From: Lucas Winther Date: Thu, 29 Oct 2026 22:30:29 +0100 Subject: [PATCH 3/6] Record what the Transformers.js 4.3.2 upgrade changes on the WebGPU side and what needs a browser check Co-Authored-By: Claude Opus 5.5 --- docs/Decisions.md | 40 ++++++++++++++++++++++++ docs/plans/001-1-transformers-upgrade.md | 4 +-- 2 files changed, 42 insertions(+), 2 deletions(-) diff --git a/docs/Decisions.md b/docs/Decisions.md index 9008a54..5aa8acb 100644 --- a/docs/Decisions.md +++ b/docs/Decisions.md @@ -1252,3 +1252,43 @@ pipeline's wav2vec2/CTC path) plus `ParakeetFeatureExtractor`. There is no TDT/RNN-T (transducer) decoder or joint-network loop anywhere in the package, so **Parakeet TDT 0.6B v3 is not supported natively**; per the spec, that path uses `parakeet.js`. + +## D-WS1d — WebGPU-side effects of the 4.3.2 upgrade: inspected, not measured (needs the owner's browser check) +**Status:** Open — inspection only (2026-10-29) +This machine has no GPU and no browser WebGPU, so D-022, D-025 and D-026 +cannot be re-measured here. What the upgrade changes on that side, from the +4.3.0–4.3.2 release notes and a 4.2.0↔4.3.2 source diff: +- **onnxruntime-web 1.26.0-dev.20260416 → 1.31.0-dev.20260914.** Five minor + versions of WebGPU EP work land at once. The WebGPU bundle still uses the + same `ort-wasm-simd-threaded.asyncify` binary pair (now 26.9 MB, was + 23.6 MB — a one-time re-download, evicted correctly because the SW cache + version hashes the worker bundle, which embeds the ort version). The JS + layer still has no Firefox/Gecko or Safari special-casing, and still + checks `shader-f16` / `isFallbackAdapter` as before. +- **Safari 26+ WebGPU (Transformers.js 4.3.0, PR 1700).** The upstream change + only alters which binary Transformers.js picks for its jsDelivr default + (`IS_SAFARI` → `IS_SAFARI_BELOW_26`). This app overrides `wasmPaths` with + `./ort/`, so it never used that default; whether WebGPU is attempted on + Safari is decided by the worker's own probe (`navigator.gpu`, D-017/D-025), + unchanged. +- **Whisper / ASR pipeline / streamers:** no functional change (comment + edits, `processor.batch_decode` → `tokenizer.batch_decode` on a + non-Whisper path, one `transpose` → `permute` rename). "Fix Whisper + progress callbacks" and "fix duplicate model file downloads when + `progress_callback` is active" (4.3.0) are in the file-loading path: + download progress may look different, and a duplicate fetch is avoided. +- **Session/dtype selection (`session.js`, `dtypes.js`):** unchanged apart + from no longer exporting two constants. +**Needs the owner's browser check** (decisions stay as they are until then): +1. **Large v3 Turbo on WebGPU (the owner's setup):** load and transcribe + `tests/audio_files/en_aiproblem.m4a`; compare wall-clock with the 4.2.0 + build and confirm the text is sane (fp16 encoder + q4 decoder, D-022 + scope note). +2. **D-026:** Firefox with Backend = WebGPU explicitly selected — still far + slower than WASM? If it is now at parity, drop the Firefox UA check. +3. **D-022:** medium stays q4 on WebGPU/WebNN. A retest of the fp16 + conversions is only worth doing if the owner wants medium faster on GPU. +4. **D-025:** Firefox "auto" lands on multithreaded WASM (footer shows + "WASM (on-device, N threads)" with N > 1). +5. **Safari 26 (macOS/iOS):** what the footer reports for "auto"; if WebGPU, + check speed and output. diff --git a/docs/plans/001-1-transformers-upgrade.md b/docs/plans/001-1-transformers-upgrade.md index 978a5fa..25d5424 100644 --- a/docs/plans/001-1-transformers-upgrade.md +++ b/docs/plans/001-1-transformers-upgrade.md @@ -109,9 +109,9 @@ onnxruntime-node 1.30.0), bun:test. ### Task 4: WebGPU-affecting changes (D-022, D-025/D-026) — inspection only -- [ ] **Step 1:** Read 4.3.0/4.3.1/4.3.2 release notes and diff 4.2.0↔4.3.2 `src/` for +- [x] **Step 1:** Read 4.3.0/4.3.1/4.3.2 release notes and diff 4.2.0↔4.3.2 `src/` for WebGPU/fp16/Firefox/Safari changes; check ort-web 1.31 dist for Gecko/fp16 handling. -- [ ] **Step 2:** `D-WS1d` listing each item as "needs owner's browser check" with what to try +- [x] **Step 2:** `D-WS1d` listing each item as "needs owner's browser check" with what to try (explicit WebGPU on Firefox for D-026; medium fp16 for D-022; Safari 26 WebGPU). No code change. Commit. From 9f1d58c0b7da036bcc3606a5183bbaaac42e4707 Mon Sep 17 00:00:00 2001 From: Lucas Winther Date: Thu, 29 Oct 2026 22:59:35 +0100 Subject: [PATCH 4/6] Keep max_new_tokens: 440 on Transformers.js 4.3.2 and pin the seek-loop condition it avoids Co-Authored-By: Claude Opus 5.5 --- docs/Decisions.md | 27 ++++++++++++++++++++++++ docs/plans/001-1-transformers-upgrade.md | 6 +++--- src/worker/inference.worker.ts | 7 +++--- tests/transformers-runtime.test.ts | 7 ++++++ 4 files changed, 41 insertions(+), 6 deletions(-) diff --git a/docs/Decisions.md b/docs/Decisions.md index 5aa8acb..eab0ebb 100644 --- a/docs/Decisions.md +++ b/docs/Decisions.md @@ -1292,3 +1292,30 @@ cannot be re-measured here. What the upgrade changes on that side, from the "WASM (on-device, N threads)" with N > 1). 5. **Safari 26 (macOS/iOS):** what the footer reports for "auto"; if WebGPU, check speed and output. + +## D-WS1b — D-021's `max_new_tokens: 440` is still needed on Transformers.js 4.3.2 +**Status:** Accepted (2026-10-29) — re-test of D-021 part 3, which stands unchanged +**Source:** 4.3.2's `WhisperForConditionalGeneration.generate()` still takes +the seek loop on exactly D-021's condition, +`generation_config.return_timestamps && !kwargs.max_new_tokens` +(`src/models/whisper/modeling_whisper.js`); `_generate_with_seek` is +unchanged. `tests/transformers-runtime.test.ts` now pins that line, so a +future bump that changes it fails the fast suite and prompts a re-measure. +**Measured** (tiny.en q8 — the catalog WASM default — on onnxruntime-node, +CPU, 16-core shared machine, same harness for both versions; pipeline options +as the worker: 30 s chunks, 5 s stride, `return_timestamps`; 888 s +`en_alien.opus`, 44 windows): + +| Transformers.js | `max_new_tokens` | generate passes | wall-clock | WER | +|---|---|---|---|---| +| 4.2.0 | 440 | 44 | 54.7 s | 0.315 | +| 4.2.0 | unset (seek loop) | 83 | 66.6 s | 0.447 | +| 4.3.2 | 440 | 44 | 55.5 s | 0.315 | +| 4.3.2 | unset (seek loop) | 84 | 119.7 s | 0.449 | + +Pass counts and WER are deterministic and reproduce D-021 (80 passes, +0.447 vs 0.315); wall-clock is noisy here (other workstreams' light jobs +share the CPU), so read it only as "the seek loop is slower", not as a +version-to-version speed comparison. +**Decision:** keep `max_new_tokens: 440` in `src/worker/inference.worker.ts` +and in `tests/live-real-model.test.ts`. diff --git a/docs/plans/001-1-transformers-upgrade.md b/docs/plans/001-1-transformers-upgrade.md index 25d5424..0c623bf 100644 --- a/docs/plans/001-1-transformers-upgrade.md +++ b/docs/plans/001-1-transformers-upgrade.md @@ -82,16 +82,16 @@ onnxruntime-node 1.30.0), bun:test. **Files:** Modify `tests/transformers-runtime.test.ts`, `docs/Decisions.md`, `src/worker/inference.worker.ts` (comment only: "4.2" → "4.2–4.3", cite D-WS1b). -- [ ] **Step 1: Test** `"Whisper generate still takes the seek loop when max_new_tokens is unset (D-021)"` +- [x] **Step 1: Test** `"Whisper generate still takes the seek loop when max_new_tokens is unset (D-021)"` — `src/models/whisper/modeling_whisper.js` contains `if (generation_config.return_timestamps && !kwargs.max_new_tokens)`. Run → PASS expected (tripwire; it encodes the revisit condition, verified against the 4.3.2 source). -- [ ] **Step 2: Measure** (`/tmp/ws1/d021.ts`, onnxruntime-node, under the lock): tiny.en q8 on +- [x] **Step 2: Measure** (`/tmp/ws1/d021.ts`, onnxruntime-node, under the lock): tiny.en q8 on `en_alien.opus` (ffmpeg-static → 16 kHz f32), pipeline options as the worker (`chunk_length_s 30, stride_length_s 5, return_timestamps true`), with and without `max_new_tokens: 440`; record wall-clock, generate-pass count (wrap `model.generate`), window count, WER vs `en_alien.txt` (`tests/dsp.ts` `wordErrorRate`). -- [ ] **Step 3:** `D-WS1b` with the numbers; keep `max_new_tokens: 440` unless the seek path is now +- [x] **Step 3:** `D-WS1b` with the numbers; keep `max_new_tokens: 440` unless the seek path is now both faster and not worse on WER. Commit. ### Task 3: D-014 re-test (WASM graphOptimizationLevel) diff --git a/src/worker/inference.worker.ts b/src/worker/inference.worker.ts index 2d5b4b2..bd3e656 100644 --- a/src/worker/inference.worker.ts +++ b/src/worker/inference.worker.ts @@ -348,9 +348,10 @@ async function transcribe(message: TranscribeMessage): Promise { stride_length_s: STRIDE_LENGTH_S, return_timestamps: true, // With return_timestamps and no explicit max_new_tokens, Transformers.js - // 4.2's Whisper generate() takes a seek-loop path that re-decodes each - // window's tail (1–3 generate passes per window). Under this pipeline's - // own 30 s/5 s chunking that is pure overhead: ~1.4× slower on long + // 4.2–4.3 Whisper generate() takes a seek-loop path (D-021; re-measured + // on 4.3.2, D-WS1b) that re-decodes each window's tail (1–3 generate + // passes per window). Under this pipeline's own 30 s/5 s chunking that + // is pure overhead: ~1.4× slower on long // files, duplicated boundary text, on_finalize firing once per pass // (breaking TranscribeProgressTracker's one-finalize-per-window // assumption — the progress bar saturated early, then looked frozen), diff --git a/tests/transformers-runtime.test.ts b/tests/transformers-runtime.test.ts index 73babd5..b790df7 100644 --- a/tests/transformers-runtime.test.ts +++ b/tests/transformers-runtime.test.ts @@ -47,4 +47,11 @@ describe("@huggingface/transformers runtime", () => { expect(body).toContain("Promise.all("); expect(body).toContain("for (const name of Object.keys(names))"); }); + + test("Whisper generate still takes the seek loop when max_new_tokens is unset (D-021, D-WS1b)", () => { + // The worker's `max_new_tokens: 440` exists only to dodge this branch. + // If upstream changes the condition, re-measure D-021 before touching it. + const source = read(join(PKG_DIR, "src/models/whisper/modeling_whisper.js")); + expect(source).toContain("if (generation_config.return_timestamps && !kwargs.max_new_tokens)"); + }); }); From cc8e031d6b859994b2996d4d59379d9fa1fa33a3 Mon Sep 17 00:00:00 2001 From: Lucas Winther Date: Fri, 30 Oct 2026 00:45:46 +0100 Subject: [PATCH 5/6] Run WASM sessions at the default graph optimization level now that ort-web 1.31 loads the 8-bit decoders Co-Authored-By: Claude Opus 5.5 --- docs/Decisions.md | 43 +++++++++++++++++++++++- docs/WorkBreakdown.md | 2 ++ docs/plans/001-1-transformers-upgrade.md | 4 +-- src/worker/inference.worker.ts | 14 ++++---- tests/offline.md | 5 +++ tests/transformers-runtime.test.ts | 13 +++++++ 6 files changed, 70 insertions(+), 11 deletions(-) diff --git a/docs/Decisions.md b/docs/Decisions.md index eab0ebb..a124be5 100644 --- a/docs/Decisions.md +++ b/docs/Decisions.md @@ -125,7 +125,8 @@ than ONNX Runtime under Bun; the server engine becomes genuinely useful rather t slow convenience. ## D-014 — WASM sessions run at graphOptimizationLevel "basic" -**Status:** Accepted (bug workaround, 2026-07-10) +**Status:** **Superseded by D-WS1c** (bug workaround, 2026-07-10; the ort-web +build in Transformers.js 4.3.2 no longer has the bug, so the cap is gone) On the WASM backend, the inference worker passes `session_options: { graphOptimizationLevel: "basic" }` to the Transformers.js pipeline. The onnxruntime-web build bundled with Transformers.js 4.2 @@ -1319,3 +1320,43 @@ share the CPU), so read it only as "the seek loop is slower", not as a version-to-version speed comparison. **Decision:** keep `max_new_tokens: 440` in `src/worker/inference.worker.ts` and in `tests/live-real-model.test.ts`. + +## D-WS1c — WASM sessions back at the default graph optimization level (D-014's "basic" cap dropped) +**Status:** Accepted (2026-10-30) — supersedes D-014 +**Re-test** of D-014's revisit condition after the Transformers.js 4.3.2 bump +(D-WS1a), which brings onnxruntime-web `1.31.0-dev.20260914-8d85527a0`. +Measured under Bun with onnxruntime-web's own wasm EP (not onnxruntime-node), +1 thread, AMD Ryzen 9 9950X shared with other workstreams. +1. **Session creation**, `onnx-community/whisper-tiny` + `decoder_model_merged_quantized.onnx` (D-014's repro file), every level: + + | onnxruntime-web | disabled | basic | extended | all | + |---|---|---|---|---| + | 1.26.0-dev.20260416 (control) | OK | OK | FAIL | FAIL | + | 1.31.0-dev.20260914 | OK | OK | OK | OK | + + The control still fails with D-014's exact error (`qdq_actions.cc:137 + TransposeDQWeightsForMatMulNBits Missing required scale: + model.decoder.embed_tokens.weight_merged_0_scale`); 1.31 loads at all four. +2. **Transcription**, Transformers.js 4.3.2 pipeline on that ort-web build, + `whisper-tiny.en` q8 (catalog WASM default), `en_aiproblem` (14.4 s), + worker options (30 s chunks, 5 s stride, timestamps, `max_new_tokens: + 440`). Both pipelines in one process, 1 warm-up each, then 8 interleaved + runs (A/B order alternating) so machine-load drift hits both equally: + + | level | warm runs (s) | median | WER | text | + |---|---|---|---|---| + | `basic` (D-014) | 1.49 1.44 1.36 1.39 1.41 1.47 1.48 1.60 | 1.47 s | 0.000 | identical | + | default (`all`) | 1.38 1.47 1.34 1.39 1.37 1.42 1.43 1.43 | 1.42 s | 0.000 | identical | + + Same transcript byte-for-byte at both levels and across every run; the + default level is ~3 % faster here (within noise; certainly not slower). +**Decision:** `src/worker/inference.worker.ts` no longer passes +`session_options` — WASM and WebGPU both use onnxruntime's default level. +`tests/transformers-runtime.test.ts` pins the onnxruntime-web version this +was measured on and that the worker sets no `graphOptimizationLevel`; a +different ort-web build fails the fast suite until this session-creation +check is re-run. +**Not covered here:** a real browser's ort-web wasm build (the same +`ort-wasm-simd-threaded.*` files, but multithreaded under COOP/COEP) — +`tests/offline.md` §2's WASM step is the owner's browser check. diff --git a/docs/WorkBreakdown.md b/docs/WorkBreakdown.md index d69541b..cb1963f 100644 --- a/docs/WorkBreakdown.md +++ b/docs/WorkBreakdown.md @@ -342,6 +342,8 @@ cached. ## M8 — Transcription quality and speed (spec 001) - [x] Transformers.js 4.2.0 → 4.3.2, sequential-session patch regenerated for 4.3.2 and guarded by `tests/transformers-runtime.test.ts` (D-WS1a). +- [x] WASM sessions back at the default graph optimization level: ort-web + 1.31.0-dev loads the q8 decoders at every level (D-WS1c supersedes D-014). --- diff --git a/docs/plans/001-1-transformers-upgrade.md b/docs/plans/001-1-transformers-upgrade.md index 0c623bf..998bbf9 100644 --- a/docs/plans/001-1-transformers-upgrade.md +++ b/docs/plans/001-1-transformers-upgrade.md @@ -98,12 +98,12 @@ onnxruntime-node 1.30.0), bun:test. **Files:** `docs/Decisions.md`; `src/worker/inference.worker.ts` only if the outcome is "drop". -- [ ] **Step 1: Measure** (`/tmp/ws1/d014.ts`): `globalThis[Symbol.for("onnxruntime")] = +- [x] **Step 1: Measure** (`/tmp/ws1/d014.ts`): `globalThis[Symbol.for("onnxruntime")] = await import("onnxruntime-web")` before importing transformers, wasm EP, 1 thread; for `onnx-community/whisper-tiny` `decoder_model_merged_quantized.onnx` create a session at `disabled/basic/extended/all`; record success/error. If all load: transcribe `en_aiproblem` with tiny.en q8 at `basic` vs default (`all`), 3 warm runs each, wall-clock + text identity. -- [ ] **Step 2:** If default fails → keep, `D-WS1c` "still needed on ort-web 1.31.0-dev". If it +- [x] **Step 2:** If default fails → keep, `D-WS1c` "still needed on ort-web 1.31.0-dev". If it loads and is not slower → remove the override (worker comment cites D-WS1c), run a q8 transcribe again through the harness with the worker's new options. Commit. diff --git a/src/worker/inference.worker.ts b/src/worker/inference.worker.ts index bd3e656..79c2492 100644 --- a/src/worker/inference.worker.ts +++ b/src/worker/inference.worker.ts @@ -260,14 +260,12 @@ async function createPipeline( const pipelineOptions: PretrainedModelOptions & { sequentialSessionLoad?: boolean } = { device, dtype, - // WASM sessions cap graph optimization at "basic" (D-014): the level-2 - // QDQ transform in the bundled onnxruntime-web build rejects the 8-bit - // decoders' tied embed_tokens weight ("Missing required scale … - // DequantizeLinear"). q4 models use native MatMulNBits ops, so the - // lower level costs them nothing. WebGPU keeps the default level. - ...(device === "wasm" && { - session_options: { graphOptimizationLevel: "basic" as const }, - }), + // No session_options: every backend runs at onnxruntime's default + // graph optimization level. D-014's WASM "basic" cap worked around a + // level-2 QDQ bug in ort-web 1.26.0-dev that rejected the 8-bit + // decoders; the 1.31.0-dev build bundled with Transformers.js 4.3.2 + // loads them at every level (D-WS1c, pinned in + // tests/transformers-runtime.test.ts). progress_callback: forwardProgress, // D-027/D-029: sequential sub-model session loading trades load speed // for a lower peak-memory footprint — only worth it where the UI diff --git a/tests/offline.md b/tests/offline.md index c1f0912..1206587 100644 --- a/tests/offline.md +++ b/tests/offline.md @@ -69,6 +69,11 @@ The worker now caps WASM sessions at `graphOptimizationLevel: "basic"` outside the browser. **Re-run this step with Backend = WASM to confirm in a real browser.** +**Update (2026-10-30, D-WS1c):** the Transformers.js 4.3.2 bump brings an +onnxruntime-web build without that bug, so the cap is gone and WASM sessions +run at the default level again. Re-run this step with Backend = WASM (Whisper +Tiny and Tiny.en) to confirm the session still loads in a real browser. + ## 3. Go offline and transcribe 1. DevTools → Network → throttling **Offline** (or OS airplane mode — stronger, diff --git a/tests/transformers-runtime.test.ts b/tests/transformers-runtime.test.ts index b790df7..06fac6c 100644 --- a/tests/transformers-runtime.test.ts +++ b/tests/transformers-runtime.test.ts @@ -54,4 +54,17 @@ describe("@huggingface/transformers runtime", () => { const source = read(join(PKG_DIR, "src/models/whisper/modeling_whisper.js")); expect(source).toContain("if (generation_config.return_timestamps && !kwargs.max_new_tokens)"); }); + + test("onnxruntime-web is the build D-WS1c re-tested 8-bit decoders on at the default optimization level", () => { + // D-014's "basic" cap was dropped because this build loads the q8 merged + // decoders at every graphOptimizationLevel. A different build needs the + // D-WS1c session-creation check re-run before it ships. + const ortWeb = JSON.parse(read(join(ROOT, "node_modules/onnxruntime-web/package.json"))).version; + expect(ortWeb).toBe("1.31.0-dev.20260914-8d85527a0"); + }); + + test("worker leaves WASM sessions at the default graph optimization level (D-WS1c)", () => { + const worker = read(join(ROOT, "src/worker/inference.worker.ts")); + expect(worker).not.toContain("graphOptimizationLevel"); + }); }); From 7b65f1f727c5d5cd43f4df2e6dae10c38b020a49 Mon Sep 17 00:00:00 2001 From: Lucas Winther Date: Fri, 30 Oct 2026 01:04:18 +0100 Subject: [PATCH 6/6] Remove the finished Transformers.js 4.3.2 upgrade plan Co-Authored-By: Claude Opus 5.5 --- docs/plans/001-1-transformers-upgrade.md | 122 ----------------------- 1 file changed, 122 deletions(-) delete mode 100644 docs/plans/001-1-transformers-upgrade.md diff --git a/docs/plans/001-1-transformers-upgrade.md b/docs/plans/001-1-transformers-upgrade.md deleted file mode 100644 index 998bbf9..0000000 --- a/docs/plans/001-1-transformers-upgrade.md +++ /dev/null @@ -1,122 +0,0 @@ ---- -status: in-progress ---- - -# 001-1 — Transformers.js 4.2.0 → 4.3.2 Implementation Plan - -> **For agentic workers:** REQUIRED SUB-SKILL: superpowers:executing-plans (inline, no nested -> subagents — coordination plan rule). Steps use checkbox (`- [ ]`) syntax for tracking. - -**Goal:** run the browser engine on `@huggingface/transformers` 4.3.2 with the D-027/D-028 -sequential-session patch carried over, and re-test the decisions the upgrade may obsolete. - -**Architecture:** dependency bump + `bun patch` regeneration; a small runtime-guard test file pins -the installed version, the patch, and the upstream seek-loop condition D-021 depends on, so a future -bump that silently drops the patch or changes the condition fails the fast suite. Re-tests run as -scratch measurement scripts outside the repo (`/tmp/ws1/`); their numbers go into `D-WS1*` entries. - -**Tech Stack:** Bun 1.3, `@huggingface/transformers` 4.3.2 (onnxruntime-web 1.31.0-dev.20260914, -onnxruntime-node 1.30.0), bun:test. - -**Spec:** `docs/specs/001-transcription-quality-and-speed.md` (Goal 1); coordination rules in -`docs/plans/001-0-coordination.md`. - -## Global Constraints - -- Bun only; no new runtime dependency; transformers stays a devDependency (D-031). -- New decisions are `## D-WS1 — …` appended at the bottom of `docs/Decisions.md`; Accepted - entries are superseded, never rewritten. -- Heavy commands (real-model runs, benchmarks, model downloads, full `bun test`) under - `flock /tmp/whisper-heavy.lock`. Ports 3110–3119. No push, no publishing. -- Measurements are CPU numbers (onnxruntime-node, or onnxruntime-web wasm EP under Bun); say which. -- No WebGPU-only default change ships on WASM numbers; WebGPU items → "needs owner's browser check". - -## Review Focus - -1. **Patch silently lost on reinstall** (lockfile/`patchedDependencies` key mismatch) → the app - loads fine but mobile OOM returns. Pinned by Task 1's patch-applied test. -2. **onnxruntime-web file names changed** (new version may ship different `.mjs/.wasm` names) → - `/ort/` serving and `dist/ort` copy must still contain what ort-web requests. Task 1: build and - check `dist/ort/` contains `ort-wasm-simd-threaded.jsep.{mjs,wasm}` (the WebGPU bundle's files). -3. **Upstream changes the seek-loop condition** → D-021's `max_new_tokens` could become wrong or - unneeded without notice. Pinned by Task 2's source-tripwire test. -4. **onnxruntime-node 1.30 drifts real-model WER** → `tests/live-real-model.test.ts` under the lock - (Task 5). -5. **q8 decoders on WASM at default optimization level** (D-014's failure) — Task 3 measures every - level before any change to the worker's session options. - ---- - -### Task 1: Upgrade to 4.3.2 and carry the patch - -**Files:** -- Create: `tests/transformers-runtime.test.ts` -- Modify: `package.json`, `bun.lock`, `AGENTS.md` (patch path), `docs/WorkBreakdown.md` -- Create: `patches/@huggingface%2Ftransformers@4.3.2.patch`; Delete: the 4.2.0 patch - -**Interfaces:** -- Produces: `tests/transformers-runtime.test.ts` (Task 2 adds a case to it). - -- [x] **Step 1: Write the failing test** `describe("@huggingface/transformers runtime")`: - - `"installed version is the pinned 4.3.2"` — `node_modules/@huggingface/transformers/package.json` - `.version === "4.3.2"`. - - `"patchedDependencies points at an existing patch for the installed version"` — root - `package.json` `patchedDependencies["@huggingface/transformers@4.3.2"]` is a path that exists. - - `"web bundle's constructSessions carries the sequential-load patch (D-027/D-028)"` — the - `constructSessions` function text sliced from `dist/transformers.web.js` contains - `options?.sequentialSessionLoad` and both `Promise.all(` and `for (const name of Object.keys(names))`. -- [x] **Step 2: Run** `bun test tests/transformers-runtime.test.ts` → FAIL on version (4.2.0) and key. -- [x] **Step 3:** `bun add -d @huggingface/transformers@4.3.2` (remove the 4.2.0 - `patchedDependencies` entry first if bun refuses), `bun patch @huggingface/transformers`, re-apply - the 4.2.0 hunk to `constructSessions` in `dist/transformers.web.js` (upstream is unchanged: - still a bare `Promise.all`), `bun patch --commit node_modules/@huggingface/transformers`. - `git rm` the 4.2.0 patch. Re-link the shared `.cache` symlink if the reinstall removed it. -- [x] **Step 4: Run** the test → PASS; `bun install --frozen-lockfile` clean; typecheck; fast - suite; `bun run build`; `ls dist/ort` shows the files ort-web 1.31 requests. -- [x] **Step 5:** docs: AGENTS.md patch filename; `D-WS1a` (upgrade, patch carried, why upstream - doesn't obsolete it, ort versions, Parakeet = CTC only); WorkBreakdown tick. Commit - "Upgrade @huggingface/transformers to 4.3.2 and carry the sequential-session patch". - -### Task 2: D-021 re-test (seek loop) - -**Files:** Modify `tests/transformers-runtime.test.ts`, `docs/Decisions.md`, -`src/worker/inference.worker.ts` (comment only: "4.2" → "4.2–4.3", cite D-WS1b). - -- [x] **Step 1: Test** `"Whisper generate still takes the seek loop when max_new_tokens is unset (D-021)"` - — `src/models/whisper/modeling_whisper.js` contains - `if (generation_config.return_timestamps && !kwargs.max_new_tokens)`. Run → PASS expected - (tripwire; it encodes the revisit condition, verified against the 4.3.2 source). -- [x] **Step 2: Measure** (`/tmp/ws1/d021.ts`, onnxruntime-node, under the lock): tiny.en q8 on - `en_alien.opus` (ffmpeg-static → 16 kHz f32), pipeline options as the worker - (`chunk_length_s 30, stride_length_s 5, return_timestamps true`), with and without - `max_new_tokens: 440`; record wall-clock, generate-pass count (wrap `model.generate`), window - count, WER vs `en_alien.txt` (`tests/dsp.ts` `wordErrorRate`). -- [x] **Step 3:** `D-WS1b` with the numbers; keep `max_new_tokens: 440` unless the seek path is now - both faster and not worse on WER. Commit. - -### Task 3: D-014 re-test (WASM graphOptimizationLevel) - -**Files:** `docs/Decisions.md`; `src/worker/inference.worker.ts` only if the outcome is "drop". - -- [x] **Step 1: Measure** (`/tmp/ws1/d014.ts`): `globalThis[Symbol.for("onnxruntime")] = - await import("onnxruntime-web")` before importing transformers, wasm EP, 1 thread; for - `onnx-community/whisper-tiny` `decoder_model_merged_quantized.onnx` create a session at - `disabled/basic/extended/all`; record success/error. If all load: transcribe `en_aiproblem` with - tiny.en q8 at `basic` vs default (`all`), 3 warm runs each, wall-clock + text identity. -- [x] **Step 2:** If default fails → keep, `D-WS1c` "still needed on ort-web 1.31.0-dev". If it - loads and is not slower → remove the override (worker comment cites D-WS1c), run a q8 transcribe - again through the harness with the worker's new options. Commit. - -### Task 4: WebGPU-affecting changes (D-022, D-025/D-026) — inspection only - -- [x] **Step 1:** Read 4.3.0/4.3.1/4.3.2 release notes and diff 4.2.0↔4.3.2 `src/` for - WebGPU/fp16/Firefox/Safari changes; check ort-web 1.31 dist for Gecko/fp16 handling. -- [x] **Step 2:** `D-WS1d` listing each item as "needs owner's browser check" with what to try - (explicit WebGPU on Firefox for D-026; medium fp16 for D-022; Safari 26 WebGPU). No code change. - Commit. - -### Task 5: Verify and finish - -- [ ] typecheck, fast suite, build green; `flock /tmp/whisper-heavy.lock bun test - tests/live-real-model.test.ts` green; record WER per clip in D-WS1a if changed from the bars. -- [ ] `git status` clean; last commit `git rm docs/plans/001-1-transformers-upgrade.md`.