ai-speedometer 2.1.2 → 2.1.5
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/dist/ai-speedometer +120 -44
- package/package.json +8 -13
- package/README.md +0 -127
- package/ai-benchmark-config.json.template +0 -21
- package/dist/ai-speedometer-headless +0 -941
- package/docs/README.md +0 -191
- package/docs/custom-verified-providers.md +0 -463
- package/docs/models-dev-integration.md +0 -488
- package/docs/publish-and-build.md +0 -68
- package/docs/token-counting-fallback.md +0 -345
- package/scripts/shebang +0 -6
package/dist/ai-speedometer
CHANGED
|
@@ -17,7 +17,7 @@ var __export = (target, all) => {
|
|
|
17
17
|
};
|
|
18
18
|
var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
|
|
19
19
|
|
|
20
|
-
// custom-verified-providers.json
|
|
20
|
+
// ../core/custom-verified-providers.json
|
|
21
21
|
var custom_verified_providers_default;
|
|
22
22
|
var init_custom_verified_providers = __esm(() => {
|
|
23
23
|
custom_verified_providers_default = {
|
|
@@ -142,7 +142,7 @@ var init_custom_verified_providers = __esm(() => {
|
|
|
142
142
|
};
|
|
143
143
|
});
|
|
144
144
|
|
|
145
|
-
// src/models-dev.ts
|
|
145
|
+
// ../core/src/models-dev.ts
|
|
146
146
|
var exports_models_dev = {};
|
|
147
147
|
__export(exports_models_dev, {
|
|
148
148
|
transformModelsDevData: () => transformModelsDevData,
|
|
@@ -387,7 +387,7 @@ var init_models_dev = __esm(() => {
|
|
|
387
387
|
];
|
|
388
388
|
});
|
|
389
389
|
|
|
390
|
-
// src/ai-config.ts
|
|
390
|
+
// ../core/src/ai-config.ts
|
|
391
391
|
var exports_ai_config = {};
|
|
392
392
|
__export(exports_ai_config, {
|
|
393
393
|
writeAIConfig: () => writeAIConfig,
|
|
@@ -558,7 +558,7 @@ var getAIConfigPaths = () => {
|
|
|
558
558
|
};
|
|
559
559
|
var init_ai_config = () => {};
|
|
560
560
|
|
|
561
|
-
// node_modules/jsonc-parser/lib/esm/impl/scanner.js
|
|
561
|
+
// ../../node_modules/.bun/jsonc-parser@3.3.1/node_modules/jsonc-parser/lib/esm/impl/scanner.js
|
|
562
562
|
function createScanner(text, ignoreTrivia = false) {
|
|
563
563
|
const len = text.length;
|
|
564
564
|
let pos = 0, value = "", tokenOffset = 0, token = 16, lineNumber = 0, lineStartOffset = 0, tokenLineStartOffset = 0, prevTokenLineStartOffset = 0, scanError = 0;
|
|
@@ -975,7 +975,7 @@ var init_scanner = __esm(() => {
|
|
|
975
975
|
})(CharacterCodes || (CharacterCodes = {}));
|
|
976
976
|
});
|
|
977
977
|
|
|
978
|
-
// node_modules/jsonc-parser/lib/esm/impl/string-intern.js
|
|
978
|
+
// ../../node_modules/.bun/jsonc-parser@3.3.1/node_modules/jsonc-parser/lib/esm/impl/string-intern.js
|
|
979
979
|
var cachedSpaces, maxCachedValues = 200, cachedBreakLinesWithSpaces;
|
|
980
980
|
var init_string_intern = __esm(() => {
|
|
981
981
|
cachedSpaces = new Array(20).fill(0).map((_, index) => {
|
|
@@ -1011,13 +1011,13 @@ var init_string_intern = __esm(() => {
|
|
|
1011
1011
|
};
|
|
1012
1012
|
});
|
|
1013
1013
|
|
|
1014
|
-
// node_modules/jsonc-parser/lib/esm/impl/format.js
|
|
1014
|
+
// ../../node_modules/.bun/jsonc-parser@3.3.1/node_modules/jsonc-parser/lib/esm/impl/format.js
|
|
1015
1015
|
var init_format = __esm(() => {
|
|
1016
1016
|
init_scanner();
|
|
1017
1017
|
init_string_intern();
|
|
1018
1018
|
});
|
|
1019
1019
|
|
|
1020
|
-
// node_modules/jsonc-parser/lib/esm/impl/parser.js
|
|
1020
|
+
// ../../node_modules/.bun/jsonc-parser@3.3.1/node_modules/jsonc-parser/lib/esm/impl/parser.js
|
|
1021
1021
|
function parse(text, errors = [], options = ParseOptions.DEFAULT) {
|
|
1022
1022
|
let currentProperty = null;
|
|
1023
1023
|
let currentParent = [];
|
|
@@ -1323,13 +1323,13 @@ var init_parser = __esm(() => {
|
|
|
1323
1323
|
})(ParseOptions || (ParseOptions = {}));
|
|
1324
1324
|
});
|
|
1325
1325
|
|
|
1326
|
-
// node_modules/jsonc-parser/lib/esm/impl/edit.js
|
|
1326
|
+
// ../../node_modules/.bun/jsonc-parser@3.3.1/node_modules/jsonc-parser/lib/esm/impl/edit.js
|
|
1327
1327
|
var init_edit = __esm(() => {
|
|
1328
1328
|
init_format();
|
|
1329
1329
|
init_parser();
|
|
1330
1330
|
});
|
|
1331
1331
|
|
|
1332
|
-
// node_modules/jsonc-parser/lib/esm/main.js
|
|
1332
|
+
// ../../node_modules/.bun/jsonc-parser@3.3.1/node_modules/jsonc-parser/lib/esm/main.js
|
|
1333
1333
|
var ScanError, SyntaxKind, parse2, ParseErrorCode;
|
|
1334
1334
|
var init_main = __esm(() => {
|
|
1335
1335
|
init_format();
|
|
@@ -1385,7 +1385,7 @@ var init_main = __esm(() => {
|
|
|
1385
1385
|
})(ParseErrorCode || (ParseErrorCode = {}));
|
|
1386
1386
|
});
|
|
1387
1387
|
|
|
1388
|
-
// src/opencode-integration.ts
|
|
1388
|
+
// ../core/src/opencode-integration.ts
|
|
1389
1389
|
var exports_opencode_integration = {};
|
|
1390
1390
|
__export(exports_opencode_integration, {
|
|
1391
1391
|
writeOpencodeConfig: () => writeOpencodeConfig,
|
|
@@ -1704,10 +1704,10 @@ var init_opencode_integration = __esm(() => {
|
|
|
1704
1704
|
init_main();
|
|
1705
1705
|
});
|
|
1706
1706
|
|
|
1707
|
-
// src/constants.ts
|
|
1707
|
+
// ../core/src/constants.ts
|
|
1708
1708
|
var TEST_PROMPT = `make a 300 word story`;
|
|
1709
1709
|
|
|
1710
|
-
// src/benchmark.ts
|
|
1710
|
+
// ../core/src/benchmark.ts
|
|
1711
1711
|
var exports_benchmark = {};
|
|
1712
1712
|
__export(exports_benchmark, {
|
|
1713
1713
|
benchmarkSingleModelRest: () => benchmarkSingleModelRest
|
|
@@ -1777,8 +1777,22 @@ async function benchmarkSingleModelRest(model) {
|
|
|
1777
1777
|
body: JSON.stringify(body)
|
|
1778
1778
|
});
|
|
1779
1779
|
if (!response.ok) {
|
|
1780
|
-
await response.text();
|
|
1781
|
-
|
|
1780
|
+
const errBody = await response.text();
|
|
1781
|
+
let errDetail = "";
|
|
1782
|
+
try {
|
|
1783
|
+
const parsed = JSON.parse(errBody);
|
|
1784
|
+
if (typeof parsed.error === "object" && parsed.error?.message)
|
|
1785
|
+
errDetail = parsed.error.message;
|
|
1786
|
+
else if (typeof parsed.error === "string")
|
|
1787
|
+
errDetail = parsed.error;
|
|
1788
|
+
else if (parsed.message)
|
|
1789
|
+
errDetail = parsed.message;
|
|
1790
|
+
else
|
|
1791
|
+
errDetail = errBody.slice(0, 200);
|
|
1792
|
+
} catch {
|
|
1793
|
+
errDetail = errBody.slice(0, 200);
|
|
1794
|
+
}
|
|
1795
|
+
throw new Error(`${response.status} ${response.statusText}${errDetail ? ": " + errDetail : ""}`);
|
|
1782
1796
|
}
|
|
1783
1797
|
const reader = response.body.getReader();
|
|
1784
1798
|
const decoder = new TextDecoder;
|
|
@@ -1904,7 +1918,7 @@ async function benchmarkSingleModelRest(model) {
|
|
|
1904
1918
|
}
|
|
1905
1919
|
var init_benchmark = () => {};
|
|
1906
1920
|
|
|
1907
|
-
// src/headless.ts
|
|
1921
|
+
// ../core/src/headless.ts
|
|
1908
1922
|
var exports_headless = {};
|
|
1909
1923
|
__export(exports_headless, {
|
|
1910
1924
|
runHeadlessBenchmark: () => runHeadlessBenchmark
|
|
@@ -2161,25 +2175,20 @@ var package_default;
|
|
|
2161
2175
|
var init_package = __esm(() => {
|
|
2162
2176
|
package_default = {
|
|
2163
2177
|
name: "ai-speedometer",
|
|
2164
|
-
version: "2.1.
|
|
2178
|
+
version: "2.1.5",
|
|
2165
2179
|
description: "A comprehensive CLI tool for benchmarking AI models across multiple providers with parallel execution and professional metrics",
|
|
2166
2180
|
bin: {
|
|
2167
2181
|
"ai-speedometer": "dist/ai-speedometer",
|
|
2168
|
-
aispeed: "dist/ai-speedometer"
|
|
2169
|
-
"ai-speedometer-headless": "dist/ai-speedometer-headless"
|
|
2182
|
+
aispeed: "dist/ai-speedometer"
|
|
2170
2183
|
},
|
|
2171
2184
|
engines: {
|
|
2172
|
-
bun: ">=1.0.0"
|
|
2173
|
-
node: ">=18.0.0"
|
|
2185
|
+
bun: ">=1.0.0"
|
|
2174
2186
|
},
|
|
2175
2187
|
scripts: {
|
|
2176
2188
|
start: "bun src/index.ts",
|
|
2177
2189
|
dev: "bun --watch src/index.ts",
|
|
2178
|
-
|
|
2179
|
-
"test:watch": "bun test --watch",
|
|
2180
|
-
"test:update": "bun test --update-snapshots",
|
|
2190
|
+
build: "bun build src/index.ts --outdir dist --target bun --external '@opentui/core' --external '@opentui/react' --external 'react' --external 'react-reconciler' && cat ../../scripts/shebang dist/index.js > dist/ai-speedometer && chmod +x dist/ai-speedometer && rm dist/index.js",
|
|
2181
2191
|
typecheck: "bun tsc --noEmit",
|
|
2182
|
-
build: "bun build src/index.ts --outdir dist --target bun --external '@opentui/core' --external '@opentui/react' --external 'react' --external 'react-reconciler' && cat scripts/shebang dist/index.js > dist/ai-speedometer && chmod +x dist/ai-speedometer && rm dist/index.js && bun build src/headless-entry.ts --outdir dist --target node --external 'jsonc-parser' && mv dist/headless-entry.js dist/ai-speedometer-headless && chmod +x dist/ai-speedometer-headless",
|
|
2183
2192
|
prepublishOnly: "bun run build"
|
|
2184
2193
|
},
|
|
2185
2194
|
keywords: [
|
|
@@ -2209,10 +2218,9 @@ var init_package = __esm(() => {
|
|
|
2209
2218
|
homepage: "https://github.com/aptdnfapt/Ai-speedometer#readme",
|
|
2210
2219
|
files: [
|
|
2211
2220
|
"dist/",
|
|
2212
|
-
"docs/",
|
|
2213
|
-
"
|
|
2214
|
-
"
|
|
2215
|
-
"ai-benchmark-config.json.template"
|
|
2221
|
+
"../../docs/",
|
|
2222
|
+
"../../README.md",
|
|
2223
|
+
"../../ai-benchmark-config.json.template"
|
|
2216
2224
|
],
|
|
2217
2225
|
dependencies: {
|
|
2218
2226
|
"@opentui/core": "0.1.79",
|
|
@@ -2221,6 +2229,7 @@ var init_package = __esm(() => {
|
|
|
2221
2229
|
"react-reconciler": "^0.32.0"
|
|
2222
2230
|
},
|
|
2223
2231
|
devDependencies: {
|
|
2232
|
+
"@ai-speedometer/core": "workspace:*",
|
|
2224
2233
|
"jsonc-parser": "^3.3.1"
|
|
2225
2234
|
}
|
|
2226
2235
|
};
|
|
@@ -2619,7 +2628,7 @@ function ModelSelectScreen() {
|
|
|
2619
2628
|
navigate("benchmark");
|
|
2620
2629
|
}, [dispatch, navigate]);
|
|
2621
2630
|
usePaste((text) => {
|
|
2622
|
-
setSearchQuery((q) => q + text);
|
|
2631
|
+
setSearchQuery((q) => q + text.replace(/[\r\n]/g, ""));
|
|
2623
2632
|
});
|
|
2624
2633
|
useKeyboard4((key) => {
|
|
2625
2634
|
if (key.name === "escape") {
|
|
@@ -3312,6 +3321,68 @@ function BenchmarkScreen() {
|
|
|
3312
3321
|
}, `ttft-${s.model.id}-${s.model.providerId}`, true, undefined, this));
|
|
3313
3322
|
}
|
|
3314
3323
|
}
|
|
3324
|
+
if (allDone && errors.length > 0) {
|
|
3325
|
+
rows.push(/* @__PURE__ */ jsxDEV10("box", {
|
|
3326
|
+
height: 1,
|
|
3327
|
+
backgroundColor: "#292e42"
|
|
3328
|
+
}, "div-errors", false, undefined, this));
|
|
3329
|
+
rows.push(/* @__PURE__ */ jsxDEV10("box", {
|
|
3330
|
+
height: 1,
|
|
3331
|
+
flexDirection: "row",
|
|
3332
|
+
paddingLeft: 1,
|
|
3333
|
+
children: /* @__PURE__ */ jsxDEV10("text", {
|
|
3334
|
+
fg: "#f7768e",
|
|
3335
|
+
children: [
|
|
3336
|
+
" FAILED (",
|
|
3337
|
+
errors.length,
|
|
3338
|
+
") "
|
|
3339
|
+
]
|
|
3340
|
+
}, undefined, true, undefined, this)
|
|
3341
|
+
}, "hdr-errors", false, undefined, this));
|
|
3342
|
+
for (const s of errors) {
|
|
3343
|
+
rows.push(/* @__PURE__ */ jsxDEV10("box", {
|
|
3344
|
+
flexDirection: "column",
|
|
3345
|
+
paddingLeft: 2,
|
|
3346
|
+
paddingTop: 1,
|
|
3347
|
+
paddingBottom: 1,
|
|
3348
|
+
children: [
|
|
3349
|
+
/* @__PURE__ */ jsxDEV10("box", {
|
|
3350
|
+
height: 1,
|
|
3351
|
+
flexDirection: "row",
|
|
3352
|
+
children: [
|
|
3353
|
+
/* @__PURE__ */ jsxDEV10("text", {
|
|
3354
|
+
fg: "#f7768e",
|
|
3355
|
+
children: "\u2717 "
|
|
3356
|
+
}, undefined, false, undefined, this),
|
|
3357
|
+
/* @__PURE__ */ jsxDEV10("text", {
|
|
3358
|
+
fg: "#c0caf5",
|
|
3359
|
+
children: [
|
|
3360
|
+
s.model.name,
|
|
3361
|
+
" "
|
|
3362
|
+
]
|
|
3363
|
+
}, undefined, true, undefined, this),
|
|
3364
|
+
/* @__PURE__ */ jsxDEV10("text", {
|
|
3365
|
+
fg: "#565f89",
|
|
3366
|
+
children: [
|
|
3367
|
+
"(",
|
|
3368
|
+
s.model.providerName,
|
|
3369
|
+
")"
|
|
3370
|
+
]
|
|
3371
|
+
}, undefined, true, undefined, this)
|
|
3372
|
+
]
|
|
3373
|
+
}, undefined, true, undefined, this),
|
|
3374
|
+
/* @__PURE__ */ jsxDEV10("box", {
|
|
3375
|
+
height: 1,
|
|
3376
|
+
paddingLeft: 3,
|
|
3377
|
+
children: /* @__PURE__ */ jsxDEV10("text", {
|
|
3378
|
+
fg: "#f7768e",
|
|
3379
|
+
children: s.error ?? "Unknown error"
|
|
3380
|
+
}, undefined, false, undefined, this)
|
|
3381
|
+
}, undefined, false, undefined, this)
|
|
3382
|
+
]
|
|
3383
|
+
}, `err-${s.model.id}-${s.model.providerId}`, true, undefined, this));
|
|
3384
|
+
}
|
|
3385
|
+
}
|
|
3315
3386
|
rows.push(/* @__PURE__ */ jsxDEV10("box", {
|
|
3316
3387
|
height: 1,
|
|
3317
3388
|
backgroundColor: "#292e42"
|
|
@@ -3520,10 +3591,11 @@ function AddVerifiedScreen() {
|
|
|
3520
3591
|
}
|
|
3521
3592
|
}
|
|
3522
3593
|
usePaste((text) => {
|
|
3594
|
+
const clean = text.replace(/[\r\n]/g, "");
|
|
3523
3595
|
if (step === "browse")
|
|
3524
|
-
setSearchQuery((q) => q +
|
|
3596
|
+
setSearchQuery((q) => q + clean);
|
|
3525
3597
|
else if (step === "confirm")
|
|
3526
|
-
setApiKey((k) => k +
|
|
3598
|
+
setApiKey((k) => k + clean);
|
|
3527
3599
|
});
|
|
3528
3600
|
useKeyboard6((key) => {
|
|
3529
3601
|
if (step === "browse") {
|
|
@@ -3935,7 +4007,7 @@ function AddCustomScreen() {
|
|
|
3935
4007
|
baseUrl: baseUrl.trim(),
|
|
3936
4008
|
apiKey: apiKey.trim(),
|
|
3937
4009
|
models: models.map((m) => ({
|
|
3938
|
-
id: m
|
|
4010
|
+
id: m,
|
|
3939
4011
|
name: m
|
|
3940
4012
|
}))
|
|
3941
4013
|
});
|
|
@@ -3950,16 +4022,17 @@ function AddCustomScreen() {
|
|
|
3950
4022
|
}
|
|
3951
4023
|
}
|
|
3952
4024
|
usePaste((text) => {
|
|
4025
|
+
const clean = text.replace(/[\r\n]/g, "");
|
|
3953
4026
|
if (step === "id")
|
|
3954
|
-
setProviderId((v) => v +
|
|
4027
|
+
setProviderId((v) => v + clean);
|
|
3955
4028
|
else if (step === "name")
|
|
3956
|
-
setProviderName((v) => v +
|
|
4029
|
+
setProviderName((v) => v + clean);
|
|
3957
4030
|
else if (step === "url")
|
|
3958
|
-
setBaseUrl((v) => v +
|
|
4031
|
+
setBaseUrl((v) => v + clean);
|
|
3959
4032
|
else if (step === "key")
|
|
3960
|
-
setApiKey((v) => v +
|
|
4033
|
+
setApiKey((v) => v + clean);
|
|
3961
4034
|
else if (step === "models")
|
|
3962
|
-
setModelInput((v) => v +
|
|
4035
|
+
setModelInput((v) => v + clean);
|
|
3963
4036
|
});
|
|
3964
4037
|
useKeyboard7((key) => {
|
|
3965
4038
|
if (step === "done") {
|
|
@@ -4023,10 +4096,8 @@ function AddCustomScreen() {
|
|
|
4023
4096
|
}
|
|
4024
4097
|
if (step === "name") {
|
|
4025
4098
|
if (key.name === "return" || key.name === "enter") {
|
|
4026
|
-
if (!providerName.trim())
|
|
4027
|
-
|
|
4028
|
-
return;
|
|
4029
|
-
}
|
|
4099
|
+
if (!providerName.trim())
|
|
4100
|
+
setProviderName(providerId);
|
|
4030
4101
|
setInputError("");
|
|
4031
4102
|
setStep("url");
|
|
4032
4103
|
return;
|
|
@@ -4315,8 +4386,12 @@ function AddCustomScreen() {
|
|
|
4315
4386
|
height: 1,
|
|
4316
4387
|
children: /* @__PURE__ */ jsxDEV12("text", {
|
|
4317
4388
|
fg: "#565f89",
|
|
4318
|
-
children:
|
|
4319
|
-
|
|
4389
|
+
children: [
|
|
4390
|
+
'e.g. My OpenAI (Enter to use "',
|
|
4391
|
+
providerId,
|
|
4392
|
+
'")'
|
|
4393
|
+
]
|
|
4394
|
+
}, undefined, true, undefined, this)
|
|
4320
4395
|
}, undefined, false, undefined, this)
|
|
4321
4396
|
]
|
|
4322
4397
|
}, undefined, true, undefined, this),
|
|
@@ -4490,8 +4565,9 @@ function AddModelsScreen() {
|
|
|
4490
4565
|
load();
|
|
4491
4566
|
}, []);
|
|
4492
4567
|
usePaste((text) => {
|
|
4568
|
+
const clean = text.replace(/[\r\n]/g, "");
|
|
4493
4569
|
if (step === "add")
|
|
4494
|
-
setModelInput((v) => v +
|
|
4570
|
+
setModelInput((v) => v + clean);
|
|
4495
4571
|
});
|
|
4496
4572
|
useKeyboard8((key) => {
|
|
4497
4573
|
if (done) {
|
package/package.json
CHANGED
|
@@ -1,24 +1,19 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ai-speedometer",
|
|
3
|
-
"version": "2.1.
|
|
3
|
+
"version": "2.1.5",
|
|
4
4
|
"description": "A comprehensive CLI tool for benchmarking AI models across multiple providers with parallel execution and professional metrics",
|
|
5
5
|
"bin": {
|
|
6
6
|
"ai-speedometer": "dist/ai-speedometer",
|
|
7
|
-
"aispeed": "dist/ai-speedometer"
|
|
8
|
-
"ai-speedometer-headless": "dist/ai-speedometer-headless"
|
|
7
|
+
"aispeed": "dist/ai-speedometer"
|
|
9
8
|
},
|
|
10
9
|
"engines": {
|
|
11
|
-
"bun": ">=1.0.0"
|
|
12
|
-
"node": ">=18.0.0"
|
|
10
|
+
"bun": ">=1.0.0"
|
|
13
11
|
},
|
|
14
12
|
"scripts": {
|
|
15
13
|
"start": "bun src/index.ts",
|
|
16
14
|
"dev": "bun --watch src/index.ts",
|
|
17
|
-
"
|
|
18
|
-
"test:watch": "bun test --watch",
|
|
19
|
-
"test:update": "bun test --update-snapshots",
|
|
15
|
+
"build": "bun build src/index.ts --outdir dist --target bun --external '@opentui/core' --external '@opentui/react' --external 'react' --external 'react-reconciler' && cat ../../scripts/shebang dist/index.js > dist/ai-speedometer && chmod +x dist/ai-speedometer && rm dist/index.js",
|
|
20
16
|
"typecheck": "bun tsc --noEmit",
|
|
21
|
-
"build": "bun build src/index.ts --outdir dist --target bun --external '@opentui/core' --external '@opentui/react' --external 'react' --external 'react-reconciler' && cat scripts/shebang dist/index.js > dist/ai-speedometer && chmod +x dist/ai-speedometer && rm dist/index.js && bun build src/headless-entry.ts --outdir dist --target node --external 'jsonc-parser' && mv dist/headless-entry.js dist/ai-speedometer-headless && chmod +x dist/ai-speedometer-headless",
|
|
22
17
|
"prepublishOnly": "bun run build"
|
|
23
18
|
},
|
|
24
19
|
"keywords": [
|
|
@@ -48,10 +43,9 @@
|
|
|
48
43
|
"homepage": "https://github.com/aptdnfapt/Ai-speedometer#readme",
|
|
49
44
|
"files": [
|
|
50
45
|
"dist/",
|
|
51
|
-
"docs/",
|
|
52
|
-
"
|
|
53
|
-
"
|
|
54
|
-
"ai-benchmark-config.json.template"
|
|
46
|
+
"../../docs/",
|
|
47
|
+
"../../README.md",
|
|
48
|
+
"../../ai-benchmark-config.json.template"
|
|
55
49
|
],
|
|
56
50
|
"dependencies": {
|
|
57
51
|
"@opentui/core": "0.1.79",
|
|
@@ -60,6 +54,7 @@
|
|
|
60
54
|
"react-reconciler": "^0.32.0"
|
|
61
55
|
},
|
|
62
56
|
"devDependencies": {
|
|
57
|
+
"@ai-speedometer/core": "workspace:*",
|
|
63
58
|
"jsonc-parser": "^3.3.1"
|
|
64
59
|
}
|
|
65
60
|
}
|
package/README.md
DELETED
|
@@ -1,127 +0,0 @@
|
|
|
1
|
-
# Ai-speedometer
|
|
2
|
-
|
|
3
|
-
A CLI tool for benchmarking AI models across multiple providers with parallel execution and performance metrics.
|
|
4
|
-
|
|
5
|
-
[](https://discord.gg/6S7HwCxbMy)
|
|
6
|
-
|
|
7
|
-
Track OSS model speeds over time: [ai-speedometer.oliveowl.xyz](https://ai-speedometer.oliveowl.xyz/)
|
|
8
|
-
|
|
9
|
-

|
|
10
|
-
|
|
11
|
-

|
|
12
|
-
|
|
13
|
-
## Install
|
|
14
|
-
|
|
15
|
-
Requires [Bun](https://bun.sh) runtime.
|
|
16
|
-
|
|
17
|
-
```bash
|
|
18
|
-
bun install -g ai-speedometer
|
|
19
|
-
```
|
|
20
|
-
|
|
21
|
-
Or with npm (Bun still required at runtime):
|
|
22
|
-
|
|
23
|
-
```bash
|
|
24
|
-
npm install -g ai-speedometer
|
|
25
|
-
```
|
|
26
|
-
|
|
27
|
-
Or run directly from source:
|
|
28
|
-
|
|
29
|
-
```bash
|
|
30
|
-
bun src/index.ts
|
|
31
|
-
```
|
|
32
|
-
|
|
33
|
-
## What It Measures
|
|
34
|
-
|
|
35
|
-
- **TTFT** (Time to First Token) - How fast the first response token arrives
|
|
36
|
-
- **Total Time** - Complete request duration
|
|
37
|
-
- **Tokens/Second** - Real-time throughput
|
|
38
|
-
- **Token Counts** - Input, output, and total tokens used
|
|
39
|
-
|
|
40
|
-
## Features
|
|
41
|
-
|
|
42
|
-
- **Interactive TUI** - Full terminal UI with Tokyo Night theme, menus, search, and live benchmark progress
|
|
43
|
-
- **REST API Benchmarking** - Default method, works with all OpenAI-compatible providers
|
|
44
|
-
- **Headless Mode** - Run benchmarks without interactive CLI using command-line arguments
|
|
45
|
-
- **Parallel Execution** - Benchmark multiple models simultaneously
|
|
46
|
-
- **Provider Management** - Add verified, custom verified, and custom providers
|
|
47
|
-
|
|
48
|
-
## Quick Setup
|
|
49
|
-
|
|
50
|
-
1. **Set Model**
|
|
51
|
-
```bash
|
|
52
|
-
ai-speedometer
|
|
53
|
-
# Select "Run Benchmark" → "Add Verified Provider" → Choose provider (OpenAI, Anthropic, etc.)
|
|
54
|
-
# Enter your API key when prompted
|
|
55
|
-
```
|
|
56
|
-
|
|
57
|
-
2. **Choose Model Provider**
|
|
58
|
-
- Verified providers (OpenAI, Anthropic, Google) - auto-configured via models.dev
|
|
59
|
-
- Custom verified providers (pre-configured trusted providers) - add API key
|
|
60
|
-
- Custom providers (Ollama, local models) - add your base URL
|
|
61
|
-
|
|
62
|
-
3. **Add API Key**
|
|
63
|
-
- Get API keys from your provider's dashboard
|
|
64
|
-
- Enter when prompted - stored securely in:
|
|
65
|
-
- `~/.local/share/opencode/auth.json` (primary storage)
|
|
66
|
-
- `~/.config/ai-speedometer/ai-benchmark-config.json` (backup storage)
|
|
67
|
-
|
|
68
|
-
4. **Run Benchmark**
|
|
69
|
-
```bash
|
|
70
|
-
ai-speedometer
|
|
71
|
-
# Select "Run Benchmark" → choose models → press Enter
|
|
72
|
-
```
|
|
73
|
-
|
|
74
|
-
## Usage
|
|
75
|
-
|
|
76
|
-
```bash
|
|
77
|
-
# Start interactive TUI
|
|
78
|
-
ai-speedometer
|
|
79
|
-
|
|
80
|
-
# Short alias
|
|
81
|
-
aispeed
|
|
82
|
-
|
|
83
|
-
# Debug mode
|
|
84
|
-
ai-speedometer --debug
|
|
85
|
-
|
|
86
|
-
# Headless benchmark
|
|
87
|
-
ai-speedometer --bench openai:gpt-4
|
|
88
|
-
# With custom API key
|
|
89
|
-
ai-speedometer --bench openai:gpt-4 --api-key "sk-your-key"
|
|
90
|
-
# Custom provider
|
|
91
|
-
ai-speedometer --bench-custom myprovider:mymodel --base-url https://... --api-key "..."
|
|
92
|
-
```
|
|
93
|
-
|
|
94
|
-
## Development
|
|
95
|
-
|
|
96
|
-
```bash
|
|
97
|
-
# Run from source
|
|
98
|
-
bun src/index.ts
|
|
99
|
-
|
|
100
|
-
# Run with auto-reload
|
|
101
|
-
bun --watch src/index.ts
|
|
102
|
-
|
|
103
|
-
# Run tests
|
|
104
|
-
bun test
|
|
105
|
-
|
|
106
|
-
# Typecheck
|
|
107
|
-
bun run typecheck
|
|
108
|
-
|
|
109
|
-
# Build standalone binary
|
|
110
|
-
bun run build # → dist/ai-speedometer
|
|
111
|
-
```
|
|
112
|
-
|
|
113
|
-
## Configuration Files
|
|
114
|
-
|
|
115
|
-
API keys and configuration are stored in:
|
|
116
|
-
|
|
117
|
-
- **Verified + Custom Verified Providers**:
|
|
118
|
-
- Primary: `~/.local/share/opencode/auth.json`
|
|
119
|
-
- Backup: `~/.config/ai-speedometer/ai-benchmark-config.json` (verifiedProviders section)
|
|
120
|
-
- **Custom Providers**: `~/.config/ai-speedometer/ai-benchmark-config.json` (customProviders section)
|
|
121
|
-
- **Provider Definitions**: `./custom-verified-providers.json` (bundled at build time)
|
|
122
|
-
|
|
123
|
-
## Requirements
|
|
124
|
-
|
|
125
|
-
- **Runtime**: Bun 1.0+ (required — install from [bun.sh](https://bun.sh))
|
|
126
|
-
- API keys for AI providers
|
|
127
|
-
- Terminal with arrow keys and ANSI colors
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"verifiedProviders": {
|
|
3
|
-
"openai": "sk-your-openai-api-key",
|
|
4
|
-
"anthropic": "sk-ant-your-anthropic-api-key"
|
|
5
|
-
},
|
|
6
|
-
"customProviders": [
|
|
7
|
-
{
|
|
8
|
-
"id": "my-custom-provider",
|
|
9
|
-
"name": "My Custom Provider",
|
|
10
|
-
"type": "openai-compatible",
|
|
11
|
-
"baseUrl": "https://api.custom.com/v1",
|
|
12
|
-
"apiKey": "YOUR_API_KEY_HERE",
|
|
13
|
-
"models": [
|
|
14
|
-
{
|
|
15
|
-
"name": "custom-model",
|
|
16
|
-
"id": "custom_model_1"
|
|
17
|
-
}
|
|
18
|
-
]
|
|
19
|
-
}
|
|
20
|
-
]
|
|
21
|
-
}
|