@wendellresearch-ai/benchwarmers 0.5.5 → 0.6.0
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/.github/logo-dark.svg +49 -0
- package/.github/logo.svg +49 -0
- package/AGENTS.md +4 -1
- package/BENCHMARKS.md +160 -0
- package/GATEWAY.md +59 -12
- package/PRIVACY.md +25 -6
- package/README.md +62 -15
- package/SECURITY.md +20 -9
- package/USAGE.md +87 -14
- package/VERSION +1 -1
- package/cli.py +12 -1
- package/gateway.py +122 -91
- package/mcp_server.py +2 -1
- package/metrics/alerts.py +25 -0
- package/metrics/bench_collections.py +58 -9
- package/metrics/catalog.py +54 -9
- package/metrics/client.py +51 -1
- package/metrics/connect.py +225 -0
- package/metrics/decide.py +690 -27
- package/metrics/discover.py +191 -11
- package/metrics/endpoints.py +4 -6
- package/metrics/guard.py +6 -4
- package/metrics/ledger.py +3 -1
- package/metrics/locked.py +102 -1
- package/metrics/offload.py +36 -19
- package/metrics/owui.py +26 -0
- package/metrics/route.py +19 -4
- package/metrics/scheduler.py +11 -1
- package/metrics/sources.py +15 -2
- package/metrics/test_decide.py +275 -7
- package/metrics/wrong.py +21 -9
- package/package.json +3 -1
- package/scripts/auto_retire.py +96 -21
- package/scripts/onboard.py +44 -3
- package/scripts/test_connect.py +152 -3
- package/scripts/test_first_run.py +4 -2
- package/scripts/test_formats.py +100 -1
- package/scripts/test_serve_edit.py +327 -4
- package/serve.py +1746 -170
- package/suite/README.md +5 -2
- package/suite/run.py +226 -6
- package/suite/test_pick.py +15 -0
- package/suite/test_score.py +82 -1
- package/ui/bench.css +44 -0
- package/ui/bench.js +940 -207
package/README.md
CHANGED
|
@@ -99,7 +99,7 @@ with [AGENTS.md](AGENTS.md).
|
|
|
99
99
|
|
|
100
100
|
## Try it
|
|
101
101
|
|
|
102
|
-
**
|
|
102
|
+
**Pre-1.0, early.** It runs with Python 3.11 or later on Windows, macOS and
|
|
103
103
|
Linux, from PyPI, npm, a checkout or Docker. Expect rough edges, and read the
|
|
104
104
|
code where these pages are thin.
|
|
105
105
|
|
|
@@ -145,6 +145,10 @@ dependencies either way: the app is the Python standard library.
|
|
|
145
145
|
its key, which goes to the key file in llm's user folder (`keys.json`,
|
|
146
146
|
shared with the `llm` CLI if you have it, not needed otherwise), never into
|
|
147
147
|
the data folder. `BENCHWARMERS_KEY_<NAME>` in the environment works too.
|
|
148
|
+
To move an install to another machine, Settings → Export and import takes
|
|
149
|
+
the folder as one .zip (settings only, or everything; the endpoints' keys
|
|
150
|
+
only if you tick them) and imports it on the other install, saving what it
|
|
151
|
+
replaces to `backups/` first.
|
|
148
152
|
|
|
149
153
|
3. **Start the dashboard.** With no endpoint yet it opens on adding one: sign
|
|
150
154
|
in with a provider on its own page (OpenRouter, NanoGPT, Hugging Face,
|
|
@@ -153,7 +157,10 @@ dependencies either way: the app is the Python standard library.
|
|
|
153
157
|
LiteLLM included. Anthropic and Gemini keys can also be called through
|
|
154
158
|
those providers' own APIs (the API choice in the same dialog). Only providers that publish a sign-in for other apps are
|
|
155
159
|
offered; adding one is an entry in `metrics/connect.py` (its docstring says
|
|
156
|
-
how).
|
|
160
|
+
how). A model server already running on this machine, at its usual port or
|
|
161
|
+
any other its process is listening on (Ollama, LM Studio, Jan, llama.cpp,
|
|
162
|
+
LocalAI, vLLM, LiteLLM, CLI Proxy API, OmniRoute), is offered under "Found
|
|
163
|
+
on this machine", its address and kind filled in.
|
|
157
164
|
|
|
158
165
|
python serve.py # http://localhost:8122
|
|
159
166
|
|
|
@@ -176,7 +183,11 @@ dependencies either way: the app is the Python standard library.
|
|
|
176
183
|
- **Collections and seats.** A collection names the models a panel always
|
|
177
184
|
includes and the shape of work it is for (review, design, enumeration...).
|
|
178
185
|
Each call adds explorer seats chosen by how long a model has gone unused, so
|
|
179
|
-
the bench keeps learning about models a router would stop asking.
|
|
186
|
+
the bench keeps learning about models a router would stop asking. A member
|
|
187
|
+
that is out of quota or rate-limited keeps its place while an explorer
|
|
188
|
+
stands in for it until it is back. A collection can set its own calls per
|
|
189
|
+
request and explorers, and one marked ad hoc (an expensive one, say) runs
|
|
190
|
+
only when a request names it.
|
|
180
191
|
- **Verdicts.** Each seat's answer carries a call id. Once you have checked an
|
|
181
192
|
answer against the real work, record whether it was useful, and which of its
|
|
182
193
|
claims were real or false. Verdicts, not vibes, decide the next panel; a
|
|
@@ -191,6 +202,18 @@ dependencies either way: the app is the Python standard library.
|
|
|
191
202
|
that is only out of quota until a stated reset is not counted against. The
|
|
192
203
|
built-in scheduler runs all of this once Settings switches it on; a fresh
|
|
193
204
|
install spends no calls until then.
|
|
205
|
+
- **Benchmarks.** One page of reports: bugs found against false alarms, who
|
|
206
|
+
is confidently wrong, real work that helped, each model against its own
|
|
207
|
+
earlier scores (Trend), whether each provider was there when the bench
|
|
208
|
+
called it (Uptime: busy, unreachable and timed out count as down; your own
|
|
209
|
+
quota and pacing are left out), and speed. Each report shares as an image or
|
|
210
|
+
its table. [BENCHMARKS.md](BENCHMARKS.md) says how to read them.
|
|
211
|
+
- **Decision models.** A model that answers typed questions with a
|
|
212
|
+
probability (Mercury Decide, say) labels a request's shape, picks a
|
|
213
|
+
collection for a request that names none (when it is sure, and the reply
|
|
214
|
+
says so), and classes an error no rule knows. Each is measured daily on
|
|
215
|
+
questions the bench's own data answers, and each use asks the one that does
|
|
216
|
+
best.
|
|
194
217
|
- **Rate limits and usage.** Limits come from providers' rate-limit headers
|
|
195
218
|
and error messages, and from what you set per connection or model
|
|
196
219
|
(requests a minute, day or month; tokens a minute or day). They are kept per
|
|
@@ -203,7 +226,10 @@ dependencies either way: the app is the Python standard library.
|
|
|
203
226
|
are read from its site and watched for changes.
|
|
204
227
|
- **Discover.** FreeLLMAPI's free catalog, with models.dev for the details
|
|
205
228
|
and paid models it lacks, merged into one list of models worth adding,
|
|
206
|
-
smartest first, each with the routes this install has to it
|
|
229
|
+
smartest first, each with the routes this install has to it and links to
|
|
230
|
+
its pages on both. Each Open WebUI connection's own model list adds what a
|
|
231
|
+
provider serves before either catalog lists it; **Refresh lists** fetches
|
|
232
|
+
them all now rather than at the daily fetch.
|
|
207
233
|
|
|
208
234
|
## Asking a panel
|
|
209
235
|
|
|
@@ -266,6 +292,7 @@ running server, so the same commands work against one on another machine.
|
|
|
266
292
|
bench model retire <alias> --reason "..." and back: bench model restore <alias>
|
|
267
293
|
bench collection save reviewers --members a,b,c --description "adversarial review"
|
|
268
294
|
bench collection save reviewers --add d --remove a
|
|
295
|
+
bench collection save heavy-hitters --ad-hoc --max-calls 4 --max-explorers 0
|
|
269
296
|
bench endpoint add openrouter --base https://openrouter.ai/api/v1 (asks for the key, hidden)
|
|
270
297
|
bench key create my-app --collections core --rpm 30
|
|
271
298
|
bench settings scheduler run --off perf
|
|
@@ -296,8 +323,9 @@ no server at `BENCHWARMERS_URL`.
|
|
|
296
323
|
|
|
297
324
|
A running Benchwarmers is an MCP server at `/mcp` on its own port
|
|
298
325
|
(`http://127.0.0.1:8122/mcp`; `/v1/mcp` works too), over streamable HTTP,
|
|
299
|
-
with
|
|
300
|
-
optionally `merged`, `with` and `system`)
|
|
326
|
+
with four tools: `list_collections`, `ask` (a collection, a prompt,
|
|
327
|
+
optionally `merged`, `with` and `system`), `verdict` and `pending_verdicts`
|
|
328
|
+
(the seats still unjudged). Nothing to start per
|
|
301
329
|
client: every agent session shares the one server, behind the same Host,
|
|
302
330
|
Origin and gateway-key checks as `/v1`. The tool descriptions carry the
|
|
303
331
|
rules: ask a collection, not a favourite model; verify before acting; name
|
|
@@ -385,6 +413,13 @@ points at it with `ANTHROPIC_BASE_URL=http://127.0.0.1:8122` and
|
|
|
385
413
|
OpenAI-, Responses- or Ollama-speaking agents with the same base URL.
|
|
386
414
|
[GATEWAY.md](GATEWAY.md), "Route mode", has the set-up and the limits.
|
|
387
415
|
|
|
416
|
+
**Ready set-ups.** The dashboard's **Clients** page (Gateway) gives each
|
|
417
|
+
popular app's configuration, filled in from your install's address,
|
|
418
|
+
collections and MCP server, with a Copy button: opencode, VS Code chat, Codex
|
|
419
|
+
CLI, Zed, Continue, Cline and Kilo Code, Claude Code, goose, and chat apps
|
|
420
|
+
(LobeHub, AnythingLLM, Cherry Studio, Chatbox, LibreChat). Where keys are
|
|
421
|
+
asked for, it makes one and fills it in, never into a file that may sync.
|
|
422
|
+
|
|
388
423
|
<!-- The MCP Registry's proof that the PyPI package is this server (server.json):
|
|
389
424
|
mcp-name: io.github.WendellResearch-AI/benchwarmers -->
|
|
390
425
|
|
|
@@ -437,12 +472,17 @@ reaches Wendell Research. What it sends, and where:
|
|
|
437
472
|
|
|
438
473
|
- **Your prompts**, only to the endpoints you add: a provider, an aggregator,
|
|
439
474
|
a hub such as Open WebUI, or a local runtime. That includes the probes, the
|
|
440
|
-
suite and onboarding, which spend calls on your keys
|
|
441
|
-
|
|
475
|
+
suite and onboarding, which spend calls on your keys, and the decision
|
|
476
|
+
models' daily benchmark, which puts past requests, judged answers and
|
|
477
|
+
redacted error text to them again. Add only endpoints you are content to
|
|
478
|
+
send that work to.
|
|
442
479
|
- **Catalog reads**, no key and nothing of yours: FreeLLMAPI (its feed and
|
|
443
480
|
its site's sitemap) and models.dev once a day, and OpenRouter's public
|
|
444
481
|
model list. With an NVIDIA connection, the public file of rate limits
|
|
445
482
|
build.nvidia.com states, once a day and on Refresh.
|
|
483
|
+
- **Model lists**, with no prompt: each Open WebUI connection's list of the
|
|
484
|
+
models its provider serves, asked through Open WebUI with the key it
|
|
485
|
+
already holds, once a day and on Discover's Refresh lists.
|
|
446
486
|
- **Sign-ins**, only when you choose one: the provider's own sign-in page.
|
|
447
487
|
- **Quota reads**, only when you press Refresh on Quota management, with no
|
|
448
488
|
prompt: OpenRouter's key status, and xKiro's and Requesty's usage, each with
|
|
@@ -450,12 +490,18 @@ reaches Wendell Research. What it sends, and where:
|
|
|
450
490
|
API asks each sign-in's own provider for its quota.
|
|
451
491
|
- **Charts**: the dashboard's browser page loads Observable Plot from jsDelivr
|
|
452
492
|
at a pinned version.
|
|
493
|
+
- **Posts**, only when you click Post on X, Bluesky, LinkedIn or Reddit in a
|
|
494
|
+
report's Share menu: that site opens in your browser with the report's name
|
|
495
|
+
and the project's link. The image goes only to your clipboard, a file, or
|
|
496
|
+
the app you pick in your system's share sheet.
|
|
453
497
|
- **Seeding real-bug tasks**, only when you run `suite/rebench.py`: the
|
|
454
498
|
SWE-rebench-V2 rows from Hugging Face and the files from GitHub.
|
|
455
499
|
|
|
456
500
|
Keys stay in the environment or llm's key file (`keys.json` in its user
|
|
457
|
-
folder),
|
|
458
|
-
|
|
501
|
+
folder), not in the data folder. An export (Settings, Export and import)
|
|
502
|
+
carries them only if you tick them, and an import that carries keys first
|
|
503
|
+
backs up the ones it replaces, in the data folder's `backups/`.
|
|
504
|
+
[PRIVACY.md](PRIVACY.md) and [SECURITY.md](SECURITY.md) have the detail.
|
|
459
505
|
|
|
460
506
|
## Limits
|
|
461
507
|
|
|
@@ -463,8 +509,8 @@ detail.
|
|
|
463
509
|
with tools is refused there, not trimmed. Route mode passes turns only to
|
|
464
510
|
members on chat-completions endpoints, keeps its sticky conversations in
|
|
465
511
|
memory (a restart starts each on a fresh pick), and has been run end to end
|
|
466
|
-
with Claude Code; the
|
|
467
|
-
|
|
512
|
+
with Claude Code; the other set-ups on the Clients page are written from
|
|
513
|
+
each app's docs, not run. Shadow seats (other members answering an agent's turn for
|
|
468
514
|
evaluation) are planned, not built.
|
|
469
515
|
- **Some parts are checked against fakes only.** The native Anthropic and
|
|
470
516
|
Gemini endpoints, and the LiteLLM and CLI Proxy API hub adapters, are built
|
|
@@ -474,9 +520,10 @@ detail.
|
|
|
474
520
|
seats before it stream as they finish.
|
|
475
521
|
- **Pacing and the ledger cover the built-in client.** Calls made through the
|
|
476
522
|
`llm` CLI, when you choose it, are neither paced nor counted.
|
|
477
|
-
- **Calls cost.** Probes, onboarding
|
|
478
|
-
tiers. Onboarding runs one model at a time for
|
|
479
|
-
the suite over the scheduled passes); a suite
|
|
523
|
+
- **Calls cost.** Probes, onboarding, the suite and the decision benchmark
|
|
524
|
+
run on your keys and free tiers. Onboarding runs one model at a time for
|
|
525
|
+
that reason (Quick spreads the suite over the scheduled passes); a suite
|
|
526
|
+
pass is paced, not burst.
|
|
480
527
|
- **The scheduler lives in the server.** Its jobs run while the dashboard (or
|
|
481
528
|
the container, or the service) is up; a missed run is made up once, within
|
|
482
529
|
seven days, when it comes back.
|
package/SECURITY.md
CHANGED
|
@@ -24,8 +24,9 @@ reproduce, and what an attacker gains.
|
|
|
24
24
|
**On this machine by default.** The dashboard (`serve.py`, port 8122) and the
|
|
25
25
|
gateway (on the same port at `/v1`, or alone with `gateway.py` on 8123) listen
|
|
26
26
|
on 127.0.0.1. Every request is checked for the server's own host name (against
|
|
27
|
-
DNS rebinding), and every write must be a same-origin
|
|
28
|
-
|
|
27
|
+
DNS rebinding), and every write must be a same-origin request with a JSON
|
|
28
|
+
body (a zip, for an import), a type no plain form can send, so a web page
|
|
29
|
+
open in your browser cannot drive either server. With no admin token
|
|
29
30
|
there is no login and the gateway asks for no key.
|
|
30
31
|
|
|
31
32
|
**Anywhere else, only with a login.** To listen beyond this machine
|
|
@@ -60,14 +61,24 @@ open itself to anyone.
|
|
|
60
61
|
- **Keys.** Endpoint keys come from `BENCHWARMERS_KEY_<NAME>` (the key name
|
|
61
62
|
upper-cased, `-` as `_`) first, then from llm's key file (`keys.json` in
|
|
62
63
|
its user folder, used whether or not the `llm` CLI is installed). They are
|
|
63
|
-
never
|
|
64
|
-
|
|
64
|
+
never shown back and never put in a log. Sign-ins through a provider's page
|
|
65
|
+
store their token the same way.
|
|
66
|
+
- **Exports.** Settings, Export and import, puts the endpoints' stored keys
|
|
67
|
+
(key, admin key, refresh token; never one from the environment) in an
|
|
68
|
+
export only when you tick them, in plain text in its `keys.json`: keep that
|
|
69
|
+
file like a password and delete it once imported. Importing one puts its
|
|
70
|
+
keys in the key store, and first backs up this install's own, with its files,
|
|
71
|
+
to the data folder's `backups/before-import-<time>.zip`. An import is
|
|
72
|
+
refused whole if any file in it would land outside its scope's folders.
|
|
65
73
|
- **The network.** Your prompts go only to the endpoints you add; the probes,
|
|
66
|
-
the suite and
|
|
67
|
-
reads (models.dev, FreeLLMAPI, OpenRouter's model
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
74
|
+
the suite, onboarding and the decision benchmark spend calls there too.
|
|
75
|
+
Otherwise: public catalog reads (models.dev, FreeLLMAPI, OpenRouter's model
|
|
76
|
+
list), each Open WebUI connection's model list (through Open WebUI, with its
|
|
77
|
+
key), a provider's sign-in page when you choose one, Observable Plot from
|
|
78
|
+
jsDelivr in the dashboard's page, the site a report's Share menu posts to
|
|
79
|
+
when you choose one (opened with the report's name and the project's link
|
|
80
|
+
only), and Hugging Face and GitHub only when you run `suite/rebench.py`.
|
|
81
|
+
[PRIVACY.md](PRIVACY.md) lists them.
|
|
71
82
|
- **Files.** It writes inside its data folder (`BENCHWARMERS_HOME`, or the
|
|
72
83
|
folder `.benchwarmers-home` names) and, in llm's user folder, the key file
|
|
73
84
|
(when you paste a key or sign in) and the model list (when it registers a
|
package/USAGE.md
CHANGED
|
@@ -13,6 +13,7 @@ coding agent doing it with you); the gateway's whole contract is in
|
|
|
13
13
|
- [Collections](#collections)
|
|
14
14
|
- [Connecting an app](#connecting-an-app)
|
|
15
15
|
- [Recording verdicts](#recording-verdicts)
|
|
16
|
+
- [Benchmarks, and sharing a report](#benchmarks-and-sharing-a-report)
|
|
16
17
|
- [Discover: finding models to add](#discover-finding-models-to-add)
|
|
17
18
|
- [Quota management](#quota-management)
|
|
18
19
|
- [The scheduler](#the-scheduler)
|
|
@@ -24,17 +25,24 @@ coding agent doing it with you); the gateway's whole contract is in
|
|
|
24
25
|
|
|
25
26
|
| Group | Page | What it is for |
|
|
26
27
|
| --- | --- | --- |
|
|
27
|
-
| Observe | **At a glance** | Every model on the bench: whether it works right now, its role, and its connection. Click a name for its popup: role, alias, facts, options, retire. |
|
|
28
|
+
| Observe | **At a glance** | Every model on the bench: whether it works right now, its uptime over 7 days, its role, and its connection. Click a name for its popup: role, alias, facts, options, retire. |
|
|
28
29
|
| | **Action needed** | What will not fix itself, by the connection it comes from, with Retry and Retire on each model. |
|
|
29
|
-
| | **Benchmarks** | How models do on the suite and on real work: bugs found against false alarms, who is confidently wrong, and
|
|
30
|
+
| | **Benchmarks** | How models do on the suite and on real work: bugs found against false alarms, who is confidently wrong, each model against its own earlier scores, uptime, speed, and the decision models. Each report shares as an image or its table. |
|
|
30
31
|
| | **Quota management** | A tile per provider: what is left, when it resets, and which of its models are resting. Then the week's resets, and what the bench sent. |
|
|
31
32
|
| | **Logs** | Gateway calls (who sat and how it went, never the prompt), changes made from the dashboard, the scheduler, and onboarding runs. |
|
|
32
|
-
| Gateway | **Endpoints** | Where models are served from. Add an endpoint (a provider's sign-in, or any OpenAI-compatible API key), change a key, and see what each one serves. Also your own app registrations and rate limits per connection. |
|
|
33
|
+
| Gateway | **Endpoints** | Where models are served from. Add an endpoint (a provider's sign-in, or any OpenAI-compatible API key), change a key, and see what each one serves. A model server running on this machine, at its usual port or any other its process is listening on (LM Studio, Jan, llama.cpp, vLLM and the like), is offered under Found on this machine: Add opens the dialog with it filled in, to test and save. Also your own app registrations and rate limits per connection. |
|
|
33
34
|
| | **Models** | Every model on the bench, by the connection it comes from. |
|
|
34
35
|
| | **Collections** | The named panels your apps ask for, and the gateway's settings. |
|
|
36
|
+
| | **Clients** | Each popular app's set-up (opencode, VS Code, Codex, Zed, Continue, Cline, Kilo Code, Claude Code, goose, chat apps), filled in from this install, with Copy and a gateway key made on the spot. |
|
|
35
37
|
| | **Discover** | Models worth adding, from public catalogs, with the ways this install can reach each one. |
|
|
36
|
-
| Control | **Settings** | Theme, gateway keys, the scheduler, the model client, providers whose free models work only in their own app, how the install is reached (shown only), and Restart. |
|
|
37
|
-
| | **Info** |
|
|
38
|
+
| Control | **Settings** | Theme, gateway keys, the scheduler, the model client, providers whose free models work only in their own app, export and import, how the install is reached (shown only), and Restart. |
|
|
39
|
+
| | **Info** | The source repository, the version (linking its release), Python, data folder and counts. |
|
|
40
|
+
|
|
41
|
+
The page shown follows the data: while it is in view it checks every 10
|
|
42
|
+
seconds, and when something has changed it swaps in the new page in place,
|
|
43
|
+
keeping open sections, sorting and filters. It waits while you are at work on
|
|
44
|
+
it (a popup open, a form not saved or in use, text selected, a chart hovered),
|
|
45
|
+
and **New results · Show**, top right, offers the change instead.
|
|
38
46
|
|
|
39
47
|
**Action needed** lists what will not fix itself, such as a model about to be
|
|
40
48
|
retired, grouped by the connection it comes from, since one cause usually
|
|
@@ -108,7 +116,9 @@ unavailable, so the daily probe keeps watching it.
|
|
|
108
116
|
`code`, `light` (small and fast), `vision` (reads images well, weak at text:
|
|
109
117
|
OCR and document models; seated only when a request carries images) or
|
|
110
118
|
`image` (makes images; never seated). A model that reads images and does
|
|
111
|
-
everything else well stays `general`.
|
|
119
|
+
everything else well stays `general`. Where a decision model is onboarded,
|
|
120
|
+
onboarding asks it to suggest a new chat model's role; the popup shows the
|
|
121
|
+
suggestion, and nothing applies it.
|
|
112
122
|
|
|
113
123
|
## Collections
|
|
114
124
|
|
|
@@ -123,16 +133,30 @@ per model with its context, vision and tools, and price. A model served by
|
|
|
123
133
|
several providers is still one row, with a chip per provider: tick the chip
|
|
124
134
|
of the route you want. Ticking two is allowed, and the count says so. The
|
|
125
135
|
search matches a model, provider or served name, and the select beside it
|
|
126
|
-
shows one provider's models
|
|
127
|
-
|
|
136
|
+
shows one provider's models. The seats above the list always show who is
|
|
137
|
+
ticked, filtered out or not, and a seat's × takes that member off, as unticking
|
|
138
|
+
it does. The tags grey out the models that
|
|
128
139
|
do not fit them.
|
|
129
140
|
|
|
130
141
|
Each call also seats explorers, the models unused longest, up to the gateway's
|
|
131
142
|
limits (Gateway settings, on the same page: how many calls a request may make,
|
|
132
|
-
and how many of them explore).
|
|
143
|
+
and how many of them explore). A collection can set its own in its popup; left
|
|
144
|
+
empty, it follows those settings. A member out of quota stays on the collection
|
|
145
|
+
and an explorer sits in for it, named `stand-in for <member>`, until the quota
|
|
146
|
+
is back. Max explorers 0 means only the members ever run, stand-ins included.
|
|
147
|
+
|
|
148
|
+
Gateway settings also says whether a request that names no collection is given
|
|
149
|
+
one by a decision model, and how sure that model must be (GATEWAY.md, "No
|
|
150
|
+
default collection").
|
|
133
151
|
|
|
134
152
|
## Connecting an app
|
|
135
153
|
|
|
154
|
+
The dashboard's **Clients** page has a ready set-up for each popular app,
|
|
155
|
+
filled in from this install (its address, collections and MCP server): copy it
|
|
156
|
+
into the file or screen it names. When keys are asked for, it makes one on the
|
|
157
|
+
spot and fills it in where a key goes, never into a file that may sync. What
|
|
158
|
+
follows is the same by hand.
|
|
159
|
+
|
|
136
160
|
Any OpenAI-compatible client works. Point it at the dashboard's port and ask
|
|
137
161
|
for the model `bench/<collection>`:
|
|
138
162
|
|
|
@@ -193,7 +217,8 @@ claude
|
|
|
193
217
|
|
|
194
218
|
Each conversation is one offload per model that answered it; a verdict is
|
|
195
219
|
optional, and the Gateway card lists route conversations apart from the
|
|
196
|
-
panels.
|
|
220
|
+
panels. The Clients page has the other agents' set-ups; GATEWAY.md, "Route
|
|
221
|
+
mode", has the limits.
|
|
197
222
|
|
|
198
223
|
**A coding agent** connects over MCP instead: the Claude Code plugin
|
|
199
224
|
(`/plugin marketplace add WendellResearch-AI/benchwarmers`, then
|
|
@@ -225,15 +250,49 @@ claims feed **Confidently wrong** on Benchmarks, and verdicts together decide
|
|
|
225
250
|
who sits on the next panel. Agreement between models is not evidence: they
|
|
226
251
|
are often wrong together.
|
|
227
252
|
|
|
253
|
+
## Benchmarks, and sharing a report
|
|
254
|
+
|
|
255
|
+
**Benchmarks** is one report after another: who to trust with a review, bug
|
|
256
|
+
hunt, real work, confidently wrong, our code, vision, trend, uptime,
|
|
257
|
+
performance and the decision models, then links to public leaderboards. Most
|
|
258
|
+
have a chart, the table folded under it (with a filter, and **Show
|
|
259
|
+
retired**), and **How to read this**;
|
|
260
|
+
[BENCHMARKS.md](BENCHMARKS.md) has the same explanations in one place.
|
|
261
|
+
**Trend** (30 or 60 days) and **Uptime** (7 or 30) have a window to choose.
|
|
262
|
+
|
|
263
|
+
**Share**, top right of each report:
|
|
264
|
+
|
|
265
|
+
- **Copy image** / **Download image**: the report's charts, title and the line
|
|
266
|
+
under it, with a band at the foot holding the logo, the project's link and
|
|
267
|
+
the date, as a PNG at twice the size shown. The table, the key and the
|
|
268
|
+
controls stay out; a window you chose shows as its words.
|
|
269
|
+
- **Copy table as Markdown** / **Download table as CSV**: the table as shown
|
|
270
|
+
(its window, filter and Show retired), a model's connection in brackets.
|
|
271
|
+
- **Share…**: your system's share sheet, with the image.
|
|
272
|
+
- **Post on** X, Bluesky, LinkedIn or Reddit: the image goes on the clipboard
|
|
273
|
+
(or is saved, where there is no clipboard), then the site opens with the
|
|
274
|
+
report's name and the project's link, for you to paste the image into.
|
|
275
|
+
|
|
276
|
+
What your browser cannot do is not offered: copying needs a secure page
|
|
277
|
+
(`localhost` is one; a LAN address over plain http is not), and Share… needs
|
|
278
|
+
a share sheet.
|
|
279
|
+
|
|
228
280
|
## Discover: finding models to add
|
|
229
281
|
|
|
230
282
|
**Discover** leads with FreeLLMAPI's catalog of free tiers and fills in from
|
|
231
|
-
models.dev, which alone has prices, paid models and providers' base URLs.
|
|
283
|
+
models.dev, which alone has prices, paid models and providers' base URLs.
|
|
284
|
+
The catalogs trail the providers by days, so it also reads each Open WebUI
|
|
285
|
+
connection's own model list (through Open WebUI, with the keys it already
|
|
286
|
+
has): a model a provider serves that neither catalog lists yet is a row of its
|
|
287
|
+
own, its price unknown where the provider's list does not say. All of them
|
|
288
|
+
are fetched daily; **Refresh lists** fetches them now. A provider is matched
|
|
289
|
+
to your Open WebUI connection by its API host, or by its name in the
|
|
290
|
+
connection's host (FreeLLMAPI's xKiro is `api.xkiro.com`). One
|
|
232
291
|
list: free models first, then by reach, and within each reach FreeLLMAPI's
|
|
233
292
|
smartest first (the **Rank** column), then what it does not rank, what is new
|
|
234
293
|
this week first and badged. A row opens its popup: what
|
|
235
294
|
the model takes and does, its limits and monthly budget, FreeLLMAPI's known
|
|
236
|
-
quirks for it, links to its freellmapi.co
|
|
295
|
+
quirks for it, links to its own pages on freellmapi.co and models.dev, and every route
|
|
237
296
|
this install has to it, each with an **Add via this**. Adding through a hub (Open WebUI, LiteLLM, CLI Proxy
|
|
238
297
|
API) puts it in that hub too; adding direct registers it on its own endpoint
|
|
239
298
|
only. Either way the onboarding joins the same queue, with the same
|
|
@@ -308,8 +367,9 @@ Under the tiles are:
|
|
|
308
367
|
## The scheduler
|
|
309
368
|
|
|
310
369
|
The recurring jobs (the morning availability probe, the catalog refresh, the
|
|
311
|
-
deprecation check and auto-retire, suite passes, the
|
|
312
|
-
capability tests) run inside the dashboard.
|
|
370
|
+
deprecation check and auto-retire, suite passes, the decision models' daily
|
|
371
|
+
benchmark, the weekly speed and capability tests) run inside the dashboard.
|
|
372
|
+
Settings, **Scheduler**:
|
|
313
373
|
|
|
314
374
|
- **Off**: nothing runs; a fresh install spends no calls until you opt in.
|
|
315
375
|
- **Log only**: writes "would run" to `runs/scheduler.log` at each due time,
|
|
@@ -326,3 +386,16 @@ call logs, probe history, task answers) lives in the data folder: the one
|
|
|
326
386
|
`BENCHWARMERS_HOME` names, else the one in `.benchwarmers-home` at the top of
|
|
327
387
|
the checkout. Back it up by copying it; move it by copying it and pointing one
|
|
328
388
|
of those two at the new place. Info shows which folder is in use.
|
|
389
|
+
|
|
390
|
+
**Export and import**, on Settings, does the same through the dashboard, for
|
|
391
|
+
another machine or a copy to keep: one .zip of **Settings only**
|
|
392
|
+
(`config/`: endpoints, collections, roles, model options, the schedule,
|
|
393
|
+
gateway keys, the theme) or **Everything** (also every result, history, log
|
|
394
|
+
and saved answer). The endpoints' API keys go in only if you tick them; the
|
|
395
|
+
file then holds them, so keep it like a password and delete it once
|
|
396
|
+
imported. On the other install, choose the file: it says what is in it
|
|
397
|
+
(scope, release, date, files, how many it replaces, keys) before **Import**.
|
|
398
|
+
Its files replace the ones of the same name, after this install's own in that
|
|
399
|
+
scope are saved to `backups/before-import-<time>.zip`; files it does not have
|
|
400
|
+
are left. Restart afterwards (Settings, Server and access), so every part
|
|
401
|
+
reads them.
|
package/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
0.
|
|
1
|
+
0.6.0
|
package/cli.py
CHANGED
|
@@ -328,7 +328,10 @@ def cmd_collection(args) -> None:
|
|
|
328
328
|
"description": args.description if args.description is not None else old.get("description") or "",
|
|
329
329
|
"tags": csv(args.tags) if args.tags is not None else old.get("tags") or [],
|
|
330
330
|
"reply": args.reply or old.get("reply") or "all",
|
|
331
|
-
"merger": args.merger if args.merger is not None else old.get("merger") or ""
|
|
331
|
+
"merger": args.merger if args.merger is not None else old.get("merger") or "",
|
|
332
|
+
"ad_hoc": args.ad_hoc if args.ad_hoc is not None else bool(old.get("ad_hoc"))}
|
|
333
|
+
for key, given in (("max_calls", args.max_calls), ("max_explorers", args.max_explorers)):
|
|
334
|
+
body[key] = old.get(key) if given is None else None if given == "default" else given
|
|
332
335
|
reply = call("POST", "/api/collection", body)
|
|
333
336
|
out(args, reply, lambda r: done(r, f"saved collection {name}: {', '.join(members)}"))
|
|
334
337
|
|
|
@@ -497,6 +500,8 @@ keeps only the answers. Then judge each seat you checked:
|
|
|
497
500
|
bench collection save reviewers --members a,b,c --description "adversarial review" --tags review
|
|
498
501
|
bench collection save reviewers --add d --remove a (the rest stays as it was)
|
|
499
502
|
bench collection save reviewers --reply merged --merger a
|
|
503
|
+
bench collection save heavy --ad-hoc (runs only when called by name; --no-ad-hoc undoes it)
|
|
504
|
+
bench collection save heavy --max-calls 4 --max-explorers 0 (its own limits; "default" follows the gateway's)
|
|
500
505
|
bench collection show reviewers
|
|
501
506
|
bench collection rm reviewers --yes""",
|
|
502
507
|
"endpoint": """examples:
|
|
@@ -629,6 +634,12 @@ def parser() -> argparse.ArgumentParser:
|
|
|
629
634
|
c.add_argument("--tags", help="comma-separated")
|
|
630
635
|
c.add_argument("--reply", choices=["all", "merged", "route"])
|
|
631
636
|
c.add_argument("--merger", help="the alias that merges, for --reply merged")
|
|
637
|
+
c.add_argument("--ad-hoc", action=argparse.BooleanOptionalAction, default=None,
|
|
638
|
+
help="only when called by name: left off what callers choose from")
|
|
639
|
+
own_limit = lambda v: v if v == "default" else int(v) # noqa: E731
|
|
640
|
+
c.add_argument("--max-calls", type=own_limit, help="its own max calls per request, or default for the gateway's")
|
|
641
|
+
c.add_argument("--max-explorers", type=own_limit,
|
|
642
|
+
help="its own max explorers, or default for the gateway's; 0 means only the members ever run")
|
|
632
643
|
|
|
633
644
|
cmd("endpoints", cmd_endpoints, "where models are served from")
|
|
634
645
|
|