@wendellresearch-ai/benchwarmers 0.2.0 → 0.2.2

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 (103) hide show
  1. package/AGENTS.md +152 -147
  2. package/BENCHMARKS.md +262 -262
  3. package/GATEWAY.md +415 -272
  4. package/NOTICE +28 -28
  5. package/PRIVACY.md +46 -46
  6. package/README.md +408 -314
  7. package/SECURITY.md +83 -83
  8. package/TERMS.md +22 -22
  9. package/USAGE.md +186 -163
  10. package/VERSION +1 -1
  11. package/bin/benchwarmers.js +16 -74
  12. package/cli.py +674 -0
  13. package/examples/config/gateway.json +5 -5
  14. package/examples/config/model-roles.json +11 -11
  15. package/gateway.py +939 -755
  16. package/launcher.py +120 -0
  17. package/mcp_server.py +266 -266
  18. package/metrics/alerts.py +116 -116
  19. package/metrics/aliases.py +41 -41
  20. package/metrics/bench_collections.py +141 -141
  21. package/metrics/catalog.py +304 -295
  22. package/metrics/client.py +804 -394
  23. package/metrics/cliproxy.py +191 -191
  24. package/metrics/connect.py +691 -691
  25. package/metrics/cost.py +171 -152
  26. package/metrics/decide.py +227 -227
  27. package/metrics/discover.py +318 -318
  28. package/metrics/endpoints.py +436 -436
  29. package/metrics/formats.py +1021 -0
  30. package/metrics/guard.py +647 -592
  31. package/metrics/learn.py +234 -221
  32. package/metrics/ledger.py +148 -0
  33. package/metrics/litellm_hub.py +206 -206
  34. package/metrics/model_roles.py +94 -84
  35. package/metrics/offload.py +166 -166
  36. package/metrics/owui.py +205 -205
  37. package/metrics/pacing.py +248 -0
  38. package/metrics/paths.py +60 -60
  39. package/metrics/quota.py +383 -0
  40. package/metrics/route.py +581 -579
  41. package/metrics/scheduler.py +275 -275
  42. package/metrics/sources.py +167 -167
  43. package/metrics/wrong.py +144 -144
  44. package/package.json +69 -65
  45. package/perf/README.md +89 -89
  46. package/perf/run.py +284 -261
  47. package/scripts/auto_retire.py +367 -367
  48. package/scripts/check.py +113 -106
  49. package/scripts/check_deprecations.py +378 -378
  50. package/scripts/check_themes.py +103 -103
  51. package/scripts/init.py +124 -124
  52. package/scripts/list_served.py +78 -78
  53. package/scripts/notice.py +78 -78
  54. package/scripts/onboard.py +410 -331
  55. package/scripts/provider_tags.py +129 -129
  56. package/scripts/reprefix.py +136 -136
  57. package/scripts/sync_config.py +105 -105
  58. package/scripts/test_auth.py +255 -255
  59. package/scripts/test_cli.py +189 -0
  60. package/scripts/test_client.py +277 -233
  61. package/scripts/test_connect.py +222 -222
  62. package/scripts/test_first_run.py +180 -180
  63. package/scripts/test_formats.py +549 -0
  64. package/scripts/test_hubs.py +328 -328
  65. package/scripts/test_launcher.py +67 -0
  66. package/scripts/test_llm_log.py +85 -81
  67. package/scripts/test_mcp.py +178 -178
  68. package/scripts/test_merged.py +215 -214
  69. package/scripts/test_no_owui.py +291 -291
  70. package/scripts/test_owui.py +90 -90
  71. package/scripts/test_quota.py +334 -0
  72. package/scripts/test_serve_edit.py +453 -438
  73. package/scripts/test_server_json.py +79 -0
  74. package/scripts/test_verdict.py +102 -98
  75. package/scripts/test_vision.py +231 -228
  76. package/serve.py +3972 -3764
  77. package/suite/mine.py +154 -154
  78. package/suite/pace.py +145 -145
  79. package/suite/run.py +1046 -1042
  80. package/suite/seed.py +421 -421
  81. package/suite/tasks/claim-alias-unbound/fixtures/onboard.py +286 -286
  82. package/suite/tasks/claim-error-text-string/fixtures/decide.py +187 -187
  83. package/suite/tasks/claim-list-body/fixtures/gateway.py +235 -235
  84. package/suite/tasks/claim-member-nominated-twice/fixtures/gateway.py +284 -284
  85. package/suite/tasks/claim-nominee-uses-slot/fixtures/gateway.py +284 -284
  86. package/suite/tasks/claim-silent-exit/fixtures/gateway.py +235 -235
  87. package/suite/tasks/claim-sse-hang/fixtures/gateway.py +235 -235
  88. package/suite/tasks/claim-unknown-nominee-crash/fixtures/gateway.py +284 -284
  89. package/suite/tasks/rebench-matchms-809-bug/task.json +23 -23
  90. package/suite/tasks/rebench-matchms-809-control/task.json +27 -27
  91. package/suite/tasks/rebench-more-itertools-1028-bug/task.json +23 -23
  92. package/suite/tasks/rebench-more-itertools-1028-control/task.json +27 -27
  93. package/suite/tasks/rebench-narwhals-2864-bug/task.json +23 -23
  94. package/suite/tasks/rebench-narwhals-2864-control/task.json +27 -27
  95. package/suite/tasks/rebench-quantecon-py-769-bug/task.json +23 -23
  96. package/suite/tasks/rebench-quantecon-py-769-control/task.json +27 -27
  97. package/suite/tasks/rebench-scrapy-6867-bug/task.json +23 -23
  98. package/suite/tasks/rebench-scrapy-6867-control/task.json +27 -27
  99. package/ui/bench.css +430 -425
  100. package/ui/bench.js +1757 -1576
  101. package/ui/themes/dark.css +35 -35
  102. package/ui/themes/hardwood.css +52 -52
  103. package/ui/themes/rainforest.css +32 -32
