tuieval 0.2.0.dev74__tar.gz → 0.2.0.dev75__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.
Files changed (78) hide show
  1. {tuieval-0.2.0.dev74 → tuieval-0.2.0.dev75}/CHANGELOG.md +1 -0
  2. {tuieval-0.2.0.dev74 → tuieval-0.2.0.dev75}/PKG-INFO +1 -1
  3. {tuieval-0.2.0.dev74 → tuieval-0.2.0.dev75}/src/tuieval/_version.py +2 -2
  4. {tuieval-0.2.0.dev74 → tuieval-0.2.0.dev75}/src/tuieval/tui.py +7 -6
  5. {tuieval-0.2.0.dev74 → tuieval-0.2.0.dev75}/tests/test_tuieval.py +50 -0
  6. {tuieval-0.2.0.dev74 → tuieval-0.2.0.dev75}/.gitignore +0 -0
  7. {tuieval-0.2.0.dev74 → tuieval-0.2.0.dev75}/LICENSE +0 -0
  8. {tuieval-0.2.0.dev74 → tuieval-0.2.0.dev75}/README.md +0 -0
  9. {tuieval-0.2.0.dev74 → tuieval-0.2.0.dev75}/RELEASING.md +0 -0
  10. {tuieval-0.2.0.dev74 → tuieval-0.2.0.dev75}/docs/images/brand/README.md +0 -0
  11. {tuieval-0.2.0.dev74 → tuieval-0.2.0.dev75}/docs/images/brand/favicon.ico +0 -0
  12. {tuieval-0.2.0.dev74 → tuieval-0.2.0.dev75}/docs/images/brand/readme-header.png +0 -0
  13. {tuieval-0.2.0.dev74 → tuieval-0.2.0.dev75}/docs/images/brand/social-preview.png +0 -0
  14. {tuieval-0.2.0.dev74 → tuieval-0.2.0.dev75}/docs/images/brand/tuieval-icon-1024.png +0 -0
  15. {tuieval-0.2.0.dev74 → tuieval-0.2.0.dev75}/docs/images/brand/tuieval-icon-128.png +0 -0
  16. {tuieval-0.2.0.dev74 → tuieval-0.2.0.dev75}/docs/images/brand/tuieval-icon-16.png +0 -0
  17. {tuieval-0.2.0.dev74 → tuieval-0.2.0.dev75}/docs/images/brand/tuieval-icon-16.svg +0 -0
  18. {tuieval-0.2.0.dev74 → tuieval-0.2.0.dev75}/docs/images/brand/tuieval-icon-256.png +0 -0
  19. {tuieval-0.2.0.dev74 → tuieval-0.2.0.dev75}/docs/images/brand/tuieval-icon-32.png +0 -0
  20. {tuieval-0.2.0.dev74 → tuieval-0.2.0.dev75}/docs/images/brand/tuieval-icon-48.png +0 -0
  21. {tuieval-0.2.0.dev74 → tuieval-0.2.0.dev75}/docs/images/brand/tuieval-icon-512.png +0 -0
  22. {tuieval-0.2.0.dev74 → tuieval-0.2.0.dev75}/docs/images/brand/tuieval-icon-64.png +0 -0
  23. {tuieval-0.2.0.dev74 → tuieval-0.2.0.dev75}/docs/images/brand/tuieval-icon-animated.svg +0 -0
  24. {tuieval-0.2.0.dev74 → tuieval-0.2.0.dev75}/docs/images/brand/tuieval-icon.svg +0 -0
  25. {tuieval-0.2.0.dev74 → tuieval-0.2.0.dev75}/docs/images/tui-answer-reasoning.png +0 -0
  26. {tuieval-0.2.0.dev74 → tuieval-0.2.0.dev75}/docs/images/tui-run-reasoning.png +0 -0
  27. {tuieval-0.2.0.dev74 → tuieval-0.2.0.dev75}/docs/images/tui-setup.png +0 -0
  28. {tuieval-0.2.0.dev74 → tuieval-0.2.0.dev75}/docs/models.md +0 -0
  29. {tuieval-0.2.0.dev74 → tuieval-0.2.0.dev75}/docs/writing-packs.md +0 -0
  30. {tuieval-0.2.0.dev74 → tuieval-0.2.0.dev75}/pyproject.toml +0 -0
  31. {tuieval-0.2.0.dev74 → tuieval-0.2.0.dev75}/src/tuieval/__init__.py +0 -0
  32. {tuieval-0.2.0.dev74 → tuieval-0.2.0.dev75}/src/tuieval/__main__.py +0 -0
  33. {tuieval-0.2.0.dev74 → tuieval-0.2.0.dev75}/src/tuieval/builtin.toml +0 -0
  34. {tuieval-0.2.0.dev74 → tuieval-0.2.0.dev75}/src/tuieval/cli.py +0 -0
  35. {tuieval-0.2.0.dev74 → tuieval-0.2.0.dev75}/src/tuieval/client.py +0 -0
  36. {tuieval-0.2.0.dev74 → tuieval-0.2.0.dev75}/src/tuieval/compare.py +0 -0
  37. {tuieval-0.2.0.dev74 → tuieval-0.2.0.dev75}/src/tuieval/doctor.py +0 -0
  38. {tuieval-0.2.0.dev74 → tuieval-0.2.0.dev75}/src/tuieval/engine.py +0 -0
  39. {tuieval-0.2.0.dev74 → tuieval-0.2.0.dev75}/src/tuieval/export.py +0 -0
  40. {tuieval-0.2.0.dev74 → tuieval-0.2.0.dev75}/src/tuieval/graders/__init__.py +0 -0
  41. {tuieval-0.2.0.dev74 → tuieval-0.2.0.dev75}/src/tuieval/graders/answer.py +0 -0
  42. {tuieval-0.2.0.dev74 → tuieval-0.2.0.dev75}/src/tuieval/graders/code.py +0 -0
  43. {tuieval-0.2.0.dev74 → tuieval-0.2.0.dev75}/src/tuieval/graders/rag.py +0 -0
  44. {tuieval-0.2.0.dev74 → tuieval-0.2.0.dev75}/src/tuieval/graders/reply.py +0 -0
  45. {tuieval-0.2.0.dev74 → tuieval-0.2.0.dev75}/src/tuieval/graders/tool_call.py +0 -0
  46. {tuieval-0.2.0.dev74 → tuieval-0.2.0.dev75}/src/tuieval/logs.py +0 -0
  47. {tuieval-0.2.0.dev74 → tuieval-0.2.0.dev75}/src/tuieval/machines.py +0 -0
  48. {tuieval-0.2.0.dev74 → tuieval-0.2.0.dev75}/src/tuieval/onboard.py +0 -0
  49. {tuieval-0.2.0.dev74 → tuieval-0.2.0.dev75}/src/tuieval/packs.py +0 -0
  50. {tuieval-0.2.0.dev74 → tuieval-0.2.0.dev75}/src/tuieval/profiles.py +0 -0
  51. {tuieval-0.2.0.dev74 → tuieval-0.2.0.dev75}/src/tuieval/pta.py +0 -0
  52. {tuieval-0.2.0.dev74 → tuieval-0.2.0.dev75}/src/tuieval/remove.py +0 -0
  53. {tuieval-0.2.0.dev74 → tuieval-0.2.0.dev75}/src/tuieval/run_evals.py +0 -0
  54. {tuieval-0.2.0.dev74 → tuieval-0.2.0.dev75}/src/tuieval/scaffold.py +0 -0
  55. {tuieval-0.2.0.dev74 → tuieval-0.2.0.dev75}/src/tuieval/selftest.py +0 -0
  56. {tuieval-0.2.0.dev74 → tuieval-0.2.0.dev75}/src/tuieval/templates/models.toml +0 -0
  57. {tuieval-0.2.0.dev74 → tuieval-0.2.0.dev75}/src/tuieval/templates/packs/answer/pack.toml +0 -0
  58. {tuieval-0.2.0.dev74 → tuieval-0.2.0.dev75}/src/tuieval/templates/packs/answer/system.txt +0 -0
  59. {tuieval-0.2.0.dev74 → tuieval-0.2.0.dev75}/src/tuieval/templates/packs/answer/tests.yaml +0 -0
  60. {tuieval-0.2.0.dev74 → tuieval-0.2.0.dev75}/src/tuieval/templates/packs/code/pack.toml +0 -0
  61. {tuieval-0.2.0.dev74 → tuieval-0.2.0.dev75}/src/tuieval/templates/packs/code/system.txt +0 -0
  62. {tuieval-0.2.0.dev74 → tuieval-0.2.0.dev75}/src/tuieval/templates/packs/code/tests.yaml +0 -0
  63. {tuieval-0.2.0.dev74 → tuieval-0.2.0.dev75}/src/tuieval/templates/packs/rag/pack.toml +0 -0
  64. {tuieval-0.2.0.dev74 → tuieval-0.2.0.dev75}/src/tuieval/templates/packs/rag/system.txt +0 -0
  65. {tuieval-0.2.0.dev74 → tuieval-0.2.0.dev75}/src/tuieval/templates/packs/rag/tests.yaml +0 -0
  66. {tuieval-0.2.0.dev74 → tuieval-0.2.0.dev75}/src/tuieval/templates/packs/reply/pack.toml +0 -0
  67. {tuieval-0.2.0.dev74 → tuieval-0.2.0.dev75}/src/tuieval/templates/packs/reply/system.txt +0 -0
  68. {tuieval-0.2.0.dev74 → tuieval-0.2.0.dev75}/src/tuieval/templates/packs/reply/tests.yaml +0 -0
  69. {tuieval-0.2.0.dev74 → tuieval-0.2.0.dev75}/src/tuieval/templates/packs/tool_call/pack.toml +0 -0
  70. {tuieval-0.2.0.dev74 → tuieval-0.2.0.dev75}/src/tuieval/templates/packs/tool_call/system.txt +0 -0
  71. {tuieval-0.2.0.dev74 → tuieval-0.2.0.dev75}/src/tuieval/templates/packs/tool_call/tests.yaml +0 -0
  72. {tuieval-0.2.0.dev74 → tuieval-0.2.0.dev75}/src/tuieval/templates/packs/tool_call/tools.yaml +0 -0
  73. {tuieval-0.2.0.dev74 → tuieval-0.2.0.dev75}/src/tuieval/tune.py +0 -0
  74. {tuieval-0.2.0.dev74 → tuieval-0.2.0.dev75}/src/tuieval/verdict.py +0 -0
  75. {tuieval-0.2.0.dev74 → tuieval-0.2.0.dev75}/src/tuieval/watch_proxy.py +0 -0
  76. {tuieval-0.2.0.dev74 → tuieval-0.2.0.dev75}/src/tuieval/workspace.py +0 -0
  77. {tuieval-0.2.0.dev74 → tuieval-0.2.0.dev75}/src/tuieval/yamlout.py +0 -0
  78. {tuieval-0.2.0.dev74 → tuieval-0.2.0.dev75}/tests/mock_server.py +0 -0
