featurebench 0.2.1__tar.gz → 0.2.3__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.3}/PKG-INFO +7 -4
- {featurebench-0.2.1 → featurebench-0.2.3}/README.md +5 -2
- {featurebench-0.2.1 → featurebench-0.2.3}/config_example.toml +11 -2
- {featurebench-0.2.1 → featurebench-0.2.3}/docs/config.md +17 -4
- {featurebench-0.2.1 → featurebench-0.2.3}/docs/harness_cli_arg.md +5 -0
- {featurebench-0.2.1 → featurebench-0.2.3}/docs/infer_cli_arg.md +15 -1
- {featurebench-0.2.1 → featurebench-0.2.3}/featurebench/cli.py +2 -2
- featurebench-0.2.3/featurebench/environment_fixes/__init__.py +13 -0
- featurebench-0.2.3/featurebench/environment_fixes/base.py +24 -0
- featurebench-0.2.3/featurebench/environment_fixes/mlflow.py +41 -0
- featurebench-0.2.3/featurebench/environment_fixes/registry.py +43 -0
- {featurebench-0.2.1 → featurebench-0.2.3}/featurebench/harness/run_evaluation.py +81 -9
- {featurebench-0.2.1 → featurebench-0.2.3}/featurebench/harness/runtime.py +26 -12
- {featurebench-0.2.1 → featurebench-0.2.3}/featurebench/infer/agents/base.py +14 -2
- {featurebench-0.2.1 → featurebench-0.2.3}/featurebench/infer/agents/mini_swe_agent.py +110 -12
- {featurebench-0.2.1 → featurebench-0.2.3}/featurebench/infer/config.py +90 -11
- featurebench-0.2.3/featurebench/infer/environments/__init__.py +1 -0
- featurebench-0.2.3/featurebench/infer/environments/mini_swe.py +185 -0
- {featurebench-0.2.1 → featurebench-0.2.3}/featurebench/infer/models.py +16 -2
- featurebench-0.2.3/featurebench/infer/network.py +473 -0
- featurebench-0.2.3/featurebench/infer/proxy_bridge.py +57 -0
- {featurebench-0.2.1 → featurebench-0.2.3}/featurebench/infer/run_infer.py +195 -10
- {featurebench-0.2.1 → featurebench-0.2.3}/featurebench/infer/runtime.py +138 -5
- {featurebench-0.2.1 → featurebench-0.2.3}/pyproject.toml +1 -1
- featurebench-0.2.3/tests/test_dataset_version.py +215 -0
- featurebench-0.2.3/tests/test_environment_fixes.py +52 -0
- featurebench-0.2.3/tests/test_infer_network.py +150 -0
- featurebench-0.2.3/tests/test_infer_runtime.py +163 -0
- featurebench-0.2.3/tests/test_mini_swe_agent.py +213 -0
- {featurebench-0.2.1 → featurebench-0.2.3}/uv.lock +43 -43
- {featurebench-0.2.1 → featurebench-0.2.3}/.gitignore +0 -0
- {featurebench-0.2.1 → featurebench-0.2.3}/.python-version +0 -0
- {featurebench-0.2.1 → featurebench-0.2.3}/LICENSE +0 -0
- {featurebench-0.2.1 → featurebench-0.2.3}/docs/pics/logo.png +0 -0
- {featurebench-0.2.1 → featurebench-0.2.3}/docs/pics/workflow.png +0 -0
- {featurebench-0.2.1 → featurebench-0.2.3}/docs/pipeline.md +0 -0
- {featurebench-0.2.1 → featurebench-0.2.3}/featurebench/__init__.py +0 -0
- {featurebench-0.2.1 → featurebench-0.2.3}/featurebench/classification/__init__.py +0 -0
- {featurebench-0.2.1 → featurebench-0.2.3}/featurebench/classification/code_classifier.py +0 -0
- {featurebench-0.2.1 → featurebench-0.2.3}/featurebench/classification/file_analyzer.py +0 -0
- {featurebench-0.2.1 → featurebench-0.2.3}/featurebench/classification/llm_top_classifier.py +0 -0
- {featurebench-0.2.1 → featurebench-0.2.3}/featurebench/classification/p2p_chooser.py +0 -0
- {featurebench-0.2.1 → featurebench-0.2.3}/featurebench/conversion/__init__.py +0 -0
- {featurebench-0.2.1 → featurebench-0.2.3}/featurebench/conversion/case_converter.py +0 -0
- {featurebench-0.2.1 → featurebench-0.2.3}/featurebench/conversion/eval_code.py +0 -0
- {featurebench-0.2.1 → featurebench-0.2.3}/featurebench/conversion/llm_prompt_generator.py +0 -0
- {featurebench-0.2.1 → featurebench-0.2.3}/featurebench/conversion/llm_testfile_adjuster.py +0 -0
- {featurebench-0.2.1 → featurebench-0.2.3}/featurebench/conversion/render_task.py +0 -0
- {featurebench-0.2.1 → featurebench-0.2.3}/featurebench/docker/__init__.py +0 -0
- {featurebench-0.2.1 → featurebench-0.2.3}/featurebench/docker/dynamic_tracer.py +0 -0
- {featurebench-0.2.1 → featurebench-0.2.3}/featurebench/docker/image_manager.py +0 -0
- {featurebench-0.2.1 → featurebench-0.2.3}/featurebench/docker/test_runner.py +0 -0
- {featurebench-0.2.1 → featurebench-0.2.3}/featurebench/docker/test_scanner.py +0 -0
- {featurebench-0.2.1 → featurebench-0.2.3}/featurebench/harness/__init__.py +0 -0
- {featurebench-0.2.1 → featurebench-0.2.3}/featurebench/harness/constants.py +0 -0
- {featurebench-0.2.1 → featurebench-0.2.3}/featurebench/harness/container.py +0 -0
- {featurebench-0.2.1 → featurebench-0.2.3}/featurebench/harness/grading.py +0 -0
- {featurebench-0.2.1 → featurebench-0.2.3}/featurebench/harness/report.py +0 -0
- {featurebench-0.2.1 → featurebench-0.2.3}/featurebench/harness/review_codes.py +0 -0
- {featurebench-0.2.1 → featurebench-0.2.3}/featurebench/harness/test_parsers.py +0 -0
- {featurebench-0.2.1 → featurebench-0.2.3}/featurebench/harness/utils.py +0 -0
- {featurebench-0.2.1 → featurebench-0.2.3}/featurebench/infer/__init__.py +0 -0
- {featurebench-0.2.1 → featurebench-0.2.3}/featurebench/infer/agents/__init__.py +0 -0
- {featurebench-0.2.1 → featurebench-0.2.3}/featurebench/infer/agents/claude_code.py +0 -0
- {featurebench-0.2.1 → featurebench-0.2.3}/featurebench/infer/agents/codex.py +0 -0
- {featurebench-0.2.1 → featurebench-0.2.3}/featurebench/infer/agents/gemini_cli.py +0 -0
- {featurebench-0.2.1 → featurebench-0.2.3}/featurebench/infer/agents/openhands.py +0 -0
- {featurebench-0.2.1 → featurebench-0.2.3}/featurebench/infer/container.py +0 -0
- {featurebench-0.2.1 → featurebench-0.2.3}/featurebench/infer/gpu_scheduler.py +0 -0
- {featurebench-0.2.1 → featurebench-0.2.3}/featurebench/infer/output.py +0 -0
- {featurebench-0.2.1 → featurebench-0.2.3}/featurebench/infer/render_infer_log.py +0 -0
- {featurebench-0.2.1 → featurebench-0.2.3}/featurebench/llm/__init__.py +0 -0
- {featurebench-0.2.1 → featurebench-0.2.3}/featurebench/llm/llm_caller.py +0 -0
- {featurebench-0.2.1 → featurebench-0.2.3}/featurebench/llm/llm_exceptions.py +0 -0
- {featurebench-0.2.1 → featurebench-0.2.3}/featurebench/mask/__init__.py +0 -0
- {featurebench-0.2.1 → featurebench-0.2.3}/featurebench/mask/mask_generator.py +0 -0
- {featurebench-0.2.1 → featurebench-0.2.3}/featurebench/mask/mask_validator.py +0 -0
- {featurebench-0.2.1 → featurebench-0.2.3}/featurebench/mask/signature_extractor.py +0 -0
- {featurebench-0.2.1 → featurebench-0.2.3}/featurebench/pipeline.py +0 -0
- {featurebench-0.2.1 → featurebench-0.2.3}/featurebench/post_verify/__init__.py +0 -0
- {featurebench-0.2.1 → featurebench-0.2.3}/featurebench/post_verify/f2p_validator.py +0 -0
- {featurebench-0.2.1 → featurebench-0.2.3}/featurebench/post_verify/level2_validator.py +0 -0
- {featurebench-0.2.1 → featurebench-0.2.3}/featurebench/post_verify/p2p_validator.py +0 -0
- {featurebench-0.2.1 → featurebench-0.2.3}/featurebench/resources/constants/fast_images.txt +0 -0
- {featurebench-0.2.1 → featurebench-0.2.3}/featurebench/resources/constants/full_images.txt +0 -0
- {featurebench-0.2.1 → featurebench-0.2.3}/featurebench/resources/constants/lite_images.txt +0 -0
- {featurebench-0.2.1 → featurebench-0.2.3}/featurebench/resources/constants/python_example.py +0 -0
- {featurebench-0.2.1 → featurebench-0.2.3}/featurebench/resources/dockerfiles/python310.py +0 -0
- {featurebench-0.2.1 → featurebench-0.2.3}/featurebench/resources/dockerfiles/python310_cu118_torch212.py +0 -0
- {featurebench-0.2.1 → featurebench-0.2.3}/featurebench/resources/dockerfiles/python310_cu121_torch251.py +0 -0
- {featurebench-0.2.1 → featurebench-0.2.3}/featurebench/resources/dockerfiles/python310_cu121_torch28.py +0 -0
- {featurebench-0.2.1 → featurebench-0.2.3}/featurebench/resources/dockerfiles/python311.py +0 -0
- {featurebench-0.2.1 → featurebench-0.2.3}/featurebench/resources/dockerfiles/python311_cu121_torch28.py +0 -0
- {featurebench-0.2.1 → featurebench-0.2.3}/featurebench/resources/dockerfiles/python312.py +0 -0
- {featurebench-0.2.1 → featurebench-0.2.3}/featurebench/resources/dockerfiles/python312_cu121_torch251.py +0 -0
- {featurebench-0.2.1 → featurebench-0.2.3}/featurebench/resources/dockerfiles/python312_cu121_torch26.py +0 -0
- {featurebench-0.2.1 → featurebench-0.2.3}/featurebench/resources/dockerfiles/python312_cu121_torch28.py +0 -0
- {featurebench-0.2.1 → featurebench-0.2.3}/featurebench/resources/dockerfiles/python312_torch251.py +0 -0
- {featurebench-0.2.1 → featurebench-0.2.3}/featurebench/resources/dockerfiles/python39.py +0 -0
- {featurebench-0.2.1 → featurebench-0.2.3}/featurebench/resources/scripts/dynamic_script/autograd_backward_patch.py +0 -0
- {featurebench-0.2.1 → featurebench-0.2.3}/featurebench/resources/scripts/dynamic_script/dynamic_script.py +0 -0
- {featurebench-0.2.1 → featurebench-0.2.3}/featurebench/resources/scripts/dynamic_script/import_hook_patch.py +0 -0
- {featurebench-0.2.1 → featurebench-0.2.3}/featurebench/resources/scripts/dynamic_script/joblib_patch.py +0 -0
- {featurebench-0.2.1 → featurebench-0.2.3}/featurebench/resources/scripts/dynamic_script/sitecustomize.py +0 -0
- {featurebench-0.2.1 → featurebench-0.2.3}/featurebench/resources/scripts/scanner_script.py +0 -0
- {featurebench-0.2.1 → featurebench-0.2.3}/featurebench/resources/templates/appendix.md.j2 +0 -0
- {featurebench-0.2.1 → featurebench-0.2.3}/featurebench/resources/templates/black_links.txt.j2 +0 -0
- {featurebench-0.2.1 → featurebench-0.2.3}/featurebench/resources/templates/config_template.yaml +0 -0
- {featurebench-0.2.1 → featurebench-0.2.3}/featurebench/resources/templates/level_1.j2 +0 -0
- {featurebench-0.2.1 → featurebench-0.2.3}/featurebench/resources/templates/level_2.j2 +0 -0
- {featurebench-0.2.1 → featurebench-0.2.3}/featurebench/resources/templates/llm_prompt_templates.yaml +0 -0
- {featurebench-0.2.1 → featurebench-0.2.3}/featurebench/scripts/cal_eval_outputs.py +0 -0
- {featurebench-0.2.1 → featurebench-0.2.3}/featurebench/scripts/post_filter_cases.py +0 -0
- {featurebench-0.2.1 → featurebench-0.2.3}/featurebench/scripts/pull_images.py +0 -0
- {featurebench-0.2.1 → featurebench-0.2.3}/featurebench/utils/__init__.py +0 -0
- {featurebench-0.2.1 → featurebench-0.2.3}/featurebench/utils/command_utils.py +0 -0
- {featurebench-0.2.1 → featurebench-0.2.3}/featurebench/utils/config.py +0 -0
- {featurebench-0.2.1 → featurebench-0.2.3}/featurebench/utils/docker_images.py +0 -0
- {featurebench-0.2.1 → featurebench-0.2.3}/featurebench/utils/logger.py +0 -0
- {featurebench-0.2.1 → featurebench-0.2.3}/featurebench/utils/parser/__init__.py +0 -0
- {featurebench-0.2.1 → featurebench-0.2.3}/featurebench/utils/parser/pytest_parser.py +0 -0
- {featurebench-0.2.1 → featurebench-0.2.3}/featurebench/utils/repo_manager.py +0 -0
- {featurebench-0.2.1 → featurebench-0.2.3}/featurebench/utils/storage.py +0 -0
- {featurebench-0.2.1 → featurebench-0.2.3}/featurebench/utils/utils.py +0 -0
- {featurebench-0.2.1 → featurebench-0.2.3}/featurebench/verified/__init__.py +0 -0
- {featurebench-0.2.1 → featurebench-0.2.3}/featurebench/verified/post_additions.py +0 -0
- {featurebench-0.2.1 → featurebench-0.2.3}/featurebench/verified/prompts/add_prompt_lv1.txt +0 -0
- {featurebench-0.2.1 → featurebench-0.2.3}/featurebench/verified/prompts/add_prompt_lv2.txt +0 -0
- {featurebench-0.2.1 → featurebench-0.2.3}/featurebench/verified/prompts/prompt_template_lv1.txt +0 -0
- {featurebench-0.2.1 → featurebench-0.2.3}/featurebench/verified/prompts/prompt_template_lv2.txt +0 -0
- {featurebench-0.2.1 → featurebench-0.2.3}/featurebench/verified/run_verification.py +0 -0
- {featurebench-0.2.1 → featurebench-0.2.3}/featurebench/verified/runner.py +0 -0
- {featurebench-0.2.1 → featurebench-0.2.3}/tests/test_eval_data_container_cleanup.py +0 -0
- {featurebench-0.2.1 → featurebench-0.2.3}/tests/test_infer_container_cleanup.py +0 -0
- {featurebench-0.2.1 → featurebench-0.2.3}/tests/test_openhands_session_cache.py +0 -0
- {featurebench-0.2.1 → featurebench-0.2.3}/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.3
|
|
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**.
|
|
@@ -50,7 +52,7 @@ It provides a unified CLI to run inference, evaluation, and dataset generation.
|
|
|
50
52
|
<!-- LEADERBOARD_START -->
|
|
51
53
|
## 🏆 Leaderboard
|
|
52
54
|
|
|
53
|
-
[Full interactive leaderboard](https://libercoders.github.io/FeatureBench/leaderboard/) with tabs, filters, and sorting.
|
|
55
|
+
[Full interactive leaderboard](https://libercoders.github.io/FeatureBench/leaderboard/) with tabs, filters, and sorting (Dataset V1.0).
|
|
54
56
|
|
|
55
57
|
<details open>
|
|
56
58
|
<summary><b>Lite split results, ranked by %PASSED</b></summary>
|
|
@@ -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 [qixing.zhou@smail.nju.edu.cn](mailto:qixing.zhou@smail.nju.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**.
|
|
@@ -26,7 +28,7 @@ It provides a unified CLI to run inference, evaluation, and dataset generation.
|
|
|
26
28
|
<!-- LEADERBOARD_START -->
|
|
27
29
|
## 🏆 Leaderboard
|
|
28
30
|
|
|
29
|
-
[Full interactive leaderboard](https://libercoders.github.io/FeatureBench/leaderboard/) with tabs, filters, and sorting.
|
|
31
|
+
[Full interactive leaderboard](https://libercoders.github.io/FeatureBench/leaderboard/) with tabs, filters, and sorting (Dataset V1.0).
|
|
30
32
|
|
|
31
33
|
<details open>
|
|
32
34
|
<summary><b>Lite split results, ranked by %PASSED</b></summary>
|
|
@@ -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 [qixing.zhou@smail.nju.edu.cn](mailto:qixing.zhou@smail.nju.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
|
# ==============================================================================
|
|
@@ -44,7 +52,8 @@ base_url = "http://localhost:8080/v1" # vLLM server URL
|
|
|
44
52
|
# Optional: Host cache directory for agent downloads; will be mounted to /download inside containers
|
|
45
53
|
# Set to empty to disable cache mount (each container will re-download/install)
|
|
46
54
|
# Use an absolute path here
|
|
47
|
-
|
|
55
|
+
# Optional shared install cache. Leave unset for leakage-resistant evaluations.
|
|
56
|
+
# download_cache_dir="/path/to/FeatureBench/download_cache"
|
|
48
57
|
|
|
49
58
|
# OpenHands Agent Configuration
|
|
50
59
|
[infer_config.openhands]
|
|
@@ -109,4 +118,4 @@ MSWEA_BASE_URL = ""
|
|
|
109
118
|
# Optional: Cost tracking mode (default behavior in FB adapter is ignore_errors)
|
|
110
119
|
MSWEA_COST_TRACKING = ""
|
|
111
120
|
# Optional: Lock mini_swe_agent version (leave empty to use latest)
|
|
112
|
-
MINI_SWE_AGENT_VERSION = ""
|
|
121
|
+
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
|
|
|
@@ -56,10 +68,11 @@ How infer reads `config.toml`:
|
|
|
56
68
|
|
|
57
69
|
```toml
|
|
58
70
|
[infer]
|
|
59
|
-
|
|
71
|
+
# Optional shared install cache. Leave unset for leakage-resistant evaluations.
|
|
72
|
+
# download_cache_dir = "/abs/path/to/FeatureBench/download_cache"
|
|
60
73
|
```
|
|
61
74
|
|
|
62
|
-
- `download_cache_dir`: host-side cache directory
|
|
75
|
+
- `download_cache_dir`: optional host-side cache directory mounted into the container at `/download`. It is disabled by default because the agent can read shared cache contents during inference.
|
|
63
76
|
- Purpose: speed up agent installs/downloads (e.g. npm cache).
|
|
64
77
|
- Empty means no mount (each container downloads on its own; usually slower).
|
|
65
78
|
|
|
@@ -208,4 +221,4 @@ Example (local vLLM):
|
|
|
208
221
|
[llm.local]
|
|
209
222
|
backend = "vllm"
|
|
210
223
|
base_url = "http://localhost:8080/v1"
|
|
211
|
-
```
|
|
224
|
+
```
|
|
@@ -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.
|
|
@@ -153,6 +160,13 @@ flags can override metadata (see the argument list below).
|
|
|
153
160
|
Default: no override (OpenHands default applies).
|
|
154
161
|
Resume mode: ignored (uses metadata).
|
|
155
162
|
|
|
163
|
+
### mini-swe-agent Only
|
|
164
|
+
|
|
165
|
+
- `--cost-limit`
|
|
166
|
+
Per-task cost limit in USD, passed to mini-swe-agent.
|
|
167
|
+
Set to `0` to disable the limit. If omitted, mini-swe-agent's upstream default applies.
|
|
168
|
+
Resume mode: ignored (uses metadata).
|
|
169
|
+
|
|
156
170
|
## Section 4: Output Directory Structure
|
|
157
171
|
|
|
158
172
|
```
|
|
@@ -166,4 +180,4 @@ runs/{timestamp}/
|
|
|
166
180
|
├── infer.log # Agent execution log
|
|
167
181
|
├── run.log # Runtime log
|
|
168
182
|
└── patch.diff # Generated patch
|
|
169
|
-
```
|
|
183
|
+
```
|
|
@@ -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())
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"""Repository-specific fixes for leaked or duplicated task-environment artifacts.
|
|
2
|
+
|
|
3
|
+
Add a fix by implementing :class:`EnvironmentFix`, decorating it with
|
|
4
|
+
``register_environment_fix``, and importing its module below. Each plugin is
|
|
5
|
+
matched by repository and is shared by inference and Oracle evaluation.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from featurebench.environment_fixes.registry import apply_environment_fixes
|
|
9
|
+
|
|
10
|
+
# Import built-in plugins so they register themselves.
|
|
11
|
+
from featurebench.environment_fixes import mlflow as _mlflow # noqa: F401, E402
|
|
12
|
+
|
|
13
|
+
__all__ = ["apply_environment_fixes"]
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"""Interfaces for repository-specific task-environment fixes."""
|
|
2
|
+
|
|
3
|
+
from abc import ABC, abstractmethod
|
|
4
|
+
from collections.abc import Callable
|
|
5
|
+
import logging
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
CommandRunner = Callable[[str], tuple[int, str | bytes]]
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class EnvironmentFix(ABC):
|
|
12
|
+
"""A targeted cleanup applied before the task repository becomes the Git baseline."""
|
|
13
|
+
|
|
14
|
+
name: str
|
|
15
|
+
repositories: frozenset[str]
|
|
16
|
+
|
|
17
|
+
def applies_to(self, repository: str) -> bool:
|
|
18
|
+
"""Return whether this fix applies to a canonical ``owner/repo`` name."""
|
|
19
|
+
normalized = repository.strip().casefold()
|
|
20
|
+
return normalized in {repo.casefold() for repo in self.repositories}
|
|
21
|
+
|
|
22
|
+
@abstractmethod
|
|
23
|
+
def apply(self, run_command: CommandRunner, logger: logging.Logger) -> bool:
|
|
24
|
+
"""Apply and verify the fix, returning ``False`` on failure."""
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
"""MLflow-specific task-environment cleanup."""
|
|
2
|
+
|
|
3
|
+
import logging
|
|
4
|
+
|
|
5
|
+
from featurebench.environment_fixes.base import CommandRunner, EnvironmentFix
|
|
6
|
+
from featurebench.environment_fixes.registry import register_environment_fix
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
@register_environment_fix
|
|
10
|
+
class MlflowParallelSourcesFix(EnvironmentFix):
|
|
11
|
+
"""Remove unmasked MLflow package copies shipped in the monorepo's ``libs`` tree."""
|
|
12
|
+
|
|
13
|
+
name = "mlflow_parallel_sources"
|
|
14
|
+
repositories = frozenset({"mlflow/mlflow"})
|
|
15
|
+
paths = (
|
|
16
|
+
"/testbed/libs/skinny/mlflow",
|
|
17
|
+
"/testbed/libs/tracing/mlflow",
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
def apply(self, run_command: CommandRunner, logger: logging.Logger) -> bool:
|
|
21
|
+
paths = " ".join(self.paths)
|
|
22
|
+
command = f"""
|
|
23
|
+
paths=({paths})
|
|
24
|
+
for path in "${{paths[@]}}"; do
|
|
25
|
+
if [ -e "$path" ] || [ -L "$path" ]; then
|
|
26
|
+
rm -rf -- "$path" || exit 1
|
|
27
|
+
echo "Removed MLflow parallel source: $path"
|
|
28
|
+
fi
|
|
29
|
+
if [ -e "$path" ] || [ -L "$path" ]; then
|
|
30
|
+
echo "MLflow parallel source still exists: $path" >&2
|
|
31
|
+
exit 1
|
|
32
|
+
fi
|
|
33
|
+
done
|
|
34
|
+
"""
|
|
35
|
+
exit_code, output = run_command(command)
|
|
36
|
+
if exit_code != 0:
|
|
37
|
+
if isinstance(output, bytes):
|
|
38
|
+
output = output.decode("utf-8", errors="replace")
|
|
39
|
+
logger.error("Failed to remove MLflow parallel sources: %s", output)
|
|
40
|
+
return False
|
|
41
|
+
return True
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
"""Registry and execution helpers for task-environment fixes."""
|
|
2
|
+
|
|
3
|
+
import logging
|
|
4
|
+
from typing import TypeVar
|
|
5
|
+
|
|
6
|
+
from featurebench.environment_fixes.base import CommandRunner, EnvironmentFix
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
_FIXES: list[EnvironmentFix] = []
|
|
10
|
+
_EnvironmentFixType = TypeVar("_EnvironmentFixType", bound=type[EnvironmentFix])
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def register_environment_fix(fix_type: _EnvironmentFixType) -> _EnvironmentFixType:
|
|
14
|
+
"""Register an environment-fix class at import time."""
|
|
15
|
+
fix = fix_type()
|
|
16
|
+
if any(existing.name == fix.name for existing in _FIXES):
|
|
17
|
+
raise ValueError(f"Duplicate environment fix name: {fix.name}")
|
|
18
|
+
_FIXES.append(fix)
|
|
19
|
+
return fix_type
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def apply_environment_fixes(
|
|
23
|
+
repository: str,
|
|
24
|
+
run_command: CommandRunner,
|
|
25
|
+
logger: logging.Logger,
|
|
26
|
+
) -> bool:
|
|
27
|
+
"""Apply every registered fix matching ``repository`` in registration order."""
|
|
28
|
+
matching_fixes = [fix for fix in _FIXES if fix.applies_to(repository)]
|
|
29
|
+
if not matching_fixes:
|
|
30
|
+
return True
|
|
31
|
+
|
|
32
|
+
for fix in matching_fixes:
|
|
33
|
+
logger.info("Applying environment fix %s for %s", fix.name, repository)
|
|
34
|
+
try:
|
|
35
|
+
if not fix.apply(run_command, logger):
|
|
36
|
+
logger.error("Environment fix %s failed for %s", fix.name, repository)
|
|
37
|
+
return False
|
|
38
|
+
except Exception:
|
|
39
|
+
logger.exception("Environment fix %s raised for %s", fix.name, repository)
|
|
40
|
+
return False
|
|
41
|
+
logger.info("Environment fix %s completed for %s", fix.name, repository)
|
|
42
|
+
|
|
43
|
+
return True
|
|
@@ -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())
|
|
@@ -13,6 +13,7 @@ from typing import Any
|
|
|
13
13
|
import pandas as pd
|
|
14
14
|
from docker.models.containers import Container
|
|
15
15
|
|
|
16
|
+
from featurebench.environment_fixes import apply_environment_fixes
|
|
16
17
|
from featurebench.harness.constants import (
|
|
17
18
|
APPLY_PATCH_FAIL,
|
|
18
19
|
APPLY_PATCH_PASS,
|
|
@@ -55,9 +56,11 @@ def run_instance_level1(
|
|
|
55
56
|
1. Activate conda environment
|
|
56
57
|
2. Restore project from /root/my_repo/
|
|
57
58
|
3. Apply patch (for masking) and directly delete F2P test files
|
|
58
|
-
4.
|
|
59
|
-
5.
|
|
60
|
-
6.
|
|
59
|
+
4. Apply repository-specific environment fixes
|
|
60
|
+
5. Reinitialize git
|
|
61
|
+
6. Apply agent's patch
|
|
62
|
+
7. Delete any generated F2P files and restore the F2P test
|
|
63
|
+
8. Run tests
|
|
61
64
|
|
|
62
65
|
Args:
|
|
63
66
|
instance: Instance data (from HuggingFace)
|
|
@@ -177,8 +180,20 @@ def run_instance_level1(
|
|
|
177
180
|
else:
|
|
178
181
|
logger.warning("No FAIL_TO_PASS tests found in instance, skipping test file deletion")
|
|
179
182
|
|
|
180
|
-
# Step 3:
|
|
181
|
-
|
|
183
|
+
# Step 3: Apply the same repository-specific cleanup used during
|
|
184
|
+
# inference. Running it before Git initialization keeps the cleanup out
|
|
185
|
+
# of the candidate patch while making Oracle validation representative.
|
|
186
|
+
logger.info("Step 3: Applying repository-specific environment fixes")
|
|
187
|
+
if not apply_environment_fixes(
|
|
188
|
+
str(repo_name),
|
|
189
|
+
lambda command: exec_run_with_timeout(container, command, timeout=120),
|
|
190
|
+
logger,
|
|
191
|
+
):
|
|
192
|
+
results["error"] = "Repository-specific environment fix failed"
|
|
193
|
+
return results
|
|
194
|
+
|
|
195
|
+
# Step 4: Reinitialize git repository
|
|
196
|
+
logger.info("Step 4: Reinitializing git repository")
|
|
182
197
|
git_cmds = [
|
|
183
198
|
"cd /testbed && rm -rf .git",
|
|
184
199
|
"cd /testbed && git init",
|
|
@@ -194,8 +209,8 @@ def run_instance_level1(
|
|
|
194
209
|
logger.warning(f"Git command failed: {cmd}")
|
|
195
210
|
logger.warning(f"Output: {output.decode(UTF8, errors='replace')}")
|
|
196
211
|
|
|
197
|
-
# Step
|
|
198
|
-
logger.info("Step
|
|
212
|
+
# Step 5: Apply agent's patch
|
|
213
|
+
logger.info("Step 5: Applying agent patch")
|
|
199
214
|
patch_content = pred[KEY_PREDICTION]
|
|
200
215
|
|
|
201
216
|
if not patch_content or patch_content.strip() == "":
|
|
@@ -231,8 +246,8 @@ def run_instance_level1(
|
|
|
231
246
|
logger.info(f"{APPLY_PATCH_PASS}")
|
|
232
247
|
results["patch_applied"] = True
|
|
233
248
|
|
|
234
|
-
# Step
|
|
235
|
-
logger.info("Step
|
|
249
|
+
# Step 6: Prepare for testing - delete generated F2P files and restore F2P test
|
|
250
|
+
logger.info("Step 6: Preparing for testing - cleaning up and restoring F2P test")
|
|
236
251
|
|
|
237
252
|
fail_to_pass = instance.get('FAIL_TO_PASS', [])
|
|
238
253
|
if not fail_to_pass:
|
|
@@ -268,8 +283,8 @@ def run_instance_level1(
|
|
|
268
283
|
else:
|
|
269
284
|
logger.warning("No test_patch available to restore F2P test file")
|
|
270
285
|
|
|
271
|
-
# Step
|
|
272
|
-
logger.info("Step
|
|
286
|
+
# Step 7: Run tests
|
|
287
|
+
logger.info("Step 7: Running tests")
|
|
273
288
|
|
|
274
289
|
# Get test configuration from repo_settings
|
|
275
290
|
repo_settings = parse_repo_settings(instance)
|
|
@@ -589,4 +604,3 @@ def run_instance_level2(
|
|
|
589
604
|
logger.error(traceback.format_exc())
|
|
590
605
|
results["error"] = str(e)
|
|
591
606
|
return results
|
|
592
|
-
|
|
@@ -41,6 +41,10 @@ class BaseAgent(ABC):
|
|
|
41
41
|
self.env_vars = env_vars or {}
|
|
42
42
|
self.logger = logger or logging.getLogger(__name__)
|
|
43
43
|
self._kwargs = kwargs
|
|
44
|
+
# Agent adapters may populate this with their native terminal status.
|
|
45
|
+
# It deliberately remains optional because not every supported agent
|
|
46
|
+
# exposes a structured status artifact.
|
|
47
|
+
self.agent_exit_status: Optional[str] = None
|
|
44
48
|
|
|
45
49
|
@property
|
|
46
50
|
@abstractmethod
|
|
@@ -354,6 +358,7 @@ class BaseAgent(ABC):
|
|
|
354
358
|
Returns:
|
|
355
359
|
True if agent completed successfully
|
|
356
360
|
"""
|
|
361
|
+
self.agent_exit_status = None
|
|
357
362
|
self.logger.info(f"Running {self.name} agent...")
|
|
358
363
|
|
|
359
364
|
with open(log_file, "a", encoding="utf-8") as f:
|
|
@@ -385,16 +390,23 @@ class BaseAgent(ABC):
|
|
|
385
390
|
log_file=log_file,
|
|
386
391
|
timeout=timeout
|
|
387
392
|
)
|
|
388
|
-
|
|
393
|
+
|
|
389
394
|
success_run = exit_code == 0
|
|
395
|
+
timed_out = not success_run and self._infer_log_has_timeout_marker(log_file)
|
|
390
396
|
success_post_run = self.post_run_hook(container, log_file)
|
|
391
397
|
|
|
398
|
+
# A host-side timeout may kill the agent before it can persist a
|
|
399
|
+
# native terminal status. Preserve the actual reason for stopping
|
|
400
|
+
# instead of reporting an unknown/generic failure.
|
|
401
|
+
if timed_out:
|
|
402
|
+
self.agent_exit_status = "TimeExceeded"
|
|
403
|
+
|
|
392
404
|
if success_run and success_post_run:
|
|
393
405
|
self.logger.info(f"{self.name} agent completed successfully")
|
|
394
406
|
return True
|
|
395
407
|
|
|
396
408
|
if not success_run:
|
|
397
|
-
if self._force_timeout_enabled() and
|
|
409
|
+
if self._force_timeout_enabled() and timed_out:
|
|
398
410
|
post_run_state = "passed" if success_post_run else "failed"
|
|
399
411
|
self.logger.warning(
|
|
400
412
|
f"{self.name} run hit timeout marker (post-run hook {post_run_state}); "
|