benchkit-cli 0.1.0__tar.gz → 0.1.2__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.
- {benchkit_cli-0.1.0/src/benchkit_cli.egg-info → benchkit_cli-0.1.2}/PKG-INFO +8 -3
- {benchkit_cli-0.1.0 → benchkit_cli-0.1.2}/README.md +7 -2
- {benchkit_cli-0.1.0 → benchkit_cli-0.1.2}/pyproject.toml +1 -1
- {benchkit_cli-0.1.0 → benchkit_cli-0.1.2}/src/benchkit/benchmarks/__init__.py +3 -1
- {benchkit_cli-0.1.0 → benchkit_cli-0.1.2}/src/benchkit/benchmarks/downloads.py +11 -0
- {benchkit_cli-0.1.0 → benchkit_cli-0.1.2}/src/benchkit/benchmarks/evalplus.py +49 -5
- {benchkit_cli-0.1.0 → benchkit_cli-0.1.2}/src/benchkit/cli.py +52 -9
- benchkit_cli-0.1.2/src/benchkit/config.py +251 -0
- {benchkit_cli-0.1.0 → benchkit_cli-0.1.2}/src/benchkit/executor.py +48 -21
- {benchkit_cli-0.1.0 → benchkit_cli-0.1.2}/src/benchkit/tui/screens/connect.py +28 -0
- {benchkit_cli-0.1.0 → benchkit_cli-0.1.2/src/benchkit_cli.egg-info}/PKG-INFO +8 -3
- {benchkit_cli-0.1.0 → benchkit_cli-0.1.2}/src/benchkit_cli.egg-info/SOURCES.txt +2 -0
- benchkit_cli-0.1.2/tests/test_config.py +198 -0
- {benchkit_cli-0.1.0 → benchkit_cli-0.1.2}/LICENSE +0 -0
- {benchkit_cli-0.1.0 → benchkit_cli-0.1.2}/setup.cfg +0 -0
- {benchkit_cli-0.1.0 → benchkit_cli-0.1.2}/src/benchkit/__init__.py +0 -0
- {benchkit_cli-0.1.0 → benchkit_cli-0.1.2}/src/benchkit/_pi_proxy.py +0 -0
- {benchkit_cli-0.1.0 → benchkit_cli-0.1.2}/src/benchkit/answer_key_guard.ts +0 -0
- {benchkit_cli-0.1.0 → benchkit_cli-0.1.2}/src/benchkit/artifacts.py +0 -0
- {benchkit_cli-0.1.0 → benchkit_cli-0.1.2}/src/benchkit/benchmarks/aider_polyglot.py +0 -0
- {benchkit_cli-0.1.0 → benchkit_cli-0.1.2}/src/benchkit/benchmarks/arc.py +0 -0
- {benchkit_cli-0.1.0 → benchkit_cli-0.1.2}/src/benchkit/benchmarks/banking77.py +0 -0
- {benchkit_cli-0.1.0 → benchkit_cli-0.1.2}/src/benchkit/benchmarks/base.py +0 -0
- {benchkit_cli-0.1.0 → benchkit_cli-0.1.2}/src/benchkit/benchmarks/boolq.py +0 -0
- {benchkit_cli-0.1.0 → benchkit_cli-0.1.2}/src/benchkit/benchmarks/chartqa.py +0 -0
- {benchkit_cli-0.1.0 → benchkit_cli-0.1.2}/src/benchkit/benchmarks/code_verifier.py +0 -0
- {benchkit_cli-0.1.0 → benchkit_cli-0.1.2}/src/benchkit/benchmarks/git_surgery.py +0 -0
- {benchkit_cli-0.1.0 → benchkit_cli-0.1.2}/src/benchkit/benchmarks/gpqa.py +0 -0
- {benchkit_cli-0.1.0 → benchkit_cli-0.1.2}/src/benchkit/benchmarks/gsm8k.py +0 -0
- {benchkit_cli-0.1.0 → benchkit_cli-0.1.2}/src/benchkit/benchmarks/hellaswag.py +0 -0
- {benchkit_cli-0.1.0 → benchkit_cli-0.1.2}/src/benchkit/benchmarks/humaneval.py +0 -0
- {benchkit_cli-0.1.0 → benchkit_cli-0.1.2}/src/benchkit/benchmarks/ifeval.py +0 -0
- {benchkit_cli-0.1.0 → benchkit_cli-0.1.2}/src/benchkit/benchmarks/ifeval_instructions.py +0 -0
- {benchkit_cli-0.1.0 → benchkit_cli-0.1.2}/src/benchkit/benchmarks/mbpp.py +0 -0
- {benchkit_cli-0.1.0 → benchkit_cli-0.1.2}/src/benchkit/benchmarks/mc_arena.py +0 -0
- {benchkit_cli-0.1.0 → benchkit_cli-0.1.2}/src/benchkit/benchmarks/mcq.py +0 -0
- {benchkit_cli-0.1.0 → benchkit_cli-0.1.2}/src/benchkit/benchmarks/medfailbench.py +0 -0
- {benchkit_cli-0.1.0 → benchkit_cli-0.1.2}/src/benchkit/benchmarks/mmlu.py +0 -0
- {benchkit_cli-0.1.0 → benchkit_cli-0.1.2}/src/benchkit/benchmarks/mmlu_pro.py +0 -0
- {benchkit_cli-0.1.0 → benchkit_cli-0.1.2}/src/benchkit/benchmarks/mmvp.py +0 -0
- {benchkit_cli-0.1.0 → benchkit_cli-0.1.2}/src/benchkit/benchmarks/ocrbench.py +0 -0
- {benchkit_cli-0.1.0 → benchkit_cli-0.1.2}/src/benchkit/benchmarks/openbookqa.py +0 -0
- {benchkit_cli-0.1.0 → benchkit_cli-0.1.2}/src/benchkit/benchmarks/patcheval.py +0 -0
- {benchkit_cli-0.1.0 → benchkit_cli-0.1.2}/src/benchkit/benchmarks/piqa.py +0 -0
- {benchkit_cli-0.1.0 → benchkit_cli-0.1.2}/src/benchkit/benchmarks/ruler.py +0 -0
- {benchkit_cli-0.1.0 → benchkit_cli-0.1.2}/src/benchkit/benchmarks/ruler_generator.py +0 -0
- {benchkit_cli-0.1.0 → benchkit_cli-0.1.2}/src/benchkit/benchmarks/sanity.py +0 -0
- {benchkit_cli-0.1.0 → benchkit_cli-0.1.2}/src/benchkit/benchmarks/treejs_arena.py +0 -0
- {benchkit_cli-0.1.0 → benchkit_cli-0.1.2}/src/benchkit/benchmarks/truthfulqa.py +0 -0
- {benchkit_cli-0.1.0 → benchkit_cli-0.1.2}/src/benchkit/benchmarks/utils.py +0 -0
- {benchkit_cli-0.1.0 → benchkit_cli-0.1.2}/src/benchkit/benchmarks/vision.py +0 -0
- {benchkit_cli-0.1.0 → benchkit_cli-0.1.2}/src/benchkit/benchmarks/vstar.py +0 -0
- {benchkit_cli-0.1.0 → benchkit_cli-0.1.2}/src/benchkit/benchmarks/winogrande.py +0 -0
- {benchkit_cli-0.1.0 → benchkit_cli-0.1.2}/src/benchkit/benchmarks/xstest.py +0 -0
- {benchkit_cli-0.1.0 → benchkit_cli-0.1.2}/src/benchkit/browser.py +0 -0
- {benchkit_cli-0.1.0 → benchkit_cli-0.1.2}/src/benchkit/catalog.py +0 -0
- {benchkit_cli-0.1.0 → benchkit_cli-0.1.2}/src/benchkit/client.py +0 -0
- {benchkit_cli-0.1.0 → benchkit_cli-0.1.2}/src/benchkit/controls.py +0 -0
- {benchkit_cli-0.1.0 → benchkit_cli-0.1.2}/src/benchkit/datasets/MMLU_LICENSE.txt +0 -0
- {benchkit_cli-0.1.0 → benchkit_cli-0.1.2}/src/benchkit/datasets/README.md +0 -0
- {benchkit_cli-0.1.0 → benchkit_cli-0.1.2}/src/benchkit/datasets/arc_challenge.jsonl +0 -0
- {benchkit_cli-0.1.0 → benchkit_cli-0.1.2}/src/benchkit/datasets/banking77.jsonl +0 -0
- {benchkit_cli-0.1.0 → benchkit_cli-0.1.2}/src/benchkit/datasets/banking77_intents.json +0 -0
- {benchkit_cli-0.1.0 → benchkit_cli-0.1.2}/src/benchkit/datasets/boolq.jsonl +0 -0
- {benchkit_cli-0.1.0 → benchkit_cli-0.1.2}/src/benchkit/datasets/code_verifier.jsonl +0 -0
- {benchkit_cli-0.1.0 → benchkit_cli-0.1.2}/src/benchkit/datasets/gpqa_diamond.jsonl +0 -0
- {benchkit_cli-0.1.0 → benchkit_cli-0.1.2}/src/benchkit/datasets/gsm8k.jsonl +0 -0
- {benchkit_cli-0.1.0 → benchkit_cli-0.1.2}/src/benchkit/datasets/hellaswag.jsonl +0 -0
- {benchkit_cli-0.1.0 → benchkit_cli-0.1.2}/src/benchkit/datasets/humaneval.jsonl +0 -0
- {benchkit_cli-0.1.0 → benchkit_cli-0.1.2}/src/benchkit/datasets/ifeval.jsonl +0 -0
- {benchkit_cli-0.1.0 → benchkit_cli-0.1.2}/src/benchkit/datasets/mbpp.jsonl +0 -0
- {benchkit_cli-0.1.0 → benchkit_cli-0.1.2}/src/benchkit/datasets/mc_blocks_1_20_1.jsonl +0 -0
- {benchkit_cli-0.1.0 → benchkit_cli-0.1.2}/src/benchkit/datasets/medfailbench_hard30.jsonl +0 -0
- {benchkit_cli-0.1.0 → benchkit_cli-0.1.2}/src/benchkit/datasets/medfailbench_hard30.md +0 -0
- {benchkit_cli-0.1.0 → benchkit_cli-0.1.2}/src/benchkit/datasets/openbookqa.jsonl +0 -0
- {benchkit_cli-0.1.0 → benchkit_cli-0.1.2}/src/benchkit/datasets/piqa.jsonl +0 -0
- {benchkit_cli-0.1.0 → benchkit_cli-0.1.2}/src/benchkit/datasets/sanity_code.jsonl +0 -0
- {benchkit_cli-0.1.0 → benchkit_cli-0.1.2}/src/benchkit/datasets/truthfulqa.jsonl +0 -0
- {benchkit_cli-0.1.0 → benchkit_cli-0.1.2}/src/benchkit/datasets/winogrande.jsonl +0 -0
- {benchkit_cli-0.1.0 → benchkit_cli-0.1.2}/src/benchkit/datasets/xstest.csv +0 -0
- {benchkit_cli-0.1.0 → benchkit_cli-0.1.2}/src/benchkit/decision.py +0 -0
- {benchkit_cli-0.1.0 → benchkit_cli-0.1.2}/src/benchkit/demo.py +0 -0
- {benchkit_cli-0.1.0 → benchkit_cli-0.1.2}/src/benchkit/dockerfiles.py +0 -0
- {benchkit_cli-0.1.0 → benchkit_cli-0.1.2}/src/benchkit/engine.py +0 -0
- {benchkit_cli-0.1.0 → benchkit_cli-0.1.2}/src/benchkit/evaluation.py +0 -0
- {benchkit_cli-0.1.0 → benchkit_cli-0.1.2}/src/benchkit/events.py +0 -0
- {benchkit_cli-0.1.0 → benchkit_cli-0.1.2}/src/benchkit/git_surgery/backport-release-stack/setup.sh +0 -0
- {benchkit_cli-0.1.0 → benchkit_cli-0.1.2}/src/benchkit/git_surgery/backport-release-stack/verify.sh +0 -0
- {benchkit_cli-0.1.0 → benchkit_cli-0.1.2}/src/benchkit/git_surgery/bisect-the-regression/setup.sh +0 -0
- {benchkit_cli-0.1.0 → benchkit_cli-0.1.2}/src/benchkit/git_surgery/bisect-the-regression/verify.sh +0 -0
- {benchkit_cli-0.1.0 → benchkit_cli-0.1.2}/src/benchkit/git_surgery/rebase-conflict-chain/setup.sh +0 -0
- {benchkit_cli-0.1.0 → benchkit_cli-0.1.2}/src/benchkit/git_surgery/rebase-conflict-chain/verify.sh +0 -0
- {benchkit_cli-0.1.0 → benchkit_cli-0.1.2}/src/benchkit/git_surgery/recover-complex-stash/setup.sh +0 -0
- {benchkit_cli-0.1.0 → benchkit_cli-0.1.2}/src/benchkit/git_surgery/recover-complex-stash/verify.sh +0 -0
- {benchkit_cli-0.1.0 → benchkit_cli-0.1.2}/src/benchkit/git_surgery/recover-lost-work/setup.sh +0 -0
- {benchkit_cli-0.1.0 → benchkit_cli-0.1.2}/src/benchkit/git_surgery/recover-lost-work/verify.sh +0 -0
- {benchkit_cli-0.1.0 → benchkit_cli-0.1.2}/src/benchkit/git_surgery/repair-force-pushed-remote/setup.sh +0 -0
- {benchkit_cli-0.1.0 → benchkit_cli-0.1.2}/src/benchkit/git_surgery/repair-force-pushed-remote/verify.sh +0 -0
- {benchkit_cli-0.1.0 → benchkit_cli-0.1.2}/src/benchkit/git_surgery/revert-merge-with-followups/setup.sh +0 -0
- {benchkit_cli-0.1.0 → benchkit_cli-0.1.2}/src/benchkit/git_surgery/revert-merge-with-followups/verify.sh +0 -0
- {benchkit_cli-0.1.0 → benchkit_cli-0.1.2}/src/benchkit/git_surgery/secret-in-history/README.md +0 -0
- {benchkit_cli-0.1.0 → benchkit_cli-0.1.2}/src/benchkit/git_surgery/secret-in-history/setup.sh +0 -0
- {benchkit_cli-0.1.0 → benchkit_cli-0.1.2}/src/benchkit/git_surgery/secret-in-history/verify.sh +0 -0
- {benchkit_cli-0.1.0 → benchkit_cli-0.1.2}/src/benchkit/git_surgery/split-the-mega-commit/setup.sh +0 -0
- {benchkit_cli-0.1.0 → benchkit_cli-0.1.2}/src/benchkit/git_surgery/split-the-mega-commit/verify.sh +0 -0
- {benchkit_cli-0.1.0 → benchkit_cli-0.1.2}/src/benchkit/git_surgery/untangle-nested-submodules/setup.sh +0 -0
- {benchkit_cli-0.1.0 → benchkit_cli-0.1.2}/src/benchkit/git_surgery/untangle-nested-submodules/verify.sh +0 -0
- {benchkit_cli-0.1.0 → benchkit_cli-0.1.2}/src/benchkit/history.py +0 -0
- {benchkit_cli-0.1.0 → benchkit_cli-0.1.2}/src/benchkit/jobs.py +0 -0
- {benchkit_cli-0.1.0 → benchkit_cli-0.1.2}/src/benchkit/leakage.py +0 -0
- {benchkit_cli-0.1.0 → benchkit_cli-0.1.2}/src/benchkit/looping.py +0 -0
- {benchkit_cli-0.1.0 → benchkit_cli-0.1.2}/src/benchkit/mc_render.py +0 -0
- {benchkit_cli-0.1.0 → benchkit_cli-0.1.2}/src/benchkit/mc_viewer/dist/atlas.png +0 -0
- {benchkit_cli-0.1.0 → benchkit_cli-0.1.2}/src/benchkit/mc_viewer/dist/blockStates.json.gz +0 -0
- {benchkit_cli-0.1.0 → benchkit_cli-0.1.2}/src/benchkit/mc_viewer/dist/version.json +0 -0
- {benchkit_cli-0.1.0 → benchkit_cli-0.1.2}/src/benchkit/mc_viewer/dist/viewer.html +0 -0
- {benchkit_cli-0.1.0 → benchkit_cli-0.1.2}/src/benchkit/mc_viewer/dist/viewer.js +0 -0
- {benchkit_cli-0.1.0 → benchkit_cli-0.1.2}/src/benchkit/mc_viewer/dist/viewer.js.LICENSE.txt +0 -0
- {benchkit_cli-0.1.0 → benchkit_cli-0.1.2}/src/benchkit/mc_viewer/dist/worker.js +0 -0
- {benchkit_cli-0.1.0 → benchkit_cli-0.1.2}/src/benchkit/mc_viewer/dist/worker.js.LICENSE.txt +0 -0
- {benchkit_cli-0.1.0 → benchkit_cli-0.1.2}/src/benchkit/metrics.py +0 -0
- {benchkit_cli-0.1.0 → benchkit_cli-0.1.2}/src/benchkit/ollama.py +0 -0
- {benchkit_cli-0.1.0 → benchkit_cli-0.1.2}/src/benchkit/perf.py +0 -0
- {benchkit_cli-0.1.0 → benchkit_cli-0.1.2}/src/benchkit/perf_report.py +0 -0
- {benchkit_cli-0.1.0 → benchkit_cli-0.1.2}/src/benchkit/perturbations.py +0 -0
- {benchkit_cli-0.1.0 → benchkit_cli-0.1.2}/src/benchkit/pi_agent.py +0 -0
- {benchkit_cli-0.1.0 → benchkit_cli-0.1.2}/src/benchkit/pi_package/package-lock.json +0 -0
- {benchkit_cli-0.1.0 → benchkit_cli-0.1.2}/src/benchkit/pi_package/package.json +0 -0
- {benchkit_cli-0.1.0 → benchkit_cli-0.1.2}/src/benchkit/report.py +0 -0
- {benchkit_cli-0.1.0 → benchkit_cli-0.1.2}/src/benchkit/report_markdown.py +0 -0
- {benchkit_cli-0.1.0 → benchkit_cli-0.1.2}/src/benchkit/results.py +0 -0
- {benchkit_cli-0.1.0 → benchkit_cli-0.1.2}/src/benchkit/retry.py +0 -0
- {benchkit_cli-0.1.0 → benchkit_cli-0.1.2}/src/benchkit/runner.py +0 -0
- {benchkit_cli-0.1.0 → benchkit_cli-0.1.2}/src/benchkit/sandbox.py +0 -0
- {benchkit_cli-0.1.0 → benchkit_cli-0.1.2}/src/benchkit/template_check.py +0 -0
- {benchkit_cli-0.1.0 → benchkit_cli-0.1.2}/src/benchkit/templates/arena.html +0 -0
- {benchkit_cli-0.1.0 → benchkit_cli-0.1.2}/src/benchkit/templates/history.html +0 -0
- {benchkit_cli-0.1.0 → benchkit_cli-0.1.2}/src/benchkit/templates/perf.html +0 -0
- {benchkit_cli-0.1.0 → benchkit_cli-0.1.2}/src/benchkit/templates/report.html +0 -0
- {benchkit_cli-0.1.0 → benchkit_cli-0.1.2}/src/benchkit/tui/__init__.py +0 -0
- {benchkit_cli-0.1.0 → benchkit_cli-0.1.2}/src/benchkit/tui/app.py +0 -0
- {benchkit_cli-0.1.0 → benchkit_cli-0.1.2}/src/benchkit/tui/app.tcss +0 -0
- {benchkit_cli-0.1.0 → benchkit_cli-0.1.2}/src/benchkit/tui/formatting.py +0 -0
- {benchkit_cli-0.1.0 → benchkit_cli-0.1.2}/src/benchkit/tui/screens/__init__.py +0 -0
- {benchkit_cli-0.1.0 → benchkit_cli-0.1.2}/src/benchkit/tui/screens/detail.py +0 -0
- {benchkit_cli-0.1.0 → benchkit_cli-0.1.2}/src/benchkit/tui/screens/help.py +0 -0
- {benchkit_cli-0.1.0 → benchkit_cli-0.1.2}/src/benchkit/tui/screens/modals.py +0 -0
- {benchkit_cli-0.1.0 → benchkit_cli-0.1.2}/src/benchkit/tui/screens/results.py +0 -0
- {benchkit_cli-0.1.0 → benchkit_cli-0.1.2}/src/benchkit/tui/screens/run.py +0 -0
- {benchkit_cli-0.1.0 → benchkit_cli-0.1.2}/src/benchkit/tui/screens/setup.py +0 -0
- {benchkit_cli-0.1.0 → benchkit_cli-0.1.2}/src/benchkit/tui/theme.py +0 -0
- {benchkit_cli-0.1.0 → benchkit_cli-0.1.2}/src/benchkit/tui/widgets.py +0 -0
- {benchkit_cli-0.1.0 → benchkit_cli-0.1.2}/src/benchkit_cli.egg-info/dependency_links.txt +0 -0
- {benchkit_cli-0.1.0 → benchkit_cli-0.1.2}/src/benchkit_cli.egg-info/entry_points.txt +0 -0
- {benchkit_cli-0.1.0 → benchkit_cli-0.1.2}/src/benchkit_cli.egg-info/requires.txt +0 -0
- {benchkit_cli-0.1.0 → benchkit_cli-0.1.2}/src/benchkit_cli.egg-info/top_level.txt +0 -0
- {benchkit_cli-0.1.0 → benchkit_cli-0.1.2}/tests/test_aider_polyglot.py +0 -0
- {benchkit_cli-0.1.0 → benchkit_cli-0.1.2}/tests/test_banking77.py +0 -0
- {benchkit_cli-0.1.0 → benchkit_cli-0.1.2}/tests/test_code_verifier.py +0 -0
- {benchkit_cli-0.1.0 → benchkit_cli-0.1.2}/tests/test_concurrency.py +0 -0
- {benchkit_cli-0.1.0 → benchkit_cli-0.1.2}/tests/test_datasets.py +0 -0
- {benchkit_cli-0.1.0 → benchkit_cli-0.1.2}/tests/test_decision.py +0 -0
- {benchkit_cli-0.1.0 → benchkit_cli-0.1.2}/tests/test_evalplus.py +0 -0
- {benchkit_cli-0.1.0 → benchkit_cli-0.1.2}/tests/test_git_surgery.py +0 -0
- {benchkit_cli-0.1.0 → benchkit_cli-0.1.2}/tests/test_gsm8k.py +0 -0
- {benchkit_cli-0.1.0 → benchkit_cli-0.1.2}/tests/test_history.py +0 -0
- {benchkit_cli-0.1.0 → benchkit_cli-0.1.2}/tests/test_humaneval.py +0 -0
- {benchkit_cli-0.1.0 → benchkit_cli-0.1.2}/tests/test_looping.py +0 -0
- {benchkit_cli-0.1.0 → benchkit_cli-0.1.2}/tests/test_mc_arena.py +0 -0
- {benchkit_cli-0.1.0 → benchkit_cli-0.1.2}/tests/test_mcq.py +0 -0
- {benchkit_cli-0.1.0 → benchkit_cli-0.1.2}/tests/test_medfailbench.py +0 -0
- {benchkit_cli-0.1.0 → benchkit_cli-0.1.2}/tests/test_medfailbench_real_outputs.py +0 -0
- {benchkit_cli-0.1.0 → benchkit_cli-0.1.2}/tests/test_medfailbench_real_outputs_escalation.py +0 -0
- {benchkit_cli-0.1.0 → benchkit_cli-0.1.2}/tests/test_medfailbench_scoring_distortion.py +0 -0
- {benchkit_cli-0.1.0 → benchkit_cli-0.1.2}/tests/test_patcheval.py +0 -0
- {benchkit_cli-0.1.0 → benchkit_cli-0.1.2}/tests/test_perturbations.py +0 -0
- {benchkit_cli-0.1.0 → benchkit_cli-0.1.2}/tests/test_pi_harness.py +0 -0
- {benchkit_cli-0.1.0 → benchkit_cli-0.1.2}/tests/test_repair.py +0 -0
- {benchkit_cli-0.1.0 → benchkit_cli-0.1.2}/tests/test_report.py +0 -0
- {benchkit_cli-0.1.0 → benchkit_cli-0.1.2}/tests/test_retry.py +0 -0
- {benchkit_cli-0.1.0 → benchkit_cli-0.1.2}/tests/test_ruler.py +0 -0
- {benchkit_cli-0.1.0 → benchkit_cli-0.1.2}/tests/test_runner.py +0 -0
- {benchkit_cli-0.1.0 → benchkit_cli-0.1.2}/tests/test_sanity.py +0 -0
- {benchkit_cli-0.1.0 → benchkit_cli-0.1.2}/tests/test_treejs_arena.py +0 -0
- {benchkit_cli-0.1.0 → benchkit_cli-0.1.2}/tests/test_unload.py +0 -0
- {benchkit_cli-0.1.0 → benchkit_cli-0.1.2}/tests/test_utils.py +0 -0
- {benchkit_cli-0.1.0 → benchkit_cli-0.1.2}/tests/test_vision.py +0 -0
- {benchkit_cli-0.1.0 → benchkit_cli-0.1.2}/tests/test_xstest.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: benchkit-cli
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.2
|
|
4
4
|
Summary: Benchmark your local LLMs with real eval suites
|
|
5
5
|
License-Expression: Apache-2.0
|
|
6
6
|
Requires-Python: >=3.11
|
|
@@ -69,8 +69,10 @@ cp .env.example .env
|
|
|
69
69
|
uv run benchkit
|
|
70
70
|
```
|
|
71
71
|
|
|
72
|
-
Set your server in
|
|
73
|
-
|
|
72
|
+
Set your server in `~/.config/benchkit/.env` to use it from any folder, in a
|
|
73
|
+
`.env` in the directory you run `benchkit` from (parent directories are not
|
|
74
|
+
searched), or on the Connect screen, where "Save as default" writes the user
|
|
75
|
+
config for you:
|
|
74
76
|
|
|
75
77
|
```env
|
|
76
78
|
BENCHKIT_PROVIDER=openai
|
|
@@ -85,6 +87,8 @@ BENCHKIT_PROVIDER=ollama
|
|
|
85
87
|
OLLAMA_HOST=http://localhost:11434
|
|
86
88
|
```
|
|
87
89
|
|
|
90
|
+
`benchkit config` shows every setting and where it came from.
|
|
91
|
+
|
|
88
92
|
No inference server available? Explore the complete UI offline:
|
|
89
93
|
|
|
90
94
|
```bash
|
|
@@ -132,6 +136,7 @@ uv run benchkit --help
|
|
|
132
136
|
| Aider Polyglot | `aider-polyglot` | 225 | Repository editing across six languages with Pi |
|
|
133
137
|
| HumanEval | `humaneval` | 164 | Python function completion |
|
|
134
138
|
| HumanEval+ | `humaneval-plus` | 164 | HumanEval with expanded EvalPlus tests |
|
|
139
|
+
| HumanEval+ TR | `humaneval-plus-tr` | 164 | HumanEval+ fully translated to Turkish, function and variable names included |
|
|
135
140
|
| MBPP | `mbpp` | 500 | Short Python programming tasks |
|
|
136
141
|
| MBPP+ | `mbpp-plus` | 378 | MBPP with expanded EvalPlus tests |
|
|
137
142
|
| GSM8K | `gsm8k` | 1,319 | Multi-step grade-school math |
|
|
@@ -51,8 +51,10 @@ cp .env.example .env
|
|
|
51
51
|
uv run benchkit
|
|
52
52
|
```
|
|
53
53
|
|
|
54
|
-
Set your server in
|
|
55
|
-
|
|
54
|
+
Set your server in `~/.config/benchkit/.env` to use it from any folder, in a
|
|
55
|
+
`.env` in the directory you run `benchkit` from (parent directories are not
|
|
56
|
+
searched), or on the Connect screen, where "Save as default" writes the user
|
|
57
|
+
config for you:
|
|
56
58
|
|
|
57
59
|
```env
|
|
58
60
|
BENCHKIT_PROVIDER=openai
|
|
@@ -67,6 +69,8 @@ BENCHKIT_PROVIDER=ollama
|
|
|
67
69
|
OLLAMA_HOST=http://localhost:11434
|
|
68
70
|
```
|
|
69
71
|
|
|
72
|
+
`benchkit config` shows every setting and where it came from.
|
|
73
|
+
|
|
70
74
|
No inference server available? Explore the complete UI offline:
|
|
71
75
|
|
|
72
76
|
```bash
|
|
@@ -114,6 +118,7 @@ uv run benchkit --help
|
|
|
114
118
|
| Aider Polyglot | `aider-polyglot` | 225 | Repository editing across six languages with Pi |
|
|
115
119
|
| HumanEval | `humaneval` | 164 | Python function completion |
|
|
116
120
|
| HumanEval+ | `humaneval-plus` | 164 | HumanEval with expanded EvalPlus tests |
|
|
121
|
+
| HumanEval+ TR | `humaneval-plus-tr` | 164 | HumanEval+ fully translated to Turkish, function and variable names included |
|
|
117
122
|
| MBPP | `mbpp` | 500 | Short Python programming tasks |
|
|
118
123
|
| MBPP+ | `mbpp-plus` | 378 | MBPP with expanded EvalPlus tests |
|
|
119
124
|
| GSM8K | `gsm8k` | 1,319 | Multi-step grade-school math |
|
|
@@ -6,7 +6,7 @@ from benchkit.benchmarks.banking77 import Banking77
|
|
|
6
6
|
from benchkit.benchmarks.boolq import BoolQ
|
|
7
7
|
from benchkit.benchmarks.chartqa import ChartQA
|
|
8
8
|
from benchkit.benchmarks.code_verifier import CodeVerifier
|
|
9
|
-
from benchkit.benchmarks.evalplus import HumanEvalPlus, MBPPPlus
|
|
9
|
+
from benchkit.benchmarks.evalplus import HumanEvalPlus, HumanEvalPlusTR, MBPPPlus
|
|
10
10
|
from benchkit.benchmarks.git_surgery import GitSurgery
|
|
11
11
|
from benchkit.benchmarks.gpqa import GPQA
|
|
12
12
|
from benchkit.benchmarks.gsm8k import GSM8K
|
|
@@ -41,6 +41,7 @@ REGISTRY: dict[str, type] = {
|
|
|
41
41
|
"treejs-arena": TreeJSArena,
|
|
42
42
|
"humaneval": HumanEval,
|
|
43
43
|
"humaneval-plus": HumanEvalPlus,
|
|
44
|
+
"humaneval-plus-tr": HumanEvalPlusTR,
|
|
44
45
|
"mbpp": MBPP,
|
|
45
46
|
"mbpp-plus": MBPPPlus,
|
|
46
47
|
"gsm8k": GSM8K,
|
|
@@ -78,6 +79,7 @@ DESCRIPTIONS: dict[str, str] = {
|
|
|
78
79
|
"sanity": "25 curated checks across code, math, instructions, science, and commonsense",
|
|
79
80
|
"humaneval": "Python function completions with the original unit tests",
|
|
80
81
|
"humaneval-plus": "HumanEval with 122k+ tougher EvalPlus test inputs",
|
|
82
|
+
"humaneval-plus-tr": "HumanEval+ fully translated to Turkish, names included",
|
|
81
83
|
"mbpp": "short Python functions from natural-language specifications",
|
|
82
84
|
"mbpp-plus": "sanitized MBPP tasks with 39k+ EvalPlus test inputs",
|
|
83
85
|
"gsm8k": "multi-step grade-school math problems with exact numeric answers",
|
|
@@ -164,3 +164,14 @@ MMLU_PRO = RemoteFile(
|
|
|
164
164
|
sha256="92ec532d9e2bae342ec7256005c20b6e5defbed76504280df775fb77068f077e",
|
|
165
165
|
size=10_260_787,
|
|
166
166
|
)
|
|
167
|
+
|
|
168
|
+
# Pinned to a dataset commit on the Hub; the sha256 covers the exact bytes.
|
|
169
|
+
HUMANEVAL_PLUS_TR = RemoteFile(
|
|
170
|
+
name="humanevalplus_tr.jsonl",
|
|
171
|
+
url=(
|
|
172
|
+
"https://huggingface.co/datasets/DogukanUrker/HumanEvalPlus-TR/resolve/"
|
|
173
|
+
"e424171b8934581819fcdeddace2af28a664966f/humanevalplus_tr.jsonl"
|
|
174
|
+
),
|
|
175
|
+
sha256="072172a4d7934b8ce27d8ad0c83b139b80296876bd2f8a8afad1476bdaa97955",
|
|
176
|
+
size=7_635_249,
|
|
177
|
+
)
|
|
@@ -3,23 +3,33 @@
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
5
|
import contextlib
|
|
6
|
+
import json
|
|
6
7
|
import multiprocessing
|
|
7
8
|
import os
|
|
8
9
|
import platform
|
|
10
|
+
import shutil
|
|
11
|
+
import tempfile
|
|
9
12
|
import textwrap
|
|
10
13
|
from functools import cache, lru_cache
|
|
11
14
|
from pathlib import Path
|
|
12
15
|
from typing import Any
|
|
13
16
|
|
|
14
17
|
from benchkit.benchmarks.base import Task
|
|
15
|
-
from benchkit.benchmarks.downloads import Dataset
|
|
18
|
+
from benchkit.benchmarks.downloads import HUMANEVAL_PLUS_TR, Dataset
|
|
16
19
|
from benchkit.benchmarks.utils import strip_think_tags
|
|
20
|
+
from benchkit.executor import sandbox_env
|
|
17
21
|
|
|
18
22
|
HUMANEVAL_SYSTEM = (
|
|
19
23
|
"Complete the following Python function. "
|
|
20
24
|
"Output ONLY the function body. "
|
|
21
25
|
"No markdown fences, no explanation, no examples."
|
|
22
26
|
)
|
|
27
|
+
# Full Turkish translation, ASCII only like the dataset itself.
|
|
28
|
+
HUMANEVAL_TR_SYSTEM = (
|
|
29
|
+
"Asagidaki Python fonksiyonunu tamamla. "
|
|
30
|
+
"YALNIZCA fonksiyon govdesini yaz. "
|
|
31
|
+
"Markdown blogu, aciklama veya ornek ekleme."
|
|
32
|
+
)
|
|
23
33
|
MBPP_SYSTEM = (
|
|
24
34
|
"Write a Python function to solve the following task. "
|
|
25
35
|
"Output ONLY the function. "
|
|
@@ -43,10 +53,29 @@ def _fork_multiprocessing():
|
|
|
43
53
|
|
|
44
54
|
EvalPlus's ``evalplus.eval`` does ``from multiprocessing import Array, Value``
|
|
45
55
|
so those names are bound on that module and must be patched there as well.
|
|
56
|
+
|
|
57
|
+
The forked child runs model-written code, so it swaps its inherited
|
|
58
|
+
environment for a minimal one before running: API keys stay with the
|
|
59
|
+
parent. ``EVALPLUS_*`` is kept because the child reads its memory limit.
|
|
46
60
|
"""
|
|
47
61
|
import evalplus.eval as _ev
|
|
48
62
|
|
|
49
63
|
fork_ctx = multiprocessing.get_context("fork")
|
|
64
|
+
|
|
65
|
+
class _ScrubbedProcess(fork_ctx.Process):
|
|
66
|
+
def run(self) -> None:
|
|
67
|
+
# EvalPlus's reliability guard disables shutil.rmtree in the child.
|
|
68
|
+
rmtree = shutil.rmtree
|
|
69
|
+
home = tempfile.mkdtemp(prefix="benchkit-evalplus-")
|
|
70
|
+
env = sandbox_env(home, keep_prefixes=("EVALPLUS_",))
|
|
71
|
+
os.environ.clear()
|
|
72
|
+
os.environ.update(env)
|
|
73
|
+
tempfile.tempdir = None
|
|
74
|
+
try:
|
|
75
|
+
super().run()
|
|
76
|
+
finally:
|
|
77
|
+
rmtree(home, ignore_errors=True)
|
|
78
|
+
|
|
50
79
|
mp_originals = (
|
|
51
80
|
multiprocessing.Process,
|
|
52
81
|
multiprocessing.Value,
|
|
@@ -54,7 +83,7 @@ def _fork_multiprocessing():
|
|
|
54
83
|
)
|
|
55
84
|
ev_originals = (_ev.Value, _ev.Array)
|
|
56
85
|
try:
|
|
57
|
-
multiprocessing.Process =
|
|
86
|
+
multiprocessing.Process = _ScrubbedProcess
|
|
58
87
|
multiprocessing.Value = fork_ctx.Value
|
|
59
88
|
multiprocessing.Array = fork_ctx.Array
|
|
60
89
|
_ev.Value = fork_ctx.Value
|
|
@@ -96,9 +125,14 @@ def _evalplus_api():
|
|
|
96
125
|
)
|
|
97
126
|
|
|
98
127
|
|
|
99
|
-
@lru_cache(maxsize=
|
|
128
|
+
@lru_cache(maxsize=3)
|
|
100
129
|
def _problems(dataset: str) -> dict[str, dict[str, Any]]:
|
|
101
130
|
get_human_eval_plus, get_mbpp_plus, *_ = _evalplus_api()
|
|
131
|
+
if dataset == "humaneval-tr":
|
|
132
|
+
# Same schema as HumanEvalPlus.jsonl: translated prompt, entry point,
|
|
133
|
+
# canonical solution and contract, original inputs and tolerances.
|
|
134
|
+
rows = HUMANEVAL_PLUS_TR.ensure().read_text(encoding="utf-8").splitlines()
|
|
135
|
+
return {row["task_id"]: row for row in map(json.loads, filter(None, rows))}
|
|
102
136
|
if dataset == "humaneval":
|
|
103
137
|
return get_human_eval_plus()
|
|
104
138
|
if dataset == "mbpp":
|
|
@@ -253,14 +287,14 @@ class _EvalPlusBenchmark:
|
|
|
253
287
|
def evaluate(self, task: Task, response: str) -> bool:
|
|
254
288
|
*_, pass_status, _, check_correctness, _ = _evalplus_api()
|
|
255
289
|
problem = _problems(self.dataset)[task.id]
|
|
256
|
-
if self.dataset
|
|
290
|
+
if self.dataset.startswith("humaneval"):
|
|
257
291
|
solution = _human_solution(problem, response)
|
|
258
292
|
else:
|
|
259
293
|
solution = _extract_code(response)
|
|
260
294
|
|
|
261
295
|
with _fork_multiprocessing():
|
|
262
296
|
result = check_correctness(
|
|
263
|
-
self.dataset,
|
|
297
|
+
"mbpp" if self.dataset == "mbpp" else "humaneval",
|
|
264
298
|
completion_id=0,
|
|
265
299
|
problem=problem,
|
|
266
300
|
solution=solution,
|
|
@@ -280,6 +314,16 @@ class HumanEvalPlus(_EvalPlusBenchmark):
|
|
|
280
314
|
)
|
|
281
315
|
|
|
282
316
|
|
|
317
|
+
class HumanEvalPlusTR(_EvalPlusBenchmark):
|
|
318
|
+
name = "humaneval-plus-tr"
|
|
319
|
+
dataset = "humaneval-tr"
|
|
320
|
+
task_count = 164
|
|
321
|
+
system = HUMANEVAL_TR_SYSTEM
|
|
322
|
+
data_source = HUMANEVAL_PLUS_TR.source(
|
|
323
|
+
"HumanEval+ fully translated to Turkish (docstrings and identifiers)"
|
|
324
|
+
)
|
|
325
|
+
|
|
326
|
+
|
|
283
327
|
class MBPPPlus(_EvalPlusBenchmark):
|
|
284
328
|
name = "mbpp-plus"
|
|
285
329
|
dataset = "mbpp"
|
|
@@ -9,13 +9,13 @@ from __future__ import annotations
|
|
|
9
9
|
import argparse
|
|
10
10
|
import sys
|
|
11
11
|
|
|
12
|
-
from dotenv import load_dotenv
|
|
13
12
|
from rich import box
|
|
14
13
|
from rich.console import Console
|
|
14
|
+
from rich.markup import escape
|
|
15
15
|
from rich.table import Table
|
|
16
16
|
from rich.text import Text
|
|
17
17
|
|
|
18
|
-
from benchkit import catalog
|
|
18
|
+
from benchkit import catalog, config
|
|
19
19
|
from benchkit.benchmarks import DESCRIPTIONS, REGISTRY
|
|
20
20
|
from benchkit.client import InferenceClient
|
|
21
21
|
from benchkit.engine import (
|
|
@@ -60,11 +60,11 @@ def _parse_args(argv: list[str]) -> argparse.Namespace:
|
|
|
60
60
|
parser.add_argument(
|
|
61
61
|
"command",
|
|
62
62
|
nargs="?",
|
|
63
|
-
choices=("perf", "history", "render-check", "datasets"),
|
|
63
|
+
choices=("perf", "history", "render-check", "datasets", "config"),
|
|
64
64
|
help=(
|
|
65
65
|
"Run a performance profile, browse historical results, check "
|
|
66
|
-
"that headless rendering works on this machine,
|
|
67
|
-
"install benchmark datasets"
|
|
66
|
+
"that headless rendering works on this machine, list and "
|
|
67
|
+
"install benchmark datasets, or show the effective configuration"
|
|
68
68
|
),
|
|
69
69
|
)
|
|
70
70
|
parser.add_argument(
|
|
@@ -73,7 +73,8 @@ def _parse_args(argv: list[str]) -> argparse.Namespace:
|
|
|
73
73
|
metavar="MODEL",
|
|
74
74
|
help=(
|
|
75
75
|
"Model name for `benchkit perf MODEL`; `install` for "
|
|
76
|
-
"`benchkit datasets install [BENCHMARK ...]`"
|
|
76
|
+
"`benchkit datasets install [BENCHMARK ...]`; `path` for "
|
|
77
|
+
"`benchkit config path`"
|
|
77
78
|
),
|
|
78
79
|
)
|
|
79
80
|
parser.add_argument(
|
|
@@ -83,6 +84,15 @@ def _parse_args(argv: list[str]) -> argparse.Namespace:
|
|
|
83
84
|
help="Datasets: benchmarks to install (default: every missing one)",
|
|
84
85
|
)
|
|
85
86
|
parser.add_argument("--host", help="Inference host, overrides BENCHKIT_HOST")
|
|
87
|
+
parser.add_argument(
|
|
88
|
+
"--env-file",
|
|
89
|
+
metavar="PATH",
|
|
90
|
+
help=(
|
|
91
|
+
"Read settings from PATH instead of ./.env (also BENCHKIT_ENV_FILE). "
|
|
92
|
+
"Precedence: flags > environment > --env-file or ./.env > "
|
|
93
|
+
"~/.config/benchkit/.env ($XDG_CONFIG_HOME) > defaults"
|
|
94
|
+
),
|
|
95
|
+
)
|
|
86
96
|
parser.add_argument(
|
|
87
97
|
"--demo",
|
|
88
98
|
action="store_true",
|
|
@@ -956,11 +966,40 @@ def _perf(args: argparse.Namespace) -> None:
|
|
|
956
966
|
)
|
|
957
967
|
|
|
958
968
|
|
|
969
|
+
def _config(args: argparse.Namespace) -> None:
|
|
970
|
+
if args.perf_model == "path":
|
|
971
|
+
for entry in config.loaded().files:
|
|
972
|
+
if entry.skipped:
|
|
973
|
+
state = f"[dim]{entry.skipped}[/dim]"
|
|
974
|
+
elif entry.exists:
|
|
975
|
+
state = "[green]found[/green]"
|
|
976
|
+
else:
|
|
977
|
+
state = "[dim]missing[/dim]"
|
|
978
|
+
console.print(f"{entry.role:<18} {escape(str(entry.path))} {state}")
|
|
979
|
+
return
|
|
980
|
+
if args.perf_model is not None:
|
|
981
|
+
console.print(
|
|
982
|
+
f"[red]Unknown config action {escape(repr(args.perf_model))}.[/red]"
|
|
983
|
+
)
|
|
984
|
+
sys.exit(1)
|
|
985
|
+
|
|
986
|
+
table = Table(box=box.SIMPLE_HEAD, header_style="bold")
|
|
987
|
+
table.add_column("Setting")
|
|
988
|
+
table.add_column("Value")
|
|
989
|
+
table.add_column("Origin", style="dim")
|
|
990
|
+
for key, value, origin in config.resolve({"BENCHKIT_HOST": args.host}):
|
|
991
|
+
shown = Text(value) if value else Text("-", style="dim")
|
|
992
|
+
table.add_row(key, shown, Text(origin))
|
|
993
|
+
console.print(table)
|
|
994
|
+
|
|
995
|
+
|
|
959
996
|
def main(argv: list[str] | None = None) -> None:
|
|
960
|
-
# Only the working directory's .env: walking up to parent directories would
|
|
961
|
-
# let a file in a shared parent such as /tmp redirect the host and API key.
|
|
962
|
-
load_dotenv(".env")
|
|
963
997
|
args = _parse_args(sys.argv[1:] if argv is None else argv)
|
|
998
|
+
try:
|
|
999
|
+
config.load(args.env_file)
|
|
1000
|
+
except config.ConfigError as exc:
|
|
1001
|
+
console.print(f"[red]{exc}[/red]")
|
|
1002
|
+
sys.exit(2)
|
|
964
1003
|
|
|
965
1004
|
if args.list:
|
|
966
1005
|
_list_benchmarks()
|
|
@@ -974,6 +1013,10 @@ def main(argv: list[str] | None = None) -> None:
|
|
|
974
1013
|
_datasets(args)
|
|
975
1014
|
return
|
|
976
1015
|
|
|
1016
|
+
if args.command == "config":
|
|
1017
|
+
_config(args)
|
|
1018
|
+
return
|
|
1019
|
+
|
|
977
1020
|
if args.command == "perf":
|
|
978
1021
|
_perf(args)
|
|
979
1022
|
return
|
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
"""Layered configuration: which settings apply, and where each one came from.
|
|
2
|
+
|
|
3
|
+
Precedence, highest first: CLI flags, real environment variables,
|
|
4
|
+
``--env-file PATH`` (or ``BENCHKIT_ENV_FILE``), ``./.env`` in the working
|
|
5
|
+
directory, the user config ``$XDG_CONFIG_HOME/benchkit/.env`` (default
|
|
6
|
+
``~/.config/benchkit/.env``), then built-in defaults. An explicit env file
|
|
7
|
+
replaces ``./.env`` rather than stacking on it.
|
|
8
|
+
|
|
9
|
+
Only BenchKit's own keys are applied from any file, so running inside another
|
|
10
|
+
project never imports that project's secrets. Parent directories are never
|
|
11
|
+
searched: a ``.env`` in a shared parent such as ``/tmp`` could otherwise
|
|
12
|
+
redirect the host and API key.
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
from __future__ import annotations
|
|
16
|
+
|
|
17
|
+
import os
|
|
18
|
+
from collections.abc import MutableMapping
|
|
19
|
+
from dataclasses import dataclass, field
|
|
20
|
+
from pathlib import Path
|
|
21
|
+
|
|
22
|
+
from dotenv import dotenv_values, set_key, unset_key
|
|
23
|
+
|
|
24
|
+
from benchkit.client import DEFAULT_HOST
|
|
25
|
+
|
|
26
|
+
ENV_FILE_VAR = "BENCHKIT_ENV_FILE"
|
|
27
|
+
_PREFIXES = ("BENCHKIT_", "EVALPLUS_")
|
|
28
|
+
_NAMES = frozenset({"OLLAMA_HOST", "OPENAI_API_KEY", "OPENAI_BASE_URL"})
|
|
29
|
+
_SECRET_SUFFIXES = ("_API_KEY", "_TOKEN", "_SECRET", "_PASSWORD")
|
|
30
|
+
|
|
31
|
+
# Settings `benchkit config` always lists, with the default each falls back to
|
|
32
|
+
# ("" when unset simply means "not used"). Internal variables the harness sets
|
|
33
|
+
# for its own child processes are left out.
|
|
34
|
+
# fmt: off
|
|
35
|
+
SETTINGS: tuple[tuple[str, str], ...] = (
|
|
36
|
+
("BENCHKIT_PROVIDER", "auto"),
|
|
37
|
+
("BENCHKIT_HOST", DEFAULT_HOST),
|
|
38
|
+
("OPENAI_BASE_URL", ""),
|
|
39
|
+
("OLLAMA_HOST", ""),
|
|
40
|
+
("BENCHKIT_API_KEY", ""),
|
|
41
|
+
("OPENAI_API_KEY", ""),
|
|
42
|
+
("BENCHKIT_TIMEOUT", "300"),
|
|
43
|
+
("BENCHKIT_CONCURRENCY", ""),
|
|
44
|
+
("BENCHKIT_HARDWARE", ""),
|
|
45
|
+
("BENCHKIT_PERF_CONFIG", ""),
|
|
46
|
+
("BENCHKIT_RETRIES", "3"),
|
|
47
|
+
("BENCHKIT_CONNECT_RETRIES", "6"),
|
|
48
|
+
("BENCHKIT_RETRY_BASE_DELAY", "0.5"),
|
|
49
|
+
("BENCHKIT_RETRY_MAX_DELAY", "8"),
|
|
50
|
+
("BENCHKIT_RETRY_MAX_WAIT", "60"),
|
|
51
|
+
("BENCHKIT_LOOP_KILL", "true"),
|
|
52
|
+
("BENCHKIT_LOOP_KILL_PERCENT", "80"),
|
|
53
|
+
("BENCHKIT_LOOP_KILL_SECONDS", "10"),
|
|
54
|
+
("BENCHKIT_PI_TIMEOUT", "900"),
|
|
55
|
+
("BENCHKIT_DOCKER", "docker"),
|
|
56
|
+
("BENCHKIT_SANDBOX_MEMORY", "2g"),
|
|
57
|
+
("BENCHKIT_SANDBOX_CPUS", "2"),
|
|
58
|
+
("BENCHKIT_SANDBOX_PIDS", ""),
|
|
59
|
+
("BENCHKIT_MC_ARENA_MEMORY", "512m"),
|
|
60
|
+
("BENCHKIT_MC_ARENA_CPUS", "1"),
|
|
61
|
+
("BENCHKIT_MC_ARENA_PIDS", "64"),
|
|
62
|
+
("BENCHKIT_MC_ARENA_BASE_IMAGE", ""),
|
|
63
|
+
("BENCHKIT_MC_ARENA_IMAGE", ""),
|
|
64
|
+
("BENCHKIT_RENDER_SETTLE", "4"),
|
|
65
|
+
("BENCHKIT_RENDER_TIMEOUT", "30"),
|
|
66
|
+
("BENCHKIT_RENDER_ALLOWED_HOSTS", ""),
|
|
67
|
+
("BENCHKIT_RENDER_OFFLINE", "false"),
|
|
68
|
+
("BENCHKIT_RENDER_CHROMIUM", ""),
|
|
69
|
+
("BENCHKIT_RENDER_NO_SANDBOX", "false"),
|
|
70
|
+
("BENCHKIT_DATASET_CACHE", ""),
|
|
71
|
+
("BENCHKIT_VISION_CACHE", ""),
|
|
72
|
+
("BENCHKIT_PATCHEVAL_DATASET", ""),
|
|
73
|
+
("BENCHKIT_AIDER_DATASET", ""),
|
|
74
|
+
)
|
|
75
|
+
# fmt: on
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
class ConfigError(Exception):
|
|
79
|
+
"""A configuration source was named but cannot be used."""
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
@dataclass(frozen=True)
|
|
83
|
+
class EnvFile:
|
|
84
|
+
"""One file BenchKit considered, in precedence order."""
|
|
85
|
+
|
|
86
|
+
path: Path
|
|
87
|
+
role: str
|
|
88
|
+
exists: bool
|
|
89
|
+
skipped: str = ""
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
@dataclass
|
|
93
|
+
class Loaded:
|
|
94
|
+
"""The files considered and the origin of every BenchKit key applied."""
|
|
95
|
+
|
|
96
|
+
files: list[EnvFile] = field(default_factory=list)
|
|
97
|
+
origins: dict[str, str] = field(default_factory=dict)
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
_loaded = Loaded()
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
def is_benchkit_key(key: str) -> bool:
|
|
104
|
+
return key.startswith(_PREFIXES) or key in _NAMES
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
def is_secret(key: str) -> bool:
|
|
108
|
+
return key.endswith(_SECRET_SUFFIXES)
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
def mask(value: str) -> str:
|
|
112
|
+
"""Hide a secret, keeping the last four characters of a long one."""
|
|
113
|
+
if not value:
|
|
114
|
+
return ""
|
|
115
|
+
if len(value) <= 8:
|
|
116
|
+
return "****"
|
|
117
|
+
return "****" + value[-4:]
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
def user_config_dir(environ: MutableMapping[str, str] | None = None) -> Path:
|
|
121
|
+
environ = os.environ if environ is None else environ
|
|
122
|
+
base = environ.get("XDG_CONFIG_HOME") or ""
|
|
123
|
+
root = Path(base).expanduser() if base else Path("~/.config").expanduser()
|
|
124
|
+
return root / "benchkit"
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
def user_env_path(environ: MutableMapping[str, str] | None = None) -> Path:
|
|
128
|
+
return user_config_dir(environ) / ".env"
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
def load(
|
|
132
|
+
env_file: str | None = None,
|
|
133
|
+
*,
|
|
134
|
+
environ: MutableMapping[str, str] | None = None,
|
|
135
|
+
cwd: Path | None = None,
|
|
136
|
+
) -> Loaded:
|
|
137
|
+
"""Apply BenchKit keys from the config files into ``environ``.
|
|
138
|
+
|
|
139
|
+
A key already in the environment is never overwritten, and a file only
|
|
140
|
+
fills keys that no higher file set. Raises ``ConfigError`` when an
|
|
141
|
+
explicit env file does not exist.
|
|
142
|
+
"""
|
|
143
|
+
global _loaded
|
|
144
|
+
environ = os.environ if environ is None else environ
|
|
145
|
+
cwd = Path.cwd() if cwd is None else cwd
|
|
146
|
+
|
|
147
|
+
files: list[EnvFile] = []
|
|
148
|
+
project = cwd / ".env"
|
|
149
|
+
explicit, role = env_file, "--env-file"
|
|
150
|
+
if not explicit and environ.get(ENV_FILE_VAR):
|
|
151
|
+
explicit, role = environ[ENV_FILE_VAR], ENV_FILE_VAR
|
|
152
|
+
if explicit:
|
|
153
|
+
path = Path(explicit).expanduser()
|
|
154
|
+
if not path.is_absolute():
|
|
155
|
+
path = cwd / path
|
|
156
|
+
if not path.is_file():
|
|
157
|
+
raise ConfigError(f"{role}: no such file: {path}")
|
|
158
|
+
files.append(EnvFile(path, role, True))
|
|
159
|
+
files.append(
|
|
160
|
+
EnvFile(
|
|
161
|
+
project, "project", project.is_file(), skipped=f"replaced by {role}"
|
|
162
|
+
)
|
|
163
|
+
)
|
|
164
|
+
else:
|
|
165
|
+
files.append(EnvFile(project, "project", project.is_file()))
|
|
166
|
+
user = user_env_path(environ)
|
|
167
|
+
files.append(EnvFile(user, "user", user.is_file()))
|
|
168
|
+
|
|
169
|
+
origins = {key: "env" for key in environ if is_benchkit_key(key)}
|
|
170
|
+
for entry in files:
|
|
171
|
+
if not entry.exists or entry.skipped:
|
|
172
|
+
continue
|
|
173
|
+
for key, value in dotenv_values(entry.path).items():
|
|
174
|
+
if value is None or key == ENV_FILE_VAR or not is_benchkit_key(key):
|
|
175
|
+
continue
|
|
176
|
+
if key in origins:
|
|
177
|
+
continue
|
|
178
|
+
environ[key] = value
|
|
179
|
+
origins[key] = str(entry.path)
|
|
180
|
+
|
|
181
|
+
_loaded = Loaded(files, origins)
|
|
182
|
+
return _loaded
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
def loaded() -> Loaded:
|
|
186
|
+
"""What the last ``load`` applied (empty before the first call)."""
|
|
187
|
+
return _loaded
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
def resolve(
|
|
191
|
+
flags: dict[str, str | None] | None = None,
|
|
192
|
+
*,
|
|
193
|
+
environ: MutableMapping[str, str] | None = None,
|
|
194
|
+
) -> list[tuple[str, str, str]]:
|
|
195
|
+
"""Every known or set BenchKit key as ``(key, value, origin)``.
|
|
196
|
+
|
|
197
|
+
``value`` is masked for secrets. ``origin`` is ``flag``, ``env``, the file
|
|
198
|
+
path the value came from, or ``default``.
|
|
199
|
+
"""
|
|
200
|
+
environ = os.environ if environ is None else environ
|
|
201
|
+
flags = {key: value for key, value in (flags or {}).items() if value}
|
|
202
|
+
defaults = dict(SETTINGS)
|
|
203
|
+
extra = sorted(
|
|
204
|
+
key
|
|
205
|
+
for key in environ
|
|
206
|
+
if is_benchkit_key(key) and key not in defaults and key != ENV_FILE_VAR
|
|
207
|
+
)
|
|
208
|
+
rows = []
|
|
209
|
+
for key in [*defaults, *extra]:
|
|
210
|
+
if key in flags:
|
|
211
|
+
value, origin = flags[key], "flag"
|
|
212
|
+
elif key in environ:
|
|
213
|
+
value, origin = environ[key], _loaded.origins.get(key, "env")
|
|
214
|
+
else:
|
|
215
|
+
value, origin = defaults.get(key, ""), "default"
|
|
216
|
+
rows.append((key, mask(value) if is_secret(key) else value, origin))
|
|
217
|
+
return rows
|
|
218
|
+
|
|
219
|
+
|
|
220
|
+
def save_user(
|
|
221
|
+
values: dict[str, str | None],
|
|
222
|
+
*,
|
|
223
|
+
environ: MutableMapping[str, str] | None = None,
|
|
224
|
+
) -> Path:
|
|
225
|
+
"""Write ``values`` to the user config; ``None`` or ``""`` removes a key.
|
|
226
|
+
|
|
227
|
+
The file can hold an API key, so it is created readable by its owner only.
|
|
228
|
+
"""
|
|
229
|
+
path = user_env_path(environ)
|
|
230
|
+
path.parent.mkdir(parents=True, exist_ok=True, mode=0o700)
|
|
231
|
+
if not path.exists():
|
|
232
|
+
path.touch(mode=0o600)
|
|
233
|
+
present = dotenv_values(path)
|
|
234
|
+
for key, value in values.items():
|
|
235
|
+
if not is_benchkit_key(key):
|
|
236
|
+
raise ValueError(f"not a BenchKit setting: {key}")
|
|
237
|
+
if value:
|
|
238
|
+
set_key(path, key, value, quote_mode="auto")
|
|
239
|
+
elif key in present:
|
|
240
|
+
unset_key(path, key, quote_mode="auto")
|
|
241
|
+
return path
|
|
242
|
+
|
|
243
|
+
|
|
244
|
+
def overridden(keys: list[str]) -> dict[str, str]:
|
|
245
|
+
"""Keys whose current value comes from somewhere above the user config."""
|
|
246
|
+
user = str(user_env_path())
|
|
247
|
+
return {
|
|
248
|
+
key: origin
|
|
249
|
+
for key in keys
|
|
250
|
+
if (origin := _loaded.origins.get(key)) is not None and origin != user
|
|
251
|
+
}
|