@wendellresearch-ai/benchwarmers 0.4.0 → 0.5.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/GATEWAY.md +9 -5
- package/PRIVACY.md +9 -3
- package/README.md +16 -8
- package/USAGE.md +73 -14
- package/VERSION +1 -1
- package/cli.py +13 -4
- package/gateway.py +34 -2
- package/launcher.py +2 -1
- package/metrics/discover.py +68 -18
- package/metrics/pacing.py +23 -3
- package/metrics/quotaview.py +460 -0
- package/metrics/scheduler.py +2 -1
- package/metrics/sources.py +29 -6
- package/package.json +1 -1
- package/scripts/check.py +1 -0
- package/scripts/test_hubs.py +10 -5
- package/scripts/test_no_owui.py +9 -0
- package/scripts/test_quota.py +12 -2
- package/scripts/test_serve_edit.py +55 -2
- package/serve.py +286 -101
- package/ui/bench.css +71 -6
- package/ui/bench.js +456 -39
|
@@ -398,7 +398,7 @@ def main() -> int:
|
|
|
398
398
|
stopped = {i["served"]: i["state"] for i in serve.onboard_queue()["items"]}
|
|
399
399
|
order.remove("quiet")
|
|
400
400
|
serve.queue_onboard([{"served": s, "endpoint": "e", "mode": m, "vision": s == "quiet"} for s, m in
|
|
401
|
-
(("ok", "full"), ("quiet", "quick"), ("bad", "quick-adhoc"))])
|
|
401
|
+
(("ok", "full-adhoc"), ("quiet", "quick"), ("bad", "quick-adhoc"))])
|
|
402
402
|
settle()
|
|
403
403
|
batch = {i["served"]: (i["state"], i["alias"], bool(i["note"])) for i in serve.onboard_queue()["items"]}
|
|
404
404
|
cleared = serve.clear_onboard_queue()["items"]
|
|
@@ -412,10 +412,55 @@ def main() -> int:
|
|
|
412
412
|
and batch == {"ok": ("done", "ok-x", False), "quiet": ("no answer", "quiet-x", True),
|
|
413
413
|
"bad": ("failed", "bad-x", True)}
|
|
414
414
|
and cleared == [] and bad_input == (False, False, False)
|
|
415
|
-
and modes == {"a": "full", "ok": "full", "quiet": "quick vision", "bad": "quick-adhoc"}
|
|
415
|
+
and modes == {"a": "full", "ok": "full-adhoc", "quiet": "quick vision", "bad": "quick-adhoc"}
|
|
416
|
+
and serve.ONBOARD_MODES["full-adhoc"] == ["--ad-hoc"]) # the suite now, then ad hoc
|
|
416
417
|
print(("ok " if ok else "FAIL ") + "onboarding queue" + ("" if ok else f" -> {stopped} {order} {batch} {modes}"))
|
|
417
418
|
failures += 0 if ok else 1
|
|
418
419
|
|
|
420
|
+
# Restart: refused unless serve.py's parent started it (nothing would start it
|
|
421
|
+
# again); refused while a job runs, unless forced; then the server shuts down.
|
|
422
|
+
import scheduler
|
|
423
|
+
kept = os.environ.get("BENCH_SERVED"), serve.SERVER
|
|
424
|
+
shut = []
|
|
425
|
+
try:
|
|
426
|
+
os.environ.pop("BENCH_SERVED", None)
|
|
427
|
+
alone = serve.restart()
|
|
428
|
+
os.environ["BENCH_SERVED"] = "1"
|
|
429
|
+
serve.SERVER = type("Server", (), {"shutdown": lambda self: shut.append(1)})()
|
|
430
|
+
scheduler.RUNNING["suite"] = True
|
|
431
|
+
busy, forced = serve.restart(), serve.restart(force=True)
|
|
432
|
+
time.sleep(0.8) # the shutdown waits half a second
|
|
433
|
+
finally:
|
|
434
|
+
scheduler.RUNNING.pop("suite", None)
|
|
435
|
+
serve.SERVER = kept[1]
|
|
436
|
+
os.environ.pop("BENCH_SERVED", None) if kept[0] is None else os.environ.update(BENCH_SERVED=kept[0])
|
|
437
|
+
ok = (not alone["ok"] and busy.get("busy") and not busy["ok"] and "suite" in busy["errors"][0]
|
|
438
|
+
and forced["ok"] and forced["cut"] and shut == [1])
|
|
439
|
+
print(("ok " if ok else "FAIL ") + "restart" + ("" if ok else f" -> {alone} {busy} {forced} {shut}"))
|
|
440
|
+
failures += 0 if ok else 1
|
|
441
|
+
|
|
442
|
+
# Action needed: an alert whose models have all left the bench is not shown,
|
|
443
|
+
# before the daily check rewrites the file (2026-10-28: a kilo connection
|
|
444
|
+
# alert stayed after Retire all 4).
|
|
445
|
+
kept_data, kept_reg = serve.DATA, serve.registered
|
|
446
|
+
with tempfile.TemporaryDirectory() as tmp:
|
|
447
|
+
(pathlib.Path(tmp) / "metrics").mkdir()
|
|
448
|
+
(pathlib.Path(tmp) / "metrics" / "alerts.json").write_text(json.dumps({
|
|
449
|
+
"connection:held:gone.example": {"kind": "connection", "message": "every model on gone.example is failing",
|
|
450
|
+
"aliases": ["g1", "g2"], "first_seen": "2026-10-28"},
|
|
451
|
+
"connection:held:here.example": {"kind": "connection", "message": "every model on here.example is failing",
|
|
452
|
+
"aliases": ["h1", "g1"], "first_seen": "2026-10-28"},
|
|
453
|
+
"retiring:x:old": {"kind": "retiring", "alias": "old", "message": "old retires", "first_seen": "2026-10-28"}}),
|
|
454
|
+
encoding="utf-8")
|
|
455
|
+
serve.DATA, serve.registered = pathlib.Path(tmp), lambda: {"h1-served": "h1"}
|
|
456
|
+
try:
|
|
457
|
+
shown = serve.problems()
|
|
458
|
+
finally:
|
|
459
|
+
serve.DATA, serve.registered = kept_data, kept_reg
|
|
460
|
+
ok = "here.example" in shown and "gone.example" not in shown and "old retires" not in shown
|
|
461
|
+
print(("ok " if ok else "FAIL ") + "action needed drops alerts on retired models")
|
|
462
|
+
failures += 0 if ok else 1
|
|
463
|
+
|
|
419
464
|
# Dismiss: one picker key or many in one write, a change-log line each;
|
|
420
465
|
# undo brings back only the ones named; nothing named is refused.
|
|
421
466
|
serve.DISMISSED_PATH = cfg / "dismissed.json"
|
|
@@ -433,6 +478,14 @@ def main() -> int:
|
|
|
433
478
|
print(("ok " if ok else "FAIL ") + "dismiss in bulk, and undo" + ("" if ok else f" -> {gone} {left} {log} {refused}"))
|
|
434
479
|
failures += 0 if ok else 1
|
|
435
480
|
|
|
481
|
+
# The member picker's provider chips: a proxy's vendor, else the bare host.
|
|
482
|
+
names = {"nvidia-api": "nvidia", "api.unorouter.com": "unorouter", "router.requesty.ai": "requesty",
|
|
483
|
+
"cli-proxy-api/codex": "codex", "openrouter": "openrouter", "apihub.agnes-ai.com": "agnes-ai"}
|
|
484
|
+
got = {t: serve.provider_label(t) for t in names}
|
|
485
|
+
ok = got == names
|
|
486
|
+
print(("ok " if ok else "FAIL ") + "provider chip names" + ("" if ok else f" -> {got}"))
|
|
487
|
+
failures += 0 if ok else 1
|
|
488
|
+
|
|
436
489
|
# The owner's files are as they were. alerts.json can change under a
|
|
437
490
|
# running suite, so only what this test could do counts: the victim's
|
|
438
491
|
# alerts cleared from the real file.
|