@wendellresearch-ai/benchwarmers 0.1.1 → 0.2.1

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 (96) hide show
  1. package/AGENTS.md +147 -147
  2. package/BENCHMARKS.md +262 -262
  3. package/GATEWAY.md +272 -271
  4. package/NOTICE +28 -28
  5. package/PRIVACY.md +46 -46
  6. package/README.md +368 -275
  7. package/SECURITY.md +83 -83
  8. package/TERMS.md +22 -22
  9. package/USAGE.md +170 -155
  10. package/VERSION +1 -1
  11. package/bin/benchwarmers.js +16 -72
  12. package/cli.py +666 -0
  13. package/examples/config/gateway.json +5 -5
  14. package/examples/config/model-roles.json +11 -11
  15. package/gateway.py +755 -712
  16. package/launcher.py +120 -0
  17. package/mcp_server.py +266 -0
  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 +295 -295
  22. package/metrics/client.py +394 -373
  23. package/metrics/cliproxy.py +191 -191
  24. package/metrics/connect.py +691 -691
  25. package/metrics/cost.py +152 -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/guard.py +617 -592
  30. package/metrics/learn.py +221 -221
  31. package/metrics/litellm_hub.py +206 -206
  32. package/metrics/model_roles.py +84 -84
  33. package/metrics/offload.py +166 -166
  34. package/metrics/owui.py +205 -205
  35. package/metrics/paths.py +60 -60
  36. package/metrics/route.py +579 -574
  37. package/metrics/scheduler.py +275 -275
  38. package/metrics/sources.py +167 -167
  39. package/metrics/wrong.py +144 -144
  40. package/package.json +68 -64
  41. package/perf/README.md +89 -89
  42. package/perf/run.py +261 -261
  43. package/scripts/auto_retire.py +367 -367
  44. package/scripts/check.py +108 -104
  45. package/scripts/check_deprecations.py +378 -378
  46. package/scripts/check_themes.py +103 -103
  47. package/scripts/init.py +124 -124
  48. package/scripts/list_served.py +78 -78
  49. package/scripts/notice.py +78 -78
  50. package/scripts/onboard.py +401 -331
  51. package/scripts/provider_tags.py +129 -129
  52. package/scripts/reprefix.py +136 -136
  53. package/scripts/sync_config.py +105 -105
  54. package/scripts/test_auth.py +255 -255
  55. package/scripts/test_cli.py +189 -0
  56. package/scripts/test_client.py +233 -233
  57. package/scripts/test_connect.py +222 -222
  58. package/scripts/test_first_run.py +180 -180
  59. package/scripts/test_hubs.py +328 -328
  60. package/scripts/test_launcher.py +67 -0
  61. package/scripts/test_llm_log.py +85 -0
  62. package/scripts/test_mcp.py +178 -0
  63. package/scripts/test_merged.py +214 -193
  64. package/scripts/test_no_owui.py +291 -291
  65. package/scripts/test_owui.py +90 -90
  66. package/scripts/test_serve_edit.py +448 -386
  67. package/scripts/test_verdict.py +98 -98
  68. package/scripts/test_vision.py +228 -228
  69. package/serve.py +3904 -3662
  70. package/suite/mine.py +154 -154
  71. package/suite/pace.py +145 -145
  72. package/suite/run.py +1046 -1040
  73. package/suite/seed.py +421 -421
  74. package/suite/tasks/claim-alias-unbound/fixtures/onboard.py +286 -286
  75. package/suite/tasks/claim-error-text-string/fixtures/decide.py +187 -187
  76. package/suite/tasks/claim-list-body/fixtures/gateway.py +235 -235
  77. package/suite/tasks/claim-member-nominated-twice/fixtures/gateway.py +284 -284
  78. package/suite/tasks/claim-nominee-uses-slot/fixtures/gateway.py +284 -284
  79. package/suite/tasks/claim-silent-exit/fixtures/gateway.py +235 -235
  80. package/suite/tasks/claim-sse-hang/fixtures/gateway.py +235 -235
  81. package/suite/tasks/claim-unknown-nominee-crash/fixtures/gateway.py +284 -284
  82. package/suite/tasks/rebench-matchms-809-bug/task.json +23 -23
  83. package/suite/tasks/rebench-matchms-809-control/task.json +27 -27
  84. package/suite/tasks/rebench-more-itertools-1028-bug/task.json +23 -23
  85. package/suite/tasks/rebench-more-itertools-1028-control/task.json +27 -27
  86. package/suite/tasks/rebench-narwhals-2864-bug/task.json +23 -23
  87. package/suite/tasks/rebench-narwhals-2864-control/task.json +27 -27
  88. package/suite/tasks/rebench-quantecon-py-769-bug/task.json +23 -23
  89. package/suite/tasks/rebench-quantecon-py-769-control/task.json +27 -27
  90. package/suite/tasks/rebench-scrapy-6867-bug/task.json +23 -23
  91. package/suite/tasks/rebench-scrapy-6867-control/task.json +27 -27
  92. package/ui/bench.css +430 -424
  93. package/ui/bench.js +1756 -1555
  94. package/ui/themes/dark.css +35 -35
  95. package/ui/themes/hardwood.css +52 -52
  96. package/ui/themes/rainforest.css +32 -32
package/AGENTS.md CHANGED
@@ -1,147 +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`.
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`.