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,428 @@
1
+ """ALFWorld environment adapter for ReflACT.
2
+
3
+ Connects the ReflACT training loop to ALFWorld by implementing
4
+ :class:`~skillopt.envs.base.EnvAdapter`.
5
+ """
6
+ from __future__ import annotations
7
+
8
+ from dataclasses import dataclass
9
+ import json
10
+ import os
11
+
12
+ from skillopt.datasets.base import BatchSpec
13
+ from skillopt.envs.base import EnvAdapter
14
+ from skillopt.envs.alfworld.dataloader import ALFWorldDataLoader
15
+ from skillopt.envs.alfworld.rollout import (
16
+ build_alfworld_env,
17
+ run_alfworld_batch,
18
+ TASKS,
19
+ )
20
+ from skillopt.utils import compute_score
21
+
22
+
23
+ @dataclass(frozen=True)
24
+ class ALFWorldBatchRun:
25
+ """Lazy ALFWorld batch description.
26
+
27
+ The adapter materializes this in rollout chunks so a large evaluation set
28
+ does not keep every ALFWorld simulator open at once.
29
+ """
30
+
31
+ env_num: int
32
+ eval_dataset: str
33
+ seed: int
34
+ is_train: bool
35
+ workers: int
36
+ specific_gamefiles: list[str] | None = None
37
+ result_ids: list[str] | None = None
38
+ items: list[dict] | None = None
39
+
40
+ def __iter__(self):
41
+ return iter(self.items or [])
42
+
43
+ def __len__(self) -> int:
44
+ return int(self.env_num or 0)
45
+
46
+
47
+ class ALFWorldAdapter(EnvAdapter):
48
+ """ALFWorld environment adapter.
49
+
50
+ Parameters
51
+ ----------
52
+ max_steps : int
53
+ Maximum steps per ALFWorld episode (default 50).
54
+ max_api_workers : int
55
+ Maximum concurrent API calls during rollout (default 8).
56
+ analyst_workers : int
57
+ Parallel workers for analyst stage (default 16).
58
+ failure_only : bool
59
+ If True, only run error analyst (skip success analyst).
60
+ minibatch_size : int
61
+ Trajectories per analyst group, M (default 8).
62
+ edit_budget : int
63
+ Maximum edits per minibatch, L (default 4).
64
+ """
65
+
66
+ def __init__(
67
+ self,
68
+ split_dir: str = "",
69
+ data_path: str = "",
70
+ split_mode: str = "split_dir",
71
+ split_ratio: str = "2:1:7",
72
+ split_seed: int = 42,
73
+ split_output_dir: str = "",
74
+ seed: int = 42,
75
+ limit: int = 0,
76
+ train_size: int = 0,
77
+ max_steps: int = 50,
78
+ workers: int = 8,
79
+ max_api_workers: int = 8,
80
+ analyst_workers: int = 16,
81
+ failure_only: bool = False,
82
+ minibatch_size: int = 8,
83
+ edit_budget: int = 4,
84
+ max_completion_tokens: int = 16384,
85
+ ) -> None:
86
+ self.max_steps = max_steps
87
+ self.workers = max(int(workers or 1), 1)
88
+ self.max_api_workers = max_api_workers
89
+ self.max_completion_tokens = int(max_completion_tokens)
90
+ self.analyst_workers = analyst_workers
91
+ self.failure_only = failure_only
92
+ self.minibatch_size = minibatch_size
93
+ self.edit_budget = edit_budget
94
+ self.dataloader = ALFWorldDataLoader(
95
+ split_dir=split_dir,
96
+ data_path=data_path,
97
+ split_mode=split_mode,
98
+ split_ratio=split_ratio,
99
+ split_seed=split_seed,
100
+ split_output_dir=split_output_dir,
101
+ seed=seed,
102
+ limit=limit,
103
+ train_size=train_size,
104
+ )
105
+ self._traj_cache: dict[str, dict | None] = {}
106
+
107
+ def setup(self, cfg: dict) -> None:
108
+ super().setup(cfg)
109
+ self.dataloader.setup(cfg)
110
+
111
+ def _load_traj_data(self, item: dict) -> dict | None:
112
+ gamefile = str(item.get("gamefile") or "").strip()
113
+ if not gamefile:
114
+ return None
115
+ if gamefile in self._traj_cache:
116
+ return self._traj_cache[gamefile]
117
+
118
+ traj_path = os.path.join(os.path.dirname(gamefile), "traj_data.json")
119
+ try:
120
+ with open(traj_path, encoding="utf-8") as f:
121
+ data = json.load(f)
122
+ except Exception:
123
+ data = None
124
+ self._traj_cache[gamefile] = data
125
+ return data
126
+
127
+ @staticmethod
128
+ def _unique_lines(values: list[str], *, limit: int = 0) -> list[str]:
129
+ lines: list[str] = []
130
+ seen: set[str] = set()
131
+ for raw in values:
132
+ line = str(raw or "").strip()
133
+ if not line or line in seen:
134
+ continue
135
+ seen.add(line)
136
+ lines.append(line)
137
+ if limit > 0 and len(lines) >= limit:
138
+ break
139
+ return lines
140
+
141
+ @staticmethod
142
+ def _format_high_pddl(high_pddl: list[dict]) -> list[str]:
143
+ steps: list[str] = []
144
+ for idx, step in enumerate(high_pddl or [], start=1):
145
+ discrete = step.get("discrete_action") or {}
146
+ action = str(discrete.get("action") or "").strip()
147
+ args = [str(arg).strip() for arg in (discrete.get("args") or []) if str(arg).strip()]
148
+ if action and args:
149
+ text = f"{action}({', '.join(args)})"
150
+ elif action:
151
+ text = action
152
+ else:
153
+ planner_action = step.get("planner_action") or {}
154
+ text = str(planner_action.get("action") or "").strip()
155
+ if text:
156
+ steps.append(f"{idx}. {text}")
157
+ return steps
158
+
159
+ def _build_reference_bundle(self, item: dict) -> dict:
160
+ data = self._load_traj_data(item)
161
+ if not data:
162
+ return {}
163
+
164
+ anns = ((data.get("turk_annotations") or {}).get("anns") or [])
165
+ task_descs = self._unique_lines(
166
+ [ann.get("task_desc", "") for ann in anns],
167
+ limit=3,
168
+ )
169
+ high_descs = self._unique_lines(
170
+ [step for ann in anns for step in (ann.get("high_descs") or [])],
171
+ limit=12,
172
+ )
173
+ pddl_params = {
174
+ key: value
175
+ for key, value in (data.get("pddl_params") or {}).items()
176
+ if value not in ("", None, [], {})
177
+ }
178
+ scene = data.get("scene") or {}
179
+ scene_summary = {
180
+ key: scene.get(key)
181
+ for key in ("floor_plan", "scene_num", "dirty_and_empty")
182
+ if scene.get(key) not in ("", None, [], {})
183
+ }
184
+ high_pddl = self._format_high_pddl((data.get("plan") or {}).get("high_pddl") or [])
185
+ task_type = str(data.get("task_type") or item.get("task_type") or "").strip()
186
+ return {
187
+ "task_type": task_type,
188
+ "task_descs": task_descs,
189
+ "high_descs": high_descs,
190
+ "pddl_params": pddl_params,
191
+ "high_pddl": high_pddl,
192
+ "scene_summary": scene_summary,
193
+ }
194
+
195
+ def build_reference_text(self, item: dict) -> str:
196
+ bundle = self._build_reference_bundle(item)
197
+ if not bundle:
198
+ return ""
199
+
200
+ parts: list[str] = []
201
+ if bundle["task_type"]:
202
+ parts.append(f"## Reference Task Type\n{bundle['task_type']}")
203
+ if bundle["task_descs"]:
204
+ parts.append(
205
+ "## Reference Human Task Descriptions\n"
206
+ + "\n".join(f"- {line}" for line in bundle["task_descs"])
207
+ )
208
+ if bundle["high_descs"]:
209
+ parts.append(
210
+ "## Reference Human High-Level Steps\n"
211
+ + "\n".join(f"{idx}. {line}" for idx, line in enumerate(bundle["high_descs"], start=1))
212
+ )
213
+ if bundle["pddl_params"]:
214
+ parts.append(
215
+ "## Reference PDDL Params\n"
216
+ + "\n".join(f"- {key}: {value}" for key, value in bundle["pddl_params"].items())
217
+ )
218
+ if bundle["high_pddl"]:
219
+ parts.append(
220
+ "## Reference Planner High-Level Plan\n" + "\n".join(bundle["high_pddl"])
221
+ )
222
+ if bundle["scene_summary"]:
223
+ parts.append(
224
+ "## Reference Scene Summary\n"
225
+ + "\n".join(f"- {key}: {value}" for key, value in bundle["scene_summary"].items())
226
+ )
227
+ return "\n\n".join(parts)
228
+
229
+ def get_reference_metadata(self, item: dict) -> dict:
230
+ bundle = self._build_reference_bundle(item)
231
+ if not bundle:
232
+ return {"fields": [], "preview": ""}
233
+
234
+ fields: list[str] = []
235
+ previews: list[str] = []
236
+ if bundle["task_type"]:
237
+ fields.append("task_type")
238
+ previews.append(f"[task_type] {bundle['task_type']}")
239
+ if bundle["task_descs"]:
240
+ fields.append("task_desc")
241
+ previews.append("[task_desc]\n" + "\n".join(bundle["task_descs"][:2]))
242
+ if bundle["high_descs"]:
243
+ fields.append("high_descs")
244
+ previews.append("[high_descs]\n" + "\n".join(bundle["high_descs"][:3]))
245
+ if bundle["pddl_params"]:
246
+ fields.append("pddl_params")
247
+ previews.append(
248
+ "[pddl_params]\n"
249
+ + "\n".join(
250
+ f"{key}: {value}" for key, value in list(bundle["pddl_params"].items())[:4]
251
+ )
252
+ )
253
+ if bundle["high_pddl"]:
254
+ fields.append("plan.high_pddl")
255
+ previews.append("[plan.high_pddl]\n" + "\n".join(bundle["high_pddl"][:3]))
256
+ if bundle["scene_summary"]:
257
+ fields.append("scene")
258
+ previews.append(
259
+ "[scene]\n"
260
+ + "\n".join(
261
+ f"{key}: {value}" for key, value in bundle["scene_summary"].items()
262
+ )
263
+ )
264
+ return {
265
+ "fields": fields,
266
+ "preview": "\n\n".join(previews)[:600],
267
+ }
268
+
269
+ @staticmethod
270
+ def _infer_dataset_from_gamefile(gamefile: str) -> tuple[str, bool]:
271
+ path = str(gamefile or "")
272
+ if "/valid_seen/" in path:
273
+ return "eval_in_distribution", False
274
+ if "/valid_unseen/" in path:
275
+ return "eval_out_of_distribution", False
276
+ return "train", True
277
+
278
+ def get_dataloader(self):
279
+ return self.dataloader
280
+
281
+ def _comparison_items(self, items: list[dict]) -> list[dict]:
282
+ enriched: list[dict] = []
283
+ for item in items:
284
+ row = dict(item)
285
+ bundle = self._build_reference_bundle(row)
286
+ if bundle.get("task_descs"):
287
+ row["task_description"] = bundle["task_descs"][0]
288
+ elif bundle.get("task_type"):
289
+ row["task_description"] = bundle["task_type"]
290
+ enriched.append(row)
291
+ return enriched
292
+
293
+ def requires_ray(self) -> bool:
294
+ return False
295
+
296
+ def build_env_from_batch(self, batch: BatchSpec, **kwargs):
297
+ gamefiles = list(batch.metadata.get("gamefiles") or [])
298
+ result_ids = list(batch.metadata.get("result_ids") or [])
299
+ items = self._comparison_items(list(batch.payload or []))
300
+ return ALFWorldBatchRun(
301
+ env_num=batch.batch_size,
302
+ eval_dataset=batch.metadata.get("eval_dataset", batch.split),
303
+ seed=batch.seed,
304
+ is_train=batch.metadata.get("is_train", batch.phase == "train"),
305
+ specific_gamefiles=gamefiles or None,
306
+ result_ids=result_ids or None,
307
+ items=items,
308
+ workers=self.workers,
309
+ )
310
+
311
+ def build_train_env(self, batch_size: int, seed: int, **kwargs):
312
+ batch = self.dataloader.build_train_batch(batch_size=batch_size, seed=seed, **kwargs)
313
+ return self.build_env_from_batch(batch, **kwargs)
314
+
315
+ def build_eval_env(self, env_num: int, split: str, seed: int, **kwargs):
316
+ batch = self.dataloader.build_eval_batch(env_num=env_num, split=split, seed=seed, **kwargs)
317
+ return self.build_env_from_batch(batch, **kwargs)
318
+
319
+ def rollout(
320
+ self,
321
+ env_manager,
322
+ skill_content: str,
323
+ out_dir: str,
324
+ **kwargs,
325
+ ) -> list[dict]:
326
+ results_path = os.path.join(out_dir, "results.jsonl")
327
+ os.makedirs(out_dir, exist_ok=True)
328
+
329
+ # Resume support
330
+ if os.path.exists(results_path):
331
+ existing: list[dict] = []
332
+ with open(results_path) as f:
333
+ for line in f:
334
+ try:
335
+ existing.append(json.loads(line))
336
+ except Exception:
337
+ pass
338
+ if existing:
339
+ return existing
340
+
341
+ if isinstance(env_manager, ALFWorldBatchRun):
342
+ results = self._run_batch(
343
+ env_manager,
344
+ skill_content=skill_content,
345
+ out_dir=out_dir,
346
+ )
347
+ else:
348
+ results = run_alfworld_batch(
349
+ env_manager=env_manager,
350
+ skill_content=skill_content,
351
+ max_steps=self.max_steps,
352
+ out_root=out_dir,
353
+ max_api_workers=self.max_api_workers,
354
+ max_completion_tokens=self.max_completion_tokens,
355
+ result_ids=getattr(env_manager, "_skillopt_result_ids", None),
356
+ )
357
+
358
+ with open(results_path, "w") as f:
359
+ for r in results:
360
+ f.write(json.dumps(r, ensure_ascii=False) + "\n")
361
+
362
+ return results
363
+
364
+ @staticmethod
365
+ def _close_env(env_manager) -> None:
366
+ close = getattr(env_manager, "close", None)
367
+ if callable(close):
368
+ close()
369
+
370
+ def _run_batch(
371
+ self,
372
+ batch: ALFWorldBatchRun,
373
+ skill_content: str,
374
+ out_dir: str,
375
+ *,
376
+ diagnostic_mode: bool = False,
377
+ diagnostic_instruction: str = "",
378
+ ) -> list[dict]:
379
+ total = int(batch.env_num or 0)
380
+ if total <= 0:
381
+ return []
382
+
383
+ workers = max(1, min(int(batch.workers or self.workers), total))
384
+ if total > workers:
385
+ print(
386
+ f" [alfworld rollout] episodes={total} "
387
+ f"env_workers={workers} chunks={(total + workers - 1) // workers}"
388
+ )
389
+
390
+ all_results: list[dict] = []
391
+ for start in range(0, total, workers):
392
+ chunk_size = min(workers, total - start)
393
+ chunk_gamefiles = (
394
+ batch.specific_gamefiles[start:start + chunk_size]
395
+ if batch.specific_gamefiles
396
+ else None
397
+ )
398
+ chunk_ids = (
399
+ batch.result_ids[start:start + chunk_size]
400
+ if batch.result_ids
401
+ else [f"env_{idx:03d}" for idx in range(start, start + chunk_size)]
402
+ )
403
+ chunk_env = build_alfworld_env(
404
+ env_num=chunk_size,
405
+ eval_dataset=batch.eval_dataset,
406
+ seed=batch.seed + start,
407
+ is_train=batch.is_train,
408
+ specific_gamefiles=chunk_gamefiles,
409
+ )
410
+ try:
411
+ chunk_results = run_alfworld_batch(
412
+ env_manager=chunk_env,
413
+ skill_content=skill_content,
414
+ max_steps=self.max_steps,
415
+ out_root=out_dir,
416
+ max_api_workers=min(self.max_api_workers, chunk_size),
417
+ max_completion_tokens=self.max_completion_tokens,
418
+ diagnostic_mode=diagnostic_mode,
419
+ diagnostic_instruction=diagnostic_instruction,
420
+ result_ids=chunk_ids,
421
+ )
422
+ finally:
423
+ self._close_env(chunk_env)
424
+ all_results.extend(chunk_results)
425
+ return all_results
426
+
427
+ def get_task_types(self) -> list[str]:
428
+ return list(TASKS)
@@ -0,0 +1,123 @@
1
+ """ALFWorld task dataloader."""
2
+ from __future__ import annotations
3
+
4
+ from skillopt.datasets.base import BatchSpec, SplitDataLoader
5
+
6
+
7
+ class ALFWorldDataLoader(SplitDataLoader):
8
+ """ALFWorld batch planner.
9
+
10
+ In split_dir mode, batches are fixed gamefile items so ablations differ
11
+ only in how the same training set is batched.
12
+ """
13
+
14
+ def __init__(
15
+ self,
16
+ split_dir: str = "",
17
+ data_path: str = "",
18
+ split_mode: str = "split_dir",
19
+ split_ratio: str = "2:1:7",
20
+ split_seed: int = 42,
21
+ split_output_dir: str = "",
22
+ seed: int = 42,
23
+ limit: int = 0,
24
+ train_size: 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.train_size_override = int(train_size or 0)
38
+
39
+ @staticmethod
40
+ def _metadata_for_items(items: list[dict], split: str, phase: str) -> dict:
41
+ gamefiles = [str(item.get("gamefile") or "") for item in items]
42
+ if any(not gamefile for gamefile in gamefiles):
43
+ raise ValueError("ALFWorld split items must contain non-empty gamefile paths.")
44
+ eval_dataset = "train"
45
+ is_train = phase == "train"
46
+ first = gamefiles[0] if gamefiles else ""
47
+ if "/valid_seen/" in first:
48
+ eval_dataset = "eval_in_distribution"
49
+ is_train = False
50
+ elif "/valid_unseen/" in first:
51
+ eval_dataset = "eval_out_of_distribution"
52
+ is_train = False
53
+ return {
54
+ "eval_dataset": eval_dataset,
55
+ "is_train": is_train,
56
+ "gamefiles": gamefiles,
57
+ "result_ids": [str(item.get("id") or idx) for idx, item in enumerate(items)],
58
+ }
59
+
60
+ def get_train_size(self) -> int:
61
+ if self.train_size_override > 0:
62
+ return self.train_size_override
63
+ return super().get_train_size()
64
+
65
+ def build_train_batch(self, batch_size: int, seed: int, **kwargs) -> BatchSpec:
66
+ batch = super().build_train_batch(batch_size=batch_size, seed=seed, **kwargs)
67
+ items = list(batch.payload or [])
68
+ batch.metadata.update(self._metadata_for_items(items, "train", "train"))
69
+ return BatchSpec(
70
+ phase="train",
71
+ split="train",
72
+ seed=seed,
73
+ batch_size=len(items),
74
+ payload=items,
75
+ metadata=batch.metadata,
76
+ )
77
+
78
+ def plan_train_epoch(
79
+ self,
80
+ *,
81
+ epoch: int,
82
+ steps_per_epoch: int,
83
+ accumulation: int,
84
+ batch_size: int,
85
+ seed: int,
86
+ **kwargs,
87
+ ) -> list[BatchSpec]:
88
+ batches = super().plan_train_epoch(
89
+ epoch=epoch,
90
+ steps_per_epoch=steps_per_epoch,
91
+ accumulation=accumulation,
92
+ batch_size=batch_size,
93
+ seed=seed,
94
+ **kwargs,
95
+ )
96
+ for batch in batches:
97
+ items = list(batch.payload or [])
98
+ batch.metadata.update(self._metadata_for_items(items, "train", "train"))
99
+ return batches
100
+
101
+ def build_eval_batch(
102
+ self,
103
+ env_num: int,
104
+ split: str,
105
+ seed: int,
106
+ **kwargs,
107
+ ) -> BatchSpec:
108
+ batch = super().build_eval_batch(
109
+ env_num=env_num,
110
+ split=split,
111
+ seed=seed,
112
+ **kwargs,
113
+ )
114
+ items = list(batch.payload or [])
115
+ batch.metadata.update(self._metadata_for_items(items, split, "eval"))
116
+ return BatchSpec(
117
+ phase="eval",
118
+ split=split,
119
+ seed=seed,
120
+ batch_size=len(items),
121
+ payload=items,
122
+ metadata=batch.metadata,
123
+ )
@@ -0,0 +1,55 @@
1
+ You are an expert failure-analysis agent for ALFWorld embodied household 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
+ ## ALFWorld Task Types
9
+ - pick_and_place: Put object in/on a receptacle
10
+ - pick_two_obj_and_place: Put two instances of an object in/on a receptacle
11
+ - look_at_obj_in_light: Examine an object under a desklamp
12
+ - pick_heat_then_place_in_recep: Heat an object and put it in/on a receptacle
13
+ - pick_cool_then_place_in_recep: Cool an object and put it in/on a receptacle
14
+ - pick_clean_then_place_in_recep: Clean an object and put it in/on a receptacle
15
+
16
+ ## Failure Type Categories
17
+ - **navigation_loop**: the agent revisits the same locations repeatedly without progress
18
+ - **missed_object**: the agent fails to pick up a visible/reachable goal object
19
+ - **wrong_sequence**: the agent performs actions in the wrong order (e.g., placing before transforming)
20
+ - **premature_stop**: the agent stops or gets stuck before completing all goal conditions
21
+ - **action_loop**: the agent repeats the same action without advancing
22
+ - **appliance_error**: the agent misuses or skips an appliance (microwave, fridge, sink)
23
+ - **rule_missing**: the skill lacks a relevant rule for this situation
24
+ - **rule_wrong**: an existing skill rule is misleading or incorrect
25
+ - **rule_ignored**: the skill has the right rule but the agent did not follow it
26
+ - **other**: none of the above
27
+
28
+ ## Analysis Process
29
+ 1. Read ALL trajectories in the minibatch.
30
+ 2. Identify the most prevalent, systematic failure patterns across them.
31
+ 3. For each pattern, classify its failure type.
32
+ 4. Propose skill edits that address the COMMON patterns — not individual edge cases.
33
+ 5. Edits must be generalizable; do not hardcode task-specific values.
34
+ 6. Only patch gaps in the skill — do not duplicate existing content.
35
+
36
+ You will be told the maximum number of edits (the budget L). Produce AT MOST L edits,
37
+ focusing on the highest-impact patterns. You may produce fewer if warranted.
38
+
39
+ Respond ONLY with a valid JSON object (no markdown fences, no extra text):
40
+ {
41
+ "batch_size": <number of trajectories analysed>,
42
+ "failure_summary": [
43
+ {"failure_type": "<type>", "count": <int>, "description": "<one-line>"}
44
+ ],
45
+ "patch": {
46
+ "reasoning": "<why these edits address the batch's common failures>",
47
+ "edits": [
48
+ {"op": "append", "content": "<markdown to add at end of skill>"},
49
+ {"op": "insert_after", "target": "<exact heading/text to insert after>", "content": "<markdown>"},
50
+ {"op": "replace", "target": "<exact text to replace>", "content": "<replacement>"},
51
+ {"op": "delete", "target": "<exact text to remove>"}
52
+ ]
53
+ }
54
+ }
55
+ Only include edits that are needed. "edits" can be an empty list if no patch is warranted.
@@ -0,0 +1,33 @@
1
+ You are an expert success-pattern analyst for AI agents operating in ALFWorld,
2
+ a text-based embodied household environment.
3
+
4
+ You will be given MULTIPLE successful agent trajectories from a single minibatch
5
+ and the current skill document. Your job is to identify generalizable behavior
6
+ patterns that are COMMON across the batch and worth encoding in the skill.
7
+
8
+ ## Rules
9
+ - Only propose patches for patterns NOT already covered in the skill.
10
+ - Focus on patterns that appear across MULTIPLE trajectories in the batch.
11
+ - Be concise. Patterns must generalize beyond specific tasks.
12
+ - Prefer reinforcing existing sections over adding new top-level sections.
13
+ - If the agents' success involved efficient exploration or smart appliance usage,
14
+ consider reinforcing that in the patch.
15
+
16
+ You will be told the maximum number of edits (the budget L). Produce AT MOST L edits,
17
+ focusing on the most broadly applicable patterns. You may produce fewer if warranted.
18
+
19
+ Respond ONLY with a valid JSON object:
20
+ {
21
+ "batch_size": <number of trajectories analysed>,
22
+ "success_patterns": ["<pattern 1>", "<pattern 2>"],
23
+ "patch": {
24
+ "reasoning": "<why these patterns are worth encoding>",
25
+ "edits": [
26
+ {"op": "append", "content": "<markdown>"},
27
+ {"op": "insert_after", "target": "<heading/text>", "content": "<markdown>"},
28
+ {"op": "replace", "target": "<old text>", "content": "<new text>"},
29
+ {"op": "delete", "target": "<exact text to remove>"}
30
+ ]
31
+ }
32
+ }
33
+ "edits" may be empty if the skill already covers all observed patterns.
@@ -0,0 +1,8 @@
1
+
2
+ You are an expert agent operating in the ALFRED Embodied Environment.
3
+ Your current observation is: {current_observation}
4
+ Your admissible actions of the current situation are: [{admissible_actions}].
5
+
6
+ Now it's your turn to take an action.
7
+ You should first reason step-by-step about the current situation. This reasoning process MUST be enclosed within <think> </think> tags.
8
+ Once you've finished your reasoning, you should choose an admissible action for current step and present it within <action> </action> tags.
@@ -0,0 +1,9 @@
1
+
2
+ You are an expert agent operating in the ALFRED Embodied Environment. Your task is to: {task_description}
3
+ Prior to this step, you have already taken {step_count} step(s). Below are the most recent {history_length} observations and the corresponding actions you took: {action_history}
4
+ You are now at step {current_step} and your current observation is: {current_observation}
5
+ Your admissible actions of the current situation are: [{admissible_actions}].
6
+
7
+ Now it's your turn to take an action.
8
+ You should first reason step-by-step about the current situation. This reasoning process MUST be enclosed within <think> </think> tags.
9
+ Once you've finished your reasoning, you should choose an admissible action for current step and present it within <action> </action> tags.
@@ -0,0 +1,16 @@
1
+
2
+ You are an expert agent operating in the ALFRED Embodied Environment. Your task is to: {task_description}
3
+
4
+ ## Retrieved Relevant Experience
5
+
6
+ {retrieved_memories}
7
+
8
+ ## Current Progress
9
+
10
+ Prior to this step, you have already taken {step_count} step(s). Below are the most recent {history_length} observations and the corresponding actions you took: {action_history}
11
+ You are now at step {current_step} and your current observation is: {current_observation}
12
+ Your admissible actions of the current situation are: [{admissible_actions}].
13
+
14
+ Now it's your turn to take an action.
15
+ You should first reason step-by-step about the current situation. This reasoning process MUST be enclosed within <think> </think> tags.
16
+ Once you've finished your reasoning, you should choose an admissible action for current step and present it within <action> </action> tags.
@@ -0,0 +1,4 @@
1
+ """ALFWorld Reflect stage.
2
+
3
+ Prompts are now loaded from .md files by the base adapter.
4
+ """