@flaxia/node 0.5.0 → 0.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/dist/assets/ai-inference.js +241 -85
  2. package/dist/assets/webgpuProbe.js +357 -0
  3. package/dist/client/SignalingClient.d.ts.map +1 -1
  4. package/dist/client/__tests__/mobile-lifecycle.test.d.ts +2 -0
  5. package/dist/client/__tests__/mobile-lifecycle.test.d.ts.map +1 -0
  6. package/dist/client/mobile-lifecycle.d.ts +20 -0
  7. package/dist/client/mobile-lifecycle.d.ts.map +1 -0
  8. package/dist/executor/WorkerPool.d.ts +7 -1
  9. package/dist/executor/WorkerPool.d.ts.map +1 -1
  10. package/dist/executor/__tests__/resourceReporter.test.d.ts +2 -0
  11. package/dist/executor/__tests__/resourceReporter.test.d.ts.map +1 -0
  12. package/dist/executor/memoryProbe.d.ts +5 -0
  13. package/dist/executor/memoryProbe.d.ts.map +1 -1
  14. package/dist/executor/resourceReporter.d.ts +15 -0
  15. package/dist/executor/resourceReporter.d.ts.map +1 -0
  16. package/dist/executor/webgpuProbe.d.ts +16 -5
  17. package/dist/executor/webgpuProbe.d.ts.map +1 -1
  18. package/dist/index.js +943 -291
  19. package/dist/swarm/__tests__/peer-quality.test.d.ts +2 -0
  20. package/dist/swarm/__tests__/peer-quality.test.d.ts.map +1 -0
  21. package/dist/swarm/__tests__/peer-transport.test.d.ts +2 -0
  22. package/dist/swarm/__tests__/peer-transport.test.d.ts.map +1 -0
  23. package/dist/swarm/adapter.d.ts +1 -1
  24. package/dist/swarm/adapter.d.ts.map +1 -1
  25. package/dist/swarm/controller.d.ts +4 -0
  26. package/dist/swarm/controller.d.ts.map +1 -1
  27. package/dist/swarm/messages.d.ts +2 -2
  28. package/dist/swarm/messages.d.ts.map +1 -1
  29. package/dist/swarm/peer-quality.d.ts +14 -0
  30. package/dist/swarm/peer-quality.d.ts.map +1 -0
  31. package/dist/swarm/peer-transport.d.ts +81 -0
  32. package/dist/swarm/peer-transport.d.ts.map +1 -0
  33. package/dist/swarm/runtime.d.ts +5 -1
  34. package/dist/swarm/runtime.d.ts.map +1 -1
  35. package/dist/swarm-engine.js +39 -20
  36. package/dist/worker.js +331 -208
  37. package/dist/workloads/__tests__/model-pipeline-cache.test.d.ts +2 -0
  38. package/dist/workloads/__tests__/model-pipeline-cache.test.d.ts.map +1 -0
  39. package/dist/workloads/ai-inference.d.ts +6 -0
  40. package/dist/workloads/ai-inference.d.ts.map +1 -1
  41. package/dist/workloads/model-pipeline-cache.d.ts +48 -0
  42. package/dist/workloads/model-pipeline-cache.d.ts.map +1 -0
  43. package/package.json +1 -1
  44. package/dist/assets/dist.js +0 -209
package/dist/worker.js CHANGED
@@ -1,13 +1,13 @@
1
- import { _ as e, a as t, b as n, c as r, g as i, h as a, i as o, l as s, n as c, o as l, s as u, t as d, v as f, x as p, y as m } from "./assets/dist.js";
1
+ import { M as e, N as t, O as n, a as r, c as i, f as a, h as o, j as s, k as c, l, m as u, o as d, r as f, t as p, u as m, v as h, x as g, y as _ } from "./assets/webgpuProbe.js";
2
2
  //#region src/executor/throttle.ts
