tuieval 0.2.0.dev33__tar.gz → 0.2.0.dev35__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.dev33 → tuieval-0.2.0.dev35}/PKG-INFO +1 -1
- {tuieval-0.2.0.dev33 → tuieval-0.2.0.dev35}/src/tuieval/_version.py +2 -2
- {tuieval-0.2.0.dev33 → tuieval-0.2.0.dev35}/src/tuieval/tui.py +24 -8
- {tuieval-0.2.0.dev33 → tuieval-0.2.0.dev35}/tests/test_tuieval.py +58 -0
- {tuieval-0.2.0.dev33 → tuieval-0.2.0.dev35}/.gitignore +0 -0
- {tuieval-0.2.0.dev33 → tuieval-0.2.0.dev35}/CHANGELOG.md +0 -0
- {tuieval-0.2.0.dev33 → tuieval-0.2.0.dev35}/LICENSE +0 -0
- {tuieval-0.2.0.dev33 → tuieval-0.2.0.dev35}/README.md +0 -0
- {tuieval-0.2.0.dev33 → tuieval-0.2.0.dev35}/RELEASING.md +0 -0
- {tuieval-0.2.0.dev33 → tuieval-0.2.0.dev35}/docs/images/brand/README.md +0 -0
- {tuieval-0.2.0.dev33 → tuieval-0.2.0.dev35}/docs/images/brand/favicon.ico +0 -0
- {tuieval-0.2.0.dev33 → tuieval-0.2.0.dev35}/docs/images/brand/readme-header.png +0 -0
- {tuieval-0.2.0.dev33 → tuieval-0.2.0.dev35}/docs/images/brand/social-preview.png +0 -0
- {tuieval-0.2.0.dev33 → tuieval-0.2.0.dev35}/docs/images/brand/tuieval-icon-1024.png +0 -0
- {tuieval-0.2.0.dev33 → tuieval-0.2.0.dev35}/docs/images/brand/tuieval-icon-128.png +0 -0
- {tuieval-0.2.0.dev33 → tuieval-0.2.0.dev35}/docs/images/brand/tuieval-icon-16.png +0 -0
- {tuieval-0.2.0.dev33 → tuieval-0.2.0.dev35}/docs/images/brand/tuieval-icon-16.svg +0 -0
- {tuieval-0.2.0.dev33 → tuieval-0.2.0.dev35}/docs/images/brand/tuieval-icon-256.png +0 -0
- {tuieval-0.2.0.dev33 → tuieval-0.2.0.dev35}/docs/images/brand/tuieval-icon-32.png +0 -0
- {tuieval-0.2.0.dev33 → tuieval-0.2.0.dev35}/docs/images/brand/tuieval-icon-48.png +0 -0
- {tuieval-0.2.0.dev33 → tuieval-0.2.0.dev35}/docs/images/brand/tuieval-icon-512.png +0 -0
- {tuieval-0.2.0.dev33 → tuieval-0.2.0.dev35}/docs/images/brand/tuieval-icon-64.png +0 -0
- {tuieval-0.2.0.dev33 → tuieval-0.2.0.dev35}/docs/images/brand/tuieval-icon-animated.svg +0 -0
- {tuieval-0.2.0.dev33 → tuieval-0.2.0.dev35}/docs/images/brand/tuieval-icon.svg +0 -0
- {tuieval-0.2.0.dev33 → tuieval-0.2.0.dev35}/docs/images/tui-setup.png +0 -0
- {tuieval-0.2.0.dev33 → tuieval-0.2.0.dev35}/docs/models.md +0 -0
- {tuieval-0.2.0.dev33 → tuieval-0.2.0.dev35}/docs/writing-packs.md +0 -0
- {tuieval-0.2.0.dev33 → tuieval-0.2.0.dev35}/pyproject.toml +0 -0
- {tuieval-0.2.0.dev33 → tuieval-0.2.0.dev35}/src/tuieval/__init__.py +0 -0
- {tuieval-0.2.0.dev33 → tuieval-0.2.0.dev35}/src/tuieval/__main__.py +0 -0
- {tuieval-0.2.0.dev33 → tuieval-0.2.0.dev35}/src/tuieval/builtin.toml +0 -0
- {tuieval-0.2.0.dev33 → tuieval-0.2.0.dev35}/src/tuieval/cli.py +0 -0
- {tuieval-0.2.0.dev33 → tuieval-0.2.0.dev35}/src/tuieval/client.py +0 -0
- {tuieval-0.2.0.dev33 → tuieval-0.2.0.dev35}/src/tuieval/compare.py +0 -0
- {tuieval-0.2.0.dev33 → tuieval-0.2.0.dev35}/src/tuieval/doctor.py +0 -0
- {tuieval-0.2.0.dev33 → tuieval-0.2.0.dev35}/src/tuieval/engine.py +0 -0
- {tuieval-0.2.0.dev33 → tuieval-0.2.0.dev35}/src/tuieval/export.py +0 -0
- {tuieval-0.2.0.dev33 → tuieval-0.2.0.dev35}/src/tuieval/graders/__init__.py +0 -0
- {tuieval-0.2.0.dev33 → tuieval-0.2.0.dev35}/src/tuieval/graders/answer.py +0 -0
- {tuieval-0.2.0.dev33 → tuieval-0.2.0.dev35}/src/tuieval/graders/code.py +0 -0
- {tuieval-0.2.0.dev33 → tuieval-0.2.0.dev35}/src/tuieval/graders/rag.py +0 -0
- {tuieval-0.2.0.dev33 → tuieval-0.2.0.dev35}/src/tuieval/graders/reply.py +0 -0
- {tuieval-0.2.0.dev33 → tuieval-0.2.0.dev35}/src/tuieval/graders/tool_call.py +0 -0
- {tuieval-0.2.0.dev33 → tuieval-0.2.0.dev35}/src/tuieval/machines.py +0 -0
- {tuieval-0.2.0.dev33 → tuieval-0.2.0.dev35}/src/tuieval/onboard.py +0 -0
- {tuieval-0.2.0.dev33 → tuieval-0.2.0.dev35}/src/tuieval/packs.py +0 -0
- {tuieval-0.2.0.dev33 → tuieval-0.2.0.dev35}/src/tuieval/profiles.py +0 -0
- {tuieval-0.2.0.dev33 → tuieval-0.2.0.dev35}/src/tuieval/remove.py +0 -0
- {tuieval-0.2.0.dev33 → tuieval-0.2.0.dev35}/src/tuieval/run_evals.py +0 -0
- {tuieval-0.2.0.dev33 → tuieval-0.2.0.dev35}/src/tuieval/scaffold.py +0 -0
- {tuieval-0.2.0.dev33 → tuieval-0.2.0.dev35}/src/tuieval/selftest.py +0 -0
- {tuieval-0.2.0.dev33 → tuieval-0.2.0.dev35}/src/tuieval/templates/models.toml +0 -0
- {tuieval-0.2.0.dev33 → tuieval-0.2.0.dev35}/src/tuieval/templates/packs/answer/pack.toml +0 -0
- {tuieval-0.2.0.dev33 → tuieval-0.2.0.dev35}/src/tuieval/templates/packs/answer/system.txt +0 -0
- {tuieval-0.2.0.dev33 → tuieval-0.2.0.dev35}/src/tuieval/templates/packs/answer/tests.yaml +0 -0
- {tuieval-0.2.0.dev33 → tuieval-0.2.0.dev35}/src/tuieval/templates/packs/code/pack.toml +0 -0
- {tuieval-0.2.0.dev33 → tuieval-0.2.0.dev35}/src/tuieval/templates/packs/code/system.txt +0 -0
- {tuieval-0.2.0.dev33 → tuieval-0.2.0.dev35}/src/tuieval/templates/packs/code/tests.yaml +0 -0
- {tuieval-0.2.0.dev33 → tuieval-0.2.0.dev35}/src/tuieval/templates/packs/rag/pack.toml +0 -0
- {tuieval-0.2.0.dev33 → tuieval-0.2.0.dev35}/src/tuieval/templates/packs/rag/system.txt +0 -0
- {tuieval-0.2.0.dev33 → tuieval-0.2.0.dev35}/src/tuieval/templates/packs/rag/tests.yaml +0 -0
- {tuieval-0.2.0.dev33 → tuieval-0.2.0.dev35}/src/tuieval/templates/packs/reply/pack.toml +0 -0
- {tuieval-0.2.0.dev33 → tuieval-0.2.0.dev35}/src/tuieval/templates/packs/reply/system.txt +0 -0
- {tuieval-0.2.0.dev33 → tuieval-0.2.0.dev35}/src/tuieval/templates/packs/reply/tests.yaml +0 -0
- {tuieval-0.2.0.dev33 → tuieval-0.2.0.dev35}/src/tuieval/templates/packs/tool_call/pack.toml +0 -0
- {tuieval-0.2.0.dev33 → tuieval-0.2.0.dev35}/src/tuieval/templates/packs/tool_call/system.txt +0 -0
- {tuieval-0.2.0.dev33 → tuieval-0.2.0.dev35}/src/tuieval/templates/packs/tool_call/tests.yaml +0 -0
- {tuieval-0.2.0.dev33 → tuieval-0.2.0.dev35}/src/tuieval/templates/packs/tool_call/tools.yaml +0 -0
- {tuieval-0.2.0.dev33 → tuieval-0.2.0.dev35}/src/tuieval/tune.py +0 -0
- {tuieval-0.2.0.dev33 → tuieval-0.2.0.dev35}/src/tuieval/verdict.py +0 -0
- {tuieval-0.2.0.dev33 → tuieval-0.2.0.dev35}/src/tuieval/watch_proxy.py +0 -0
- {tuieval-0.2.0.dev33 → tuieval-0.2.0.dev35}/src/tuieval/workspace.py +0 -0
- {tuieval-0.2.0.dev33 → tuieval-0.2.0.dev35}/src/tuieval/yamlout.py +0 -0
- {tuieval-0.2.0.dev33 → tuieval-0.2.0.dev35}/tests/mock_server.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: tuieval
|
|
3
|
-
Version: 0.2.0.
|
|
3
|
+
Version: 0.2.0.dev35
|
|
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.dev35'
|
|
22
|
+
__version_tuple__ = version_tuple = (0, 2, 0, 'dev35')
|
|
23
23
|
|
|
24
24
|
__commit_id__ = commit_id = None
|
|
@@ -10,9 +10,10 @@ Run screen: live reasoning and answer, per-test ✓/✗, TTFT and tokens/s, p
|
|
|
10
10
|
k skips the current model, c cancels everything, f pauses auto-scroll.
|
|
11
11
|
r shows results at any time (also mid-run); n starts a new run when it ends.
|
|
12
12
|
Enter on a Recent results row shows that answer in full.
|
|
13
|
-
Results:
|
|
14
|
-
|
|
15
|
-
Per question cell shows the answer: grading and checks, reasoning,
|
|
13
|
+
Results: opens on Per question, which compares each model's tokens and seconds on the same
|
|
14
|
+
question. ctrl+r reloads (it also reloads when a run's pack finishes). Enter on a
|
|
15
|
+
Failures row or a Per question cell shows the answer: grading and checks, reasoning,
|
|
16
|
+
answer, question.
|
|
16
17
|
Answer detail: [ and ] step to the previous/next answer; esc/q close.
|
|
17
18
|
Anywhere: esc/q go back (q quits only on Setup), ctrl+q quits, w lists this session's runs and
|
|
18
19
|
tunes. Leaving a live run or tune keeps it going; the header shows its progress.
|
|
@@ -180,7 +181,8 @@ def fmt_secs(secs):
|
|
|
180
181
|
|
|
181
182
|
|
|
182
183
|
class StreamView(TextArea):
|
|
183
|
-
"""Read-only, word-wrapped text that grows as tokens stream in. Scroll it with the mouse
|
|
184
|
+
"""Read-only, word-wrapped text that grows as tokens stream in. Scroll it with the mouse; it follows
|
|
185
|
+
new text only while scrolled to the bottom."""
|
|
184
186
|
|
|
185
187
|
can_focus = False
|
|
186
188
|
|
|
@@ -188,14 +190,28 @@ class StreamView(TextArea):
|
|
|
188
190
|
|
|
189
191
|
def __init__(self, **kw):
|
|
190
192
|
super().__init__(read_only=True, soft_wrap=True, show_cursor=False, max_checkpoints=1, **kw)
|
|
193
|
+
self.trim_pending = False
|
|
191
194
|
|
|
192
195
|
def append(self, text, follow=True):
|
|
196
|
+
# Follow only when already at the bottom: scrolled up to read, the view stays put.
|
|
197
|
+
follow = follow and self.scroll_y >= self.max_scroll_y - 1
|
|
193
198
|
self.insert(text, self.document.end)
|
|
194
199
|
if len(self.text) > self.MAX_CHARS:
|
|
195
|
-
|
|
200
|
+
if follow:
|
|
201
|
+
self.trim()
|
|
202
|
+
elif not self.trim_pending: # once the new text is laid out, so the place is measured right
|
|
203
|
+
self.trim_pending = True
|
|
204
|
+
self.call_after_refresh(self.trim)
|
|
196
205
|
if follow:
|
|
197
206
|
self.scroll_end(animate=False)
|
|
198
207
|
|
|
208
|
+
def trim(self):
|
|
209
|
+
"""Drop the oldest text, keeping the view the same distance from the end (the text that's left)."""
|
|
210
|
+
self.trim_pending = False
|
|
211
|
+
from_end = self.max_scroll_y - self.scroll_y
|
|
212
|
+
self.load_text("…" + self.text[-self.MAX_CHARS // 2:])
|
|
213
|
+
self.call_after_refresh(lambda: self.scroll_to(y=max(0, self.max_scroll_y - from_end), animate=False))
|
|
214
|
+
|
|
199
215
|
|
|
200
216
|
# ------------------------------------------------------------------ answer detail
|
|
201
217
|
def answer_entry(row):
|
|
@@ -315,8 +331,8 @@ with the model's reasoning and answer as they stream, then recent results with t
|
|
|
315
331
|
v with several models at a time: stream the next one (k skips the one streaming)""",
|
|
316
332
|
"ResultsScreen": """[b]Results[/b]
|
|
317
333
|
|
|
318
|
-
|
|
319
|
-
it's INCONCLUSIVE. The other tabs are the evidence:
|
|
334
|
+
Opens on [b]Per question[/b]. [b]Production readiness[/b] gives one verdict per model and use case,
|
|
335
|
+
and what's missing when it's INCONCLUSIVE. The other tabs are the evidence:
|
|
320
336
|
Scorecard accuracy, critical failures and truncation per model and pack
|
|
321
337
|
Speed & tokens time and tokens per answer (★ = nothing beats it on both accuracy and time)
|
|
322
338
|
Per question every question, model by model
|
|
@@ -2324,7 +2340,7 @@ class ResultsScreen(Screen):
|
|
|
2324
2340
|
yield Static(id="results-info")
|
|
2325
2341
|
if self.smoke_dir:
|
|
2326
2342
|
yield Button("Show this Smoke run's results", id="toggle-smoke")
|
|
2327
|
-
with TabbedContent():
|
|
2343
|
+
with TabbedContent(initial="tab-per-question"):
|
|
2328
2344
|
with TabPane("Production readiness"):
|
|
2329
2345
|
yield Static(id="readiness-short")
|
|
2330
2346
|
yield Static(self.READINESS_HELP, id="readiness-help")
|
|
@@ -733,6 +733,64 @@ class FirstRun(unittest.TestCase):
|
|
|
733
733
|
env=dict(os.environ, TUIEVAL_HOME=self.ws, TUIEVAL_DETECT_PORTS=""), timeout=60).stdout.strip()
|
|
734
734
|
self.assertEqual(out, "['first'] ['my-model'] smoke False") # tuning shows once something has run
|
|
735
735
|
|
|
736
|
+
def test_results_open_on_per_question(self):
|
|
737
|
+
tuieval(self.ws, "add", "my-model", "--server", "local")
|
|
738
|
+
code = textwrap.dedent("""
|
|
739
|
+
import asyncio
|
|
740
|
+
from tuieval.tui import EvalsApp
|
|
741
|
+
from textual.widgets import TabbedContent
|
|
742
|
+
async def go():
|
|
743
|
+
app = EvalsApp({})
|
|
744
|
+
async with app.run_test(size=(140, 40)) as pilot:
|
|
745
|
+
await pilot.pause()
|
|
746
|
+
await pilot.press("r")
|
|
747
|
+
await pilot.pause()
|
|
748
|
+
print(type(app.screen).__name__, app.screen.query_one(TabbedContent).active)
|
|
749
|
+
asyncio.run(go())
|
|
750
|
+
""")
|
|
751
|
+
out = subprocess.run([sys.executable, "-c", code], capture_output=True, text=True,
|
|
752
|
+
env=dict(os.environ, TUIEVAL_HOME=self.ws, TUIEVAL_DETECT_PORTS=""), timeout=60).stdout.strip()
|
|
753
|
+
self.assertEqual(out, "ResultsScreen tab-per-question")
|
|
754
|
+
|
|
755
|
+
def test_stream_follows_only_at_the_bottom(self):
|
|
756
|
+
code = textwrap.dedent("""
|
|
757
|
+
import asyncio
|
|
758
|
+
from textual.app import App
|
|
759
|
+
from tuieval.tui import StreamView
|
|
760
|
+
class A(App):
|
|
761
|
+
def compose(self):
|
|
762
|
+
yield StreamView()
|
|
763
|
+
async def go():
|
|
764
|
+
app = A()
|
|
765
|
+
async with app.run_test(size=(60, 12)) as pilot:
|
|
766
|
+
s = app.query_one(StreamView)
|
|
767
|
+
for i in range(100):
|
|
768
|
+
s.append(f"line {i}\\n")
|
|
769
|
+
await pilot.pause()
|
|
770
|
+
s.scroll_to(y=20, animate=False)
|
|
771
|
+
await pilot.pause()
|
|
772
|
+
for i in range(100):
|
|
773
|
+
s.append("more\\n")
|
|
774
|
+
await pilot.pause()
|
|
775
|
+
held = s.scroll_y
|
|
776
|
+
s.scroll_end(animate=False)
|
|
777
|
+
await pilot.pause()
|
|
778
|
+
s.append("last\\n")
|
|
779
|
+
await pilot.pause()
|
|
780
|
+
following = s.scroll_y == s.max_scroll_y
|
|
781
|
+
s.MAX_CHARS = len(s.text) + 100 # the next text trims the oldest
|
|
782
|
+
s.scroll_to(y=s.max_scroll_y - 30, animate=False)
|
|
783
|
+
await pilot.pause()
|
|
784
|
+
top = s.document.get_line(s.scroll_y)
|
|
785
|
+
s.append("x\\n" * 60)
|
|
786
|
+
await pilot.pause()
|
|
787
|
+
await pilot.pause()
|
|
788
|
+
print(held, following, s.text.startswith("…"), s.document.get_line(s.scroll_y) == top)
|
|
789
|
+
asyncio.run(go())
|
|
790
|
+
""")
|
|
791
|
+
out = subprocess.run([sys.executable, "-c", code], capture_output=True, text=True, timeout=60).stdout.strip()
|
|
792
|
+
self.assertEqual(out, "20 True True True") # scrolled up stays put, also through a trim; bottom follows
|
|
793
|
+
|
|
736
794
|
def test_doctor(self):
|
|
737
795
|
tuieval(self.ws, "add", "mock", "--server", "local", "--label", "wanted")
|
|
738
796
|
p = tuieval(self.ws, "doctor", check=False, ports=self.port)
|
|
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.dev33 → tuieval-0.2.0.dev35}/src/tuieval/templates/packs/tool_call/system.txt
RENAMED
|
File without changes
|
{tuieval-0.2.0.dev33 → tuieval-0.2.0.dev35}/src/tuieval/templates/packs/tool_call/tests.yaml
RENAMED
|
File without changes
|
{tuieval-0.2.0.dev33 → tuieval-0.2.0.dev35}/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
|