featurebench 0.2.1__tar.gz → 0.2.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.
- {featurebench-0.2.1 → featurebench-0.2.2}/PKG-INFO +6 -3
- {featurebench-0.2.1 → featurebench-0.2.2}/README.md +4 -1
- {featurebench-0.2.1 → featurebench-0.2.2}/config_example.toml +9 -1
- {featurebench-0.2.1 → featurebench-0.2.2}/docs/config.md +14 -2
- {featurebench-0.2.1 → featurebench-0.2.2}/docs/harness_cli_arg.md +5 -0
- {featurebench-0.2.1 → featurebench-0.2.2}/docs/infer_cli_arg.md +8 -1
- {featurebench-0.2.1 → featurebench-0.2.2}/featurebench/cli.py +2 -2
- {featurebench-0.2.1 → featurebench-0.2.2}/featurebench/harness/run_evaluation.py +81 -9
- {featurebench-0.2.1 → featurebench-0.2.2}/featurebench/infer/agents/mini_swe_agent.py +16 -0
- {featurebench-0.2.1 → featurebench-0.2.2}/featurebench/infer/config.py +90 -11
- {featurebench-0.2.1 → featurebench-0.2.2}/featurebench/infer/models.py +8 -1
- {featurebench-0.2.1 → featurebench-0.2.2}/featurebench/infer/run_infer.py +56 -6
- {featurebench-0.2.1 → featurebench-0.2.2}/pyproject.toml +1 -1
- featurebench-0.2.2/tests/test_dataset_version.py +212 -0
- {featurebench-0.2.1 → featurebench-0.2.2}/uv.lock +1 -1
- {featurebench-0.2.1 → featurebench-0.2.2}/.gitignore +0 -0
- {featurebench-0.2.1 → featurebench-0.2.2}/.python-version +0 -0
- {featurebench-0.2.1 → featurebench-0.2.2}/LICENSE +0 -0
- {featurebench-0.2.1 → featurebench-0.2.2}/docs/pics/logo.png +0 -0
- {featurebench-0.2.1 → featurebench-0.2.2}/docs/pics/workflow.png +0 -0
- {featurebench-0.2.1 → featurebench-0.2.2}/docs/pipeline.md +0 -0
- {featurebench-0.2.1 → featurebench-0.2.2}/featurebench/__init__.py +0 -0
- {featurebench-0.2.1 → featurebench-0.2.2}/featurebench/classification/__init__.py +0 -0
- {featurebench-0.2.1 → featurebench-0.2.2}/featurebench/classification/code_classifier.py +0 -0
- {featurebench-0.2.1 → featurebench-0.2.2}/featurebench/classification/file_analyzer.py +0 -0
- {featurebench-0.2.1 → featurebench-0.2.2}/featurebench/classification/llm_top_classifier.py +0 -0
- {featurebench-0.2.1 → featurebench-0.2.2}/featurebench/classification/p2p_chooser.py +0 -0
- {featurebench-0.2.1 → featurebench-0.2.2}/featurebench/conversion/__init__.py +0 -0
- {featurebench-0.2.1 → featurebench-0.2.2}/featurebench/conversion/case_converter.py +0 -0
- {featurebench-0.2.1 → featurebench-0.2.2}/featurebench/conversion/eval_code.py +0 -0
- {featurebench-0.2.1 → featurebench-0.2.2}/featurebench/conversion/llm_prompt_generator.py +0 -0
- {featurebench-0.2.1 → featurebench-0.2.2}/featurebench/conversion/llm_testfile_adjuster.py +0 -0
- {featurebench-0.2.1 → featurebench-0.2.2}/featurebench/conversion/render_task.py +0 -0
- {featurebench-0.2.1 → featurebench-0.2.2}/featurebench/docker/__init__.py +0 -0
- {featurebench-0.2.1 → featurebench-0.2.2}/featurebench/docker/dynamic_tracer.py +0 -0
- {featurebench-0.2.1 → featurebench-0.2.2}/featurebench/docker/image_manager.py +0 -0
- {featurebench-0.2.1 → featurebench-0.2.2}/featurebench/docker/test_runner.py +0 -0
- {featurebench-0.2.1 → featurebench-0.2.2}/featurebench/docker/test_scanner.py +0 -0
- {featurebench-0.2.1 → featurebench-0.2.2}/featurebench/harness/__init__.py +0 -0
- {featurebench-0.2.1 → featurebench-0.2.2}/featurebench/harness/constants.py +0 -0
- {featurebench-0.2.1 → featurebench-0.2.2}/featurebench/harness/container.py +0 -0
- {featurebench-0.2.1 → featurebench-0.2.2}/featurebench/harness/grading.py +0 -0
- {featurebench-0.2.1 → featurebench-0.2.2}/featurebench/harness/report.py +0 -0
- {featurebench-0.2.1 → featurebench-0.2.2}/featurebench/harness/review_codes.py +0 -0
- {featurebench-0.2.1 → featurebench-0.2.2}/featurebench/harness/runtime.py +0 -0
- {featurebench-0.2.1 → featurebench-0.2.2}/featurebench/harness/test_parsers.py +0 -0
- {featurebench-0.2.1 → featurebench-0.2.2}/featurebench/harness/utils.py +0 -0
- {featurebench-0.2.1 → featurebench-0.2.2}/featurebench/infer/__init__.py +0 -0
- {featurebench-0.2.1 → featurebench-0.2.2}/featurebench/infer/agents/__init__.py +0 -0
- {featurebench-0.2.1 → featurebench-0.2.2}/featurebench/infer/agents/base.py +0 -0
- {featurebench-0.2.1 → featurebench-0.2.2}/featurebench/infer/agents/claude_code.py +0 -0
- {featurebench-0.2.1 → featurebench-0.2.2}/featurebench/infer/agents/codex.py +0 -0
- {featurebench-0.2.1 → featurebench-0.2.2}/featurebench/infer/agents/gemini_cli.py +0 -0
- {featurebench-0.2.1 → featurebench-0.2.2}/featurebench/infer/agents/openhands.py +0 -0
- {featurebench-0.2.1 → featurebench-0.2.2}/featurebench/infer/container.py +0 -0
- {featurebench-0.2.1 → featurebench-0.2.2}/featurebench/infer/gpu_scheduler.py +0 -0
- {featurebench-0.2.1 → featurebench-0.2.2}/featurebench/infer/output.py +0 -0
- {featurebench-0.2.1 → featurebench-0.2.2}/featurebench/infer/render_infer_log.py +0 -0
- {featurebench-0.2.1 → featurebench-0.2.2}/featurebench/infer/runtime.py +0 -0
- {featurebench-0.2.1 → featurebench-0.2.2}/featurebench/llm/__init__.py +0 -0
- {featurebench-0.2.1 → featurebench-0.2.2}/featurebench/llm/llm_caller.py +0 -0
- {featurebench-0.2.1 → featurebench-0.2.2}/featurebench/llm/llm_exceptions.py +0 -0
- {featurebench-0.2.1 → featurebench-0.2.2}/featurebench/mask/__init__.py +0 -0
- {featurebench-0.2.1 → featurebench-0.2.2}/featurebench/mask/mask_generator.py +0 -0
- {featurebench-0.2.1 → featurebench-0.2.2}/featurebench/mask/mask_validator.py +0 -0
- {featurebench-0.2.1 → featurebench-0.2.2}/featurebench/mask/signature_extractor.py +0 -0
- {featurebench-0.2.1 → featurebench-0.2.2}/featurebench/pipeline.py +0 -0
- {featurebench-0.2.1 → featurebench-0.2.2}/featurebench/post_verify/__init__.py +0 -0
- {featurebench-0.2.1 → featurebench-0.2.2}/featurebench/post_verify/f2p_validator.py +0 -0
- {featurebench-0.2.1 → featurebench-0.2.2}/featurebench/post_verify/level2_validator.py +0 -0
- {featurebench-0.2.1 → featurebench-0.2.2}/featurebench/post_verify/p2p_validator.py +0 -0
- {featurebench-0.2.1 → featurebench-0.2.2}/featurebench/resources/constants/fast_images.txt +0 -0
- {featurebench-0.2.1 → featurebench-0.2.2}/featurebench/resources/constants/full_images.txt +0 -0
- {featurebench-0.2.1 → featurebench-0.2.2}/featurebench/resources/constants/lite_images.txt +0 -0
- {featurebench-0.2.1 → featurebench-0.2.2}/featurebench/resources/constants/python_example.py +0 -0
- {featurebench-0.2.1 → featurebench-0.2.2}/featurebench/resources/dockerfiles/python310.py +0 -0
- {featurebench-0.2.1 → featurebench-0.2.2}/featurebench/resources/dockerfiles/python310_cu118_torch212.py +0 -0
- {featurebench-0.2.1 → featurebench-0.2.2}/featurebench/resources/dockerfiles/python310_cu121_torch251.py +0 -0
- {featurebench-0.2.1 → featurebench-0.2.2}/featurebench/resources/dockerfiles/python310_cu121_torch28.py +0 -0
- {featurebench-0.2.1 → featurebench-0.2.2}/featurebench/resources/dockerfiles/python311.py +0 -0
- {featurebench-0.2.1 → featurebench-0.2.2}/featurebench/resources/dockerfiles/python311_cu121_torch28.py +0 -0
- {featurebench-0.2.1 → featurebench-0.2.2}/featurebench/resources/dockerfiles/python312.py +0 -0
- {featurebench-0.2.1 → featurebench-0.2.2}/featurebench/resources/dockerfiles/python312_cu121_torch251.py +0 -0
- {featurebench-0.2.1 → featurebench-0.2.2}/featurebench/resources/dockerfiles/python312_cu121_torch26.py +0 -0
- {featurebench-0.2.1 → featurebench-0.2.2}/featurebench/resources/dockerfiles/python312_cu121_torch28.py +0 -0
- {featurebench-0.2.1 → featurebench-0.2.2}/featurebench/resources/dockerfiles/python312_torch251.py +0 -0
- {featurebench-0.2.1 → featurebench-0.2.2}/featurebench/resources/dockerfiles/python39.py +0 -0
- {featurebench-0.2.1 → featurebench-0.2.2}/featurebench/resources/scripts/dynamic_script/autograd_backward_patch.py +0 -0
- {featurebench-0.2.1 → featurebench-0.2.2}/featurebench/resources/scripts/dynamic_script/dynamic_script.py +0 -0
- {featurebench-0.2.1 → featurebench-0.2.2}/featurebench/resources/scripts/dynamic_script/import_hook_patch.py +0 -0
- {featurebench-0.2.1 → featurebench-0.2.2}/featurebench/resources/scripts/dynamic_script/joblib_patch.py +0 -0
- {featurebench-0.2.1 → featurebench-0.2.2}/featurebench/resources/scripts/dynamic_script/sitecustomize.py +0 -0
- {featurebench-0.2.1 → featurebench-0.2.2}/featurebench/resources/scripts/scanner_script.py +0 -0
- {featurebench-0.2.1 → featurebench-0.2.2}/featurebench/resources/templates/appendix.md.j2 +0 -0
- {featurebench-0.2.1 → featurebench-0.2.2}/featurebench/resources/templates/black_links.txt.j2 +0 -0
- {featurebench-0.2.1 → featurebench-0.2.2}/featurebench/resources/templates/config_template.yaml +0 -0
- {featurebench-0.2.1 → featurebench-0.2.2}/featurebench/resources/templates/level_1.j2 +0 -0
- {featurebench-0.2.1 → featurebench-0.2.2}/featurebench/resources/templates/level_2.j2 +0 -0
- {featurebench-0.2.1 → featurebench-0.2.2}/featurebench/resources/templates/llm_prompt_templates.yaml +0 -0
- {featurebench-0.2.1 → featurebench-0.2.2}/featurebench/scripts/cal_eval_outputs.py +0 -0
- {featurebench-0.2.1 → featurebench-0.2.2}/featurebench/scripts/post_filter_cases.py +0 -0
- {featurebench-0.2.1 → featurebench-0.2.2}/featurebench/scripts/pull_images.py +0 -0
- {featurebench-0.2.1 → featurebench-0.2.2}/featurebench/utils/__init__.py +0 -0
- {featurebench-0.2.1 → featurebench-0.2.2}/featurebench/utils/command_utils.py +0 -0
- {featurebench-0.2.1 → featurebench-0.2.2}/featurebench/utils/config.py +0 -0
- {featurebench-0.2.1 → featurebench-0.2.2}/featurebench/utils/docker_images.py +0 -0
- {featurebench-0.2.1 → featurebench-0.2.2}/featurebench/utils/logger.py +0 -0
- {featurebench-0.2.1 → featurebench-0.2.2}/featurebench/utils/parser/__init__.py +0 -0
- {featurebench-0.2.1 → featurebench-0.2.2}/featurebench/utils/parser/pytest_parser.py +0 -0
- {featurebench-0.2.1 → featurebench-0.2.2}/featurebench/utils/repo_manager.py +0 -0
- {featurebench-0.2.1 → featurebench-0.2.2}/featurebench/utils/storage.py +0 -0
- {featurebench-0.2.1 → featurebench-0.2.2}/featurebench/utils/utils.py +0 -0
- {featurebench-0.2.1 → featurebench-0.2.2}/featurebench/verified/__init__.py +0 -0
- {featurebench-0.2.1 → featurebench-0.2.2}/featurebench/verified/post_additions.py +0 -0
- {featurebench-0.2.1 → featurebench-0.2.2}/featurebench/verified/prompts/add_prompt_lv1.txt +0 -0
- {featurebench-0.2.1 → featurebench-0.2.2}/featurebench/verified/prompts/add_prompt_lv2.txt +0 -0
- {featurebench-0.2.1 → featurebench-0.2.2}/featurebench/verified/prompts/prompt_template_lv1.txt +0 -0
- {featurebench-0.2.1 → featurebench-0.2.2}/featurebench/verified/prompts/prompt_template_lv2.txt +0 -0
- {featurebench-0.2.1 → featurebench-0.2.2}/featurebench/verified/run_verification.py +0 -0
- {featurebench-0.2.1 → featurebench-0.2.2}/featurebench/verified/runner.py +0 -0
- {featurebench-0.2.1 → featurebench-0.2.2}/tests/test_eval_data_container_cleanup.py +0 -0
- {featurebench-0.2.1 → featurebench-0.2.2}/tests/test_infer_container_cleanup.py +0 -0
- {featurebench-0.2.1 → featurebench-0.2.2}/tests/test_openhands_session_cache.py +0 -0
- {featurebench-0.2.1 → featurebench-0.2.2}/tests/test_pull_images.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
2
|
Name: featurebench
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.2
|
|
4
4
|
Summary: FeatureBench Pipeline - A test-driven data generation pipeline for building and evaluating feature-level coding benchmarks
|
|
5
5
|
License-File: LICENSE
|
|
6
6
|
Requires-Python: >=3.12
|
|
@@ -41,6 +41,8 @@ It provides a unified CLI to run inference, evaluation, and dataset generation.
|
|
|
41
41
|
|
|
42
42
|
## 📰 News
|
|
43
43
|
|
|
44
|
+
📦 **2026.08.24**: We released **FeatureBench Dataset V1.1**, primarily correcting inconsistencies and omissions in task problem statements.
|
|
45
|
+
|
|
44
46
|
📊 **2026.05.18**: We added **lite split** evaluation results for frontier models including **GPT-5.5, Claude Opus 4.7, DeepSeek-V4, GLM-5.1, Kimi-2.6, Mimo-V2.5-Pro**, and more to the leaderboard.
|
|
45
47
|
|
|
46
48
|
🚀 **2026.03.27**: We released the **fast split** containing 100 instances (a subset of full split). These instances require no GPU and are optimized for rapid evaluation. On an Intel Xeon Platinum 8457C with 944GB RAM, the average evaluation time per instance using gold patches is **57.2 seconds**.
|
|
@@ -121,6 +123,7 @@ fb pull --mode /path/to/images.txt # one image name per line
|
|
|
121
123
|
```bash
|
|
122
124
|
fb infer \
|
|
123
125
|
--config-path config.toml \
|
|
126
|
+
--data-version v1.1 \
|
|
124
127
|
--agent mini_swe_agent \
|
|
125
128
|
--model openai/qwen3-coder-480b-a35b-instruct \
|
|
126
129
|
--split fast
|
|
@@ -156,4 +159,4 @@ If you found FeatureBench useful, please cite us as:
|
|
|
156
159
|
|
|
157
160
|
## 📧 Contact
|
|
158
161
|
|
|
159
|
-
If you have any questions, feel free to contact [
|
|
162
|
+
If you have any questions, feel free to contact [zhouqixing@stu.cqu.edu.cn](mailto:zhouqixing@stu.cqu.edu.cn) or [zjcheng2022@gmail.com](mailto:zjcheng2022@gmail.com).
|
|
@@ -17,6 +17,8 @@ It provides a unified CLI to run inference, evaluation, and dataset generation.
|
|
|
17
17
|
|
|
18
18
|
## 📰 News
|
|
19
19
|
|
|
20
|
+
📦 **2026.08.24**: We released **FeatureBench Dataset V1.1**, primarily correcting inconsistencies and omissions in task problem statements.
|
|
21
|
+
|
|
20
22
|
📊 **2026.05.18**: We added **lite split** evaluation results for frontier models including **GPT-5.5, Claude Opus 4.7, DeepSeek-V4, GLM-5.1, Kimi-2.6, Mimo-V2.5-Pro**, and more to the leaderboard.
|
|
21
23
|
|
|
22
24
|
🚀 **2026.03.27**: We released the **fast split** containing 100 instances (a subset of full split). These instances require no GPU and are optimized for rapid evaluation. On an Intel Xeon Platinum 8457C with 944GB RAM, the average evaluation time per instance using gold patches is **57.2 seconds**.
|
|
@@ -97,6 +99,7 @@ fb pull --mode /path/to/images.txt # one image name per line
|
|
|
97
99
|
```bash
|
|
98
100
|
fb infer \
|
|
99
101
|
--config-path config.toml \
|
|
102
|
+
--data-version v1.1 \
|
|
100
103
|
--agent mini_swe_agent \
|
|
101
104
|
--model openai/qwen3-coder-480b-a35b-instruct \
|
|
102
105
|
--split fast
|
|
@@ -132,4 +135,4 @@ If you found FeatureBench useful, please cite us as:
|
|
|
132
135
|
|
|
133
136
|
## 📧 Contact
|
|
134
137
|
|
|
135
|
-
If you have any questions, feel free to contact [
|
|
138
|
+
If you have any questions, feel free to contact [zhouqixing@stu.cqu.edu.cn](mailto:zhouqixing@stu.cqu.edu.cn) or [zjcheng2022@gmail.com](mailto:zjcheng2022@gmail.com).
|
|
@@ -6,6 +6,14 @@ HF_ENDPOINT=""
|
|
|
6
6
|
HF_TOKEN=""
|
|
7
7
|
GITHUB_TOKEN=""
|
|
8
8
|
|
|
9
|
+
# ==============================================================================
|
|
10
|
+
# Hugging Face Dataset
|
|
11
|
+
# ==============================================================================
|
|
12
|
+
[dataset]
|
|
13
|
+
# Dataset tag, branch, or commit SHA used by both `fb infer` and `fb eval`.
|
|
14
|
+
# The CLI flag `--data-version` overrides this value.
|
|
15
|
+
revision="v1.1"
|
|
16
|
+
|
|
9
17
|
# ==============================================================================
|
|
10
18
|
# DataPipeline Configuration
|
|
11
19
|
# ==============================================================================
|
|
@@ -109,4 +117,4 @@ MSWEA_BASE_URL = ""
|
|
|
109
117
|
# Optional: Cost tracking mode (default behavior in FB adapter is ignore_errors)
|
|
110
118
|
MSWEA_COST_TRACKING = ""
|
|
111
119
|
# Optional: Lock mini_swe_agent version (leave empty to use latest)
|
|
112
|
-
MINI_SWE_AGENT_VERSION = ""
|
|
120
|
+
MINI_SWE_AGENT_VERSION = ""
|
|
@@ -31,13 +31,25 @@ HF_TOKEN = ""
|
|
|
31
31
|
GITHUB_TOKEN = ""
|
|
32
32
|
```
|
|
33
33
|
|
|
34
|
+
### [dataset] (dataset version used by harness / infer)
|
|
35
|
+
|
|
36
|
+
```toml
|
|
37
|
+
[dataset]
|
|
38
|
+
revision = "v1.1"
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
- `revision`: Hugging Face dataset tag, branch, or commit SHA used by both
|
|
42
|
+
`fb infer` and `fb eval`. The default is `v1.1`.
|
|
43
|
+
- `--data-version` overrides this value for a single command.
|
|
44
|
+
|
|
34
45
|
---
|
|
35
46
|
|
|
36
47
|
## A. Harness
|
|
37
48
|
|
|
38
49
|
The core idea of harness is: read the `output.jsonl` produced by infer, apply each patch to the corresponding repository image, run tests, and generate evaluation results.
|
|
39
50
|
|
|
40
|
-
When harness loads the HuggingFace dataset during evaluation, it uses `HF_ENDPOINT`
|
|
51
|
+
When harness loads the HuggingFace dataset during evaluation, it uses `HF_ENDPOINT`
|
|
52
|
+
from `[env_vars]` and the pinned revision from `[dataset]`.
|
|
41
53
|
|
|
42
54
|
---
|
|
43
55
|
|
|
@@ -208,4 +220,4 @@ Example (local vLLM):
|
|
|
208
220
|
[llm.local]
|
|
209
221
|
backend = "vllm"
|
|
210
222
|
base_url = "http://localhost:8080/v1"
|
|
211
|
-
```
|
|
223
|
+
```
|
|
@@ -51,6 +51,11 @@ fb eval \
|
|
|
51
51
|
HuggingFace dataset repo name (e.g., `LiberCoders/FeatureBench`).
|
|
52
52
|
Default: `LiberCoders/FeatureBench`.
|
|
53
53
|
|
|
54
|
+
- `--data-version`
|
|
55
|
+
Hugging Face dataset tag, branch, or commit SHA.
|
|
56
|
+
Normally inferred from the inference run's `run_metadata.json`.
|
|
57
|
+
If unavailable, falls back to `[dataset].revision` or `v1.1`.
|
|
58
|
+
|
|
54
59
|
- `--split`
|
|
55
60
|
Dataset split name (e.g., `lite`, `full`).
|
|
56
61
|
Default: `full`.
|
|
@@ -6,6 +6,7 @@ This document describes all CLI arguments supported by `fb infer`.
|
|
|
6
6
|
|
|
7
7
|
```bash
|
|
8
8
|
fb infer \
|
|
9
|
+
--data-version v1.1 \
|
|
9
10
|
--agent gemini_cli \
|
|
10
11
|
--model gemini-3-pro-preview
|
|
11
12
|
```
|
|
@@ -53,6 +54,12 @@ flags can override metadata (see the argument list below).
|
|
|
53
54
|
HuggingFace dataset repo name (e.g., `LiberCoders/FeatureBench`).
|
|
54
55
|
Default: `LiberCoders/FeatureBench` in non-resume mode.
|
|
55
56
|
|
|
57
|
+
- `--data-version`
|
|
58
|
+
Hugging Face dataset tag, branch, or commit SHA.
|
|
59
|
+
Overrides `[dataset].revision` from `config.toml`; default: `v1.1`.
|
|
60
|
+
Saved into `run_metadata.json`; resume mode keeps the recorded dataset version.
|
|
61
|
+
This is separate from `--version`, which controls the agent software version.
|
|
62
|
+
|
|
56
63
|
- `--split`
|
|
57
64
|
Dataset split name (e.g., `lite`, `full`).
|
|
58
65
|
Default: `full` in non-resume mode. In resume mode, uses metadata.
|
|
@@ -166,4 +173,4 @@ runs/{timestamp}/
|
|
|
166
173
|
├── infer.log # Agent execution log
|
|
167
174
|
├── run.log # Runtime log
|
|
168
175
|
└── patch.diff # Generated patch
|
|
169
|
-
```
|
|
176
|
+
```
|
|
@@ -31,7 +31,7 @@ def _print_help(stream=None) -> None:
|
|
|
31
31
|
" data Run data pipeline (supports featurebench-pipeline args)\n"
|
|
32
32
|
"\n"
|
|
33
33
|
"Examples:\n"
|
|
34
|
-
" fb infer --agent mini_swe_agent --model openai/gpt-4o --split fast\n"
|
|
34
|
+
" fb infer --data-version v1.1 --agent mini_swe_agent --model openai/gpt-4o --split fast\n"
|
|
35
35
|
" fb eval --predictions-path runs/xxx/output.jsonl --split fast\n"
|
|
36
36
|
" fb pull --mode fast\n"
|
|
37
37
|
" fb data --config-path constants/python_new.py --output-dir runs/data\n"
|
|
@@ -128,4 +128,4 @@ def main(argv: Sequence[str] | None = None) -> int:
|
|
|
128
128
|
|
|
129
129
|
|
|
130
130
|
if __name__ == "__main__":
|
|
131
|
-
raise SystemExit(main())
|
|
131
|
+
raise SystemExit(main())
|
|
@@ -74,7 +74,13 @@ from featurebench.harness.utils import (
|
|
|
74
74
|
parse_repo_settings,
|
|
75
75
|
)
|
|
76
76
|
|
|
77
|
-
from featurebench.infer.config import
|
|
77
|
+
from featurebench.infer.config import (
|
|
78
|
+
DEFAULT_DATASET_REVISION,
|
|
79
|
+
InferConfigLoader,
|
|
80
|
+
configure_hf_access,
|
|
81
|
+
resolve_hf_dataset_revision,
|
|
82
|
+
verify_loaded_dataset_revision,
|
|
83
|
+
)
|
|
78
84
|
from featurebench.infer.gpu_scheduler import GpuLease, GpuScheduler, detect_host_gpu_ids, parse_gpu_id_list
|
|
79
85
|
|
|
80
86
|
# Global console for rich output
|
|
@@ -747,6 +753,7 @@ def load_dataset_from_hf(
|
|
|
747
753
|
split: str,
|
|
748
754
|
dataset: str,
|
|
749
755
|
config_path: str | None = None,
|
|
756
|
+
dataset_revision: str | None = None,
|
|
750
757
|
) -> pd.DataFrame:
|
|
751
758
|
"""
|
|
752
759
|
Load dataset from HuggingFace using config.toml settings.
|
|
@@ -766,21 +773,39 @@ def load_dataset_from_hf(
|
|
|
766
773
|
resolved_path = Path(config_path).expanduser() if config_path else None
|
|
767
774
|
config_loader = InferConfigLoader(resolved_path)
|
|
768
775
|
env_vars = config_loader.env_vars
|
|
769
|
-
hf_token = env_vars
|
|
776
|
+
hf_token, hf_endpoint = configure_hf_access(env_vars)
|
|
777
|
+
configured_revision = config_loader.get_dataset_revision()
|
|
770
778
|
except FileNotFoundError:
|
|
771
779
|
console.print("[yellow]Warning: config.toml not found, using defaults[/]")
|
|
772
|
-
hf_token =
|
|
780
|
+
hf_token, hf_endpoint = configure_hf_access({})
|
|
781
|
+
configured_revision = DEFAULT_DATASET_REVISION
|
|
782
|
+
|
|
783
|
+
requested_revision = str(dataset_revision or "").strip()
|
|
784
|
+
effective_revision = requested_revision or configured_revision
|
|
773
785
|
|
|
774
786
|
console.print(f"[bold blue]Loading dataset from HuggingFace...[/]")
|
|
775
787
|
console.print(f"[dim]Repository: {dataset}[/]")
|
|
776
788
|
console.print(f"[dim]Split: {split}[/]")
|
|
789
|
+
console.print(f"[dim]Version: {effective_revision}[/]")
|
|
777
790
|
|
|
778
791
|
if hf_token:
|
|
779
792
|
console.print("[dim]Using HuggingFace token from config[/]")
|
|
780
793
|
|
|
781
794
|
try:
|
|
795
|
+
resolved_revision = resolve_hf_dataset_revision(
|
|
796
|
+
dataset,
|
|
797
|
+
effective_revision,
|
|
798
|
+
hf_token,
|
|
799
|
+
hf_endpoint,
|
|
800
|
+
)
|
|
782
801
|
# Load the specified split
|
|
783
|
-
hf_dataset = load_dataset(
|
|
802
|
+
hf_dataset = load_dataset(
|
|
803
|
+
dataset,
|
|
804
|
+
split=split,
|
|
805
|
+
token=hf_token,
|
|
806
|
+
revision=resolved_revision,
|
|
807
|
+
)
|
|
808
|
+
verify_loaded_dataset_revision(hf_dataset, resolved_revision)
|
|
784
809
|
df = pd.DataFrame(hf_dataset)
|
|
785
810
|
|
|
786
811
|
# Determine level from instance_id's last segment (e.g., "xxx.lv1" -> level 1)
|
|
@@ -809,6 +834,28 @@ def load_dataset_from_hf(
|
|
|
809
834
|
raise
|
|
810
835
|
|
|
811
836
|
|
|
837
|
+
def resolve_eval_dataset_revision(
|
|
838
|
+
cli_revision: str | None,
|
|
839
|
+
run_metadata: dict | None,
|
|
840
|
+
) -> str | None:
|
|
841
|
+
"""Resolve the dataset revision for evaluation.
|
|
842
|
+
|
|
843
|
+
An explicit CLI value wins. Otherwise, evaluation follows the revision
|
|
844
|
+
recorded by inference. Runs created before revision tracking belong to the
|
|
845
|
+
original v1.0 dataset. When no run metadata is available, the dataset
|
|
846
|
+
loader falls back to the configured/default revision.
|
|
847
|
+
"""
|
|
848
|
+
requested_revision = str(cli_revision or "").strip()
|
|
849
|
+
if requested_revision:
|
|
850
|
+
return requested_revision
|
|
851
|
+
|
|
852
|
+
if run_metadata:
|
|
853
|
+
recorded_revision = str(run_metadata.get("dataset_revision") or "").strip()
|
|
854
|
+
return recorded_revision or "v1.0"
|
|
855
|
+
|
|
856
|
+
return None
|
|
857
|
+
|
|
858
|
+
|
|
812
859
|
def parse_args() -> argparse.Namespace:
|
|
813
860
|
"""Parse command line arguments."""
|
|
814
861
|
parser = argparse.ArgumentParser(
|
|
@@ -874,6 +921,17 @@ def parse_args() -> argparse.Namespace:
|
|
|
874
921
|
help="HuggingFace dataset repo name (e.g., 'LiberCoders/FeatureBench')",
|
|
875
922
|
)
|
|
876
923
|
|
|
924
|
+
parser.add_argument(
|
|
925
|
+
"--data-version",
|
|
926
|
+
dest="dataset_version",
|
|
927
|
+
type=str,
|
|
928
|
+
default=None,
|
|
929
|
+
help=(
|
|
930
|
+
"Hugging Face dataset version (tag, branch, or commit SHA). "
|
|
931
|
+
"Default: infer from run_metadata.json, then [dataset].revision, then v1.1"
|
|
932
|
+
),
|
|
933
|
+
)
|
|
934
|
+
|
|
877
935
|
parser.add_argument(
|
|
878
936
|
"--split",
|
|
879
937
|
type=str,
|
|
@@ -956,15 +1014,23 @@ def main():
|
|
|
956
1014
|
# we keep FAIL_TO_PASS test files visible during Level 1 patch application to avoid
|
|
957
1015
|
# "patch touches deleted test file" apply failures.
|
|
958
1016
|
white_enabled = False
|
|
1017
|
+
run_metadata = None
|
|
959
1018
|
try:
|
|
960
1019
|
metadata_path = output_dir / "run_metadata.json"
|
|
961
|
-
if metadata_path.exists():
|
|
1020
|
+
if not use_gold_patch and metadata_path.exists():
|
|
962
1021
|
with open(metadata_path, "r", encoding="utf-8") as f:
|
|
963
1022
|
meta = json.load(f)
|
|
964
|
-
if isinstance(meta, dict)
|
|
965
|
-
|
|
1023
|
+
if isinstance(meta, dict):
|
|
1024
|
+
run_metadata = meta
|
|
1025
|
+
white_enabled = meta.get("white_box") is True
|
|
966
1026
|
except Exception:
|
|
967
1027
|
white_enabled = False
|
|
1028
|
+
run_metadata = None
|
|
1029
|
+
|
|
1030
|
+
dataset_revision = resolve_eval_dataset_revision(
|
|
1031
|
+
args.dataset_version,
|
|
1032
|
+
run_metadata,
|
|
1033
|
+
)
|
|
968
1034
|
|
|
969
1035
|
# Print startup banner
|
|
970
1036
|
console.print()
|
|
@@ -996,7 +1062,13 @@ def main():
|
|
|
996
1062
|
console.print()
|
|
997
1063
|
|
|
998
1064
|
# Load dataset
|
|
999
|
-
dataset = load_dataset_from_hf(
|
|
1065
|
+
dataset = load_dataset_from_hf(
|
|
1066
|
+
console,
|
|
1067
|
+
args.split,
|
|
1068
|
+
args.dataset,
|
|
1069
|
+
args.config_path,
|
|
1070
|
+
dataset_revision,
|
|
1071
|
+
)
|
|
1000
1072
|
|
|
1001
1073
|
# Load predictions
|
|
1002
1074
|
console.print(f"[bold blue]Loading predictions...[/]")
|
|
@@ -1221,4 +1293,4 @@ def main():
|
|
|
1221
1293
|
|
|
1222
1294
|
|
|
1223
1295
|
if __name__ == "__main__":
|
|
1224
|
-
raise SystemExit(main())
|
|
1296
|
+
raise SystemExit(main())
|
|
@@ -109,6 +109,14 @@ echo "mini-swe-agent installation complete"
|
|
|
109
109
|
)
|
|
110
110
|
except Exception:
|
|
111
111
|
pass
|
|
112
|
+
try:
|
|
113
|
+
self.cm.copy_from_container(
|
|
114
|
+
container,
|
|
115
|
+
"/root/.config/mini-swe-agent/last_mini_run.traj.json",
|
|
116
|
+
log_dir / "traj.json",
|
|
117
|
+
)
|
|
118
|
+
except Exception:
|
|
119
|
+
pass
|
|
112
120
|
return True
|
|
113
121
|
|
|
114
122
|
def failure_hook(self, container, log_file: Path) -> None:
|
|
@@ -122,6 +130,14 @@ echo "mini-swe-agent installation complete"
|
|
|
122
130
|
)
|
|
123
131
|
except Exception:
|
|
124
132
|
pass
|
|
133
|
+
try:
|
|
134
|
+
self.cm.copy_from_container(
|
|
135
|
+
container,
|
|
136
|
+
"/root/.config/mini-swe-agent/last_mini_run.traj.json",
|
|
137
|
+
log_dir / "traj.json",
|
|
138
|
+
)
|
|
139
|
+
except Exception:
|
|
140
|
+
pass
|
|
125
141
|
|
|
126
142
|
def get_run_command(self, instruction: str) -> str:
|
|
127
143
|
"""Get the command to run mini-swe-agent."""
|
|
@@ -5,8 +5,75 @@ Configuration loader for the inference module.
|
|
|
5
5
|
import logging
|
|
6
6
|
import os
|
|
7
7
|
from pathlib import Path
|
|
8
|
-
from typing import Any, Dict, List, Optional
|
|
8
|
+
from typing import Any, Dict, List, Optional, Tuple, Union
|
|
9
|
+
|
|
9
10
|
import toml
|
|
11
|
+
from huggingface_hub import HfApi
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
DEFAULT_DATASET_REVISION = "v1.1"
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def configure_hf_access(env_vars: Dict[str, Any]) -> Tuple[Union[str, bool, None], Optional[str]]:
|
|
18
|
+
"""Apply configured Hub access settings and return normalized values."""
|
|
19
|
+
configured_endpoint = str(env_vars.get("HF_ENDPOINT") or "").strip()
|
|
20
|
+
endpoint = configured_endpoint or str(os.environ.get("HF_ENDPOINT") or "").strip()
|
|
21
|
+
if endpoint:
|
|
22
|
+
os.environ["HF_ENDPOINT"] = endpoint
|
|
23
|
+
# ``datasets.config.HF_ENDPOINT`` is initialized at import time, so update
|
|
24
|
+
# it as well when callers load their config after importing datasets.
|
|
25
|
+
import datasets
|
|
26
|
+
|
|
27
|
+
datasets.config.HF_ENDPOINT = endpoint
|
|
28
|
+
|
|
29
|
+
if "HF_TOKEN" in env_vars:
|
|
30
|
+
configured_token = str(env_vars.get("HF_TOKEN") or "").strip()
|
|
31
|
+
token: Union[str, bool, None] = configured_token or False
|
|
32
|
+
else:
|
|
33
|
+
token = str(os.environ.get("HF_TOKEN") or "").strip() or None
|
|
34
|
+
|
|
35
|
+
return token, endpoint or None
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def resolve_hf_dataset_revision(
|
|
39
|
+
dataset: str,
|
|
40
|
+
revision: str,
|
|
41
|
+
token: Union[str, bool, None],
|
|
42
|
+
endpoint: Optional[str],
|
|
43
|
+
) -> str:
|
|
44
|
+
"""Resolve a Hub dataset revision to its immutable commit SHA."""
|
|
45
|
+
try:
|
|
46
|
+
info = HfApi(endpoint=endpoint, token=token).dataset_info(
|
|
47
|
+
repo_id=dataset,
|
|
48
|
+
revision=revision,
|
|
49
|
+
)
|
|
50
|
+
except Exception as exc:
|
|
51
|
+
raise RuntimeError(
|
|
52
|
+
f"Unable to resolve dataset revision '{revision}' for '{dataset}'. "
|
|
53
|
+
"Refusing to use an unverified cached dataset."
|
|
54
|
+
) from exc
|
|
55
|
+
|
|
56
|
+
resolved_revision = str(info.sha or "").strip()
|
|
57
|
+
if not resolved_revision:
|
|
58
|
+
raise RuntimeError(
|
|
59
|
+
f"Hugging Face returned no commit SHA for '{dataset}' at '{revision}'"
|
|
60
|
+
)
|
|
61
|
+
return resolved_revision
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def verify_loaded_dataset_revision(dataset: Any, resolved_revision: str) -> None:
|
|
65
|
+
"""Reject Hugging Face's fallback to a cache from another revision."""
|
|
66
|
+
cache_files = getattr(dataset, "cache_files", None) or []
|
|
67
|
+
cache_paths = [
|
|
68
|
+
Path(item["filename"])
|
|
69
|
+
for item in cache_files
|
|
70
|
+
if isinstance(item, dict) and item.get("filename")
|
|
71
|
+
]
|
|
72
|
+
if cache_paths and any(resolved_revision not in path.parts for path in cache_paths):
|
|
73
|
+
raise RuntimeError(
|
|
74
|
+
f"Loaded dataset cache does not match resolved commit {resolved_revision}. "
|
|
75
|
+
"Refusing to use a different dataset version."
|
|
76
|
+
)
|
|
10
77
|
|
|
11
78
|
|
|
12
79
|
class InferConfigLoader:
|
|
@@ -75,6 +142,12 @@ class InferConfigLoader:
|
|
|
75
142
|
return Path(path).expanduser()
|
|
76
143
|
return None
|
|
77
144
|
|
|
145
|
+
def get_dataset_revision(self) -> str:
|
|
146
|
+
"""Get the pinned Hugging Face dataset revision."""
|
|
147
|
+
dataset_cfg = self._config.get("dataset", {}) or {}
|
|
148
|
+
revision = str(dataset_cfg.get("revision") or "").strip()
|
|
149
|
+
return revision or DEFAULT_DATASET_REVISION
|
|
150
|
+
|
|
78
151
|
def get_agent_env_vars(self, agent_name: str) -> Dict[str, str]:
|
|
79
152
|
"""
|
|
80
153
|
Get environment variables for a specific agent.
|
|
@@ -153,20 +226,15 @@ class DatasetLoader:
|
|
|
153
226
|
|
|
154
227
|
def _setup_hf_env(self) -> None:
|
|
155
228
|
"""Set up HuggingFace environment variables."""
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
if env_vars.get("HF_ENDPOINT"):
|
|
159
|
-
os.environ["HF_ENDPOINT"] = env_vars["HF_ENDPOINT"]
|
|
160
|
-
|
|
161
|
-
if env_vars.get("HF_TOKEN"):
|
|
162
|
-
os.environ["HF_TOKEN"] = env_vars["HF_TOKEN"]
|
|
229
|
+
configure_hf_access(self.config.env_vars)
|
|
163
230
|
|
|
164
231
|
def load_dataset(
|
|
165
232
|
self,
|
|
166
233
|
dataset: str,
|
|
167
234
|
split: Optional[str] = None,
|
|
168
235
|
levels: Optional[List[int]] = None,
|
|
169
|
-
task_ids: Optional[List[str]] = None
|
|
236
|
+
task_ids: Optional[List[str]] = None,
|
|
237
|
+
revision: Optional[str] = None,
|
|
170
238
|
) -> List[Dict[str, Any]]:
|
|
171
239
|
"""
|
|
172
240
|
Load dataset from HuggingFace.
|
|
@@ -177,6 +245,8 @@ class DatasetLoader:
|
|
|
177
245
|
levels: List of levels to filter (1, 2). If None, loads all levels.
|
|
178
246
|
Level is determined by the last segment of instance_id (e.g., "lv1", "lv2").
|
|
179
247
|
task_ids: Specific task IDs to filter. If None, loads all tasks.
|
|
248
|
+
revision: Hugging Face dataset revision (tag, branch, or commit SHA).
|
|
249
|
+
If omitted, uses ``[dataset].revision`` or ``v1.1``.
|
|
180
250
|
|
|
181
251
|
Returns:
|
|
182
252
|
List of task instances as dictionaries
|
|
@@ -193,7 +263,8 @@ class DatasetLoader:
|
|
|
193
263
|
from datasets import load_dataset
|
|
194
264
|
|
|
195
265
|
env_vars = self.config.env_vars
|
|
196
|
-
hf_token = env_vars
|
|
266
|
+
hf_token, hf_endpoint = configure_hf_access(env_vars)
|
|
267
|
+
dataset_revision = str(revision or "").strip() or self.config.get_dataset_revision()
|
|
197
268
|
|
|
198
269
|
dataset_name = str(dataset or "").strip()
|
|
199
270
|
if not dataset_name:
|
|
@@ -205,11 +276,19 @@ class DatasetLoader:
|
|
|
205
276
|
all_instances = []
|
|
206
277
|
|
|
207
278
|
try:
|
|
279
|
+
resolved_revision = resolve_hf_dataset_revision(
|
|
280
|
+
dataset_name,
|
|
281
|
+
dataset_revision,
|
|
282
|
+
hf_token,
|
|
283
|
+
hf_endpoint,
|
|
284
|
+
)
|
|
208
285
|
dataset = load_dataset(
|
|
209
286
|
dataset_name,
|
|
210
287
|
split=split,
|
|
211
|
-
token=hf_token
|
|
288
|
+
token=hf_token,
|
|
289
|
+
revision=resolved_revision,
|
|
212
290
|
)
|
|
291
|
+
verify_loaded_dataset_revision(dataset, resolved_revision)
|
|
213
292
|
|
|
214
293
|
for item in dataset:
|
|
215
294
|
item_dict = dict(item)
|
|
@@ -152,6 +152,8 @@ class InferConfig:
|
|
|
152
152
|
model: str
|
|
153
153
|
# HuggingFace dataset repo name (e.g., "LiberCoders/FeatureBench")
|
|
154
154
|
dataset: str = "LiberCoders/FeatureBench"
|
|
155
|
+
# Hugging Face dataset tag, branch, or commit SHA. None defers to config.toml/default.
|
|
156
|
+
dataset_revision: Optional[str] = None
|
|
155
157
|
n_concurrent: int = 1
|
|
156
158
|
n_attempts: int = 1
|
|
157
159
|
task_ids: Optional[List[str]] = None
|
|
@@ -191,6 +193,7 @@ class InferConfig:
|
|
|
191
193
|
"agent": self.agent,
|
|
192
194
|
"model": self.model,
|
|
193
195
|
"dataset": self.dataset,
|
|
196
|
+
"dataset_revision": self.dataset_revision,
|
|
194
197
|
"n_concurrent": self.n_concurrent,
|
|
195
198
|
"n_attempts": self.n_attempts,
|
|
196
199
|
"task_ids": self.task_ids,
|
|
@@ -257,6 +260,7 @@ class RunMetadata:
|
|
|
257
260
|
task_ids: List[str]
|
|
258
261
|
output_path: str
|
|
259
262
|
start_time: str
|
|
263
|
+
dataset_revision: str = "v1.1"
|
|
260
264
|
timeout: int = 7200
|
|
261
265
|
proxy_port: Optional[int] = None
|
|
262
266
|
runtime_proxy: Optional[bool] = None
|
|
@@ -284,6 +288,7 @@ class RunMetadata:
|
|
|
284
288
|
"agent": self.agent,
|
|
285
289
|
"model": self.model,
|
|
286
290
|
"dataset": self.dataset,
|
|
291
|
+
"dataset_revision": self.dataset_revision,
|
|
287
292
|
"n_concurrent": self.n_concurrent,
|
|
288
293
|
"n_attempts": self.n_attempts,
|
|
289
294
|
"task_ids": self.task_ids,
|
|
@@ -321,6 +326,8 @@ class RunMetadata:
|
|
|
321
326
|
"""Load metadata from a JSON file."""
|
|
322
327
|
with open(path, "r", encoding="utf-8") as f:
|
|
323
328
|
data = json.load(f)
|
|
329
|
+
# Runs created before dataset versioning used the original Hub release.
|
|
330
|
+
data.setdefault("dataset_revision", "v1.0")
|
|
324
331
|
return cls(**data)
|
|
325
332
|
|
|
326
333
|
|
|
@@ -358,4 +365,4 @@ class TaskPaths:
|
|
|
358
365
|
|
|
359
366
|
def ensure_dirs(self) -> None:
|
|
360
367
|
"""Create all necessary directories."""
|
|
361
|
-
self.attempt_dir.mkdir(parents=True, exist_ok=True)
|
|
368
|
+
self.attempt_dir.mkdir(parents=True, exist_ok=True)
|