benchkit-cli 0.1.0__py3-none-any.whl

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 (149) hide show
  1. benchkit/__init__.py +1 -0
  2. benchkit/_pi_proxy.py +219 -0
  3. benchkit/answer_key_guard.ts +49 -0
  4. benchkit/artifacts.py +87 -0
  5. benchkit/benchmarks/__init__.py +105 -0
  6. benchkit/benchmarks/aider_polyglot.py +405 -0
  7. benchkit/benchmarks/arc.py +52 -0
  8. benchkit/benchmarks/banking77.py +149 -0
  9. benchkit/benchmarks/base.py +19 -0
  10. benchkit/benchmarks/boolq.py +49 -0
  11. benchkit/benchmarks/chartqa.py +133 -0
  12. benchkit/benchmarks/code_verifier.py +77 -0
  13. benchkit/benchmarks/downloads.py +166 -0
  14. benchkit/benchmarks/evalplus.py +288 -0
  15. benchkit/benchmarks/git_surgery.py +485 -0
  16. benchkit/benchmarks/gpqa.py +56 -0
  17. benchkit/benchmarks/gsm8k.py +97 -0
  18. benchkit/benchmarks/hellaswag.py +49 -0
  19. benchkit/benchmarks/humaneval.py +103 -0
  20. benchkit/benchmarks/ifeval.py +56 -0
  21. benchkit/benchmarks/ifeval_instructions.py +477 -0
  22. benchkit/benchmarks/mbpp.py +60 -0
  23. benchkit/benchmarks/mc_arena.py +479 -0
  24. benchkit/benchmarks/mcq.py +94 -0
  25. benchkit/benchmarks/medfailbench.py +537 -0
  26. benchkit/benchmarks/mmlu.py +54 -0
  27. benchkit/benchmarks/mmlu_pro.py +62 -0
  28. benchkit/benchmarks/mmvp.py +115 -0
  29. benchkit/benchmarks/ocrbench.py +96 -0
  30. benchkit/benchmarks/openbookqa.py +52 -0
  31. benchkit/benchmarks/patcheval.py +929 -0
  32. benchkit/benchmarks/piqa.py +52 -0
  33. benchkit/benchmarks/ruler.py +172 -0
  34. benchkit/benchmarks/ruler_generator.py +535 -0
  35. benchkit/benchmarks/sanity.py +174 -0
  36. benchkit/benchmarks/treejs_arena.py +268 -0
  37. benchkit/benchmarks/truthfulqa.py +52 -0
  38. benchkit/benchmarks/utils.py +25 -0
  39. benchkit/benchmarks/vision.py +230 -0
  40. benchkit/benchmarks/vstar.py +108 -0
  41. benchkit/benchmarks/winogrande.py +52 -0
  42. benchkit/benchmarks/xstest.py +116 -0
  43. benchkit/browser.py +429 -0
  44. benchkit/catalog.py +121 -0
  45. benchkit/cli.py +1000 -0
  46. benchkit/client.py +1413 -0
  47. benchkit/controls.py +87 -0
  48. benchkit/datasets/MMLU_LICENSE.txt +21 -0
  49. benchkit/datasets/README.md +142 -0
  50. benchkit/datasets/arc_challenge.jsonl +1172 -0
  51. benchkit/datasets/banking77.jsonl +3080 -0
  52. benchkit/datasets/banking77_intents.json +79 -0
  53. benchkit/datasets/boolq.jsonl +3270 -0
  54. benchkit/datasets/code_verifier.jsonl +500 -0
  55. benchkit/datasets/gpqa_diamond.jsonl +198 -0
  56. benchkit/datasets/gsm8k.jsonl +1319 -0
  57. benchkit/datasets/hellaswag.jsonl +1000 -0
  58. benchkit/datasets/humaneval.jsonl +164 -0
  59. benchkit/datasets/ifeval.jsonl +541 -0
  60. benchkit/datasets/mbpp.jsonl +500 -0
  61. benchkit/datasets/mc_blocks_1_20_1.jsonl +1003 -0
  62. benchkit/datasets/medfailbench_hard30.jsonl +30 -0
  63. benchkit/datasets/medfailbench_hard30.md +13 -0
  64. benchkit/datasets/openbookqa.jsonl +500 -0
  65. benchkit/datasets/piqa.jsonl +1838 -0
  66. benchkit/datasets/sanity_code.jsonl +6 -0
  67. benchkit/datasets/truthfulqa.jsonl +817 -0
  68. benchkit/datasets/winogrande.jsonl +1267 -0
  69. benchkit/datasets/xstest.csv +451 -0
  70. benchkit/decision.py +194 -0
  71. benchkit/demo.py +451 -0
  72. benchkit/dockerfiles.py +247 -0
  73. benchkit/engine.py +1270 -0
  74. benchkit/evaluation.py +195 -0
  75. benchkit/events.py +141 -0
  76. benchkit/executor.py +96 -0
  77. benchkit/git_surgery/backport-release-stack/setup.sh +328 -0
  78. benchkit/git_surgery/backport-release-stack/verify.sh +119 -0
  79. benchkit/git_surgery/bisect-the-regression/setup.sh +49 -0
  80. benchkit/git_surgery/bisect-the-regression/verify.sh +34 -0
  81. benchkit/git_surgery/rebase-conflict-chain/setup.sh +65 -0
  82. benchkit/git_surgery/rebase-conflict-chain/verify.sh +43 -0
  83. benchkit/git_surgery/recover-complex-stash/setup.sh +152 -0
  84. benchkit/git_surgery/recover-complex-stash/verify.sh +95 -0
  85. benchkit/git_surgery/recover-lost-work/setup.sh +40 -0
  86. benchkit/git_surgery/recover-lost-work/verify.sh +36 -0
  87. benchkit/git_surgery/repair-force-pushed-remote/setup.sh +171 -0
  88. benchkit/git_surgery/repair-force-pushed-remote/verify.sh +83 -0
  89. benchkit/git_surgery/revert-merge-with-followups/setup.sh +198 -0
  90. benchkit/git_surgery/revert-merge-with-followups/verify.sh +98 -0
  91. benchkit/git_surgery/secret-in-history/README.md +27 -0
  92. benchkit/git_surgery/secret-in-history/setup.sh +107 -0
  93. benchkit/git_surgery/secret-in-history/verify.sh +106 -0
  94. benchkit/git_surgery/split-the-mega-commit/setup.sh +50 -0
  95. benchkit/git_surgery/split-the-mega-commit/verify.sh +48 -0
  96. benchkit/git_surgery/untangle-nested-submodules/setup.sh +193 -0
  97. benchkit/git_surgery/untangle-nested-submodules/verify.sh +90 -0
  98. benchkit/history.py +474 -0
  99. benchkit/jobs.py +332 -0
  100. benchkit/leakage.py +51 -0
  101. benchkit/looping.py +873 -0
  102. benchkit/mc_render.py +274 -0
  103. benchkit/mc_viewer/dist/atlas.png +0 -0
  104. benchkit/mc_viewer/dist/blockStates.json.gz +0 -0
  105. benchkit/mc_viewer/dist/version.json +4 -0
  106. benchkit/mc_viewer/dist/viewer.html +23 -0
  107. benchkit/mc_viewer/dist/viewer.js +2 -0
  108. benchkit/mc_viewer/dist/viewer.js.LICENSE.txt +25 -0
  109. benchkit/mc_viewer/dist/worker.js +2 -0
  110. benchkit/mc_viewer/dist/worker.js.LICENSE.txt +19 -0
  111. benchkit/metrics.py +100 -0
  112. benchkit/ollama.py +60 -0
  113. benchkit/perf.py +353 -0
  114. benchkit/perf_report.py +207 -0
  115. benchkit/perturbations.py +208 -0
  116. benchkit/pi_agent.py +476 -0
  117. benchkit/pi_package/package-lock.json +1827 -0
  118. benchkit/pi_package/package.json +8 -0
  119. benchkit/report.py +142 -0
  120. benchkit/report_markdown.py +645 -0
  121. benchkit/results.py +688 -0
  122. benchkit/retry.py +163 -0
  123. benchkit/runner.py +769 -0
  124. benchkit/sandbox.py +1167 -0
  125. benchkit/template_check.py +291 -0
  126. benchkit/templates/arena.html +504 -0
  127. benchkit/templates/history.html +58 -0
  128. benchkit/templates/perf.html +509 -0
  129. benchkit/templates/report.html +769 -0
  130. benchkit/tui/__init__.py +5 -0
  131. benchkit/tui/app.py +87 -0
  132. benchkit/tui/app.tcss +512 -0
  133. benchkit/tui/formatting.py +84 -0
  134. benchkit/tui/screens/__init__.py +1 -0
  135. benchkit/tui/screens/connect.py +191 -0
  136. benchkit/tui/screens/detail.py +288 -0
  137. benchkit/tui/screens/help.py +84 -0
  138. benchkit/tui/screens/modals.py +544 -0
  139. benchkit/tui/screens/results.py +361 -0
  140. benchkit/tui/screens/run.py +988 -0
  141. benchkit/tui/screens/setup.py +733 -0
  142. benchkit/tui/theme.py +135 -0
  143. benchkit/tui/widgets.py +120 -0
  144. benchkit_cli-0.1.0.dist-info/METADATA +294 -0
  145. benchkit_cli-0.1.0.dist-info/RECORD +149 -0
  146. benchkit_cli-0.1.0.dist-info/WHEEL +5 -0
  147. benchkit_cli-0.1.0.dist-info/entry_points.txt +3 -0
  148. benchkit_cli-0.1.0.dist-info/licenses/LICENSE +201 -0
  149. benchkit_cli-0.1.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,52 @@
