tuieval 0.2.0.dev105__tar.gz → 0.2.0.dev108__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.dev105 → tuieval-0.2.0.dev108}/CHANGELOG.md +2 -0
- {tuieval-0.2.0.dev105 → tuieval-0.2.0.dev108}/PKG-INFO +1 -1
- {tuieval-0.2.0.dev105 → tuieval-0.2.0.dev108}/src/tuieval/_version.py +2 -2
- {tuieval-0.2.0.dev105 → tuieval-0.2.0.dev108}/src/tuieval/tui.py +63 -14
- {tuieval-0.2.0.dev105 → tuieval-0.2.0.dev108}/tests/test_tuieval.py +57 -1
- {tuieval-0.2.0.dev105 → tuieval-0.2.0.dev108}/.gitignore +0 -0
- {tuieval-0.2.0.dev105 → tuieval-0.2.0.dev108}/LICENSE +0 -0
- {tuieval-0.2.0.dev105 → tuieval-0.2.0.dev108}/README.md +0 -0
- {tuieval-0.2.0.dev105 → tuieval-0.2.0.dev108}/RELEASING.md +0 -0
- {tuieval-0.2.0.dev105 → tuieval-0.2.0.dev108}/docs/images/brand/README.md +0 -0
- {tuieval-0.2.0.dev105 → tuieval-0.2.0.dev108}/docs/images/brand/favicon.ico +0 -0
- {tuieval-0.2.0.dev105 → tuieval-0.2.0.dev108}/docs/images/brand/readme-header.png +0 -0
- {tuieval-0.2.0.dev105 → tuieval-0.2.0.dev108}/docs/images/brand/social-preview.png +0 -0
- {tuieval-0.2.0.dev105 → tuieval-0.2.0.dev108}/docs/images/brand/tuieval-icon-1024.png +0 -0
- {tuieval-0.2.0.dev105 → tuieval-0.2.0.dev108}/docs/images/brand/tuieval-icon-128.png +0 -0
- {tuieval-0.2.0.dev105 → tuieval-0.2.0.dev108}/docs/images/brand/tuieval-icon-16.png +0 -0
- {tuieval-0.2.0.dev105 → tuieval-0.2.0.dev108}/docs/images/brand/tuieval-icon-16.svg +0 -0
- {tuieval-0.2.0.dev105 → tuieval-0.2.0.dev108}/docs/images/brand/tuieval-icon-256.png +0 -0
- {tuieval-0.2.0.dev105 → tuieval-0.2.0.dev108}/docs/images/brand/tuieval-icon-32.png +0 -0
- {tuieval-0.2.0.dev105 → tuieval-0.2.0.dev108}/docs/images/brand/tuieval-icon-48.png +0 -0
- {tuieval-0.2.0.dev105 → tuieval-0.2.0.dev108}/docs/images/brand/tuieval-icon-512.png +0 -0
- {tuieval-0.2.0.dev105 → tuieval-0.2.0.dev108}/docs/images/brand/tuieval-icon-64.png +0 -0
- {tuieval-0.2.0.dev105 → tuieval-0.2.0.dev108}/docs/images/brand/tuieval-icon-animated.svg +0 -0
- {tuieval-0.2.0.dev105 → tuieval-0.2.0.dev108}/docs/images/brand/tuieval-icon.svg +0 -0
- {tuieval-0.2.0.dev105 → tuieval-0.2.0.dev108}/docs/images/tui-answer-reasoning.png +0 -0
- {tuieval-0.2.0.dev105 → tuieval-0.2.0.dev108}/docs/images/tui-run-reasoning.png +0 -0
- {tuieval-0.2.0.dev105 → tuieval-0.2.0.dev108}/docs/images/tui-setup.png +0 -0
- {tuieval-0.2.0.dev105 → tuieval-0.2.0.dev108}/docs/models.md +0 -0
- {tuieval-0.2.0.dev105 → tuieval-0.2.0.dev108}/docs/writing-packs.md +0 -0
- {tuieval-0.2.0.dev105 → tuieval-0.2.0.dev108}/pyproject.toml +0 -0
- {tuieval-0.2.0.dev105 → tuieval-0.2.0.dev108}/src/tuieval/__init__.py +0 -0
- {tuieval-0.2.0.dev105 → tuieval-0.2.0.dev108}/src/tuieval/__main__.py +0 -0
- {tuieval-0.2.0.dev105 → tuieval-0.2.0.dev108}/src/tuieval/builtin.toml +0 -0
- {tuieval-0.2.0.dev105 → tuieval-0.2.0.dev108}/src/tuieval/cli.py +0 -0
- {tuieval-0.2.0.dev105 → tuieval-0.2.0.dev108}/src/tuieval/client.py +0 -0
- {tuieval-0.2.0.dev105 → tuieval-0.2.0.dev108}/src/tuieval/compare.py +0 -0
- {tuieval-0.2.0.dev105 → tuieval-0.2.0.dev108}/src/tuieval/doctor.py +0 -0
- {tuieval-0.2.0.dev105 → tuieval-0.2.0.dev108}/src/tuieval/engine.py +0 -0
- {tuieval-0.2.0.dev105 → tuieval-0.2.0.dev108}/src/tuieval/export.py +0 -0
- {tuieval-0.2.0.dev105 → tuieval-0.2.0.dev108}/src/tuieval/graders/__init__.py +0 -0
- {tuieval-0.2.0.dev105 → tuieval-0.2.0.dev108}/src/tuieval/graders/answer.py +0 -0
- {tuieval-0.2.0.dev105 → tuieval-0.2.0.dev108}/src/tuieval/graders/code.py +0 -0
- {tuieval-0.2.0.dev105 → tuieval-0.2.0.dev108}/src/tuieval/graders/rag.py +0 -0
- {tuieval-0.2.0.dev105 → tuieval-0.2.0.dev108}/src/tuieval/graders/reply.py +0 -0
- {tuieval-0.2.0.dev105 → tuieval-0.2.0.dev108}/src/tuieval/graders/tool_call.py +0 -0
- {tuieval-0.2.0.dev105 → tuieval-0.2.0.dev108}/src/tuieval/insights.py +0 -0
- {tuieval-0.2.0.dev105 → tuieval-0.2.0.dev108}/src/tuieval/logs.py +0 -0
- {tuieval-0.2.0.dev105 → tuieval-0.2.0.dev108}/src/tuieval/machines.py +0 -0
- {tuieval-0.2.0.dev105 → tuieval-0.2.0.dev108}/src/tuieval/onboard.py +0 -0
- {tuieval-0.2.0.dev105 → tuieval-0.2.0.dev108}/src/tuieval/packs.py +0 -0
- {tuieval-0.2.0.dev105 → tuieval-0.2.0.dev108}/src/tuieval/profiles.py +0 -0
- {tuieval-0.2.0.dev105 → tuieval-0.2.0.dev108}/src/tuieval/pta.py +0 -0
- {tuieval-0.2.0.dev105 → tuieval-0.2.0.dev108}/src/tuieval/remove.py +0 -0
- {tuieval-0.2.0.dev105 → tuieval-0.2.0.dev108}/src/tuieval/run_evals.py +0 -0
- {tuieval-0.2.0.dev105 → tuieval-0.2.0.dev108}/src/tuieval/scaffold.py +0 -0
- {tuieval-0.2.0.dev105 → tuieval-0.2.0.dev108}/src/tuieval/selftest.py +0 -0
- {tuieval-0.2.0.dev105 → tuieval-0.2.0.dev108}/src/tuieval/templates/models.toml +0 -0
- {tuieval-0.2.0.dev105 → tuieval-0.2.0.dev108}/src/tuieval/templates/packs/answer/pack.toml +0 -0
- {tuieval-0.2.0.dev105 → tuieval-0.2.0.dev108}/src/tuieval/templates/packs/answer/system.txt +0 -0
- {tuieval-0.2.0.dev105 → tuieval-0.2.0.dev108}/src/tuieval/templates/packs/answer/tests.yaml +0 -0
- {tuieval-0.2.0.dev105 → tuieval-0.2.0.dev108}/src/tuieval/templates/packs/code/pack.toml +0 -0
- {tuieval-0.2.0.dev105 → tuieval-0.2.0.dev108}/src/tuieval/templates/packs/code/system.txt +0 -0
- {tuieval-0.2.0.dev105 → tuieval-0.2.0.dev108}/src/tuieval/templates/packs/code/tests.yaml +0 -0
- {tuieval-0.2.0.dev105 → tuieval-0.2.0.dev108}/src/tuieval/templates/packs/rag/pack.toml +0 -0
- {tuieval-0.2.0.dev105 → tuieval-0.2.0.dev108}/src/tuieval/templates/packs/rag/system.txt +0 -0
- {tuieval-0.2.0.dev105 → tuieval-0.2.0.dev108}/src/tuieval/templates/packs/rag/tests.yaml +0 -0
- {tuieval-0.2.0.dev105 → tuieval-0.2.0.dev108}/src/tuieval/templates/packs/reply/pack.toml +0 -0
- {tuieval-0.2.0.dev105 → tuieval-0.2.0.dev108}/src/tuieval/templates/packs/reply/system.txt +0 -0
- {tuieval-0.2.0.dev105 → tuieval-0.2.0.dev108}/src/tuieval/templates/packs/reply/tests.yaml +0 -0
- {tuieval-0.2.0.dev105 → tuieval-0.2.0.dev108}/src/tuieval/templates/packs/tool_call/pack.toml +0 -0
- {tuieval-0.2.0.dev105 → tuieval-0.2.0.dev108}/src/tuieval/templates/packs/tool_call/system.txt +0 -0
- {tuieval-0.2.0.dev105 → tuieval-0.2.0.dev108}/src/tuieval/templates/packs/tool_call/tests.yaml +0 -0
- {tuieval-0.2.0.dev105 → tuieval-0.2.0.dev108}/src/tuieval/templates/packs/tool_call/tools.yaml +0 -0
- {tuieval-0.2.0.dev105 → tuieval-0.2.0.dev108}/src/tuieval/tune.py +0 -0
- {tuieval-0.2.0.dev105 → tuieval-0.2.0.dev108}/src/tuieval/verdict.py +0 -0
- {tuieval-0.2.0.dev105 → tuieval-0.2.0.dev108}/src/tuieval/watch_proxy.py +0 -0
- {tuieval-0.2.0.dev105 → tuieval-0.2.0.dev108}/src/tuieval/workspace.py +0 -0
- {tuieval-0.2.0.dev105 → tuieval-0.2.0.dev108}/src/tuieval/yamlout.py +0 -0
- {tuieval-0.2.0.dev105 → tuieval-0.2.0.dev108}/tests/mock_server.py +0 -0
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
## Unreleased
|
|
4
4
|
|
|
5
|
+
- The Models heading shows how many are selected, naming any the filter hides; Start asks first when some are hidden.
|
|
6
|
+
- Results → Failures: a Models button filters the list (the same pick as the other tabs), with the number of failures shown.
|
|
5
7
|
- Fix: an answer followed by a stray `</think>` (or a stray code fence after it) was graded as empty; the answer before the tag is graded now. The code grader also reads a doubled ```` ```python ```` fence as one.
|
|
6
8
|
- Run screen: `x` removes the highlighted pack from the run going if it hasn't started (the reverse of adding it); a model left with nothing isn't started.
|
|
7
9
|
- `k` (skip model) asks first, naming the model. Yes/no dialogs start on No; `y` answers yes, `n` or Esc no.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: tuieval
|
|
3
|
-
Version: 0.2.0.
|
|
3
|
+
Version: 0.2.0.dev108
|
|
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.dev108'
|
|
22
|
+
__version_tuple__ = version_tuple = (0, 2, 0, 'dev108')
|
|
23
23
|
|
|
24
24
|
__commit_id__ = commit_id = None
|
|
@@ -454,7 +454,8 @@ with the model's reasoning and answer as they stream, then recent results with t
|
|
|
454
454
|
Results open here.
|
|
455
455
|
Production readiness one verdict per model and use case; the table says why and what to run next
|
|
456
456
|
Per question every question, model by model (filters: pack, level, Models disagree)
|
|
457
|
-
Failures every wrong answer with the grader's reason; enter opens it
|
|
457
|
+
Failures every wrong answer with the grader's reason (filter: Models); enter opens it
|
|
458
|
+
in full
|
|
458
459
|
|
|
459
460
|
Click a column name to sort a table by it; click it again to reverse. Empty cells stay last.
|
|
460
461
|
|
|
@@ -775,10 +776,7 @@ class SetupScreen(Screen):
|
|
|
775
776
|
self.verdicts = {}
|
|
776
777
|
self.app.log(f"verdicts failed: {err!r}")
|
|
777
778
|
codes = group_codes(e)
|
|
778
|
-
self.
|
|
779
|
-
"[b]Models[/b] [dim][green]✓[/green] pass [red]✗[/red] fail [yellow]?[/yellow] inconclusive "
|
|
780
|
-
"grey = earlier · x hides[/dim]\n[dim]"
|
|
781
|
-
+ " ".join(f"{c} {g}" for g, c in codes.items()) + "[/dim]")
|
|
779
|
+
self.legend_codes = codes
|
|
782
780
|
n_hidden = sum(m["label"] in hidden for m in e.cfg["models"])
|
|
783
781
|
self.query_one("#show-hidden", Checkbox).label = f"Show hidden ({n_hidden})"
|
|
784
782
|
sections = {}
|
|
@@ -818,8 +816,27 @@ class SetupScreen(Screen):
|
|
|
818
816
|
at = values.index(keep) if keep in values else min(keep_at or 0, models.option_count - 1)
|
|
819
817
|
models.highlighted = min((i for i in enabled if i >= at), default=enabled[-1])
|
|
820
818
|
self.show_detail()
|
|
819
|
+
self.update_legend()
|
|
821
820
|
self.update_estimate()
|
|
822
821
|
|
|
822
|
+
def unseen_models(self):
|
|
823
|
+
"""Ticked models the list doesn't show right now (the filter leaves them out)."""
|
|
824
|
+
models = self.query_one("#models", SelectionList)
|
|
825
|
+
visible = {models.get_option_at_index(i).value for i in range(models.option_count)}
|
|
826
|
+
return [m["label"] for m in self.app.engine.cfg["models"]
|
|
827
|
+
if m["label"] in self.selected_models and m["label"] not in visible]
|
|
828
|
+
|
|
829
|
+
def update_legend(self):
|
|
830
|
+
"""The Models heading: how many are ticked (and which ones the filter hides), then the key."""
|
|
831
|
+
n, unseen = len(self.selected_models), self.unseen_models()
|
|
832
|
+
count = f"[b]{n}[/b] selected" if n else "[dim]none selected[/dim]"
|
|
833
|
+
if unseen:
|
|
834
|
+
count += f" [yellow]({len(unseen)} not shown: {rich_escape(', '.join(unseen))})[/yellow]"
|
|
835
|
+
self.query_one("#models-legend", Label).update(
|
|
836
|
+
f"[b]Models[/b] {count} [dim][green]✓[/green] pass [red]✗[/red] fail [yellow]?[/yellow] "
|
|
837
|
+
"inconclusive grey = earlier · x hides[/dim]\n[dim]"
|
|
838
|
+
+ " ".join(f"{c} {g}" for g, c in getattr(self, "legend_codes", {}).items()) + "[/dim]")
|
|
839
|
+
|
|
823
840
|
@on(SelectionList.SelectionHighlighted, "#models")
|
|
824
841
|
def show_detail(self, *_):
|
|
825
842
|
"""Everything about the highlighted model: verdicts in full, serving, per-pack results."""
|
|
@@ -893,6 +910,7 @@ class SetupScreen(Screen):
|
|
|
893
910
|
return
|
|
894
911
|
visible = {models.get_option_at_index(i).value for i in range(models.option_count)}
|
|
895
912
|
self.selected_models = (self.selected_models - visible) | set(models.selected)
|
|
913
|
+
self.update_legend()
|
|
896
914
|
self.update_estimate()
|
|
897
915
|
|
|
898
916
|
def tier(self):
|
|
@@ -1109,10 +1127,20 @@ class SetupScreen(Screen):
|
|
|
1109
1127
|
self.notify(f"Nothing to run: {item.problem}.", severity="warning")
|
|
1110
1128
|
return
|
|
1111
1129
|
self.app.start_or_queue(item)
|
|
1112
|
-
|
|
1113
|
-
|
|
1130
|
+
def asked(yes=True):
|
|
1131
|
+
if not yes:
|
|
1132
|
+
return
|
|
1133
|
+
if rows:
|
|
1134
|
+
self.app.push_screen(RetestScreen(rows, force, rerun), go)
|
|
1135
|
+
else:
|
|
1136
|
+
go({})
|
|
1137
|
+
unseen = self.unseen_models()
|
|
1138
|
+
if unseen: # ticks the filter hides are easy to forget: name them before anything starts
|
|
1139
|
+
self.app.push_screen(ConfirmScreen(
|
|
1140
|
+
f"Start {len(labels)} model(s)? {len(unseen)} of them the filter hides:\n "
|
|
1141
|
+
+ rich_escape("\n ".join(unseen) + f"\n\nAll selected: {', '.join(labels)}")), asked)
|
|
1114
1142
|
else:
|
|
1115
|
-
|
|
1143
|
+
asked()
|
|
1116
1144
|
|
|
1117
1145
|
def action_tune(self):
|
|
1118
1146
|
e = self.app.engine
|
|
@@ -2825,6 +2853,9 @@ class ResultsScreen(Screen):
|
|
|
2825
2853
|
yield Static(id="pq-legend")
|
|
2826
2854
|
yield DataTable(id="per-question", zebra_stripes=True, cursor_type="cell")
|
|
2827
2855
|
with TabPane("Failures", id="tab-failures"):
|
|
2856
|
+
with Horizontal(id="fail-controls"):
|
|
2857
|
+
yield Button("Models: all", id="fail-models")
|
|
2858
|
+
yield Static(id="fail-count")
|
|
2828
2859
|
yield Static("[dim]Enter on a row shows the whole answer, its reasoning and what was checked.[/dim]")
|
|
2829
2860
|
yield DataTable(id="failures", zebra_stripes=True, cursor_type="row")
|
|
2830
2861
|
yield Footer()
|
|
@@ -2902,12 +2933,7 @@ class ResultsScreen(Screen):
|
|
|
2902
2933
|
info.update(f"{len(paths)} {'Smoke ' if smoke else ''}result files in {os.path.relpath(results_dir)}/" + banner
|
|
2903
2934
|
+ "".join(f"\n[yellow]⚠ {n}[/yellow]" for n in notes))
|
|
2904
2935
|
self.rows, self.infos = rows, infos
|
|
2905
|
-
|
|
2906
|
-
f.add_columns("Model", "Level", "Test", "Reason")
|
|
2907
|
-
# compare.failures lists the failed rows in order, so they line up with fail_rows
|
|
2908
|
-
self.fail_rows = [r for r in rows if not r["ok"]]
|
|
2909
|
-
for i, (model, test, reason, level) in enumerate(compare.failures(rows)):
|
|
2910
|
-
f.add_row(model, diff_badge(level), rich_escape(test), rich_escape(reason[:130]), key=str(i))
|
|
2936
|
+
self.fill_failures()
|
|
2911
2937
|
self.fill_per_question()
|
|
2912
2938
|
self.fill_pta()
|
|
2913
2939
|
self.fill_readiness(results_dir)
|
|
@@ -2916,6 +2942,24 @@ class ResultsScreen(Screen):
|
|
|
2916
2942
|
self.fill_insights()
|
|
2917
2943
|
self.sort_tables()
|
|
2918
2944
|
|
|
2945
|
+
def fill_failures(self):
|
|
2946
|
+
"""Every wrong answer, of the models picked (Models: shared with the other tabs)."""
|
|
2947
|
+
f = self.query_one("#failures", DataTable)
|
|
2948
|
+
f.clear(columns=True)
|
|
2949
|
+
f.add_columns("Model", "Level", "Test", "Reason")
|
|
2950
|
+
every = {r["model"] for r in self.rows}
|
|
2951
|
+
chosen = {m for m in self.app.pq_models if m in every}
|
|
2952
|
+
rows = [r for r in self.rows if not chosen or r["model"] in chosen]
|
|
2953
|
+
# compare.failures lists the failed rows in order, so they line up with fail_rows
|
|
2954
|
+
self.fail_rows = [r for r in rows if not r["ok"]]
|
|
2955
|
+
for i, (model, test, reason, level) in enumerate(compare.failures(rows)):
|
|
2956
|
+
f.add_row(model, diff_badge(level), rich_escape(test), rich_escape(reason[:130]), key=str(i))
|
|
2957
|
+
self.query_one("#fail-models", Button).label = f"Models: {len(chosen)} picked" if chosen else "Models: all"
|
|
2958
|
+
n = len(self.fail_rows)
|
|
2959
|
+
self.query_one("#fail-count", Static).update(
|
|
2960
|
+
f"{n} failure{'s' * (n != 1)}" + (f" of {len(chosen)} model{'s' * (len(chosen) != 1)}" if chosen else ""))
|
|
2961
|
+
self.sort_table(f)
|
|
2962
|
+
|
|
2919
2963
|
@on(DataTable.RowSelected, "#failures")
|
|
2920
2964
|
def failure_selected(self, event):
|
|
2921
2965
|
# in the order shown, so [ and ] step through them as sorted
|
|
@@ -2979,6 +3023,7 @@ class ResultsScreen(Screen):
|
|
|
2979
3023
|
@on(Button.Pressed, "#pq-models")
|
|
2980
3024
|
@on(Button.Pressed, "#pta-models")
|
|
2981
3025
|
@on(Button.Pressed, "#ins-models")
|
|
3026
|
+
@on(Button.Pressed, "#fail-models")
|
|
2982
3027
|
def pick_models(self):
|
|
2983
3028
|
counts = {}
|
|
2984
3029
|
for t in getattr(self, "pq_all_tests", []):
|
|
@@ -2997,6 +3042,7 @@ class ResultsScreen(Screen):
|
|
|
2997
3042
|
# after the picker has closed: a table rebuilt under a modal keeps its header-only widths
|
|
2998
3043
|
self.call_after_refresh(self.fill_per_question)
|
|
2999
3044
|
self.call_after_refresh(self.fill_pta)
|
|
3045
|
+
self.call_after_refresh(self.fill_failures)
|
|
3000
3046
|
self.insights_stale = True
|
|
3001
3047
|
if self.query_one(TabbedContent).active == "tab-insights":
|
|
3002
3048
|
self.call_after_refresh(self.fill_insights)
|
|
@@ -3397,6 +3443,9 @@ class EvalsApp(App):
|
|
|
3397
3443
|
#pq-controls Checkbox { width: auto; }
|
|
3398
3444
|
#pq-controls Select { width: 22; margin-right: 1; }
|
|
3399
3445
|
#pq-models { margin-right: 1; min-width: 20; }
|
|
3446
|
+
#fail-controls { height: 3; }
|
|
3447
|
+
#fail-models { margin-right: 1; min-width: 20; }
|
|
3448
|
+
#fail-count { width: auto; padding: 1 1; }
|
|
3400
3449
|
#pq-compare-title { padding: 0 1; height: auto; }
|
|
3401
3450
|
#pq-summary { height: auto; } /* every picked model, no scrolling: the tab scrolls instead */
|
|
3402
3451
|
#pq-legend { padding: 0 1; height: auto; }
|
|
@@ -1130,6 +1130,47 @@ class AddToRun(unittest.TestCase):
|
|
|
1130
1130
|
self.assertEqual(fewer, 4) # its 4 questions are no longer counted
|
|
1131
1131
|
self.assertEqual(out["running"], [False, True])
|
|
1132
1132
|
|
|
1133
|
+
def test_tui_counts_ticked_models_and_names_filtered_ones_before_start(self):
|
|
1134
|
+
code = textwrap.dedent("""
|
|
1135
|
+
import asyncio, json
|
|
1136
|
+
from tuieval.tui import EvalsApp, ConfirmScreen
|
|
1137
|
+
from textual.widgets import SelectionList, Input, Label
|
|
1138
|
+
async def go():
|
|
1139
|
+
app = EvalsApp({})
|
|
1140
|
+
async with app.run_test(size=(160, 50)) as pilot:
|
|
1141
|
+
await pilot.pause()
|
|
1142
|
+
s, out = app.screen, {}
|
|
1143
|
+
legend = lambda: str(s.query_one("#models-legend", Label).render())
|
|
1144
|
+
out["none"] = legend()
|
|
1145
|
+
s.query_one("#suites", SelectionList).select("apps")
|
|
1146
|
+
models = s.query_one("#models", SelectionList)
|
|
1147
|
+
models.select("a")
|
|
1148
|
+
models.select("b")
|
|
1149
|
+
await pilot.pause()
|
|
1150
|
+
out["two"] = legend()
|
|
1151
|
+
s.query_one("#filter", Input).value = "zzz-nothing"
|
|
1152
|
+
await pilot.pause()
|
|
1153
|
+
out["filtered"] = legend()
|
|
1154
|
+
s.action_start()
|
|
1155
|
+
await pilot.pause()
|
|
1156
|
+
out["asked"] = isinstance(app.screen, ConfirmScreen) and str(app.screen.question)
|
|
1157
|
+
await pilot.press("n")
|
|
1158
|
+
await pilot.pause()
|
|
1159
|
+
out["cancelled"] = app.screen is s and not app.is_busy()
|
|
1160
|
+
print(json.dumps(out))
|
|
1161
|
+
asyncio.run(go())
|
|
1162
|
+
""")
|
|
1163
|
+
p = subprocess.run([sys.executable, "-c", code], capture_output=True, text=True, timeout=600,
|
|
1164
|
+
env=dict(os.environ, TUIEVAL_HOME=self.ws, TUIEVAL_DETECT_PORTS=""))
|
|
1165
|
+
out = json.loads(p.stdout.strip().splitlines()[-1]) if p.stdout.strip() else p.stderr
|
|
1166
|
+
self.assertIsInstance(out, dict, out)
|
|
1167
|
+
self.assertIn("none selected", out["none"])
|
|
1168
|
+
self.assertIn("2 selected", out["two"])
|
|
1169
|
+
self.assertNotIn("not shown", out["two"])
|
|
1170
|
+
self.assertIn("2 not shown: a, b", out["filtered"])
|
|
1171
|
+
self.assertIn("All selected: a, b", out["asked"])
|
|
1172
|
+
self.assertTrue(out["cancelled"])
|
|
1173
|
+
|
|
1133
1174
|
def test_tui_asks_before_skipping_a_model(self):
|
|
1134
1175
|
path = os.path.join(self.ws, "models.toml")
|
|
1135
1176
|
write(path, read(path).replace('"--delay", "0.2"', '"--delay", "3"')) # still running while it's asked
|
|
@@ -1571,6 +1612,17 @@ class PTAIndex(unittest.TestCase):
|
|
|
1571
1612
|
app.screen.query_one(TabbedContent).active = "tab-failures"
|
|
1572
1613
|
await pilot.pause(0.3)
|
|
1573
1614
|
f = app.screen.query_one("#failures", DataTable)
|
|
1615
|
+
count = lambda: str(app.screen.query_one("#fail-count", Static).render())
|
|
1616
|
+
fails = {"all": [f.row_count, count()]}
|
|
1617
|
+
for m in ("good", "hosted"): # Models: only that model's failures
|
|
1618
|
+
app.pq_models = {m}
|
|
1619
|
+
app.screen.fill_failures()
|
|
1620
|
+
await pilot.pause(0.2)
|
|
1621
|
+
fails[m] = [f.row_count, count(), str(app.screen.query_one("#fail-models").label),
|
|
1622
|
+
sorted({str(f.get_row_at(r)[0]) for r in range(f.row_count)})]
|
|
1623
|
+
app.pq_models = set()
|
|
1624
|
+
app.screen.fill_failures()
|
|
1625
|
+
await pilot.pause(0.2)
|
|
1574
1626
|
await click_header(f, "Test")
|
|
1575
1627
|
sorts["tests"], _ = await click_header(f, "Test")
|
|
1576
1628
|
sorts["tests"] = [str(f.get_row_at(r)[2]) for r in range(f.row_count)]
|
|
@@ -1581,7 +1633,7 @@ class PTAIndex(unittest.TestCase):
|
|
|
1581
1633
|
s = app.screen
|
|
1582
1634
|
sorts["opened"] = s.entries[s.index]["record"]["test"]
|
|
1583
1635
|
print(json.dumps({"rows": rows, "bars": "P parsimony" in tri, "disagree": [both, alone],
|
|
1584
|
-
"tab": tab, "sorts": sorts}))
|
|
1636
|
+
"tab": tab, "sorts": sorts, "fails": fails}))
|
|
1585
1637
|
asyncio.run(go())
|
|
1586
1638
|
""")
|
|
1587
1639
|
p = subprocess.run([sys.executable, "-c", code], capture_output=True, text=True, timeout=300,
|
|
@@ -1596,6 +1648,10 @@ class PTAIndex(unittest.TestCase):
|
|
|
1596
1648
|
self.assertEqual((s["up"], s["down"], s["kept"]), (["hosted", "good"], ["good", "hosted"], ["good", "hosted"]))
|
|
1597
1649
|
self.assertIn("answers right ▼", s["labels"])
|
|
1598
1650
|
self.assertEqual((s["tests"][0], s["opened"]), ("apps: d", "d"))
|
|
1651
|
+
fails = got["fails"]
|
|
1652
|
+
self.assertEqual(fails["all"], [4, "4 failures"])
|
|
1653
|
+
self.assertEqual(fails["good"], [0, "0 failures of 1 model", "Models: 1 picked", []])
|
|
1654
|
+
self.assertEqual(fails["hosted"], [4, "4 failures of 1 model", "Models: 1 picked", ["hosted"]])
|
|
1599
1655
|
|
|
1600
1656
|
|
|
1601
1657
|
class Unavailable(unittest.TestCase):
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{tuieval-0.2.0.dev105 → tuieval-0.2.0.dev108}/src/tuieval/templates/packs/tool_call/pack.toml
RENAMED
|
File without changes
|
{tuieval-0.2.0.dev105 → tuieval-0.2.0.dev108}/src/tuieval/templates/packs/tool_call/system.txt
RENAMED
|
File without changes
|
{tuieval-0.2.0.dev105 → tuieval-0.2.0.dev108}/src/tuieval/templates/packs/tool_call/tests.yaml
RENAMED
|
File without changes
|
{tuieval-0.2.0.dev105 → tuieval-0.2.0.dev108}/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
|