self-evolve-framework 1.4.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/rules/ponytail.mdc +98 -23
- 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
- package/template/skills/ponytail/SKILL.md +0 -133
- package/template/skills/ponytail/scripts/hooks/claude-codex-hooks.json +0 -44
- package/template/skills/ponytail/scripts/hooks/copilot-hooks.json +0 -21
- package/template/skills/ponytail/scripts/hooks/ponytail-activate.js +0 -91
- package/template/skills/ponytail/scripts/hooks/ponytail-config.js +0 -122
- package/template/skills/ponytail/scripts/hooks/ponytail-instructions.js +0 -94
- package/template/skills/ponytail/scripts/hooks/ponytail-mode-tracker.js +0 -55
- package/template/skills/ponytail/scripts/hooks/ponytail-runtime.js +0 -68
- package/template/skills/ponytail/scripts/hooks/ponytail-statusline.ps1 +0 -21
- package/template/skills/ponytail/scripts/hooks/ponytail-statusline.sh +0 -12
- package/template/skills/ponytail/scripts/hooks/ponytail-subagent.js +0 -22
- package/template/skills/ponytail/scripts/mcp/README.md +0 -46
- package/template/skills/ponytail/scripts/mcp/index.js +0 -48
- package/template/skills/ponytail/scripts/mcp/instructions.js +0 -26
- package/template/skills/ponytail/scripts/mcp/package.json +0 -13
- package/template/skills/ponytail/scripts/mcp/test/instructions.test.js +0 -22
- package/template/skills/ponytail-audit/SKILL.md +0 -41
- package/template/skills/ponytail-debt/SKILL.md +0 -44
- package/template/skills/ponytail-gain/SKILL.md +0 -50
- package/template/skills/ponytail-help/SKILL.md +0 -69
- package/template/skills/ponytail-review/SKILL.md +0 -57
|
@@ -0,0 +1,494 @@
|
|
|
1
|
+
"""SearchQA rollout — single-turn QA agent + batch execution.
|
|
2
|
+
|
|
3
|
+
The QA agent receives a skill document, question, and context passages,
|
|
4
|
+
then produces an answer in <answer>...</answer> tags.
|
|
5
|
+
|
|
6
|
+
Public API
|
|
7
|
+
----------
|
|
8
|
+
- :func:`process_one` — run + evaluate one QA item
|
|
9
|
+
- :func:`run_batch` — parallel execution of a list of items
|
|
10
|
+
"""
|
|
11
|
+
from __future__ import annotations
|
|
12
|
+
|
|
13
|
+
import json
|
|
14
|
+
import os
|
|
15
|
+
import time
|
|
16
|
+
from collections import Counter
|
|
17
|
+
from concurrent.futures import FIRST_COMPLETED, ThreadPoolExecutor, wait
|
|
18
|
+
|
|
19
|
+
from skillopt.envs.searchqa.evaluator import evaluate
|
|
20
|
+
from skillopt.model import chat_target, is_target_exec_backend
|
|
21
|
+
from skillopt.model.codex_harness import prepare_workspace, render_skill_md, run_target_exec
|
|
22
|
+
from skillopt.prompts import load_prompt
|
|
23
|
+
|
|
24
|
+
# ── Prompt templates ─────────────────────────────────────────────────────────
|
|
25
|
+
|
|
26
|
+
_MAX_CONTEXT_CHARS = 6000
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def _raise_on_systemic_failure(results: list[dict]) -> None:
|
|
30
|
+
"""Abort when all rollout rows failed before any agent response."""
|
|
31
|
+
if not results or not all(row.get("agent_ok") is False for row in results):
|
|
32
|
+
return
|
|
33
|
+
reasons = Counter(str(row.get("fail_reason") or "unknown error") for row in results)
|
|
34
|
+
common_reason, count = reasons.most_common(1)[0]
|
|
35
|
+
raise RuntimeError(
|
|
36
|
+
f"SearchQA rollout failed for all {len(results)} items before an agent "
|
|
37
|
+
f"response ({count}x): {common_reason}"
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def _truncate_context(context: str, max_chars: int = _MAX_CONTEXT_CHARS) -> str:
|
|
42
|
+
"""Truncate context at [DOC] boundaries to stay within budget."""
|
|
43
|
+
if len(context) <= max_chars:
|
|
44
|
+
return context
|
|
45
|
+
docs = context.split("[DOC]")
|
|
46
|
+
result = ""
|
|
47
|
+
for doc in docs:
|
|
48
|
+
candidate = result + "[DOC]" + doc if result else doc
|
|
49
|
+
if len(candidate) > max_chars:
|
|
50
|
+
break
|
|
51
|
+
result = candidate
|
|
52
|
+
if not result:
|
|
53
|
+
result = context[:max_chars] + "\n...[truncated]"
|
|
54
|
+
return result
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def _build_system(skill_content: str) -> str:
|
|
58
|
+
if skill_content.strip():
|
|
59
|
+
skill_section = f"## Skill\n{skill_content.strip()}\n\n"
|
|
60
|
+
else:
|
|
61
|
+
skill_section = ""
|
|
62
|
+
return load_prompt("rollout_system", env="searchqa").format(skill_section=skill_section)
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def _build_user(
|
|
66
|
+
question: str,
|
|
67
|
+
context: str,
|
|
68
|
+
*,
|
|
69
|
+
diagnostic_mode: bool = False,
|
|
70
|
+
diagnostic_instruction: str = "",
|
|
71
|
+
diagnostic_trace_context: str = "",
|
|
72
|
+
) -> str:
|
|
73
|
+
context = _truncate_context(context)
|
|
74
|
+
parts = [
|
|
75
|
+
f"## Context\n{context}",
|
|
76
|
+
f"## Question\n{question}",
|
|
77
|
+
]
|
|
78
|
+
if diagnostic_trace_context.strip():
|
|
79
|
+
parts.append(
|
|
80
|
+
"## Previous Codex Trace Snapshot\n"
|
|
81
|
+
"This is a partial transcript from an earlier attempt. Use it as your current reasoning context.\n\n"
|
|
82
|
+
f"{diagnostic_trace_context.strip()}"
|
|
83
|
+
)
|
|
84
|
+
if diagnostic_mode and diagnostic_instruction.strip():
|
|
85
|
+
parts.append(f"## Training Readout\n{diagnostic_instruction.strip()}")
|
|
86
|
+
return "\n\n".join(parts)
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
def _build_codex_skill(skill_content: str) -> str:
|
|
90
|
+
return render_skill_md(
|
|
91
|
+
skill_content,
|
|
92
|
+
description="Dynamic ReflACT skill for solving the current SearchQA example.",
|
|
93
|
+
preamble=(
|
|
94
|
+
"Use this skill when solving the current SearchQA task.\n"
|
|
95
|
+
"Read the provided context carefully, ground the answer in that context,\n"
|
|
96
|
+
"and return the final answer inside <answer>...</answer>."
|
|
97
|
+
),
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
def _run_codex_once(
|
|
102
|
+
*,
|
|
103
|
+
pred_dir: str,
|
|
104
|
+
skill_content: str,
|
|
105
|
+
question: str,
|
|
106
|
+
context: str,
|
|
107
|
+
model: str,
|
|
108
|
+
timeout: int,
|
|
109
|
+
diagnostic_mode: bool = False,
|
|
110
|
+
diagnostic_instruction: str = "",
|
|
111
|
+
diagnostic_trace_context: str = "",
|
|
112
|
+
previous_response: str = "",
|
|
113
|
+
) -> tuple[str, str, str, str]:
|
|
114
|
+
user = _build_user(
|
|
115
|
+
question,
|
|
116
|
+
context,
|
|
117
|
+
diagnostic_mode=diagnostic_mode,
|
|
118
|
+
diagnostic_instruction=diagnostic_instruction,
|
|
119
|
+
diagnostic_trace_context=diagnostic_trace_context,
|
|
120
|
+
)
|
|
121
|
+
task_parts = [user]
|
|
122
|
+
if previous_response:
|
|
123
|
+
task_parts.append(
|
|
124
|
+
"## Previous Attempt\n"
|
|
125
|
+
f"{previous_response}\n\n"
|
|
126
|
+
"Review it against the same context and question. If needed, correct it."
|
|
127
|
+
)
|
|
128
|
+
task_text = "\n\n".join(task_parts)
|
|
129
|
+
skill_md = _build_codex_skill(skill_content)
|
|
130
|
+
work_dir = os.path.join(pred_dir, "codex_exec")
|
|
131
|
+
prepare_workspace(
|
|
132
|
+
work_dir=work_dir,
|
|
133
|
+
skill_md=skill_md,
|
|
134
|
+
task_text=task_text,
|
|
135
|
+
)
|
|
136
|
+
prompt = (
|
|
137
|
+
"Use the `skillopt-target` skill available in this workspace.\n"
|
|
138
|
+
"Read `task.md` and answer the SearchQA question.\n"
|
|
139
|
+
"Return the final answer inside <answer>...</answer>."
|
|
140
|
+
)
|
|
141
|
+
final_message, raw = run_target_exec(
|
|
142
|
+
work_dir=work_dir,
|
|
143
|
+
prompt=prompt,
|
|
144
|
+
model=model,
|
|
145
|
+
timeout=timeout,
|
|
146
|
+
)
|
|
147
|
+
return final_message or raw, raw, skill_md, task_text
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
# ── Single-item execution ───────────────────────────────────────────────────
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
def process_one(
|
|
154
|
+
item: dict,
|
|
155
|
+
out_root: str,
|
|
156
|
+
skill_content: str,
|
|
157
|
+
max_turns: int = 1,
|
|
158
|
+
diagnostic_mode: bool = False,
|
|
159
|
+
diagnostic_instruction: str = "",
|
|
160
|
+
diagnostic_trace_context: str = "",
|
|
161
|
+
exec_timeout: int = 120,
|
|
162
|
+
max_completion_tokens: int = 16384,
|
|
163
|
+
) -> dict:
|
|
164
|
+
"""Process a single QA item: run agent + evaluate.
|
|
165
|
+
|
|
166
|
+
Parameters
|
|
167
|
+
----------
|
|
168
|
+
item : dict
|
|
169
|
+
Must have keys: ``id``, ``question``, ``context``, ``answers``.
|
|
170
|
+
out_root : str
|
|
171
|
+
Output directory (predictions saved under ``predictions/<id>/``).
|
|
172
|
+
skill_content : str
|
|
173
|
+
Current skill document text.
|
|
174
|
+
max_turns : int
|
|
175
|
+
Max reasoning turns (1 = single-turn QA).
|
|
176
|
+
|
|
177
|
+
Returns
|
|
178
|
+
-------
|
|
179
|
+
dict
|
|
180
|
+
Result with ``hard`` (EM as int), ``soft`` (F1), etc.
|
|
181
|
+
"""
|
|
182
|
+
item_id = str(item["id"])
|
|
183
|
+
question = item["question"]
|
|
184
|
+
context = item.get("context", "")
|
|
185
|
+
gold_answers = item.get("answers", [])
|
|
186
|
+
|
|
187
|
+
result = {
|
|
188
|
+
"id": item_id,
|
|
189
|
+
"question": question,
|
|
190
|
+
"em": 0.0,
|
|
191
|
+
"f1": 0.0,
|
|
192
|
+
"sub_em": 0.0,
|
|
193
|
+
"hard": 0,
|
|
194
|
+
"soft": 0.0,
|
|
195
|
+
"predicted_answer": "",
|
|
196
|
+
"gold_answers": gold_answers,
|
|
197
|
+
"response": "",
|
|
198
|
+
"fail_reason": "",
|
|
199
|
+
"agent_ok": False,
|
|
200
|
+
"n_turns": 0,
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
try:
|
|
204
|
+
pred_dir = os.path.join(out_root, "predictions", item_id)
|
|
205
|
+
os.makedirs(pred_dir, exist_ok=True)
|
|
206
|
+
|
|
207
|
+
if is_target_exec_backend():
|
|
208
|
+
from skillopt.model import azure_openai as _llm
|
|
209
|
+
|
|
210
|
+
conversation: list[dict] = []
|
|
211
|
+
response = ""
|
|
212
|
+
system = ""
|
|
213
|
+
user = ""
|
|
214
|
+
for turn in range(max_turns):
|
|
215
|
+
response, raw, system, user = _run_codex_once(
|
|
216
|
+
pred_dir=pred_dir,
|
|
217
|
+
skill_content=skill_content,
|
|
218
|
+
question=question,
|
|
219
|
+
context=context,
|
|
220
|
+
model=_llm.TARGET_DEPLOYMENT,
|
|
221
|
+
timeout=exec_timeout,
|
|
222
|
+
diagnostic_mode=diagnostic_mode if turn == 0 else False,
|
|
223
|
+
diagnostic_instruction=diagnostic_instruction if turn == 0 else "",
|
|
224
|
+
diagnostic_trace_context=diagnostic_trace_context if turn == 0 else "",
|
|
225
|
+
previous_response=response if turn > 0 else "",
|
|
226
|
+
)
|
|
227
|
+
conversation.append({"type": "message", "turn": turn + 1, "content": response})
|
|
228
|
+
if turn > 0 and "<answer>" in response.lower():
|
|
229
|
+
break
|
|
230
|
+
|
|
231
|
+
result["response"] = response
|
|
232
|
+
result["agent_ok"] = True
|
|
233
|
+
result["n_turns"] = len(conversation)
|
|
234
|
+
|
|
235
|
+
with open(os.path.join(pred_dir, "target_system_prompt.txt"), "w") as f:
|
|
236
|
+
f.write(system)
|
|
237
|
+
with open(os.path.join(pred_dir, "target_user_prompt.txt"), "w") as f:
|
|
238
|
+
f.write(user)
|
|
239
|
+
with open(os.path.join(pred_dir, "conversation.json"), "w") as f:
|
|
240
|
+
json.dump(conversation, f, ensure_ascii=False, indent=2)
|
|
241
|
+
|
|
242
|
+
eval_result = evaluate(response, gold_answers)
|
|
243
|
+
result["em"] = eval_result["em"]
|
|
244
|
+
result["f1"] = eval_result["f1"]
|
|
245
|
+
result["sub_em"] = eval_result["sub_em"]
|
|
246
|
+
result["predicted_answer"] = eval_result["predicted_answer"]
|
|
247
|
+
result["hard"] = int(eval_result["em"])
|
|
248
|
+
result["soft"] = eval_result["f1"]
|
|
249
|
+
if eval_result["em"] < 1.0:
|
|
250
|
+
result["fail_reason"] = (
|
|
251
|
+
f"EM=0: predicted '{eval_result['predicted_answer']}' "
|
|
252
|
+
f"but expected {gold_answers}"
|
|
253
|
+
)
|
|
254
|
+
eval_detail = (
|
|
255
|
+
f"[EVALUATION RESULT]\n"
|
|
256
|
+
f"Question: {question}\n"
|
|
257
|
+
f"Predicted answer: {eval_result['predicted_answer']!r}\n"
|
|
258
|
+
f"Gold answers: {gold_answers!r}\n"
|
|
259
|
+
f"Exact Match: {eval_result['em']}\n"
|
|
260
|
+
f"F1: {eval_result['f1']:.4f}"
|
|
261
|
+
)
|
|
262
|
+
conversation.append({"role": "system", "content": eval_detail})
|
|
263
|
+
with open(os.path.join(pred_dir, "conversation.json"), "w") as f:
|
|
264
|
+
json.dump(conversation, f, ensure_ascii=False, indent=2)
|
|
265
|
+
return result
|
|
266
|
+
|
|
267
|
+
system = _build_system(skill_content)
|
|
268
|
+
user = _build_user(
|
|
269
|
+
question,
|
|
270
|
+
context,
|
|
271
|
+
diagnostic_mode=diagnostic_mode,
|
|
272
|
+
diagnostic_instruction=diagnostic_instruction,
|
|
273
|
+
diagnostic_trace_context=diagnostic_trace_context,
|
|
274
|
+
)
|
|
275
|
+
|
|
276
|
+
conversation: list[dict] = []
|
|
277
|
+
response = ""
|
|
278
|
+
|
|
279
|
+
for turn in range(max_turns):
|
|
280
|
+
if turn == 0:
|
|
281
|
+
resp_text, _ = chat_target(
|
|
282
|
+
system=system, user=user,
|
|
283
|
+
max_completion_tokens=max_completion_tokens,
|
|
284
|
+
retries=5, stage="rollout",
|
|
285
|
+
timeout=exec_timeout,
|
|
286
|
+
)
|
|
287
|
+
else:
|
|
288
|
+
refinement = (
|
|
289
|
+
f"Your previous answer was:\n{response}\n\n"
|
|
290
|
+
f"Review it against the context and question. "
|
|
291
|
+
f"If correct, repeat it. If wrong, provide a corrected answer.\n"
|
|
292
|
+
f"Use <answer>...</answer> tags for your final answer."
|
|
293
|
+
)
|
|
294
|
+
resp_text, _ = chat_target(
|
|
295
|
+
system=system, user=refinement,
|
|
296
|
+
max_completion_tokens=max_completion_tokens,
|
|
297
|
+
retries=5, stage="rollout",
|
|
298
|
+
timeout=exec_timeout,
|
|
299
|
+
)
|
|
300
|
+
|
|
301
|
+
response = resp_text
|
|
302
|
+
conversation.append({"type": "message", "turn": turn + 1, "content": resp_text})
|
|
303
|
+
|
|
304
|
+
if turn > 0 and "<answer>" in resp_text.lower():
|
|
305
|
+
break
|
|
306
|
+
|
|
307
|
+
result["response"] = response
|
|
308
|
+
result["agent_ok"] = True
|
|
309
|
+
result["n_turns"] = len(conversation)
|
|
310
|
+
|
|
311
|
+
# Save conversation
|
|
312
|
+
with open(os.path.join(pred_dir, "target_system_prompt.txt"), "w") as f:
|
|
313
|
+
f.write(system)
|
|
314
|
+
with open(os.path.join(pred_dir, "target_user_prompt.txt"), "w") as f:
|
|
315
|
+
f.write(user)
|
|
316
|
+
with open(os.path.join(pred_dir, "conversation.json"), "w") as f:
|
|
317
|
+
json.dump(conversation, f, ensure_ascii=False, indent=2)
|
|
318
|
+
|
|
319
|
+
# Evaluate
|
|
320
|
+
eval_result = evaluate(response, gold_answers)
|
|
321
|
+
result["em"] = eval_result["em"]
|
|
322
|
+
result["f1"] = eval_result["f1"]
|
|
323
|
+
result["sub_em"] = eval_result["sub_em"]
|
|
324
|
+
result["predicted_answer"] = eval_result["predicted_answer"]
|
|
325
|
+
result["hard"] = int(eval_result["em"])
|
|
326
|
+
result["soft"] = eval_result["f1"]
|
|
327
|
+
|
|
328
|
+
if eval_result["em"] < 1.0:
|
|
329
|
+
result["fail_reason"] = (
|
|
330
|
+
f"EM=0: predicted '{eval_result['predicted_answer']}' "
|
|
331
|
+
f"but expected {gold_answers}"
|
|
332
|
+
)
|
|
333
|
+
|
|
334
|
+
# Append eval details to conversation for the analyst
|
|
335
|
+
eval_detail = (
|
|
336
|
+
f"[EVALUATION RESULT]\n"
|
|
337
|
+
f"Question: {question}\n"
|
|
338
|
+
f"Predicted answer: {eval_result['predicted_answer']!r}\n"
|
|
339
|
+
f"Gold answers: {gold_answers!r}\n"
|
|
340
|
+
f"Exact Match: {eval_result['em']}\n"
|
|
341
|
+
f"F1: {eval_result['f1']:.4f}"
|
|
342
|
+
)
|
|
343
|
+
conversation.append({
|
|
344
|
+
"role": "system",
|
|
345
|
+
"content": eval_detail,
|
|
346
|
+
})
|
|
347
|
+
# Re-save enriched conversation
|
|
348
|
+
with open(os.path.join(pred_dir, "conversation.json"), "w") as f:
|
|
349
|
+
json.dump(conversation, f, ensure_ascii=False, indent=2)
|
|
350
|
+
|
|
351
|
+
except Exception as e: # noqa: BLE001
|
|
352
|
+
result["fail_reason"] = f"error: {e}"
|
|
353
|
+
|
|
354
|
+
return result
|
|
355
|
+
|
|
356
|
+
|
|
357
|
+
# ── Batch execution ──────────────────────────────────────────────────────────
|
|
358
|
+
|
|
359
|
+
|
|
360
|
+
def run_batch(
|
|
361
|
+
items: list[dict],
|
|
362
|
+
out_root: str,
|
|
363
|
+
skill_content: str,
|
|
364
|
+
max_turns: int = 1,
|
|
365
|
+
exec_timeout: int = 120,
|
|
366
|
+
workers: int = 64,
|
|
367
|
+
max_completion_tokens: int = 16384,
|
|
368
|
+
diagnostic_mode: bool = False,
|
|
369
|
+
diagnostic_instruction: str = "",
|
|
370
|
+
diagnostic_trace_context_by_id: dict[str, str] | None = None,
|
|
371
|
+
task_timeout: int = 600,
|
|
372
|
+
) -> list[dict]:
|
|
373
|
+
"""Run QA agent on all items with ThreadPoolExecutor. Resume-aware."""
|
|
374
|
+
task_timeout = max(int(task_timeout), int(exec_timeout) + 60)
|
|
375
|
+
results_path = os.path.join(out_root, "results.jsonl")
|
|
376
|
+
os.makedirs(out_root, exist_ok=True)
|
|
377
|
+
|
|
378
|
+
# Resume: load already-done
|
|
379
|
+
done_ids: set[str] = set()
|
|
380
|
+
existing: list[dict] = []
|
|
381
|
+
if os.path.exists(results_path):
|
|
382
|
+
with open(results_path) as f:
|
|
383
|
+
for line in f:
|
|
384
|
+
try:
|
|
385
|
+
r = json.loads(line)
|
|
386
|
+
done_ids.add(str(r["id"]))
|
|
387
|
+
existing.append(r)
|
|
388
|
+
except Exception:
|
|
389
|
+
pass
|
|
390
|
+
|
|
391
|
+
pending = [it for it in items if str(it["id"]) not in done_ids]
|
|
392
|
+
if not pending:
|
|
393
|
+
_raise_on_systemic_failure(existing)
|
|
394
|
+
return existing
|
|
395
|
+
|
|
396
|
+
total = len(existing) + len(pending)
|
|
397
|
+
completed = len(existing)
|
|
398
|
+
correct_count = sum(1 for r in existing if r.get("hard", 0))
|
|
399
|
+
if existing:
|
|
400
|
+
print(f" [rollout] resuming: {completed}/{total} already done", flush=True)
|
|
401
|
+
|
|
402
|
+
results = list(existing)
|
|
403
|
+
|
|
404
|
+
def _timeout_result(item: dict) -> dict:
|
|
405
|
+
return {
|
|
406
|
+
"id": str(item["id"]),
|
|
407
|
+
"question": item.get("question", ""),
|
|
408
|
+
"task_description": item.get("question", ""),
|
|
409
|
+
"task_type": item.get("task_type") or "searchqa",
|
|
410
|
+
"hard": 0,
|
|
411
|
+
"soft": 0.0,
|
|
412
|
+
"predicted_answer": "",
|
|
413
|
+
"response": "",
|
|
414
|
+
"fail_reason": f"task-timeout-{task_timeout}s",
|
|
415
|
+
"agent_ok": False,
|
|
416
|
+
"n_turns": 0,
|
|
417
|
+
"gold_answer": item.get("answers", []),
|
|
418
|
+
"phase": "timeout",
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
def _error_result(item: dict, exc: Exception) -> dict:
|
|
422
|
+
row = _timeout_result(item)
|
|
423
|
+
row["phase"] = "error"
|
|
424
|
+
row["fail_reason"] = f"unexpected: {type(exc).__name__}: {exc}"
|
|
425
|
+
return row
|
|
426
|
+
|
|
427
|
+
started_at: dict[str, float] = {}
|
|
428
|
+
|
|
429
|
+
def _run_one(item: dict) -> dict:
|
|
430
|
+
started_at[str(item["id"])] = time.time()
|
|
431
|
+
return process_one(
|
|
432
|
+
item,
|
|
433
|
+
out_root,
|
|
434
|
+
skill_content,
|
|
435
|
+
max_turns,
|
|
436
|
+
diagnostic_mode,
|
|
437
|
+
diagnostic_instruction,
|
|
438
|
+
(diagnostic_trace_context_by_id or {}).get(str(item["id"]), ""),
|
|
439
|
+
exec_timeout,
|
|
440
|
+
max_completion_tokens,
|
|
441
|
+
)
|
|
442
|
+
|
|
443
|
+
with open(results_path, "a") as outf:
|
|
444
|
+
ex = ThreadPoolExecutor(max_workers=workers)
|
|
445
|
+
try:
|
|
446
|
+
futs = {ex.submit(_run_one, it): it for it in pending}
|
|
447
|
+
pending_futs = set(futs)
|
|
448
|
+
while pending_futs:
|
|
449
|
+
done, _ = wait(pending_futs, timeout=5, return_when=FIRST_COMPLETED)
|
|
450
|
+
now = time.time()
|
|
451
|
+
timed_out = [
|
|
452
|
+
fut for fut in pending_futs - done
|
|
453
|
+
if str(futs[fut]["id"]) in started_at
|
|
454
|
+
and now - started_at[str(futs[fut]["id"])] >= task_timeout
|
|
455
|
+
]
|
|
456
|
+
for fut in done:
|
|
457
|
+
pending_futs.remove(fut)
|
|
458
|
+
item = futs[fut]
|
|
459
|
+
try:
|
|
460
|
+
res = fut.result()
|
|
461
|
+
except Exception as exc: # noqa: BLE001
|
|
462
|
+
res = _error_result(item, exc)
|
|
463
|
+
results.append(res)
|
|
464
|
+
completed += 1
|
|
465
|
+
if res.get("hard", 0):
|
|
466
|
+
correct_count += 1
|
|
467
|
+
acc = correct_count / completed if completed else 0
|
|
468
|
+
print(
|
|
469
|
+
f" [rollout] {completed}/{total} "
|
|
470
|
+
f"(acc={acc:.3f}) id={res['id']} "
|
|
471
|
+
f"hard={res.get('hard', '?')}",
|
|
472
|
+
flush=True,
|
|
473
|
+
)
|
|
474
|
+
outf.write(json.dumps(res, ensure_ascii=False) + "\n")
|
|
475
|
+
outf.flush()
|
|
476
|
+
for fut in timed_out:
|
|
477
|
+
pending_futs.remove(fut)
|
|
478
|
+
fut.cancel()
|
|
479
|
+
res = _timeout_result(futs[fut])
|
|
480
|
+
results.append(res)
|
|
481
|
+
completed += 1
|
|
482
|
+
acc = correct_count / completed if completed else 0
|
|
483
|
+
print(
|
|
484
|
+
f" [rollout] {completed}/{total} "
|
|
485
|
+
f"(acc={acc:.3f}) id={res['id']} TIMEOUT",
|
|
486
|
+
flush=True,
|
|
487
|
+
)
|
|
488
|
+
outf.write(json.dumps(res, ensure_ascii=False) + "\n")
|
|
489
|
+
outf.flush()
|
|
490
|
+
finally:
|
|
491
|
+
ex.shutdown(wait=False, cancel_futures=True)
|
|
492
|
+
|
|
493
|
+
_raise_on_systemic_failure(results)
|
|
494
|
+
return results
|
package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/spreadsheetbench/adapter.py
ADDED
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
"""SpreadsheetBench environment adapter for ReflACT.
|
|
2
|
+
|
|
3
|
+
Connects the ReflACT training loop to SpreadsheetBench by implementing
|
|
4
|
+
:class:`~skillopt.envs.base.EnvAdapter`.
|
|
5
|
+
"""
|
|
6
|
+
from __future__ import annotations
|
|
7
|
+
|
|
8
|
+
import json
|
|
9
|
+
import os
|
|
10
|
+
|
|
11
|
+
from skillopt.datasets.base import BatchSpec
|
|
12
|
+
from skillopt.envs.base import EnvAdapter
|
|
13
|
+
from skillopt.envs.spreadsheetbench.dataloader import SpreadsheetBenchDataLoader
|
|
14
|
+
from skillopt.envs.spreadsheetbench.rollout import (
|
|
15
|
+
process_one,
|
|
16
|
+
run_spreadsheet_batch,
|
|
17
|
+
run_spreadsheet_batch_codegen,
|
|
18
|
+
)
|
|
19
|
+
from skillopt.model import get_target_backend, is_target_exec_backend
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
# Task types used for per-category breakdowns
|
|
23
|
+
TASK_TYPES = ["cell_level", "sheet_level"]
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class SpreadsheetBenchAdapter(EnvAdapter):
|
|
27
|
+
"""SpreadsheetBench environment adapter."""
|
|
28
|
+
|
|
29
|
+
def __init__(
|
|
30
|
+
self,
|
|
31
|
+
split_dir: str = "",
|
|
32
|
+
data_path: str = "",
|
|
33
|
+
split_mode: str = "ratio",
|
|
34
|
+
split_ratio: str = "2:1:7",
|
|
35
|
+
split_seed: int = 42,
|
|
36
|
+
split_output_dir: str = "",
|
|
37
|
+
data_root: str = "",
|
|
38
|
+
mode: str = "single",
|
|
39
|
+
max_turns: int = 30,
|
|
40
|
+
exec_timeout: int = 600,
|
|
41
|
+
workers: int = 64,
|
|
42
|
+
analyst_workers: int = 16,
|
|
43
|
+
failure_only: bool = False,
|
|
44
|
+
minibatch_size: int = 8,
|
|
45
|
+
edit_budget: int = 4,
|
|
46
|
+
seed: int = 42,
|
|
47
|
+
max_completion_tokens: int = 16384,
|
|
48
|
+
) -> None:
|
|
49
|
+
self.data_root = data_root
|
|
50
|
+
self.mode = mode # "single", "multi", or "react"
|
|
51
|
+
self.max_turns = max_turns
|
|
52
|
+
self.exec_timeout = exec_timeout
|
|
53
|
+
self.workers = workers
|
|
54
|
+
self.max_completion_tokens = int(max_completion_tokens)
|
|
55
|
+
self.analyst_workers = analyst_workers
|
|
56
|
+
self.failure_only = failure_only
|
|
57
|
+
self.minibatch_size = minibatch_size
|
|
58
|
+
self.edit_budget = edit_budget
|
|
59
|
+
self.dataloader = SpreadsheetBenchDataLoader(
|
|
60
|
+
split_dir=split_dir,
|
|
61
|
+
data_path=data_path,
|
|
62
|
+
split_mode=split_mode,
|
|
63
|
+
split_ratio=split_ratio,
|
|
64
|
+
split_seed=split_seed,
|
|
65
|
+
split_output_dir=split_output_dir,
|
|
66
|
+
data_root=data_root,
|
|
67
|
+
seed=seed,
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
def setup(self, cfg: dict) -> None:
|
|
71
|
+
super().setup(cfg)
|
|
72
|
+
if is_target_exec_backend() and self.mode != "single":
|
|
73
|
+
raise NotImplementedError(
|
|
74
|
+
"Exec target backends are currently supported only for SpreadsheetBench mode=single."
|
|
75
|
+
)
|
|
76
|
+
self.dataloader.setup(cfg)
|
|
77
|
+
|
|
78
|
+
def get_dataloader(self):
|
|
79
|
+
return self.dataloader
|
|
80
|
+
|
|
81
|
+
def build_env_from_batch(self, batch: BatchSpec, **kwargs):
|
|
82
|
+
return list(batch.payload or [])
|
|
83
|
+
|
|
84
|
+
def build_train_env(self, batch_size: int, seed: int, **kwargs):
|
|
85
|
+
batch = self.dataloader.build_train_batch(batch_size=batch_size, seed=seed, **kwargs)
|
|
86
|
+
return self.build_env_from_batch(batch, **kwargs)
|
|
87
|
+
|
|
88
|
+
def build_eval_env(self, env_num: int, split: str, seed: int, **kwargs):
|
|
89
|
+
batch = self.dataloader.build_eval_batch(env_num=env_num, split=split, seed=seed, **kwargs)
|
|
90
|
+
return self.build_env_from_batch(batch, **kwargs)
|
|
91
|
+
|
|
92
|
+
def rollout(
|
|
93
|
+
self,
|
|
94
|
+
env_manager,
|
|
95
|
+
skill_content: str,
|
|
96
|
+
out_dir: str,
|
|
97
|
+
**kwargs,
|
|
98
|
+
) -> list[dict]:
|
|
99
|
+
"""Run agent on all items and return results.
|
|
100
|
+
|
|
101
|
+
Dispatches based on ``self.mode``:
|
|
102
|
+
- ``"single"`` / ``"multi"``: codegen agent (no tool-call)
|
|
103
|
+
- ``"react"``: ReAct agent with tool-call (legacy)
|
|
104
|
+
"""
|
|
105
|
+
items = env_manager # For static datasets, env_manager is a list of items
|
|
106
|
+
results_path = os.path.join(out_dir, "results.jsonl")
|
|
107
|
+
os.makedirs(out_dir, exist_ok=True)
|
|
108
|
+
|
|
109
|
+
# Resume support
|
|
110
|
+
if os.path.exists(results_path):
|
|
111
|
+
existing: list[dict] = []
|
|
112
|
+
with open(results_path) as f:
|
|
113
|
+
for line in f:
|
|
114
|
+
try:
|
|
115
|
+
existing.append(json.loads(line))
|
|
116
|
+
except Exception:
|
|
117
|
+
pass
|
|
118
|
+
if existing:
|
|
119
|
+
return existing
|
|
120
|
+
|
|
121
|
+
if self.mode in ("single", "multi"):
|
|
122
|
+
results = run_spreadsheet_batch_codegen(
|
|
123
|
+
items=items,
|
|
124
|
+
data_root=self.data_root,
|
|
125
|
+
out_root=out_dir,
|
|
126
|
+
skill_content=skill_content,
|
|
127
|
+
mode=self.mode,
|
|
128
|
+
max_turns=self.max_turns,
|
|
129
|
+
max_completion_tokens=self.max_completion_tokens,
|
|
130
|
+
max_api_workers=self.workers,
|
|
131
|
+
task_timeout=self.exec_timeout,
|
|
132
|
+
use_eval_feedback=kwargs.get("use_eval_feedback", False),
|
|
133
|
+
diagnostic_mode=kwargs.get("diagnostic_mode", False),
|
|
134
|
+
diagnostic_instruction=kwargs.get("diagnostic_instruction", ""),
|
|
135
|
+
diagnostic_trace_context_by_id=kwargs.get("diagnostic_trace_context_by_id"),
|
|
136
|
+
)
|
|
137
|
+
else:
|
|
138
|
+
results = run_spreadsheet_batch(
|
|
139
|
+
items=items,
|
|
140
|
+
data_root=self.data_root,
|
|
141
|
+
out_root=out_dir,
|
|
142
|
+
skill_content=skill_content,
|
|
143
|
+
max_turns=self.max_turns,
|
|
144
|
+
max_completion_tokens=self.max_completion_tokens,
|
|
145
|
+
max_api_workers=self.workers,
|
|
146
|
+
task_timeout=max(600, int(self.exec_timeout) + 60),
|
|
147
|
+
diagnostic_mode=kwargs.get("diagnostic_mode", False),
|
|
148
|
+
diagnostic_instruction=kwargs.get("diagnostic_instruction", ""),
|
|
149
|
+
diagnostic_trace_context_by_id=kwargs.get("diagnostic_trace_context_by_id"),
|
|
150
|
+
)
|
|
151
|
+
|
|
152
|
+
with open(results_path, "w") as f:
|
|
153
|
+
for r in results:
|
|
154
|
+
f.write(json.dumps(r, ensure_ascii=False) + "\n")
|
|
155
|
+
|
|
156
|
+
return results
|
|
157
|
+
|
|
158
|
+
def get_task_types(self) -> list[str]:
|
|
159
|
+
return list(TASK_TYPES)
|