self-evolve-framework 1.5.0 → 1.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/template/skills/skillopt-sleep/SKILL.md +42 -0
- package/template/skills/skillopt-sleep/configs/_base_/default.yaml +103 -0
- package/template/skills/skillopt-sleep/configs/alfworld/default.yaml +29 -0
- package/template/skills/skillopt-sleep/configs/docvqa/default.yaml +28 -0
- package/template/skills/skillopt-sleep/configs/features/soft_gate.yaml +47 -0
- package/template/skills/skillopt-sleep/configs/livemathematicianbench/default.yaml +22 -0
- package/template/skills/skillopt-sleep/configs/officeqa/default.yaml +34 -0
- package/template/skills/skillopt-sleep/configs/searchqa/default.yaml +32 -0
- package/template/skills/skillopt-sleep/configs/spreadsheetbench/default.yaml +34 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/__init__.py +28 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/config.py +282 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/datasets/__init__.py +7 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/datasets/base.py +512 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/engine/__init__.py +9 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/engine/trainer.py +2379 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/__init__.py +1 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/_template/README.md +43 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/_template/config_template.yaml +55 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/_template/env_template.py +151 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/_template/loader_template.py +87 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/alfworld/__init__.py +5 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/alfworld/adapter.py +428 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/alfworld/dataloader.py +123 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/alfworld/prompts/analyst_error.md +55 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/alfworld/prompts/analyst_success.md +33 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/alfworld/prompts/rollout_no_history.md +8 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/alfworld/prompts/rollout_with_history.md +9 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/alfworld/prompts/rollout_with_memory.md +16 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/alfworld/reflect.py +4 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/alfworld/rollout.py +366 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/alfworld/skills/initial.md +45 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/alfworld/vendor/__init__.py +9 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/alfworld/vendor/alfworld_envs.py +221 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/alfworld/vendor/alfworld_projection.py +60 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/alfworld/vendor/alfworld_prompts.py +8 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/alfworld/vendor/config_tw.yaml +145 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/alfworld/vendor/env_base.py +84 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/alfworld/vendor/env_manager.py +139 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/alfworld/vendor/memory.py +87 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/base.py +329 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/docvqa/__init__.py +1 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/docvqa/adapter.py +90 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/docvqa/dataloader.py +61 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/docvqa/evaluator.py +113 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/docvqa/prompts/analyst_error.md +35 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/docvqa/prompts/analyst_success.md +24 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/docvqa/prompts/rollout_system.md +12 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/docvqa/rollout.py +391 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/docvqa/skills/initial.md +11 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/livemathematicianbench/__init__.py +1 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/livemathematicianbench/adapter.py +129 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/livemathematicianbench/dataloader.py +308 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/livemathematicianbench/evaluator.py +62 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/livemathematicianbench/prompts/analyst_error.md +37 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/livemathematicianbench/prompts/analyst_success.md +25 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/livemathematicianbench/prompts/rollout_system.md +12 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/livemathematicianbench/reflect.py +4 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/livemathematicianbench/rollout.py +434 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/livemathematicianbench/skills/initial.md +16 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/officeqa/__init__.py +1 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/officeqa/adapter.py +112 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/officeqa/dataloader.py +71 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/officeqa/evaluator.py +46 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/officeqa/prompts/analyst_error.md +37 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/officeqa/prompts/analyst_success.md +25 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/officeqa/prompts/rollout_system.md +15 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/officeqa/rollout.py +799 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/officeqa/skills/initial.md +15 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/officeqa/tool_runtime.py +552 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/searchqa/__init__.py +1 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/searchqa/adapter.py +96 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/searchqa/dataloader.py +42 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/searchqa/evaluator.py +100 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/searchqa/prompts/analyst_error.md +46 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/searchqa/prompts/analyst_success.md +32 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/searchqa/prompts/rollout_system.md +13 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/searchqa/reflect.py +4 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/searchqa/rollout.py +494 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/searchqa/skills/initial.md +3 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/spreadsheetbench/__init__.py +5 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/spreadsheetbench/adapter.py +159 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/spreadsheetbench/codegen_agent.py +731 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/spreadsheetbench/dataloader.py +37 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/spreadsheetbench/evaluator.py +158 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/spreadsheetbench/executor.py +67 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/spreadsheetbench/prompts/analyst_error.md +46 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/spreadsheetbench/prompts/analyst_success.md +32 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/spreadsheetbench/prompts/codegen_system.md +1 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/spreadsheetbench/prompts/critical_rules.md +9 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/spreadsheetbench/prompts/react_system.md +21 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/spreadsheetbench/react_agent.py +395 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/spreadsheetbench/reflect.py +4 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/spreadsheetbench/rollout.py +979 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/envs/spreadsheetbench/skills/initial.md +56 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/evaluation/__init__.py +13 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/evaluation/gate.py +148 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/gradient/__init__.py +15 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/gradient/aggregate.py +253 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/gradient/reflect.py +635 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/model/__init__.py +514 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/model/azure_openai.py +915 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/model/backend_config.py +185 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/model/claude_backend.py +371 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/model/codex_backend.py +666 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/model/codex_harness.py +1057 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/model/common.py +229 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/model/minimax_backend.py +277 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/model/qwen_backend.py +456 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/model/router.py +236 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/optimizer/__init__.py +15 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/optimizer/appendix.py +156 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/optimizer/clip.py +109 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/optimizer/lr_autonomous.py +108 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/optimizer/meta_skill.py +79 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/optimizer/rewrite.py +59 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/optimizer/scheduler.py +127 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/optimizer/select.py +4 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/optimizer/skill.py +201 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/optimizer/skill_aware.py +206 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/optimizer/slow_update.py +396 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/optimizer/update_modes.py +135 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/prompts/__init__.py +63 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/prompts/analyst_error.md +41 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/prompts/analyst_error_full_rewrite.md +32 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/prompts/analyst_error_rewrite.md +44 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/prompts/analyst_success.md +36 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/prompts/analyst_success_full_rewrite.md +30 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/prompts/analyst_success_rewrite.md +33 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/prompts/lr_autonomous.md +20 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/prompts/merge_failure.md +30 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/prompts/merge_failure_full_rewrite.md +28 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/prompts/merge_failure_rewrite.md +26 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/prompts/merge_final.md +33 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/prompts/merge_final_full_rewrite.md +28 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/prompts/merge_final_rewrite.md +25 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/prompts/merge_success.md +28 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/prompts/merge_success_full_rewrite.md +28 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/prompts/merge_success_rewrite.md +25 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/prompts/meta_skill.md +40 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/prompts/ranking.md +20 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/prompts/ranking_rewrite.md +15 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/prompts/rewrite_skill.md +25 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/prompts/slow_update.md +60 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/scheduler/__init__.py +8 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/types.py +306 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/utils/__init__.py +4 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/utils/json_utils.py +172 -0
- package/template/skills/skillopt-sleep/scripts/framework/skillopt/utils/scoring.py +28 -0
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# Spreadsheet Manipulation Skill (xlsx)
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
This skill guides agents in manipulating Excel (.xlsx) spreadsheets using Python.
|
|
5
|
+
|
|
6
|
+
**Primary libraries**: `openpyxl` (structure-preserving read/write), `pandas` (data transformation).
|
|
7
|
+
Never use any other third-party libraries.
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## Common Workflow
|
|
12
|
+
|
|
13
|
+
1. **Explore** the input file: list sheets, inspect headers, check dimensions.
|
|
14
|
+
2. **Write `solution.py`** with `INPUT_PATH` and `OUTPUT_PATH` defined at the top.
|
|
15
|
+
3. **Execute** `python solution.py` and verify the output file was created.
|
|
16
|
+
4. **Confirm** the target cells/range contain the expected values.
|
|
17
|
+
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
## Library Selection
|
|
21
|
+
|
|
22
|
+
| Use case | Library |
|
|
23
|
+
|----------|---------|
|
|
24
|
+
| Preserve formulas, formatting, named ranges | `openpyxl` |
|
|
25
|
+
| Bulk data transformation, aggregation, sorting | `pandas` → write back with `openpyxl` |
|
|
26
|
+
| Simple cell read/write | `openpyxl` |
|
|
27
|
+
|
|
28
|
+
**Warning**: `pandas.to_excel()` silently destroys existing formulas and named ranges.
|
|
29
|
+
When writing back to a spreadsheet that contains formulas, always use `openpyxl.save()`.
|
|
30
|
+
|
|
31
|
+
---
|
|
32
|
+
|
|
33
|
+
## solution.py Template
|
|
34
|
+
|
|
35
|
+
```python
|
|
36
|
+
import openpyxl
|
|
37
|
+
import pandas as pd
|
|
38
|
+
|
|
39
|
+
INPUT_PATH = "..." # set to the actual input path
|
|
40
|
+
OUTPUT_PATH = "..." # set to the actual output path
|
|
41
|
+
|
|
42
|
+
wb = openpyxl.load_workbook(INPUT_PATH)
|
|
43
|
+
ws = wb.active # or wb["SheetName"]
|
|
44
|
+
|
|
45
|
+
# --- perform manipulation ---
|
|
46
|
+
|
|
47
|
+
wb.save(OUTPUT_PATH)
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
---
|
|
51
|
+
|
|
52
|
+
## Output Requirements
|
|
53
|
+
|
|
54
|
+
- Save the result to `OUTPUT_PATH`.
|
|
55
|
+
- Do not hardcode row counts or column letters — iterate over actual rows in the workbook.
|
|
56
|
+
- Preserve sheets and cells not mentioned in the instruction.
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"""ReflACT Evaluation -- candidate skill validation and model selection.
|
|
2
|
+
|
|
3
|
+
Analogous to validation-based early stopping and model selection in neural
|
|
4
|
+
network training: evaluates candidate skills on held-out selection sets and
|
|
5
|
+
decides whether to accept or reject proposed updates.
|
|
6
|
+
"""
|
|
7
|
+
from skillopt.evaluation.gate import ( # noqa: F401
|
|
8
|
+
GateAction,
|
|
9
|
+
GateMetric,
|
|
10
|
+
GateResult,
|
|
11
|
+
evaluate_gate,
|
|
12
|
+
select_gate_score,
|
|
13
|
+
)
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
"""Validation gate — accept / reject candidate skills.
|
|
2
|
+
|
|
3
|
+
Analogous to validation-based early stopping and model selection in neural
|
|
4
|
+
network training: compares the candidate's score against the current and
|
|
5
|
+
best scores, then returns an accept/reject decision.
|
|
6
|
+
|
|
7
|
+
The trainer owns side-effects (cache lookup, rollout, printing, state
|
|
8
|
+
mutation). This module is the pure decision function.
|
|
9
|
+
|
|
10
|
+
Metric selection
|
|
11
|
+
----------------
|
|
12
|
+
Three gate metrics are supported:
|
|
13
|
+
|
|
14
|
+
* ``"hard"`` (default, backward-compatible):
|
|
15
|
+
Compare candidate vs current/best using *hard* exact-match accuracy.
|
|
16
|
+
* ``"soft"``:
|
|
17
|
+
Compare using *soft* per-item score (F1 / partial credit / etc.).
|
|
18
|
+
Use this when a small held-out selection set has too few items for
|
|
19
|
+
hard accuracy to be sensitive to incremental skill improvements.
|
|
20
|
+
* ``"mixed"``:
|
|
21
|
+
Compare using a weighted average ``(1 - w) * hard + w * soft``.
|
|
22
|
+
``w`` is configurable via ``mixed_weight`` (default ``0.5``).
|
|
23
|
+
"""
|
|
24
|
+
from __future__ import annotations
|
|
25
|
+
|
|
26
|
+
from dataclasses import dataclass
|
|
27
|
+
from typing import Literal
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
GateAction = Literal["accept_new_best", "accept", "reject"]
|
|
31
|
+
GateMetric = Literal["hard", "soft", "mixed"]
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
@dataclass(frozen=True)
|
|
35
|
+
class GateResult:
|
|
36
|
+
"""Immutable outcome of the validation gate."""
|
|
37
|
+
|
|
38
|
+
action: GateAction
|
|
39
|
+
current_skill: str
|
|
40
|
+
current_score: float
|
|
41
|
+
best_skill: str
|
|
42
|
+
best_score: float
|
|
43
|
+
best_step: int
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def select_gate_score(
|
|
47
|
+
hard: float,
|
|
48
|
+
soft: float,
|
|
49
|
+
metric: GateMetric = "hard",
|
|
50
|
+
mixed_weight: float = 0.5,
|
|
51
|
+
) -> float:
|
|
52
|
+
"""Project (hard, soft) onto a single comparison metric.
|
|
53
|
+
|
|
54
|
+
Parameters
|
|
55
|
+
----------
|
|
56
|
+
hard, soft
|
|
57
|
+
Aggregate hard / soft scores from a rollout batch (both 0..1).
|
|
58
|
+
metric
|
|
59
|
+
Which metric to compare on.
|
|
60
|
+
mixed_weight
|
|
61
|
+
For ``"mixed"``: weight given to ``soft``. Must be in ``[0, 1]``.
|
|
62
|
+
Ignored for ``"hard"`` / ``"soft"``.
|
|
63
|
+
"""
|
|
64
|
+
if metric == "hard":
|
|
65
|
+
return float(hard)
|
|
66
|
+
if metric == "soft":
|
|
67
|
+
return float(soft)
|
|
68
|
+
if metric == "mixed":
|
|
69
|
+
w = max(0.0, min(1.0, float(mixed_weight)))
|
|
70
|
+
return (1.0 - w) * float(hard) + w * float(soft)
|
|
71
|
+
raise ValueError(
|
|
72
|
+
f"unknown gate metric {metric!r}; expected 'hard', 'soft', or 'mixed'"
|
|
73
|
+
)
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
def evaluate_gate(
|
|
77
|
+
candidate_skill: str,
|
|
78
|
+
cand_hard: float,
|
|
79
|
+
current_skill: str,
|
|
80
|
+
current_score: float,
|
|
81
|
+
best_skill: str,
|
|
82
|
+
best_score: float,
|
|
83
|
+
best_step: int,
|
|
84
|
+
global_step: int,
|
|
85
|
+
*,
|
|
86
|
+
cand_soft: float = 0.0,
|
|
87
|
+
metric: GateMetric = "hard",
|
|
88
|
+
mixed_weight: float = 0.5,
|
|
89
|
+
) -> GateResult:
|
|
90
|
+
"""Pure gate decision: compare candidate score to current/best.
|
|
91
|
+
|
|
92
|
+
Parameters
|
|
93
|
+
----------
|
|
94
|
+
candidate_skill
|
|
95
|
+
The candidate skill content being evaluated.
|
|
96
|
+
cand_hard, cand_soft
|
|
97
|
+
Aggregate hard / soft scores of the candidate on the selection set.
|
|
98
|
+
current_skill, current_score
|
|
99
|
+
The currently-active skill and its *metric-space* score.
|
|
100
|
+
best_skill, best_score, best_step
|
|
101
|
+
The best-so-far skill, its *metric-space* score, and the step
|
|
102
|
+
at which it was accepted.
|
|
103
|
+
global_step
|
|
104
|
+
Current global training step (recorded if a new best is accepted).
|
|
105
|
+
cand_soft
|
|
106
|
+
Soft score of the candidate; only consulted when ``metric != "hard"``.
|
|
107
|
+
Defaults to ``0.0`` for backward compatibility with callers that
|
|
108
|
+
previously passed only ``cand_hard``.
|
|
109
|
+
metric
|
|
110
|
+
Which metric to compare on. Defaults to ``"hard"`` to preserve
|
|
111
|
+
the original gate behavior.
|
|
112
|
+
mixed_weight
|
|
113
|
+
Weight on ``soft`` when ``metric == "mixed"``.
|
|
114
|
+
|
|
115
|
+
Returns
|
|
116
|
+
-------
|
|
117
|
+
GateResult
|
|
118
|
+
Updated state; the caller decides what to do with it (print,
|
|
119
|
+
mutate trainer state, log, etc.).
|
|
120
|
+
"""
|
|
121
|
+
cand_score = select_gate_score(cand_hard, cand_soft, metric, mixed_weight)
|
|
122
|
+
|
|
123
|
+
if cand_score > current_score:
|
|
124
|
+
if cand_score > best_score:
|
|
125
|
+
return GateResult(
|
|
126
|
+
action="accept_new_best",
|
|
127
|
+
current_skill=candidate_skill,
|
|
128
|
+
current_score=cand_score,
|
|
129
|
+
best_skill=candidate_skill,
|
|
130
|
+
best_score=cand_score,
|
|
131
|
+
best_step=global_step,
|
|
132
|
+
)
|
|
133
|
+
return GateResult(
|
|
134
|
+
action="accept",
|
|
135
|
+
current_skill=candidate_skill,
|
|
136
|
+
current_score=cand_score,
|
|
137
|
+
best_skill=best_skill,
|
|
138
|
+
best_score=best_score,
|
|
139
|
+
best_step=best_step,
|
|
140
|
+
)
|
|
141
|
+
return GateResult(
|
|
142
|
+
action="reject",
|
|
143
|
+
current_skill=current_skill,
|
|
144
|
+
current_score=current_score,
|
|
145
|
+
best_skill=best_skill,
|
|
146
|
+
best_score=best_score,
|
|
147
|
+
best_step=best_step,
|
|
148
|
+
)
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"""SkillOpt Gradient -- trajectory analysis and patch generation.
|
|
2
|
+
|
|
3
|
+
Analogous to gradient computation in neural network training: analyzes
|
|
4
|
+
minibatch rollout trajectories to produce skill-edit patches (the "gradient"
|
|
5
|
+
that drives skill updates).
|
|
6
|
+
|
|
7
|
+
Modules
|
|
8
|
+
-------
|
|
9
|
+
- reflect: minibatch trajectory analysis (gradient computation)
|
|
10
|
+
- aggregate: hierarchical patch merging (gradient aggregation)
|
|
11
|
+
"""
|
|
12
|
+
from skillopt.gradient.reflect import ( # noqa: F401
|
|
13
|
+
run_minibatch_reflect,
|
|
14
|
+
)
|
|
15
|
+
from skillopt.gradient.aggregate import merge_patches # noqa: F401
|
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
"""ReflACT Aggregate stage — hierarchical patch merging.
|
|
2
|
+
|
|
3
|
+
The Aggregate stage takes independently-generated patches from the Reflect
|
|
4
|
+
stage and merges them into a single coherent patch via hierarchical LLM calls.
|
|
5
|
+
Failure-driven patches take priority over success-driven ones.
|
|
6
|
+
"""
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
import json
|
|
10
|
+
from concurrent.futures import ThreadPoolExecutor, as_completed
|
|
11
|
+
|
|
12
|
+
from skillopt.model import chat_optimizer
|
|
13
|
+
from skillopt.optimizer.meta_skill import format_meta_skill_context
|
|
14
|
+
from skillopt.optimizer.update_modes import (
|
|
15
|
+
get_payload_items,
|
|
16
|
+
is_full_rewrite_minibatch_mode,
|
|
17
|
+
is_rewrite_mode,
|
|
18
|
+
normalize_update_mode,
|
|
19
|
+
payload_key,
|
|
20
|
+
payload_label,
|
|
21
|
+
)
|
|
22
|
+
from skillopt.prompts import load_prompt
|
|
23
|
+
from skillopt.utils import extract_json
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
# ── Internal helpers ──────────────────────────────────────────────────────────
|
|
27
|
+
|
|
28
|
+
def _merge_batch(
|
|
29
|
+
skill_content: str,
|
|
30
|
+
patches: list[dict],
|
|
31
|
+
system_prompt: str,
|
|
32
|
+
update_mode: str,
|
|
33
|
+
meta_skill_context: str = "",
|
|
34
|
+
level: int = 1,
|
|
35
|
+
) -> dict:
|
|
36
|
+
"""Call optimizer LLM to merge a batch of patches into one."""
|
|
37
|
+
patches_text = json.dumps(patches, ensure_ascii=False, indent=2)
|
|
38
|
+
user = (
|
|
39
|
+
f"## Current Skill\n{skill_content}\n\n"
|
|
40
|
+
f"## Patches to merge ({len(patches)} total, merge level {level})\n{patches_text}"
|
|
41
|
+
)
|
|
42
|
+
optimizer_ctx = format_meta_skill_context(meta_skill_context)
|
|
43
|
+
if optimizer_ctx:
|
|
44
|
+
user = f"{optimizer_ctx}\n\n{user}"
|
|
45
|
+
try:
|
|
46
|
+
response, _ = chat_optimizer(
|
|
47
|
+
system=system_prompt,
|
|
48
|
+
user=user,
|
|
49
|
+
max_completion_tokens=64000 if is_full_rewrite_minibatch_mode(update_mode) else 16384,
|
|
50
|
+
retries=3,
|
|
51
|
+
stage="merge",
|
|
52
|
+
)
|
|
53
|
+
merged = extract_json(response)
|
|
54
|
+
key = payload_key(update_mode)
|
|
55
|
+
if merged and key in merged:
|
|
56
|
+
for e in merged.get(key, []):
|
|
57
|
+
e["merge_level"] = level
|
|
58
|
+
return merged
|
|
59
|
+
except Exception: # noqa: BLE001
|
|
60
|
+
pass
|
|
61
|
+
# Fallback: concatenate all edits
|
|
62
|
+
all_edits = []
|
|
63
|
+
for p in patches:
|
|
64
|
+
for e in get_payload_items(p, update_mode):
|
|
65
|
+
e.setdefault("merge_level", level)
|
|
66
|
+
all_edits.append(e)
|
|
67
|
+
return {"reasoning": "fallback concatenation", payload_key(update_mode): all_edits}
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def _hierarchical_merge(
|
|
71
|
+
skill_content: str,
|
|
72
|
+
patches: list[dict],
|
|
73
|
+
system_prompt: str,
|
|
74
|
+
update_mode: str,
|
|
75
|
+
batch_size: int,
|
|
76
|
+
verbose: bool,
|
|
77
|
+
label: str = "",
|
|
78
|
+
workers: int = 16,
|
|
79
|
+
meta_skill_context: str = "",
|
|
80
|
+
) -> dict:
|
|
81
|
+
"""Hierarchically merge N patches using the given system prompt.
|
|
82
|
+
|
|
83
|
+
Same-level batches are executed in PARALLEL via ThreadPoolExecutor.
|
|
84
|
+
"""
|
|
85
|
+
if not patches:
|
|
86
|
+
return {"reasoning": "no patches", payload_key(update_mode): []}
|
|
87
|
+
if len(patches) == 1:
|
|
88
|
+
return patches[0]
|
|
89
|
+
|
|
90
|
+
current = list(patches)
|
|
91
|
+
level = 0
|
|
92
|
+
while len(current) > 1:
|
|
93
|
+
level += 1
|
|
94
|
+
batches: list[tuple[int, list[dict]]] = []
|
|
95
|
+
for i in range(0, len(current), batch_size):
|
|
96
|
+
batch = current[i : i + batch_size]
|
|
97
|
+
batches.append((i, batch))
|
|
98
|
+
|
|
99
|
+
if verbose:
|
|
100
|
+
print(
|
|
101
|
+
f" [aggregate {label}] level={level} "
|
|
102
|
+
f"{len(current)} patches → {len(batches)} batches "
|
|
103
|
+
f"(parallel, batch_size={batch_size})"
|
|
104
|
+
)
|
|
105
|
+
|
|
106
|
+
next_level: list[dict | None] = [None] * len(batches)
|
|
107
|
+
|
|
108
|
+
to_merge: list[tuple[int, list[dict]]] = []
|
|
109
|
+
for idx, (i, batch) in enumerate(batches):
|
|
110
|
+
if len(batch) == 1:
|
|
111
|
+
next_level[idx] = batch[0]
|
|
112
|
+
else:
|
|
113
|
+
to_merge.append((idx, batch))
|
|
114
|
+
|
|
115
|
+
if to_merge:
|
|
116
|
+
with ThreadPoolExecutor(max_workers=workers) as ex:
|
|
117
|
+
futs = {
|
|
118
|
+
ex.submit(
|
|
119
|
+
_merge_batch, skill_content, batch, system_prompt, update_mode,
|
|
120
|
+
meta_skill_context, level,
|
|
121
|
+
): idx
|
|
122
|
+
for idx, batch in to_merge
|
|
123
|
+
}
|
|
124
|
+
for fut in as_completed(futs):
|
|
125
|
+
idx = futs[fut]
|
|
126
|
+
next_level[idx] = fut.result()
|
|
127
|
+
if verbose:
|
|
128
|
+
batch_i, batch_data = batches[idx]
|
|
129
|
+
n_edits = len(get_payload_items(next_level[idx], update_mode))
|
|
130
|
+
print(
|
|
131
|
+
f" [aggregate {label}] level={level} "
|
|
132
|
+
f"batch [{batch_i}:{batch_i+len(batch_data)}] "
|
|
133
|
+
f"→ 1 patch ({n_edits} {payload_label(update_mode)})"
|
|
134
|
+
)
|
|
135
|
+
|
|
136
|
+
current = [x for x in next_level if x is not None]
|
|
137
|
+
|
|
138
|
+
return current[0]
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
# ── Public API ────────────────────────────────────────────────────────────────
|
|
142
|
+
|
|
143
|
+
def merge_patches(
|
|
144
|
+
skill_content: str,
|
|
145
|
+
failure_patches: list[dict],
|
|
146
|
+
success_patches: list[dict],
|
|
147
|
+
batch_size: int = 8,
|
|
148
|
+
verbose: bool = True,
|
|
149
|
+
workers: int = 16,
|
|
150
|
+
update_mode: str = "patch",
|
|
151
|
+
meta_skill_context: str = "",
|
|
152
|
+
) -> dict:
|
|
153
|
+
"""Failure-first hierarchical merge with support count tracking.
|
|
154
|
+
|
|
155
|
+
1. Merge failure patches independently (parallel)
|
|
156
|
+
2. Merge success patches independently (parallel)
|
|
157
|
+
3. Final merge: combine both groups with failure priority
|
|
158
|
+
|
|
159
|
+
Returns a merged :class:`~skillopt.types.Patch` dict (``edits`` + ``reasoning``).
|
|
160
|
+
"""
|
|
161
|
+
if verbose:
|
|
162
|
+
print(
|
|
163
|
+
f" [3/6 AGGREGATE] "
|
|
164
|
+
f"failure={len(failure_patches)} success={len(success_patches)} "
|
|
165
|
+
f"(parallel, workers={workers})"
|
|
166
|
+
)
|
|
167
|
+
|
|
168
|
+
update_mode = normalize_update_mode(update_mode)
|
|
169
|
+
if is_full_rewrite_minibatch_mode(update_mode):
|
|
170
|
+
merge_failure_prompt = load_prompt("merge_failure_full_rewrite")
|
|
171
|
+
merge_success_prompt = load_prompt("merge_success_full_rewrite")
|
|
172
|
+
merge_final_prompt = load_prompt("merge_final_full_rewrite")
|
|
173
|
+
elif is_rewrite_mode(update_mode):
|
|
174
|
+
merge_failure_prompt = load_prompt("merge_failure_rewrite")
|
|
175
|
+
merge_success_prompt = load_prompt("merge_success_rewrite")
|
|
176
|
+
merge_final_prompt = load_prompt("merge_final_rewrite")
|
|
177
|
+
else:
|
|
178
|
+
merge_failure_prompt = load_prompt("merge_failure")
|
|
179
|
+
merge_success_prompt = load_prompt("merge_success")
|
|
180
|
+
merge_final_prompt = load_prompt("merge_final")
|
|
181
|
+
|
|
182
|
+
failure_merged = _hierarchical_merge(
|
|
183
|
+
skill_content, failure_patches, merge_failure_prompt, update_mode,
|
|
184
|
+
batch_size, verbose, label="failure", workers=workers,
|
|
185
|
+
meta_skill_context=meta_skill_context,
|
|
186
|
+
)
|
|
187
|
+
|
|
188
|
+
success_merged = _hierarchical_merge(
|
|
189
|
+
skill_content, success_patches, merge_success_prompt, update_mode,
|
|
190
|
+
batch_size, verbose, label="success", workers=workers,
|
|
191
|
+
meta_skill_context=meta_skill_context,
|
|
192
|
+
)
|
|
193
|
+
|
|
194
|
+
f_edits = get_payload_items(failure_merged, update_mode)
|
|
195
|
+
s_edits = get_payload_items(success_merged, update_mode)
|
|
196
|
+
|
|
197
|
+
if not f_edits and not s_edits:
|
|
198
|
+
return {"reasoning": "no updates from either group", payload_key(update_mode): []}
|
|
199
|
+
if not s_edits:
|
|
200
|
+
return failure_merged
|
|
201
|
+
if not f_edits:
|
|
202
|
+
return success_merged
|
|
203
|
+
|
|
204
|
+
combined_patches = [failure_merged, success_merged]
|
|
205
|
+
combined_text = json.dumps(combined_patches, ensure_ascii=False, indent=2)
|
|
206
|
+
if is_full_rewrite_minibatch_mode(update_mode):
|
|
207
|
+
item_label = payload_label(update_mode)
|
|
208
|
+
user = (
|
|
209
|
+
f"## Current Skill\n{skill_content}\n\n"
|
|
210
|
+
f"## Two pre-merged candidate groups to combine\n"
|
|
211
|
+
f"Group 1 (from failed trajectories): "
|
|
212
|
+
f"{len(f_edits)} {item_label}\n"
|
|
213
|
+
f"Group 2 (from successful trajectories): "
|
|
214
|
+
f"{len(s_edits)} {item_label}\n\n"
|
|
215
|
+
f"{combined_text}"
|
|
216
|
+
)
|
|
217
|
+
else:
|
|
218
|
+
user = (
|
|
219
|
+
f"## Current Skill\n{skill_content}\n\n"
|
|
220
|
+
f"## Two pre-merged patch groups to combine\n"
|
|
221
|
+
f"Group 1 (failure-driven, HIGH priority): "
|
|
222
|
+
f"{len(f_edits)} edits\n"
|
|
223
|
+
f"Group 2 (success-driven, lower priority): "
|
|
224
|
+
f"{len(s_edits)} edits\n\n"
|
|
225
|
+
f"{combined_text}"
|
|
226
|
+
)
|
|
227
|
+
optimizer_ctx = format_meta_skill_context(meta_skill_context)
|
|
228
|
+
if optimizer_ctx:
|
|
229
|
+
user = f"{optimizer_ctx}\n\n{user}"
|
|
230
|
+
try:
|
|
231
|
+
response, _ = chat_optimizer(
|
|
232
|
+
system=merge_final_prompt,
|
|
233
|
+
user=user,
|
|
234
|
+
max_completion_tokens=64000 if is_full_rewrite_minibatch_mode(update_mode) else 16384,
|
|
235
|
+
retries=3,
|
|
236
|
+
stage="merge",
|
|
237
|
+
)
|
|
238
|
+
final = extract_json(response)
|
|
239
|
+
key = payload_key(update_mode)
|
|
240
|
+
if final and key in final:
|
|
241
|
+
if verbose:
|
|
242
|
+
print(
|
|
243
|
+
f" [aggregate final] "
|
|
244
|
+
f"{len(f_edits)}+{len(s_edits)} → {len(final[key])} {payload_label(update_mode)}"
|
|
245
|
+
)
|
|
246
|
+
return final
|
|
247
|
+
except Exception: # noqa: BLE001
|
|
248
|
+
pass
|
|
249
|
+
|
|
250
|
+
return {
|
|
251
|
+
"reasoning": "fallback: failure first, then success",
|
|
252
|
+
payload_key(update_mode): f_edits + s_edits,
|
|
253
|
+
}
|