package/AGENTS.md CHANGED
@@ -1,147 +1,152 @@
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`.
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
+ Clients of the Anthropic, Ollama, Gemini and Responses APIs work too, with
109
+ the server's address as their base URL (GATEWAY.md, "Other API formats");
110
+ requests carrying tools are refused, since a panel answers with text.
111
+ For a chat window that shows one answer, ask for `bench/<collection>:merged`
112
+ (or set the collection's reply to merged): a merger model writes one answer
113
+ saying where the seats agreed and disagreed, and every seat is still in
114
+ `bench`.
115
+ Photos go in as OpenAI `image_url` parts (an https URL, or a `data:` URL up to
116
+ 20 MB a request); only models that take images sit, and the others are listed
117
+ in `bench.skipped`. One the catalog knows nothing about sits once its model
118
+ popup ticks Vision / OCR.
119
+ After the person checks an answer against the real work, record a verdict
120
+ (dashboard, or `POST /bench/verdict`); verdicts choose the next panels. See
121
+ GATEWAY.md for the whole contract.
122
+
123
+ ## Beyond this machine
124
+
125
+ Both servers refuse to listen anywhere but 127.0.0.1 without an admin token:
126
+
127
+ BENCHWARMERS_ADMIN_TOKEN=<16 or more characters>
128
+ BENCH_BIND=0.0.0.0
129
+ BENCHWARMERS_PUBLIC_URL=https://bench.example.com # the address browsers use
130
+
131
+ The dashboard then asks for the token once (a session cookie for a week), and
132
+ the gateway routes need a gateway key made on Settings (`Authorization: Bearer
133
+ <key>`). Give each app its own key, limited to the collections it uses and a
134
+ rate; `BENCHWARMERS_REQUIRE_KEYS=1` asks for keys on this machine too. A
135
+ browser app on another origin also needs `BENCH_ALLOWED_ORIGINS`. Check the
136
+ result on Settings, Server and access, which shows each of these as it stands
137
+ (never a secret's value). In Docker: put the token and the `BENCHWARMERS_KEY_<NAME>` variables in
138
+ a `.env` beside `compose.yaml`, then `docker compose up -d`; the dashboard and
139
+ gateway share one port and the data folder is a volume. For a hosting platform
140
+ (Fly.io, Railway, Render) or a VPS with Caddy, follow [HOSTING.md](HOSTING.md)
141
+ and its templates under `deploy/`.
142
+
143
+ ## When something looks wrong
144
+
145
+ - **"no endpoints configured"** from a script: add one (step 3).
146
+ - **A model answers with an empty string**: usually a reasoning model that ran
147
+ out of its output budget, not a dead model.
148
+ - **"sign in again"** on a model: the endpoint's key was refused (expired or
149
+ revoked). Fix it on the Endpoints page (Sign in again, or Change key); it never
150
+ retires the model.
151
+ - **A server will not start**: it says why; beyond 127.0.0.1 it needs
152
+ `BENCHWARMERS_ADMIN_TOKEN`.