@wendellresearch-ai/benchwarmers 0.6.7 → 0.6.8
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/VERSION +1 -1
- package/metrics/decide.py +19 -4
- package/metrics/endpoints.py +2 -1
- package/metrics/test_decide.py +17 -1
- package/package.json +1 -1
- package/scripts/onboard.py +8 -0
package/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
0.6.
|
|
1
|
+
0.6.8
|
package/metrics/decide.py
CHANGED
|
@@ -19,12 +19,17 @@ model answers a typed question.
|
|
|
19
19
|
|
|
20
20
|
WHERE THE CALL GOES
|
|
21
21
|
-------------------
|
|
22
|
-
Each endpoint in `config/endpoints.json` may carry a `decisions` URL.
|
|
22
|
+
Each endpoint in `config/endpoints.json` may carry a `decisions` URL. One
|
|
23
|
+
that is not a hub and has none is asked under its own base (`decisions_url`:
|
|
24
|
+
`<base>/decisions`, then `<base>/systemone`, as AMD Token Lab names it). Open
|
|
23
25
|
WebUI has one only through its `/openai/{path}` passthrough, which forwards to
|
|
24
26
|
`{connection base}/decisions` and answers only when the server runs with
|
|
25
27
|
ENABLE_OPENAI_API_PASSTHROUGH=True. That reaches Inception
|
|
26
28
|
(`api.inceptionlabs.ai/v1/decisions`) but never OpenRouter, whose Decisions API
|
|
27
|
-
is `/api/alpha/decisions`, outside its `/api/v1` base.
|
|
29
|
+
is `/api/alpha/decisions`, outside its `/api/v1` base. Nor a connection with
|
|
30
|
+
a prefix in Open WebUI: the passthrough sends the provider the prefixed id
|
|
31
|
+
(`amd.d3-flash`), which it does not know; such a model is onboarded from the
|
|
32
|
+
provider's own endpoint.
|
|
28
33
|
|
|
29
34
|
A model is called on the endpoint it was picked from when onboarding, recorded
|
|
30
35
|
as `via`: picked from Open WebUI, it goes through Open WebUI; picked from
|
|
@@ -226,6 +231,16 @@ def load() -> dict[str, dict]:
|
|
|
226
231
|
return {}
|
|
227
232
|
|
|
228
233
|
|
|
234
|
+
def decisions_url(endpoint: str) -> str:
|
|
235
|
+
"""Where `endpoint`'s Decisions API is: its own `decisions` URL, else `{path}`
|
|
236
|
+
under its base, which is where a provider that has one serves it (AMD Token
|
|
237
|
+
Lab: /v1/systemone), so a direct endpoint needs nothing written by hand. ""
|
|
238
|
+
for a hub without one: its relay is not under its base (Open WebUI's is
|
|
239
|
+
/openai/{path}, outside /api) and is given by hand."""
|
|
240
|
+
url = endpoints.load()[endpoint].get("decisions") or ""
|
|
241
|
+
return url or ("" if endpoints.hub(endpoint) else endpoints.base(endpoint) + "/{path}")
|
|
242
|
+
|
|
243
|
+
|
|
229
244
|
def call(endpoint: str, served: str, state, questions: dict, timeout: int = 60,
|
|
230
245
|
path: str = "decisions", alias: str = "", use: str = "", meta: dict | None = None,
|
|
231
246
|
retry: bool = True) -> dict:
|
|
@@ -237,7 +252,7 @@ def call(endpoint: str, served: str, state, questions: dict, timeout: int = 60,
|
|
|
237
252
|
try:
|
|
238
253
|
# Inside the try, so an endpoint gone from the config is logged too.
|
|
239
254
|
entry = endpoints.load()[endpoint]
|
|
240
|
-
url = (
|
|
255
|
+
url = decisions_url(endpoint).replace("{path}", path)
|
|
241
256
|
if not url:
|
|
242
257
|
raise ValueError(f"{endpoint} has no decisions URL in config/endpoints.json")
|
|
243
258
|
headers = {"Content-Type": "application/json", **(entry.get("headers") or {})}
|
|
@@ -343,7 +358,7 @@ def error_text(exc: Exception) -> str:
|
|
|
343
358
|
def probe(endpoint: str, served: str) -> tuple[str | None, str]:
|
|
344
359
|
"""(None, path) if `endpoint`'s decisions URL answers a yes/no question for
|
|
345
360
|
`served`, else (why not, ""). Each of PATHS is tried where the URL has `{path}`."""
|
|
346
|
-
url =
|
|
361
|
+
url = decisions_url(endpoint)
|
|
347
362
|
if not url:
|
|
348
363
|
return f"{endpoint} has no decisions URL in config/endpoints.json", ""
|
|
349
364
|
why = []
|
package/metrics/endpoints.py
CHANGED
|
@@ -20,7 +20,8 @@ that asks "what is served" asks every endpoint here.
|
|
|
20
20
|
|
|
21
21
|
`decisions` (optional) is the full URL of the endpoint's Decisions API, for
|
|
22
22
|
decision models that cannot be reached through chat completions; see
|
|
23
|
-
`metrics/decide.py`.
|
|
23
|
+
`metrics/decide.py`. Without one, an endpoint that is not a hub is asked under
|
|
24
|
+
its own base (`decide.decisions_url`). Open WebUI's is its `/openai/{path}` passthrough, which
|
|
24
25
|
answers only when the server runs with ENABLE_OPENAI_API_PASSTHROUGH=True;
|
|
25
26
|
`{path}` is filled per model (`decisions` for Inception, `systemone` for
|
|
26
27
|
Ollama), because the passthrough appends it to the connection's own base.
|
package/metrics/test_decide.py
CHANGED
|
@@ -31,7 +31,9 @@ def jsonl(path: str, rows: list[dict]) -> None:
|
|
|
31
31
|
write("config/endpoints.json", {"hub": {"base": "http://127.0.0.1:9/api", "key": "hub", "default": True,
|
|
32
32
|
"decisions": "http://127.0.0.1:9/openai/{path}"},
|
|
33
33
|
"cf": {"base": "http://127.0.0.1:9/ai/v1", "key": "hub",
|
|
34
|
-
"decisions": "http://127.0.0.1:9/ai/run/{model}"}
|
|
34
|
+
"decisions": "http://127.0.0.1:9/ai/run/{model}"},
|
|
35
|
+
"bare": {"base": "http://127.0.0.1:9/v1", "key": "hub", "kind": "provider"},
|
|
36
|
+
"barehub": {"base": "http://127.0.0.1:8/api", "key": "hub"}})
|
|
35
37
|
# dm2 first: before any result it is the one asked (the first that takes choice, as before),
|
|
36
38
|
# except per request, where its :free budget is spared while dm1 can answer.
|
|
37
39
|
MODELS = {
|
|
@@ -148,6 +150,20 @@ decide.urllib.request.urlopen = cf_urlopen
|
|
|
148
150
|
assert decide.probe("cf", "@cf/cloudflare/clef-flash") == (None, "decisions")
|
|
149
151
|
assert decide.log_rows()[-1]["answers"]["probe"]["noul"] == 0.98
|
|
150
152
|
decide.LOG.unlink()
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
# An endpoint with no decisions URL is asked under its own base, each path in turn (AMD Token
|
|
156
|
+
# Lab answers only /v1/systemone); a hub without one is not asked: its relay is given by hand.
|
|
157
|
+
def bare_urlopen(request, timeout=0):
|
|
158
|
+
if request.full_url != "http://127.0.0.1:9/v1/systemone":
|
|
159
|
+
raise http_error(b'{"error": {"message": "Unknown endpoint"}}', 404)
|
|
160
|
+
return io.BytesIO(json.dumps({"answers": {"probe": {"type": "noul", "noul": 0.99}}}).encode())
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
decide.urllib.request.urlopen = bare_urlopen
|
|
164
|
+
assert decide.probe("bare", "d3") == (None, "systemone")
|
|
165
|
+
assert decide.probe("barehub", "d3") == ("barehub has no decisions URL in config/endpoints.json", "")
|
|
166
|
+
decide.LOG.unlink()
|
|
151
167
|
decide.urllib.request.urlopen = urlopen
|
|
152
168
|
|
|
153
169
|
# ---- every call is logged, and an error's body survives the log -------------------------------
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wendellresearch-ai/benchwarmers",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.8",
|
|
4
4
|
"description": "Self-hosted panel gateway for LLMs: ask a collection of models at once, keep every answer side by side, rotate explorer models in, and let your verdicts pick the next panel.",
|
|
5
5
|
"mcpName": "io.github.WendellResearch-AI/benchwarmers",
|
|
6
6
|
"license": "MIT",
|
package/scripts/onboard.py
CHANGED
|
@@ -292,8 +292,16 @@ def main() -> None:
|
|
|
292
292
|
" models_url .../ai/models/search?per_page=1000) and onboard it from there.\n"
|
|
293
293
|
if "@cf/" in name and endpoint != "cloudflare" and "{model}" not in
|
|
294
294
|
(endpoints.load()[endpoint].get("decisions") or "") else
|
|
295
|
+
# Only a hub gets here: any other endpoint is asked under its own base.
|
|
296
|
+
" Give this hub a decisions URL in config/endpoints.json (Open WebUI's is"
|
|
297
|
+
" http://<host>/openai/{path}), or onboard the model from its provider's own endpoint.\n"
|
|
298
|
+
if "has no decisions URL" in why else
|
|
295
299
|
" Open WebUI relays decisions only with ENABLE_OPENAI_API_PASSTHROUGH=True"
|
|
296
300
|
" in its environment.\n" if owui and "passthrough" in why.lower() else
|
|
301
|
+
# The relay sends the id as Open WebUI lists it, connection prefix and all.
|
|
302
|
+
f" Open WebUI sends the provider the prefixed id ({name}), which it does not know."
|
|
303
|
+
" Add the provider as an endpoint of its own and onboard the model from there.\n"
|
|
304
|
+
if owui and " 404" in why and connection_prefix(live[name]) else
|
|
297
305
|
" Its connection has no /decisions under its base. An OpenRouter-hosted decision"
|
|
298
306
|
" model cannot go through Open WebUI (its Decisions API is outside /api/v1);"
|
|
299
307
|
" pick it from openrouter (direct) instead.\n" if owui and " 404" in why and " 402" not in why else
|