@@ -2,6 +2,7 @@
2
2
 
3
3
  ## Unreleased
4
4
 
5
+ - Fix: a question description or grader reason containing `[` no longer crashes the run screen.
5
6
  - Retest asks per pack before it starts: from zero, continue or leave out. It now really starts from zero, and replaced smoke results go to history/.
6
7
  - Retest: the setup checkbox "Rerun existing results" is now "Retest (ask again, even if already answered)", and `tuieval run --retest` is the same (`--force` still works).
7
8
  - `tuieval logs` follows the server log of the model running now and moves on with the run; `logs live` shows each answer as it finishes, `--list` every log.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: tuieval
3
- Version: 0.2.0.dev74
3
+ Version: 0.2.0.dev75
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.dev74'
22
- __version_tuple__ = version_tuple = (0, 2, 0, 'dev74')
21
+ __version__ = version = '0.2.0.dev75'
22
+ __version_tuple__ = version_tuple = (0, 2, 0, 'dev75')
23
23
 
24
24
  __commit_id__ = commit_id = None
@@ -2239,9 +2239,10 @@ class RunScreen(Screen):
2239
2239
  self.req_started, self.req_tokens, self.req_first = time.time(), 0, None
2240
2240
  job = d["job"]
2241
2241
  rep_note = f" · repeat {d['repeat'] + 1}/{job.repeat}" if job.repeat > 1 else ""
