benchwarmers 0.2.1__tar.gz
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.
- benchwarmers-0.2.1/.gitignore +42 -0
- benchwarmers-0.2.1/AGENTS.md +147 -0
- benchwarmers-0.2.1/BENCHMARKS.md +262 -0
- benchwarmers-0.2.1/GATEWAY.md +272 -0
- benchwarmers-0.2.1/LICENSE +21 -0
- benchwarmers-0.2.1/NOTICE +28 -0
- benchwarmers-0.2.1/PKG-INFO +390 -0
- benchwarmers-0.2.1/PRIVACY.md +46 -0
- benchwarmers-0.2.1/README.md +368 -0
- benchwarmers-0.2.1/SECURITY.md +83 -0
- benchwarmers-0.2.1/TERMS.md +22 -0
- benchwarmers-0.2.1/USAGE.md +170 -0
- benchwarmers-0.2.1/VERSION +1 -0
- benchwarmers-0.2.1/cli.py +666 -0
- benchwarmers-0.2.1/examples/config/gateway.json +5 -0
- benchwarmers-0.2.1/examples/config/model-roles.json +11 -0
- benchwarmers-0.2.1/gateway.py +755 -0
- benchwarmers-0.2.1/launcher.py +120 -0
- benchwarmers-0.2.1/mcp_server.py +266 -0
- benchwarmers-0.2.1/metrics/alerts.py +116 -0
- benchwarmers-0.2.1/metrics/aliases.py +41 -0
- benchwarmers-0.2.1/metrics/bench_collections.py +141 -0
- benchwarmers-0.2.1/metrics/catalog.py +295 -0
- benchwarmers-0.2.1/metrics/client.py +394 -0
- benchwarmers-0.2.1/metrics/cliproxy.py +191 -0
- benchwarmers-0.2.1/metrics/connect.py +691 -0
- benchwarmers-0.2.1/metrics/cost.py +152 -0
- benchwarmers-0.2.1/metrics/decide.py +227 -0
- benchwarmers-0.2.1/metrics/discover.py +318 -0
- benchwarmers-0.2.1/metrics/endpoints.py +436 -0
- benchwarmers-0.2.1/metrics/guard.py +617 -0
- benchwarmers-0.2.1/metrics/learn.py +221 -0
- benchwarmers-0.2.1/metrics/litellm_hub.py +206 -0
- benchwarmers-0.2.1/metrics/locked.py +142 -0
- benchwarmers-0.2.1/metrics/model_roles.py +84 -0
- benchwarmers-0.2.1/metrics/offload.py +166 -0
- benchwarmers-0.2.1/metrics/owui.py +205 -0
- benchwarmers-0.2.1/metrics/paths.py +60 -0
- benchwarmers-0.2.1/metrics/probe_caps.py +150 -0
- benchwarmers-0.2.1/metrics/route.py +579 -0
- benchwarmers-0.2.1/metrics/scheduler.py +275 -0
- benchwarmers-0.2.1/metrics/sources.py +167 -0
- benchwarmers-0.2.1/metrics/test_decide.py +29 -0
- benchwarmers-0.2.1/metrics/wrong.py +144 -0
- benchwarmers-0.2.1/perf/README.md +89 -0
- benchwarmers-0.2.1/perf/run.py +261 -0
- benchwarmers-0.2.1/pyproject.toml +62 -0
- benchwarmers-0.2.1/repoqa/README.md +78 -0
- benchwarmers-0.2.1/repoqa/run.py +307 -0
- benchwarmers-0.2.1/scripts/auto_retire.py +367 -0
- benchwarmers-0.2.1/scripts/check.py +108 -0
- benchwarmers-0.2.1/scripts/check_deprecations.py +378 -0
- benchwarmers-0.2.1/scripts/check_themes.py +103 -0
- benchwarmers-0.2.1/scripts/init.py +124 -0
- benchwarmers-0.2.1/scripts/list_served.py +78 -0
- benchwarmers-0.2.1/scripts/notice.py +78 -0
- benchwarmers-0.2.1/scripts/onboard.py +401 -0
- benchwarmers-0.2.1/scripts/provider_tags.py +129 -0
- benchwarmers-0.2.1/scripts/reprefix.py +136 -0
- benchwarmers-0.2.1/scripts/sync_config.py +105 -0
- benchwarmers-0.2.1/scripts/test_auth.py +255 -0
- benchwarmers-0.2.1/scripts/test_cli.py +189 -0
- benchwarmers-0.2.1/scripts/test_client.py +233 -0
- benchwarmers-0.2.1/scripts/test_connect.py +222 -0
- benchwarmers-0.2.1/scripts/test_first_run.py +180 -0
- benchwarmers-0.2.1/scripts/test_hubs.py +328 -0
- benchwarmers-0.2.1/scripts/test_launcher.py +67 -0
- benchwarmers-0.2.1/scripts/test_llm_log.py +85 -0
- benchwarmers-0.2.1/scripts/test_mcp.py +178 -0
- benchwarmers-0.2.1/scripts/test_merged.py +214 -0
- benchwarmers-0.2.1/scripts/test_no_owui.py +291 -0
- benchwarmers-0.2.1/scripts/test_owui.py +90 -0
- benchwarmers-0.2.1/scripts/test_serve_edit.py +448 -0
- benchwarmers-0.2.1/scripts/test_verdict.py +98 -0
- benchwarmers-0.2.1/scripts/test_vision.py +228 -0
- benchwarmers-0.2.1/serve.py +3904 -0
- benchwarmers-0.2.1/suite/README.md +152 -0
- benchwarmers-0.2.1/suite/REBENCH.md +101 -0
- benchwarmers-0.2.1/suite/mine.py +154 -0
- benchwarmers-0.2.1/suite/pace.py +145 -0
- benchwarmers-0.2.1/suite/rebench-rejected.json +8 -0
- benchwarmers-0.2.1/suite/rebench.py +274 -0
- benchwarmers-0.2.1/suite/run.py +1046 -0
- benchwarmers-0.2.1/suite/seed.py +421 -0
- benchwarmers-0.2.1/suite/tasks/claim-alias-unbound/fixtures/onboard.py +286 -0
- benchwarmers-0.2.1/suite/tasks/claim-alias-unbound/task.json +23 -0
- benchwarmers-0.2.1/suite/tasks/claim-error-text-string/fixtures/decide.py +187 -0
- benchwarmers-0.2.1/suite/tasks/claim-error-text-string/task.json +23 -0
- benchwarmers-0.2.1/suite/tasks/claim-list-body/fixtures/gateway.py +235 -0
- benchwarmers-0.2.1/suite/tasks/claim-list-body/task.json +23 -0
- benchwarmers-0.2.1/suite/tasks/claim-member-nominated-twice/fixtures/gateway.py +284 -0
- benchwarmers-0.2.1/suite/tasks/claim-member-nominated-twice/fixtures/route.py +542 -0
- benchwarmers-0.2.1/suite/tasks/claim-member-nominated-twice/task.json +24 -0
- benchwarmers-0.2.1/suite/tasks/claim-nominee-uses-slot/fixtures/gateway.py +284 -0
- benchwarmers-0.2.1/suite/tasks/claim-nominee-uses-slot/fixtures/route.py +542 -0
- benchwarmers-0.2.1/suite/tasks/claim-nominee-uses-slot/task.json +24 -0
- benchwarmers-0.2.1/suite/tasks/claim-silent-exit/fixtures/gateway.py +235 -0
- benchwarmers-0.2.1/suite/tasks/claim-silent-exit/task.json +23 -0
- benchwarmers-0.2.1/suite/tasks/claim-sse-hang/fixtures/gateway.py +235 -0
- benchwarmers-0.2.1/suite/tasks/claim-sse-hang/task.json +23 -0
- benchwarmers-0.2.1/suite/tasks/claim-unknown-nominee-crash/fixtures/gateway.py +284 -0
- benchwarmers-0.2.1/suite/tasks/claim-unknown-nominee-crash/fixtures/route.py +542 -0
- benchwarmers-0.2.1/suite/tasks/claim-unknown-nominee-crash/task.json +24 -0
- benchwarmers-0.2.1/suite/tasks/rebench-matchms-809-bug/task.json +23 -0
- benchwarmers-0.2.1/suite/tasks/rebench-matchms-809-control/task.json +27 -0
- benchwarmers-0.2.1/suite/tasks/rebench-more-itertools-1028-bug/task.json +23 -0
- benchwarmers-0.2.1/suite/tasks/rebench-more-itertools-1028-control/task.json +27 -0
- benchwarmers-0.2.1/suite/tasks/rebench-narwhals-2864-bug/task.json +23 -0
- benchwarmers-0.2.1/suite/tasks/rebench-narwhals-2864-control/task.json +27 -0
- benchwarmers-0.2.1/suite/tasks/rebench-quantecon-py-769-bug/task.json +23 -0
- benchwarmers-0.2.1/suite/tasks/rebench-quantecon-py-769-control/task.json +27 -0
- benchwarmers-0.2.1/suite/tasks/rebench-scrapy-6867-bug/task.json +23 -0
- benchwarmers-0.2.1/suite/tasks/rebench-scrapy-6867-control/task.json +27 -0
- benchwarmers-0.2.1/suite/test_mine.py +31 -0
- benchwarmers-0.2.1/suite/test_pick.py +51 -0
- benchwarmers-0.2.1/suite/test_rebench.py +67 -0
- benchwarmers-0.2.1/suite/test_score.py +30 -0
- benchwarmers-0.2.1/suite/test_seed.py +78 -0
- benchwarmers-0.2.1/ui/bench.css +430 -0
- benchwarmers-0.2.1/ui/bench.js +1756 -0
- benchwarmers-0.2.1/ui/fonts/OFL-Chivo-Mono.txt +93 -0
- benchwarmers-0.2.1/ui/fonts/OFL-Chivo.txt +93 -0
- benchwarmers-0.2.1/ui/fonts/chivo-latin-400-normal.woff2 +0 -0
- benchwarmers-0.2.1/ui/fonts/chivo-latin-500-normal.woff2 +0 -0
- benchwarmers-0.2.1/ui/fonts/chivo-latin-700-normal.woff2 +0 -0
- benchwarmers-0.2.1/ui/fonts/chivo-latin-800-normal.woff2 +0 -0
- benchwarmers-0.2.1/ui/fonts/chivo-mono-latin-400-normal.woff2 +0 -0
- benchwarmers-0.2.1/ui/fonts/chivo-mono-latin-500-normal.woff2 +0 -0
- benchwarmers-0.2.1/ui/mascot.png +0 -0
- benchwarmers-0.2.1/ui/themes/dark.css +35 -0
- benchwarmers-0.2.1/ui/themes/hardwood.css +52 -0
- benchwarmers-0.2.1/ui/themes/rainforest.css +32 -0
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
*.bak
|
|
2
|
+
*.*.bak
|
|
3
|
+
# metrics/paths.py: this checkout's pointer to its data folder (one per machine)
|
|
4
|
+
.benchwarmers-home
|
|
5
|
+
# Personal notes for Claude Code in a checkout; never part of the project
|
|
6
|
+
CLAUDE.local.md
|
|
7
|
+
# An install's own data, when its data folder is the checkout itself (the
|
|
8
|
+
# default until `init` exists): never committed by accident. Files already
|
|
9
|
+
# tracked here (this private repo's history) are unaffected.
|
|
10
|
+
/config/
|
|
11
|
+
/metrics/*.json
|
|
12
|
+
/metrics/*.jsonl
|
|
13
|
+
/perf/history.csv
|
|
14
|
+
/runs/
|
|
15
|
+
# metrics/locked.py: lock files beside the JSON they guard, and temp files mid-write
|
|
16
|
+
*.json.lock
|
|
17
|
+
.*.part
|
|
18
|
+
keys.json
|
|
19
|
+
# compose.yaml's secrets (the admin token, BENCHWARMERS_KEY_*)
|
|
20
|
+
.env
|
|
21
|
+
__pycache__/
|
|
22
|
+
# pip wheel . / python -m build (pyproject.toml)
|
|
23
|
+
/dist/
|
|
24
|
+
/build/
|
|
25
|
+
*.egg-info/
|
|
26
|
+
suite/tasks/*/output/
|
|
27
|
+
.venv/
|
|
28
|
+
floor/results/
|
|
29
|
+
evalplus_results/
|
|
30
|
+
funcbench/tool/.venv/
|
|
31
|
+
funcbench/results/
|
|
32
|
+
funcbench/tool/
|
|
33
|
+
repoqa/results/
|
|
34
|
+
runs/gateway/
|
|
35
|
+
runs/cooldowns.json
|
|
36
|
+
runs/cache/
|
|
37
|
+
runs/discover-seen.json
|
|
38
|
+
runs/scheduler.log
|
|
39
|
+
runs/scheduler-state.json
|
|
40
|
+
runs/scheduler.lock
|
|
41
|
+
.archify/**/*.json
|
|
42
|
+
!.archify/**/candidate.json
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
# Setting up Benchwarmers with a person (for coding agents)
|
|
2
|
+
|
|
3
|
+
You are helping someone install Benchwarmers, a self-hosted panel gateway for
|
|
4
|
+
LLMs: one prompt goes to a named collection of models, every answer comes back
|
|
5
|
+
labelled, and the person's verdicts decide who sits on the next panel. Follow
|
|
6
|
+
these steps with them in order. Each says what to run and what to check.
|
|
7
|
+
|
|
8
|
+
## Ground rules
|
|
9
|
+
|
|
10
|
+
- **Never print, paste, log or commit an API key**, and never put one in a JSON
|
|
11
|
+
file. Keys live in exactly one of two places (step 3).
|
|
12
|
+
- **Their data is not the code.** Endpoints, registrations, collections,
|
|
13
|
+
verdicts and history live in a data folder outside the checkout. Never add
|
|
14
|
+
anything from it to the repository.
|
|
15
|
+
- **Ask before spending model calls.** Onboarding probes a model (4 calls) and
|
|
16
|
+
runs the review suite (more); free tiers run out. Say what a step costs.
|
|
17
|
+
- **Prefer the dashboard for anything involving a sign-in.** Signing in to a
|
|
18
|
+
provider happens on the provider's own page in the person's browser; you
|
|
19
|
+
cannot and must not do it for them.
|
|
20
|
+
|
|
21
|
+
## 1. Install
|
|
22
|
+
|
|
23
|
+
Python 3.11 or later; nothing else is required.
|
|
24
|
+
|
|
25
|
+
git clone https://github.com/WendellResearch-AI/benchwarmers
|
|
26
|
+
cd benchwarmers
|
|
27
|
+
python -m venv .venv
|
|
28
|
+
.venv/bin/pip install llm # optional; Windows: .venv\Scripts\pip install llm
|
|
29
|
+
|
|
30
|
+
The `llm` CLI is today's default model client. Without it, choose the
|
|
31
|
+
built-in client (`metrics/client.py`), which needs nothing installed: on
|
|
32
|
+
Settings, Model client, once the dashboard runs, or with
|
|
33
|
+
`BENCH_CLIENT=builtin` (which wins over Settings).
|
|
34
|
+
|
|
35
|
+
Check: `python scripts/check.py --quick` ends with `all checks pass`.
|
|
36
|
+
|
|
37
|
+
## 2. Make the data folder
|
|
38
|
+
|
|
39
|
+
python scripts/init.py # or: python scripts/init.py <folder>
|
|
40
|
+
|
|
41
|
+
It creates the folder from `examples/` (by default in the OS's per-user data
|
|
42
|
+
folder) and points this checkout at it with a `.benchwarmers-home` file.
|
|
43
|
+
`BENCHWARMERS_HOME=<folder>` overrides the pointer.
|
|
44
|
+
|
|
45
|
+
Check: `python metrics/paths.py` prints the folder and why it was chosen.
|
|
46
|
+
|
|
47
|
+
## 3. Add a first endpoint, and its key
|
|
48
|
+
|
|
49
|
+
An endpoint is any OpenAI-compatible API: a provider (Groq, Mistral), an
|
|
50
|
+
aggregator (OpenRouter), a hub the person runs (Open WebUI, LiteLLM, CLI Proxy
|
|
51
|
+
API) or a local runtime (Ollama). Three ways, best first:
|
|
52
|
+
|
|
53
|
+
- **Sign in from the dashboard** (step 4 opens it on this): OpenRouter,
|
|
54
|
+
NanoGPT, Hugging Face, Pollinations, a ChatGPT plan, GitHub Models, or a
|
|
55
|
+
local Ollama. No key is copied by hand.
|
|
56
|
+
- **`init` with a key**, asked for without echo:
|
|
57
|
+
|
|
58
|
+
python scripts/init.py --endpoint openrouter https://openrouter.ai/api/v1 --key
|
|
59
|
+
|
|
60
|
+
- **An environment variable**, for Docker and servers. The variable is
|
|
61
|
+
`BENCHWARMERS_KEY_<NAME>`, where `<NAME>` is the endpoint's key name
|
|
62
|
+
upper-cased with `-` written as `_`:
|
|
63
|
+
|
|
64
|
+
| Endpoint key name | Variable |
|
|
65
|
+
|---|---|
|
|
66
|
+
| `openrouter` | `BENCHWARMERS_KEY_OPENROUTER` |
|
|
67
|
+
| `openrouter-2` | `BENCHWARMERS_KEY_OPENROUTER_2` |
|
|
68
|
+
| `my-hub` | `BENCHWARMERS_KEY_MY_HUB` |
|
|
69
|
+
|
|
70
|
+
Without the variable, keys come from the `llm` CLI's key store
|
|
71
|
+
(`llm keys set <name>` writes there). The variable wins when both exist.
|
|
72
|
+
|
|
73
|
+
One provider can be several endpoints (a pasted key and a sign-in, or two
|
|
74
|
+
accounts); each needs its own name, and Benchwarmers suggests a free one.
|
|
75
|
+
|
|
76
|
+
## 4. Start the dashboard
|
|
77
|
+
|
|
78
|
+
python serve.py # http://localhost:8122
|
|
79
|
+
|
|
80
|
+
With no endpoint yet it opens on adding one. It listens on 127.0.0.1 only; to
|
|
81
|
+
reach it from elsewhere see "Beyond this machine" below.
|
|
82
|
+
|
|
83
|
+
Check: the page loads and Endpoints lists the endpoint from step 3.
|
|
84
|
+
|
|
85
|
+
## 5. Onboard a few models
|
|
86
|
+
|
|
87
|
+
In the dashboard: **Onboard a model**, pick a model the endpoint serves. Or:
|
|
88
|
+
|
|
89
|
+
python scripts/onboard.py "vendor/model-id" --endpoint openrouter
|
|
90
|
+
python scripts/onboard.py "vendor/model-id" --endpoint openrouter --skip-suite # probe only
|
|
91
|
+
|
|
92
|
+
Each is registered, probed (4 calls) and run through the suite. Confirm the
|
|
93
|
+
cost with the person first. Three to five models make a useful first panel.
|
|
94
|
+
|
|
95
|
+
## 6. Make a collection, start the gateway
|
|
96
|
+
|
|
97
|
+
On the Collections page: a name, the members a panel always includes, and the
|
|
98
|
+
shape of work it is for (review, design, ...). Then:
|
|
99
|
+
|
|
100
|
+
python gateway.py # http://127.0.0.1:8123/v1
|
|
101
|
+
|
|
102
|
+
Any OpenAI-compatible client asks for the model `bench/<collection>`:
|
|
103
|
+
|
|
104
|
+
curl http://127.0.0.1:8123/v1/chat/completions -H "Content-Type: application/json" \
|
|
105
|
+
-d '{"model": "bench/<collection>", "messages": [{"role": "user", "content": "..."}]}'
|
|
106
|
+
|
|
107
|
+
Every seat's answer comes back, plus a `bench` field with each seat's call id.
|
|
108
|
+
For a chat window that shows one answer, ask for `bench/<collection>:merged`
|
|
109
|
+
(or set the collection's reply to merged): a merger model writes one answer
|
|
110
|
+
saying where the seats agreed and disagreed, and every seat is still in
|
|
111
|
+
`bench`.
|
|
112
|
+
Photos go in as OpenAI `image_url` parts (an https URL, or a `data:` URL up to
|
|
113
|
+
20 MB a request); only models that take images sit, and the others are listed
|
|
114
|
+
in `bench.skipped`. One the catalog knows nothing about sits once its model
|
|
115
|
+
popup ticks Vision / OCR.
|
|
116
|
+
After the person checks an answer against the real work, record a verdict
|
|
117
|
+
(dashboard, or `POST /bench/verdict`); verdicts choose the next panels. See
|
|
118
|
+
GATEWAY.md for the whole contract.
|
|
119
|
+
|
|
120
|
+
## Beyond this machine
|
|
121
|
+
|
|
122
|
+
Both servers refuse to listen anywhere but 127.0.0.1 without an admin token:
|
|
123
|
+
|
|
124
|
+
BENCHWARMERS_ADMIN_TOKEN=<16 or more characters>
|
|
125
|
+
BENCH_BIND=0.0.0.0
|
|
126
|
+
BENCHWARMERS_PUBLIC_URL=https://bench.example.com # the address browsers use
|
|
127
|
+
|
|
128
|
+
The dashboard then asks for the token once (a session cookie for a week), and
|
|
129
|
+
the gateway routes need a gateway key made on Settings (`Authorization: Bearer
|
|
130
|
+
<key>`). Give each app its own key, limited to the collections it uses and a
|
|
131
|
+
rate; `BENCHWARMERS_REQUIRE_KEYS=1` asks for keys on this machine too. A
|
|
132
|
+
browser app on another origin also needs `BENCH_ALLOWED_ORIGINS`. Check the
|
|
133
|
+
result on Settings, Server and access, which shows each of these as it stands
|
|
134
|
+
(never a secret's value). In Docker: put the token and the `BENCHWARMERS_KEY_<NAME>` variables in
|
|
135
|
+
a `.env` beside `compose.yaml`, then `docker compose up -d`; the dashboard and
|
|
136
|
+
gateway share one port and the data folder is a volume.
|
|
137
|
+
|
|
138
|
+
## When something looks wrong
|
|
139
|
+
|
|
140
|
+
- **"no endpoints configured"** from a script: add one (step 3).
|
|
141
|
+
- **A model answers with an empty string**: usually a reasoning model that ran
|
|
142
|
+
out of its output budget, not a dead model.
|
|
143
|
+
- **"sign in again"** on a model: the endpoint's key was refused (expired or
|
|
144
|
+
revoked). Fix it on the Endpoints page (Sign in again, or Change key); it never
|
|
145
|
+
retires the model.
|
|
146
|
+
- **A server will not start**: it says why; beyond 127.0.0.1 it needs
|
|
147
|
+
`BENCHWARMERS_ADMIN_TOKEN`.
|
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
# Standard benchmarks: which to adopt, and why
|
|
2
|
+
|
|
3
|
+
Two repositories were proposed. They are not the same kind of thing, and only
|
|
4
|
+
one of them is a thing you can run.
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## `leobeeson/llm_benchmarks` — a reading list, not a harness
|
|
9
|
+
|
|
10
|
+
**What it is:** a single README cataloguing benchmarks by category, with
|
|
11
|
+
descriptions and links. Three commits. **No code, no datasets, no runner.**
|
|
12
|
+
|
|
13
|
+
**Verdict: read it, cite it, do not vendor it.**
|
|
14
|
+
|
|
15
|
+
There is nothing to pull in. Copying a catalogue into this repo creates a
|
|
16
|
+
second copy that goes stale while the original is one click away. Its value is
|
|
17
|
+
that it is a well-organised map of what exists — use it the way you would use
|
|
18
|
+
a bibliography: to decide what to go and get.
|
|
19
|
+
|
|
20
|
+
Where it *is* useful is deciding what a benchmark is even for. The categories
|
|
21
|
+
it lays out (knowledge, reasoning, coding, instruction-following, safety) are
|
|
22
|
+
a reasonable checklist against which to notice that a model rated well on
|
|
23
|
+
"coding" may be bad at the specific coding task you have.
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
## `LiveCodeBench/LiveCodeBench` — a real harness, worth running, scoped
|
|
28
|
+
|
|
29
|
+
**What it is:** the official harness for the *LiveCodeBench* paper. 1,055
|
|
30
|
+
problems from LeetCode, AtCoder and Codeforces spanning May 2023 – April 2025.
|
|
31
|
+
It evaluates code generation, self-repair, code execution and test-output
|
|
32
|
+
prediction. It supports closed API models with a `--multiprocess` flag for
|
|
33
|
+
rate-limit-adjustable parallelism, so an OpenAI-compatible endpoint —
|
|
34
|
+
which is what Open WebUI serves — can be evaluated.
|
|
35
|
+
|
|
36
|
+
**Verdict: SUPERSEDED — do not adopt. See `LIVECODEBENCH.md`.**
|
|
37
|
+
|
|
38
|
+
> **Amended after trying it.** The original verdict below was "adopt it, but
|
|
39
|
+
> scoped". That was wrong, and the fact that disproves it is *in the paragraph
|
|
40
|
+
> above*: the problems span **May 2023 – April 2025**, while our models carry a
|
|
41
|
+
> 2026 cutoff. The date filter — the entire reason to adopt it — therefore
|
|
42
|
+
> selects zero problems, and any score without the filter is contaminated.
|
|
43
|
+
> I recorded the disqualifying date here and then spent six dependency fixes
|
|
44
|
+
> before checking it against the models. The reasoning below is left intact
|
|
45
|
+
> because it is still correct about *why* the property matters; it is only
|
|
46
|
+
> wrong that this benchmark can supply it to us.
|
|
47
|
+
|
|
48
|
+
### Why it is worth having
|
|
49
|
+
|
|
50
|
+
**Contamination-free by construction, which is the whole point.** Every
|
|
51
|
+
problem carries a release date, so you can evaluate a model *only* on problems
|
|
52
|
+
published after its training cutoff. Nearly every other public benchmark has
|
|
53
|
+
leaked into training sets, which is why scores drift upward without models
|
|
54
|
+
getting better at anything. For a file whose entire purpose is tracking
|
|
55
|
+
whether a model is actually improving, that property is worth more than the
|
|
56
|
+
score itself.
|
|
57
|
+
|
|
58
|
+
**It is objective.** Notes like the ones in `MODELS.md` are honest but they
|
|
59
|
+
are *my* judgement of my own offloads, which is exactly the kind of evidence
|
|
60
|
+
that flatters itself. A pass/fail test suite does not care.
|
|
61
|
+
|
|
62
|
+
### The caveats, stated before anyone runs it
|
|
63
|
+
|
|
64
|
+
**Runtime is the binding constraint, not accuracy.** From the smoke tests in
|
|
65
|
+
`runs/2026-09-03`, latency through this Open WebUI path ranges from 6.6 s
|
|
66
|
+
(`north-mini-code`) to 134 s (`nemotron-lightning`) on a *one-word* prompt.
|
|
67
|
+
1,055 problems against the slow end is on the order of **40 hours for one
|
|
68
|
+
model**. A full sweep of six models is not a thing that happens.
|
|
69
|
+
|
|
70
|
+
→ **Run a dated subset.** The most recent 50–100 problems, which are also the
|
|
71
|
+
ones least likely to be contaminated. That is a couple of hours for the fast
|
|
72
|
+
models and an overnight run for the slow ones, and it answers the question.
|
|
73
|
+
|
|
74
|
+
**Python 3.11 and `uv`.** wendell-research is on 3.14. It needs its own
|
|
75
|
+
environment; do not try to share one.
|
|
76
|
+
|
|
77
|
+
**It measures competitive programming, and that is not what we offload.**
|
|
78
|
+
This is the important caveat. The actual tasks routed to these models are:
|
|
79
|
+
read an unfamiliar file and describe its structure; draft a component against
|
|
80
|
+
a written spec; review one small surface adversarially. LiveCodeBench measures
|
|
81
|
+
none of those. A model can be excellent at Codeforces problems and still
|
|
82
|
+
invent a filename that does not exist — which is precisely the failure
|
|
83
|
+
`gemini-flash-3.8` produced twice.
|
|
84
|
+
|
|
85
|
+
→ Treat its score as **one axis**, useful for ranking raw coding capability
|
|
86
|
+
and for noticing when a model has genuinely regressed. Not as a proxy for
|
|
87
|
+
"good at our work".
|
|
88
|
+
|
|
89
|
+
---
|
|
90
|
+
|
|
91
|
+
## The third thing, which matters more than either
|
|
92
|
+
|
|
93
|
+
**A local task suite built from our own offload shapes.**
|
|
94
|
+
|
|
95
|
+
Neither repository can tell us the thing we most want to know, because the
|
|
96
|
+
thing we most want to know is specific to this work. The suite that would:
|
|
97
|
+
|
|
98
|
+
| Task | Shape | Scored against |
|
|
99
|
+
| --- | --- | --- |
|
|
100
|
+
| Edit-point audit | Pipe 3 unfamiliar React files, ask for every user-editable value | An answer verified by hand against the files |
|
|
101
|
+
| Component draft | A tight spec (exact DOM, exact class names, framework versions) | Does it parse? Does it invent APIs? |
|
|
102
|
+
| Adversarial review | "This route is public. What can an authenticated admin do to make it serve something it should not?" | Did it find the avatar-through-brand-logo case? |
|
|
103
|
+
| Structured extraction | 40 test files → every substring assertion where a line match is meant | A known-good list |
|
|
104
|
+
|
|
105
|
+
Each has **a recorded correct answer already**, because each was done and
|
|
106
|
+
verified. That makes them regression tests for models rather than for code.
|
|
107
|
+
Cheap to run, directly predictive, and they measure the failure mode that
|
|
108
|
+
actually costs us — confident invention — which no public benchmark scores.
|
|
109
|
+
|
|
110
|
+
**ADOPTED 2026-09-04: EvalPlus (HumanEval+/MBPP+), as a floor tier only.**
|
|
111
|
+
See [`floor/README.md`](floor/README.md). It **fails** the date check below —
|
|
112
|
+
HumanEval and MBPP are 2021, our models are 2026 — and was adopted anyway,
|
|
113
|
+
knowingly, because a contaminated benchmark is still valid *downward*:
|
|
114
|
+
memorisation can only inflate a score, so a low one is real evidence and a high
|
|
115
|
+
one is worthless. It supplies the two things our own suite cannot — an absolute
|
|
116
|
+
scale, and a way to baseline a brand-new model against published figures. It
|
|
117
|
+
may never rank our models. That is the difference between adopting it and
|
|
118
|
+
adopting LiveCodeBench, which was adopted for a job it could not do.
|
|
119
|
+
|
|
120
|
+
**Recommended order (amended):** the local suite is the primary
|
|
121
|
+
benchmark, not the first of two. LiveCodeBench is dropped — its data ends
|
|
122
|
+
before our models' training cutoffs. The catalogue stays a bibliography.
|
|
123
|
+
|
|
124
|
+
**Before adopting any benchmark from it, check one thing first:** what is the
|
|
125
|
+
newest question, and is it after the cutoff of the model you want to score?
|
|
126
|
+
Every option in this file except our own suite fails that check today. Our
|
|
127
|
+
suite passes it for a reason no public benchmark can copy: its tasks are
|
|
128
|
+
built on private codebases, so they are in nobody's training set.
|
|
129
|
+
|
|
130
|
+
---
|
|
131
|
+
|
|
132
|
+
# Second review — 2026-09-04
|
|
133
|
+
|
|
134
|
+
Five more candidates, assessed against three criteria the operator set: **more
|
|
135
|
+
than Python**, **newer**, and **contamination-free if possible**. Each was
|
|
136
|
+
checked rather than recalled, because the LiveCodeBench detour came from
|
|
137
|
+
trusting a recollection.
|
|
138
|
+
|
|
139
|
+
| Candidate | Beyond Python | Contamination | Verdict |
|
|
140
|
+
| --- | --- | --- | --- |
|
|
141
|
+
| **FuncBenchGen** | Function calling, not code-gen | **Free by construction** | **Adopt** |
|
|
142
|
+
| **MultiPL-E** | **18 languages** | Inherits HumanEval/MBPP (2021) | **Adopt into Floor** |
|
|
143
|
+
| Ag-LiveCodeBench-X | Yes (Lua, Julia, …) | Inherits LCB's 2025-04 ceiling | Wait |
|
|
144
|
+
| LiveCodeBench | Python | Data ends 2025-04-06 | Still blocked |
|
|
145
|
+
| HELM | Very broad | Public datasets | Framework, not a fit |
|
|
146
|
+
| BIG-bench | Broad | 2021–22, absorbed | Skip |
|
|
147
|
+
|
|
148
|
+
## FuncBenchGen — the one that is genuinely uncontaminated
|
|
149
|
+
|
|
150
|
+
It **generates** tasks by traversing a hidden function-dependency DAG with
|
|
151
|
+
controllable depth and distractors, rather than publishing a fixed set. That
|
|
152
|
+
makes it contamination-free *by construction* rather than by date — the only
|
|
153
|
+
durable form, because anything published eventually gets scraped. ICLR 2026,
|
|
154
|
+
and it interfaces through LiteLLM so an OpenAI-compatible endpoint works.
|
|
155
|
+
|
|
156
|
+
It measures **multi-step tool use**, which is a different axis from writing a
|
|
157
|
+
function and one nothing else here covers.
|
|
158
|
+
|
|
159
|
+
## MultiPL-E — the answer to "not just Python"
|
|
160
|
+
|
|
161
|
+
Translates HumanEval and MBPP into **18 further languages**. 1,129 commits, and
|
|
162
|
+
it ships a container with every toolchain.
|
|
163
|
+
|
|
164
|
+
**It is the same 2021 problems, so it is equally contaminated in principle** —
|
|
165
|
+
which is why it belongs in `floor/` under the same downward-only rule, not
|
|
166
|
+
beside the suite. One real nuance: a translation into a low-resource language
|
|
167
|
+
(Lua, Racket, OCaml) is *less* likely to have been memorised verbatim than the
|
|
168
|
+
Python original, simply because less of that code exists to train on. Weaker
|
|
169
|
+
contamination, not absent.
|
|
170
|
+
|
|
171
|
+
**The integration gap:** its runners target HuggingFace and vLLM models, not
|
|
172
|
+
API endpoints. That is the same wall `evalplus.codegen` presented, and the same
|
|
173
|
+
answer applies — take the dataset from the Hub and generate through our own
|
|
174
|
+
`llm` path, using their container only for execution.
|
|
175
|
+
|
|
176
|
+
## Why Ag-LiveCodeBench-X is a wait, not a no
|
|
177
|
+
|
|
178
|
+
Multi-language and agentic, from the same lab as MultiPL-E. But it is a variant
|
|
179
|
+
**of** LiveCodeBench, so it inherits that problem set and therefore the same
|
|
180
|
+
date ceiling that disqualified it: the newest problem predates our models'
|
|
181
|
+
training cutoffs. One commit on main. Revisit when it has its own problems or a
|
|
182
|
+
newer LCB release lands.
|
|
183
|
+
|
|
184
|
+
## HELM and BIG-bench
|
|
185
|
+
|
|
186
|
+
**HELM** is a framework rather than a benchmark — broad, actively maintained,
|
|
187
|
+
genuinely useful for holistic evaluation. Its scenarios are public datasets, so
|
|
188
|
+
it inherits their contamination, and it is heavy. If breadth beyond code is
|
|
189
|
+
ever wanted it is the right tool; it is not the right tool for "is this model
|
|
190
|
+
good at our work".
|
|
191
|
+
|
|
192
|
+
**BIG-bench** is 2021–22, superseded in practice by BIG-Bench Hard, and
|
|
193
|
+
thoroughly absorbed into training sets. Skip.
|
|
194
|
+
|
|
195
|
+
## The rule this review confirms
|
|
196
|
+
|
|
197
|
+
**Only generated benchmarks stay uncontaminated, and only private code stays
|
|
198
|
+
private.** Everything published is on a clock. That is why the tiers are
|
|
199
|
+
shaped as they are: `suite/` (our own repositories) and FuncBenchGen
|
|
200
|
+
(synthesised per run) are the two that can be trusted upward; everything else
|
|
201
|
+
is a floor.
|
|
202
|
+
|
|
203
|
+
---
|
|
204
|
+
|
|
205
|
+
# What already existed, and what this should have reused (2026-09-05)
|
|
206
|
+
|
|
207
|
+
Asked late whether an off-the-shelf tool would have done this. **Largely yes,
|
|
208
|
+
for one of the four tiers**, and the honest answer is that it should have been
|
|
209
|
+
checked at the start rather than after the code was written.
|
|
210
|
+
|
|
211
|
+
| What we built | What already does it |
|
|
212
|
+
| --- | --- |
|
|
213
|
+
| `suite/run.py` — run N models over N prompts, assert on output, compare | **promptfoo** — a CLI and library for exactly this, with a viewer |
|
|
214
|
+
| `metrics/cost.py` — token and cost accounting | **Langfuse**, **Helicone** — LLM observability with cost tracking |
|
|
215
|
+
| `floor/` — public code benchmarks | **EvalPlus** (which we did use), `lm-evaluation-harness` |
|
|
216
|
+
| `metrics/route.py` — pick a model per task | **RouteLLM**, **Not Diamond**, OpenRouter's own auto-router |
|
|
217
|
+
|
|
218
|
+
**`promptfoo` is the real overlap.** It would have supplied the runner, the
|
|
219
|
+
assertion mechanism, multi-model comparison and a results viewer — a good
|
|
220
|
+
share of `suite/run.py` and `serve.py`.
|
|
221
|
+
|
|
222
|
+
## What would not have come off a shelf
|
|
223
|
+
|
|
224
|
+
- **The tasks.** Drawn from private repositories with answers verified before
|
|
225
|
+
any model saw them. No tool can supply those; that is the whole point of the
|
|
226
|
+
tier and the reason it can rank when the public ones cannot.
|
|
227
|
+
- **The failure taxonomy.** `structural` / `entitlement` / `capacity` /
|
|
228
|
+
`timeout`, each tied to a different ACTION — fix the registration, keep and
|
|
229
|
+
watch, retry, wait. Generic harnesses record pass/fail, and every hard-won
|
|
230
|
+
correction in this repo came from refusing to collapse those.
|
|
231
|
+
- **The benchmark-versus-offload distinction.** A general tool counts calls. It
|
|
232
|
+
cannot know that 164 of them were a floor run rather than work, which is the
|
|
233
|
+
difference between "most used" and "most measured".
|
|
234
|
+
- **Explore/exploit routing on staleness.** Commercial routers optimise cost
|
|
235
|
+
and quality per call. None of them is trying to stop a local roster of models
|
|
236
|
+
going stale through disuse.
|
|
237
|
+
|
|
238
|
+
## Should it be migrated
|
|
239
|
+
|
|
240
|
+
**Not now, and the reason is where the value sits.** It is in the tasks, the
|
|
241
|
+
verified answers and the recorded reasoning — not in the runner, which is the
|
|
242
|
+
part promptfoo would replace. Swapping it would re-implement the taxonomy and
|
|
243
|
+
the ledger inside somebody else's abstraction for no gain today.
|
|
244
|
+
|
|
245
|
+
**Revisit if the suite gets large — but as a COMPONENT, not a replacement.**
|
|
246
|
+
That is the sharper framing, and it is the one to act on. This repository is
|
|
247
|
+
not an eval runner; it is an integration of four things that are usually
|
|
248
|
+
separate products: evaluation, cost accounting, availability monitoring and
|
|
249
|
+
routing. The glue between them is where its value is, and no single tool sells
|
|
250
|
+
that glue.
|
|
251
|
+
|
|
252
|
+
So at forty or fifty tasks the move is not "migrate to promptfoo". It is
|
|
253
|
+
"let promptfoo be the runner inside `suite/`", keeping the failure taxonomy,
|
|
254
|
+
the offload ledger and the router above it. That swaps ~400 lines we maintain
|
|
255
|
+
for something better maintained, and gives up nothing that is actually ours.
|
|
256
|
+
|
|
257
|
+
The tasks are portable, which is what makes that possible whenever it becomes
|
|
258
|
+
worth doing.
|
|
259
|
+
|
|
260
|
+
**The lesson is the process, not the verdict.** The same check that now
|
|
261
|
+
precedes adopting a benchmark — *does this already exist, and does it fit* —
|
|
262
|
+
should have preceded building one.
|