tuieval 0.2.0.dev42__tar.gz → 0.2.0.dev43__tar.gz
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.
- {tuieval-0.2.0.dev42 → tuieval-0.2.0.dev43}/CHANGELOG.md +1 -0
- {tuieval-0.2.0.dev42 → tuieval-0.2.0.dev43}/PKG-INFO +1 -1
- {tuieval-0.2.0.dev42 → tuieval-0.2.0.dev43}/src/tuieval/_version.py +2 -2
- {tuieval-0.2.0.dev42 → tuieval-0.2.0.dev43}/src/tuieval/client.py +11 -1
- {tuieval-0.2.0.dev42 → tuieval-0.2.0.dev43}/src/tuieval/engine.py +3 -0
- {tuieval-0.2.0.dev42 → tuieval-0.2.0.dev43}/tests/mock_server.py +4 -1
- {tuieval-0.2.0.dev42 → tuieval-0.2.0.dev43}/tests/test_tuieval.py +45 -0
- {tuieval-0.2.0.dev42 → tuieval-0.2.0.dev43}/.gitignore +0 -0
- {tuieval-0.2.0.dev42 → tuieval-0.2.0.dev43}/LICENSE +0 -0
- {tuieval-0.2.0.dev42 → tuieval-0.2.0.dev43}/README.md +0 -0
- {tuieval-0.2.0.dev42 → tuieval-0.2.0.dev43}/RELEASING.md +0 -0
- {tuieval-0.2.0.dev42 → tuieval-0.2.0.dev43}/docs/images/brand/README.md +0 -0
- {tuieval-0.2.0.dev42 → tuieval-0.2.0.dev43}/docs/images/brand/favicon.ico +0 -0
- {tuieval-0.2.0.dev42 → tuieval-0.2.0.dev43}/docs/images/brand/readme-header.png +0 -0
- {tuieval-0.2.0.dev42 → tuieval-0.2.0.dev43}/docs/images/brand/social-preview.png +0 -0
- {tuieval-0.2.0.dev42 → tuieval-0.2.0.dev43}/docs/images/brand/tuieval-icon-1024.png +0 -0
- {tuieval-0.2.0.dev42 → tuieval-0.2.0.dev43}/docs/images/brand/tuieval-icon-128.png +0 -0
- {tuieval-0.2.0.dev42 → tuieval-0.2.0.dev43}/docs/images/brand/tuieval-icon-16.png +0 -0
- {tuieval-0.2.0.dev42 → tuieval-0.2.0.dev43}/docs/images/brand/tuieval-icon-16.svg +0 -0
- {tuieval-0.2.0.dev42 → tuieval-0.2.0.dev43}/docs/images/brand/tuieval-icon-256.png +0 -0
- {tuieval-0.2.0.dev42 → tuieval-0.2.0.dev43}/docs/images/brand/tuieval-icon-32.png +0 -0
- {tuieval-0.2.0.dev42 → tuieval-0.2.0.dev43}/docs/images/brand/tuieval-icon-48.png +0 -0
- {tuieval-0.2.0.dev42 → tuieval-0.2.0.dev43}/docs/images/brand/tuieval-icon-512.png +0 -0
- {tuieval-0.2.0.dev42 → tuieval-0.2.0.dev43}/docs/images/brand/tuieval-icon-64.png +0 -0
- {tuieval-0.2.0.dev42 → tuieval-0.2.0.dev43}/docs/images/brand/tuieval-icon-animated.svg +0 -0
- {tuieval-0.2.0.dev42 → tuieval-0.2.0.dev43}/docs/images/brand/tuieval-icon.svg +0 -0
- {tuieval-0.2.0.dev42 → tuieval-0.2.0.dev43}/docs/images/tui-answer-reasoning.png +0 -0
- {tuieval-0.2.0.dev42 → tuieval-0.2.0.dev43}/docs/images/tui-run-reasoning.png +0 -0
- {tuieval-0.2.0.dev42 → tuieval-0.2.0.dev43}/docs/images/tui-setup.png +0 -0
- {tuieval-0.2.0.dev42 → tuieval-0.2.0.dev43}/docs/models.md +0 -0
- {tuieval-0.2.0.dev42 → tuieval-0.2.0.dev43}/docs/writing-packs.md +0 -0
- {tuieval-0.2.0.dev42 → tuieval-0.2.0.dev43}/pyproject.toml +0 -0
- {tuieval-0.2.0.dev42 → tuieval-0.2.0.dev43}/src/tuieval/__init__.py +0 -0
- {tuieval-0.2.0.dev42 → tuieval-0.2.0.dev43}/src/tuieval/__main__.py +0 -0
- {tuieval-0.2.0.dev42 → tuieval-0.2.0.dev43}/src/tuieval/builtin.toml +0 -0
- {tuieval-0.2.0.dev42 → tuieval-0.2.0.dev43}/src/tuieval/cli.py +0 -0
- {tuieval-0.2.0.dev42 → tuieval-0.2.0.dev43}/src/tuieval/compare.py +0 -0
- {tuieval-0.2.0.dev42 → tuieval-0.2.0.dev43}/src/tuieval/doctor.py +0 -0
- {tuieval-0.2.0.dev42 → tuieval-0.2.0.dev43}/src/tuieval/export.py +0 -0
- {tuieval-0.2.0.dev42 → tuieval-0.2.0.dev43}/src/tuieval/graders/__init__.py +0 -0
- {tuieval-0.2.0.dev42 → tuieval-0.2.0.dev43}/src/tuieval/graders/answer.py +0 -0
- {tuieval-0.2.0.dev42 → tuieval-0.2.0.dev43}/src/tuieval/graders/code.py +0 -0
- {tuieval-0.2.0.dev42 → tuieval-0.2.0.dev43}/src/tuieval/graders/rag.py +0 -0
- {tuieval-0.2.0.dev42 → tuieval-0.2.0.dev43}/src/tuieval/graders/reply.py +0 -0
- {tuieval-0.2.0.dev42 → tuieval-0.2.0.dev43}/src/tuieval/graders/tool_call.py +0 -0
- {tuieval-0.2.0.dev42 → tuieval-0.2.0.dev43}/src/tuieval/machines.py +0 -0
- {tuieval-0.2.0.dev42 → tuieval-0.2.0.dev43}/src/tuieval/onboard.py +0 -0
- {tuieval-0.2.0.dev42 → tuieval-0.2.0.dev43}/src/tuieval/packs.py +0 -0
- {tuieval-0.2.0.dev42 → tuieval-0.2.0.dev43}/src/tuieval/profiles.py +0 -0
- {tuieval-0.2.0.dev42 → tuieval-0.2.0.dev43}/src/tuieval/pta.py +0 -0
- {tuieval-0.2.0.dev42 → tuieval-0.2.0.dev43}/src/tuieval/remove.py +0 -0
- {tuieval-0.2.0.dev42 → tuieval-0.2.0.dev43}/src/tuieval/run_evals.py +0 -0
- {tuieval-0.2.0.dev42 → tuieval-0.2.0.dev43}/src/tuieval/scaffold.py +0 -0
- {tuieval-0.2.0.dev42 → tuieval-0.2.0.dev43}/src/tuieval/selftest.py +0 -0
- {tuieval-0.2.0.dev42 → tuieval-0.2.0.dev43}/src/tuieval/templates/models.toml +0 -0
- {tuieval-0.2.0.dev42 → tuieval-0.2.0.dev43}/src/tuieval/templates/packs/answer/pack.toml +0 -0
- {tuieval-0.2.0.dev42 → tuieval-0.2.0.dev43}/src/tuieval/templates/packs/answer/system.txt +0 -0
- {tuieval-0.2.0.dev42 → tuieval-0.2.0.dev43}/src/tuieval/templates/packs/answer/tests.yaml +0 -0
- {tuieval-0.2.0.dev42 → tuieval-0.2.0.dev43}/src/tuieval/templates/packs/code/pack.toml +0 -0
- {tuieval-0.2.0.dev42 → tuieval-0.2.0.dev43}/src/tuieval/templates/packs/code/system.txt +0 -0
- {tuieval-0.2.0.dev42 → tuieval-0.2.0.dev43}/src/tuieval/templates/packs/code/tests.yaml +0 -0
- {tuieval-0.2.0.dev42 → tuieval-0.2.0.dev43}/src/tuieval/templates/packs/rag/pack.toml +0 -0
- {tuieval-0.2.0.dev42 → tuieval-0.2.0.dev43}/src/tuieval/templates/packs/rag/system.txt +0 -0
- {tuieval-0.2.0.dev42 → tuieval-0.2.0.dev43}/src/tuieval/templates/packs/rag/tests.yaml +0 -0
- {tuieval-0.2.0.dev42 → tuieval-0.2.0.dev43}/src/tuieval/templates/packs/reply/pack.toml +0 -0
- {tuieval-0.2.0.dev42 → tuieval-0.2.0.dev43}/src/tuieval/templates/packs/reply/system.txt +0 -0
- {tuieval-0.2.0.dev42 → tuieval-0.2.0.dev43}/src/tuieval/templates/packs/reply/tests.yaml +0 -0
- {tuieval-0.2.0.dev42 → tuieval-0.2.0.dev43}/src/tuieval/templates/packs/tool_call/pack.toml +0 -0
- {tuieval-0.2.0.dev42 → tuieval-0.2.0.dev43}/src/tuieval/templates/packs/tool_call/system.txt +0 -0
- {tuieval-0.2.0.dev42 → tuieval-0.2.0.dev43}/src/tuieval/templates/packs/tool_call/tests.yaml +0 -0
- {tuieval-0.2.0.dev42 → tuieval-0.2.0.dev43}/src/tuieval/templates/packs/tool_call/tools.yaml +0 -0
- {tuieval-0.2.0.dev42 → tuieval-0.2.0.dev43}/src/tuieval/tui.py +0 -0
- {tuieval-0.2.0.dev42 → tuieval-0.2.0.dev43}/src/tuieval/tune.py +0 -0
- {tuieval-0.2.0.dev42 → tuieval-0.2.0.dev43}/src/tuieval/verdict.py +0 -0
- {tuieval-0.2.0.dev42 → tuieval-0.2.0.dev43}/src/tuieval/watch_proxy.py +0 -0
- {tuieval-0.2.0.dev42 → tuieval-0.2.0.dev43}/src/tuieval/workspace.py +0 -0
- {tuieval-0.2.0.dev42 → tuieval-0.2.0.dev43}/src/tuieval/yamlout.py +0 -0
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
## Unreleased
|
|
4
4
|
|
|
5
|
+
- A model a server won't serve (HTTP 401-404, e.g. OpenRouter's "No endpoints found") is never judged on it: those answers don't count, and the model stops at once instead of failing every question.
|
|
5
6
|
- PTA index: privacy, time (total, relative to the fastest) and accuracy per model, as a triangle in Results, `tuieval pta` and the report.
|
|
6
7
|
- Run several models at a time: `parallel_models` per machine, **Models at a time** in the TUI, or `tuieval run --parallel N` (default 1). Models wait for memory to fit, and answers note what ran alongside them.
|
|
7
8
|
- More evals during a run: `n` opens Setup, and Start adds them to the run going (same tier) or queues them after it.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: tuieval
|
|
3
|
-
Version: 0.2.0.
|
|
3
|
+
Version: 0.2.0.dev43
|
|
4
4
|
Summary: Evaluate local and frontier LLMs on your own questions: accuracy, speed, tokens and PASS/FAIL verdicts, in the terminal.
|
|
5
5
|
Project-URL: Homepage, https://github.com/ashe-wb/tuieval
|
|
6
6
|
Project-URL: Issues, https://github.com/ashe-wb/tuieval/issues
|
|
@@ -18,7 +18,7 @@ version_tuple: tuple[int | str, ...]
|
|
|
18
18
|
commit_id: str | None
|
|
19
19
|
__commit_id__: str | None
|
|
20
20
|
|
|
21
|
-
__version__ = version = '0.2.0.
|
|
22
|
-
__version_tuple__ = version_tuple = (0, 2, 0, '
|
|
21
|
+
__version__ = version = '0.2.0.dev43'
|
|
22
|
+
__version_tuple__ = version_tuple = (0, 2, 0, 'dev43')
|
|
23
23
|
|
|
24
24
|
__commit_id__ = commit_id = None
|
|
@@ -17,6 +17,10 @@ import time
|
|
|
17
17
|
import urllib.parse
|
|
18
18
|
|
|
19
19
|
SERVER_ERROR_PREFIXES = ("server returned HTTP 5", "server returned HTTP 429", "server error", "connection error")
|
|
20
|
+
# the model can't be reached there at all (a bad key, no credits, or a hosted API with no provider serving it, e.g.
|
|
21
|
+
# OpenRouter's 404 "No endpoints found"): not the model's answer either, and waiting won't fix it
|
|
22
|
+
UNAVAILABLE_PREFIXES = ("server returned HTTP 401", "server returned HTTP 402", "server returned HTTP 403",
|
|
23
|
+
"server returned HTTP 404")
|
|
20
24
|
|
|
21
25
|
|
|
22
26
|
def is_server_error(error):
|
|
@@ -27,9 +31,15 @@ def is_server_error(error):
|
|
|
27
31
|
and "timeout" not in error.lower()
|
|
28
32
|
|
|
29
33
|
|
|
34
|
+
def is_unavailable(error):
|
|
35
|
+
"""True for an error saying the model isn't available on that server at all: HTTP 401, 402, 403 or
|
|
36
|
+
404. Never the model's answer, and not worth retrying."""
|
|
37
|
+
return bool(error) and error.startswith(UNAVAILABLE_PREFIXES)
|
|
38
|
+
|
|
39
|
+
|
|
30
40
|
def server_error_row(rec):
|
|
31
41
|
"""A stored answer that was really a server failure (never a judgement of the model)."""
|
|
32
|
-
return not rec.get("pass") and is_server_error(rec.get("reason"))
|
|
42
|
+
return not rec.get("pass") and (is_server_error(rec.get("reason")) or is_unavailable(rec.get("reason")))
|
|
33
43
|
|
|
34
44
|
|
|
35
45
|
class Cancelled(Exception):
|
|
@@ -2105,6 +2105,9 @@ class Engine:
|
|
|
2105
2105
|
self._check()
|
|
2106
2106
|
if res["error"] and not alive():
|
|
2107
2107
|
raise ModelFailed(f"the server stopped: {res['error']}")
|
|
2108
|
+
if client.is_unavailable(res["error"]): # never an answer; retrying won't help
|
|
2109
|
+
raise ModelFailed(f"the model isn't available there (not counted against it): "
|
|
2110
|
+
f"{res['error'][:300]}")
|
|
2108
2111
|
if not client.is_server_error(res["error"]):
|
|
2109
2112
|
break
|
|
2110
2113
|
# the server failed, not the model: never recorded as an answer
|
|
@@ -6,6 +6,7 @@ oracle answers each question with its test's `reference` (or the expected tool
|
|
|
6
6
|
correct grader passes it
|
|
7
7
|
wrong answers with the test's first `wrong` entry (or "ANSWER: 0")
|
|
8
8
|
fixed always "ANSWER: 42"
|
|
9
|
+
unavailable HTTP 404 "No endpoints found" for every chat request
|
|
9
10
|
|
|
10
11
|
Streams like llama.cpp: reasoning_content then content deltas, usage and timings at the end.
|
|
11
12
|
"""
|
|
@@ -77,6 +78,8 @@ class Handler(BaseHTTPRequestHandler):
|
|
|
77
78
|
if isinstance(content, list):
|
|
78
79
|
content = " ".join(p.get("text", "") for p in content if isinstance(p, dict))
|
|
79
80
|
test = self.answers.get(" ".join(str(content).split()))
|
|
81
|
+
if self.mode == "unavailable": # like OpenRouter with no provider serving the model
|
|
82
|
+
return self._json({"error": {"message": f"No endpoints found for {self.model}.", "code": 404}}, 404)
|
|
80
83
|
text, calls = reply_for(test, self.mode)
|
|
81
84
|
self.send_response(200)
|
|
82
85
|
self.send_header("Content-Type", "text/event-stream")
|
|
@@ -105,7 +108,7 @@ def main(argv=None):
|
|
|
105
108
|
p = argparse.ArgumentParser()
|
|
106
109
|
p.add_argument("--port", type=int, default=18090)
|
|
107
110
|
p.add_argument("--packs", required=True)
|
|
108
|
-
p.add_argument("--mode", choices=("oracle", "wrong", "fixed"), default="oracle")
|
|
111
|
+
p.add_argument("--mode", choices=("oracle", "wrong", "fixed", "unavailable"), default="oracle")
|
|
109
112
|
p.add_argument("--model", default="mock")
|
|
110
113
|
p.add_argument("--delay", type=float, default=0.0, help="seconds each answer takes")
|
|
111
114
|
a, _ = p.parse_known_args(argv) # other flags (e.g. speed knobs under test) are accepted and ignored
|
|
@@ -198,6 +198,16 @@ class WorkspaceGraders(unittest.TestCase):
|
|
|
198
198
|
|
|
199
199
|
|
|
200
200
|
class Units(unittest.TestCase):
|
|
201
|
+
def test_server_errors_never_judge_the_model(self):
|
|
202
|
+
from tuieval import client
|
|
203
|
+
no_endpoints = 'server returned HTTP 404: {"error":{"message":"No endpoints found for some/model."}}'
|
|
204
|
+
for reason, retry, unavailable in ((no_endpoints, False, True), ("server returned HTTP 402: no credits", False, True),
|
|
205
|
+
("server returned HTTP 503: busy", True, False),
|
|
206
|
+
("server returned HTTP 400: bad request", False, False),
|
|
207
|
+
("connection error: timed out", False, False)): # the model too slow
|
|
208
|
+
self.assertEqual((client.is_server_error(reason), client.is_unavailable(reason)), (retry, unavailable), reason)
|
|
209
|
+
self.assertEqual(client.server_error_row({"pass": False, "reason": reason}), retry or unavailable, reason)
|
|
210
|
+
|
|
201
211
|
def test_tune_workload_needs_no_packs(self):
|
|
202
212
|
from tuieval import tune
|
|
203
213
|
work = tune.workload(None, 65536)
|
|
@@ -787,6 +797,41 @@ class PTAIndex(unittest.TestCase):
|
|
|
787
797
|
self.assertEqual([r[:4] for r in got["rows"]][0], ["good", "100", "100", "100"])
|
|
788
798
|
|
|
789
799
|
|
|
800
|
+
class Unavailable(unittest.TestCase):
|
|
801
|
+
"""A model no server will serve (OpenRouter's 404 "No endpoints found", a bad key, no credits) stops at
|
|
802
|
+
once and is never judged on it; the other models run as usual."""
|
|
803
|
+
|
|
804
|
+
def test_unavailable_model_stops_and_isnt_judged(self):
|
|
805
|
+
with tempfile.TemporaryDirectory() as tmp:
|
|
806
|
+
ws = os.path.join(tmp, "ws")
|
|
807
|
+
tuieval(tmp, "init", ws)
|
|
808
|
+
d = os.path.join(ws, "packs", "apps")
|
|
809
|
+
os.makedirs(d)
|
|
810
|
+
write(os.path.join(d, "pack.toml"), 'label = "apps"\n[certify]\nrepeat = 1\n[gate]\nmin_accuracy = 0.1\n')
|
|
811
|
+
write(os.path.join(d, "tests.yaml"), "".join(
|
|
812
|
+
f"- {{id: {t}, input: question {t}, expected: 1, reference: 'ANSWER: 1', difficulty: easy}}\n"
|
|
813
|
+
for t in "abc"))
|
|
814
|
+
up, down = Mock(os.path.join(ws, "packs"), "oracle"), Mock(os.path.join(ws, "packs"), "unavailable")
|
|
815
|
+
try:
|
|
816
|
+
with open(os.path.join(ws, "models.toml"), "a") as f:
|
|
817
|
+
f.write(f'\n[servers.up]\nurl = "http://127.0.0.1:{up.port}"\n'
|
|
818
|
+
f'\n[servers.down]\nurl = "http://127.0.0.1:{down.port}"\n')
|
|
819
|
+
tuieval(ws, "add", "mock", "--server", "up", "--label", "works")
|
|
820
|
+
tuieval(ws, "add", "mock", "--server", "down", "--label", "gone")
|
|
821
|
+
t = time.time()
|
|
822
|
+
out = tuieval(ws, "run", "--tier", "certify", check=False).stdout
|
|
823
|
+
finally:
|
|
824
|
+
up.stop()
|
|
825
|
+
down.stop()
|
|
826
|
+
self.assertLess(time.time() - t, 60) # no retrying for minutes
|
|
827
|
+
self.assertIn("isn't available there", out)
|
|
828
|
+
verdict = tuieval(ws, "verdict", check=False).stdout
|
|
829
|
+
self.assertNotIn("0% right", verdict) # never judged on the 404s
|
|
830
|
+
rows = [l for l in verdict.splitlines() if "gone" in l]
|
|
831
|
+
self.assertFalse(any("FAIL" in l for l in rows), rows)
|
|
832
|
+
self.assertIn("works", tuieval(ws, "pta").stdout)
|
|
833
|
+
|
|
834
|
+
|
|
790
835
|
class FirstRun(unittest.TestCase):
|
|
791
836
|
"""A new user's first run fails fast with the fix, never hangs or shows a bare Python error."""
|
|
792
837
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{tuieval-0.2.0.dev42 → tuieval-0.2.0.dev43}/src/tuieval/templates/packs/tool_call/system.txt
RENAMED
|
File without changes
|
{tuieval-0.2.0.dev42 → tuieval-0.2.0.dev43}/src/tuieval/templates/packs/tool_call/tests.yaml
RENAMED
|
File without changes
|
{tuieval-0.2.0.dev42 → tuieval-0.2.0.dev43}/src/tuieval/templates/packs/tool_call/tools.yaml
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|