@mlbottleneck/engine 0.4.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/LICENSE +21 -0
- package/README.md +121 -0
- package/localmaxxing-snapshot.json +1 -0
- package/mlbottleneck-engine.d.ts +167 -0
- package/mlbottleneck-engine.mjs +7802 -0
- package/mlbottleneck-engine.umd.js +7810 -0
- package/package.json +49 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Steve Seguin
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
# ML Bottleneck engine SDK
|
|
2
|
+
|
|
3
|
+
The planner's physics engine — decode and prefill rooflines, memory fit, parallelism search, speculative-decoding model, and benchmark calibration — as a dependency-free JavaScript library. It is built from the exact `engine.js` that [mlbottleneck.com](https://mlbottleneck.com) runs, so a third-party page gets the same numbers as the site.
|
|
4
|
+
|
|
5
|
+
## Get it
|
|
6
|
+
|
|
7
|
+
| Channel | How |
|
|
8
|
+
| --- | --- |
|
|
9
|
+
| npm | `npm install @mlbottleneck/engine` → `import { createEngine } from '@mlbottleneck/engine'` (evidence: `import snapshot from '@mlbottleneck/engine/snapshot'`) |
|
|
10
|
+
| Script tag (UMD) | `<script src="https://mlbottleneck.com/dist/mlbottleneck-engine.umd.js"></script>` → `window.MLBottleneck` |
|
|
11
|
+
| ES module | `import { createEngine } from 'https://mlbottleneck.com/dist/mlbottleneck-engine.mjs'` |
|
|
12
|
+
| GitHub release | `sdk-v<version>` releases on the repo carry the tarball, both bundles, the TypeScript types, the evidence snapshot, and checksums |
|
|
13
|
+
| Node | download `dist/` (or the release tarball) and `import('./mlbottleneck-engine.mjs')` / `require('./mlbottleneck-engine.umd.js')` |
|
|
14
|
+
|
|
15
|
+
Benchmark evidence is optional: `dist/localmaxxing-snapshot.json` carries the gold rows the site calibrates against. Without it the engine still predicts from physics and reports `confidence: "uncalibrated"`.
|
|
16
|
+
|
|
17
|
+
## 60-second example
|
|
18
|
+
|
|
19
|
+
```html
|
|
20
|
+
<script src="https://mlbottleneck.com/dist/mlbottleneck-engine.umd.js"></script>
|
|
21
|
+
<script>
|
|
22
|
+
const engine = MLBottleneck.createEngine();
|
|
23
|
+
const result = engine.predict({
|
|
24
|
+
model: 'qwen3.8_27b', // preset key, label, or Hugging Face id
|
|
25
|
+
hardware: { template: 'RTX 3090', count: 2 },
|
|
26
|
+
quantization: 'Q4_K_M', // family ("q4") or format label
|
|
27
|
+
runtime: 'llama_cpp',
|
|
28
|
+
promptTokens: 4096,
|
|
29
|
+
outputTokens: 512
|
|
30
|
+
});
|
|
31
|
+
console.log(result.decode.tokensPerSecond, 'tok/s decode');
|
|
32
|
+
console.log(result.prefill.tokensPerSecond, 'tok/s prefill');
|
|
33
|
+
console.log(result.fits ? 'fits in VRAM' : result.warnings.join(' '));
|
|
34
|
+
</script>
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
With evidence (calibrated expectation, peers, confidence):
|
|
38
|
+
|
|
39
|
+
```js
|
|
40
|
+
import { createEngine } from './mlbottleneck-engine.mjs';
|
|
41
|
+
const snapshot = await fetch('./localmaxxing-snapshot.json').then(r => r.json());
|
|
42
|
+
const engine = createEngine({ snapshot });
|
|
43
|
+
const { ceiling } = engine.predict({ model: 'qwen3.6_35b_a3b', hardware: 'AMD Strix Halo (Ryzen AI Max+ 395)', quantization: 'q4', runtime: 'llama_cpp' });
|
|
44
|
+
// ceiling.expectedTokensPerSecond – engine rate × measured peer correction
|
|
45
|
+
// ceiling.optimizedTokensPerSecond – what a well-tuned run of this stack reaches
|
|
46
|
+
// ceiling.physicalTokensPerSecond – zero-overhead bandwidth roofline
|
|
47
|
+
// ceiling.confidence – 'strong' | 'directional' | 'uncalibrated'
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## `predict(request)`
|
|
51
|
+
|
|
52
|
+
| Field | Type | Notes |
|
|
53
|
+
| --- | --- | --- |
|
|
54
|
+
| `model` | string \| object | Preset key (`listModels()`), or an architecture object: `{ totalParamsB, hiddenSize, numLayers, numHeads, numKVHeads?, intermediateSize?, isMoE?, numExperts?, activeExperts?, activeParamsB?, attentionMechanism?, useMTP? }`. Add `preset: 'qwen3_8b'` to start from a preset and override fields. |
|
|
55
|
+
| `hardware` | string \| object \| array | Template key(s) (`listHardware()`), `{ template, count }`, or a custom device `{ name, memoryGB, localBandwidthGBps, computeTFlops: { float16 }, networkBandwidthGBps? }`. Lookups are case/space-insensitive and accept unique partial names (`'H100 SXM 80GB'`). |
|
|
56
|
+
| `quantization` | string | Family `float32 | float16 | bfloat16 | int8 | fp8 | q6 | q5 | q4 | q3 | q2` or a format label (`Q4_K_M`, `UD-IQ4_XS`, `MXFP4`, `NVFP4`, `AWQ`, `Q8_0`, …) — formats carry their real bits-per-weight. Default `q4`. |
|
|
57
|
+
| `runtime` | string | `auto` (llama.cpp on consumer GPUs, vLLM on data-center NVIDIA, SGLang on Instinct/Gaudi/TPU, MLX on Macs), `llama_cpp`, `ollama`, `mlx`, `vllm`, `sglang`, `tensorrt_llm`, `exo`. |
|
|
58
|
+
| `strategy` | string | `auto` (search), `pipeline`, `tensor`, `data`, `expert`, `sequence`, `context`, `hybrid_tp_pp`, `hybrid_tp_dp`. |
|
|
59
|
+
| `batchSize` | number | Concurrent sequences. `decode.tokensPerSecond` is the aggregate across the batch; `decode.perUserTokensPerSecond` (and `msPerToken`) is what one sequence sees. |
|
|
60
|
+
| `promptTokens`, `outputTokens` | number | The workload. KV memory is sized for prompt + output; the decode rate is read at prompt + output/2. |
|
|
61
|
+
| `speculation` | object | `{ method: 'mtp' | 'dflash' | 'dspark' | 'eagle3' | 'draft_model' | 'ngram' | 'suffix', tokens?, acceptance?, draftRatio? }`. Omitted fields use the method's published defaults. Draft weights and draft KV count toward memory; gains shrink with batch size and context. |
|
|
62
|
+
| `kvCacheCompression` | string | `none`, `q8_kv`, `q4_kv` (llama.cpp `-ctk q8_0` / `q4_0`, vLLM fp8 KV). Compressed KV reads fewer bytes but the decode attention kernel pays a dequantization cost, so deep contexts do not get the full byte saving. |
|
|
63
|
+
| `cpuMoeLayers` | number | MoE only: pin this many layers' routed experts to system RAM (llama.cpp `--n-cpu-moe N`). Default: only what memory forces. |
|
|
64
|
+
| `usage` | object | `{ hoursPerDay, costPerKwh }` for the power/cost estimate. |
|
|
65
|
+
| `includeRaw` | boolean | Attach the full per-device engine output under `result.raw`. |
|
|
66
|
+
|
|
67
|
+
### Result
|
|
68
|
+
|
|
69
|
+
```ts
|
|
70
|
+
{
|
|
71
|
+
fits: boolean, // every device holds its share of weights + KV
|
|
72
|
+
strategy: { key, reasoning, auto },
|
|
73
|
+
decode: { tokensPerSecond, msPerToken, perUserTokensPerSecond, withoutSpeculation, speculationMultiplier },
|
|
74
|
+
prefill: { tokensPerSecond, timeToFirstTokenSeconds },
|
|
75
|
+
ceiling: { physicalTokensPerSecond, // zero-overhead bandwidth/compute roofline
|
|
76
|
+
latencyBoundTokensPerSecond, // roofline plus the irreducible per-layer/per-token floor and coordination
|
|
77
|
+
optimizedTokensPerSecond, // what the best-demonstrated kernel efficiency on this stack reaches
|
|
78
|
+
expectedTokensPerSecond, // engine rate x peer correction (stock software)
|
|
79
|
+
engineTokensPerSecond, correctionFactor, confidence, peers, verifiedPeers },
|
|
80
|
+
memory: { modelSizeGB, residentWeightsGB, kvCacheGB, availableGB },
|
|
81
|
+
bottleneck: 'memory' | 'compute' | 'runtime' | 'coordination' | ..., // devices[].coreBinding adds 'attention' for deep contexts
|
|
82
|
+
power: { watts, tdpWatts, costPerDay, costPer1KTokens },
|
|
83
|
+
devices: [{ name, template, residentWeightGB, kvCacheGB, hasOverflow, overflowMode,
|
|
84
|
+
decodeTokensPerSecond, prefillTokensPerSecond, rooflineTokensPerSecond,
|
|
85
|
+
decodeBreakdownMs: { weightRead, kvRead, compute, runtime, draft, coordination, total } }],
|
|
86
|
+
warnings: string[],
|
|
87
|
+
config: { model, quantization, quantFormat, runtime, batchSize, promptTokens, outputTokens, speculation }
|
|
88
|
+
}
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
Numbers are *planning estimates*: the engine is calibrated so that the median community run lands on its prediction and ~85% land within 1.5×. Show users the ceiling ladder (`physical` → `optimized` → `expected`) rather than a single number when you can.
|
|
92
|
+
|
|
93
|
+
## Other methods
|
|
94
|
+
|
|
95
|
+
- `engine.sweep(request, { levels, maxContext })` — decode/prefill/memory across prompt lengths and concurrency levels (what the site's "How it scales" charts plot).
|
|
96
|
+
- `engine.listModels()` / `engine.listHardware()` — catalogs with sizes, MoE flags, and `supersededBy` for old releases.
|
|
97
|
+
- `engine.setEvidence(snapshot)` — load or replace benchmark evidence after creation.
|
|
98
|
+
- `engine.catalogs` — the raw `MODEL_PRESETS`, `DEVICE_TEMPLATES`, `FRAMEWORK_PROFILES`, `SPECULATION_METHODS`, `QUANT_FORMATS` tables.
|
|
99
|
+
- `engine.engine.*` — lower-level functions with the same signatures as `engine.js` (`calculateMetricsForConfig`, `findOptimalStrategy`, `getSpeculationPlan`, `buildExecutionPlan`, …) for integrations that need the per-device breakdowns.
|
|
100
|
+
|
|
101
|
+
## Deep links into the planner
|
|
102
|
+
|
|
103
|
+
Any site can open the full planner pre-configured (no SDK needed):
|
|
104
|
+
|
|
105
|
+
```
|
|
106
|
+
https://mlbottleneck.com/?model=qwen3.8_27b&hardware=Intel%20Arc%20Pro%20B70&count=2&format=Q4_K_M&runtime=vllm&prompt=4096&output=512&spec=mtp:3#plan
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
`model` (preset key, label, or Hugging Face id), `hardware` (template name, case/space-insensitive), `count`, `quant` (family), `format` (exact quant label), `runtime`, `strategy`, `prompt`, `output`, `batch`, `spec` (`method[:draft tokens]`). Unknown values are ignored; anything recognized opens the prediction step.
|
|
110
|
+
|
|
111
|
+
## Versioning and releases
|
|
112
|
+
|
|
113
|
+
- `package.json` `version` is the SDK version; `engine.version` reports it.
|
|
114
|
+
- `npm test` rebuilds `dist/` from `engine.js` + `sdk/api.js` (and stamps the page's `engine.js?v=<hash>` cache key), so the committed bundle is always the one that passed the suite.
|
|
115
|
+
- Bump the version when the engine, catalogs, or API change; `.github/workflows/release-sdk.yml` then publishes a `sdk-v<version>` GitHub release with the bundles, types, evidence snapshot, and checksums, and `.github/workflows/publish-npm.yml` publishes `dist/` to npm as `@mlbottleneck/engine` (name set by `sdkName` in `package.json`; needs the `NPM_TOKEN` repository secret and a LICENSE). The weekly evidence refresh updates `dist/localmaxxing-snapshot.json` in place without a release.
|
|
116
|
+
|
|
117
|
+
## Limits
|
|
118
|
+
|
|
119
|
+
- Predictions assume the runtime's mainstream kernels (flash attention on, weights resident unless the engine models expert offload or spill).
|
|
120
|
+
- Network-bound multi-node setups use the template's interconnect bandwidth; pass `networkBandwidthGBps` per device for real fabrics.
|
|
121
|
+
- The evidence snapshot is community-submitted (Localmaxxing); `confidence` tells you how much of it applies to your stack.
|