self-evolve-framework 1.5.0 → 1.6.0
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.
- package/package.json +1 -1
- package/template/skills/skillopt-sleep/SKILL.md +42 -0
- package/template/skills/skillopt-sleep/configs/_base_/default.yaml +103 -0
- package/template/skills/skillopt-sleep/configs/alfworld/default.yaml +29 -0
- package/template/skills/skillopt-sleep/configs/docvqa/default.yaml +28 -0
- package/template/skills/skillopt-sleep/configs/features/soft_gate.yaml +47 -0
- package/template/skills/skillopt-sleep/configs/livemathematicianbench/default.yaml +22 -0
- package/template/skills/skillopt-sleep/configs/officeqa/default.yaml +34 -0
- package/template/skills/skillopt-sleep/configs/searchqa/default.yaml +32 -0
- package/template/skills/skillopt-sleep/configs/spreadsheetbench/default.yaml +34 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/__init__.py +28 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/config.py +282 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/datasets/__init__.py +7 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/datasets/base.py +512 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/engine/__init__.py +9 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/engine/trainer.py +2379 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/__init__.py +1 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/_template/README.md +43 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/_template/config_template.yaml +55 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/_template/env_template.py +151 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/_template/loader_template.py +87 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/alfworld/__init__.py +5 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/alfworld/adapter.py +428 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/alfworld/dataloader.py +123 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/alfworld/prompts/analyst_error.md +55 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/alfworld/prompts/analyst_success.md +33 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/alfworld/prompts/rollout_no_history.md +8 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/alfworld/prompts/rollout_with_history.md +9 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/alfworld/prompts/rollout_with_memory.md +16 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/alfworld/reflect.py +4 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/alfworld/rollout.py +366 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/alfworld/skills/initial.md +45 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/alfworld/vendor/__init__.py +9 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/alfworld/vendor/alfworld_envs.py +221 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/alfworld/vendor/alfworld_projection.py +60 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/alfworld/vendor/alfworld_prompts.py +8 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/alfworld/vendor/config_tw.yaml +145 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/alfworld/vendor/env_base.py +84 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/alfworld/vendor/env_manager.py +139 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/alfworld/vendor/memory.py +87 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/base.py +329 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/docvqa/__init__.py +1 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/docvqa/adapter.py +90 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/docvqa/dataloader.py +61 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/docvqa/evaluator.py +113 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/docvqa/prompts/analyst_error.md +35 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/docvqa/prompts/analyst_success.md +24 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/docvqa/prompts/rollout_system.md +12 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/docvqa/rollout.py +391 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/docvqa/skills/initial.md +11 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/livemathematicianbench/__init__.py +1 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/livemathematicianbench/adapter.py +129 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/livemathematicianbench/dataloader.py +308 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/livemathematicianbench/evaluator.py +62 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/livemathematicianbench/prompts/analyst_error.md +37 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/livemathematicianbench/prompts/analyst_success.md +25 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/livemathematicianbench/prompts/rollout_system.md +12 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/livemathematicianbench/reflect.py +4 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/livemathematicianbench/rollout.py +434 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/livemathematicianbench/skills/initial.md +16 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/officeqa/__init__.py +1 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/officeqa/adapter.py +112 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/officeqa/dataloader.py +71 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/officeqa/evaluator.py +46 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/officeqa/prompts/analyst_error.md +37 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/officeqa/prompts/analyst_success.md +25 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/officeqa/prompts/rollout_system.md +15 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/officeqa/rollout.py +799 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/officeqa/skills/initial.md +15 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/officeqa/tool_runtime.py +552 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/searchqa/__init__.py +1 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/searchqa/adapter.py +96 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/searchqa/dataloader.py +42 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/searchqa/evaluator.py +100 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/searchqa/prompts/analyst_error.md +46 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/searchqa/prompts/analyst_success.md +32 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/searchqa/prompts/rollout_system.md +13 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/searchqa/reflect.py +4 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/searchqa/rollout.py +494 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/searchqa/skills/initial.md +3 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/spreadsheetbench/__init__.py +5 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/spreadsheetbench/adapter.py +159 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/spreadsheetbench/codegen_agent.py +731 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/spreadsheetbench/dataloader.py +37 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/spreadsheetbench/evaluator.py +158 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/spreadsheetbench/executor.py +67 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/spreadsheetbench/prompts/analyst_error.md +46 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/spreadsheetbench/prompts/analyst_success.md +32 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/spreadsheetbench/prompts/codegen_system.md +1 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/spreadsheetbench/prompts/critical_rules.md +9 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/spreadsheetbench/prompts/react_system.md +21 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/spreadsheetbench/react_agent.py +395 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/spreadsheetbench/reflect.py +4 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/spreadsheetbench/rollout.py +979 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/spreadsheetbench/skills/initial.md +56 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/evaluation/__init__.py +13 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/evaluation/gate.py +148 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/gradient/__init__.py +15 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/gradient/aggregate.py +253 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/gradient/reflect.py +635 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/model/__init__.py +514 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/model/azure_openai.py +915 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/model/backend_config.py +185 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/model/claude_backend.py +371 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/model/codex_backend.py +666 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/model/codex_harness.py +1057 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/model/common.py +229 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/model/minimax_backend.py +277 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/model/qwen_backend.py +456 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/model/router.py +236 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/optimizer/__init__.py +15 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/optimizer/appendix.py +156 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/optimizer/clip.py +109 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/optimizer/lr_autonomous.py +108 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/optimizer/meta_skill.py +79 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/optimizer/rewrite.py +59 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/optimizer/scheduler.py +127 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/optimizer/select.py +4 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/optimizer/skill.py +201 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/optimizer/skill_aware.py +206 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/optimizer/slow_update.py +396 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/optimizer/update_modes.py +135 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/prompts/__init__.py +63 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/prompts/analyst_error.md +41 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/prompts/analyst_error_full_rewrite.md +32 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/prompts/analyst_error_rewrite.md +44 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/prompts/analyst_success.md +36 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/prompts/analyst_success_full_rewrite.md +30 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/prompts/analyst_success_rewrite.md +33 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/prompts/lr_autonomous.md +20 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/prompts/merge_failure.md +30 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/prompts/merge_failure_full_rewrite.md +28 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/prompts/merge_failure_rewrite.md +26 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/prompts/merge_final.md +33 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/prompts/merge_final_full_rewrite.md +28 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/prompts/merge_final_rewrite.md +25 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/prompts/merge_success.md +28 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/prompts/merge_success_full_rewrite.md +28 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/prompts/merge_success_rewrite.md +25 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/prompts/meta_skill.md +40 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/prompts/ranking.md +20 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/prompts/ranking_rewrite.md +15 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/prompts/rewrite_skill.md +25 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/prompts/slow_update.md +60 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/scheduler/__init__.py +8 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/types.py +306 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/utils/__init__.py +4 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/utils/json_utils.py +172 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/utils/scoring.py +28 -0
|
@@ -0,0 +1,308 @@
|
|
|
1
|
+
"""LiveMathematicianBench task dataloader."""
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
import glob
|
|
5
|
+
import hashlib
|
|
6
|
+
import json
|
|
7
|
+
import os
|
|
8
|
+
import random
|
|
9
|
+
from typing import Any
|
|
10
|
+
|
|
11
|
+
from skillopt.datasets.base import BatchSpec, SplitDataLoader
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
# ── Raw data loading utilities (for preprocessing / standalone eval) ─────
|
|
15
|
+
|
|
16
|
+
_CHOICE_LABELS = ["A", "B", "C", "D", "E", "F", "G"]
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def _load_json(path: str) -> Any:
|
|
20
|
+
with open(path) as f:
|
|
21
|
+
return json.load(f)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def _iter_monthly_files(data_path: str) -> list[str]:
|
|
25
|
+
if not data_path:
|
|
26
|
+
return []
|
|
27
|
+
if os.path.isfile(data_path):
|
|
28
|
+
return [data_path]
|
|
29
|
+
if os.path.isdir(data_path):
|
|
30
|
+
nested = glob.glob(
|
|
31
|
+
os.path.join(data_path, "**", "qa_*_final.json"),
|
|
32
|
+
recursive=True,
|
|
33
|
+
)
|
|
34
|
+
flat = glob.glob(os.path.join(data_path, "qa_*_final.json"))
|
|
35
|
+
return sorted(set(nested + flat))
|
|
36
|
+
return []
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def _coerce_choices(raw_choices: Any) -> list[dict]:
|
|
40
|
+
if isinstance(raw_choices, list):
|
|
41
|
+
choices: list[dict] = []
|
|
42
|
+
for idx, item in enumerate(raw_choices):
|
|
43
|
+
if isinstance(item, dict):
|
|
44
|
+
label = str(item.get("label") or _CHOICE_LABELS[idx]).strip()
|
|
45
|
+
text = str(item.get("text") or item.get("content") or "").strip()
|
|
46
|
+
else:
|
|
47
|
+
label = _CHOICE_LABELS[idx]
|
|
48
|
+
text = str(item).strip()
|
|
49
|
+
if text:
|
|
50
|
+
choices.append({"label": label, "text": text})
|
|
51
|
+
return choices
|
|
52
|
+
|
|
53
|
+
if isinstance(raw_choices, dict):
|
|
54
|
+
labels = sorted(raw_choices.keys())
|
|
55
|
+
return [
|
|
56
|
+
{"label": str(label).strip(), "text": str(raw_choices[label]).strip()}
|
|
57
|
+
for label in labels
|
|
58
|
+
if str(raw_choices[label]).strip()
|
|
59
|
+
]
|
|
60
|
+
|
|
61
|
+
return []
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def _coerce_theorem_types(raw: Any) -> list[str]:
|
|
65
|
+
if isinstance(raw, list):
|
|
66
|
+
return [str(x).strip() for x in raw if str(x).strip()]
|
|
67
|
+
if raw is None:
|
|
68
|
+
return []
|
|
69
|
+
text = str(raw).strip()
|
|
70
|
+
return [text] if text else []
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def _normalize_label(text: str) -> str:
|
|
74
|
+
return str(text).strip().upper().rstrip(".):")
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
def _normalize_item(item: dict, row_idx: int, source_path: str) -> dict:
|
|
78
|
+
mcq = item.get("mcq", {}) if isinstance(item.get("mcq"), dict) else {}
|
|
79
|
+
question = str(mcq.get("question") or item.get("question") or "").strip()
|
|
80
|
+
choices = _coerce_choices(mcq.get("choices") or item.get("choices") or [])
|
|
81
|
+
correct = mcq.get("correct_choice") or item.get("correct_choice") or {}
|
|
82
|
+
|
|
83
|
+
if isinstance(correct, dict):
|
|
84
|
+
correct_label = _normalize_label(correct.get("label", ""))
|
|
85
|
+
correct_text = str(correct.get("text") or "").strip()
|
|
86
|
+
else:
|
|
87
|
+
correct_label = _normalize_label(correct)
|
|
88
|
+
correct_text = ""
|
|
89
|
+
|
|
90
|
+
choice_by_label = {
|
|
91
|
+
_normalize_label(choice["label"]): choice["text"]
|
|
92
|
+
for choice in choices
|
|
93
|
+
}
|
|
94
|
+
if correct_label and not correct_text:
|
|
95
|
+
correct_text = choice_by_label.get(correct_label, "")
|
|
96
|
+
if correct_label and correct_text and correct_label not in choice_by_label:
|
|
97
|
+
choices.append({"label": correct_label, "text": correct_text})
|
|
98
|
+
choices.sort(key=lambda choice: _CHOICE_LABELS.index(choice["label"]) if choice["label"] in _CHOICE_LABELS else len(_CHOICE_LABELS))
|
|
99
|
+
choice_by_label[correct_label] = correct_text
|
|
100
|
+
|
|
101
|
+
month = str(item.get("month") or "").strip()
|
|
102
|
+
item_no = item.get("no", row_idx + 1)
|
|
103
|
+
item_id = f"{month}:{item_no}" if month else str(item_no)
|
|
104
|
+
|
|
105
|
+
return {
|
|
106
|
+
"id": item_id,
|
|
107
|
+
"month": month,
|
|
108
|
+
"no": item_no,
|
|
109
|
+
"paper_link": str(item.get("paper_link") or "").strip(),
|
|
110
|
+
"theorem": str(item.get("theorem") or "").strip(),
|
|
111
|
+
"sketch": str(item.get("sketch") or "").strip(),
|
|
112
|
+
"theorem_type": _coerce_theorem_types(item.get("theorem_type")),
|
|
113
|
+
"question": question,
|
|
114
|
+
"choices": choices,
|
|
115
|
+
"correct_choice": {
|
|
116
|
+
"label": correct_label,
|
|
117
|
+
"text": correct_text,
|
|
118
|
+
},
|
|
119
|
+
"source_path": source_path,
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
def load_items(data_path: str) -> list[dict]:
|
|
124
|
+
"""Load and normalise LiveMathematicianBench items from JSON files."""
|
|
125
|
+
files = _iter_monthly_files(data_path)
|
|
126
|
+
if not files:
|
|
127
|
+
raise ValueError(
|
|
128
|
+
"LiveMathematicianBench requires data_path to be a qa_*_final.json file "
|
|
129
|
+
"or a directory containing monthly qa_*_final.json files."
|
|
130
|
+
)
|
|
131
|
+
|
|
132
|
+
items: list[dict] = []
|
|
133
|
+
for path in files:
|
|
134
|
+
raw = _load_json(path)
|
|
135
|
+
if not isinstance(raw, list):
|
|
136
|
+
raise ValueError(f"Expected JSON array in {path}, got {type(raw).__name__}")
|
|
137
|
+
for row_idx, item in enumerate(raw):
|
|
138
|
+
norm = _normalize_item(item, row_idx=row_idx, source_path=path)
|
|
139
|
+
if norm["question"] and norm["choices"] and norm["correct_choice"]["label"]:
|
|
140
|
+
items.append(norm)
|
|
141
|
+
if not items:
|
|
142
|
+
raise ValueError(f"No valid LiveMathematicianBench items loaded from {data_path}")
|
|
143
|
+
return items
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
# ── Dataloader ───────────────────────────────────────────────────────────
|
|
147
|
+
|
|
148
|
+
class LiveMathematicianBenchDataLoader(SplitDataLoader):
|
|
149
|
+
"""LiveMathematicianBench dataloader with per-seed choice shuffling."""
|
|
150
|
+
|
|
151
|
+
def __init__(
|
|
152
|
+
self,
|
|
153
|
+
split_dir: str = "",
|
|
154
|
+
data_path: str = "",
|
|
155
|
+
split_mode: str = "ratio",
|
|
156
|
+
split_ratio: str = "2:1:7",
|
|
157
|
+
split_seed: int = 42,
|
|
158
|
+
split_output_dir: str = "",
|
|
159
|
+
seed: int = 42,
|
|
160
|
+
limit: int = 0,
|
|
161
|
+
shuffle_choices: bool = True,
|
|
162
|
+
**kwargs,
|
|
163
|
+
) -> None:
|
|
164
|
+
super().__init__(
|
|
165
|
+
split_dir=split_dir,
|
|
166
|
+
data_path=data_path,
|
|
167
|
+
split_mode=split_mode,
|
|
168
|
+
split_ratio=split_ratio,
|
|
169
|
+
split_seed=split_seed,
|
|
170
|
+
split_output_dir=split_output_dir,
|
|
171
|
+
seed=seed,
|
|
172
|
+
limit=limit,
|
|
173
|
+
)
|
|
174
|
+
self.shuffle_choices = shuffle_choices
|
|
175
|
+
self._task_types: list[str] = []
|
|
176
|
+
|
|
177
|
+
def load_raw_items(self, data_path: str) -> list[dict]:
|
|
178
|
+
return load_items(data_path)
|
|
179
|
+
|
|
180
|
+
def setup(self, cfg: dict) -> None:
|
|
181
|
+
super().setup(cfg)
|
|
182
|
+
all_items = self.train_items + self.val_items + self.test_items
|
|
183
|
+
task_types: set[str] = set()
|
|
184
|
+
for item in all_items:
|
|
185
|
+
for name in item.get("theorem_type", []):
|
|
186
|
+
if name:
|
|
187
|
+
task_types.add(name)
|
|
188
|
+
self._task_types = sorted(task_types)
|
|
189
|
+
|
|
190
|
+
def get_task_types(self) -> list[str]:
|
|
191
|
+
return list(self._task_types)
|
|
192
|
+
|
|
193
|
+
# ── Choice shuffling ─────────────────────────────────────────────────
|
|
194
|
+
|
|
195
|
+
@staticmethod
|
|
196
|
+
def _item_shuffle_seed(item_id: str, seed: int) -> int:
|
|
197
|
+
digest = hashlib.sha256(f"{seed}:{item_id}".encode("utf-8")).hexdigest()
|
|
198
|
+
return int(digest[:16], 16)
|
|
199
|
+
|
|
200
|
+
def _shuffle_item_choices(self, item: dict, seed: int) -> dict:
|
|
201
|
+
if not self.shuffle_choices:
|
|
202
|
+
return {
|
|
203
|
+
**item,
|
|
204
|
+
"choices": [dict(c) for c in item["choices"]],
|
|
205
|
+
"correct_choice": dict(item["correct_choice"]),
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
shuffled_choices = [dict(c) for c in item["choices"]]
|
|
209
|
+
rng = random.Random(self._item_shuffle_seed(str(item["id"]), seed))
|
|
210
|
+
rng.shuffle(shuffled_choices)
|
|
211
|
+
|
|
212
|
+
original_correct = _normalize_label(item["correct_choice"]["label"])
|
|
213
|
+
remapped_choices: list[dict] = []
|
|
214
|
+
new_correct_choice = dict(item["correct_choice"])
|
|
215
|
+
|
|
216
|
+
for idx, choice in enumerate(shuffled_choices):
|
|
217
|
+
new_label = _CHOICE_LABELS[idx]
|
|
218
|
+
old_label = _normalize_label(choice["label"])
|
|
219
|
+
remapped_choices.append({"label": new_label, "text": choice["text"]})
|
|
220
|
+
if old_label == original_correct:
|
|
221
|
+
new_correct_choice = {"label": new_label, "text": choice["text"]}
|
|
222
|
+
|
|
223
|
+
transformed = dict(item)
|
|
224
|
+
transformed["choices"] = remapped_choices
|
|
225
|
+
transformed["correct_choice"] = new_correct_choice
|
|
226
|
+
return transformed
|
|
227
|
+
|
|
228
|
+
def _materialize_batch(self, items: list[dict], seed: int) -> list[dict]:
|
|
229
|
+
return [self._shuffle_item_choices(item, seed) for item in items]
|
|
230
|
+
|
|
231
|
+
# ── Batch construction (override for choice shuffling) ───────────────
|
|
232
|
+
|
|
233
|
+
def plan_train_epoch(
|
|
234
|
+
self,
|
|
235
|
+
*,
|
|
236
|
+
epoch: int,
|
|
237
|
+
steps_per_epoch: int,
|
|
238
|
+
accumulation: int,
|
|
239
|
+
batch_size: int,
|
|
240
|
+
seed: int,
|
|
241
|
+
**kwargs,
|
|
242
|
+
) -> list[BatchSpec]:
|
|
243
|
+
"""Build a shuffled epoch while preserving per-batch choice shuffling."""
|
|
244
|
+
epoch_rng = random.Random(seed + epoch * 1000)
|
|
245
|
+
items = list(self.train_items)
|
|
246
|
+
epoch_rng.shuffle(items)
|
|
247
|
+
|
|
248
|
+
total_batches = steps_per_epoch * accumulation
|
|
249
|
+
if total_batches <= 0:
|
|
250
|
+
return []
|
|
251
|
+
|
|
252
|
+
batches: list[BatchSpec] = []
|
|
253
|
+
cursor = 0
|
|
254
|
+
for batch_idx in range(total_batches):
|
|
255
|
+
batch_seed = seed + epoch * 1000 + batch_idx + 1
|
|
256
|
+
batch_items = items[cursor: cursor + batch_size]
|
|
257
|
+
cursor += len(batch_items)
|
|
258
|
+
|
|
259
|
+
if not batch_items and items:
|
|
260
|
+
refill_rng = random.Random(batch_seed)
|
|
261
|
+
batch_items = list(items)
|
|
262
|
+
refill_rng.shuffle(batch_items)
|
|
263
|
+
batch_items = batch_items[:batch_size]
|
|
264
|
+
|
|
265
|
+
batch_items = self._materialize_batch(batch_items, batch_seed)
|
|
266
|
+
batches.append(
|
|
267
|
+
BatchSpec(
|
|
268
|
+
phase="train",
|
|
269
|
+
split="train",
|
|
270
|
+
seed=batch_seed,
|
|
271
|
+
batch_size=len(batch_items),
|
|
272
|
+
payload=batch_items,
|
|
273
|
+
)
|
|
274
|
+
)
|
|
275
|
+
|
|
276
|
+
return batches
|
|
277
|
+
|
|
278
|
+
def build_train_batch(self, batch_size: int, seed: int, **kwargs) -> BatchSpec:
|
|
279
|
+
rng = random.Random(seed)
|
|
280
|
+
items = list(self.train_items)
|
|
281
|
+
rng.shuffle(items)
|
|
282
|
+
items = self._materialize_batch(items[:batch_size], seed)
|
|
283
|
+
return BatchSpec(
|
|
284
|
+
phase="train",
|
|
285
|
+
split="train",
|
|
286
|
+
seed=seed,
|
|
287
|
+
batch_size=len(items),
|
|
288
|
+
payload=items,
|
|
289
|
+
)
|
|
290
|
+
|
|
291
|
+
def build_eval_batch(
|
|
292
|
+
self,
|
|
293
|
+
env_num: int,
|
|
294
|
+
split: str,
|
|
295
|
+
seed: int,
|
|
296
|
+
**kwargs,
|
|
297
|
+
) -> BatchSpec:
|
|
298
|
+
items = self.get_split_items(split)
|
|
299
|
+
if env_num and env_num < len(items):
|
|
300
|
+
items = items[:env_num]
|
|
301
|
+
items = self._materialize_batch(items, seed)
|
|
302
|
+
return BatchSpec(
|
|
303
|
+
phase="eval",
|
|
304
|
+
split=split,
|
|
305
|
+
seed=seed,
|
|
306
|
+
batch_size=len(items),
|
|
307
|
+
payload=items,
|
|
308
|
+
)
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
"""LiveMathematicianBench evaluation helpers."""
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
import re
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def extract_answer(text: str) -> str:
|
|
8
|
+
matches = re.findall(r"<answer>(.*?)</answer>", text, re.DOTALL | re.IGNORECASE)
|
|
9
|
+
if matches:
|
|
10
|
+
return matches[-1].strip()
|
|
11
|
+
lines = [ln.strip() for ln in text.strip().splitlines() if ln.strip()]
|
|
12
|
+
if lines:
|
|
13
|
+
return lines[-1]
|
|
14
|
+
return text.strip()
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def normalize_label(text: str) -> str:
|
|
18
|
+
return str(text).strip().upper().rstrip(".):")
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def parse_choice_label(prediction_text: str, choices: list[dict]) -> str:
|
|
22
|
+
answer = extract_answer(prediction_text)
|
|
23
|
+
label = normalize_label(answer)
|
|
24
|
+
valid_labels = {normalize_label(choice.get("label", "")) for choice in choices}
|
|
25
|
+
if label in valid_labels:
|
|
26
|
+
return label
|
|
27
|
+
|
|
28
|
+
answer_lower = answer.lower()
|
|
29
|
+
for choice in choices:
|
|
30
|
+
choice_label = normalize_label(choice.get("label", ""))
|
|
31
|
+
choice_text = str(choice.get("text", "")).strip()
|
|
32
|
+
if choice_text and choice_text.lower() == answer_lower:
|
|
33
|
+
return choice_label
|
|
34
|
+
|
|
35
|
+
first_token = normalize_label(answer.split()[0]) if answer.split() else ""
|
|
36
|
+
if first_token in valid_labels:
|
|
37
|
+
return first_token
|
|
38
|
+
return label
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def evaluate(prediction_text: str, correct_choice: dict, choices: list[dict]) -> dict:
|
|
42
|
+
predicted_label = parse_choice_label(prediction_text, choices)
|
|
43
|
+
correct_label = normalize_label(correct_choice.get("label", ""))
|
|
44
|
+
predicted_text = ""
|
|
45
|
+
correct_text = str(correct_choice.get("text", "")).strip()
|
|
46
|
+
|
|
47
|
+
for choice in choices:
|
|
48
|
+
if normalize_label(choice.get("label", "")) == predicted_label:
|
|
49
|
+
predicted_text = str(choice.get("text", "")).strip()
|
|
50
|
+
break
|
|
51
|
+
|
|
52
|
+
is_correct = float(predicted_label == correct_label)
|
|
53
|
+
return {
|
|
54
|
+
"em": is_correct,
|
|
55
|
+
"f1": is_correct,
|
|
56
|
+
"sub_em": is_correct,
|
|
57
|
+
"predicted_answer": predicted_label or extract_answer(prediction_text),
|
|
58
|
+
"predicted_label": predicted_label,
|
|
59
|
+
"predicted_text": predicted_text,
|
|
60
|
+
"correct_label": correct_label,
|
|
61
|
+
"correct_text": correct_text,
|
|
62
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
You are an expert failure-analysis agent for theorem-grounded mathematical multiple-choice questions.
|
|
2
|
+
|
|
3
|
+
You will be given MULTIPLE failed trajectories from a single minibatch and the current skill document.
|
|
4
|
+
Each trajectory includes the target's response and an evaluation result showing the predicted option
|
|
5
|
+
versus the correct option.
|
|
6
|
+
|
|
7
|
+
Your job is to identify COMMON reasoning failures across the batch and propose concise skill edits.
|
|
8
|
+
|
|
9
|
+
## Failure Type Categories
|
|
10
|
+
- **quantifier_miss**: the agent missed exact quantifiers, scope, or existence/uniqueness conditions
|
|
11
|
+
- **strength_mismatch**: the agent preferred a weaker or stronger statement than what was proved
|
|
12
|
+
- **condition_miss**: the agent ignored hypotheses, equality cases, or domain restrictions
|
|
13
|
+
- **option_confusion**: the agent confused similar answer choices or failed to compare them exactly
|
|
14
|
+
- **other**: none of the above
|
|
15
|
+
|
|
16
|
+
## Rules
|
|
17
|
+
1. Focus on patterns that recur across the minibatch.
|
|
18
|
+
2. Prefer edits that improve exact choice discrimination, not theorem-specific memorization.
|
|
19
|
+
3. Do not hardcode paper-specific content.
|
|
20
|
+
4. Only patch gaps not already covered by the skill.
|
|
21
|
+
|
|
22
|
+
Respond ONLY with a valid JSON object:
|
|
23
|
+
{
|
|
24
|
+
"batch_size": <number>,
|
|
25
|
+
"failure_summary": [
|
|
26
|
+
{"failure_type": "<type>", "count": <int>, "description": "<one-line>"}
|
|
27
|
+
],
|
|
28
|
+
"patch": {
|
|
29
|
+
"reasoning": "<why these edits address the common failures>",
|
|
30
|
+
"edits": [
|
|
31
|
+
{"op": "append", "content": "<markdown>"},
|
|
32
|
+
{"op": "insert_after", "target": "<heading/text>", "content": "<markdown>"},
|
|
33
|
+
{"op": "replace", "target": "<old text>", "content": "<new text>"},
|
|
34
|
+
{"op": "delete", "target": "<exact text to remove>"}
|
|
35
|
+
]
|
|
36
|
+
}
|
|
37
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
You are an expert success-pattern analyst for theorem-grounded mathematical multiple-choice questions.
|
|
2
|
+
|
|
3
|
+
You will be given MULTIPLE successful trajectories from a minibatch and the current skill document.
|
|
4
|
+
Identify generalizable behavior patterns that are genuinely helping the agent choose the exact correct option.
|
|
5
|
+
|
|
6
|
+
## Rules
|
|
7
|
+
- Focus on broadly useful reasoning behaviors.
|
|
8
|
+
- Prefer patterns about exact comparison of options, quantifiers, and equality conditions.
|
|
9
|
+
- Do not add theorem-specific facts.
|
|
10
|
+
- "edits" may be empty if the skill already captures the useful patterns.
|
|
11
|
+
|
|
12
|
+
Respond ONLY with a valid JSON object:
|
|
13
|
+
{
|
|
14
|
+
"batch_size": <number>,
|
|
15
|
+
"success_patterns": ["<pattern 1>", "<pattern 2>"],
|
|
16
|
+
"patch": {
|
|
17
|
+
"reasoning": "<why these patterns matter>",
|
|
18
|
+
"edits": [
|
|
19
|
+
{"op": "append", "content": "<markdown>"},
|
|
20
|
+
{"op": "insert_after", "target": "<heading/text>", "content": "<markdown>"},
|
|
21
|
+
{"op": "replace", "target": "<old text>", "content": "<new text>"},
|
|
22
|
+
{"op": "delete", "target": "<exact text to remove>"}
|
|
23
|
+
]
|
|
24
|
+
}
|
|
25
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
You are an expert mathematical reasoning agent solving multiple-choice questions.
|
|
2
|
+
|
|
3
|
+
{skill_section}## Task Format
|
|
4
|
+
You will receive one mathematics multiple-choice question and its answer choices.
|
|
5
|
+
Reason carefully about quantifiers, hypotheses, extremal wording, and exact equality conditions.
|
|
6
|
+
|
|
7
|
+
## Answer Format
|
|
8
|
+
Think step by step, then provide your final answer inside <answer>...</answer> tags.
|
|
9
|
+
Inside the tags, output only the single choice label, such as A or C.
|
|
10
|
+
|
|
11
|
+
Example:
|
|
12
|
+
<answer>B</answer>
|