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.
Files changed (149) hide show
  1. package/package.json +1 -1
  2. package/template/skills/skillopt-sleep/SKILL.md +42 -0
  3. package/template/skills/skillopt-sleep/configs/_base_/default.yaml +103 -0
  4. package/template/skills/skillopt-sleep/configs/alfworld/default.yaml +29 -0
  5. package/template/skills/skillopt-sleep/configs/docvqa/default.yaml +28 -0
  6. package/template/skills/skillopt-sleep/configs/features/soft_gate.yaml +47 -0
  7. package/template/skills/skillopt-sleep/configs/livemathematicianbench/default.yaml +22 -0
  8. package/template/skills/skillopt-sleep/configs/officeqa/default.yaml +34 -0
  9. package/template/skills/skillopt-sleep/configs/searchqa/default.yaml +32 -0
  10. package/template/skills/skillopt-sleep/configs/spreadsheetbench/default.yaml +34 -0
  11. package/template/skills/skillopt-sleep/scripts/framework/skillopt/__init__.py +28 -0
  12. package/template/skills/skillopt-sleep/scripts/framework/skillopt/config.py +282 -0
  13. package/template/skills/skillopt-sleep/scripts/framework/skillopt/datasets/__init__.py +7 -0
  14. package/template/skills/skillopt-sleep/scripts/framework/skillopt/datasets/base.py +512 -0
  15. package/template/skills/skillopt-sleep/scripts/framework/skillopt/engine/__init__.py +9 -0
  16. package/template/skills/skillopt-sleep/scripts/framework/skillopt/engine/trainer.py +2379 -0
  17. package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/__init__.py +1 -0
  18. package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/_template/README.md +43 -0
  19. package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/_template/config_template.yaml +55 -0
  20. package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/_template/env_template.py +151 -0
  21. package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/_template/loader_template.py +87 -0
  22. package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/alfworld/__init__.py +5 -0
  23. package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/alfworld/adapter.py +428 -0
  24. package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/alfworld/dataloader.py +123 -0
  25. package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/alfworld/prompts/analyst_error.md +55 -0
  26. package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/alfworld/prompts/analyst_success.md +33 -0
  27. package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/alfworld/prompts/rollout_no_history.md +8 -0
  28. package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/alfworld/prompts/rollout_with_history.md +9 -0
  29. package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/alfworld/prompts/rollout_with_memory.md +16 -0
  30. package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/alfworld/reflect.py +4 -0
  31. package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/alfworld/rollout.py +366 -0
  32. package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/alfworld/skills/initial.md +45 -0
  33. package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/alfworld/vendor/__init__.py +9 -0
  34. package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/alfworld/vendor/alfworld_envs.py +221 -0
  35. package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/alfworld/vendor/alfworld_projection.py +60 -0
  36. package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/alfworld/vendor/alfworld_prompts.py +8 -0
  37. package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/alfworld/vendor/config_tw.yaml +145 -0
  38. package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/alfworld/vendor/env_base.py +84 -0
  39. package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/alfworld/vendor/env_manager.py +139 -0
  40. package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/alfworld/vendor/memory.py +87 -0
  41. package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/base.py +329 -0
  42. package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/docvqa/__init__.py +1 -0
  43. package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/docvqa/adapter.py +90 -0
  44. package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/docvqa/dataloader.py +61 -0
  45. package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/docvqa/evaluator.py +113 -0
  46. package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/docvqa/prompts/analyst_error.md +35 -0
  47. package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/docvqa/prompts/analyst_success.md +24 -0
  48. package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/docvqa/prompts/rollout_system.md +12 -0
  49. package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/docvqa/rollout.py +391 -0
  50. package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/docvqa/skills/initial.md +11 -0
  51. package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/livemathematicianbench/__init__.py +1 -0
  52. package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/livemathematicianbench/adapter.py +129 -0
  53. package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/livemathematicianbench/dataloader.py +308 -0
  54. package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/livemathematicianbench/evaluator.py +62 -0
  55. package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/livemathematicianbench/prompts/analyst_error.md +37 -0
  56. package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/livemathematicianbench/prompts/analyst_success.md +25 -0
  57. package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/livemathematicianbench/prompts/rollout_system.md +12 -0
  58. package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/livemathematicianbench/reflect.py +4 -0
  59. package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/livemathematicianbench/rollout.py +434 -0
  60. package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/livemathematicianbench/skills/initial.md +16 -0
  61. package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/officeqa/__init__.py +1 -0
  62. package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/officeqa/adapter.py +112 -0
  63. package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/officeqa/dataloader.py +71 -0
  64. package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/officeqa/evaluator.py +46 -0
  65. package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/officeqa/prompts/analyst_error.md +37 -0
  66. package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/officeqa/prompts/analyst_success.md +25 -0
  67. package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/officeqa/prompts/rollout_system.md +15 -0
  68. package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/officeqa/rollout.py +799 -0
  69. package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/officeqa/skills/initial.md +15 -0
  70. package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/officeqa/tool_runtime.py +552 -0
  71. package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/searchqa/__init__.py +1 -0
  72. package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/searchqa/adapter.py +96 -0
  73. package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/searchqa/dataloader.py +42 -0
  74. package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/searchqa/evaluator.py +100 -0
  75. package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/searchqa/prompts/analyst_error.md +46 -0
  76. package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/searchqa/prompts/analyst_success.md +32 -0
  77. package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/searchqa/prompts/rollout_system.md +13 -0
  78. package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/searchqa/reflect.py +4 -0
  79. package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/searchqa/rollout.py +494 -0
  80. package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/searchqa/skills/initial.md +3 -0
  81. package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/spreadsheetbench/__init__.py +5 -0
  82. package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/spreadsheetbench/adapter.py +159 -0
  83. package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/spreadsheetbench/codegen_agent.py +731 -0
  84. package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/spreadsheetbench/dataloader.py +37 -0
  85. package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/spreadsheetbench/evaluator.py +158 -0
  86. package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/spreadsheetbench/executor.py +67 -0
  87. package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/spreadsheetbench/prompts/analyst_error.md +46 -0
  88. package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/spreadsheetbench/prompts/analyst_success.md +32 -0
  89. package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/spreadsheetbench/prompts/codegen_system.md +1 -0
  90. package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/spreadsheetbench/prompts/critical_rules.md +9 -0
  91. package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/spreadsheetbench/prompts/react_system.md +21 -0
  92. package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/spreadsheetbench/react_agent.py +395 -0
  93. package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/spreadsheetbench/reflect.py +4 -0
  94. package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/spreadsheetbench/rollout.py +979 -0
  95. package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/spreadsheetbench/skills/initial.md +56 -0
  96. package/template/skills/skillopt-sleep/scripts/framework/skillopt/evaluation/__init__.py +13 -0
  97. package/template/skills/skillopt-sleep/scripts/framework/skillopt/evaluation/gate.py +148 -0
  98. package/template/skills/skillopt-sleep/scripts/framework/skillopt/gradient/__init__.py +15 -0
  99. package/template/skills/skillopt-sleep/scripts/framework/skillopt/gradient/aggregate.py +253 -0
  100. package/template/skills/skillopt-sleep/scripts/framework/skillopt/gradient/reflect.py +635 -0
  101. package/template/skills/skillopt-sleep/scripts/framework/skillopt/model/__init__.py +514 -0
  102. package/template/skills/skillopt-sleep/scripts/framework/skillopt/model/azure_openai.py +915 -0
  103. package/template/skills/skillopt-sleep/scripts/framework/skillopt/model/backend_config.py +185 -0
  104. package/template/skills/skillopt-sleep/scripts/framework/skillopt/model/claude_backend.py +371 -0
  105. package/template/skills/skillopt-sleep/scripts/framework/skillopt/model/codex_backend.py +666 -0
  106. package/template/skills/skillopt-sleep/scripts/framework/skillopt/model/codex_harness.py +1057 -0
  107. package/template/skills/skillopt-sleep/scripts/framework/skillopt/model/common.py +229 -0
  108. package/template/skills/skillopt-sleep/scripts/framework/skillopt/model/minimax_backend.py +277 -0
  109. package/template/skills/skillopt-sleep/scripts/framework/skillopt/model/qwen_backend.py +456 -0
  110. package/template/skills/skillopt-sleep/scripts/framework/skillopt/model/router.py +236 -0
  111. package/template/skills/skillopt-sleep/scripts/framework/skillopt/optimizer/__init__.py +15 -0
  112. package/template/skills/skillopt-sleep/scripts/framework/skillopt/optimizer/appendix.py +156 -0
  113. package/template/skills/skillopt-sleep/scripts/framework/skillopt/optimizer/clip.py +109 -0
  114. package/template/skills/skillopt-sleep/scripts/framework/skillopt/optimizer/lr_autonomous.py +108 -0
  115. package/template/skills/skillopt-sleep/scripts/framework/skillopt/optimizer/meta_skill.py +79 -0
  116. package/template/skills/skillopt-sleep/scripts/framework/skillopt/optimizer/rewrite.py +59 -0
  117. package/template/skills/skillopt-sleep/scripts/framework/skillopt/optimizer/scheduler.py +127 -0
  118. package/template/skills/skillopt-sleep/scripts/framework/skillopt/optimizer/select.py +4 -0
  119. package/template/skills/skillopt-sleep/scripts/framework/skillopt/optimizer/skill.py +201 -0
  120. package/template/skills/skillopt-sleep/scripts/framework/skillopt/optimizer/skill_aware.py +206 -0
  121. package/template/skills/skillopt-sleep/scripts/framework/skillopt/optimizer/slow_update.py +396 -0
  122. package/template/skills/skillopt-sleep/scripts/framework/skillopt/optimizer/update_modes.py +135 -0
  123. package/template/skills/skillopt-sleep/scripts/framework/skillopt/prompts/__init__.py +63 -0
  124. package/template/skills/skillopt-sleep/scripts/framework/skillopt/prompts/analyst_error.md +41 -0
  125. package/template/skills/skillopt-sleep/scripts/framework/skillopt/prompts/analyst_error_full_rewrite.md +32 -0
  126. package/template/skills/skillopt-sleep/scripts/framework/skillopt/prompts/analyst_error_rewrite.md +44 -0
  127. package/template/skills/skillopt-sleep/scripts/framework/skillopt/prompts/analyst_success.md +36 -0
  128. package/template/skills/skillopt-sleep/scripts/framework/skillopt/prompts/analyst_success_full_rewrite.md +30 -0
  129. package/template/skills/skillopt-sleep/scripts/framework/skillopt/prompts/analyst_success_rewrite.md +33 -0
  130. package/template/skills/skillopt-sleep/scripts/framework/skillopt/prompts/lr_autonomous.md +20 -0
  131. package/template/skills/skillopt-sleep/scripts/framework/skillopt/prompts/merge_failure.md +30 -0
  132. package/template/skills/skillopt-sleep/scripts/framework/skillopt/prompts/merge_failure_full_rewrite.md +28 -0
  133. package/template/skills/skillopt-sleep/scripts/framework/skillopt/prompts/merge_failure_rewrite.md +26 -0
  134. package/template/skills/skillopt-sleep/scripts/framework/skillopt/prompts/merge_final.md +33 -0
  135. package/template/skills/skillopt-sleep/scripts/framework/skillopt/prompts/merge_final_full_rewrite.md +28 -0
  136. package/template/skills/skillopt-sleep/scripts/framework/skillopt/prompts/merge_final_rewrite.md +25 -0
  137. package/template/skills/skillopt-sleep/scripts/framework/skillopt/prompts/merge_success.md +28 -0
  138. package/template/skills/skillopt-sleep/scripts/framework/skillopt/prompts/merge_success_full_rewrite.md +28 -0
  139. package/template/skills/skillopt-sleep/scripts/framework/skillopt/prompts/merge_success_rewrite.md +25 -0
  140. package/template/skills/skillopt-sleep/scripts/framework/skillopt/prompts/meta_skill.md +40 -0
  141. package/template/skills/skillopt-sleep/scripts/framework/skillopt/prompts/ranking.md +20 -0
  142. package/template/skills/skillopt-sleep/scripts/framework/skillopt/prompts/ranking_rewrite.md +15 -0
  143. package/template/skills/skillopt-sleep/scripts/framework/skillopt/prompts/rewrite_skill.md +25 -0
  144. package/template/skills/skillopt-sleep/scripts/framework/skillopt/prompts/slow_update.md +60 -0
  145. package/template/skills/skillopt-sleep/scripts/framework/skillopt/scheduler/__init__.py +8 -0
  146. package/template/skills/skillopt-sleep/scripts/framework/skillopt/types.py +306 -0
  147. package/template/skills/skillopt-sleep/scripts/framework/skillopt/utils/__init__.py +4 -0
  148. package/template/skills/skillopt-sleep/scripts/framework/skillopt/utils/json_utils.py +172 -0
  149. package/template/skills/skillopt-sleep/scripts/framework/skillopt/utils/scoring.py +28 -0