2242
- self.current = (f"[b]{job.label}[/b] · {job.pack.label} · test {job.done + 1}/{job.total}{rep_note}"
2242
+ self.current = (f"[b]{rich_escape(job.label)}[/b] · {rich_escape(job.pack.label)} · test "
2243
+ f"{job.done + 1}/{job.total}{rep_note}"
2243
2244
  f"{' [magenta]🖼 image[/magenta]' if d['has_image'] else ''}\n"
2244
- f"{diff_badge(d.get('difficulty', 'unrated'))} {d['test']}")
2245
+ f"{diff_badge(d.get('difficulty', 'unrated'))} {rich_escape(d['test'])}")
2245
2246
  elif kind == "request_done":
2246
2247
  if self.watched(kind, d):
2247
2248
  self.flush_streams()
@@ -2251,12 +2252,12 @@ class RunScreen(Screen):
2251
2252
  # follow new rows unless you're browsing an older one
2252
2253
  at_end = not recent.has_focus or recent.cursor_row >= recent.row_count - 1
2253
2254
  calls = f" [cyan]→ {r['tool_calls'][0]['name']}()[/cyan]" if r.get("tool_calls") else ""
2254
- row_key = recent.add_row(mark, diff_badge(r.get("difficulty", "unrated")), r["description"][:50], job.label,
2255
+ row_key = recent.add_row(mark, diff_badge(r.get("difficulty", "unrated")), rich_escape(r["description"][:50]), job.label,
2255
2256
  str(r.get("completion_tokens") or ""),
2256
2257
  (f"{r['ttft_s']:.1f}" + (" ⟲" if r.get("cached_tokens") else ""))
2257
2258
  if r.get("ttft_s") is not None else "",
2258
2259
  f"{r['gen_tps']:.0f}" if r.get("gen_tps") else "", f"{r['total_s']:.0f}",
2259
- r["reason"][:90] + calls
2260
+ rich_escape(r["reason"][:90]) + calls
2260
2261
  + (f" [red]copy of repeat {r['identical_to_repeat'] + 1}[/red]"
2261
2262
  if r.get("identical_to_repeat") is not None else ""))
2262
2263
  self.stats.append(r)
@@ -2364,7 +2365,7 @@ class RunScreen(Screen):
2364
2365
  self.event("[bold yellow]REUSE[/bold yellow] " + msg)
2365
2366
  self.notify(msg, severity="warning", timeout=20)
2366
2367
  elif kind == "identical_answer":
2367
- msg = (f"{d['label']} · {d['pack']} · {d['test']}: repeat {d['repeat'] + 1} is an exact copy of repeat "
2368
+ msg = (f"{d['label']} · {d['pack']} · {rich_escape(d['test'])}: repeat {d['repeat'] + 1} is an exact copy of repeat "
2368
2369
  f"{d['same'] + 1}, so the server may be returning cached answers rather than fresh ones.")
2369
2370
  self.event("[bold red]COPY[/bold red] " + msg)
2370
2371
  self.notify(msg, severity="error", timeout=20)
@@ -2711,7 +2712,7 @@ class ResultsScreen(Screen):
2711
2712
  # compare.failures lists the failed rows in order, so they line up with fail_rows
2712
2713
  self.fail_rows = [r for r in rows if not r["ok"]]
2713
2714
  for i, (model, test, reason, level) in enumerate(compare.failures(rows)):
2714
- f.add_row(model, diff_badge(level), test, rich_escape(reason[:130]), key=str(i))
2715
+ f.add_row(model, diff_badge(level), rich_escape(test), rich_escape(reason[:130]), key=str(i))
2715
2716
  self.fill_per_question()
2716
2717
  self.fill_pta()
2717
2718
  self.fill_readiness(results_dir)
@@ -735,6 +735,56 @@ class Parallel(unittest.TestCase):
735
735
  self.assertEqual(sum(r["pass"] for r in self.results("b")["results"]), 6)
736
736
 
737
737
 
738
+ class MarkupInText(unittest.TestCase):
739
+ """Brackets in a description or a grader's reason are shown as text: an unmatched
740
+ "[" once crashed the run screen (it swallowed the "[dim]" of the line after it)."""
741
+
742
+ def test_run_screen_shows_brackets(self):
743
+ with tempfile.TemporaryDirectory() as tmp:
744
+ ws = os.path.join(tmp, "ws")
745
+ tuieval(tmp, "init", ws)
746
+ d = os.path.join(ws, "packs", "br")
747
+ os.makedirs(d)
748
+ write(os.path.join(d, "pack.toml"), 'label = "Brackets"\n[certify]\nrepeat = 1\n[gate]\nmin_accuracy = 0.1\n')
749
+ write(os.path.join(d, "tests.yaml"),
750
+ "- {id: a, description: 'notional in [t - 10 s, t), excluding ties', input: q a, expected: 1, "
751
+ "reference: 'ANSWER: 1', wrong: ['ANSWER: [2'], difficulty: hard}\n"
752
+ "- {id: b, description: 'window [a, b) then [/dim] text', input: q b, expected: 1, "
753
+ "reference: 'ANSWER: 1', wrong: ['ANSWER: [2'], difficulty: hard}\n")
754
+ mock = [sys.executable, os.path.join(HERE, "mock_server.py"), "--port", "{port}", "--packs",
755
+ os.path.join(ws, "packs"), "--model", "{served_name}", "--mode", "wrong", "--delay", "0.2"]
756
+ with open(os.path.join(ws, "models.toml"), "a") as f:
757
+ f.write(f'\n[servers.mk]\ncmd = {json.dumps(mock)}\nport = {free_port()}\n'
758
+ '\n[[models]]\nlabel = "m"\nserver = "mk"\nmodel = "m"\n')
759
+ code = textwrap.dedent("""
760
+ import asyncio, json, time
761
+ from tuieval.tui import EvalsApp, RunScreen
762
+ from textual.widgets import SelectionList
763
+ async def go():
764
+ app = EvalsApp({})
765
+ async with app.run_test(size=(160, 50)) as pilot:
766
+ await pilot.pause()
767
+ s = app.screen
768
+ s.query_one("#suites", SelectionList).select("br")
769
+ s.selected_models = {"m"}
770
+ s.refresh_models()
771
+ s.query_one("#tier-certify").value = True
772
+ await pilot.pause()
773
+ s.action_start()
774
+ deadline = time.time() + 240
775
+ while time.time() < deadline:
776
+ await pilot.pause(0.2)
777
+ if isinstance(app.screen, RunScreen) and not app.screen.running:
778
+ break
779
+ print(json.dumps([(j.key, j.status, j.done) for j in app.screen.jobs]))
780
+ asyncio.run(go())
781
+ """)
782
+ p = subprocess.run([sys.executable, "-c", code], capture_output=True, text=True, timeout=480,
783
+ env=dict(os.environ, TUIEVAL_HOME=ws, TUIEVAL_DETECT_PORTS=""))
784
+ self.assertNotIn("MarkupError", p.stderr + p.stdout)
785
+ self.assertEqual(json.loads(p.stdout.strip().splitlines()[-1]), [["m/br", "done", 2]], p.stderr[-2000:])
786
+
787
+
738
788
  class AddToRun(unittest.TestCase):
739
789
  """More evals while a run is going: added to it (they run after its other jobs) or queued after it."""
740
790
 
File without changes
File without changes
File without changes