7.1 KiB
API Reference
This page documents the public Python API SkillOpt exposes for extending the
framework with new environments / benchmarks. For ready-made adapters,
browse skillopt/envs/.
Source of truth. The classes below are real Python ABCs defined in
skillopt/envs/base.py,skillopt/datasets/base.py,skillopt/types.py, andskillopt/evaluation/gate.py. If this page ever drifts, the code wins — please open an issue.
Core Classes
EnvAdapter
skillopt/envs/base.py — abstract adapter that connects the SkillOpt
trainer to an environment (benchmark, simulator, REST API, ...).
Subclasses must implement the four abstract methods below. Reflection has a
shared default implementation and only needs to be overridden for
environment-specific behavior.
from abc import ABC, abstractmethod
from skillopt.datasets.base import BaseDataLoader, BatchSpec
class EnvAdapter(ABC):
# ── Lifecycle hooks (have defaults; override only if needed) ────────
def setup(self, cfg: dict) -> None: ...
def get_dataloader(self) -> BaseDataLoader | None: ...
def requires_ray(self) -> bool: ... # default False
def reflect(self, results: list[dict], skill_content: str,
out_dir: str, **kwargs) -> list[dict | None]:
"""Delegate to the shared minibatch reflection pipeline."""
...
# ── Abstract methods (subclasses MUST implement) ────────────────────
@abstractmethod
def build_train_env(self, batch_size: int, seed: int, **kwargs):
"""Return an environment-manager object to be passed to rollout()."""
@abstractmethod
def build_eval_env(self, env_num: int, split: str, seed: int, **kwargs):
"""Like build_train_env() but for a fixed eval split."""
@abstractmethod
def rollout(self, env_manager, skill_content: str,
out_dir: str, **kwargs) -> list[dict]:
"""Run a batch of episodes with the current skill.
Each returned dict MUST contain:
- "id": str episode/task identifier
- "hard": int (0|1) pass/fail (may be float 0.0-1.0 if smoothed)
- "soft": float partial-credit score in [0.0, 1.0]
It MAY contain env-specific extra keys (parsed into RolloutResult.extras).
"""
@abstractmethod
def get_task_types(self) -> list[str]:
"""Distinct task-type strings used for stratified sampling."""
The default reflect() delegates to run_minibatch_reflect and returns raw
patch dicts with a patch payload plus a failure or success source type.
It expects each rollout to persist a non-empty trajectory at
<rollout_dir>/predictions/<result-id>/conversation.json; results without that
file can be scored but are skipped during reflection.
The trainer also calls several default-implemented helpers on every adapter:
build_reference_text, get_reference_metadata, attach_reference_context,
select_representative_items, and build_env_from_batch. Read the docstrings
in skillopt/envs/base.py if you need to override any of these — most
benchmarks do not.
BaseDataLoader / SplitDataLoader
skillopt/datasets/base.py — episode-planning loaders.
class BaseDataLoader(ABC):
def setup(self, cfg: dict) -> None: ...
@abstractmethod
def build_train_batch(self, batch_size: int, seed: int, **kwargs) -> BatchSpec: ...
@abstractmethod
def build_eval_batch(self, env_num: int, split: str, seed: int, **kwargs) -> BatchSpec: ...
class SplitDataLoader(BaseDataLoader):
"""Concrete base for dataset-backed envs with on-disk train/val/test splits.
Subclasses only need to implement load_split_items() (and optionally
load_raw_items() if you also want ``split_mode='ratio'``).
"""
def load_split_items(self, split_path: str) -> list[dict]: ...
def load_raw_items(self, data_path: str) -> list[dict]: ... # optional
SplitDataLoader handles two layout modes:
split_mode |
What it expects |
|---|---|
"split_dir" |
A directory with train/, val/, test/ subdirs already split. |
"ratio" |
A raw dataset path + split_ratio: "2:1:7" style string. |
In either case the items returned by load_split_items() are plain
dict objects with at minimum an "id" key.
BatchSpec
skillopt/datasets/base.py — a slotted dataclass describing one batch
request the trainer hands to the adapter.
@dataclass(slots=True)
class BatchSpec:
phase: str # "train" | "eval"
split: str # "train" | "val" | "test" | "valid_seen" | ...
seed: int
batch_size: int
payload: object | None = None # what the loader produced (e.g. list[dict])
metadata: dict = field(default_factory=dict)
Edit / Patch
skillopt/types.py — the I/O types Reflect / Aggregate / Update produce
and consume.
EditOp = Literal["append", "insert_after", "replace", "delete"]
@dataclass
class Edit:
op: EditOp
content: str = ""
target: str = ""
support_count: int | None = None
source_type: Literal["failure", "success"] | None = None
merge_level: int | None = None
update_origin: str = ""
update_target: str = ""
@dataclass
class Patch:
edits: list[Edit] = field(default_factory=list)
reasoning: str = ""
ranking_details: dict[str, Any] | None = None
Both types support to_dict() / from_dict() for serialization.
RolloutResult
skillopt/types.py — the normalised rollout return type. The trainer
calls RolloutResult.from_dict(...) on each dict returned from
EnvAdapter.rollout(), so the only hard requirement on those dicts is
the three keys above (id, hard, soft). Extra fields are preserved
into RolloutResult.extras.
GateResult / GateAction
skillopt/evaluation/gate.py — the validation-gate decision types
returned for each candidate optimization step, and optionally for a separate
epoch-end slow-update candidate.
Registering an environment
Environments are not registered via decorators or a BENCHMARK_REGISTRY
dict. The training and standalone-evaluation entry points each keep a lazy
_ENV_REGISTRY, populated by _register_builtins() in scripts/train.py and
scripts/eval_only.py. Add the environment to both entry points. See
Add a New Benchmark for the full step-by-step.
Backends (model layer)
The model layer lives under skillopt.model.*. Backends are selected
via model.optimizer_backend and model.target_backend in the config —
not via a base class subclass. Supported values (as of this writing):
| Backend | Optimizer? | Target? |
|---|---|---|
openai_chat |
✓ | ✓ |
claude_chat |
✓ | ✓ |
qwen_chat |
✓ | ✓ |
minimax_chat |
✓ | ✓ |
openai_compatible |
✓ | ✓ |
codex_exec |
✓ | ✓ |
claude_code_exec |
— | ✓ |
See skillopt/model/backend_config.py for the live whitelist and
docs/reference/config.md for the per-backend
configuration keys.