@mlbottleneck/engine 0.4.1 → 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.
- package/README.md +7 -1
- package/localmaxxing-snapshot.json +1 -1
- package/mlbottleneck-engine.d.ts +33 -0
- package/mlbottleneck-engine.mjs +280 -5
- package/mlbottleneck-engine.umd.js +280 -5
- package/package.json +1 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! ML Bottleneck engine v0.
|
|
1
|
+
/*! ML Bottleneck engine v0.5.1 | https://mlbottleneck.com | MIT */
|
|
2
2
|
// Generated by scripts/build-sdk.mjs from engine.js and sdk/api.js. Do not edit.
|
|
3
3
|
(function (root, factory) {
|
|
4
4
|
if (typeof define === 'function' && define.amd) {
|
|
@@ -32,13 +32,22 @@
|
|
|
32
32
|
}
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
-
// Benchmark evidence
|
|
36
|
-
|
|
35
|
+
// Benchmark evidence. Localmaxxing gold rows calibrate the engine (peer
|
|
36
|
+
// correction, optimized target). Lab rows (data/lab-evidence.json, the
|
|
37
|
+
// author's neural.download Intel lab) never calibrate it: they are shown
|
|
38
|
+
// beside a plan as measured references — stock / lab-baseline rows can be
|
|
39
|
+
// the nearest measured run, tuned rows show what a tuned stack reached.
|
|
40
|
+
const ENGINE_EVIDENCE = { goldCases: [], labCases: [] };
|
|
37
41
|
let goldValidationCache = null;
|
|
42
|
+
let labEvidenceCache = null;
|
|
43
|
+
let labValidationCache = null;
|
|
38
44
|
|
|
39
45
|
function setEngineEvidence(snapshot) {
|
|
40
46
|
ENGINE_EVIDENCE.goldCases = Array.isArray(snapshot?.goldCases) ? snapshot.goldCases : [];
|
|
47
|
+
ENGINE_EVIDENCE.labCases = Array.isArray(snapshot?.labCases) ? snapshot.labCases : [];
|
|
41
48
|
goldValidationCache = null;
|
|
49
|
+
labEvidenceCache = null;
|
|
50
|
+
labValidationCache = null;
|
|
42
51
|
}
|
|
43
52
|
|
|
44
53
|
// Nominal storage bytes per weight for each quantization family. Real
|
|
@@ -7366,6 +7375,244 @@
|
|
|
7366
7375
|
}
|
|
7367
7376
|
|
|
7368
7377
|
|
|
7378
|
+
// ---- Lab evidence (neural.download) ------------------------------------
|
|
7379
|
+
const LAB_EVIDENCE_ORIGIN = 'neural.download';
|
|
7380
|
+
const TENSOR_CAPABLE_RUNTIMES = ['vllm', 'sglang', 'tensorrt_llm'];
|
|
7381
|
+
|
|
7382
|
+
// One measured lab point in the shape the gold helpers understand. Depth
|
|
7383
|
+
// sweeps and speculation ladders expand into one row per point so a plan
|
|
7384
|
+
// at 32K depth finds the 32K measurement, not the 128-token one.
|
|
7385
|
+
function normalizeLabEvidenceRow(row, overrides = {}) {
|
|
7386
|
+
const preset = MODEL_PRESETS[row.presetKey];
|
|
7387
|
+
const template = DEVICE_TEMPLATES[row.hardwareTemplate];
|
|
7388
|
+
if (!preset || !template) return null;
|
|
7389
|
+
const format = getQuantFormat(row.quantization);
|
|
7390
|
+
const quantKey = format ? format.family : String(row.quantization || 'q4').toLowerCase();
|
|
7391
|
+
const promptTokens = Number.isFinite(overrides.promptTokens) ? overrides.promptTokens : (Number.isFinite(row.promptTokens) ? row.promptTokens : 128);
|
|
7392
|
+
const outputTokens = Number.isFinite(row.outputTokens) && row.outputTokens > 0 ? row.outputTokens : 128;
|
|
7393
|
+
const speculation = overrides.speculation !== undefined ? overrides.speculation : (row.speculation || null);
|
|
7394
|
+
const observedTokS = Number.isFinite(overrides.observedTokS) ? overrides.observedTokS : row.observedTokS;
|
|
7395
|
+
if (!Number.isFinite(observedTokS) || observedTokS <= 0) return null;
|
|
7396
|
+
const batchSize = Math.max(1, Number(overrides.batchSize) || 1);
|
|
7397
|
+
const deviceCount = Math.max(1, Number(row.deviceCount) || 1);
|
|
7398
|
+
const runtime = FRAMEWORK_PROFILES[row.runtimeKey];
|
|
7399
|
+
const strategy = row.strategy || (deviceCount > 1 ? (TENSOR_CAPABLE_RUNTIMES.includes(row.runtimeKey) ? 'tensor' : 'pipeline') : 'pipeline');
|
|
7400
|
+
return {
|
|
7401
|
+
id: overrides.id || row.id,
|
|
7402
|
+
origin: LAB_EVIDENCE_ORIGIN,
|
|
7403
|
+
isLab: true,
|
|
7404
|
+
stack: row.stack || 'stock',
|
|
7405
|
+
source: row.url || '',
|
|
7406
|
+
url: row.url || '',
|
|
7407
|
+
note: row.note || '',
|
|
7408
|
+
model: preset.label || row.presetKey,
|
|
7409
|
+
hfId: preset.hfId || '',
|
|
7410
|
+
presetKey: row.presetKey,
|
|
7411
|
+
hardware: template.name || row.hardwareTemplate,
|
|
7412
|
+
hardwareTemplate: row.hardwareTemplate,
|
|
7413
|
+
deviceCount,
|
|
7414
|
+
runtimeKey: row.runtimeKey,
|
|
7415
|
+
engine: runtime ? runtime.label : row.runtimeKey,
|
|
7416
|
+
quantization: row.quantization || quantKey,
|
|
7417
|
+
quantKey,
|
|
7418
|
+
strategy,
|
|
7419
|
+
speculation,
|
|
7420
|
+
promptTokens,
|
|
7421
|
+
outputTokens,
|
|
7422
|
+
contextLength: promptTokens + outputTokens,
|
|
7423
|
+
decodeContextTokens: promptTokens + outputTokens / 2,
|
|
7424
|
+
// Per-request decode rate (one sequence's tokens per second); the
|
|
7425
|
+
// aggregate across a batched run is kept separately.
|
|
7426
|
+
observedTokS,
|
|
7427
|
+
batchSize,
|
|
7428
|
+
aggregateTokS: Number.isFinite(overrides.aggregateTokS) ? overrides.aggregateTokS : observedTokS * batchSize,
|
|
7429
|
+
prefillTokS: Number.isFinite(overrides.prefillTokS) ? overrides.prefillTokS : (Number.isFinite(row.prefillTokS) ? row.prefillTokS : null),
|
|
7430
|
+
reproducibility: 1
|
|
7431
|
+
};
|
|
7432
|
+
}
|
|
7433
|
+
|
|
7434
|
+
function getLabEvidenceRows() {
|
|
7435
|
+
if (labEvidenceCache) return labEvidenceCache;
|
|
7436
|
+
const rows = [];
|
|
7437
|
+
for (const row of ENGINE_EVIDENCE.labCases || []) {
|
|
7438
|
+
if (!row || typeof row !== 'object' || !row.id) continue;
|
|
7439
|
+
const base = normalizeLabEvidenceRow(row);
|
|
7440
|
+
if (base) rows.push(base);
|
|
7441
|
+
for (const point of Array.isArray(row.depthSweep) ? row.depthSweep : []) {
|
|
7442
|
+
const swept = normalizeLabEvidenceRow(row, {
|
|
7443
|
+
id: `${row.id}@${point.promptTokens}`,
|
|
7444
|
+
promptTokens: point.promptTokens,
|
|
7445
|
+
observedTokS: point.decodeTokS,
|
|
7446
|
+
prefillTokS: point.prefillTokS
|
|
7447
|
+
});
|
|
7448
|
+
if (swept) rows.push(swept);
|
|
7449
|
+
}
|
|
7450
|
+
for (const rung of Array.isArray(row.speculationLadder) ? row.speculationLadder : []) {
|
|
7451
|
+
const stepped = normalizeLabEvidenceRow(row, {
|
|
7452
|
+
id: `${row.id}@${rung.method}${rung.tokens}`,
|
|
7453
|
+
speculation: { method: rung.method, tokens: rung.tokens },
|
|
7454
|
+
observedTokS: rung.observedTokS
|
|
7455
|
+
});
|
|
7456
|
+
if (stepped) rows.push(stepped);
|
|
7457
|
+
}
|
|
7458
|
+
// Concurrency sweeps: { users, perUserTokS, aggregateTokS } per level
|
|
7459
|
+
// (llama-batched-bench -npl / vllm bench serve --max-concurrency).
|
|
7460
|
+
for (const level of Array.isArray(row.concurrencySweep) ? row.concurrencySweep : []) {
|
|
7461
|
+
const users = Math.max(1, Number(level.users) || 1);
|
|
7462
|
+
const perUser = Number.isFinite(level.perUserTokS) ? level.perUserTokS : (Number.isFinite(level.aggregateTokS) ? level.aggregateTokS / users : NaN);
|
|
7463
|
+
const batched = normalizeLabEvidenceRow(row, {
|
|
7464
|
+
id: `${row.id}@u${users}`,
|
|
7465
|
+
batchSize: users,
|
|
7466
|
+
observedTokS: perUser,
|
|
7467
|
+
aggregateTokS: Number.isFinite(level.aggregateTokS) ? level.aggregateTokS : perUser * users
|
|
7468
|
+
});
|
|
7469
|
+
if (batched) rows.push(batched);
|
|
7470
|
+
}
|
|
7471
|
+
}
|
|
7472
|
+
labEvidenceCache = rows;
|
|
7473
|
+
return rows;
|
|
7474
|
+
}
|
|
7475
|
+
|
|
7476
|
+
// Rows that can stand in as the plan's "nearest measured" run: community
|
|
7477
|
+
// gold runs plus the lab's stock / baseline rows without speculation. A
|
|
7478
|
+
// tuned stack is not a stock reference.
|
|
7479
|
+
function getMeasuredReferenceRows() {
|
|
7480
|
+
return getGoldValidationRows().concat(getLabEvidenceRows().filter(row => row.stack !== 'tuned' && !row.speculation));
|
|
7481
|
+
}
|
|
7482
|
+
|
|
7483
|
+
function describeSameSetup(target, row) {
|
|
7484
|
+
return row.runtimeKey === target.runtimeKey && row.quantKey === target.quantKey &&
|
|
7485
|
+
(row.deviceCount || 1) === (target.deviceCount || 1);
|
|
7486
|
+
}
|
|
7487
|
+
|
|
7488
|
+
// A reference run must serve the same number of concurrent requests as
|
|
7489
|
+
// the plan: per-request decode at 16 users says nothing about one user.
|
|
7490
|
+
function sameBatch(target, row) {
|
|
7491
|
+
return (row.batchSize || 1) === (target.batchSize || 1);
|
|
7492
|
+
}
|
|
7493
|
+
|
|
7494
|
+
function depthDistance(target, row) {
|
|
7495
|
+
const targetDepth = Math.max(64, Number.isFinite(target.decodeContextTokens) ? target.decodeContextTokens : (target.contextLength || 64));
|
|
7496
|
+
const rowDepth = Math.max(64, Number.isFinite(row.decodeContextTokens) ? row.decodeContextTokens : (row.contextLength || 64));
|
|
7497
|
+
return Math.abs(Math.log(targetDepth / rowDepth));
|
|
7498
|
+
}
|
|
7499
|
+
|
|
7500
|
+
// Closest measured run for the ladder: same preset and hardware template
|
|
7501
|
+
// are required; runtime, quantization, device count, and decode depth
|
|
7502
|
+
// refine the choice. Community runs and lab stock rows compete equally.
|
|
7503
|
+
function findNearestMeasuredRun(target) {
|
|
7504
|
+
if (!target?.presetKey || !target.hardwareTemplate) return null;
|
|
7505
|
+
const candidates = getMeasuredReferenceRows()
|
|
7506
|
+
.filter(row => row.presetKey === target.presetKey && row.hardwareTemplate === target.hardwareTemplate && sameBatch(target, row))
|
|
7507
|
+
.map(row => ({ row, score: getGoldSimilarity(target, row) }))
|
|
7508
|
+
.sort((a, b) => b.score - a.score ||
|
|
7509
|
+
depthDistance(target, a.row) - depthDistance(target, b.row) ||
|
|
7510
|
+
(b.row.reproducibility || 0) - (a.row.reproducibility || 0));
|
|
7511
|
+
const best = candidates[0];
|
|
7512
|
+
if (!best) return null;
|
|
7513
|
+
return { ...best.row, sameSetup: describeSameSetup(target, best.row), similarity: best.score };
|
|
7514
|
+
}
|
|
7515
|
+
|
|
7516
|
+
// The tuned lab result closest to this plan on the same machine (same
|
|
7517
|
+
// hardware template and device count — a different card count is a
|
|
7518
|
+
// different roofline); runtime, quantization, and depth refine the
|
|
7519
|
+
// choice and ties go to the faster run. Labeled as tuned, never used as
|
|
7520
|
+
// a stock reference.
|
|
7521
|
+
function findLabTunedRun(target) {
|
|
7522
|
+
if (!target?.presetKey || !target.hardwareTemplate) return null;
|
|
7523
|
+
const candidates = getLabEvidenceRows()
|
|
7524
|
+
.filter(row => row.stack === 'tuned' && row.presetKey === target.presetKey &&
|
|
7525
|
+
row.hardwareTemplate === target.hardwareTemplate && (row.deviceCount || 1) === (target.deviceCount || 1) && sameBatch(target, row))
|
|
7526
|
+
.map(row => ({ row, score: getGoldSimilarity(target, row) }))
|
|
7527
|
+
.sort((a, b) => b.score - a.score ||
|
|
7528
|
+
depthDistance(target, a.row) - depthDistance(target, b.row) ||
|
|
7529
|
+
b.row.observedTokS - a.row.observedTokS);
|
|
7530
|
+
const best = candidates[0];
|
|
7531
|
+
if (!best) return null;
|
|
7532
|
+
return { ...best.row, sameSetup: describeSameSetup(target, best.row), similarity: best.score };
|
|
7533
|
+
}
|
|
7534
|
+
|
|
7535
|
+
function buildEvidenceTarget(modelConfig, devicesArray, metrics = null) {
|
|
7536
|
+
return {
|
|
7537
|
+
hfId: modelConfig.hfId,
|
|
7538
|
+
presetKey: modelConfig.modelPreset,
|
|
7539
|
+
hardwareTemplate: devicesArray[0]?.template || '',
|
|
7540
|
+
runtimeKey: getFrameworkProfile(modelConfig, devicesArray).key,
|
|
7541
|
+
quantKey: modelConfig.quantizationType,
|
|
7542
|
+
quantization: modelConfig.quantFormat || '',
|
|
7543
|
+
deviceCount: devicesArray.length,
|
|
7544
|
+
contextLength: modelConfig.seqLength,
|
|
7545
|
+
decodeContextTokens: getDecodeContextTokens(modelConfig),
|
|
7546
|
+
hasOverflow: Array.isArray(metrics) ? metrics.some(metric => metric.hasOverflow) : false,
|
|
7547
|
+
batchSize: modelConfig.batchSize || 1
|
|
7548
|
+
};
|
|
7549
|
+
}
|
|
7550
|
+
|
|
7551
|
+
// The engine's view of one lab row in the row's own setup (speculation
|
|
7552
|
+
// included when the row used it): stock projection, optimized target, and
|
|
7553
|
+
// physical roofline. Stock rows show how the engine tracks the lab's
|
|
7554
|
+
// hardware; tuned rows show how much of the optimized target a tuned
|
|
7555
|
+
// stack actually reached.
|
|
7556
|
+
function calculateLabCaseProjection(row) {
|
|
7557
|
+
const preset = MODEL_PRESETS[row.presetKey];
|
|
7558
|
+
const template = DEVICE_TEMPLATES[row.hardwareTemplate];
|
|
7559
|
+
if (!preset || !template || !DTYPE_SIZES[row.quantKey]) return null;
|
|
7560
|
+
const devices = Array.from({ length: row.deviceCount }, (_, index) => ({
|
|
7561
|
+
id: index + 1,
|
|
7562
|
+
template: row.hardwareTemplate,
|
|
7563
|
+
name: `${template.name || row.hardwareTemplate}${row.deviceCount > 1 ? ` #${index + 1}` : ''}`,
|
|
7564
|
+
...JSON.parse(JSON.stringify(template))
|
|
7565
|
+
}));
|
|
7566
|
+
const strategy = row.strategy;
|
|
7567
|
+
const spec = row.speculation;
|
|
7568
|
+
const modelConfig = normalizeModelConfig({
|
|
7569
|
+
...preset,
|
|
7570
|
+
modelPreset: row.presetKey,
|
|
7571
|
+
quantizationType: row.quantKey,
|
|
7572
|
+
quantFormat: getQuantFormat(row.quantization) ? row.quantization : '',
|
|
7573
|
+
runtimeFramework: row.runtimeKey,
|
|
7574
|
+
parallelismStrategy: strategy,
|
|
7575
|
+
optimizationMode: spec ? 'speculative' : 'none',
|
|
7576
|
+
specMethod: spec ? spec.method : 'mtp',
|
|
7577
|
+
specTokens: spec ? spec.tokens : null,
|
|
7578
|
+
specAcceptance: null,
|
|
7579
|
+
specDraftRatio: spec && Number.isFinite(spec.draftRatio) ? spec.draftRatio : null,
|
|
7580
|
+
kvCacheCompression: 'none',
|
|
7581
|
+
batchSize: row.batchSize || 1,
|
|
7582
|
+
promptTokens: row.promptTokens,
|
|
7583
|
+
outputTokens: row.outputTokens,
|
|
7584
|
+
seqLength: row.promptTokens + row.outputTokens
|
|
7585
|
+
});
|
|
7586
|
+
const metrics = calculateMetricsForConfig(modelConfig, devices);
|
|
7587
|
+
const genericTokS = calculateSystemRateFromDeviceRates(metrics.map(metric => metric.decodeTokensPerSecond), strategy, row.batchSize || 1, devices, getSystemRateOptions(modelConfig));
|
|
7588
|
+
const prefillProjectedTokS = getSystemPrefillRateForMetrics(modelConfig, metrics, devices, strategy);
|
|
7589
|
+
const calibration = calculateCurrentCalibration(modelConfig, metrics, genericTokS, strategy, devices);
|
|
7590
|
+
if (!calibration || !Number.isFinite(genericTokS) || genericTokS <= 0) return null;
|
|
7591
|
+
return {
|
|
7592
|
+
...row,
|
|
7593
|
+
genericTokS,
|
|
7594
|
+
prefillProjectedTokS,
|
|
7595
|
+
expectedTokS: calibration.expectedTokS,
|
|
7596
|
+
optimizedTokS: calibration.optimizedTokS,
|
|
7597
|
+
physicalTokS: calibration.physicalTokS,
|
|
7598
|
+
latencyBoundTokS: calibration.latencyBoundTokS,
|
|
7599
|
+
calibrationPeers: calibration.peers,
|
|
7600
|
+
confidence: calibration.confidence,
|
|
7601
|
+
observedToGeneric: row.observedTokS / genericTokS,
|
|
7602
|
+
observedToExpected: row.observedTokS / calibration.expectedTokS,
|
|
7603
|
+
observedToOptimized: row.observedTokS / calibration.optimizedTokS,
|
|
7604
|
+
observedToPhysical: row.observedTokS / calibration.physicalTokS,
|
|
7605
|
+
hasOverflow: metrics.some(metric => metric.hasOverflow)
|
|
7606
|
+
};
|
|
7607
|
+
}
|
|
7608
|
+
|
|
7609
|
+
function getLabValidationRows() {
|
|
7610
|
+
if (labValidationCache) return labValidationCache;
|
|
7611
|
+
labValidationCache = getLabEvidenceRows().map(calculateLabCaseProjection).filter(Boolean);
|
|
7612
|
+
return labValidationCache;
|
|
7613
|
+
}
|
|
7614
|
+
|
|
7615
|
+
|
|
7369
7616
|
function calculateCurrentCalibration(modelConfig, metrics, genericSystemRate, strategy, devicesArray = null) {
|
|
7370
7617
|
const devices = devicesArray || defaultDevices();
|
|
7371
7618
|
if (!metrics?.length || !Number.isFinite(genericSystemRate)) return null;
|
|
@@ -7678,6 +7925,7 @@
|
|
|
7678
7925
|
}
|
|
7679
7926
|
const power = calculatePowerAndCost(devices, aggregateDecode, metrics, request.usage || {});
|
|
7680
7927
|
const speculationActive = Boolean(primary?.speculation && primary.speculationMultiplier > 1);
|
|
7928
|
+
const evidenceTarget = buildEvidenceTarget(config, devices, metrics);
|
|
7681
7929
|
return {
|
|
7682
7930
|
fits,
|
|
7683
7931
|
strategy: { key: strategy, label: strategy, reasoning: strategyInfo?.reasoning || null, auto: Boolean(strategyInfo) },
|
|
@@ -7711,6 +7959,10 @@
|
|
|
7711
7959
|
kvCacheGB: sdkRound(metrics.reduce((sum, metric) => sum + (metric.residentKvCacheGB || 0), 0), 2),
|
|
7712
7960
|
availableGB: sdkRound(devices.reduce((sum, device) => sum + (parseFloat(device.memoryGB) || 0), 0), 1)
|
|
7713
7961
|
},
|
|
7962
|
+
measured: {
|
|
7963
|
+
nearest: sdkSummarizeMeasuredRun(findNearestMeasuredRun(evidenceTarget)),
|
|
7964
|
+
labTuned: sdkSummarizeMeasuredRun(findLabTunedRun(evidenceTarget))
|
|
7965
|
+
},
|
|
7714
7966
|
bottleneck: primary?.decodeTimeBreakdown?.dominant || null,
|
|
7715
7967
|
power: power ? { watts: sdkRound(power.actualPowerWatts, 0), tdpWatts: sdkRound(power.totalTDP, 0), costPerDay: sdkRound(power.dailyCost, 3), costPer1KTokens: sdkRound(power.costPer1KTokens, 5) } : null,
|
|
7716
7968
|
devices: metrics.map((metric, index) => sdkSummarizeDevice(metric, devices[index])),
|
|
@@ -7740,6 +7992,29 @@
|
|
|
7740
7992
|
};
|
|
7741
7993
|
}
|
|
7742
7994
|
|
|
7995
|
+
// A measured reference run (community gold row or neural.download lab row)
|
|
7996
|
+
// in a stable shape; null when nothing on the same model + hardware exists.
|
|
7997
|
+
function sdkSummarizeMeasuredRun(row) {
|
|
7998
|
+
if (!row) return null;
|
|
7999
|
+
return {
|
|
8000
|
+
tokensPerSecond: sdkRound(row.observedTokS, 2),
|
|
8001
|
+
origin: row.isLab ? 'lab' : 'community',
|
|
8002
|
+
stack: row.isLab ? row.stack : 'stock',
|
|
8003
|
+
model: row.model,
|
|
8004
|
+
hardware: row.hardware,
|
|
8005
|
+
deviceCount: row.deviceCount || 1,
|
|
8006
|
+
runtime: row.runtimeKey,
|
|
8007
|
+
quantization: row.quantization || row.quantKey,
|
|
8008
|
+
depthTokens: Math.round(row.decodeContextTokens || row.contextLength || 0),
|
|
8009
|
+
concurrency: row.batchSize || 1,
|
|
8010
|
+
aggregateTokensPerSecond: sdkRound(row.aggregateTokS || row.observedTokS * (row.batchSize || 1), 2),
|
|
8011
|
+
speculation: row.speculation ? { method: row.speculation.method, tokens: row.speculation.tokens ?? null } : null,
|
|
8012
|
+
sameSetup: Boolean(row.sameSetup),
|
|
8013
|
+
url: row.source || row.url || null,
|
|
8014
|
+
note: row.note || null
|
|
8015
|
+
};
|
|
8016
|
+
}
|
|
8017
|
+
|
|
7743
8018
|
function listModels() {
|
|
7744
8019
|
return Object.entries(MODEL_PRESETS).map(([key, preset]) => ({
|
|
7745
8020
|
key,
|
|
@@ -7801,10 +8076,10 @@
|
|
|
7801
8076
|
|
|
7802
8077
|
if (options.snapshot) setEngineEvidence(options.snapshot);
|
|
7803
8078
|
const api = createApi();
|
|
7804
|
-
api.version = "0.
|
|
8079
|
+
api.version = "0.5.1";
|
|
7805
8080
|
api.evidenceGeneratedAt = options.snapshot?.generatedAt || null;
|
|
7806
8081
|
return api;
|
|
7807
8082
|
}
|
|
7808
8083
|
|
|
7809
|
-
return { createEngine, version: "0.
|
|
8084
|
+
return { createEngine, version: "0.5.1" };
|
|
7810
8085
|
}));
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mlbottleneck/engine",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.1",
|
|
4
4
|
"description": "Physics-based LLM inference planner: decode/prefill tokens per second, memory fit, multi-GPU strategy, and speculative-decoding gains for any model on any hardware, calibrated on community benchmarks.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"llm",
|