@pie-project/server-web 0.5.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,91 @@
1
+ # @pie-project/server-web
2
+
3
+ The browser half of `@pie-project/server`: the same runtime, WebGPU engine
4
+ and inferlet sandbox as `pie serve`, compiled to `wasm32-unknown-unknown`.
5
+ No server-side inference: the page fetches a `.wgpu.zt` artifact, the
6
+ weights land in WebGPU buffers, and inferlets run under wasmtime's Pulley
7
+ interpreter inside the same module. A bundler reaches it through
8
+ `@pie-project/server`'s `browser` export condition; nothing imports it by
9
+ name.
10
+
11
+ ## Use
12
+
13
+ The package ships the wasm and a self-contained bundle (`dist/pie.mjs`,
14
+ `dist/worker.mjs`, `dist/pie_browser_bg.wasm`); the client
15
+ (`@pie-project/client`) is bundled in and re-exported. The worker and the
16
+ wasm are fetched relative to the module, so serve them from your own origin
17
+ (a bundler that understands `new URL(…, import.meta.url)` — Vite, webpack 5 —
18
+ does this by itself; without one, copy `dist/` next to your page).
19
+
20
+ ```js
21
+ import { Server } from "@pie-project/server"; // resolves here under a bundler
22
+ import "@pie-project/language-python";
23
+
24
+ const server = await Server.start({ model: "/models/qwen3.5-0.8b.wgpu.zt" }); // served with Range support
25
+ const program = await server.install(inferletBytes, manifestToml);
26
+ const client = await server.connect(); // a PieClient, as for `pie serve`
27
+ const proc = await client.launchProcess(program, { prompt: "The capital of France is", max_tokens: 16 });
28
+ for (;;) {
29
+ const { event, value } = await proc.recv();
30
+ if (event === "return" || event === "error") break;
31
+ }
32
+ await server.shutdown();
33
+ ```
34
+
35
+ The page-level functions behind the class (`load`, `bootLazy`, `install`,
36
+ `installLanguage`, `connect`, `awaitCache`, `memoryBytes`) are exported as
37
+ well; `tests/browser` drives them directly.
38
+
39
+
40
+ - The page must be cross-origin isolated (`Cross-Origin-Opener-Policy:
41
+ same-origin`, `Cross-Origin-Embedder-Policy: require-corp`), and the
42
+ browser needs WebGPU and JSPI: Chrome 137+, Firefox 153+ (Firefox on
43
+ Linux has no WebGPU, so the engine cannot boot there).
44
+ - `bootLazy` never holds the artifact in the tab: the loader's reads are
45
+ served as 8 MiB-aligned `Range` requests, and after a boot from the
46
+ network the artifact is copied into the origin's private file system
47
+ (files up to about 2 GB) so the next visit reads it from there;
48
+ `awaitCache()` waits for that copy. Peak wasm memory is a few times the
49
+ largest tensor: 0.8B boots in 285 MiB, 9B in 4 bits in 1.5 GiB.
50
+ - The engine cannot ask WebGPU how much device memory there is and assumes
51
+ 8 GiB; a large model with the default pools is refused ("raise the device
52
+ weight budget") — pass `device_memory_mb = 20480` (or a smaller
53
+ `max_total_pages`) in the boot config. `BootConfig` in
54
+ `crates/browser/src/boot.rs` lists the keys.
55
+ - Rust, JavaScript and Python inferlets run. Not available in a tab: MoE
56
+ host-tier expert streaming, Python inferlet snapshots, telemetry, and
57
+ outbound HTTP or files from inferlets (the WASI interfaces link, a call
58
+ fails).
59
+ - `index.d.ts` carries the types.
60
+
61
+ ## Build
62
+
63
+ ```bash
64
+ rustup target add wasm32-unknown-unknown
65
+ cargo install wasm-bindgen-cli --version 0.2.128 --locked # must match Cargo.lock
66
+ ./javascript/server-web/build.sh # release; `min` for the 23 MB shipping build, `dev` for debug
67
+ ```
68
+
69
+ `build.sh` builds `crates/browser`, runs wasm-bindgen into `pkg/`, and bundles
70
+ `src/` with esbuild into `dist/` (`npm run bundle`). The package's own
71
+ dependencies are installed on the first run. Tests, benchmarks and CI gates
72
+ live under `tests/browser` (see its README).
73
+
74
+ ## How it fits together
75
+
76
+ | piece | what it does |
77
+ |---|---|
78
+ | `crates/browser` | The wasm-bindgen host: boot, install, sessions speaking the MessagePack frames `pie serve`'s WebSocket carries, `pie_tick`. |
79
+ | `crates/wasmtime-web` | wasmtime in a tab: heap-backed "virtual memory", TLS slots, fibers implemented by the page's JSPI glue (`src/platform.mjs`), and the WASI host for the inferlet's imports (cli, io, clocks, random; 0.2 linked by hand, the 0.3 clocks from `crates/inferlet/wit`). The 0.2 filesystem and http interfaces a JavaScript or Python guest runtime imports regardless are stubbed per component, so they link and only a call fails. |
80
+ | `crates/web-std` | The executor the page ticks, timers over `performance.now()`, crossbeam-shaped channels, and green threads on fibers. The runtime's scheduler and engine lanes run on those unchanged; `crates/runtime`'s `rt` facade names it on wasm32. |
81
+ | `crates/engine-wgpu` | The same engine on both hosts, written for the browser: no GPU wait blocks, every step lands by callback, guests run from the landing. What differs by host sits in `device/host.rs`. |
82
+ | `src/worker.mjs` | The host: wasm init, the tick loop, sessions, the artifact served by byte range. Runs in a Web Worker so the page stays responsive through the inferlet's in-browser compile and every forward pass; `load({ worker: false })` runs it on the page for debugging. |
83
+ | `src/pie.mjs` | The page-side API: the `Server` class over `load`, `bootLazy`, `install`, `connect`. |
84
+ | `src/languages.mjs` | The language registry `@pie-project/server/languages` re-exports: what a language package calls on import. |
85
+ | `src/platform.mjs` | Fibers (JSPI), the clock, the wake hook the wasm imports. |
86
+ | `src/transport.mjs` | The client's in-page socket over the runtime's frame API. |
87
+
88
+ The native wgpu server is the engine's test host rather than a production
89
+ backend: it runs the browser's code path over Vulkan, Metal or DX12 with a
90
+ poll thread standing in for the page's event loop, so what the browser suite
91
+ exercises is exercised natively too, and the two produce identical tokens.