3
- function h(e) {
3
+ function v(e) {
4
4
  return new Promise((t) => setTimeout(t, e));
5
5
  }
6
- var g = 3e4, ee = 500, _ = class extends Error {
6
+ var y = 3e4, ee = 500, b = class extends Error {
7
7
  constructor(e, t, n) {
8
8
  super(`device is over its CPU budget (load ${e.toFixed(2)} > max ${t.toFixed(2)}) after waiting ${Math.round(n)}ms; task not started`), this.load = e, this.maxLoad = t, this.waitedMs = n, this.retryable = !0, this.name = "ThrottleBusyError";
9
9
  }
10
- }, v = class {
10
+ }, te = class {
11
11
  constructor(e = .15) {
12
12
  this.windowStart = performance.now(), this.windowBusyMs = 0, this.lastLoad = 0, this.dutyStartedAt = null, this.maxLoad = Math.max(.05, Math.min(.3, e));
13
13
  }
@@ -34,13 +34,13 @@ var g = 3e4, ee = 500, _ = class extends Error {
34
34
  async shouldPause() {
35
35
  return this.rollWindow(performance.now()), this.estimate(this.windowBusyMs) > this.maxLoad;
36
36
  }
37
- async waitForSlot(e = g) {
37
+ async waitForSlot(e = y) {
38
38
  if (!Number.isFinite(e) || e < 0) throw Error(`waitForSlot: maxWaitMs must be a non-negative number, got ${String(e)}`);
39
39
  let t = performance.now();
40
40
  for (; await this.shouldPause();) {
41
41
  let n = performance.now() - t;
42
- if (n >= e) throw new _(this.lastLoad, this.maxLoad, n);
43
- await h(Math.min(ee, Math.max(1, e - n)));
42
+ if (n >= e) throw new b(this.lastLoad, this.maxLoad, n);
43
+ await v(Math.min(ee, Math.max(1, e - n)));
44
44
  }
45
45
  }
46
46
  async yieldIfOverloaded() {
@@ -49,7 +49,7 @@ var g = 3e4, ee = 500, _ = class extends Error {
49
49
  let t = Math.max(0, e - this.dutyStartedAt);
50
50
  if (t < 200) return 0;
51
51
  let n = Math.ceil(t * (1 / this.maxLoad - 1));
52
- return this.dutyStartedAt = null, n > 0 && await h(n), this.estimate(this.windowBusyMs), n;
52
+ return this.dutyStartedAt = null, n > 0 && await v(n), this.estimate(this.windowBusyMs), n;
53
53
  }
54
54
  get lastMeasuredLoad() {
55
55
  return this.lastLoad;
@@ -57,13 +57,13 @@ var g = 3e4, ee = 500, _ = class extends Error {
57
57
  get maxLoadValue() {
58
58
  return this.maxLoad;
59
59
  }
60
- }, y = 4096;
61
- function b(e) {
60
+ }, x = 4096;
61
+ function ne(e) {
62
62
  let t = e.maxSeq;
63
- return typeof t == "number" && Number.isInteger(t) && t > 0 ? t : y;
63
+ return typeof t == "number" && Number.isInteger(t) && t > 0 ? t : x;
64
64
  }
65
- function x(e, t, n) {
66
- let { pos: r, tokens: i } = e.header, a = b(t);
65
+ function S(e, t, n) {
66
+ let { pos: r, tokens: i } = e.header, a = ne(t);
67
67
  if (!Number.isInteger(i) || i < 1) return {
68
68
  kind: "corrupt",
69
69
  reason: `carried ${i} token columns`
@@ -95,78 +95,78 @@ function x(e, t, n) {
95
95
  hidden: o
96
96
  };
97
97
  }
98
- function te(e, t, n, r) {
99
- let i = s(e);
100
- return i ? i.header.pos !== t || i.header.requestId !== t ? { kind: "stale" } : x(i, n, r) : {
98
+ function re(e, t, n, r) {
99
+ let i = _(e);
100
+ return i ? i.header.pos !== t || i.header.requestId !== t ? { kind: "stale" } : S(i, n, r) : {
101
101
  kind: "corrupt",
102
102
  reason: "malformed frame header"
103
103
  };
104
104
  }
105
- async function ne(t) {
106
- let { engine: n, link: i, semantics: o, promptTokens: s, chainLength: c, maxNewTokens: l } = t;
107
- if (s.length === 0) throw Error("swarm host requires at least one prompt token");
108
- n.reset();
109
- let u = null;
110
- i.onFrame((t) => {
111
- if (e(t)) return;
112
- let r = u;
113
- if (!r) return;
114
- let i = te(t, r.pos, n, o);
105
+ async function ie(n) {
106
+ let { engine: r, link: i, semantics: a, promptTokens: o, chainLength: s, maxNewTokens: c } = n;
107
+ if (o.length === 0) throw Error("swarm host requires at least one prompt token");
108
+ r.reset();
109
+ let l = null;
110
+ i.onFrame((e) => {
111
+ if (t(e)) return;
112
+ let n = l;
113
+ if (!n) return;
114
+ let i = re(e, n.pos, r, a);
115
115
  if (i.kind !== "stale") {
116
- if (u = null, i.kind === "corrupt") {
117
- r.reject(/* @__PURE__ */ Error(`swarm hop failed: ${i.reason}`));
116
+ if (l = null, i.kind === "corrupt") {
117
+ n.reject(/* @__PURE__ */ Error(`swarm hop failed: ${i.reason}`));
118
118
  return;
119
119
  }
120
- r.resolve(i.hidden);
120
+ n.resolve(i.hidden);
121
121
  }
122
122
  });
123
- let d = (e, t) => c <= 1 ? Promise.resolve(e) : new Promise((n, a) => {
124
- u = {
123
+ let u = (e, t) => s <= 1 ? Promise.resolve(e) : new Promise((n, r) => {
124
+ l = {
125
125
  pos: t,
126
126
  resolve: n,
127
- reject: a
128
- }, i.send(r({
127
+ reject: r
128
+ }, i.send(h({
129
129
  requestId: t,
130
130
  pos: t,
131
131
  tokens: 1
132
- }, o.packHidden(e)));
133
- }), f = async (e, t) => d(await n.embedRun(e, t), t), p = null;
134
- for (let e = 0; e < s.length; e++) {
135
- let t = await f(s[e], e);
136
- e === s.length - 1 && (p = await n.headFromHidden(t));
137
- }
138
- if (!p) throw Error("swarm host produced no logits for the prompt");
139
- let m = [], h = s.length, g = o.argmax(p);
140
- for (; m.length < l && !(t.eosIds?.has(g) || (m.push(g), await t.onToken?.(g), m.length >= l));) {
141
- let e = await f(g, h++);
142
- p = await n.headFromHidden(e), g = o.argmax(p);
143
- }
144
- return c > 1 && i.send(a()), { tokens: m };
145
- }
146
- function re(t) {
147
- let { engine: n, link: i, semantics: a } = t;
148
- return n.reset(), new Promise((t, o) => {
149
- let c = Promise.resolve(), l = !1;
150
- i.onFrame((u) => {
151
- if (!l) {
152
- if (e(u)) {
153
- l = !0, i.send(u), c = c.then(() => t());
132
+ }, a.packHidden(e)));
133
+ }), d = async (e, t) => u(await r.embedRun(e, t), t), f = null;
134
+ for (let e = 0; e < o.length; e++) {
135
+ let t = await d(o[e], e);
136
+ e === o.length - 1 && (f = await r.headFromHidden(t));
137
+ }
138
+ if (!f) throw Error("swarm host produced no logits for the prompt");
139
+ let p = [], m = o.length, g = a.argmax(f);
140
+ for (; p.length < c && !(n.eosIds?.has(g) || (p.push(g), await n.onToken?.(g), p.length >= c));) {
141
+ let e = await d(g, m++);
142
+ f = await r.headFromHidden(e), g = a.argmax(f);
143
+ }
144
+ return s > 1 && i.send(e()), { tokens: p };
145
+ }
146
+ function ae(e) {
147
+ let { engine: n, link: r, semantics: i } = e;
148
+ return n.reset(), new Promise((e, a) => {
149
+ let o = Promise.resolve(), s = !1;
150
+ r.onFrame((c) => {
151
+ if (!s) {
152
+ if (t(c)) {
153
+ s = !0, r.send(c), o = o.then(() => e());
154
154
  return;
155
155
  }
156
- c = c.then(async () => {
157
- if (l) return;
158
- let e = s(u);
156
+ o = o.then(async () => {
157
+ if (s) return;
158
+ let e = _(c);
159
159
  if (!e) throw Error("swarm frame has a malformed frame header");
160
- let t = x(e, n, a);
160
+ let t = S(e, n, i);
161
161
  if (t.kind === "corrupt") throw Error(`swarm frame is unusable: ${t.reason}`);
162
- let o = await n.runHidden(t.hidden, e.header.pos);
163
- i.send(r({
162
+ let a = await n.runHidden(t.hidden, e.header.pos);
163
+ r.send(h({
164
164
  requestId: e.header.requestId,
165
165
  pos: e.header.pos,
166
166
  tokens: e.header.tokens
167
- }, a.packHidden(o)));
167
+ }, i.packHidden(a)));
168
168
  }).catch((e) => {
169
- l = !0, o(e instanceof Error ? e : Error(String(e)));
169
+ s = !0, a(e instanceof Error ? e : Error(String(e)));
170
170
  });
171
171
  }
172
172
  });
@@ -174,9 +174,9 @@ function re(t) {
174
174
  }
175
175
  //#endregion
176
176
  //#region src/swarm/controller.ts
177
- var S = class {
177
+ var oe = class {
178
178
  constructor(e) {
179
- this.options = e, this.frameHandler = null, this.engine = null, this.semantics = null, this.sessionId = "", this.model = "", this.chainLength = 1, this.chain = [], this.slice = null, this.hostWarm = void 0, this.prompt = "", this.maxNewTokens = 128, this.sliceLoaded = !1, this.generationStarted = !1, this.settled = !1;
179
+ this.options = e, this.frameHandler = null, this.engine = null, this.semantics = null, this.sessionId = "", this.model = "", this.chainLength = 1, this.chain = [], this.slice = null, this.hostWarm = void 0, this.prompt = "", this.maxNewTokens = 128, this.sliceLoaded = !1, this.generationStarted = !1, this.settled = !1, this.flowPaused = !1, this.flowWaiters = /* @__PURE__ */ new Set();
180
180
  }
181
181
  async start() {
182
182
  if (this.settled) return;
@@ -200,7 +200,7 @@ var S = class {
200
200
  }
201
201
  async handleControl(e) {
202
202
  if (!this.settled && e.sessionId === this.sessionId) try {
203
- e.type === "swarm-slice" ? await this.loadSlice(e) : e.type === "swarm-start" ? await this.startHost() : e.type === "swarm-error" && this.fail(Error(e.error || "swarm session aborted by the coordinator"));
203
+ e.type === "swarm-slice" ? await this.loadSlice(e) : e.type === "swarm-start" ? await this.startHost() : e.type === "swarm-error" ? this.fail(Error(e.error || "swarm session aborted by the coordinator")) : e.type === "swarm-flow" && (this.flowPaused = e.paused, this.flowPaused || this.releaseFlowWaiters());
204
204
  } catch (e) {
205
205
  this.fail(e);
206
206
  }
@@ -223,7 +223,7 @@ var S = class {
223
223
  if (!Number.isInteger(e.chainLength) || e.chainLength < 1 || e.chainLength > 16) throw Error(`swarm slice has an invalid chain length: ${JSON.stringify(e.chainLength)}`);
224
224
  if (!Number.isInteger(e.index) || e.index < 0 || e.index >= e.chainLength) throw Error(`swarm slice has an invalid index: ${JSON.stringify(e.index)}`);
225
225
  if (e.role !== (e.index === 0 ? "host" : "worker")) throw Error(`swarm slice role ${e.role} does not match index ${e.index}`);
226
- if (!l(e.slice)) throw Error(`swarm slice is out of bounds: ${JSON.stringify(e.slice)}`);
226
+ if (!u(e.slice)) throw Error(`swarm slice is out of bounds: ${JSON.stringify(e.slice)}`);
227
227
  let t = e.index === 0;
228
228
  if (e.slice.hasEmbed !== t || e.slice.hasHead !== t) throw Error("swarm slice embed/head ownership does not match the host position");
229
229
  }
@@ -238,11 +238,11 @@ var S = class {
238
238
  this.engine = t, this.semantics = n, this.hostWarm = r, this.sliceLoaded = !0, this.options.sendControl({
239
239
  type: "swarm-ready",
240
240
  sessionId: e.sessionId
241
- }), e.role === "worker" && (this.generationStarted = !0, re({
241
+ }), e.role === "worker" && (this.generationStarted = !0, ae({
242
242
  engine: t,
243
243
  link: this.link(),
244
244
  semantics: n
245
- }).then(() => this.finish(C())).catch((e) => this.fail(e)));
245
+ }).then(() => this.finish(se())).catch((e) => this.fail(e)));
246
246
  }
247
247
  async startHost() {
248
248
  if (this.generationStarted) return;
@@ -254,7 +254,7 @@ var S = class {
254
254
  let r = t.encodePrompt(this.prompt), i = e.maxSeq ?? 4096;
255
255
  if (r.length + n > i) throw Error(`swarm request needs ${r.length + n} tokens but the model context holds ${i}`);
256
256
  this.generationStarted = !0;
257
- let a = performance.now(), { tokens: o } = await ne({
257
+ let a = performance.now(), { tokens: o } = await ie({
258
258
  chainLength: this.chainLength,
259
259
  promptTokens: r,
260
260
  maxNewTokens: n,
@@ -262,7 +262,10 @@ var S = class {
262
262
  link: this.link(),
263
263
  semantics: t,
264
264
  eosIds: t.eosIds,
265
- onToken: (e) => this.options.emitToken(t.decodeTokens([e]))
265
+ onToken: async (e) => {
266
+ if (await this.waitForFlow(), this.settled) throw Error("swarm session stopped while generation was paused");
267
+ await this.options.emitToken(t.decodeTokens([e]));
268
+ }
266
269
  }), s = t.decodeTokens;
267
270
  this.finish({
268
271
  output: s(o),
@@ -294,13 +297,20 @@ var S = class {
294
297
  } catch {}
295
298
  }
296
299
  finish(e) {
297
- this.settled || (this.settled = !0, this.teardown(), this.options.onDone(e));
300
+ this.settled || (this.settled = !0, this.releaseFlowWaiters(), this.teardown(), this.options.onDone(e));
298
301
  }
299
302
  fail(e) {
300
- this.settled || (this.settled = !0, this.teardown(), this.options.onError(e instanceof Error ? e.message : String(e)));
303
+ this.settled || (this.settled = !0, this.releaseFlowWaiters(), this.teardown(), this.options.onError(e instanceof Error ? e.message : String(e)));
304
+ }
305
+ waitForFlow() {
306
+ return !this.flowPaused || this.settled ? Promise.resolve() : new Promise((e) => this.flowWaiters.add(e));
307
+ }
308
+ releaseFlowWaiters() {
309
+ for (let e of this.flowWaiters) e();
310
+ this.flowWaiters.clear();
301
311
  }
302
312
  };
303
- function C() {
313
+ function se() {
304
314
  return {
305
315
  output: "",
306
316
  tokens: [],
@@ -310,13 +320,13 @@ function C() {
310
320
  }
311
321
  //#endregion
312
322
  //#region src/swarm/adapter.ts
313
- var w = class extends Error {
323
+ var C = class extends Error {
314
324
  constructor(e) {
315
325
  super(e), this.name = "SwarmEngineUnavailableError";
316
326
  }
317
327
  };
318
- async function T(e, t) {
319
- if (!(await f()).webgpu) throw new w("WebGPU is not available in this context");
328
+ async function w(e, t) {
329
+ if (!(await p()).webgpu) throw new C("WebGPU is not available in this context");
320
330
  let n = t ?? ((e) => import(
321
331
  /* @vite-ignore */
322
332
  e
@@ -324,14 +334,18 @@ async function T(e, t) {
324
334
  try {
325
335
  r = await n(e);
326
336
  } catch (e) {
327
- throw new w(`failed to load swarm engine module: ${e instanceof Error ? e.message : String(e)}`);
337
+ throw new C(`failed to load swarm engine module: ${e instanceof Error ? e.message : String(e)}`);
328
338
  }
329
339
  let i = r?.Qwen35Engine;
330
- if (!i || typeof i.create != "function") throw new w(`module at ${e} does not export Qwen35Engine.create`);
340
+ if (!i || typeof i.create != "function") throw new C(`module at ${e} does not export Qwen35Engine.create`);
331
341
  return r;
332
342
  }
333
- function E(e, t) {
334
- let n = !1;
343
+ function ce(e, t, n, r) {
344
+ let i = !1, a = async (e) => {
345
+ r?.();
346
+ let t = await e();
347
+ return r?.(), t;
348
+ };
335
349
  return {
336
350
  get dim() {
337
351
  return e.dims.dim;
@@ -342,61 +356,102 @@ function E(e, t) {
342
356
  get maxSeq() {
343
357
  return e.maxSeq;
344
358
  },
345
- reset: () => e.reset(),
346
- embedRun: (t, n) => e.embedRun(t, n),
347
- runHidden: (t, n) => e.runHidden(t, n),
348
- headFromHidden: (t) => e.headFromHidden(t),
349
- setHidden: (t) => e.setHidden(t),
359
+ reset: () => {
360
+ r?.(), e.reset();
361
+ },
362
+ embedRun: (t, n) => a(() => e.embedRun(t, n)),
363
+ runHidden: (t, n) => a(() => e.runHidden(t, n)),
364
+ headFromHidden: (t) => a(() => e.headFromHidden(t)),
365
+ setHidden: (t) => {
366
+ r?.(), e.setHidden(t);
367
+ },
350
368
  dispose: () => {
351
- if (!n) {
352
- n = !0;
369
+ if (!i) {
370
+ i = !0;
353
371
  try {
354
372
  e.dispose?.();
355
373
  } catch {}
356
374
  try {
357
375
  t?.destroy?.();
358
376
  } catch {}
377
+ try {
378
+ n?.();
379
+ } catch {}
359
380
  }
360
381
  }
361
382
  };
362
383
  }
363
384
  //#endregion
364
385
  //#region src/swarm/runtime.ts
365
- var D = {
386
+ var T = {
366
387
  "qwen3.5-2b": "https://huggingface.co/unsloth/Qwen3.5-2B-GGUF/resolve/main/Qwen3.5-2B-Q4_0.gguf",
367
388
  "qwen3.8-27b": "https://huggingface.co/unsloth/Qwen3.8-27B-GGUF/resolve/main/Qwen3.8-27B-Q4_0.gguf",
368
389
  "qwen3.6-35b-moe": "https://huggingface.co/bartowski/Qwen_Qwen3.6-35B-A3B-GGUF/resolve/main/Qwen_Qwen3.6-35B-A3B-Q4_0.gguf"
369
- }, ie = "flaxia-swarm-weights-v1", ae = 12 * 1024 * 1024, O = 256 * 1024 * 1024;
370
- function oe(e) {
371
- let t = D[e];
390
+ }, le = "flaxia-swarm-weights-v1", ue = 12 * 1024 * 1024, E = 256 * 1024 * 1024, D = /* @__PURE__ */ new Map();
391
+ function O(e, t) {
392
+ D.set(e, {
393
+ status: t,
394
+ failedExpiresAt: t.state === "failed" ? Date.now() + 3e4 : void 0
395
+ });
396
+ }
397
+ function k(e, t, n, r) {
398
+ let i = j(e);
399
+ return {
400
+ modelId: e,
401
+ revision: /\/resolve\/([^/]+)\//.exec(new URL(i).pathname)?.[1] ?? "unknown",
402
+ dtype: /-(q\d+_\d+)\.gguf/i.exec(i)?.[1] ?? "unknown",
403
+ backend: "webgpu",
404
+ layerRange: [t.start, t.end],
405
+ state: n,
406
+ referenceCount: r
407
+ };
408
+ }
409
+ function A(e = Date.now()) {
410
+ let t = [];
411
+ for (let [n, r] of D) {
412
+ if (r.failedExpiresAt !== void 0 && r.failedExpiresAt <= e) {
413
+ D.delete(n);
414
+ continue;
415
+ }
416
+ t.push(r.status);
417
+ }
418
+ return {
419
+ version: 1,
420
+ sampledAt: e,
421
+ expiresAt: e + s,
422
+ entries: t.slice(0, 8)
423
+ };
424
+ }
425
+ function j(e) {
426
+ let t = Object.prototype.hasOwnProperty.call(T, e) ? T[e] : void 0;
372
427
  if (t) return t;
373
- throw new w(`unknown swarm model: ${e}`);
428
+ throw new C(`unknown swarm model: ${e}`);
374
429
  }
375
- var k = null, A = 0, j = 0;
376
- async function M() {
377
- if (k !== null) return k;
430
+ var M = null, N = 0, P = 0;
431
+ async function de() {
432
+ if (M !== null) return M;
378
433
  try {
379
- k = typeof caches < "u" ? await caches.open(ie) : !1;
434
+ M = typeof caches < "u" ? await caches.open(le) : !1;
380
435
  } catch {
381
- k = !1;
436
+ M = !1;
382
437
  }
383
- return k;
438
+ return M;
384
439
  }
385
- function N(e, t, n) {
440
+ function fe(e, t, n) {
386
441
  return `https://flaxia-weights.local/${encodeURIComponent(e)}/${t}-${n}`;
387
442
  }
388
- async function P(e, t, n) {
389
- let r = await F(e, t, n), i = new Uint8Array(await r.arrayBuffer()), a = n - t + 1;
443
+ async function F(e, t, n) {
444
+ let r = await I(e, t, n), i = new Uint8Array(await r.arrayBuffer()), a = n - t + 1;
390
445
  if (i.byteLength !== a) throw Error(`short range ${i.byteLength}/${a}`);
391
446
  return i;
392
447
  }
393
- async function F(e, t, n) {
394
- let r = n - t + 1, i = await M(), a = N(e, t, n);
448
+ async function I(e, t, n) {
449
+ let r = n - t + 1, i = await de(), a = fe(e, t, n);
395
450
  if (i) try {
396
451
  let e = await i.match(a);
397
452
  if (e) {
398
453
  let t = new Uint8Array(await e.arrayBuffer());
399
- if (t.byteLength === r) return A++, new Response(t, { status: 200 });
454
+ if (t.byteLength === r) return N++, new Response(t, { status: 200 });
400
455
  await i.delete(a).catch(() => {});
401
456
  }
402
457
  } catch {}
@@ -405,7 +460,7 @@ async function F(e, t, n) {
405
460
  try {
406
461
  let s = await fetch(e, { headers: { Range: `bytes=${t}-${n}` } });
407
462
  if (s.status !== 206) o = /* @__PURE__ */ Error(`model host refused range requests (${s.status})`);
408
- else return j++, i && s.clone().arrayBuffer().then((e) => {
463
+ else return P++, i && s.clone().arrayBuffer().then((e) => {
409
464
  if (e.byteLength === r) return i.put(a, new Response(e, {
410
465
  status: 200,
411
466
  headers: { "content-type": "application/octet-stream" }
@@ -418,29 +473,29 @@ async function F(e, t, n) {
418
473
  }
419
474
  throw Error(`range fetch ${t}-${n} failed: ${o instanceof Error ? o.message : String(o)}`);
420
475
  }
421
- async function I(e, t) {
422
- let n = ae;
476
+ async function pe(e, t) {
477
+ let n = ue;
423
478
  for (;;) {
424
- let r = await P(t, 0, n - 1), i = r.buffer.slice(r.byteOffset, r.byteOffset + r.byteLength);
479
+ let r = await F(t, 0, n - 1), i = r.buffer.slice(r.byteOffset, r.byteOffset + r.byteLength);
425
480
  try {
426
481
  return e.parseGGUFHeader(i);
427
482
  } catch (e) {
428
- if (n >= O) throw e;
429
- n = Math.min(n * 2, O);
483
+ if (n >= E) throw e;
484
+ n = Math.min(n * 2, E);
430
485
  }
431
486
  }
432
487
  }
433
- async function L() {
488
+ async function me() {
434
489
  let e = navigator.gpu;
435
- if (!e) throw new w("WebGPU is not available in this context");
490
+ if (!e) throw new C("WebGPU is not available in this context");
436
491
  let t = await e.requestAdapter({ powerPreference: "high-performance" });
437
- if (!t) throw new w("no WebGPU adapter");
492
+ if (!t) throw new C("no WebGPU adapter");
438
493
  return t.requestDevice({ requiredLimits: {
439
494
  maxBufferSize: t.limits.maxBufferSize,
440
495
  maxStorageBufferBindingSize: t.limits.maxStorageBufferBindingSize
441
496
  } });
442
497
  }
443
- function R(e, t) {
498
+ function he(e, t) {
444
499
  let n = t.vocab, r = n["<|im_start|>"], i = n["<|im_end|>"], a = n["<think>"], o = n["</think>"], s = (e) => [
445
500
  r,
446
501
  ...t.encode("user\n" + e),
@@ -470,32 +525,32 @@ function R(e, t) {
470
525
  eosIds: new Set(c)
471
526
  };
472
527
  }
473
- function z() {
474
- let e = null, t = null, n = () => {
475
- if (!e) {
476
- let t = new URL("./swarm-engine.js", "" + import.meta.url).href;
477
- e = T(t).then((e) => e);
528
+ function L(e) {
529
+ let t = null, n = null, r = () => {
530
+ if (!t) {
531
+ let n = new URL("./swarm-engine.js", "" + import.meta.url).href;
532
+ t = e ? e() : w(n).then((e) => e);
478
533
  }
479
- return e;
480
- }, r = async (e) => {
481
- let r = await n(), i = oe(e);
482
- (!t || t.url !== i) && (t = {
534
+ return t;
535
+ }, i = async (e) => {
536
+ let t = await r(), i = j(e);
537
+ (!n || n.url !== i) && (n = {
483
538
  url: i,
484
- gguf: await I(r, i)
539
+ gguf: await pe(t, i)
485
540
  });
486
- let a = Number(t.gguf.meta["qwen35.block_count"]) - Number(t.gguf.meta["qwen35.nextn_predict_layers"] || 0);
487
- if (!Number.isInteger(a) || a < 1) throw new w(`model ${e} has no qwen35 trunk layers`);
541
+ let a = Number(n.gguf.meta["qwen35.block_count"]) - Number(n.gguf.meta["qwen35.nextn_predict_layers"] || 0);
542
+ if (!Number.isInteger(a) || a < 1) throw new C(`model ${e} has no qwen35 trunk layers`);
488
543
  return {
489
- mod: r,
544
+ mod: t,
490
545
  url: i,
491
- gguf: t.gguf,
546
+ gguf: n.gguf,
492
547
  layers: a
493
548
  };
494
549
  };
495
550
  return {
496
551
  async plan(e, t) {
497
- let { layers: n } = await r(t);
498
- return d({
552
+ let { layers: n } = await i(t);
553
+ return g({
499
554
  sessionId: "",
500
555
  taskId: "",
501
556
  model: t,
@@ -507,60 +562,103 @@ function z() {
507
562
  }).chain;
508
563
  },
509
564
  async load(e, t) {
510
- A = 0, j = 0;
511
- let { mod: n, url: i, gguf: a } = await r(t), o = await L(), s = n.makeTokenizer(n.tokenizerFromGGUF(a.meta)), c = (e) => P(i, e.byteOffset, e.byteOffset + e.byteLength - 1);
512
- a.streamEntry = (e) => n.streamEntryToGPU(o, e, (e) => F(i, e.byteOffset, e.byteOffset + e.byteLength - 1), { staging: 4 * 1024 * 1024 });
513
- let l = await n.qwen35Weights(a, c, {
514
- lo: e.start,
515
- hi: e.end,
516
- hasEmbed: e.hasEmbed,
517
- hasHead: e.hasHead,
518
- mtp: e.hasHead
519
- }, void 0, (e, t) => n.gpuUploadEntry(o, e, t === n.GGML_EMBED)), u = a.tensors[n.GGML_EMBED]?.shape[0] ?? 0, d = await n.Qwen35Engine.create({
520
- device: o,
521
- meta: a.meta,
522
- layerRange: [e.start, e.end],
523
- hasEmbed: e.hasEmbed,
524
- hasHead: e.hasHead,
525
- vocab: u,
526
- maxSeq: Math.min(y, Number(a.meta["qwen35.context_length"]) || 4096),
527
- batchCols: 4,
528
- weights: l
529
- }), f = A > 0 && j === 0;
530
- return {
531
- engine: E(d, o),
532
- semantics: R(n, s),
533
- warm: f
534
- };
565
+ N = 0, P = 0;
566
+ let n = JSON.stringify([
567
+ t,
568
+ e.start,
569
+ e.end
570
+ ]);
571
+ O(n, k(t, e, "loading", 1));
572
+ let r, a = !1;
573
+ try {
574
+ let { mod: o, url: s, gguf: c } = await i(t);
575
+ r = await me();
576
+ let l = null, u = r;
577
+ u.addEventListener?.("uncapturederror", () => {
578
+ l = "swarm GPU validation failed";
579
+ }), u.lost?.then(() => {
580
+ l = "swarm GPU device lost";
581
+ });
582
+ let d = () => {
583
+ if (l) throw new C(l);
584
+ }, f = he(o, o.makeTokenizer(o.tokenizerFromGGUF(c.meta))), p = (e) => F(s, e.byteOffset, e.byteOffset + e.byteLength - 1);
585
+ c.streamEntry = (e) => o.streamEntryToGPU(r, e, (e) => I(s, e.byteOffset, e.byteOffset + e.byteLength - 1), { staging: 4 * 1024 * 1024 });
586
+ let m = await o.qwen35Weights(c, p, {
587
+ lo: e.start,
588
+ hi: e.end,
589
+ hasEmbed: e.hasEmbed,
590
+ hasHead: e.hasHead,
591
+ mtp: e.hasHead
592
+ }, void 0, (e, t) => o.gpuUploadEntry(r, e, t === o.GGML_EMBED)), h = c.tensors[o.GGML_EMBED]?.shape[0] ?? 0, g = await o.Qwen35Engine.create({
593
+ device: r,
594
+ meta: c.meta,
595
+ layerRange: [e.start, e.end],
596
+ hasEmbed: e.hasEmbed,
597
+ hasHead: e.hasHead,
598
+ vocab: h,
599
+ maxSeq: Math.min(x, Number(c.meta["qwen35.context_length"]) || 4096),
600
+ batchCols: 4,
601
+ weights: m
602
+ });
603
+ d();
604
+ let _ = ce(g, r, () => {
605
+ O(n, k(t, e, "evicting", 0)), queueMicrotask(() => D.delete(n));
606
+ }, d);
607
+ return a = !0, O(n, k(t, e, "ready", 1)), {
608
+ engine: _,
609
+ semantics: f,
610
+ warm: N > 0 && P === 0
611
+ };
612
+ } catch (i) {
613
+ if (O(n, k(t, e, "failed", 0)), !a) try {
614
+ r?.destroy?.();
615
+ } catch {}
616
+ throw i;
617
+ }
535
618
  }
536
619
  };
537
620
  }
538
621
  //#endregion
539
622
  //#region src/swarm/messages.ts
540
- function B(e) {
541
- return o(e) || c(e) || i(e) || t(e);
623
+ function ge(e) {
624
+ return a(e) || m(e) || o(e) || c(e) || i(e) || n(e);
542
625
  }
543
- function V(e) {
626
+ function _e(e) {
544
627
  if (!e || typeof e != "object") return !1;
545
628
  let t = e;
546
- return t.type === "swarm-control" && typeof t.id == "string" && B(t.message);
629
+ return t.type === "swarm-control" && typeof t.id == "string" && ge(t.message);
547
630
  }
548
631
  //#endregion
549
632
  //#region src/worker/main.worker.ts
550
- var H = null, U = g, W = 1, G = 15e3, K = /* @__PURE__ */ new Map(), q = null, J = null, Y = null, se = 6e4;
551
- async function ce() {
633
+ var R = null, ve = y, ye = 1, z = 15e3, B = /* @__PURE__ */ new Map(), V = /* @__PURE__ */ new Set(), H = /* @__PURE__ */ new Map();
634
+ function U(e) {
635
+ V.delete(e);
636
+ let t = H.get(e);
637
+ if (t) {
638
+ H.delete(e);
639
+ for (let e of t) e();
640
+ }
641
+ }
642
+ function be(e) {
643
+ return V.has(e) ? new Promise((t) => {
644
+ let n = H.get(e) ?? /* @__PURE__ */ new Set();
645
+ n.add(t), H.set(e, n);
646
+ }) : Promise.resolve();
647
+ }
648
+ var W = null, G = null, K = null, xe = 6e4;
649
+ async function Se() {
552
650
  for (let e = 0;; e++) try {
553
- await H.waitForSlot(U);
651
+ await R.waitForSlot(ve);
554
652
  return;
555
653
  } catch (t) {
556
- if (!(t instanceof _)) throw t;
557
- if (e >= W) throw Error(`device CPU busy: ${t.message}; task not started, retry on an idle node (retryable)`);
558
- console.warn(`[flaxia-node:worker] ${t.message}; cooling down ${G}ms before retrying`), await new Promise((e) => setTimeout(e, G));
654
+ if (!(t instanceof b)) throw t;
655
+ if (e >= ye) throw Error(`device CPU busy: ${t.message}; task not started, retry on an idle node (retryable)`);
656
+ console.warn(`[flaxia-node:worker] ${t.message}; cooling down ${z}ms before retrying`), await new Promise((e) => setTimeout(e, z));
559
657
  }
560
658
  }
561
- function le(e) {
659
+ function Ce(e) {
562
660
  let t = (t) => {
563
- let n = K.get(e);
661
+ let n = B.get(e);
564
662
  if (n !== void 0) throw Error(n);
565
663
  self.postMessage({
566
664
  id: e,
@@ -568,54 +666,71 @@ function le(e) {
568
666
  token: t
569
667
  });
570
668
  };
571
- return async (e) => {
572
- t(e), await H?.yieldIfOverloaded();
669
+ return async (n) => {
670
+ await be(e), t(n), await R?.yieldIfOverloaded();
573
671
  };
574
672
  }
575
- var X = p(), Z = X >= m;
576
- console.log(`[flaxia-node:worker] startup memory probe wasmMemoryBytes=${X} capable=${Z}`);
577
- function ue() {
578
- return n();
673
+ var q = d(), J = q >= f;
674
+ console.log(`[flaxia-node:worker] startup memory probe wasmMemoryBytes=${q} capable=${J}`);
675
+ function Y() {
676
+ return r();
579
677
  }
580
- var Q = /* @__PURE__ */ new Map(), $ = null;
581
- function de() {
582
- for (let e of Q.values()) try {
678
+ var X = /* @__PURE__ */ new Map(), Z = /* @__PURE__ */ new Map();
679
+ Z.set("swarm-inference", A);
680
+ var Q = null;
681
+ function we() {
682
+ for (let e of X.values()) try {
583
683
  e();
584
684
  } catch {}
585
- Q.clear();
685
+ X.clear(), Z.clear(), Z.set("swarm-inference", A);
586
686
  }
587
- function fe() {
588
- $ && clearTimeout($), $ = setTimeout(() => {
589
- $ = null, de();
590
- }, se);
687
+ function $() {
688
+ let e = Date.now(), t = [...Z.values()].flatMap((e) => {
689
+ try {
690
+ return e().entries;
691
+ } catch {
692
+ return [];
693
+ }
694
+ }).slice(0, 8);
695
+ return {
696
+ version: 1,
697
+ sampledAt: e,
698
+ expiresAt: e + 6e4,
699
+ entries: t
700
+ };
701
+ }
702
+ function Te() {
703
+ Q && clearTimeout(Q), Q = setTimeout(() => {
704
+ Q = null, we();
705
+ }, xe);
591
706
  }
592
- async function pe(e, t, n, r) {
707
+ async function Ee(e, t, n, r) {
593
708
  switch (e) {
594
709
  case "ai-inference":
595
710
  let i = await import("./assets/ai-inference.js");
596
- return Q.set(e, i.releaseCache), await i.handleAiInference(t, n);
711
+ return X.set(e, i.releaseCache), Z.set(e, i.getModelCacheSnapshot), await i.handleAiInference(t, n);
597
712
  case "image-process": return await (await import("./assets/image-process.js")).handleImageProcess(t);
598
713
  case "container": return await (await import("./assets/container.js")).handleContainer(t, r?.fileSourceOrigins ?? [], r?.containerImageOrigins ?? []);
599
714
  case "vector-embed":
600
715
  let a = await import("./assets/vector-embed.js");
601
- return Q.set(e, a.releaseCache), await a.handleVectorEmbed(t);
716
+ return X.set(e, a.releaseCache), await a.handleVectorEmbed(t);
602
717
  case "vector-store":
603
718
  let o = await import("./assets/vector-store.js");
604
- return Q.set(e, o.releaseCache), await o.handleVectorStore(t);
719
+ return X.set(e, o.releaseCache), await o.handleVectorStore(t);
605
720
  case "vector-query":
606
721
  let s = await import("./assets/vector-query.js");
607
- return Q.set(e, s.releaseCache), await s.handleVectorQuery(t);
722
+ return X.set(e, s.releaseCache), await s.handleVectorQuery(t);
608
723
  case "nudenet":
609
724
  let c = await import("./assets/nudenet.js");
610
- return Q.set(e, c.releaseCache), await c.handleNudeNet(t);
725
+ return X.set(e, c.releaseCache), await c.handleNudeNet(t);
611
726
  default: throw Error(`Unknown workload type: ${e}`);
612
727
  }
613
728
  }
614
- function me(e, t, n) {
729
+ function De(e, t, n) {
615
730
  return new Promise((r, i) => {
616
- let a = new S({
731
+ let a = new oe({
617
732
  initial: t,
618
- runtime: z(),
733
+ runtime: L(),
619
734
  sendControl: (t) => self.postMessage({
620
735
  id: e,
621
736
  type: "swarm-message",
@@ -628,66 +743,74 @@ function me(e, t, n) {
628
743
  }, [t]),
629
744
  emitToken: n,
630
745
  onDone: (e) => {
631
- q === a && (q = null, J = null), r(e);
746
+ W === a && (W = null, G = null), r(e);
632
747
  },
633
748
  onError: (e) => {
634
- q === a && (q = null, J = null), i(Error(e));
749
+ W === a && (W = null, G = null), i(Error(e));
635
750
  }
636
751
  });
637
- q = a, J = e, a.start();
752
+ W = a, G = e, a.start();
638
753
  });
639
754
  }
640
755
  self.onmessage = async (e) => {
641
756
  let t = e.data;
757
+ if (t?.type === "token-flow") {
758
+ let e = typeof t.id == "string" ? t.id : "";
759
+ e && K === e && typeof t.paused == "boolean" && (t.paused ? V.add(e) : U(e));
760
+ return;
761
+ }
642
762
  if (t?.type === "swarm-control") {
643
- if (!V(t)) {
763
+ if (!_e(t)) {
644
764
  console.warn("[flaxia-node:worker] dropped malformed swarm-control message");
645
765
  return;
646
766
  }
647
- q && q.handleControl(t.message);
767
+ W && W.handleControl(t.message);
648
768
  return;
649
769
  }
650
770
  if (t?.type === "swarm-frame") {
651
- t.frame instanceof ArrayBuffer ? q?.handleFrame(t.frame) : console.warn("[flaxia-node:worker] dropped malformed swarm-frame message");
771
+ t.frame instanceof ArrayBuffer ? W?.handleFrame(t.frame) : console.warn("[flaxia-node:worker] dropped malformed swarm-frame message");
652
772
  return;
653
773
  }
654
774
  if (t?.type === "abort") {
655
775
  let e = t.id, n = typeof t.reason == "string" && t.reason ? t.reason : "aborted by the coordinator";
656
- q && J === e ? q.abort(n) : Y === e && K.set(e, n);
776
+ U(e), W && G === e ? W.abort(n) : K === e && B.set(e, n);
657
777
  return;
658
778
  }
659
779
  let { id: n, workload: r, payload: i, config: a } = t, o = performance.now();
660
- Y = n;
780
+ K = n, U(n);
661
781
  try {
662
- if (H ||= new v(a?.maxCpuLoad), console.log(`[flaxia-node:worker] task start id=${n} workload=${r}`), !Z) throw Error(`node incapable: insufficient WASM memory (${X} bytes < ${m}); rejecting all tasks`);
663
- if (u.has(r) && !ue()) throw Error(`${r}: insufficient WASM memory (${X} bytes < ${m})`);
664
- await ce(), H.beginWork();
782
+ if (R ||= new te(a?.maxCpuLoad), console.log(`[flaxia-node:worker] task start id=${n} workload=${r}`), !J) throw Error(`node incapable: insufficient WASM memory (${q} bytes < ${f}); rejecting all tasks`);
783
+ if (l.has(r) && !Y()) throw Error(`${r}: insufficient WASM memory (${q} bytes < ${f})`);
784
+ await Se(), R.beginWork();
665
785
  let e = setInterval(() => {
666
786
  self.postMessage({
667
787
  id: n,
668
788
  type: "heartbeat",
669
- cpuLoad: H?.lastMeasuredLoad ?? 0
789
+ cpuLoad: R?.lastMeasuredLoad ?? 0,
790
+ modelCache: $()
670
791
  });
671
792
  }, 1e4), t = performance.now();
672
793
  try {
673
- let e = le(n), t = Array.isArray(a?.fileSourceOrigins) ? a.fileSourceOrigins.filter((e) => typeof e == "string") : [], s = Array.isArray(a?.containerImageOrigins) ? a.containerImageOrigins.filter((e) => typeof e == "string") : [], c = r === "swarm-inference" ? await me(n, i, e) : await pe(r, i, e, {
794
+ let e = Ce(n), t = Array.isArray(a?.fileSourceOrigins) ? a.fileSourceOrigins.filter((e) => typeof e == "string") : [], s = Array.isArray(a?.containerImageOrigins) ? a.containerImageOrigins.filter((e) => typeof e == "string") : [], c = r === "swarm-inference" ? await De(n, i, e) : await Ee(r, i, e, {
674
795
  fileSourceOrigins: t,
675
796
  containerImageOrigins: s
676
797
  });
677
798
  self.postMessage({
678
799
  id: n,
679
800
  type: "done",
680
- result: c
801
+ result: c,
802
+ modelCache: $()
681
803
  }), console.log(`[flaxia-node:worker] task done id=${n} workload=${r} durationMs=${Math.round(performance.now() - o)}`);
682
804
  } finally {
683
- Y = null, K.delete(n), clearInterval(e), H.markTaskComplete(performance.now() - t), fe();
805
+ K = null, B.delete(n), U(n), clearInterval(e), R.markTaskComplete(performance.now() - t), Te();
684
806
  }
685
807
  } catch (e) {
686
808
  let t = e instanceof Error ? e.message : String(e);
687
- console.error(`[flaxia-node:worker] task error id=${n} workload=${r} error=${t}`), Y === n && (Y = null), self.postMessage({
809
+ console.error(`[flaxia-node:worker] task error id=${n} workload=${r} error=${t}`), K === n && (K = null), U(n), self.postMessage({
688
810
  id: n,
689
811
  type: "error",
690
- error: t
812
+ error: t,
813
+ modelCache: $()
691
814
  });
692
815
  }
693
816
  };