@wendellresearch-ai/benchwarmers 0.2.0 → 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.
- package/AGENTS.md +147 -147
- package/BENCHMARKS.md +262 -262
- package/GATEWAY.md +272 -272
- package/NOTICE +28 -28
- package/PRIVACY.md +46 -46
- package/README.md +368 -314
- package/SECURITY.md +83 -83
- package/TERMS.md +22 -22
- package/USAGE.md +170 -163
- package/VERSION +1 -1
- package/bin/benchwarmers.js +16 -74
- package/cli.py +666 -0
- package/examples/config/gateway.json +5 -5
- package/examples/config/model-roles.json +11 -11
- package/gateway.py +755 -755
- package/launcher.py +120 -0
- package/mcp_server.py +266 -266
- package/metrics/alerts.py +116 -116
- package/metrics/aliases.py +41 -41
- package/metrics/bench_collections.py +141 -141
- package/metrics/catalog.py +295 -295
- package/metrics/client.py +394 -394
- package/metrics/cliproxy.py +191 -191
- package/metrics/connect.py +691 -691
- package/metrics/cost.py +152 -152
- package/metrics/decide.py +227 -227
- package/metrics/discover.py +318 -318
- package/metrics/endpoints.py +436 -436
- package/metrics/guard.py +617 -592
- package/metrics/learn.py +221 -221
- package/metrics/litellm_hub.py +206 -206
- package/metrics/model_roles.py +84 -84
- package/metrics/offload.py +166 -166
- package/metrics/owui.py +205 -205
- package/metrics/paths.py +60 -60
- package/metrics/route.py +579 -579
- package/metrics/scheduler.py +275 -275
- package/metrics/sources.py +167 -167
- package/metrics/wrong.py +144 -144
- package/package.json +68 -65
- package/perf/README.md +89 -89
- package/perf/run.py +261 -261
- package/scripts/auto_retire.py +367 -367
- package/scripts/check.py +108 -106
- package/scripts/check_deprecations.py +378 -378
- package/scripts/check_themes.py +103 -103
- package/scripts/init.py +124 -124
- package/scripts/list_served.py +78 -78
- package/scripts/notice.py +78 -78
- package/scripts/onboard.py +401 -331
- package/scripts/provider_tags.py +129 -129
- package/scripts/reprefix.py +136 -136
- package/scripts/sync_config.py +105 -105
- package/scripts/test_auth.py +255 -255
- package/scripts/test_cli.py +189 -0
- package/scripts/test_client.py +233 -233
- package/scripts/test_connect.py +222 -222
- package/scripts/test_first_run.py +180 -180
- package/scripts/test_hubs.py +328 -328
- package/scripts/test_launcher.py +67 -0
- package/scripts/test_llm_log.py +85 -81
- package/scripts/test_mcp.py +178 -178
- package/scripts/test_merged.py +214 -214
- package/scripts/test_no_owui.py +291 -291
- package/scripts/test_owui.py +90 -90
- package/scripts/test_serve_edit.py +448 -438
- package/scripts/test_verdict.py +98 -98
- package/scripts/test_vision.py +228 -228
- package/serve.py +3904 -3764
- package/suite/mine.py +154 -154
- package/suite/pace.py +145 -145
- package/suite/run.py +1046 -1042
- package/suite/seed.py +421 -421
- package/suite/tasks/claim-alias-unbound/fixtures/onboard.py +286 -286
- package/suite/tasks/claim-error-text-string/fixtures/decide.py +187 -187
- package/suite/tasks/claim-list-body/fixtures/gateway.py +235 -235
- package/suite/tasks/claim-member-nominated-twice/fixtures/gateway.py +284 -284
- package/suite/tasks/claim-nominee-uses-slot/fixtures/gateway.py +284 -284
- package/suite/tasks/claim-silent-exit/fixtures/gateway.py +235 -235
- package/suite/tasks/claim-sse-hang/fixtures/gateway.py +235 -235
- package/suite/tasks/claim-unknown-nominee-crash/fixtures/gateway.py +284 -284
- package/suite/tasks/rebench-matchms-809-bug/task.json +23 -23
- package/suite/tasks/rebench-matchms-809-control/task.json +27 -27
- package/suite/tasks/rebench-more-itertools-1028-bug/task.json +23 -23
- package/suite/tasks/rebench-more-itertools-1028-control/task.json +27 -27
- package/suite/tasks/rebench-narwhals-2864-bug/task.json +23 -23
- package/suite/tasks/rebench-narwhals-2864-control/task.json +27 -27
- package/suite/tasks/rebench-quantecon-py-769-bug/task.json +23 -23
- package/suite/tasks/rebench-quantecon-py-769-control/task.json +27 -27
- package/suite/tasks/rebench-scrapy-6867-bug/task.json +23 -23
- package/suite/tasks/rebench-scrapy-6867-control/task.json +27 -27
- package/ui/bench.css +430 -425
- package/ui/bench.js +1756 -1576
- package/ui/themes/dark.css +35 -35
- package/ui/themes/hardwood.css +52 -52
- 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`.
|