mlx-bun 0.0.13 → 0.2.0
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 +31 -21
- package/bin/mlx-bun.mjs +1 -1
- package/docs/{design → archive}/hlg-sampling.md +3 -3
- package/docs/{investigations → archive/investigations}/hlg-sampling-investigation.md +1 -1
- package/docs/archive/investigations/pareto-specialized-runtime-findings.md +92 -0
- package/docs/{planning → archive/planning}/chat-ui-vision.md +1 -1
- package/docs/{planning → archive/planning}/release-notes-v0.0.9.md +1 -1
- package/docs/{planning → archive/planning}/website-readme-pass-plan.md +1 -1
- package/docs/design/colibri-glm52-port.md +1 -1
- package/docs/design/compat-cli-surface-design.md +1 -1
- package/docs/design/decode-speed-program.md +1 -1
- package/docs/design/docs-reorg-plan.md +1 -1
- package/docs/design/dspark-serving-program.md +1 -1
- package/docs/design/dspark-speculative-decoding.md +53 -3
- package/docs/design/grammar-spec-batching-integration.md +1 -1
- package/docs/design/mlx-lm-serving-execution-seam.md +81 -0
- package/docs/design/orpo-dynamic-lambda.md +1 -1
- package/docs/design/orpo-future-enhancements.md +1 -1
- package/docs/design/orpo-training.md +2 -2
- package/docs/design/parity-tier-dag.md +1 -1
- package/docs/design/repo-cleanup-plan.md +46 -4
- package/docs/design/segmented-backward-training.md +2 -2
- package/docs/design/ssd-kv-cold-tier.md +127 -0
- package/docs/design/turboquant-weights.md +467 -0
- package/docs/design/w4a16-compute-precision-spike.md +1 -1
- package/docs/design/web-chat-redesign.md +5 -5
- package/docs/planning/chunk-task-roadmap.md +1 -1
- package/docs/planning/curve-sampler-research-plan.md +4 -4
- package/docs/planning/memory-docs-and-dag-plan.md +1 -1
- package/docs/planning/release-notes-v0.2.0.md +49 -0
- package/docs/planning/video-series.md +421 -0
- package/docs/reference/cli.md +15 -4
- package/docs/reference/distribution.md +1 -0
- package/docs/reference/features-matrix.md +3 -2
- package/docs/reference/library-api.md +41 -1
- package/docs/reference/models.md +33 -0
- package/docs/reference/server-api.md +69 -14
- package/docs/reference/server-config.md +57 -33
- package/package.json +2 -2
- package/src/anthropic.ts +92 -3
- package/src/cli.ts +131 -36
- package/src/eval/kl.ts +27 -20
- package/src/eval/runner.ts +23 -4
- package/src/eval/tasks/bfcl.ts +2 -1
- package/src/eval/tasks/gsm8k.ts +2 -1
- package/src/eval/tasks/hashhop.ts +2 -1
- package/src/eval/tasks/humaneval.ts +5 -4
- package/src/eval/tasks/ifeval.ts +2 -1
- package/src/eval/tasks/mmlu.ts +2 -1
- package/src/expert-io.ts +3 -1
- package/src/expert-offload.ts +3 -1
- package/src/expert-trace.ts +3 -1
- package/src/fit.ts +24 -43
- package/src/flags.ts +7 -9
- package/src/generate.ts +107 -92
- package/src/grammar.ts +2 -1
- package/src/harness-pi.ts +1 -1
- package/src/index.ts +20 -0
- package/src/jobs/job-entry.ts +3 -2
- package/src/kv-scheme.ts +199 -0
- package/src/kv-store.ts +370 -205
- package/src/media-fetch.ts +19 -3
- package/src/memory/model.ts +2 -1
- package/src/memory/vault.ts +2 -1
- package/src/memory-plan.ts +18 -0
- package/src/mlx/ffi.ts +8 -11
- package/src/mlx/ops.ts +31 -6
- package/src/model/batched-mask.ts +1 -1
- package/src/model/batched-quant.ts +1 -1
- package/src/model/batched-rotating-quant.ts +43 -97
- package/src/model/batched-rotating-state.ts +73 -0
- package/src/model/batched-rotating.ts +56 -105
- package/src/model/batched-row-storage.ts +127 -0
- package/src/model/compiled-decode.ts +3 -2
- package/src/model/factory.ts +44 -49
- package/src/model/gemma4-base.ts +163 -10
- package/src/model/generated/gemma4-12b.ts +50 -146
- package/src/model/generated/gemma4-26b.ts +32 -92
- package/src/model/generated/gemma4-e4b.ts +26 -74
- package/src/model/glm52-cache.ts +19 -9
- package/src/model/glm52-memory.ts +28 -1
- package/src/model/minicpm5.ts +2 -1
- package/src/model/profile.ts +433 -0
- package/src/model/qwen3-delta.ts +98 -2
- package/src/model/qwen3-mrope.ts +252 -0
- package/src/model/qwen3_5.ts +217 -25
- package/src/native/frame_extract.swift +140 -0
- package/src/native-pack.ts +13 -6
- package/src/pi-web.ts +6 -5
- package/src/prompt-cache.ts +2 -2
- package/src/quantize/atomic-output.ts +38 -0
- package/src/quantize/calibration.ts +2 -1
- package/src/quantize/config-writer.ts +6 -0
- package/src/quantize/index.ts +28 -1
- package/src/quantize/job.ts +11 -0
- package/src/quantize/quantizer.ts +265 -100
- package/src/quantize/rotate.ts +603 -0
- package/src/quantize/safetensors-writer.ts +79 -1
- package/src/quantize/sensitivity.ts +41 -59
- package/src/quantize/weight-transform.ts +292 -0
- package/src/responses.ts +102 -2
- package/src/runtime-config.ts +67 -0
- package/src/sampler.ts +272 -0
- package/src/serve/admin-routes.ts +184 -0
- package/src/serve/aux-routes.ts +132 -0
- package/src/serve/batch-scheduler.ts +200 -87
- package/src/serve/completion-executor.ts +346 -0
- package/src/serve/completion-sink.ts +157 -0
- package/src/serve/discovery-routes.ts +205 -0
- package/src/serve/generation-gateway.ts +116 -109
- package/src/serve/kv-budget.ts +14 -0
- package/src/serve/lab-routes.ts +338 -0
- package/src/serve/model-admin-routes.ts +153 -0
- package/src/serve/prompt-response-trace.ts +147 -0
- package/src/serve/request-plan.ts +158 -0
- package/src/serve/static-routes.ts +101 -0
- package/src/server.ts +704 -1400
- package/src/spec/dflash-source.ts +2 -1
- package/src/spec/dspark/module-dflash.ts +1 -1
- package/src/spec/glm52-mtp-source.ts +8 -0
- package/src/spec/qwen-mtp-source.ts +431 -0
- package/src/spec/serve-loop.ts +36 -68
- package/src/ssd-cache.ts +17 -14
- package/src/ssd-durability.ts +195 -0
- package/src/train/flash-cce.ts +12 -11
- package/src/train/forward.ts +32 -1
- package/src/train/loss.ts +2 -1
- package/src/train/segmented.ts +4 -3
- package/src/train/trainer.ts +3 -2
- package/src/vision/preprocess.ts +1 -1
- package/src/vision/prompt.ts +47 -1
- package/src/vision/qwen3vl-preprocess.ts +409 -0
- package/src/vision/qwen3vl-prompt.ts +196 -0
- package/src/vision/qwen3vl-tower.ts +513 -0
- package/src/vision/video-frames.ts +148 -0
- package/src/web/app.js +10 -3
- package/src/web/src/chat.ts +12 -5
- package/src/weights.ts +81 -26
- /package/docs/{investigations → archive/investigations}/chunk-finetune-experiment.md +0 -0
- /package/docs/{investigations → archive/investigations}/colibri-oracle-pin.md +0 -0
- /package/docs/{investigations → archive/investigations}/curve-bisector-routing.md +0 -0
- /package/docs/{investigations → archive/investigations}/curve-runs/bisector-route.json +0 -0
- /package/docs/{investigations → archive/investigations}/curve-runs/bisector-trace.json +0 -0
- /package/docs/{investigations → archive/investigations}/curve-runs/curve-terrain.json +0 -0
- /package/docs/{investigations → archive/investigations}/curve-runs/curve-terrain.svg +0 -0
- /package/docs/{investigations → archive/investigations}/curve-terrain.html +0 -0
- /package/docs/{investigations → archive/investigations}/decode-roofline-lookagain.md +0 -0
- /package/docs/{investigations → archive/investigations}/dspark-handoff.md +0 -0
- /package/docs/{investigations → archive/investigations}/expert-offload-single-user-moe.md +0 -0
- /package/docs/{investigations → archive/investigations}/hlg-ab.html +0 -0
- /package/docs/{investigations → archive/investigations}/hlg-explorer.html +0 -0
- /package/docs/{investigations → archive/investigations}/hlg-figs/cliff.svg +0 -0
- /package/docs/{investigations → archive/investigations}/hlg-figs/cross.svg +0 -0
- /package/docs/{investigations → archive/investigations}/hlg-figs/edges.svg +0 -0
- /package/docs/{investigations → archive/investigations}/hlg-figs/k20-grids.svg +0 -0
- /package/docs/{investigations → archive/investigations}/hlg-figs/k20-peaks.svg +0 -0
- /package/docs/{investigations → archive/investigations}/hlg-figs/lw-curve.svg +0 -0
- /package/docs/{investigations → archive/investigations}/hlg-figs/terrain.svg +0 -0
- /package/docs/{investigations → archive/investigations}/hlg-report.html +0 -0
- /package/docs/{investigations → archive/investigations}/hlg-runs/hlg-ab.json +0 -0
- /package/docs/{investigations → archive/investigations}/hlg-runs/hlg-blind-prompts.md +0 -0
- /package/docs/{investigations → archive/investigations}/hlg-runs/hlg-blind.json +0 -0
- /package/docs/{investigations → archive/investigations}/hlg-runs/hlg-cliff.json +0 -0
- /package/docs/{investigations → archive/investigations}/hlg-runs/hlg-cross.json +0 -0
- /package/docs/{investigations → archive/investigations}/hlg-runs/hlg-edge.json +0 -0
- /package/docs/{investigations → archive/investigations}/hlg-runs/hlg-eval1.json +0 -0
- /package/docs/{investigations → archive/investigations}/hlg-runs/hlg-frontier.json +0 -0
- /package/docs/{investigations → archive/investigations}/hlg-runs/hlg-grid.json +0 -0
- /package/docs/{investigations → archive/investigations}/hlg-runs/hlg-grid2.json +0 -0
- /package/docs/{investigations → archive/investigations}/hlg-runs/hlg-lw-coarse.json +0 -0
- /package/docs/{investigations → archive/investigations}/hlg-runs/hlg-map.json +0 -0
- /package/docs/{investigations → archive/investigations}/hlg-runs/run0-original.log +0 -0
- /package/docs/{investigations → archive/investigations}/hlg-runs/runA-recommended.log +0 -0
- /package/docs/{investigations → archive/investigations}/hlg-runs/runAA-cliff-cpm5.log +0 -0
- /package/docs/{investigations → archive/investigations}/hlg-runs/runAB-grid2-e4b.log +0 -0
- /package/docs/{investigations → archive/investigations}/hlg-runs/runAC-peak-e4b-partial.log +0 -0
- /package/docs/{investigations → archive/investigations}/hlg-runs/runAD-ab-samples.log +0 -0
- /package/docs/{investigations → archive/investigations}/hlg-runs/runAE-edge-e4b.log +0 -0
- /package/docs/{investigations → archive/investigations}/hlg-runs/runAF-logit-calibration.log +0 -0
- /package/docs/{investigations → archive/investigations}/hlg-runs/runAG-eval-config2.log +0 -0
- /package/docs/{investigations → archive/investigations}/hlg-runs/runB-gain-variants.log +0 -0
- /package/docs/{investigations → archive/investigations}/hlg-runs/runC-pivots.log +0 -0
- /package/docs/{investigations → archive/investigations}/hlg-runs/runD-oetf.log +0 -0
- /package/docs/{investigations → archive/investigations}/hlg-runs/runE-eotf.log +0 -0
- /package/docs/{investigations → archive/investigations}/hlg-runs/runF-shaper-working.log +0 -0
- /package/docs/{investigations → archive/investigations}/hlg-runs/runG-shaper-sweep.log +0 -0
- /package/docs/{investigations → archive/investigations}/hlg-runs/runH-wsweep.log +0 -0
- /package/docs/{investigations → archive/investigations}/hlg-runs/runI-asweep.log +0 -0
- /package/docs/{investigations → archive/investigations}/hlg-runs/runJ-knobmap.log +0 -0
- /package/docs/{investigations → archive/investigations}/hlg-runs/runK-frontier.log +0 -0
- /package/docs/{investigations → archive/investigations}/hlg-runs/runL-widemap.log +0 -0
- /package/docs/{investigations → archive/investigations}/hlg-runs/runM-frontier-emb.log +0 -0
- /package/docs/{investigations → archive/investigations}/hlg-runs/runN-verify.log +0 -0
- /package/docs/{investigations → archive/investigations}/hlg-runs/runO-frontier-seed5000.log +0 -0
- /package/docs/{investigations → archive/investigations}/hlg-runs/runP-grid-AxSm.log +0 -0
- /package/docs/{investigations → archive/investigations}/hlg-runs/runQ-grid-tgW.log +0 -0
- /package/docs/{investigations → archive/investigations}/hlg-runs/runR-blind-transcript.log +0 -0
- /package/docs/{investigations → archive/investigations}/hlg-runs/runS-cross-coherence.log +0 -0
- /package/docs/{investigations → archive/investigations}/hlg-runs/runT-cross-cpm5.log +0 -0
- /package/docs/{investigations → archive/investigations}/hlg-runs/runU-cross-12b.log +0 -0
- /package/docs/{investigations → archive/investigations}/hlg-runs/runV-lw-e4b.log +0 -0
- /package/docs/{investigations → archive/investigations}/hlg-runs/runW-lw-12b.log +0 -0
- /package/docs/{investigations → archive/investigations}/hlg-runs/runX-lw-cpm5.log +0 -0
- /package/docs/{investigations → archive/investigations}/hlg-runs/runY-cliff-e4b.log +0 -0
- /package/docs/{investigations → archive/investigations}/hlg-runs/runZ-cliff-12b.log +0 -0
- /package/docs/{investigations → archive/investigations}/indexshare-performance-spike.md +0 -0
- /package/docs/{investigations → archive/investigations}/kernel-perf-review-2026-07.md +0 -0
- /package/docs/{investigations → archive/investigations}/lab-build-journal.md +0 -0
- /package/docs/{investigations → archive/investigations}/openwiki-evaluation.md +0 -0
- /package/docs/{investigations → archive/investigations}/orpo-base-uf-experiment-and-directions.md +0 -0
- /package/docs/{investigations → archive/investigations}/orpo-flash-cce-pin-leak.md +0 -0
- /package/docs/{investigations → archive/investigations}/orpo-uf-testing-handoff.md +0 -0
- /package/docs/{investigations → archive/investigations}/pi-builtin-investigation.md +0 -0
- /package/docs/{investigations → archive/investigations}/segmented-backward-handoff.md +0 -0
- /package/docs/{investigations → archive/investigations}/starter-model-port-handoff.md +0 -0
- /package/docs/{investigations → archive/investigations}/steel-flash-cce-handoff.md +0 -0
- /package/docs/{investigations → archive/investigations}/trainer-validation-experiment.md +0 -0
- /package/docs/{planning → archive/planning}/chat-ui-vision-memory-first.md +0 -0
- /package/docs/{planning → archive/planning}/journal.md +0 -0
- /package/docs/{planning → archive/planning}/release-notes-v0.0.10.md +0 -0
- /package/docs/{planning → archive/planning}/release-notes-v0.0.11.md +0 -0
- /package/docs/{planning → archive/planning}/release-notes-v0.0.12.md +0 -0
- /package/docs/{planning → archive/planning}/release-notes-v0.0.13.md +0 -0
- /package/docs/{planning → archive/planning}/web-ui-pass-plan.md +0 -0
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
import { MlxArray } from "../../mlx/array";
|
|
13
13
|
import * as ops from "../../mlx/ops";
|
|
14
14
|
import {
|
|
15
|
+
cacheSignature,
|
|
15
16
|
disposing,
|
|
16
17
|
fusedSdpaRuntimeOk,
|
|
17
18
|
KVCache,
|
|
@@ -529,83 +530,34 @@ function sharerFullQuantG64B4VPliScal(layer: DecoderLayer, x: MlxArray, mask: Ma
|
|
|
529
530
|
}
|
|
530
531
|
|
|
531
532
|
export class GeneratedGemma4 extends Gemma4Model {
|
|
532
|
-
/** Per-layer cache
|
|
533
|
-
* for; anything else runs the monolith path. */
|
|
533
|
+
/** Per-layer cache signatures must match what this file was generated for. */
|
|
534
534
|
#matches(cache: Cache[]): boolean {
|
|
535
535
|
return (
|
|
536
536
|
cache.length === 24 &&
|
|
537
|
-
cache[0]
|
|
538
|
-
cache[
|
|
539
|
-
cache[
|
|
540
|
-
cache[
|
|
541
|
-
cache[
|
|
542
|
-
cache[
|
|
543
|
-
cache[
|
|
544
|
-
cache[
|
|
545
|
-
cache[
|
|
546
|
-
cache[
|
|
547
|
-
cache[
|
|
548
|
-
cache[
|
|
549
|
-
cache[
|
|
550
|
-
cache[
|
|
551
|
-
cache[
|
|
552
|
-
cache[
|
|
553
|
-
cache[
|
|
554
|
-
cache[
|
|
555
|
-
cache[
|
|
556
|
-
cache[
|
|
557
|
-
cache[
|
|
558
|
-
cache[
|
|
559
|
-
cache[
|
|
560
|
-
cache[
|
|
561
|
-
cache[8] instanceof RotatingQuantizedKVCache &&
|
|
562
|
-
cache[8].bits === 4 &&
|
|
563
|
-
cache[8].groupSize === 64 &&
|
|
564
|
-
cache[9] instanceof RotatingQuantizedKVCache &&
|
|
565
|
-
cache[9].bits === 8 &&
|
|
566
|
-
cache[9].groupSize === 64 &&
|
|
567
|
-
cache[10] instanceof RotatingQuantizedKVCache &&
|
|
568
|
-
cache[10].bits === 8 &&
|
|
569
|
-
cache[10].groupSize === 64 &&
|
|
570
|
-
cache[11] instanceof QuantizedKVCache &&
|
|
571
|
-
cache[11].bits === 8 &&
|
|
572
|
-
cache[11].groupSize === 64 &&
|
|
573
|
-
cache[12] instanceof RotatingQuantizedKVCache &&
|
|
574
|
-
cache[12].bits === 4 &&
|
|
575
|
-
cache[12].groupSize === 64 &&
|
|
576
|
-
cache[13] instanceof RotatingQuantizedKVCache &&
|
|
577
|
-
cache[13].bits === 4 &&
|
|
578
|
-
cache[13].groupSize === 64 &&
|
|
579
|
-
cache[14] instanceof RotatingQuantizedKVCache &&
|
|
580
|
-
cache[14].bits === 8 &&
|
|
581
|
-
cache[14].groupSize === 64 &&
|
|
582
|
-
cache[15] instanceof RotatingQuantizedKVCache &&
|
|
583
|
-
cache[15].bits === 4 &&
|
|
584
|
-
cache[15].groupSize === 64 &&
|
|
585
|
-
cache[16] instanceof RotatingQuantizedKVCache &&
|
|
586
|
-
cache[16].bits === 4 &&
|
|
587
|
-
cache[16].groupSize === 64 &&
|
|
588
|
-
cache[17] instanceof QuantizedKVCache &&
|
|
589
|
-
cache[17].bits === 4 &&
|
|
590
|
-
cache[17].groupSize === 64 &&
|
|
591
|
-
cache[18] instanceof RotatingQuantizedKVCache &&
|
|
592
|
-
cache[18].bits === 4 &&
|
|
593
|
-
cache[18].groupSize === 64 &&
|
|
594
|
-
cache[19] instanceof RotatingQuantizedKVCache &&
|
|
595
|
-
cache[19].bits === 4 &&
|
|
596
|
-
cache[19].groupSize === 64 &&
|
|
597
|
-
cache[20] instanceof RotatingQuantizedKVCache &&
|
|
598
|
-
cache[20].bits === 4 &&
|
|
599
|
-
cache[20].groupSize === 64 &&
|
|
600
|
-
cache[21] instanceof RotatingQuantizedKVCache &&
|
|
601
|
-
cache[21].bits === 4 &&
|
|
602
|
-
cache[21].groupSize === 64 &&
|
|
603
|
-
cache[22] instanceof RotatingQuantizedKVCache &&
|
|
604
|
-
cache[22].bits === 4 &&
|
|
605
|
-
cache[22].groupSize === 64 &&
|
|
606
|
-
cache[23] instanceof QuantizedKVCache &&
|
|
607
|
-
cache[23].bits === 4 &&
|
|
608
|
-
cache[23].groupSize === 64
|
|
537
|
+
cacheSignature(cache[0]) === "kv:rotating-quant:4:64" &&
|
|
538
|
+
cacheSignature(cache[1]) === "kv:rotating-quant:4:64" &&
|
|
539
|
+
cacheSignature(cache[2]) === "kv:rotating-quant:4:64" &&
|
|
540
|
+
cacheSignature(cache[3]) === "kv:rotating-quant:8:64" &&
|
|
541
|
+
cacheSignature(cache[4]) === "kv:rotating-quant:8:64" &&
|
|
542
|
+
cacheSignature(cache[5]) === "kv:quant:4:64" &&
|
|
543
|
+
cacheSignature(cache[6]) === "kv:rotating-quant:4:64" &&
|
|
544
|
+
cacheSignature(cache[7]) === "kv:rotating-quant:4:64" &&
|
|
545
|
+
cacheSignature(cache[8]) === "kv:rotating-quant:4:64" &&
|
|
546
|
+
cacheSignature(cache[9]) === "kv:rotating-quant:8:64" &&
|
|
547
|
+
cacheSignature(cache[10]) === "kv:rotating-quant:8:64" &&
|
|
548
|
+
cacheSignature(cache[11]) === "kv:quant:8:64" &&
|
|
549
|
+
cacheSignature(cache[12]) === "kv:rotating-quant:4:64" &&
|
|
550
|
+
cacheSignature(cache[13]) === "kv:rotating-quant:4:64" &&
|
|
551
|
+
cacheSignature(cache[14]) === "kv:rotating-quant:8:64" &&
|
|
552
|
+
cacheSignature(cache[15]) === "kv:rotating-quant:4:64" &&
|
|
553
|
+
cacheSignature(cache[16]) === "kv:rotating-quant:4:64" &&
|
|
554
|
+
cacheSignature(cache[17]) === "kv:quant:4:64" &&
|
|
555
|
+
cacheSignature(cache[18]) === "kv:rotating-quant:4:64" &&
|
|
556
|
+
cacheSignature(cache[19]) === "kv:rotating-quant:4:64" &&
|
|
557
|
+
cacheSignature(cache[20]) === "kv:rotating-quant:4:64" &&
|
|
558
|
+
cacheSignature(cache[21]) === "kv:rotating-quant:4:64" &&
|
|
559
|
+
cacheSignature(cache[22]) === "kv:rotating-quant:4:64" &&
|
|
560
|
+
cacheSignature(cache[23]) === "kv:quant:4:64"
|
|
609
561
|
);
|
|
610
562
|
}
|
|
611
563
|
|
package/src/model/glm52-cache.ts
CHANGED
|
@@ -88,7 +88,7 @@ function trimToTokens(array: MlxArray, tokens: number): MlxArray {
|
|
|
88
88
|
const stop = [...array.shape];
|
|
89
89
|
stop[1] = tokens;
|
|
90
90
|
const view = array.slice(start, stop);
|
|
91
|
-
const exact = ops.
|
|
91
|
+
const exact = ops.copyOf(view); // TRUE copy: see 2026-08-20 contiguous-view pin class
|
|
92
92
|
view.dispose();
|
|
93
93
|
return exact;
|
|
94
94
|
}
|
|
@@ -225,6 +225,15 @@ export class Glm52Cache implements BatchableCache {
|
|
|
225
225
|
throw new Error("native MTP cache cannot contain target DSA state");
|
|
226
226
|
}
|
|
227
227
|
|
|
228
|
+
signature(): string {
|
|
229
|
+
if (this.role === "mtp") return "kv:mla:mtp";
|
|
230
|
+
return this.dsa ? "kv:mla:target:dsa" : "kv:mla:target";
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
bytesPerToken(): number {
|
|
234
|
+
return (this.kvLoraRank + this.ropeHeadDim + (this.dsa?.headDim ?? 0)) * 4;
|
|
235
|
+
}
|
|
236
|
+
|
|
228
237
|
/** Append one equal-width row block without expanding it to per-head K/V. */
|
|
229
238
|
append(latent: MlxArray, rope: MlxArray, dsa: MlxArray | null = null): void {
|
|
230
239
|
const latentShape = latent.shape;
|
|
@@ -620,15 +629,16 @@ export class Glm52Cache implements BatchableCache {
|
|
|
620
629
|
const nextWidth = this.offset - removablePad;
|
|
621
630
|
const indices = ops.fromInt32([...keep], [keep.length]);
|
|
622
631
|
const filterFamily = (array: MlxArray): MlxArray => {
|
|
623
|
-
const
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
const
|
|
632
|
+
const trimmed = removablePad === 0
|
|
633
|
+
? array
|
|
634
|
+
: array.slice(
|
|
635
|
+
[0, removablePad, 0],
|
|
636
|
+
[this.batchSize!, this.offset, array.shape[2]!],
|
|
637
|
+
);
|
|
638
|
+
const selected = ops.takeAxis(trimmed, indices, 0);
|
|
639
|
+
const exact = ops.copyOf(selected); // TRUE copy: see 2026-08-20 contiguous-view pin class
|
|
630
640
|
selected.dispose();
|
|
631
|
-
|
|
641
|
+
if (trimmed !== array) trimmed.dispose();
|
|
632
642
|
return exact;
|
|
633
643
|
};
|
|
634
644
|
|
|
@@ -4,6 +4,7 @@ import {
|
|
|
4
4
|
type Glm52Config,
|
|
5
5
|
} from "./glm52-config";
|
|
6
6
|
import { ColibriGlm52Container } from "./glm52-container";
|
|
7
|
+
import type { MemoryPlan } from "../memory-plan";
|
|
7
8
|
|
|
8
9
|
export const GLM52_G5_GIB = 1024 ** 3;
|
|
9
10
|
export const GLM52_G5_DEFAULT_MACHINE_BYTES = 32 * GLM52_G5_GIB;
|
|
@@ -73,8 +74,9 @@ export interface Glm52MemoryLineItems {
|
|
|
73
74
|
readonly safetyMarginBytes: number;
|
|
74
75
|
}
|
|
75
76
|
|
|
76
|
-
export interface Glm52MemoryPlan {
|
|
77
|
+
export interface Glm52MemoryPlan extends MemoryPlan {
|
|
77
78
|
readonly schemaVersion: 1;
|
|
79
|
+
readonly strategy: "glm52-colibri";
|
|
78
80
|
readonly preset: "g5-32gb-quality";
|
|
79
81
|
readonly machineBytes: number;
|
|
80
82
|
readonly processLimitBytes: number;
|
|
@@ -374,11 +376,14 @@ export function planGlm52Memory(
|
|
|
374
376
|
|
|
375
377
|
return {
|
|
376
378
|
schemaVersion: 1,
|
|
379
|
+
strategy: "glm52-colibri",
|
|
380
|
+
fits: true,
|
|
377
381
|
preset: "g5-32gb-quality",
|
|
378
382
|
machineBytes,
|
|
379
383
|
processLimitBytes,
|
|
380
384
|
osReserveBytes,
|
|
381
385
|
contextTokens,
|
|
386
|
+
maxSafeContext: contextTokens,
|
|
382
387
|
maxGenerationTokens,
|
|
383
388
|
batchSize,
|
|
384
389
|
enableMtp,
|
|
@@ -392,6 +397,28 @@ export function planGlm52Memory(
|
|
|
392
397
|
mtpResidentSlots,
|
|
393
398
|
mtpTotalSlots,
|
|
394
399
|
lineItems,
|
|
400
|
+
weightsBytes: sum("GLM planned weights", [
|
|
401
|
+
lineItems.residentWeightsBytes,
|
|
402
|
+
lineItems.mainExpertSlabBytes,
|
|
403
|
+
lineItems.mtpExpertSlabBytes,
|
|
404
|
+
]),
|
|
405
|
+
kvBytes: sum("GLM planned KV", [
|
|
406
|
+
lineItems.targetKvBytes,
|
|
407
|
+
lineItems.mtpKvBytes,
|
|
408
|
+
]),
|
|
409
|
+
transientBytes: sum("GLM planned transient", [
|
|
410
|
+
lineItems.reconstructedKvTransientBytes,
|
|
411
|
+
lineItems.verifyBatchTransientBytes,
|
|
412
|
+
]),
|
|
413
|
+
reserveBytes: sum("GLM planned reserves", [
|
|
414
|
+
lineItems.allocatorReserveBytes,
|
|
415
|
+
lineItems.bunNativeReserveBytes,
|
|
416
|
+
lineItems.safetyMarginBytes,
|
|
417
|
+
]),
|
|
418
|
+
totalBytes: plannedProcessBytes,
|
|
419
|
+
usableBytes: processLimitBytes,
|
|
420
|
+
predictedDecodeTps: null,
|
|
421
|
+
allocatorLimitBytes: lineItems.allocatorReserveBytes,
|
|
395
422
|
runtimeReserveBytes,
|
|
396
423
|
plannedProcessBytes,
|
|
397
424
|
processHeadroomBytes: processLimitBytes - plannedProcessBytes,
|
package/src/model/minicpm5.ts
CHANGED
|
@@ -24,6 +24,7 @@ import {
|
|
|
24
24
|
type Mask,
|
|
25
25
|
} from "./gemma4-base";
|
|
26
26
|
import { CompiledFunction } from "../mlx/compile";
|
|
27
|
+
import { runtimeValue } from "../runtime-config";
|
|
27
28
|
|
|
28
29
|
/** Verbatim port of mlx_lm/models/activations.py:
|
|
29
30
|
* `@partial(mx.compile, shapeless=True) def swiglu(gate, x): return nn.silu(gate) * x`
|
|
@@ -207,7 +208,7 @@ export class LlamaMLP {
|
|
|
207
208
|
// Plain sigmoid+mul+mul otherwise (M>1 prefill/training, or inside a compile
|
|
208
209
|
// trace) — identical math either way. MLX_BUN_COMPILED_SWIGLU=0 disables.
|
|
209
210
|
let hidden: MlxArray;
|
|
210
|
-
if (M === 1 && !isCompiledTrace() &&
|
|
211
|
+
if (M === 1 && !isCompiledTrace() && runtimeValue("MLX_BUN_COMPILED_SWIGLU") !== "0") {
|
|
211
212
|
hidden = compiledSwiglu(gate, up);
|
|
212
213
|
gate.dispose();
|
|
213
214
|
up.dispose();
|
|
@@ -0,0 +1,433 @@
|
|
|
1
|
+
import type { ModelConfig } from "../config";
|
|
2
|
+
import { configFingerprint } from "./fingerprint";
|
|
3
|
+
import {
|
|
4
|
+
isDiffusionGemmaConfig,
|
|
5
|
+
isGlm52Config,
|
|
6
|
+
isMiniCPM5Config,
|
|
7
|
+
isQwen35Config,
|
|
8
|
+
isQwen3Config,
|
|
9
|
+
isQwen3MoeConfig,
|
|
10
|
+
} from "./support";
|
|
11
|
+
import { GENERATED } from "./generated";
|
|
12
|
+
import { GENERIC_MODEL_TYPES, genericArgsFor, remapModelType } from "./universal/archs";
|
|
13
|
+
|
|
14
|
+
export const ENGINE_CAPABILITIES = Object.freeze([
|
|
15
|
+
"autoregressive",
|
|
16
|
+
"colibri-container",
|
|
17
|
+
"diffusion",
|
|
18
|
+
"diffusion-gemma-graph",
|
|
19
|
+
"gemma4-graph",
|
|
20
|
+
"generated-graph",
|
|
21
|
+
"glm5.2-graph",
|
|
22
|
+
"minicpm5-graph",
|
|
23
|
+
"mixed-precision-kv",
|
|
24
|
+
"native-mtp",
|
|
25
|
+
"qwen3-graph",
|
|
26
|
+
"qwen3-moe-graph",
|
|
27
|
+
"qwen3.5-graph",
|
|
28
|
+
"recurrent-state",
|
|
29
|
+
"safetensors",
|
|
30
|
+
"streamed-experts",
|
|
31
|
+
"universal-dense-graph",
|
|
32
|
+
"vision-sidecar",
|
|
33
|
+
] as const);
|
|
34
|
+
|
|
35
|
+
export type EngineCapability = typeof ENGINE_CAPABILITIES[number];
|
|
36
|
+
export type FidelityTier = "l1" | "l2" | "l3";
|
|
37
|
+
|
|
38
|
+
export type FidelityTarget =
|
|
39
|
+
| Readonly<{ tier: "l1"; oracle: "mlx-lm"; claim: "bit-exact" }>
|
|
40
|
+
| Readonly<{ tier: "l2"; oracle: "mlx-optiq"; claim: "bit-exact" }>
|
|
41
|
+
| Readonly<{ tier: "l3"; oracle: null; claim: "measured" }>;
|
|
42
|
+
|
|
43
|
+
export type ModelLoader = "safetensors" | "colibri";
|
|
44
|
+
export type ModelGraph =
|
|
45
|
+
| "gemma4"
|
|
46
|
+
| "minicpm5"
|
|
47
|
+
| "qwen3.5"
|
|
48
|
+
| "qwen3"
|
|
49
|
+
| "qwen3-moe"
|
|
50
|
+
| "diffusion-gemma"
|
|
51
|
+
| "glm5.2"
|
|
52
|
+
| "universal-dense";
|
|
53
|
+
export type GenerationLoop = "autoregressive" | "diffusion";
|
|
54
|
+
export type ModelSpecialization = "artifact" | "dedicated" | "generated" | "generic";
|
|
55
|
+
|
|
56
|
+
export interface ModelExecutionComposition {
|
|
57
|
+
readonly loader: ModelLoader;
|
|
58
|
+
readonly graph: ModelGraph;
|
|
59
|
+
readonly loop: GenerationLoop;
|
|
60
|
+
readonly specialization: ModelSpecialization;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/** A profile declares construction only. Request methods such as MTP, KV
|
|
64
|
+
* schemes, adapters, grammar, and sampling are resolved independently and
|
|
65
|
+
* cannot be rewritten by profile selection. */
|
|
66
|
+
export interface ModelProfile {
|
|
67
|
+
readonly id: string;
|
|
68
|
+
/** Exact external identity. Family profiles omit this field. */
|
|
69
|
+
readonly artifactFingerprint?: string;
|
|
70
|
+
/** Structural guard for an exact artifact declaration. */
|
|
71
|
+
readonly configFingerprint?: string;
|
|
72
|
+
readonly fidelity: FidelityTarget;
|
|
73
|
+
readonly requiredCapabilities: readonly EngineCapability[];
|
|
74
|
+
readonly execution: ModelExecutionComposition;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export interface ArtifactModelProfile extends ModelProfile {
|
|
78
|
+
readonly artifactFingerprint: string;
|
|
79
|
+
readonly configFingerprint: string;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export interface ModelArtifactIdentity {
|
|
83
|
+
readonly fingerprint: string | null;
|
|
84
|
+
readonly configFingerprint: string;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export interface ResolvedModelProfile {
|
|
88
|
+
readonly profile: ModelProfile;
|
|
89
|
+
readonly artifact: ModelArtifactIdentity;
|
|
90
|
+
readonly exactArtifact: boolean;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export interface ResolveModelProfileOptions {
|
|
94
|
+
/** Explicit identity for a non-Hugging-Face artifact. The caller owns its
|
|
95
|
+
* provenance; mlx-bun never mistakes a local path for a content identity. */
|
|
96
|
+
readonly artifactFingerprint?: string | null;
|
|
97
|
+
/** Additional exact declarations composed with the shipped profiles. */
|
|
98
|
+
readonly artifactProfiles?: readonly ArtifactModelProfile[];
|
|
99
|
+
readonly engineCapabilities?: readonly EngineCapability[];
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
const L1: FidelityTarget = Object.freeze({
|
|
103
|
+
tier: "l1", oracle: "mlx-lm", claim: "bit-exact",
|
|
104
|
+
});
|
|
105
|
+
const L2: FidelityTarget = Object.freeze({
|
|
106
|
+
tier: "l2", oracle: "mlx-optiq", claim: "bit-exact",
|
|
107
|
+
});
|
|
108
|
+
const L3: FidelityTarget = Object.freeze({
|
|
109
|
+
tier: "l3", oracle: null, claim: "measured",
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
function freezeProfile<T extends ModelProfile>(profile: T): T {
|
|
113
|
+
Object.freeze(profile.fidelity);
|
|
114
|
+
Object.freeze(profile.requiredCapabilities);
|
|
115
|
+
Object.freeze(profile.execution);
|
|
116
|
+
return Object.freeze(profile);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
function snapshotProfile(profile: ModelProfile): ModelProfile {
|
|
120
|
+
return freezeProfile({
|
|
121
|
+
...profile,
|
|
122
|
+
fidelity: { ...profile.fidelity },
|
|
123
|
+
requiredCapabilities: [...profile.requiredCapabilities],
|
|
124
|
+
execution: { ...profile.execution },
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/** Exact artifact declarations already backed by this repository's parity or
|
|
129
|
+
* measured evidence. A new revision gets the family profile until it earns a
|
|
130
|
+
* declaration of its own. */
|
|
131
|
+
export const BUILTIN_ARTIFACT_PROFILES: readonly ArtifactModelProfile[] = Object.freeze([
|
|
132
|
+
freezeProfile({
|
|
133
|
+
id: "qwen3.8-27b-optiq-4bit",
|
|
134
|
+
artifactFingerprint:
|
|
135
|
+
"hf:mlx-community/Qwen3.8-27B-OptiQ-4bit@b04599de95d7a9bfbd7f208d347c0f10d9432a42",
|
|
136
|
+
configFingerprint: "50117975cb405944",
|
|
137
|
+
fidelity: L1,
|
|
138
|
+
requiredCapabilities: Object.freeze([
|
|
139
|
+
"safetensors", "autoregressive", "qwen3.5-graph", "recurrent-state", "vision-sidecar",
|
|
140
|
+
]),
|
|
141
|
+
execution: Object.freeze({
|
|
142
|
+
loader: "safetensors",
|
|
143
|
+
graph: "qwen3.5",
|
|
144
|
+
loop: "autoregressive",
|
|
145
|
+
specialization: "artifact",
|
|
146
|
+
}),
|
|
147
|
+
}),
|
|
148
|
+
freezeProfile({
|
|
149
|
+
id: "glm5.2-colibri-int4-int8-mtp",
|
|
150
|
+
artifactFingerprint:
|
|
151
|
+
"hf:mateogrgic/GLM-5.2-colibri-int4-with-int8-mtp@3cc8db99b1b13fc79325d987ba3c1c430766b3b8",
|
|
152
|
+
configFingerprint: "8b49d0941e18f1b9",
|
|
153
|
+
fidelity: L3,
|
|
154
|
+
requiredCapabilities: Object.freeze([
|
|
155
|
+
"colibri-container", "autoregressive", "glm5.2-graph", "streamed-experts",
|
|
156
|
+
]),
|
|
157
|
+
execution: Object.freeze({
|
|
158
|
+
loader: "colibri",
|
|
159
|
+
graph: "glm5.2",
|
|
160
|
+
loop: "autoregressive",
|
|
161
|
+
specialization: "artifact",
|
|
162
|
+
}),
|
|
163
|
+
}),
|
|
164
|
+
]);
|
|
165
|
+
|
|
166
|
+
const FAMILY_PROFILES = {
|
|
167
|
+
gemma4Generated: freezeProfile({
|
|
168
|
+
id: "gemma4-generated",
|
|
169
|
+
fidelity: L1,
|
|
170
|
+
requiredCapabilities: ["safetensors", "autoregressive", "gemma4-graph", "generated-graph"],
|
|
171
|
+
execution: {
|
|
172
|
+
loader: "safetensors", graph: "gemma4", loop: "autoregressive", specialization: "generated",
|
|
173
|
+
},
|
|
174
|
+
}),
|
|
175
|
+
gemma4: freezeProfile({
|
|
176
|
+
id: "gemma4-dedicated",
|
|
177
|
+
fidelity: L1,
|
|
178
|
+
requiredCapabilities: ["safetensors", "autoregressive", "gemma4-graph"],
|
|
179
|
+
execution: {
|
|
180
|
+
loader: "safetensors", graph: "gemma4", loop: "autoregressive", specialization: "dedicated",
|
|
181
|
+
},
|
|
182
|
+
}),
|
|
183
|
+
minicpm5: freezeProfile({
|
|
184
|
+
id: "minicpm5-dedicated",
|
|
185
|
+
fidelity: L1,
|
|
186
|
+
requiredCapabilities: ["safetensors", "autoregressive", "minicpm5-graph"],
|
|
187
|
+
execution: {
|
|
188
|
+
loader: "safetensors", graph: "minicpm5", loop: "autoregressive", specialization: "dedicated",
|
|
189
|
+
},
|
|
190
|
+
}),
|
|
191
|
+
qwen35: freezeProfile({
|
|
192
|
+
id: "qwen3.5-dedicated",
|
|
193
|
+
fidelity: L1,
|
|
194
|
+
requiredCapabilities: ["safetensors", "autoregressive", "qwen3.5-graph", "recurrent-state"],
|
|
195
|
+
execution: {
|
|
196
|
+
loader: "safetensors", graph: "qwen3.5", loop: "autoregressive", specialization: "dedicated",
|
|
197
|
+
},
|
|
198
|
+
}),
|
|
199
|
+
qwen3: freezeProfile({
|
|
200
|
+
id: "qwen3-dedicated",
|
|
201
|
+
fidelity: L1,
|
|
202
|
+
requiredCapabilities: ["safetensors", "autoregressive", "qwen3-graph"],
|
|
203
|
+
execution: {
|
|
204
|
+
loader: "safetensors", graph: "qwen3", loop: "autoregressive", specialization: "dedicated",
|
|
205
|
+
},
|
|
206
|
+
}),
|
|
207
|
+
qwen3Moe: freezeProfile({
|
|
208
|
+
id: "qwen3-moe-dedicated",
|
|
209
|
+
fidelity: L1,
|
|
210
|
+
requiredCapabilities: ["safetensors", "autoregressive", "qwen3-moe-graph"],
|
|
211
|
+
execution: {
|
|
212
|
+
loader: "safetensors", graph: "qwen3-moe", loop: "autoregressive", specialization: "dedicated",
|
|
213
|
+
},
|
|
214
|
+
}),
|
|
215
|
+
diffusionGemma: freezeProfile({
|
|
216
|
+
id: "diffusion-gemma-dedicated",
|
|
217
|
+
fidelity: L2,
|
|
218
|
+
requiredCapabilities: ["safetensors", "diffusion", "diffusion-gemma-graph"],
|
|
219
|
+
execution: {
|
|
220
|
+
loader: "safetensors", graph: "diffusion-gemma", loop: "diffusion", specialization: "dedicated",
|
|
221
|
+
},
|
|
222
|
+
}),
|
|
223
|
+
glm52: freezeProfile({
|
|
224
|
+
id: "glm5.2-colibri",
|
|
225
|
+
fidelity: L3,
|
|
226
|
+
requiredCapabilities: ["colibri-container", "autoregressive", "glm5.2-graph", "streamed-experts"],
|
|
227
|
+
execution: {
|
|
228
|
+
loader: "colibri", graph: "glm5.2", loop: "autoregressive", specialization: "dedicated",
|
|
229
|
+
},
|
|
230
|
+
}),
|
|
231
|
+
universal: freezeProfile({
|
|
232
|
+
id: "universal-dense",
|
|
233
|
+
fidelity: L1,
|
|
234
|
+
requiredCapabilities: ["safetensors", "autoregressive", "universal-dense-graph"],
|
|
235
|
+
execution: {
|
|
236
|
+
loader: "safetensors", graph: "universal-dense", loop: "autoregressive", specialization: "generic",
|
|
237
|
+
},
|
|
238
|
+
}),
|
|
239
|
+
} satisfies Record<string, ModelProfile>;
|
|
240
|
+
|
|
241
|
+
/** Return a stable external fingerprint only when the directory is an exact HF
|
|
242
|
+
* snapshot revision. Relocation does not change the identity. Arbitrary local
|
|
243
|
+
* directories and mutable aliases intentionally return null. */
|
|
244
|
+
export function externalArtifactFingerprint(modelDir: string): string | null {
|
|
245
|
+
const match = modelDir.replaceAll("\\", "/").match(
|
|
246
|
+
/(?:^|\/)models--([^/]+)\/snapshots\/([0-9a-f]{40,64})(?:\/|$)/i,
|
|
247
|
+
);
|
|
248
|
+
if (!match) return null;
|
|
249
|
+
const encodedRepo = match[1]!;
|
|
250
|
+
const separator = encodedRepo.indexOf("--");
|
|
251
|
+
if (separator <= 0 || separator === encodedRepo.length - 2) return null;
|
|
252
|
+
const repo = `${encodedRepo.slice(0, separator)}/${encodedRepo.slice(separator + 2)}`;
|
|
253
|
+
return `hf:${repo}@${match[2]!.toLowerCase()}`;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
function familyProfile(config: ModelConfig, fingerprint: string): ModelProfile {
|
|
257
|
+
if (isGlm52Config(config)) return FAMILY_PROFILES.glm52;
|
|
258
|
+
if (isDiffusionGemmaConfig(config)) return FAMILY_PROFILES.diffusionGemma;
|
|
259
|
+
if (isMiniCPM5Config(config)) return FAMILY_PROFILES.minicpm5;
|
|
260
|
+
if (isQwen35Config(config)) return FAMILY_PROFILES.qwen35;
|
|
261
|
+
if (isQwen3MoeConfig(config)) return FAMILY_PROFILES.qwen3Moe;
|
|
262
|
+
if (isQwen3Config(config)) return FAMILY_PROFILES.qwen3;
|
|
263
|
+
if (config.modelType.startsWith("gemma4"))
|
|
264
|
+
return GENERATED.has(fingerprint) ? FAMILY_PROFILES.gemma4Generated : FAMILY_PROFILES.gemma4;
|
|
265
|
+
if (genericArgsFor(config)) return FAMILY_PROFILES.universal;
|
|
266
|
+
|
|
267
|
+
const arch = remapModelType(config.modelType);
|
|
268
|
+
throw new Error(
|
|
269
|
+
`unsupported model_type "${config.modelType}"` +
|
|
270
|
+
(arch !== config.modelType ? ` (mlx-lm remaps it to "${arch}")` : "") +
|
|
271
|
+
` — targeted: gemma4*, diffusion_gemma, glm_moe_dsa, qwen3_5, qwen3, qwen3_moe, MiniCPM5;` +
|
|
272
|
+
` generic (Tier-0): ${[...GENERIC_MODEL_TYPES].sort().join(", ")}`,
|
|
273
|
+
);
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
interface GraphMetadata {
|
|
277
|
+
readonly accepts: (config: ModelConfig) => boolean;
|
|
278
|
+
readonly capabilities: readonly EngineCapability[];
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
const GRAPH_METADATA: Readonly<Record<ModelGraph, GraphMetadata>> = Object.freeze({
|
|
282
|
+
"gemma4": {
|
|
283
|
+
accepts: (config) => config.modelType.startsWith("gemma4"),
|
|
284
|
+
capabilities: ["gemma4-graph"],
|
|
285
|
+
},
|
|
286
|
+
"minicpm5": { accepts: isMiniCPM5Config, capabilities: ["minicpm5-graph"] },
|
|
287
|
+
"qwen3.5": {
|
|
288
|
+
accepts: isQwen35Config,
|
|
289
|
+
capabilities: ["qwen3.5-graph", "recurrent-state"],
|
|
290
|
+
},
|
|
291
|
+
"qwen3": { accepts: isQwen3Config, capabilities: ["qwen3-graph"] },
|
|
292
|
+
"qwen3-moe": { accepts: isQwen3MoeConfig, capabilities: ["qwen3-moe-graph"] },
|
|
293
|
+
"diffusion-gemma": {
|
|
294
|
+
accepts: isDiffusionGemmaConfig,
|
|
295
|
+
capabilities: ["diffusion-gemma-graph"],
|
|
296
|
+
},
|
|
297
|
+
"glm5.2": {
|
|
298
|
+
accepts: isGlm52Config,
|
|
299
|
+
capabilities: ["glm5.2-graph", "streamed-experts"],
|
|
300
|
+
},
|
|
301
|
+
"universal-dense": {
|
|
302
|
+
accepts: (config) => {
|
|
303
|
+
try { return genericArgsFor(config) !== null; } catch { return false; }
|
|
304
|
+
},
|
|
305
|
+
capabilities: ["universal-dense-graph"],
|
|
306
|
+
},
|
|
307
|
+
});
|
|
308
|
+
|
|
309
|
+
function graphAccepts(profile: ModelProfile, config: ModelConfig): boolean {
|
|
310
|
+
return GRAPH_METADATA[profile.execution.graph].accepts(config);
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
function executionCapabilities(profile: ModelProfile): EngineCapability[] {
|
|
314
|
+
const required: EngineCapability[] = [profile.execution.loader === "colibri"
|
|
315
|
+
? "colibri-container"
|
|
316
|
+
: "safetensors"];
|
|
317
|
+
if (profile.execution.loop === "diffusion") required.push("diffusion");
|
|
318
|
+
else required.push("autoregressive");
|
|
319
|
+
required.push(...GRAPH_METADATA[profile.execution.graph].capabilities);
|
|
320
|
+
if (profile.execution.specialization === "generated") required.push("generated-graph");
|
|
321
|
+
return required;
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
function validateProfile(profile: ModelProfile): void {
|
|
325
|
+
if (!profile.id) throw new Error("model profile id must not be empty");
|
|
326
|
+
if ((profile.artifactFingerprint === undefined) !== (profile.configFingerprint === undefined))
|
|
327
|
+
throw new Error(
|
|
328
|
+
`model profile ${profile.id} must declare artifactFingerprint and configFingerprint together`,
|
|
329
|
+
);
|
|
330
|
+
const fidelityOk =
|
|
331
|
+
(profile.fidelity.tier === "l1" && profile.fidelity.oracle === "mlx-lm" &&
|
|
332
|
+
profile.fidelity.claim === "bit-exact") ||
|
|
333
|
+
(profile.fidelity.tier === "l2" && profile.fidelity.oracle === "mlx-optiq" &&
|
|
334
|
+
profile.fidelity.claim === "bit-exact") ||
|
|
335
|
+
(profile.fidelity.tier === "l3" && profile.fidelity.oracle === null &&
|
|
336
|
+
profile.fidelity.claim === "measured");
|
|
337
|
+
if (!fidelityOk) throw new Error(`model profile ${profile.id} has an invalid fidelity contract`);
|
|
338
|
+
const expectedLoader = profile.execution.graph === "glm5.2" ? "colibri" : "safetensors";
|
|
339
|
+
const expectedLoop = profile.execution.graph === "diffusion-gemma"
|
|
340
|
+
? "diffusion"
|
|
341
|
+
: "autoregressive";
|
|
342
|
+
if (profile.execution.loader !== expectedLoader || profile.execution.loop !== expectedLoop)
|
|
343
|
+
throw new Error(
|
|
344
|
+
`model profile ${profile.id} has an invalid execution composition for ` +
|
|
345
|
+
`${profile.execution.graph}`,
|
|
346
|
+
);
|
|
347
|
+
const declared = new Set(profile.requiredCapabilities);
|
|
348
|
+
const underdeclared = executionCapabilities(profile).filter((capability) => !declared.has(capability));
|
|
349
|
+
if (underdeclared.length)
|
|
350
|
+
throw new Error(
|
|
351
|
+
`model profile ${profile.id} does not declare execution capabilities: ` +
|
|
352
|
+
`${underdeclared.join(", ")}`,
|
|
353
|
+
);
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
export function resolveModelProfile(
|
|
357
|
+
config: ModelConfig,
|
|
358
|
+
options: ResolveModelProfileOptions = {},
|
|
359
|
+
): ResolvedModelProfile {
|
|
360
|
+
const fingerprint = configFingerprint(config);
|
|
361
|
+
const artifactFingerprint = options.artifactFingerprint === undefined
|
|
362
|
+
? externalArtifactFingerprint(config.modelDir)
|
|
363
|
+
: options.artifactFingerprint;
|
|
364
|
+
const artifactProfiles = options.artifactProfiles
|
|
365
|
+
? [...BUILTIN_ARTIFACT_PROFILES, ...options.artifactProfiles]
|
|
366
|
+
: BUILTIN_ARTIFACT_PROFILES;
|
|
367
|
+
const capabilities = new Set(options.engineCapabilities ?? ENGINE_CAPABILITIES);
|
|
368
|
+
|
|
369
|
+
let profile: ModelProfile | undefined;
|
|
370
|
+
let exactArtifact = false;
|
|
371
|
+
if (artifactFingerprint) {
|
|
372
|
+
const matches = artifactProfiles.filter((entry) => {
|
|
373
|
+
validateProfile(entry);
|
|
374
|
+
return entry.artifactFingerprint === artifactFingerprint;
|
|
375
|
+
});
|
|
376
|
+
if (matches.length > 1)
|
|
377
|
+
throw new Error(`multiple model profiles declare artifact ${artifactFingerprint}`);
|
|
378
|
+
profile = matches[0];
|
|
379
|
+
if (profile) {
|
|
380
|
+
exactArtifact = true;
|
|
381
|
+
if (profile.configFingerprint !== fingerprint)
|
|
382
|
+
throw new Error(
|
|
383
|
+
`model profile ${profile.id} matched artifact ${artifactFingerprint}, but config fingerprint ` +
|
|
384
|
+
`${fingerprint} != declared ${profile.configFingerprint}; refusing to fall back`,
|
|
385
|
+
);
|
|
386
|
+
if (!graphAccepts(profile, config))
|
|
387
|
+
throw new Error(
|
|
388
|
+
`model profile ${profile.id} selects ${profile.execution.graph}, which is incompatible with ` +
|
|
389
|
+
`${config.modelType}; refusing to fall back`,
|
|
390
|
+
);
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
profile ??= familyProfile(config, fingerprint);
|
|
394
|
+
validateProfile(profile);
|
|
395
|
+
profile = snapshotProfile(profile);
|
|
396
|
+
|
|
397
|
+
const missing = profile.requiredCapabilities.filter((capability) => !capabilities.has(capability));
|
|
398
|
+
if (missing.length)
|
|
399
|
+
throw new Error(
|
|
400
|
+
`model profile ${profile.id} requires missing engine capabilities: ${missing.join(", ")}; ` +
|
|
401
|
+
`refusing to fall back`,
|
|
402
|
+
);
|
|
403
|
+
|
|
404
|
+
return Object.freeze({
|
|
405
|
+
profile,
|
|
406
|
+
artifact: Object.freeze({ fingerprint: artifactFingerprint, configFingerprint: fingerprint }),
|
|
407
|
+
exactArtifact,
|
|
408
|
+
});
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
/** Guard the factory seam when a caller passes a previously resolved profile. */
|
|
412
|
+
export function assertResolvedModelProfile(
|
|
413
|
+
config: ModelConfig,
|
|
414
|
+
resolved: ResolvedModelProfile,
|
|
415
|
+
): void {
|
|
416
|
+
const fingerprint = configFingerprint(config);
|
|
417
|
+
if (resolved.artifact.configFingerprint !== fingerprint)
|
|
418
|
+
throw new Error(
|
|
419
|
+
`model profile ${resolved.profile.id} was resolved for config ` +
|
|
420
|
+
`${resolved.artifact.configFingerprint}, not ${fingerprint}`,
|
|
421
|
+
);
|
|
422
|
+
if (!graphAccepts(resolved.profile, config))
|
|
423
|
+
throw new Error(
|
|
424
|
+
`model profile ${resolved.profile.id} selects ${resolved.profile.execution.graph}, ` +
|
|
425
|
+
`which is incompatible with ${config.modelType}`,
|
|
426
|
+
);
|
|
427
|
+
if (resolved.exactArtifact &&
|
|
428
|
+
resolved.profile.artifactFingerprint !== resolved.artifact.fingerprint)
|
|
429
|
+
throw new Error(
|
|
430
|
+
`model profile ${resolved.profile.id} does not match artifact ` +
|
|
431
|
+
`${resolved.artifact.fingerprint ?? "<unidentified>"}`,
|
|
432
|
+
);
|
|
433
|
+
}
|