@@ -0,0 +1,37 @@
1
+ """SpreadsheetBench task dataloader."""
2
+ from __future__ import annotations
3
+
4
+ from skillopt.datasets.base import SplitDataLoader
5
+
6
+
7
+ class SpreadsheetBenchDataLoader(SplitDataLoader):
8
+ """SpreadsheetBench dataloader.
9
+
10
+ Each split directory contains a .json file (JSON array of task items).
11
+ Spreadsheet files referenced by items live under a separate ``data_root``.
12
+ """
13
+
14
+ def __init__(
15
+ self,
16
+ split_dir: str = "",
17
+ data_path: str = "",
18
+ split_mode: str = "ratio",
19
+ split_ratio: str = "2:1:7",
20
+ split_seed: int = 42,
21
+ split_output_dir: str = "",
22
+ data_root: str = "",
23
+ seed: int = 42,
24
+ limit: int = 0,
25
+ **kwargs,
26
+ ) -> None:
27
+ super().__init__(
28
+ split_dir=split_dir,
29
+ data_path=data_path,
30
+ split_mode=split_mode,
31
+ split_ratio=split_ratio,
32
+ split_seed=split_seed,
33
+ split_output_dir=split_output_dir,
34
+ seed=seed,
35
+ limit=limit,
36
+ )
37
+ self.data_root = data_root
@@ -0,0 +1,158 @@
1
+ """Cell-value evaluator faithful to the official SpreadsheetBench
2
+ `evaluation/evaluation.py` (https://github.com/RUCKBReasoning/SpreadsheetBench).
3
+
4
+ Key rules (copied from the official `transform_value` / `compare_cell_value`):
5
+ * numeric values (int/float and numeric strings) are compared after
6
+ ``round(float(v), 2)`` — a fixed 2-decimal quantization (NOT a tolerance);
7
+ * ``datetime.time`` is stringified and the trailing microseconds stripped;
8
+ * ``datetime.datetime`` is converted to an Excel serial day and rounded
9
+ to an integer day;
10
+ * an empty string ``""`` and ``None`` are considered equal, but otherwise
11
+ ``type(v1) != type(v2)`` fails the comparison.
12
+
13
+ Format/style comparison is deliberately NOT performed — the official
14
+ reference evaluator also skips it (the relevant lines are commented out
15
+ in `cell_level_compare`). soft vs hard is defined at the run_bench level
16
+ across a task's multiple test cases, not here.
17
+ """
18
+ from __future__ import annotations
19
+
20
+ import datetime
21
+ import os
22
+ import re
23
+
24
+ import openpyxl
25
+
26
+
27
+ # ---------- value transform / compare (official port) ----------
28
+
29
+ def _datetime_to_float(dt: datetime.datetime) -> float:
30
+ excel_start_date = datetime.datetime(1899, 12, 30)
31
+ delta = dt - excel_start_date
32
+ return delta.days + delta.seconds / 86400.0
33
+
34
+
35
+ def _transform_value(v):
36
+ if isinstance(v, bool):
37
+ # openpyxl can return Python bool; official code doesn't special-case
38
+ # bools, but round(float(True), 2) == 1.0 which breaks 1 vs True. Keep
39
+ # parity with the official transform by promoting bool -> float.
40
+ return round(float(v), 2)
41
+ if isinstance(v, (int, float)):
42
+ return round(float(v), 2)
43
+ if isinstance(v, datetime.time):
44
+ return str(v)[:-3]
45
+ if isinstance(v, datetime.datetime):
46
+ return round(_datetime_to_float(v), 0)
47
+ if isinstance(v, str):
48
+ try:
49
+ return round(float(v), 2)
50
+ except ValueError:
51
+ return v
52
+ return v
53
+
54
+
55
+ def _compare_cell_value(v1, v2) -> bool:
56
+ v1 = _transform_value(v1)
57
+ v2 = _transform_value(v2)
58
+ if (v1 == "" and v2 is None) or (v1 is None and v2 == ""):
59
+ return True
60
+ if (v1 == "" and v2 == "") or (v1 is None and v2 is None):
61
+ return True
62
+ if type(v1) is not type(v2):
63
+ return False
64
+ return v1 == v2
65
+
66
+
67
+ # ---------- range parsing (official port) ----------
68
+
69
+ def _col_num2name(n: int) -> str:
70
+ name = ""
71
+ while n > 0:
72
+ n, r = divmod(n - 1, 26)
73
+ name = chr(65 + r) + name
74
+ return name
75
+
76
+
77
+ def _col_name2num(name: str) -> int:
78
+ num = 0
79
+ for c in name:
80
+ num = num * 26 + (ord(c) - ord("A") + 1)
81
+ return num
82
+
83
+
84
+ def _parse_range(range_str: str):
85
+ start_cell, end_cell = range_str.split(":")
86
+ sc = "".join(ch for ch in start_cell if ch.isalpha())
87
+ sr = "".join(ch for ch in start_cell if ch.isdigit())
88
+ ec = "".join(ch for ch in end_cell if ch.isalpha())
89
+ er = "".join(ch for ch in end_cell if ch.isdigit())
90
+ return (_col_name2num(sc), int(sr)), (_col_name2num(ec), int(er))
91
+
92
+
93
+ def _generate_cell_names(range_str: str):
94
+ if ":" not in range_str:
95
+ return [range_str]
96
+ (sc, sr), (ec, er) = _parse_range(range_str)
97
+ cols = [_col_num2name(i) for i in range(sc, ec + 1)]
98
+ return [f"{c}{r}" for c in cols for r in range(sr, er + 1)]
99
+
100
+
101
+ def _cell_level_compare(wb_gt, wb_proc, sheet_name: str, cell_range: str):
102
+ if sheet_name not in wb_proc.sheetnames:
103
+ return False, f"worksheet not found: {sheet_name}"
104
+ ws_gt = wb_gt[sheet_name]
105
+ ws_proc = wb_proc[sheet_name]
106
+ for cn in _generate_cell_names(cell_range):
107
+ cg = ws_gt[cn]
108
+ cp = ws_proc[cn]
109
+ if not _compare_cell_value(cg.value, cp.value):
110
+ return False, f"value@{sheet_name}!{cn}: gt={cg.value!r} pred={cp.value!r}"
111
+ return True, ""
112
+
113
+
114
+ # ---------- public API ----------
115
+
116
+ def compare_workbooks(gt_file: str, proc_file: str, answer_position: str) -> tuple[bool, str]:
117
+ """Return (ok, msg). Single test-case comparison, official semantics."""
118
+ if not os.path.exists(proc_file):
119
+ return False, "file not exist"
120
+ try:
121
+ wb_gt = openpyxl.load_workbook(filename=gt_file, data_only=True)
122
+ wb_proc = openpyxl.load_workbook(filename=proc_file, data_only=True)
123
+ except Exception as e: # noqa: BLE001
124
+ return False, f"load error: {e}"
125
+ try:
126
+ ok_all = True
127
+ msg_first = ""
128
+ for scr in (answer_position or "").split(","):
129
+ scr = scr.strip()
130
+ if not scr:
131
+ continue
132
+ if "!" in scr:
133
+ sheet_name, cell_range = scr.split("!", 1)
134
+ sheet_name = sheet_name.strip().strip("'\"")
135
+ else:
136
+ sheet_name = wb_gt.sheetnames[0]
137
+ cell_range = scr
138
+ cell_range = cell_range.strip().strip("'\"")
139
+ ok, msg = _cell_level_compare(wb_gt, wb_proc, sheet_name, cell_range)
140
+ if not ok:
141
+ ok_all = False
142
+ if not msg_first:
143
+ msg_first = msg
144
+ return ok_all, msg_first
145
+ finally:
146
+ wb_gt.close()
147
+ wb_proc.close()
148
+
149
+
150
+ def evaluate(pred_path: str, gold_path: str,
151
+ instruction_type: str, answer_position: str) -> dict:
152
+ """Single test-case evaluate. soft/hard aggregation happens in run_bench."""
153
+ ok, msg = compare_workbooks(gold_path, pred_path, answer_position)
154
+ return {
155
+ "ok": ok,
156
+ "reason": msg,
157
+ "instruction_type": instruction_type,
158
+ }
@@ -0,0 +1,67 @@
1
+ """Execute LLM-generated Python code against an input xlsx to produce an output xlsx."""
2
+ from __future__ import annotations
3
+
4
+ import os
5
+ import re
6
+ import subprocess
7
+ import sys
8
+ import tempfile
9
+ import textwrap
10
+
11
+
12
+ RUNNER_TEMPLATE = textwrap.dedent(
13
+ """
14
+ import os, sys, traceback
15
+ INPUT_PATH = {input_path!r}
16
+ OUTPUT_PATH = {output_path!r}
17
+ try:
18
+ {user_code_indented}
19
+ except Exception:
20
+ traceback.print_exc()
21
+ sys.exit(2)
22
+ """
23
+ )
24
+
25
+ # Regex to strip user-defined INPUT_PATH / OUTPUT_PATH assignments,
26
+ # since the runner template injects the correct values.
27
+ _PATH_ASSIGN_RE = re.compile(
28
+ r'^\s*(INPUT_PATH|OUTPUT_PATH)\s*=\s*.+$', re.MULTILINE
29
+ )
30
+
31
+
32
+ def _strip_path_assignments(code: str) -> str:
33
+ """Remove INPUT_PATH/OUTPUT_PATH assignments from user code."""
34
+ return _PATH_ASSIGN_RE.sub("", code)
35
+
36
+
37
+ def run_generated_code(code: str, input_path: str, output_path: str, timeout: int | None = 120) -> tuple[bool, str]:
38
+ os.makedirs(os.path.dirname(output_path), exist_ok=True)
39
+ cleaned = _strip_path_assignments(code)
40
+ indented = textwrap.indent(cleaned, " ")
41
+ script = RUNNER_TEMPLATE.format(
42
+ input_path=input_path,
43
+ output_path=output_path,
44
+ user_code_indented=indented,
45
+ )
46
+ with tempfile.NamedTemporaryFile("w", suffix=".py", delete=False) as f:
47
+ f.write(script)
48
+ tmp = f.name
49
+ try:
50
+ proc = subprocess.run(
51
+ [sys.executable, tmp],
52
+ capture_output=True,
53
+ text=True,
54
+ timeout=timeout if timeout and timeout > 0 else None,
55
+ )
56
+ if proc.returncode != 0:
57
+ return False, (proc.stdout + "\n" + proc.stderr).strip()
58
+ if not os.path.exists(output_path):
59
+ return False, "output file was not created"
60
+ return True, ""
61
+ except subprocess.TimeoutExpired:
62
+ return False, f"timeout after {timeout}s"
63
+ finally:
64
+ try:
65
+ os.unlink(tmp)
66
+ except OSError:
67
+ pass
@@ -0,0 +1,46 @@
1
+ You are an expert failure-analysis agent for spreadsheet manipulation tasks.
2
+
3
+ You will be given MULTIPLE failed agent trajectories from a single minibatch
4
+ and the current skill document.
5
+ Your job is to identify the most important COMMON failure patterns across
6
+ the batch and propose a concise set of skill edits.
7
+
8
+ ## Failure Type Categories
9
+ - **rule_missing**: the skill lacks a relevant rule for this type of task
10
+ - **rule_wrong**: an existing skill rule is misleading or incorrect
11
+ - **rule_ignored**: the skill has the right rule but the agent did not follow it
12
+ - **data_exploration**: the agent did not read enough data from the spreadsheet
13
+ - **code_error**: the agent's code has a bug unrelated to the skill
14
+ - **other**: none of the above
15
+
16
+ ## Analysis Process
17
+ 1. Read ALL failed trajectories in the minibatch.
18
+ 2. Identify the most prevalent, systematic failure patterns across them.
19
+ 3. For each pattern, classify its failure type.
20
+ 4. Propose skill edits that address the COMMON patterns — not individual edge cases.
21
+ 5. Edits must be generalizable; do not hardcode task-specific values
22
+ (file paths, cell addresses, expected values).
23
+ 6. Only patch gaps in the skill — do not duplicate existing content.
24
+ 7. If the failure is because the agent did not read enough spreadsheet rows/columns
25
+ to understand the data, propose a patch encouraging broader data exploration.
26
+
27
+ You will be told the maximum number of edits (the budget L). Produce AT MOST L edits,
28
+ focusing on the highest-impact patterns. You may produce fewer if warranted.
29
+
30
+ Respond ONLY with a valid JSON object (no markdown fences, no extra text):
31
+ {
32
+ "batch_size": <number of trajectories analysed>,
33
+ "failure_summary": [
34
+ {"failure_type": "<type>", "count": <int>, "description": "<one-line>"}
35
+ ],
36
+ "patch": {
37
+ "reasoning": "<why these edits address the batch's common failures>",
38
+ "edits": [
39
+ {"op": "append", "content": "<markdown to add at end of skill>"},
40
+ {"op": "insert_after", "target": "<exact heading/text to insert after>", "content": "<markdown>"},
41
+ {"op": "replace", "target": "<exact text to replace>", "content": "<replacement>"},
42
+ {"op": "delete", "target": "<exact text to remove>"}
43
+ ]
44
+ }
45
+ }
46
+ Only include edits that are needed. "edits" can be an empty list if no patch is warranted.
@@ -0,0 +1,32 @@
1
+ You are an expert success-pattern analyst for AI spreadsheet agents.
2
+
3
+ You will be given MULTIPLE successful agent trajectories from a single minibatch
4
+ and the current skill document. Your job is to identify generalizable behavior
5
+ patterns that are COMMON across the batch and worth encoding in the skill.
6
+
7
+ ## Rules
8
+ - Only propose patches for patterns NOT already covered in the skill.
9
+ - Focus on patterns that appear across MULTIPLE trajectories in the batch.
10
+ - Be concise. Patterns must generalize beyond specific tasks.
11
+ - Prefer reinforcing existing sections over adding new top-level sections.
12
+ - If the agents' success involved reading enough data rows or using a smart
13
+ exploration strategy, consider reinforcing that in the patch.
14
+
15
+ You will be told the maximum number of edits (the budget L). Produce AT MOST L edits,
16
+ focusing on the most broadly applicable patterns. You may produce fewer if warranted.
17
+
18
+ Respond ONLY with a valid JSON object:
19
+ {
20
+ "batch_size": <number of trajectories analysed>,
21
+ "success_patterns": ["<pattern 1>", "<pattern 2>"],
22
+ "patch": {
23
+ "reasoning": "<why these patterns are worth encoding>",
24
+ "edits": [
25
+ {"op": "append", "content": "<markdown>"},
26
+ {"op": "insert_after", "target": "<heading/text>", "content": "<markdown>"},
27
+ {"op": "replace", "target": "<old text>", "content": "<new text>"},
28
+ {"op": "delete", "target": "<exact text to remove>"}
29
+ ]
30
+ }
31
+ }
32
+ "edits" may be empty if the skill already covers all observed patterns.
@@ -0,0 +1 @@
1
+ You are an expert Python programmer specializing in spreadsheet manipulation. You will be given a user instruction together with a preview of an input .xlsx file. Your job is to write a single self-contained Python script that reads the input file at the path stored in the variable INPUT_PATH, performs the requested manipulation, and saves the result to OUTPUT_PATH. Use only the standard library, openpyxl, and pandas. Do not print anything. Do not use input(). Do not hardcode file paths. Return ONLY the Python code inside a single ```python ... ``` fenced block.
@@ -0,0 +1,9 @@
1
+ ## Critical Rules (MUST follow)
2
+ 1. NEVER write Excel formulas to cells that will be graded on their displayed value.
3
+ openpyxl does NOT compute formulas -- the evaluator will see None.
4
+ Instead, compute results in Python and write literal values (numbers/strings).
5
+ 2. After saving the workbook, ALWAYS reopen and verify the written values:
6
+ `wb2 = openpyxl.load_workbook(OUTPUT_PATH); print(wb2[sheet][cell].value)`
7
+ 3. Use the `write_file` tool to create solution.py -- it avoids shell escaping issues.
8
+ Do NOT use `echo "..." > solution.py` for multi-line scripts.
9
+
@@ -0,0 +1,21 @@
1
+ You are an expert spreadsheet manipulation agent.
2
+
3
+ {critical_rules}{skill_section}## Tools
4
+ You have two tools:
5
+ - `bash` -- execute any shell command and receive its output.
6
+ - `write_file` -- write content to a file (path, content). Use this for solution.py.
7
+
8
+ ## Protocol
9
+ 1. Explore the input spreadsheet to understand its structure (sheets, headers, row count).
10
+ 2. Use the `write_file` tool to create `solution.py` in the current directory.
11
+ solution.py MUST start with:
12
+ INPUT_PATH = "<exact input path given in the task>"
13
+ OUTPUT_PATH = "<exact output path given in the task>"
14
+ Then perform the manipulation and save the result to OUTPUT_PATH.
15
+ Use only: standard library, openpyxl, pandas.
16
+ 3. Run `python solution.py` via `bash` and verify the output was created.
17
+ 4. Fix any errors and re-run until the output is correct.
18
+ 5. Once OUTPUT_PATH exists and is correct, stop calling tools.
19
+
20
+ Do NOT use any libraries other than standard library, openpyxl, and pandas.
21
+ Do NOT hardcode cell values from the preview -- iterate over actual rows.