benchwarmers 0.2.1__py3-none-any.whl

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.
Files changed (133) hide show
  1. benchwarmers/AGENTS.md +147 -0
  2. benchwarmers/BENCHMARKS.md +262 -0
  3. benchwarmers/GATEWAY.md +272 -0
  4. benchwarmers/NOTICE +28 -0
  5. benchwarmers/PRIVACY.md +46 -0
  6. benchwarmers/SECURITY.md +83 -0
  7. benchwarmers/TERMS.md +22 -0
  8. benchwarmers/USAGE.md +170 -0
  9. benchwarmers/VERSION +1 -0
  10. benchwarmers/cli.py +666 -0
  11. benchwarmers/examples/config/gateway.json +5 -0
  12. benchwarmers/examples/config/model-roles.json +11 -0
  13. benchwarmers/gateway.py +755 -0
  14. benchwarmers/launcher.py +120 -0
  15. benchwarmers/mcp_server.py +266 -0
  16. benchwarmers/metrics/alerts.py +116 -0
  17. benchwarmers/metrics/aliases.py +41 -0
  18. benchwarmers/metrics/bench_collections.py +141 -0
  19. benchwarmers/metrics/catalog.py +295 -0
  20. benchwarmers/metrics/client.py +394 -0
  21. benchwarmers/metrics/cliproxy.py +191 -0
  22. benchwarmers/metrics/connect.py +691 -0
  23. benchwarmers/metrics/cost.py +152 -0
  24. benchwarmers/metrics/decide.py +227 -0
  25. benchwarmers/metrics/discover.py +318 -0
  26. benchwarmers/metrics/endpoints.py +436 -0
  27. benchwarmers/metrics/guard.py +617 -0
  28. benchwarmers/metrics/learn.py +221 -0
  29. benchwarmers/metrics/litellm_hub.py +206 -0
  30. benchwarmers/metrics/locked.py +142 -0
  31. benchwarmers/metrics/model_roles.py +84 -0
  32. benchwarmers/metrics/offload.py +166 -0
  33. benchwarmers/metrics/owui.py +205 -0
  34. benchwarmers/metrics/paths.py +60 -0
  35. benchwarmers/metrics/probe_caps.py +150 -0
  36. benchwarmers/metrics/route.py +579 -0
  37. benchwarmers/metrics/scheduler.py +275 -0
  38. benchwarmers/metrics/sources.py +167 -0
  39. benchwarmers/metrics/test_decide.py +29 -0
  40. benchwarmers/metrics/wrong.py +144 -0
  41. benchwarmers/perf/README.md +89 -0
  42. benchwarmers/perf/run.py +261 -0
  43. benchwarmers/repoqa/README.md +78 -0
  44. benchwarmers/repoqa/run.py +307 -0
  45. benchwarmers/scripts/auto_retire.py +367 -0
  46. benchwarmers/scripts/check.py +108 -0
  47. benchwarmers/scripts/check_deprecations.py +378 -0
  48. benchwarmers/scripts/check_themes.py +103 -0
  49. benchwarmers/scripts/init.py +124 -0
  50. benchwarmers/scripts/list_served.py +78 -0
  51. benchwarmers/scripts/notice.py +78 -0
  52. benchwarmers/scripts/onboard.py +401 -0
  53. benchwarmers/scripts/provider_tags.py +129 -0
  54. benchwarmers/scripts/reprefix.py +136 -0
  55. benchwarmers/scripts/sync_config.py +105 -0
  56. benchwarmers/scripts/test_auth.py +255 -0
  57. benchwarmers/scripts/test_cli.py +189 -0
  58. benchwarmers/scripts/test_client.py +233 -0
  59. benchwarmers/scripts/test_connect.py +222 -0
  60. benchwarmers/scripts/test_first_run.py +180 -0
  61. benchwarmers/scripts/test_hubs.py +328 -0
  62. benchwarmers/scripts/test_launcher.py +67 -0
  63. benchwarmers/scripts/test_llm_log.py +85 -0
  64. benchwarmers/scripts/test_mcp.py +178 -0
  65. benchwarmers/scripts/test_merged.py +214 -0
  66. benchwarmers/scripts/test_no_owui.py +291 -0
  67. benchwarmers/scripts/test_owui.py +90 -0
  68. benchwarmers/scripts/test_serve_edit.py +448 -0
  69. benchwarmers/scripts/test_verdict.py +98 -0
  70. benchwarmers/scripts/test_vision.py +228 -0
  71. benchwarmers/serve.py +3904 -0
  72. benchwarmers/suite/README.md +152 -0
  73. benchwarmers/suite/REBENCH.md +101 -0
  74. benchwarmers/suite/mine.py +154 -0
  75. benchwarmers/suite/pace.py +145 -0
  76. benchwarmers/suite/rebench-rejected.json +8 -0
  77. benchwarmers/suite/rebench.py +274 -0
  78. benchwarmers/suite/run.py +1046 -0
  79. benchwarmers/suite/seed.py +421 -0
  80. benchwarmers/suite/tasks/claim-alias-unbound/fixtures/onboard.py +286 -0
  81. benchwarmers/suite/tasks/claim-alias-unbound/task.json +23 -0
  82. benchwarmers/suite/tasks/claim-error-text-string/fixtures/decide.py +187 -0
  83. benchwarmers/suite/tasks/claim-error-text-string/task.json +23 -0
  84. benchwarmers/suite/tasks/claim-list-body/fixtures/gateway.py +235 -0
  85. benchwarmers/suite/tasks/claim-list-body/task.json +23 -0
  86. benchwarmers/suite/tasks/claim-member-nominated-twice/fixtures/gateway.py +284 -0
  87. benchwarmers/suite/tasks/claim-member-nominated-twice/fixtures/route.py +542 -0
  88. benchwarmers/suite/tasks/claim-member-nominated-twice/task.json +24 -0
  89. benchwarmers/suite/tasks/claim-nominee-uses-slot/fixtures/gateway.py +284 -0
  90. benchwarmers/suite/tasks/claim-nominee-uses-slot/fixtures/route.py +542 -0
  91. benchwarmers/suite/tasks/claim-nominee-uses-slot/task.json +24 -0
  92. benchwarmers/suite/tasks/claim-silent-exit/fixtures/gateway.py +235 -0
  93. benchwarmers/suite/tasks/claim-silent-exit/task.json +23 -0
  94. benchwarmers/suite/tasks/claim-sse-hang/fixtures/gateway.py +235 -0
  95. benchwarmers/suite/tasks/claim-sse-hang/task.json +23 -0
  96. benchwarmers/suite/tasks/claim-unknown-nominee-crash/fixtures/gateway.py +284 -0
  97. benchwarmers/suite/tasks/claim-unknown-nominee-crash/fixtures/route.py +542 -0
  98. benchwarmers/suite/tasks/claim-unknown-nominee-crash/task.json +24 -0
  99. benchwarmers/suite/tasks/rebench-matchms-809-bug/task.json +23 -0
  100. benchwarmers/suite/tasks/rebench-matchms-809-control/task.json +27 -0
  101. benchwarmers/suite/tasks/rebench-more-itertools-1028-bug/task.json +23 -0
  102. benchwarmers/suite/tasks/rebench-more-itertools-1028-control/task.json +27 -0
  103. benchwarmers/suite/tasks/rebench-narwhals-2864-bug/task.json +23 -0
  104. benchwarmers/suite/tasks/rebench-narwhals-2864-control/task.json +27 -0
  105. benchwarmers/suite/tasks/rebench-quantecon-py-769-bug/task.json +23 -0
  106. benchwarmers/suite/tasks/rebench-quantecon-py-769-control/task.json +27 -0
  107. benchwarmers/suite/tasks/rebench-scrapy-6867-bug/task.json +23 -0
  108. benchwarmers/suite/tasks/rebench-scrapy-6867-control/task.json +27 -0
  109. benchwarmers/suite/test_mine.py +31 -0
  110. benchwarmers/suite/test_pick.py +51 -0
  111. benchwarmers/suite/test_rebench.py +67 -0
  112. benchwarmers/suite/test_score.py +30 -0
  113. benchwarmers/suite/test_seed.py +78 -0
  114. benchwarmers/ui/bench.css +430 -0
  115. benchwarmers/ui/bench.js +1756 -0
  116. benchwarmers/ui/fonts/OFL-Chivo-Mono.txt +93 -0
  117. benchwarmers/ui/fonts/OFL-Chivo.txt +93 -0
  118. benchwarmers/ui/fonts/chivo-latin-400-normal.woff2 +0 -0
  119. benchwarmers/ui/fonts/chivo-latin-500-normal.woff2 +0 -0
  120. benchwarmers/ui/fonts/chivo-latin-700-normal.woff2 +0 -0
  121. benchwarmers/ui/fonts/chivo-latin-800-normal.woff2 +0 -0
  122. benchwarmers/ui/fonts/chivo-mono-latin-400-normal.woff2 +0 -0
  123. benchwarmers/ui/fonts/chivo-mono-latin-500-normal.woff2 +0 -0
  124. benchwarmers/ui/mascot.png +0 -0
  125. benchwarmers/ui/themes/dark.css +35 -0
  126. benchwarmers/ui/themes/hardwood.css +52 -0
  127. benchwarmers/ui/themes/rainforest.css +32 -0
  128. benchwarmers-0.2.1.dist-info/METADATA +390 -0
  129. benchwarmers-0.2.1.dist-info/RECORD +133 -0
  130. benchwarmers-0.2.1.dist-info/WHEEL +4 -0
  131. benchwarmers-0.2.1.dist-info/entry_points.txt +3 -0
  132. benchwarmers-0.2.1.dist-info/licenses/LICENSE +21 -0
  133. benchwarmers-0.2.1.dist-info/licenses/NOTICE +28 -0
benchwarmers/AGENTS.md ADDED
@@ -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.