mlx-bun 0.0.7 → 0.0.9
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 +112 -20
- package/docs/design/batching-v2-plan.md +515 -0
- package/docs/design/bucketing-stage.md +196 -0
- package/docs/design/compat-cli-surface-design.md +11 -11
- package/docs/design/diffusion-gemma-port.md +602 -0
- package/docs/design/docs-reorg-plan.md +1 -1
- package/docs/design/dreaming-nightly-pipeline.md +291 -0
- package/docs/design/dspark-speculative-decoding.md +106 -0
- package/docs/design/generic-model-support.md +381 -0
- package/docs/design/memory-inference-path.md +422 -0
- package/docs/design/memory-synthesis.md +287 -0
- package/docs/design/minicpm5-decode-megakernel.md +484 -0
- package/docs/design/mlx-lm-tool-parity-plan.md +535 -0
- package/docs/design/orpo-dynamic-lambda.md +41 -0
- package/docs/design/orpo-training.md +35 -5
- package/docs/design/parallel-slots.md +12 -1
- package/docs/design/parity-tier-dag.md +13 -5
- package/docs/design/spec-decode-larger-targets.md +229 -0
- package/docs/design/tauri-desktop-app.md +2 -2
- package/docs/design/the-dreaming-handoff.md +141 -0
- package/docs/design/the-dreaming-master-plan.md +446 -0
- package/docs/design/write-pipeline-entity.md +468 -0
- package/docs/investigations/curve-bisector-routing.md +1 -1
- package/docs/investigations/decode-roofline-lookagain.md +262 -0
- package/docs/investigations/dspark-handoff.md +58 -0
- package/docs/investigations/kernel-perf-review-2026-07.md +92 -0
- package/docs/planning/PRODUCT_ROADMAP.md +2 -2
- package/docs/planning/curve-sampler-research-plan.md +331 -0
- package/docs/planning/memory-docs-and-dag-plan.md +185 -0
- package/docs/planning/pi-integration-review.md +178 -0
- package/docs/planning/release-notes-v0.0.9.md +122 -0
- package/docs/planning/web-ui-pass-plan.md +213 -0
- package/docs/planning/website-readme-pass-plan.md +224 -0
- package/docs/reference/cli.md +255 -0
- package/docs/reference/embedding.md +7 -2
- package/docs/reference/library-api.md +22 -3
- package/docs/reference/memory.md +5 -5
- package/docs/reference/models.md +137 -0
- package/docs/reference/orpo-quickstart.md +6 -0
- package/docs/reference/server-api.md +187 -9
- package/docs/reference/server-config.md +40 -9
- package/docs/reference/training.md +25 -11
- package/package.json +1 -1
- package/src/anthropic.ts +22 -0
- package/src/assets/curve-designer.html +1 -1
- package/src/chat-template.ts +25 -7
- package/src/cli.ts +1029 -86
- package/src/config.ts +54 -3
- package/src/diffusion/diffusion-generate.ts +436 -0
- package/src/download.ts +99 -8
- package/src/embed.ts +77 -0
- package/src/eval/perplexity.ts +164 -0
- package/src/eval/runner.ts +19 -7
- package/src/eval/tasks/bfcl.ts +1 -1
- package/src/generate.ts +196 -19
- package/src/harness-pi.ts +43 -17
- package/src/index.ts +2 -0
- package/src/lora.ts +2 -2
- package/src/memory/article.ts +558 -0
- package/src/memory/chunk-validation.ts +150 -0
- package/src/memory/chunk.ts +305 -12
- package/src/memory/cluster.ts +344 -17
- package/src/memory/coverage.ts +134 -0
- package/src/memory/crosslink.ts +0 -0
- package/src/memory/db.ts +184 -45
- package/src/memory/entity.ts +203 -0
- package/src/memory/gate.ts +187 -0
- package/src/memory/history.ts +152 -0
- package/src/memory/ingest.ts +324 -11
- package/src/memory/model.ts +321 -0
- package/src/memory/normalize.ts +671 -0
- package/src/memory/parse.ts +22 -0
- package/src/memory/pipeline.ts +242 -30
- package/src/memory/prompts.ts +42 -0
- package/src/memory/query.ts +334 -0
- package/src/memory/reconcile.ts +734 -0
- package/src/memory/redirect.ts +108 -0
- package/src/memory/reindex.ts +325 -0
- package/src/memory/resolve.ts +307 -0
- package/src/memory/route.ts +272 -0
- package/src/memory/schedule.ts +6 -4
- package/src/memory/stages.ts +774 -0
- package/src/memory/synthesize.ts +1629 -20
- package/src/memory/tools.ts +446 -96
- package/src/memory/vault.ts +462 -35
- package/src/memory/wikify.ts +1057 -16
- package/src/mlx/ffi.ts +11 -0
- package/src/mlx/ops.ts +113 -0
- package/src/model/compiled-decode.ts +43 -8
- package/src/model/diffusion-gemma.ts +1026 -0
- package/src/model/factory.ts +35 -8
- package/src/model/flash-attention.ts +4 -2
- package/src/model/fused-decode-kernel.ts +14 -7
- package/src/model/fused-mlp-kernel.ts +169 -0
- package/src/model/fused-swiglu-kernel.ts +240 -0
- package/src/model/gemma4-base.ts +62 -6
- package/src/model/gemma4.ts +33 -2
- package/src/model/minicpm5.ts +106 -8
- package/src/model/qwen3.ts +276 -0
- package/src/model/steel-linear-kernel.ts +96 -0
- package/src/model/support.ts +45 -7
- package/src/model/universal/archs.ts +332 -0
- package/src/model/universal/dense.ts +576 -0
- package/src/model/universal/modules.ts +163 -0
- package/src/model/universal/rope.ts +366 -0
- package/src/pi-provider.ts +1 -1
- package/src/pi-terminal.ts +29 -8
- package/src/pi-web.ts +19 -2
- package/src/quantize/config-writer.ts +1 -1
- package/src/registry.ts +215 -7
- package/src/responses.ts +23 -0
- package/src/sampler.ts +220 -9
- package/src/serve/batch-scheduler.ts +272 -80
- package/src/serve/generation-gateway.ts +90 -18
- package/src/server.ts +643 -50
- package/src/spec/drafter.ts +81 -49
- package/src/spec/dspark/data-dflash.ts +156 -0
- package/src/spec/dspark/data.ts +201 -0
- package/src/spec/dspark/generate-dflash.ts +193 -0
- package/src/spec/dspark/generate.ts +290 -0
- package/src/spec/dspark/loss.ts +213 -0
- package/src/spec/dspark/module-dflash.ts +361 -0
- package/src/spec/dspark/module.ts +540 -0
- package/src/spec/dspark/sample.ts +112 -0
- package/src/spec/generate.ts +40 -19
- package/src/status-page.html +1 -1
- package/src/tokenizer.ts +7 -0
- package/src/train/diffusion-lora.ts +216 -0
- package/src/train/flash-cce.ts +70 -15
- package/src/train/fuse.ts +243 -0
- package/src/train/index.ts +3 -0
- package/src/train/job.ts +8 -0
- package/src/train/loss.ts +289 -30
- package/src/train/prefix-shared.ts +33 -5
- package/src/train/segmented.ts +67 -11
- package/src/train/trainer.ts +92 -28
- package/src/vision/diffusion-vision.ts +620 -0
- package/src/web/skills/memory/SKILL.md +40 -17
package/src/mlx/ffi.ts
CHANGED
|
@@ -119,6 +119,9 @@ export const C = dlopen(LIBMLXC_PATH, {
|
|
|
119
119
|
mlx_divide: { args: [P, u64, u64, u64], returns: i32 },
|
|
120
120
|
mlx_tanh: { args: [P, u64, u64], returns: i32 },
|
|
121
121
|
mlx_sigmoid: { args: [P, u64, u64], returns: i32 },
|
|
122
|
+
mlx_erf: { args: [P, u64, u64], returns: i32 },
|
|
123
|
+
// (res, c, a, b, alpha, beta, stream) — alpha·(a@b) + beta·c (nn.Linear bias path)
|
|
124
|
+
mlx_addmm: { args: [P, u64, u64, u64, f32, f32, u64], returns: i32 },
|
|
122
125
|
mlx_power: { args: [P, u64, u64, u64], returns: i32 },
|
|
123
126
|
mlx_take_axis: { args: [P, u64, u64, i32, u64], returns: i32 },
|
|
124
127
|
mlx_reshape: { args: [P, u64, P, u64, u64], returns: i32 },
|
|
@@ -142,11 +145,17 @@ export const C = dlopen(LIBMLXC_PATH, {
|
|
|
142
145
|
mlx_take_along_axis: { args: [P, u64, u64, i32, u64], returns: i32 },
|
|
143
146
|
mlx_put_along_axis: { args: [P, u64, u64, u64, i32, u64], returns: i32 },
|
|
144
147
|
mlx_cumsum: { args: [P, u64, i32, FFIType.bool, FFIType.bool, u64], returns: i32 },
|
|
148
|
+
mlx_cummax: { args: [P, u64, i32, FFIType.bool, FFIType.bool, u64], returns: i32 },
|
|
145
149
|
mlx_where: { args: [P, u64, u64, u64, u64], returns: i32 },
|
|
146
150
|
mlx_logsumexp_axis: { args: [P, u64, i32, FFIType.bool, u64], returns: i32 },
|
|
147
151
|
mlx_greater_equal: { args: [P, u64, u64, u64], returns: i32 },
|
|
148
152
|
mlx_less: { args: [P, u64, u64, u64], returns: i32 },
|
|
153
|
+
mlx_less_equal: { args: [P, u64, u64, u64], returns: i32 },
|
|
149
154
|
mlx_logical_and: { args: [P, u64, u64, u64], returns: i32 },
|
|
155
|
+
mlx_logical_not: { args: [P, u64, u64], returns: i32 },
|
|
156
|
+
mlx_equal: { args: [P, u64, u64, u64], returns: i32 },
|
|
157
|
+
mlx_all: { args: [P, u64, FFIType.bool, u64], returns: i32 },
|
|
158
|
+
mlx_any_axis: { args: [P, u64, i32, FFIType.bool, u64], returns: i32 },
|
|
150
159
|
mlx_random_key: { args: [P, u64], returns: i32 },
|
|
151
160
|
mlx_random_categorical: { args: [P, u64, i32, u64, u64], returns: i32 },
|
|
152
161
|
mlx_astype: { args: [P, u64, i32, u64], returns: i32 },
|
|
@@ -181,6 +190,8 @@ export const C = dlopen(LIBMLXC_PATH, {
|
|
|
181
190
|
// (res, low, high, shape*, n, dtype, key may-be-null, stream) — low/high are
|
|
182
191
|
// scalar mlx_arrays. Used for mlx-lm-faithful LoRA A init (uniform).
|
|
183
192
|
mlx_random_uniform: { args: [P, u64, u64, P, u64, i32, u64, u64], returns: i32 },
|
|
193
|
+
mlx_random_randint: { args: [P, u64, u64, P, u64, i32, u64, u64], returns: i32 },
|
|
194
|
+
mlx_random_seed: { args: [u64], returns: i32 },
|
|
184
195
|
mlx_random_split_num: { args: [P, u64, i32, u64], returns: i32 },
|
|
185
196
|
// --- training: loss/optimizer elementwise + reductions
|
|
186
197
|
mlx_stop_gradient: { args: [P, u64, u64], returns: i32 },
|
package/src/mlx/ops.ts
CHANGED
|
@@ -111,6 +111,23 @@ export function rope(
|
|
|
111
111
|
);
|
|
112
112
|
}
|
|
113
113
|
|
|
114
|
+
/** fast::rope with every knob exposed (traditional + scale), for the
|
|
115
|
+
* universal rope factory (rope_utils.initialize_rope port). The plain
|
|
116
|
+
* `rope` above stays byte-identical for existing call sites. */
|
|
117
|
+
export function ropeScaled(
|
|
118
|
+
x: MlxArray, dims: number, traditional: boolean, base: number | null,
|
|
119
|
+
scale: number, offset: number, freqs: MlxArray | null, s: S = gpuStream,
|
|
120
|
+
): MlxArray {
|
|
121
|
+
return new MlxArray(
|
|
122
|
+
outArray("fast_rope", (o) =>
|
|
123
|
+
C.mlx_fast_rope(
|
|
124
|
+
o, x.handle, dims, traditional, optFloat(base), scale, offset,
|
|
125
|
+
freqs?.handle ?? 0n, s,
|
|
126
|
+
),
|
|
127
|
+
),
|
|
128
|
+
);
|
|
129
|
+
}
|
|
130
|
+
|
|
114
131
|
/** fast::rope with the position offset as an ARRAY (int32 scalar) instead
|
|
115
132
|
* of a baked int — required inside compiled decode graphs, where the
|
|
116
133
|
* offset changes every step but the graph must not. Same kernel as
|
|
@@ -267,6 +284,35 @@ export function geluApprox(x: MlxArray, s: S = gpuStream): MlxArray {
|
|
|
267
284
|
return out;
|
|
268
285
|
}
|
|
269
286
|
|
|
287
|
+
export function erf(a: MlxArray, s: S = gpuStream): MlxArray {
|
|
288
|
+
return new MlxArray(outArray("erf", (o) => C.mlx_erf(o, a.handle, s)));
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
/** nn.gelu (PRECISE, erf-based): x · (1 + erf(x/√2)) / 2 — composed exactly
|
|
292
|
+
* as mlx's python source (weak scalars promote to x's dtype). Used by the
|
|
293
|
+
* gemma-1 gated MLP and starcoder2's plain MLP; distinct from geluApprox
|
|
294
|
+
* (gelu_pytorch_tanh). */
|
|
295
|
+
export function geluPrecise(x: MlxArray, s: S = gpuStream): MlxArray {
|
|
296
|
+
const sqrt2 = scalarLike(Math.sqrt(2), x);
|
|
297
|
+
const xs = div(x, sqrt2, s); // x / math.sqrt(2) — division, not mul-by-reciprocal
|
|
298
|
+
const e = erf(xs, s);
|
|
299
|
+
const one = scalarLike(1, x);
|
|
300
|
+
const e1 = add(one, e, s);
|
|
301
|
+
const xe = mul(x, e1, s);
|
|
302
|
+
const two = scalarLike(2, x);
|
|
303
|
+
const out = div(xe, two, s); // (...) / 2
|
|
304
|
+
for (const a of [sqrt2, xs, e, one, e1, xe, two]) a.dispose();
|
|
305
|
+
return out;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
/** mx.addmm(c, a, b): a@b + c fused (α=β=1) — nn.Linear's bias path
|
|
309
|
+
* (`mx.addmm(bias, x, weight.T)`). */
|
|
310
|
+
export function addmm(c: MlxArray, a: MlxArray, b: MlxArray, s: S = gpuStream): MlxArray {
|
|
311
|
+
return new MlxArray(
|
|
312
|
+
outArray("addmm", (o) => C.mlx_addmm(o, c.handle, a.handle, b.handle, 1.0, 1.0, s)),
|
|
313
|
+
);
|
|
314
|
+
}
|
|
315
|
+
|
|
270
316
|
export function exp(a: MlxArray, s: S = gpuStream): MlxArray {
|
|
271
317
|
return new MlxArray(outArray("exp", (o) => C.mlx_exp(o, a.handle, s)));
|
|
272
318
|
}
|
|
@@ -315,6 +361,13 @@ export function cumsum(a: MlxArray, axis: number, s: S = gpuStream): MlxArray {
|
|
|
315
361
|
);
|
|
316
362
|
}
|
|
317
363
|
|
|
364
|
+
/** Cumulative maximum along `axis` (inclusive, forward) — mlx.core.cummax. */
|
|
365
|
+
export function cummax(a: MlxArray, axis: number, s: S = gpuStream): MlxArray {
|
|
366
|
+
return new MlxArray(
|
|
367
|
+
outArray("cummax", (o) => C.mlx_cummax(o, a.handle, axis, false, true, s)),
|
|
368
|
+
);
|
|
369
|
+
}
|
|
370
|
+
|
|
318
371
|
export function where(cond: MlxArray, x: MlxArray, y: MlxArray, s: S = gpuStream): MlxArray {
|
|
319
372
|
return new MlxArray(
|
|
320
373
|
outArray("where", (o) => C.mlx_where(o, cond.handle, x.handle, y.handle, s)),
|
|
@@ -370,6 +423,38 @@ export function less(a: MlxArray, b: MlxArray, s: S = gpuStream): MlxArray {
|
|
|
370
423
|
return new MlxArray(outArray("less", (o) => C.mlx_less(o, a.handle, b.handle, s)));
|
|
371
424
|
}
|
|
372
425
|
|
|
426
|
+
export function lessEqual(a: MlxArray, b: MlxArray, s: S = gpuStream): MlxArray {
|
|
427
|
+
return new MlxArray(outArray("less_equal", (o) => C.mlx_less_equal(o, a.handle, b.handle, s)));
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
export function logicalNot(a: MlxArray, s: S = gpuStream): MlxArray {
|
|
431
|
+
return new MlxArray(outArray("logical_not", (o) => C.mlx_logical_not(o, a.handle, s)));
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
export function equal(a: MlxArray, b: MlxArray, s: S = gpuStream): MlxArray {
|
|
435
|
+
return new MlxArray(outArray("equal", (o) => C.mlx_equal(o, a.handle, b.handle, s)));
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
/** Reduce-all to a scalar (mlx.core.all). */
|
|
439
|
+
export function allReduce(a: MlxArray, s: S = gpuStream): MlxArray {
|
|
440
|
+
return new MlxArray(outArray("all", (o) => C.mlx_all(o, a.handle, false, s)));
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
/** any along one axis (mlx.core.any). */
|
|
444
|
+
export function anyAxis(a: MlxArray, axis: number, keepdims: boolean, s: S = gpuStream): MlxArray {
|
|
445
|
+
return new MlxArray(outArray("any_axis", (o) => C.mlx_any_axis(o, a.handle, axis, keepdims, s)));
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
/** Read a 0-d/1-elem boolean array to host (forces eval). */
|
|
449
|
+
export function itemBool(a: MlxArray): boolean {
|
|
450
|
+
const u = a.astype(Dtype.uint32);
|
|
451
|
+
try {
|
|
452
|
+
return itemUint32(u) !== 0;
|
|
453
|
+
} finally {
|
|
454
|
+
u.dispose();
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
|
|
373
458
|
export function logicalAnd(a: MlxArray, b: MlxArray, s: S = gpuStream): MlxArray {
|
|
374
459
|
return new MlxArray(
|
|
375
460
|
outArray("logical_and", (o) => C.mlx_logical_and(o, a.handle, b.handle, s)),
|
|
@@ -443,6 +528,34 @@ export function randomKey(seed: bigint): MlxArray {
|
|
|
443
528
|
return new MlxArray(outArray("random_key", (o) => C.mlx_random_key(o, seed)));
|
|
444
529
|
}
|
|
445
530
|
|
|
531
|
+
/** Set the GLOBAL mlx PRNG seed (mlx.core.random.seed). Calls to randint/etc
|
|
532
|
+
* with a null key thread the global key, so seeding then calling in the same
|
|
533
|
+
* order as the reference reproduces its draws bit-for-bit. */
|
|
534
|
+
export function randomSeed(seed: bigint): void {
|
|
535
|
+
if (C.mlx_random_seed(seed) !== 0) throw new Error(`mlx_random_seed failed: ${takeMlxError() ?? ""}`);
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
/** Uniform integers in [low, high) — mlx.core.random.randint. With key=null it
|
|
539
|
+
* uses (and advances) the global key, matching mx.random.randint exactly. */
|
|
540
|
+
export function randint(
|
|
541
|
+
low: number, high: number, shape: number[], dtype: Dtype,
|
|
542
|
+
key: MlxArray | null = null, s: S = gpuStream,
|
|
543
|
+
): MlxArray {
|
|
544
|
+
const buf = new Int32Array(shape);
|
|
545
|
+
const lo = MlxArray.fromInt32(new Int32Array([low]), []);
|
|
546
|
+
const hi = MlxArray.fromInt32(new Int32Array([high]), []);
|
|
547
|
+
try {
|
|
548
|
+
return new MlxArray(
|
|
549
|
+
outArray("random_randint", (o) =>
|
|
550
|
+
C.mlx_random_randint(o, lo.handle, hi.handle, ptr(buf), BigInt(shape.length), dtype, key?.handle ?? 0n, s),
|
|
551
|
+
),
|
|
552
|
+
);
|
|
553
|
+
} finally {
|
|
554
|
+
lo.dispose();
|
|
555
|
+
hi.dispose();
|
|
556
|
+
}
|
|
557
|
+
}
|
|
558
|
+
|
|
446
559
|
export function randomCategorical(logits: MlxArray, key: MlxArray | null, s: S = gpuStream): MlxArray {
|
|
447
560
|
return new MlxArray(
|
|
448
561
|
outArray("categorical", (o) =>
|
|
@@ -590,6 +590,29 @@ export class CompiledDecode {
|
|
|
590
590
|
const evalWith: MlxArray[] = [];
|
|
591
591
|
let carried = cur; // seg 0 consumes the token array; later, hidden state
|
|
592
592
|
let carriedOwned = false; // cur belongs to the caller
|
|
593
|
+
// Mid-step failure safety (a later segment's closure.apply can throw at
|
|
594
|
+
// first trace AFTER earlier layers already advanced): the step must be
|
|
595
|
+
// TRANSACTIONAL, or the caller's uncompiled re-forward of the same token
|
|
596
|
+
// double-writes the committed layers (+1 offset skew forever, silently
|
|
597
|
+
// corrupted attention). Two mechanisms, chosen by what each phase allows:
|
|
598
|
+
// - ring segments: adoptDecodeStep is a pure host-side handle swap with
|
|
599
|
+
// no reader between here and step end (each cache is read only by its
|
|
600
|
+
// own layer, inside the closure that produced the update), so the
|
|
601
|
+
// adopts are STAGED and committed only once every segment and js layer
|
|
602
|
+
// has succeeded. On failure the staged buffers are disposed and the
|
|
603
|
+
// ring caches are exactly at their pre-step state (prepareDecodeStep's
|
|
604
|
+
// growth/trim/rotate bookkeeping is benign for the uncompiled path —
|
|
605
|
+
// the same invariant #stepWhole and generate.ts's fallback rely on).
|
|
606
|
+
// - js (concat) layers: layer.forward commits via the cache's real
|
|
607
|
+
// updateAndFetch mid-loop, so on failure the commit is ROLLED BACK by
|
|
608
|
+
// reverting offset (and ring index) — trim(1) semantics. The written
|
|
609
|
+
// KV row beyond the reverted offset is dead data the re-forward
|
|
610
|
+
// overwrites at the same position (updateAndFetch writes at offset/
|
|
611
|
+
// ringIdx), so post-recovery state equals a single clean write. This
|
|
612
|
+
// holds for the post-wrap quantized-under-perf-kernel case too: the
|
|
613
|
+
// in-place S=1 write slot is re-derived from the reverted ringIdx.
|
|
614
|
+
const stagedAdopts: { c: AnyCache; bufs: MlxArray[] }[] = [];
|
|
615
|
+
const committedJs: { c: AnyCache; offsetBefore: number }[] = [];
|
|
593
616
|
try {
|
|
594
617
|
for (let s = 0; s < segs.length; s++) {
|
|
595
618
|
const { from, to } = segs[s]!;
|
|
@@ -636,17 +659,14 @@ export class CompiledDecode {
|
|
|
636
659
|
carried = outs[0]!;
|
|
637
660
|
carriedOwned = true;
|
|
638
661
|
// ring updates are ancestors of the carried hidden state (the
|
|
639
|
-
// in-graph fetch reads the updated buffer): no eval roots
|
|
662
|
+
// in-graph fetch reads the updated buffer): no eval roots. The
|
|
663
|
+
// host-side adoption is deferred to the end of the step (see above).
|
|
640
664
|
let oi = 1;
|
|
641
665
|
for (let i = from; i < to; i++) {
|
|
642
666
|
const c = anyCaches[i]!;
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
} else {
|
|
647
|
-
(c as RotatingKVCache).adoptDecodeStep(outs[oi]!, outs[oi + 1]!);
|
|
648
|
-
oi += 2;
|
|
649
|
-
}
|
|
667
|
+
const width = c instanceof RotatingQuantizedKVCache ? 6 : 2;
|
|
668
|
+
stagedAdopts.push({ c, bufs: outs.slice(oi, oi + width) });
|
|
669
|
+
oi += width;
|
|
650
670
|
}
|
|
651
671
|
}
|
|
652
672
|
if (s < jsLayers.length) {
|
|
@@ -655,6 +675,7 @@ export class CompiledDecode {
|
|
|
655
675
|
const c = anyCaches[li]!;
|
|
656
676
|
const window = layer.layerType === "sliding_attention" ? this.model.windowSize : null;
|
|
657
677
|
const mask = c.makeMask(1, window); // N=1 → mode ""
|
|
678
|
+
committedJs.push({ c, offsetBefore: c.offset });
|
|
658
679
|
const { h: next, shared } = layer.forward(carried, mask, c, null, null);
|
|
659
680
|
if (carriedOwned) carried.dispose();
|
|
660
681
|
carried = next;
|
|
@@ -663,6 +684,20 @@ export class CompiledDecode {
|
|
|
663
684
|
mask.arr?.dispose();
|
|
664
685
|
}
|
|
665
686
|
}
|
|
687
|
+
// every segment and js layer succeeded — commit the staged ring adopts
|
|
688
|
+
for (const { c, bufs } of stagedAdopts) {
|
|
689
|
+
if (c instanceof RotatingQuantizedKVCache) c.adoptDecodeStep(bufs);
|
|
690
|
+
else (c as RotatingKVCache).adoptDecodeStep(bufs[0]!, bufs[1]!);
|
|
691
|
+
}
|
|
692
|
+
} catch (e) {
|
|
693
|
+
// unwind: free staged (never-adopted) ring buffers and the owned hidden
|
|
694
|
+
// state, and revert the js layers' committed writes, so the caller's
|
|
695
|
+
// uncompiled re-forward of this token starts from the pre-step state.
|
|
696
|
+
for (const { bufs } of stagedAdopts) for (const b of bufs) b.dispose();
|
|
697
|
+
for (const { c, offsetBefore } of committedJs)
|
|
698
|
+
if (c.offset > offsetBefore) c.trim(c.offset - offsetBefore);
|
|
699
|
+
if (carriedOwned) carried.dispose();
|
|
700
|
+
throw e;
|
|
666
701
|
} finally {
|
|
667
702
|
for (const t of stepTemps) t.dispose();
|
|
668
703
|
}
|