@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
@@ -1,105 +1,105 @@
1
- """Move `extra-openai-models.yaml` between this repo and the llm CLI.
2
-
3
- The CLI reads its model registrations from one fixed path in its own per-user
4
- folder (endpoints.LLM_DIR), which is not somewhere anyone thinks to look and
5
- not somewhere version control reaches. So the data folder holds the canonical
6
- copy and this moves it into place.
7
-
8
- python scripts/sync_config.py # data folder -> llm (the usual way)
9
- python scripts/sync_config.py --pull # llm -> data folder (live has drifted)
10
- python scripts/sync_config.py --check # report differences, change nothing
11
-
12
- A backup of whatever is being overwritten is written beside the target first,
13
- because the live file is the one thing here that is not reproducible if the
14
- repo copy turns out to be older.
15
- """
16
-
17
- from __future__ import annotations
18
-
19
- import argparse
20
- import datetime as dt
21
- import filecmp
22
- import pathlib
23
- import shutil
24
- import sys
25
-
26
- sys.path.insert(0, str(pathlib.Path(__file__).resolve().parent.parent / "metrics"))
27
- from paths import DATA # noqa: E402 -- the install's data folder (metrics/paths.py)
28
- import endpoints # noqa: E402
29
- REPO = DATA / "config" / "extra-openai-models.yaml"
30
- LIVE = endpoints.LLM_DIR / "extra-openai-models.yaml"
31
-
32
-
33
- def _backup(path: pathlib.Path) -> pathlib.Path | None:
34
- if not path.exists():
35
- return None
36
- stamp = dt.datetime.now().strftime("%Y%m%dT%H%M%S")
37
- dest = path.with_suffix(f".{stamp}.bak")
38
- shutil.copy2(path, dest)
39
- return dest
40
-
41
-
42
- def main() -> int:
43
- ap = argparse.ArgumentParser(description=__doc__)
44
- ap.add_argument("--pull", action="store_true",
45
- help="copy the live file back into the repo")
46
- ap.add_argument("--check", action="store_true",
47
- help="report whether they differ; change nothing")
48
- args = ap.parse_args()
49
-
50
- if not REPO.exists() and not args.pull:
51
- print(f"repo copy missing: {REPO}", file=sys.stderr)
52
- return 1
53
-
54
- if args.check:
55
- if not LIVE.exists():
56
- print(f"live file does not exist: {LIVE}")
57
- return 1
58
- same = REPO.exists() and filecmp.cmp(REPO, LIVE, shallow=False)
59
- print("identical" if same else "DIFFERENT")
60
- if not same:
61
- print(f" repo: {REPO}")
62
- print(f" live: {LIVE}")
63
- return 0 if same else 1
64
-
65
- src, dst = (LIVE, REPO) if args.pull else (REPO, LIVE)
66
- if not src.exists():
67
- print(f"source missing: {src}", file=sys.stderr)
68
- return 1
69
-
70
- dst.parent.mkdir(parents=True, exist_ok=True)
71
- backup = _backup(dst)
72
- shutil.copy2(src, dst)
73
- print(f"{src}\n -> {dst}")
74
- if backup:
75
- print(f" (previous version kept at {backup.name})")
76
- if not args.pull:
77
- apply_options()
78
- print("\nConfirm with: llm models list")
79
- return 0
80
-
81
-
82
- def apply_options() -> None:
83
- """`config/model-options.json` -> `llm models options set`, per alias.
84
-
85
- Default options live in the llm CLI's own store, which no repo reaches;
86
- this file is the canonical copy, as the yaml is for registrations."""
87
- import json
88
- import subprocess
89
- path = REPO.parent / "model-options.json"
90
- # No llm CLI (the Docker image): no store to set them in, and the
91
- # built-in client reads this file itself.
92
- if not path.exists() or not shutil.which("llm"):
93
- return
94
- for alias, options in json.loads(path.read_text(encoding="utf-8")).items():
95
- if alias.startswith("_"):
96
- continue
97
- for name, value in options.items():
98
- done = subprocess.run(["llm", "models", "options", "set", alias, name, str(value)],
99
- capture_output=True, text=True)
100
- if done.returncode:
101
- print(f" could not set {alias} {name}={value}: {done.stderr.strip()[:200]}")
102
-
103
-
104
- if __name__ == "__main__":
105
- raise SystemExit(main())
1
+ """Move `extra-openai-models.yaml` between this repo and the llm CLI.
2
+
3
+ The CLI reads its model registrations from one fixed path in its own per-user
4
+ folder (endpoints.LLM_DIR), which is not somewhere anyone thinks to look and
5
+ not somewhere version control reaches. So the data folder holds the canonical
6
+ copy and this moves it into place.
7
+
8
+ python scripts/sync_config.py # data folder -> llm (the usual way)
9
+ python scripts/sync_config.py --pull # llm -> data folder (live has drifted)
10
+ python scripts/sync_config.py --check # report differences, change nothing
11
+
12
+ A backup of whatever is being overwritten is written beside the target first,
13
+ because the live file is the one thing here that is not reproducible if the
14
+ repo copy turns out to be older.
15
+ """
16
+
17
+ from __future__ import annotations
18
+
19
+ import argparse
20
+ import datetime as dt
21
+ import filecmp
22
+ import pathlib
23
+ import shutil
24
+ import sys
25
+
26
+ sys.path.insert(0, str(pathlib.Path(__file__).resolve().parent.parent / "metrics"))
27
+ from paths import DATA # noqa: E402 -- the install's data folder (metrics/paths.py)
28
+ import endpoints # noqa: E402
29
+ REPO = DATA / "config" / "extra-openai-models.yaml"
30
+ LIVE = endpoints.LLM_DIR / "extra-openai-models.yaml"
31
+
32
+
33
+ def _backup(path: pathlib.Path) -> pathlib.Path | None:
34
+ if not path.exists():
35
+ return None
36
+ stamp = dt.datetime.now().strftime("%Y%m%dT%H%M%S")
37
+ dest = path.with_suffix(f".{stamp}.bak")
38
+ shutil.copy2(path, dest)
39
+ return dest
40
+
41
+
42
+ def main() -> int:
43
+ ap = argparse.ArgumentParser(description=__doc__)
44
+ ap.add_argument("--pull", action="store_true",
45
+ help="copy the live file back into the repo")
46
+ ap.add_argument("--check", action="store_true",
47
+ help="report whether they differ; change nothing")
48
+ args = ap.parse_args()
49
+
50
+ if not REPO.exists() and not args.pull:
51
+ print(f"repo copy missing: {REPO}", file=sys.stderr)
52
+ return 1
53
+
54
+ if args.check:
55
+ if not LIVE.exists():
56
+ print(f"live file does not exist: {LIVE}")
57
+ return 1
58
+ same = REPO.exists() and filecmp.cmp(REPO, LIVE, shallow=False)
59
+ print("identical" if same else "DIFFERENT")
60
+ if not same:
61
+ print(f" repo: {REPO}")
62
+ print(f" live: {LIVE}")
63
+ return 0 if same else 1
64
+
65
+ src, dst = (LIVE, REPO) if args.pull else (REPO, LIVE)
66
+ if not src.exists():
67
+ print(f"source missing: {src}", file=sys.stderr)
68
+ return 1
69
+
70
+ dst.parent.mkdir(parents=True, exist_ok=True)
71
+ backup = _backup(dst)
72
+ shutil.copy2(src, dst)
73
+ print(f"{src}\n -> {dst}")
74
+ if backup:
75
+ print(f" (previous version kept at {backup.name})")
76
+ if not args.pull:
77
+ apply_options()
78
+ print("\nConfirm with: llm models list")
79
+ return 0
80
+
81
+
82
+ def apply_options() -> None:
83
+ """`config/model-options.json` -> `llm models options set`, per alias.
84
+
85
+ Default options live in the llm CLI's own store, which no repo reaches;
86
+ this file is the canonical copy, as the yaml is for registrations."""
87
+ import json
88
+ import subprocess
89
+ path = REPO.parent / "model-options.json"
90
+ # No llm CLI (the Docker image): no store to set them in, and the
91
+ # built-in client reads this file itself.
92
+ if not path.exists() or not shutil.which("llm"):
93
+ return
94
+ for alias, options in json.loads(path.read_text(encoding="utf-8")).items():
95
+ if alias.startswith("_"):
96
+ continue
97
+ for name, value in options.items():
98
+ done = subprocess.run(["llm", "models", "options", "set", alias, name, str(value)],
99
+ capture_output=True, text=True)
100
+ if done.returncode:
101
+ print(f" could not set {alias} {name}={value}: {done.stderr.strip()[:200]}")
102
+
103
+
104
+ if __name__ == "__main__":
105
+ raise SystemExit(main())