@jeffreyjyz/mpc 0.1.6 → 0.1.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +9 -0
- package/package.json +3 -2
- package/src/cli/engine/score.ts +7 -7
- package/src/constants/data.ts +7 -0
- package/src/constants/sources.ts +4 -1
- package/src/constants/view.ts +4 -1
- package/src/data/sources/aa/api.ts +13 -3
package/README.md
CHANGED
|
@@ -25,6 +25,15 @@ bun link
|
|
|
25
25
|
mpc --help
|
|
26
26
|
```
|
|
27
27
|
|
|
28
|
+
Working on the CLI itself? `bun run dev:link` points `mpcdev` at this checkout, so the
|
|
29
|
+
published `mpc` keeps running the installed release while `mpcdev` runs your edits:
|
|
30
|
+
|
|
31
|
+
```sh
|
|
32
|
+
bun run dev:link
|
|
33
|
+
mpcdev --version # this checkout
|
|
34
|
+
mpc --version # the published install
|
|
35
|
+
```
|
|
36
|
+
|
|
28
37
|
## Usage
|
|
29
38
|
|
|
30
39
|
```sh
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jeffreyjyz/mpc",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.9",
|
|
4
4
|
"description": "Compare model pricing across opencode Go and Command Code plans",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -22,7 +22,8 @@
|
|
|
22
22
|
"start": "bun run src/index.ts",
|
|
23
23
|
"test": "bun test",
|
|
24
24
|
"lint": "biome lint --write .",
|
|
25
|
-
"typecheck": "bun check"
|
|
25
|
+
"typecheck": "bun check",
|
|
26
|
+
"dev:link": "ln -sfn \"$PWD/src/index.ts\" \"$HOME/.bun/bin/mpcdev\""
|
|
26
27
|
},
|
|
27
28
|
"devDependencies": {
|
|
28
29
|
"@biomejs/biome": "^2.5.13",
|
package/src/cli/engine/score.ts
CHANGED
|
@@ -76,19 +76,19 @@ export function assignValueIndex(metrics: EntryMetrics[], config: ScoreConfig):
|
|
|
76
76
|
const byAbility = of(scored, ability);
|
|
77
77
|
const bySpeed = of(speeded, speed);
|
|
78
78
|
|
|
79
|
-
//
|
|
80
|
-
//
|
|
79
|
+
// Unlimited requests win the volume term outright — you cannot buy more than
|
|
80
|
+
// infinite — but the model still enters the composite, so a free model with a
|
|
81
|
+
// low ability no longer outranks everything by virtue of being free.
|
|
82
|
+
const volumeTerm = (m: EntryMetrics) =>
|
|
83
|
+
Number.isFinite(m.requestsPerMonth) ? (byVolume.get(m) ?? 0.5) : 1;
|
|
84
|
+
|
|
81
85
|
const composites = new Map<EntryMetrics, number>();
|
|
82
86
|
for (const m of scored) {
|
|
83
|
-
if (!Number.isFinite(m.requestsPerMonth)) {
|
|
84
|
-
m.valueIndex = 100;
|
|
85
|
-
continue;
|
|
86
|
-
}
|
|
87
87
|
composites.set(
|
|
88
88
|
m,
|
|
89
89
|
100 * (wAbility ?? 0) * (byAbility.get(m) ?? 0.5) +
|
|
90
90
|
100 * (wTps ?? 0) * (bySpeed.get(m) ?? 0.5) +
|
|
91
|
-
100 * (wVolume ?? 0) * (
|
|
91
|
+
100 * (wVolume ?? 0) * volumeTerm(m) +
|
|
92
92
|
100 * (wCache ?? 0) * (1 - (byCache.get(m) ?? 0.5)) +
|
|
93
93
|
100 * (wOutput ?? 0) * (1 - (byOutput.get(m) ?? 0.5)),
|
|
94
94
|
);
|
package/src/constants/data.ts
CHANGED
|
@@ -13,6 +13,13 @@ export const ALIASES: Record<string, string> = {
|
|
|
13
13
|
// CommandCode prefixes these with "Tencent"; OpenCode Go does not.
|
|
14
14
|
tencenthy3: "hy3",
|
|
15
15
|
tencenthy4preview: "hy4preview",
|
|
16
|
+
// AA's slug keeps the vendor the catalogs drop: "tencent-hy4", "reflection-beam".
|
|
17
|
+
tencenthy4: "hy4",
|
|
18
|
+
reflectionbeam: "beam10",
|
|
19
|
+
// AA suffixes the bake date onto the slug: "mimo-v2-5-0424".
|
|
20
|
+
mimov250424: "mimov25",
|
|
21
|
+
// CommandCode lists the same Jev build twice, once with its version suffix.
|
|
22
|
+
jev1140: "jev",
|
|
16
23
|
// CommandCode writes "(exp)"; OpenCode Go writes "-exp".
|
|
17
24
|
deepseekv4flashvision: "deepseekv4flashvisionexp",
|
|
18
25
|
// Alibaba's "Qwen3.8-Flash-Next" is the release name of the model
|
package/src/constants/sources.ts
CHANGED
|
@@ -79,7 +79,10 @@ export const DEFAULT_OC_PLAN = "go";
|
|
|
79
79
|
export const DOC_URL = "https://opencode.ai/v2/docs/console/go/";
|
|
80
80
|
export const OC_MODELS_URL = "https://opencode.ai/zen/go/v1/models";
|
|
81
81
|
|
|
82
|
-
|
|
82
|
+
/** Artificial Analysis retired `/api/v2/data/*` on 2026-11-04 (410 Gone). The free
|
|
83
|
+
* tier serves the same index and median output speed mpc reads, so no Pro plan
|
|
84
|
+
* is needed; the paid list at `/api/v2/language/models` answers 403 without one. */
|
|
85
|
+
export const API_URL = "https://artificialanalysis.ai/api/v2/language/models/free";
|
|
83
86
|
export const AA_MODELS_URL = "https://artificialanalysis.ai/models";
|
|
84
87
|
|
|
85
88
|
// CommandCode only publishes Intelligence and Tok/s on the GOAT/Pro catalogs.
|
package/src/constants/view.ts
CHANGED
|
@@ -100,7 +100,10 @@ export const LEGEND: [string, string][] = [
|
|
|
100
100
|
["ability", "benchmark score for the model (source above)"],
|
|
101
101
|
["tps", "output tokens per second (source above)"],
|
|
102
102
|
["COST", "0-100 volume index: requests/mo, lower is better (no ability)"],
|
|
103
|
-
[
|
|
103
|
+
[
|
|
104
|
+
"VAL",
|
|
105
|
+
"0-100 ability-aware value: ability + speed + volume + cache + output · a free row wins volume only, so it can post COST 0 and a mid VAL",
|
|
106
|
+
],
|
|
104
107
|
];
|
|
105
108
|
|
|
106
109
|
export const CSV_HEADER = [
|
|
@@ -26,13 +26,23 @@ async function fetchTextWithKey(url: string, key: string): Promise<string> {
|
|
|
26
26
|
headers: { "x-api-key": key, "user-agent": "mpc/0.1" },
|
|
27
27
|
});
|
|
28
28
|
if (!res.ok) {
|
|
29
|
-
throw new Error(
|
|
30
|
-
`Artificial Analysis API ${res.status}: set AA_API_KEY or use --bench cc / aa-web`,
|
|
31
|
-
);
|
|
29
|
+
throw new Error(`Artificial Analysis API ${res.status}: ${statusHint(res.status)}`);
|
|
32
30
|
}
|
|
33
31
|
return res.text();
|
|
34
32
|
}
|
|
35
33
|
|
|
34
|
+
/** One line per cause: a retired path is not a bad key, and the old message
|
|
35
|
+
* blamed credentials for every status. */
|
|
36
|
+
function statusHint(status: number): string {
|
|
37
|
+
if (status === 401) return "AA_API_KEY rejected, replace the key";
|
|
38
|
+
if (status === 403)
|
|
39
|
+
return "this endpoint needs a Pro subscription, the free list is /language/models/free";
|
|
40
|
+
if (status === 404 || status === 410)
|
|
41
|
+
return "endpoint retired, see artificialanalysis.ai/data-api";
|
|
42
|
+
if (status === 429) return "daily quota spent, use --bench cc / aa-web";
|
|
43
|
+
return "unexpected response, use --bench cc / aa-web";
|
|
44
|
+
}
|
|
45
|
+
|
|
36
46
|
/** Keep the best variant per key; AA lists a row per reasoning effort. */
|
|
37
47
|
function mergeAaPage(
|
|
38
48
|
page: { intelligence: Map<string, number>; tps: Map<string, number> },
|