1
+ """PIQA benchmark - binary physical commonsense reasoning."""
2
+
3
+ import json
4
+ from pathlib import Path
5
+
6
+ from benchkit.benchmarks.base import Task
7
+ from benchkit.benchmarks.mcq import extract_choice
8
+ from benchkit.benchmarks.utils import strip_think_tags
9
+
10
+ DATASET = Path(__file__).parent.parent / "datasets" / "piqa.jsonl"
11
+
12
+ SYSTEM = (
13
+ "Choose the most appropriate solution for the goal. "
14
+ "Reply with ONLY the letter (A or B)."
15
+ )
16
+
17
+
18
+ def _format_choices(choices: list[str]) -> str:
19
+ return "\n".join(
20
+ f"{letter}) {choice}" for letter, choice in zip("AB", choices, strict=False)
21
+ )
22
+
23
+
24
+ class PIQA:
25
+ name = "piqa"
26
+ decision_instructions = "Which solution best achieves the goal?"
27
+
28
+ def load_tasks(self) -> list[Task]:
29
+ tasks = []
30
+ with open(DATASET) as f:
31
+ for line in f:
32
+ d = json.loads(line)
33
+ tasks.append(
34
+ Task(
35
+ id=d["task_id"],
36
+ prompt=d["goal"],
37
+ metadata={
38
+ "choices": d["choices"],
39
+ "answer": d["answer"],
40
+ },
41
+ )
42
+ )
43
+ return tasks
44
+
45
+ def build_prompt(self, task: Task) -> str:
46
+ choices = _format_choices(task.metadata["choices"])
47
+ return f"{SYSTEM}\n\nGoal: {task.prompt}\n\n{choices}"
48
+
49
+ def evaluate(self, task: Task, response: str) -> bool:
50
+ text = strip_think_tags(response)
51
+ choice = extract_choice(text, task.metadata["choices"])
52
+ return choice == task.metadata["answer"]
@@ -0,0 +1,172 @@
1
+ """RULER effective-context benchmark with runtime-generated prompts."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import math
6
+ import threading
7
+ from collections.abc import Callable
8
+
9
+ from benchkit.benchmarks.base import Task
10
+ from benchkit.benchmarks.downloads import Dataset
11
+ from benchkit.benchmarks.ruler_generator import (
12
+ CONTEXT_BUCKETS,
13
+ DEFAULT_SAMPLES_PER_KIND,
14
+ ESSAY_FILE,
15
+ PRACTICAL_SAMPLES_PER_KIND,
16
+ TASK_KINDS,
17
+ TASKS_PER_BUCKET,
18
+ cache_dir,
19
+ context_label,
20
+ corpus_installed,
21
+ fit_prompt,
22
+ generate_tasks,
23
+ install_corpus,
24
+ )
25
+ from benchkit.benchmarks.utils import strip_think_tags
26
+
27
+
28
+ class RULER:
29
+ """Consumer-friendly RULER suite with repeated task-family coverage."""
30
+
31
+ name = "ruler"
32
+ samples_per_kind = PRACTICAL_SAMPLES_PER_KIND
33
+ tasks_per_variant = samples_per_kind * len(TASK_KINDS)
34
+ task_count = tasks_per_variant * len(CONTEXT_BUCKETS)
35
+ context_buckets = CONTEXT_BUCKETS
36
+ variant_labels = tuple(context_label(bucket) for bucket in CONTEXT_BUCKETS)
37
+ variant_count = len(CONTEXT_BUCKETS)
38
+ list_task_count = f"{tasks_per_variant} × 6"
39
+ include_in_overall = False
40
+ list_note = "practical · 13 tasks × 3 samples · 4k–128k"
41
+ evaluation_activity = "checking retrieved values"
42
+ data_source = Dataset(
43
+ summary="SQuAD 2.0 + HotpotQA haystacks and the Paul Graham essays",
44
+ size=None,
45
+ location=cache_dir,
46
+ is_installed=corpus_installed,
47
+ install=lambda _progress: install_corpus(),
48
+ hint=(
49
+ f"{ESSAY_FILE} is not downloadable; generate it with NVIDIA/RULER's "
50
+ "download_paulgraham_essay.py"
51
+ ),
52
+ )
53
+
54
+ def __init__(self) -> None:
55
+ self._unit_hints: dict[tuple[str, str, int], int] = {}
56
+ self._hint_lock = threading.Lock()
57
+
58
+ def load_tasks(self) -> list[Task]:
59
+ return generate_tasks(samples_per_kind=self.samples_per_kind)
60
+
61
+ def variants(self, client: object, model: str) -> list[str]:
62
+ """Return buckets that fit the model's discovered served context."""
63
+ limit: int | None = None
64
+ discover = getattr(client, "context_length", None)
65
+ if callable(discover):
66
+ try:
67
+ value = discover(model)
68
+ if isinstance(value, int) and not isinstance(value, bool) and value > 0:
69
+ limit = value
70
+ except Exception:
71
+ limit = None
72
+ return [
73
+ context_label(bucket)
74
+ for bucket in CONTEXT_BUCKETS
75
+ if limit is None or bucket <= limit
76
+ ]
77
+
78
+ def tasks_for_variant(self, tasks: list[Task], variant: str) -> list[Task]:
79
+ return [task for task in tasks if task.metadata.get("variant") == variant]
80
+
81
+ def result_metadata(self, variant: str | None) -> dict:
82
+ if not variant:
83
+ return {"include_in_overall": self.include_in_overall}
84
+ context_tokens = next(
85
+ (bucket for bucket in CONTEXT_BUCKETS if context_label(bucket) == variant),
86
+ 0,
87
+ )
88
+ return {
89
+ "context_tokens": context_tokens,
90
+ "context_label": variant,
91
+ "include_in_overall": self.include_in_overall,
92
+ }
93
+
94
+ def build_prompt(self, task: Task) -> str:
95
+ prompt, _, _ = fit_prompt(task)
96
+ return prompt
97
+
98
+ def build_prompt_for(self, task: Task, client: object, model: str) -> str:
99
+ tokenizer = getattr(client, "tokenize", None)
100
+ token_count: Callable[[str], int | None] | None = None
101
+ if callable(tokenizer):
102
+
103
+ def count(prompt: str) -> int | None:
104
+ tokens = tokenizer(model, prompt)
105
+ return len(tokens) if isinstance(tokens, list) else None
106
+
107
+ token_count = count
108
+
109
+ cache_key = (
110
+ model,
111
+ str(task.metadata["task_type"]),
112
+ int(task.metadata["context_tokens"]),
113
+ )
114
+ with self._hint_lock:
115
+ initial_units = self._unit_hints.get(cache_key)
116
+ prompt, units, _ = fit_prompt(
117
+ task,
118
+ token_count,
119
+ initial_units=initial_units,
120
+ )
121
+ with self._hint_lock:
122
+ self._unit_hints[cache_key] = units
123
+ return prompt
124
+
125
+ def evaluate(self, task: Task, response: str) -> float:
126
+ """Return RULER's fraction of reference strings found in the answer."""
127
+ text = strip_think_tags(response).casefold()
128
+ answers = [str(answer).casefold() for answer in task.metadata["answers"]]
129
+ if not answers:
130
+ return 0.0
131
+ return sum(answer in text for answer in answers) / len(answers)
132
+
133
+ def task_statistics(self, records: list[object]) -> list[dict]:
134
+ """Return per-task mean scores and Wilson 95% intervals."""
135
+ grouped: dict[str, list[float]] = {}
136
+ for record in records:
137
+ parts = str(getattr(record, "task_id", "")).split("/")
138
+ if len(parts) >= 4:
139
+ grouped.setdefault(parts[2], []).append(
140
+ float(getattr(record, "score", 0.0))
141
+ )
142
+ rows = []
143
+ z = 1.959963984540054
144
+ for kind, scores in sorted(grouped.items()):
145
+ n = len(scores)
146
+ mean = sum(scores) / n
147
+ denominator = 1 + z * z / n
148
+ center = (mean + z * z / (2 * n)) / denominator
149
+ margin = (
150
+ z * math.sqrt(mean * (1 - mean) / n + z * z / (4 * n * n)) / denominator
151
+ )
152
+ rows.append(
153
+ {
154
+ "task": kind,
155
+ "samples": n,
156
+ "score": round(mean * 100, 1),
157
+ "ci95_low": round(max(0.0, center - margin) * 100, 1),
158
+ "ci95_high": round(min(1.0, center + margin) * 100, 1),
159
+ }
160
+ )
161
+ return rows
162
+
163
+
164
+ class RULERFull(RULER):
165
+ """Complete RULER suite for research-scale, explicitly opted-in runs."""
166
+
167
+ name = "ruler-full"
168
+ samples_per_kind = DEFAULT_SAMPLES_PER_KIND
169
+ tasks_per_variant = TASKS_PER_BUCKET
170
+ task_count = tasks_per_variant * len(CONTEXT_BUCKETS)
171
+ list_task_count = f"{tasks_per_variant:,} × 6"
172
+ list_note = "full · 13 tasks × 500 samples · 4k–128k · extremely slow"